From: Xavier Claessens Date: Fri, 22 Jun 2007 10:47:42 +0000 (+0000) Subject: Rename all filenames starting with "gossip" by "empathy", change namespace X-Git-Url: https://git.0d.be/?p=empathy.git;a=commitdiff_plain;h=58505161bcc63ba91190f6b38a3c52c0c564ca32 Rename all filenames starting with "gossip" by "empathy", change namespace 2007-06-22 Xavier Claessens * libempathy/*.[ch]: * libempathy-gtk/*.[ch]: * src/*.[ch]: Rename all filenames starting with "gossip" by "empathy", change namespace of all gossip_*() functions to empathy_*(). Fixes bug #444490 (Mario Danic, Xavier Claessens). svn path=/trunk/; revision=170 --- diff --git a/ChangeLog b/ChangeLog index 92e273f6..e3794a23 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2007-06-22 Xavier Claessens + + * libempathy/*.[ch]: + * libempathy-gtk/*.[ch]: + * src/*.[ch]: Rename all filenames starting with "gossip" by "empathy", + change namespace of all gossip_*() functions to empathy_*(). + Fixes bug #444490 (Mario Danic, Xavier Claessens). + 2007-06-21 Xavier Claessens * configure.ac: Bump version to 0.9 diff --git a/TODO b/TODO index a1117010..284f8c9f 100644 --- a/TODO +++ b/TODO @@ -1,19 +1,17 @@ Things you can do if you want to help: - - Rename all files and functions name to use the empathy namespace. Bug #444490. - Porting gossip-account-widget-*.{c,h} from gossip project (Guillaume is already working on IRC widget). - UI for inviting a contact in a chatroom. - UI for accept/refuse invitation to join a chatroom. - UI to send a message directly to a contact. - GtkWidget-ify libempathy-gtk. Actually most window/dialog do not inherit from GtkWindow/GtkDialog. Need to create a glade catalog. - - Filter channels before dispatching them. For example we need a GtkStatusIcon that blink when an event arrives (text/voip/ft channel) and tells the MC to dispatch the channel only when the user clicked the icon. Like in gossip. For that we need a filter DBus API in MC, not yet written, a draft spec is proposed on the telepathy ML. - - Make use of NetworkManager to set the presence - Remove Quit option everywhere, empathy is a session service and shouldn't be leaved. - Add sound events - Add register capability in GossipAccountsDialog if the profile says it's supported. - Write a manual based on gossip's. - Testing and Bugfixing. - Update translations. + - Fix indentation and alignment broken since namespace changed from gossip_ to empathy_ SoC projects: - Adding VoIP support based on the patch proposed for gossip. diff --git a/libempathy-gtk/Makefile.am b/libempathy-gtk/Makefile.am index 113b37c3..5a01c647 100644 --- a/libempathy-gtk/Makefile.am +++ b/libempathy-gtk/Makefile.am @@ -14,33 +14,33 @@ libempathy_gtk_la_SOURCES = \ empathy-status-icon.c empathy-status-icon.h \ empathy-contact-widget.c empathy-contact-widget.h \ empathy-contact-dialogs.c empathy-contact-dialogs.h \ - gossip-accounts-dialog.c gossip-accounts-dialog.h \ - gossip-account-widget-generic.c gossip-account-widget-generic.h \ - gossip-account-widget-jabber.c gossip-account-widget-jabber.h \ - gossip-profile-chooser.c gossip-profile-chooser.h \ - gossip-cell-renderer-expander.c gossip-cell-renderer-expander.h \ - gossip-cell-renderer-text.c gossip-cell-renderer-text.h \ - gossip-spell.c gossip-spell.h \ - gossip-spell-dialog.c gossip-spell-dialog.h \ - gossip-contact-groups.c gossip-contact-groups.h \ - gossip-contact-list-store.c gossip-contact-list-store.h \ - gossip-contact-list-view.c gossip-contact-list-view.h \ - gossip-preferences.c gossip-preferences.h \ - gossip-theme-manager.c gossip-theme-manager.h \ - gossip-chat-window.c gossip-chat-window.h \ - gossip-chat.c gossip-chat.h \ - gossip-chat-view.c gossip-chat-view.h \ - gossip-private-chat.c gossip-private-chat.h \ - gossip-group-chat.c gossip-group-chat.h \ - gossip-geometry.c gossip-geometry.h \ - gossip-status-presets.c gossip-status-presets.h \ - gossip-presence-chooser.c gossip-presence-chooser.h \ - gossip-about-dialog.c gossip-about-dialog.h \ - gossip-account-chooser.c gossip-account-chooser.h \ - gossip-new-chatroom-dialog.c gossip-new-chatroom-dialog.h \ - gossip-chatrooms-window.c gossip-chatrooms-window.h \ - gossip-log-window.c gossip-log-window.h \ - gossip-ui-utils.c gossip-ui-utils.h + empathy-accounts-dialog.c empathy-accounts-dialog.h \ + empathy-account-widget-generic.c empathy-account-widget-generic.h \ + empathy-account-widget-jabber.c empathy-account-widget-jabber.h \ + empathy-profile-chooser.c empathy-profile-chooser.h \ + empathy-cell-renderer-expander.c empathy-cell-renderer-expander.h \ + empathy-cell-renderer-text.c empathy-cell-renderer-text.h \ + empathy-spell.c empathy-spell.h \ + empathy-spell-dialog.c empathy-spell-dialog.h \ + empathy-contact-groups.c empathy-contact-groups.h \ + empathy-contact-list-store.c empathy-contact-list-store.h \ + empathy-contact-list-view.c empathy-contact-list-view.h \ + empathy-preferences.c empathy-preferences.h \ + empathy-theme-manager.c empathy-theme-manager.h \ + empathy-chat-window.c empathy-chat-window.h \ + empathy-chat.c empathy-chat.h \ + empathy-chat-view.c empathy-chat-view.h \ + empathy-private-chat.c empathy-private-chat.h \ + empathy-group-chat.c empathy-group-chat.h \ + empathy-geometry.c empathy-geometry.h \ + empathy-status-presets.c empathy-status-presets.h \ + empathy-presence-chooser.c empathy-presence-chooser.h \ + empathy-about-dialog.c empathy-about-dialog.h \ + empathy-account-chooser.c empathy-account-chooser.h \ + empathy-new-chatroom-dialog.c empathy-new-chatroom-dialog.h \ + empathy-chatrooms-window.c empathy-chatrooms-window.h \ + empathy-log-window.c empathy-log-window.h \ + empathy-ui-utils.c empathy-ui-utils.h libempathy_gtk_la_LIBADD = \ $(EMPATHY_LIBS) \ @@ -54,21 +54,21 @@ glade_DATA = \ empathy-status-icon.glade \ empathy-contact-widget.glade \ empathy-contact-dialogs.glade \ - gossip-preferences.glade \ - gossip-presence-chooser.glade \ - gossip-accounts-dialog.glade \ - gossip-account-widget-jabber.glade \ - gossip-new-chatroom-dialog.glade \ - gossip-group-chat.glade \ - gossip-chatrooms-window.glade \ - gossip-spell-dialog.glade \ - gossip-log-window.glade \ - gossip-chat.glade + empathy-preferences.glade \ + empathy-presence-chooser.glade \ + empathy-accounts-dialog.glade \ + empathy-account-widget-jabber.glade \ + empathy-new-chatroom-dialog.glade \ + empathy-group-chat.glade \ + empathy-chatrooms-window.glade \ + empathy-spell-dialog.glade \ + empathy-log-window.glade \ + empathy-chat.glade dtddir = $(datadir)/empathy dtd_DATA = \ - gossip-status-presets.dtd \ - gossip-contact-groups.dtd + empathy-status-presets.dtd \ + empathy-contact-groups.dtd EXTRA_DIST = \ diff --git a/libempathy-gtk/empathy-about-dialog.c b/libempathy-gtk/empathy-about-dialog.c new file mode 100644 index 00000000..07d62ab7 --- /dev/null +++ b/libempathy-gtk/empathy-about-dialog.c @@ -0,0 +1,113 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Martyn Russell + * Xavier Claessens + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "empathy-about-dialog.h" +#include "empathy-ui-utils.h" + +#define WEB_SITE "http://live.gnome.org/Empathy" + +static void about_dialog_activate_link_cb (GtkAboutDialog *about, + const gchar *link, + gpointer data); + +static const char *authors[] = { + "Mikael Hallendal", + "Richard Hult", + "Martyn Russell", + "Geert-Jan Van den Bogaerde", + "Kevin Dougherty", + "Eitan Isaacson", + "Xavier Claessens", + NULL +}; + +static const char *documenters[] = { + NULL +}; + +static const char *artists[] = { + "Andreas Nilsson ", + "Vinicius Depizzol ", + NULL +}; + +static const char *license[] = { + N_("Empathy 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."), + N_("Empathy 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."), + N_("You should have received a copy of the GNU General Public License " + "along with Empathy; if not, write to the Free Software Foundation, Inc., " + "51 Franklin Street, Fifth Floor, Boston, MA 02110-130159 USA") +}; + +static void +about_dialog_activate_link_cb (GtkAboutDialog *about, + const gchar *link, + gpointer data) +{ + empathy_url_show (link); +} + +void +empathy_about_dialog_new (GtkWindow *parent) +{ + gchar *license_trans; + + gtk_about_dialog_set_url_hook (about_dialog_activate_link_cb, NULL, NULL); + + license_trans = g_strconcat (_(license[0]), "\n\n", + _(license[1]), "\n\n", + _(license[2]), "\n\n", + NULL); + + gtk_show_about_dialog (parent, + "artists", artists, + "authors", authors, + "comments", _("An Instant Messaging client for GNOME"), + "license", license_trans, + "wrap-license", TRUE, + "copyright", "Imendio AB 2002-2007\nCollabora Ltd 2007", + "documenters", documenters, + "logo-icon-name", "empathy", + "translator-credits", _("translator-credits"), + "version", PACKAGE_VERSION, + "website", WEB_SITE, + NULL); + + g_free (license_trans); +} + + diff --git a/libempathy-gtk/empathy-about-dialog.h b/libempathy-gtk/empathy-about-dialog.h new file mode 100644 index 00000000..ad5705e0 --- /dev/null +++ b/libempathy-gtk/empathy-about-dialog.h @@ -0,0 +1,34 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Martyn Russell + */ + +#ifndef __EMPATHY_ABOUT_DIALOG_H__ +#define __EMPATHY_ABOUT_DIALOG_H__ + +#include + +G_BEGIN_DECLS + +void empathy_about_dialog_new (GtkWindow *parent); + +G_END_DECLS + +#endif /* __EMPATHY_ABOUT_DIALOG_H__ */ diff --git a/libempathy-gtk/empathy-account-chooser.c b/libempathy-gtk/empathy-account-chooser.c new file mode 100644 index 00000000..eb46c52f --- /dev/null +++ b/libempathy-gtk/empathy-account-chooser.c @@ -0,0 +1,637 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2005-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Martyn Russell + */ + +#include "config.h" + +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include "empathy-ui-utils.h" +#include "empathy-account-chooser.h" + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_ACCOUNT_CHOOSER, EmpathyAccountChooserPriv)) + +typedef struct { + MissionControl *mc; + McAccountMonitor *monitor; + + gboolean set_active_item; + gboolean can_select_all; + gboolean has_all_option; +} EmpathyAccountChooserPriv; + +typedef struct { + EmpathyAccountChooser *chooser; + McAccount *account; + gboolean set; +} SetAccountData; + +enum { + COL_ACCOUNT_IMAGE, + COL_ACCOUNT_TEXT, + COL_ACCOUNT_ENABLED, /* Usually tied to connected state */ + COL_ACCOUNT_POINTER, + COL_ACCOUNT_COUNT +}; + +static void account_chooser_finalize (GObject *object); +static void account_chooser_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); +static void account_chooser_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void account_chooser_setup (EmpathyAccountChooser *chooser); +static void account_chooser_account_created_cb (McAccountMonitor *monitor, + const gchar *unique_name, + EmpathyAccountChooser *chooser); +static void account_chooser_account_add_foreach (McAccount *account, + EmpathyAccountChooser *chooser); +static void account_chooser_account_deleted_cb (McAccountMonitor *monitor, + const gchar *unique_name, + EmpathyAccountChooser *chooser); +static void account_chooser_account_remove_foreach (McAccount *account, + EmpathyAccountChooser *chooser); +static void account_chooser_update_iter (EmpathyAccountChooser *chooser, + GtkTreeIter *iter, + McAccount *account); +static void account_chooser_status_changed_cb (MissionControl *mc, + TelepathyConnectionStatus status, + McPresence presence, + TelepathyConnectionStatusReason reason, + const gchar *unique_name, + EmpathyAccountChooser *chooser); +static gboolean account_chooser_separator_func (GtkTreeModel *model, + GtkTreeIter *iter, + EmpathyAccountChooser *chooser); +static gboolean account_chooser_set_account_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + SetAccountData *data); +static gboolean account_chooser_set_enabled_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + EmpathyAccountChooser *chooser); + +enum { + PROP_0, + PROP_CAN_SELECT_ALL, + PROP_HAS_ALL_OPTION, +}; + +G_DEFINE_TYPE (EmpathyAccountChooser, empathy_account_chooser, GTK_TYPE_COMBO_BOX); + +static void +empathy_account_chooser_class_init (EmpathyAccountChooserClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = account_chooser_finalize; + object_class->get_property = account_chooser_get_property; + object_class->set_property = account_chooser_set_property; + + g_object_class_install_property (object_class, + PROP_CAN_SELECT_ALL, + g_param_spec_boolean ("can-select-all", + "Can Select All", + "Should the user be able to select offline accounts", + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_HAS_ALL_OPTION, + g_param_spec_boolean ("has-all-option", + "Has All Option", + "Have a separate option in the list to mean ALL accounts", + FALSE, + G_PARAM_READWRITE)); + + g_type_class_add_private (object_class, sizeof (EmpathyAccountChooserPriv)); +} + +static void +empathy_account_chooser_init (EmpathyAccountChooser *chooser) +{ +} + +static void +account_chooser_finalize (GObject *object) +{ + EmpathyAccountChooser *chooser; + EmpathyAccountChooserPriv *priv; + + chooser = EMPATHY_ACCOUNT_CHOOSER (object); + priv = GET_PRIV (object); + + g_signal_handlers_disconnect_by_func (priv->monitor, + account_chooser_account_created_cb, + chooser); + g_signal_handlers_disconnect_by_func (priv->monitor, + account_chooser_account_deleted_cb, + chooser); + dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc), + "AccountStatusChanged", + G_CALLBACK (account_chooser_status_changed_cb), + chooser); + g_object_unref (priv->mc); + g_object_unref (priv->monitor); + + G_OBJECT_CLASS (empathy_account_chooser_parent_class)->finalize (object); +} + +static void +account_chooser_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + EmpathyAccountChooserPriv *priv; + + priv = GET_PRIV (object); + + switch (param_id) { + case PROP_CAN_SELECT_ALL: + g_value_set_boolean (value, priv->can_select_all); + break; + case PROP_HAS_ALL_OPTION: + g_value_set_boolean (value, priv->has_all_option); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + }; +} + +static void +account_chooser_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + EmpathyAccountChooserPriv *priv; + + priv = GET_PRIV (object); + + switch (param_id) { + case PROP_CAN_SELECT_ALL: + empathy_account_chooser_set_can_select_all (EMPATHY_ACCOUNT_CHOOSER (object), + g_value_get_boolean (value)); + break; + case PROP_HAS_ALL_OPTION: + empathy_account_chooser_set_has_all_option (EMPATHY_ACCOUNT_CHOOSER (object), + g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + }; +} + +GtkWidget * +empathy_account_chooser_new (void) +{ + EmpathyAccountChooserPriv *priv; + McAccountMonitor *monitor; + GtkWidget *chooser; + + monitor = mc_account_monitor_new (); + chooser = g_object_new (EMPATHY_TYPE_ACCOUNT_CHOOSER, NULL); + + priv = GET_PRIV (chooser); + + priv->mc = empathy_mission_control_new (); + priv->monitor = mc_account_monitor_new (); + + g_signal_connect (priv->monitor, "account-created", + G_CALLBACK (account_chooser_account_created_cb), + chooser); + g_signal_connect (priv->monitor, "account-deleted", + G_CALLBACK (account_chooser_account_deleted_cb), + chooser); + dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc), "AccountStatusChanged", + G_CALLBACK (account_chooser_status_changed_cb), + chooser, NULL); + + account_chooser_setup (EMPATHY_ACCOUNT_CHOOSER (chooser)); + + return chooser; +} + +McAccount * +empathy_account_chooser_get_account (EmpathyAccountChooser *chooser) +{ + EmpathyAccountChooserPriv *priv; + McAccount *account; + GtkTreeModel *model; + GtkTreeIter iter; + + g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), NULL); + + priv = GET_PRIV (chooser); + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (chooser)); + gtk_combo_box_get_active_iter (GTK_COMBO_BOX (chooser), &iter); + + gtk_tree_model_get (model, &iter, COL_ACCOUNT_POINTER, &account, -1); + + return account; +} + +gboolean +empathy_account_chooser_set_account (EmpathyAccountChooser *chooser, + McAccount *account) +{ + GtkComboBox *combobox; + GtkTreeModel *model; + GtkTreeIter iter; + SetAccountData data; + + g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), FALSE); + + combobox = GTK_COMBO_BOX (chooser); + model = gtk_combo_box_get_model (combobox); + gtk_combo_box_get_active_iter (combobox, &iter); + + data.chooser = chooser; + data.account = account; + + gtk_tree_model_foreach (model, + (GtkTreeModelForeachFunc) account_chooser_set_account_foreach, + &data); + + return data.set; +} + +gboolean +empathy_account_chooser_get_can_select_all (EmpathyAccountChooser *chooser) +{ + EmpathyAccountChooserPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), FALSE); + + priv = GET_PRIV (chooser); + + return priv->can_select_all; +} + +void +empathy_account_chooser_set_can_select_all (EmpathyAccountChooser *chooser, + gboolean can_select_all) +{ + EmpathyAccountChooserPriv *priv; + GtkComboBox *combobox; + GtkTreeModel *model; + + g_return_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser)); + + priv = GET_PRIV (chooser); + + if (priv->can_select_all == can_select_all) { + return; + } + + combobox = GTK_COMBO_BOX (chooser); + model = gtk_combo_box_get_model (combobox); + + priv->can_select_all = can_select_all; + + gtk_tree_model_foreach (model, + (GtkTreeModelForeachFunc) account_chooser_set_enabled_foreach, + chooser); + + g_object_notify (G_OBJECT (chooser), "can-select-all"); +} + +gboolean +empathy_account_chooser_get_has_all_option (EmpathyAccountChooser *chooser) +{ + EmpathyAccountChooserPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), FALSE); + + priv = GET_PRIV (chooser); + + return priv->has_all_option; +} + +void +empathy_account_chooser_set_has_all_option (EmpathyAccountChooser *chooser, + gboolean has_all_option) +{ + EmpathyAccountChooserPriv *priv; + GtkComboBox *combobox; + GtkListStore *store; + GtkTreeModel *model; + GtkTreeIter iter; + + g_return_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser)); + + priv = GET_PRIV (chooser); + + if (priv->has_all_option == has_all_option) { + return; + } + + combobox = GTK_COMBO_BOX (chooser); + model = gtk_combo_box_get_model (combobox); + store = GTK_LIST_STORE (model); + + priv->has_all_option = has_all_option; + + /* + * The first 2 options are the ALL and separator + */ + + if (has_all_option) { + gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser), + (GtkTreeViewRowSeparatorFunc) + account_chooser_separator_func, + chooser, + NULL); + + gtk_list_store_prepend (store, &iter); + gtk_list_store_set (store, &iter, + COL_ACCOUNT_TEXT, NULL, + COL_ACCOUNT_ENABLED, TRUE, + COL_ACCOUNT_POINTER, NULL, + -1); + + gtk_list_store_prepend (store, &iter); + gtk_list_store_set (store, &iter, + COL_ACCOUNT_TEXT, _("All"), + COL_ACCOUNT_ENABLED, TRUE, + COL_ACCOUNT_POINTER, NULL, + -1); + } else { + if (gtk_tree_model_get_iter_first (model, &iter)) { + if (gtk_list_store_remove (GTK_LIST_STORE (model), &iter)) { + gtk_list_store_remove (GTK_LIST_STORE (model), &iter); + } + } + + gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser), + (GtkTreeViewRowSeparatorFunc) + NULL, + NULL, + NULL); + } + + g_object_notify (G_OBJECT (chooser), "has-all-option"); +} + +static void +account_chooser_setup (EmpathyAccountChooser *chooser) +{ + EmpathyAccountChooserPriv *priv; + GList *accounts; + GtkListStore *store; + GtkCellRenderer *renderer; + GtkComboBox *combobox; + + priv = GET_PRIV (chooser); + + /* Set up combo box with new store */ + combobox = GTK_COMBO_BOX (chooser); + + gtk_cell_layout_clear (GTK_CELL_LAYOUT (combobox)); + + store = gtk_list_store_new (COL_ACCOUNT_COUNT, + G_TYPE_STRING, + G_TYPE_STRING, /* Name */ + G_TYPE_BOOLEAN, /* Enabled */ + MC_TYPE_ACCOUNT); + + gtk_combo_box_set_model (combobox, GTK_TREE_MODEL (store)); + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, FALSE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer, + "icon-name", COL_ACCOUNT_IMAGE, + "sensitive", COL_ACCOUNT_ENABLED, + NULL); + g_object_set (renderer, "stock-size", GTK_ICON_SIZE_BUTTON, NULL); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer, + "text", COL_ACCOUNT_TEXT, + "sensitive", COL_ACCOUNT_ENABLED, + NULL); + + /* Populate accounts */ + accounts = mc_accounts_list (); + g_list_foreach (accounts, + (GFunc) account_chooser_account_add_foreach, + chooser); + + mc_accounts_list_free (accounts); + g_object_unref (store); +} + +static void +account_chooser_account_created_cb (McAccountMonitor *monitor, + const gchar *unique_name, + EmpathyAccountChooser *chooser) +{ + McAccount *account; + + account = mc_account_lookup (unique_name); + account_chooser_account_add_foreach (account, chooser); + g_object_unref (account); +} + +static void +account_chooser_account_add_foreach (McAccount *account, + EmpathyAccountChooser *chooser) +{ + EmpathyAccountChooserPriv *priv; + GtkListStore *store; + GtkComboBox *combobox; + GtkTreeIter iter; + + priv = GET_PRIV (chooser); + + combobox = GTK_COMBO_BOX (chooser); + store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox)); + + gtk_list_store_append (store, &iter); + account_chooser_update_iter (chooser, &iter, account); +} + +static void +account_chooser_account_deleted_cb (McAccountMonitor *monitor, + const gchar *unique_name, + EmpathyAccountChooser *chooser) +{ + McAccount *account; + + account = mc_account_lookup (unique_name); + account_chooser_account_remove_foreach (account, chooser); + g_object_unref (account); +} + +static void +account_chooser_account_remove_foreach (McAccount *account, + EmpathyAccountChooser *chooser) +{ + /* Fixme: TODO */ +} + +static void +account_chooser_update_iter (EmpathyAccountChooser *chooser, + GtkTreeIter *iter, + McAccount *account) +{ + EmpathyAccountChooserPriv *priv; + GtkListStore *store; + GtkComboBox *combobox; + TpConn *tp_conn; + const gchar *icon_name; + gboolean is_enabled; + + priv = GET_PRIV (chooser); + + combobox = GTK_COMBO_BOX (chooser); + store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox)); + + icon_name = empathy_icon_name_from_account (account); + tp_conn = mission_control_get_connection (priv->mc, account, NULL); + is_enabled = (tp_conn != NULL || priv->can_select_all); + + if (tp_conn) { + g_object_unref (tp_conn); + } + + gtk_list_store_set (store, iter, + COL_ACCOUNT_IMAGE, icon_name, + COL_ACCOUNT_TEXT, mc_account_get_display_name (account), + COL_ACCOUNT_ENABLED, is_enabled, + COL_ACCOUNT_POINTER, account, + -1); + + /* set first connected account as active account */ + if (priv->set_active_item == FALSE && is_enabled) { + priv->set_active_item = TRUE; + gtk_combo_box_set_active_iter (combobox, iter); + } +} + +static void +account_chooser_status_changed_cb (MissionControl *mc, + TelepathyConnectionStatus status, + McPresence presence, + TelepathyConnectionStatusReason reason, + const gchar *unique_name, + EmpathyAccountChooser *chooser) +{ + /* FIXME: implement */ +} + +static gboolean +account_chooser_separator_func (GtkTreeModel *model, + GtkTreeIter *iter, + EmpathyAccountChooser *chooser) +{ + EmpathyAccountChooserPriv *priv; + gchar *text; + gboolean is_separator; + + priv = GET_PRIV (chooser); + + if (!priv->has_all_option) { + return FALSE; + } + + gtk_tree_model_get (model, iter, COL_ACCOUNT_TEXT, &text, -1); + is_separator = text == NULL; + g_free (text); + + return is_separator; +} + +static gboolean +account_chooser_set_account_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + SetAccountData *data) +{ + McAccount *account; + gboolean equal; + + gtk_tree_model_get (model, iter, COL_ACCOUNT_POINTER, &account, -1); + + /* Special case so we can make it possible to select the All option */ + if (!data->account && !account) { + equal = TRUE; + } + else if ((data->account && !account) || (!data->account && account)) { + equal = FALSE; + } else { + equal = empathy_account_equal (data->account, account); + g_object_unref (account); + } + + if (equal) { + GtkComboBox *combobox; + + combobox = GTK_COMBO_BOX (data->chooser); + gtk_combo_box_set_active_iter (combobox, iter); + + data->set = TRUE; + } + + return equal; +} + +static gboolean +account_chooser_set_enabled_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + EmpathyAccountChooser *chooser) +{ + EmpathyAccountChooserPriv *priv; + McAccount *account; + + priv = GET_PRIV (chooser); + + gtk_tree_model_get (model, iter, COL_ACCOUNT_POINTER, &account, -1); + if (!account) { + return FALSE; + } + + account_chooser_update_iter (chooser, iter, account); + g_object_unref (account); + + return FALSE; +} + diff --git a/libempathy-gtk/empathy-account-chooser.h b/libempathy-gtk/empathy-account-chooser.h new file mode 100644 index 00000000..8d9cb657 --- /dev/null +++ b/libempathy-gtk/empathy-account-chooser.h @@ -0,0 +1,66 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2005-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Martyn Russell + */ + +#ifndef __EMPATHY_ACCOUNT_CHOOSER_H__ +#define __EMPATHY_ACCOUNT_CHOOSER_H__ + +#include + +#include + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_ACCOUNT_CHOOSER (empathy_account_chooser_get_type ()) +#define EMPATHY_ACCOUNT_CHOOSER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_ACCOUNT_CHOOSER, EmpathyAccountChooser)) +#define EMPATHY_ACCOUNT_CHOOSER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_ACCOUNT_CHOOSER, EmpathyAccountChooserClass)) +#define EMPATHY_IS_ACCOUNT_CHOOSER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_ACCOUNT_CHOOSER)) +#define EMPATHY_IS_ACCOUNT_CHOOSER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_ACCOUNT_CHOOSER)) +#define EMPATHY_ACCOUNT_CHOOSER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_ACCOUNT_CHOOSER, EmpathyAccountChooserClass)) + +typedef struct _EmpathyAccountChooser EmpathyAccountChooser; +typedef struct _EmpathyAccountChooserClass EmpathyAccountChooserClass; + +struct _EmpathyAccountChooser { + GtkComboBox parent; +}; + +struct _EmpathyAccountChooserClass { + GtkComboBoxClass parent_class; +}; + +GType empathy_account_chooser_get_type (void) G_GNUC_CONST; +GtkWidget * empathy_account_chooser_new (void); +McAccount * empathy_account_chooser_get_account (EmpathyAccountChooser *chooser); +gboolean empathy_account_chooser_set_account (EmpathyAccountChooser *chooser, + McAccount *account); +gboolean empathy_account_chooser_get_can_select_all (EmpathyAccountChooser *chooser); + +void empathy_account_chooser_set_can_select_all (EmpathyAccountChooser *chooser, + gboolean can_select_all); +gboolean empathy_account_chooser_get_has_all_option (EmpathyAccountChooser *chooser); +void empathy_account_chooser_set_has_all_option (EmpathyAccountChooser *chooser, + gboolean has_all_option); + +G_END_DECLS + +#endif /* __EMPATHY_ACCOUNT_CHOOSER_H__ */ + diff --git a/libempathy-gtk/empathy-account-widget-generic.c b/libempathy-gtk/empathy-account-widget-generic.c new file mode 100644 index 00000000..4f9ea03b --- /dev/null +++ b/libempathy-gtk/empathy-account-widget-generic.c @@ -0,0 +1,310 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Xavier Claessens + * Martyn Russell + */ + +#include + +#include + +#include +#include + +#include +#include + +#include + +#include "empathy-account-widget-generic.h" + +typedef struct { + McAccount *account; + + GtkWidget *sw; + GtkWidget *table_settings; + GtkSizeGroup *size_group; + + guint n_rows; +} EmpathyAccountWidgetGeneric; + +static gboolean account_widget_generic_entry_focus_cb (GtkWidget *widget, + GdkEventFocus *event, + EmpathyAccountWidgetGeneric *settings); +static void account_widget_generic_int_changed_cb (GtkWidget *widget, + EmpathyAccountWidgetGeneric *settings); +static void account_widget_generic_checkbutton_toggled_cb (GtkWidget *widget, + EmpathyAccountWidgetGeneric *settings); +static gchar * account_widget_generic_format_param_name (const gchar *param_name); +static void account_widget_generic_setup_foreach (McProtocolParam *param, + EmpathyAccountWidgetGeneric *settings); +static void account_widget_generic_destroy_cb (GtkWidget *widget, + EmpathyAccountWidgetGeneric *settings); + +static gboolean +account_widget_generic_entry_focus_cb (GtkWidget *widget, + GdkEventFocus *event, + EmpathyAccountWidgetGeneric *settings) +{ + const gchar *str; + const gchar *param_name; + + str = gtk_entry_get_text (GTK_ENTRY (widget)); + param_name = g_object_get_data (G_OBJECT (widget), "param_name"); + + mc_account_set_param_string (settings->account, param_name, str); + + return FALSE; +} + +static void +account_widget_generic_int_changed_cb (GtkWidget *widget, + EmpathyAccountWidgetGeneric *settings) +{ + const gchar *param_name; + gint value; + + value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (widget)); + param_name = g_object_get_data (G_OBJECT (widget), "param_name"); + + mc_account_set_param_int (settings->account, param_name, value); +} + +static void +account_widget_generic_checkbutton_toggled_cb (GtkWidget *widget, + EmpathyAccountWidgetGeneric *settings) +{ + gboolean active; + const gchar *param_name; + + active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + param_name = g_object_get_data (G_OBJECT (widget), "param_name"); + + mc_account_set_param_boolean (settings->account, param_name, active); +} + +static gchar * +account_widget_generic_format_param_name (const gchar *param_name) +{ + gchar *str; + gchar *p; + + str = g_strdup (param_name); + + if (str && g_ascii_isalpha (str[0])) { + str[0] = g_ascii_toupper (str[0]); + } + + while ((p = strchr (str, '-')) != NULL) { + if (p[1] != '\0' && g_ascii_isalpha (p[1])) { + p[0] = ' '; + p[1] = g_ascii_toupper (p[1]); + } + + p++; + } + + return str; +} + +static void +account_widget_generic_setup_foreach (McProtocolParam *param, + EmpathyAccountWidgetGeneric *settings) +{ + GtkWidget *widget; + gchar *param_name_formatted; + + param_name_formatted = account_widget_generic_format_param_name (param->name); + + gtk_table_resize (GTK_TABLE (settings->table_settings), + ++settings->n_rows, + 2); + + if (param->signature[0] == 's') { + gchar *str = NULL; + + str = g_strdup_printf (_("%s:"), param_name_formatted); + widget = gtk_label_new (str); + g_free (str); + + gtk_size_group_add_widget (settings->size_group, widget); + gtk_table_attach (GTK_TABLE (settings->table_settings), + widget, + 0, 1, + settings->n_rows - 1, settings->n_rows, + GTK_FILL, 0, + 0, 0); + + str = NULL; + widget = gtk_entry_new (); + mc_account_get_param_string (settings->account, + param->name, + &str); + if (str) { + gtk_entry_set_text (GTK_ENTRY (widget), str); + g_free (str); + } + + if (strstr (param->name, "password")) { + gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE); + } + + g_signal_connect (widget, "focus-out-event", + G_CALLBACK (account_widget_generic_entry_focus_cb), + settings); + + gtk_table_attach (GTK_TABLE (settings->table_settings), + widget, + 1, 2, + settings->n_rows - 1, settings->n_rows, + GTK_FILL | GTK_EXPAND, 0, + 0, 0); + } + else if (param->signature[0] == 'q' || + param->signature[0] == 'n') { + gchar *str = NULL; + gint value = 0; + + str = g_strdup_printf (_("%s:"), param_name_formatted); + widget = gtk_label_new (str); + g_free (str); + + gtk_size_group_add_widget (settings->size_group, widget); + gtk_table_attach (GTK_TABLE (settings->table_settings), + widget, + 0, 1, + settings->n_rows - 1, settings->n_rows, + GTK_FILL, 0, + 0, 0); + + widget = gtk_spin_button_new_with_range (0, G_MAXINT, 1); + mc_account_get_param_int (settings->account, + param->name, + &value); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value); + + g_signal_connect (widget, "value-changed", + G_CALLBACK (account_widget_generic_int_changed_cb), + settings); + + gtk_table_attach (GTK_TABLE (settings->table_settings), + widget, + 1, 2, + settings->n_rows - 1, settings->n_rows, + GTK_FILL | GTK_EXPAND, 0, + 0, 0); + } + else if (param->signature[0] == 'b') { + gboolean value = FALSE; + + mc_account_get_param_boolean (settings->account, + param->name, + &value); + + widget = gtk_check_button_new_with_label (param_name_formatted); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), value); + + g_signal_connect (widget, "toggled", + G_CALLBACK (account_widget_generic_checkbutton_toggled_cb), + settings); + + gtk_table_attach (GTK_TABLE (settings->table_settings), + widget, + 0, 2, + settings->n_rows - 1, settings->n_rows, + GTK_FILL | GTK_EXPAND, 0, + 0, 0); + } else { + g_assert_not_reached (); + } + + g_free (param_name_formatted); + + g_object_set_data_full (G_OBJECT (widget), "param_name", + g_strdup (param->name), g_free); +} + +static void +accounts_widget_generic_setup (EmpathyAccountWidgetGeneric *settings) +{ + McProtocol *protocol; + McProfile *profile; + GSList *params; + + profile = mc_account_get_profile (settings->account); + protocol = mc_profile_get_protocol (profile); + params = mc_protocol_get_params (protocol); + + g_slist_foreach (params, + (GFunc) account_widget_generic_setup_foreach, + settings); + + g_slist_free (params); +} + +static void +account_widget_generic_destroy_cb (GtkWidget *widget, + EmpathyAccountWidgetGeneric *settings) +{ + g_object_unref (settings->account); + g_object_unref (settings->size_group); + + g_free (settings); +} + +GtkWidget * +empathy_account_widget_generic_new (McAccount *account, + GtkWidget *label_name) +{ + EmpathyAccountWidgetGeneric *settings; + + g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + g_return_val_if_fail (GTK_IS_WIDGET (label_name), NULL); + + settings = g_new0 (EmpathyAccountWidgetGeneric, 1); + + settings->account = g_object_ref (account); + + settings->table_settings = gtk_table_new (0, 2, FALSE); + gtk_table_set_row_spacings (GTK_TABLE (settings->table_settings), 6); + gtk_table_set_col_spacings (GTK_TABLE (settings->table_settings), 6); + settings->sw = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (settings->sw), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (settings->sw), + settings->table_settings); + + settings->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + if (label_name) { + gtk_size_group_add_widget (settings->size_group, label_name); + } + + accounts_widget_generic_setup (settings); + + g_signal_connect (settings->sw, "destroy", + G_CALLBACK (account_widget_generic_destroy_cb), + settings); + + gtk_widget_show_all (settings->sw); + + return settings->sw; +} diff --git a/libempathy-gtk/empathy-account-widget-generic.h b/libempathy-gtk/empathy-account-widget-generic.h new file mode 100644 index 00000000..e26c72e8 --- /dev/null +++ b/libempathy-gtk/empathy-account-widget-generic.h @@ -0,0 +1,39 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Xavier Claessens + * Martyn Russell + */ + +#ifndef __EMPATHY_ACCOUNT_WIDGET_GENERIC_H__ +#define __EMPATHY_ACCOUNT_WIDGET_GENERIC_H__ + +#include + +#include + +G_BEGIN_DECLS + +GtkWidget *empathy_account_widget_generic_new (McAccount *account, + GtkWidget *label_name); + +G_END_DECLS + +#endif /* __EMPATHY_ACCOUNT_WIDGET_GENERIC_H__ */ diff --git a/libempathy-gtk/empathy-account-widget-jabber.c b/libempathy-gtk/empathy-account-widget-jabber.c new file mode 100644 index 00000000..2e5a4871 --- /dev/null +++ b/libempathy-gtk/empathy-account-widget-jabber.c @@ -0,0 +1,281 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Xavier Claessens + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include "empathy-account-widget-jabber.h" +#include "empathy-ui-utils.h" + +#define PORT_WITHOUT_SSL 5222 +#define PORT_WITH_SSL 5223 + +typedef struct { + McAccount *account; + + GtkWidget *vbox_settings; + GtkWidget *button_forget; + GtkWidget *entry_id; + GtkWidget *entry_password; + GtkWidget *entry_resource; + GtkWidget *entry_server; + GtkWidget *spinbutton_port; + GtkWidget *checkbutton_ssl; +} EmpathyAccountWidgetJabber; + +static gboolean account_widget_jabber_entry_focus_cb (GtkWidget *widget, + GdkEventFocus *event, + EmpathyAccountWidgetJabber *settings); +static void account_widget_jabber_entry_changed_cb (GtkWidget *widget, + EmpathyAccountWidgetJabber *settings); +static void account_widget_jabber_checkbutton_toggled_cb (GtkWidget *widget, + EmpathyAccountWidgetJabber *settings); +static void account_widget_jabber_value_changed_cb (GtkWidget *spinbutton, + EmpathyAccountWidgetJabber *settings); +static void account_widget_jabber_button_forget_clicked_cb (GtkWidget *button, + EmpathyAccountWidgetJabber *settings); +static void account_widget_jabber_destroy_cb (GtkWidget *widget, + EmpathyAccountWidgetJabber *settings); +static void account_widget_jabber_setup (EmpathyAccountWidgetJabber *settings); + +static gboolean +account_widget_jabber_entry_focus_cb (GtkWidget *widget, + GdkEventFocus *event, + EmpathyAccountWidgetJabber *settings) +{ + const gchar *param; + const gchar *str; + + if (widget == settings->entry_password) { + param = "password"; + } + else if (widget == settings->entry_resource) { + param = "resource"; + } + else if (widget == settings->entry_server) { + param = "server"; + } + else if (widget == settings->entry_id) { + param = "account"; + } else { + return FALSE; + } + + str = gtk_entry_get_text (GTK_ENTRY (widget)); + if (G_STR_EMPTY (str)) { + gchar *value = NULL; + + mc_account_get_param_string (settings->account, param, &value); + gtk_entry_set_text (GTK_ENTRY (widget), value ? value : ""); + g_free (value); + } else { + mc_account_set_param_string (settings->account, param, str); + } + + return FALSE; +} + +static void +account_widget_jabber_entry_changed_cb (GtkWidget *widget, + EmpathyAccountWidgetJabber *settings) +{ + if (widget == settings->entry_password) { + const gchar *str; + + str = gtk_entry_get_text (GTK_ENTRY (widget)); + gtk_widget_set_sensitive (settings->button_forget, !G_STR_EMPTY (str)); + } +} + +static void +account_widget_jabber_checkbutton_toggled_cb (GtkWidget *widget, + EmpathyAccountWidgetJabber *settings) +{ + if (widget == settings->checkbutton_ssl) { + gint port = 0; + gboolean old_ssl; + + mc_account_get_param_int (settings->account, "port", &port); + old_ssl = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if (old_ssl) { + if (port == PORT_WITHOUT_SSL) { + port = PORT_WITH_SSL; + } + } else { + if (port == PORT_WITH_SSL) { + port = PORT_WITHOUT_SSL; + } + } + + mc_account_set_param_int (settings->account, "port", port); + mc_account_set_param_boolean (settings->account, "old-ssl", old_ssl); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (settings->spinbutton_port), port); + } +} + +static void +account_widget_jabber_value_changed_cb (GtkWidget *spinbutton, + EmpathyAccountWidgetJabber *settings) +{ + if (spinbutton == settings->spinbutton_port) { + gdouble value; + + value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (spinbutton)); + mc_account_set_param_int (settings->account, "port", (gint) value); + } +} + +static void +account_widget_jabber_button_forget_clicked_cb (GtkWidget *button, + EmpathyAccountWidgetJabber *settings) +{ + mc_account_set_param_string (settings->account, "password", ""); + gtk_entry_set_text (GTK_ENTRY (settings->entry_password), ""); +} + +static void +account_widget_jabber_destroy_cb (GtkWidget *widget, + EmpathyAccountWidgetJabber *settings) +{ + g_object_unref (settings->account); + g_free (settings); +} + +static void +account_widget_jabber_setup (EmpathyAccountWidgetJabber *settings) +{ + gint port = 0; + gchar *id = NULL; + gchar *resource = NULL; + gchar *server = NULL; + gchar *password = NULL; + gboolean old_ssl = FALSE; + + mc_account_get_param_int (settings->account, "port", &port); + mc_account_get_param_string (settings->account, "account", &id); + mc_account_get_param_string (settings->account, "resource", &resource); + mc_account_get_param_string (settings->account, "server", &server); + mc_account_get_param_string (settings->account, "password", &password); + mc_account_get_param_boolean (settings->account, "old-ssl", &old_ssl); + + if (!id) { + McProfile *profile; + const gchar *server; + + profile = mc_account_get_profile (settings->account); + server = mc_profile_get_default_account_domain (profile); + if (server) { + id = g_strconcat ("user@", server, NULL); + } + g_object_unref (profile); + } + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (settings->checkbutton_ssl), old_ssl); + gtk_entry_set_text (GTK_ENTRY (settings->entry_id), id ? id : ""); + gtk_entry_set_text (GTK_ENTRY (settings->entry_password), password ? password : ""); + gtk_entry_set_text (GTK_ENTRY (settings->entry_resource), resource ? resource : ""); + gtk_entry_set_text (GTK_ENTRY (settings->entry_server), server ? server : ""); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (settings->spinbutton_port), port); + + gtk_widget_set_sensitive (settings->button_forget, !G_STR_EMPTY (password)); + + g_free (id); + g_free (resource); + g_free (server); + g_free (password); +} + +GtkWidget * +empathy_account_widget_jabber_new (McAccount *account) +{ + EmpathyAccountWidgetJabber *settings; + GladeXML *glade; + GtkSizeGroup *size_group; + GtkWidget *label_id, *label_password; + GtkWidget *label_server, *label_resource, *label_port; + + settings = g_new0 (EmpathyAccountWidgetJabber, 1); + settings->account = g_object_ref (account); + + glade = empathy_glade_get_file ("empathy-account-widget-jabber.glade", + "vbox_jabber_settings", + NULL, + "vbox_jabber_settings", &settings->vbox_settings, + "button_forget", &settings->button_forget, + "label_id", &label_id, + "label_password", &label_password, + "label_resource", &label_resource, + "label_server", &label_server, + "label_port", &label_port, + "entry_id", &settings->entry_id, + "entry_password", &settings->entry_password, + "entry_resource", &settings->entry_resource, + "entry_server", &settings->entry_server, + "spinbutton_port", &settings->spinbutton_port, + "checkbutton_ssl", &settings->checkbutton_ssl, + NULL); + + account_widget_jabber_setup (settings); + + empathy_glade_connect (glade, + settings, + "vbox_jabber_settings", "destroy", account_widget_jabber_destroy_cb, + "button_forget", "clicked", account_widget_jabber_button_forget_clicked_cb, + "entry_password", "changed", account_widget_jabber_entry_changed_cb, + "spinbutton_port", "value-changed", account_widget_jabber_value_changed_cb, + "entry_id", "focus-out-event", account_widget_jabber_entry_focus_cb, + "entry_password", "focus-out-event", account_widget_jabber_entry_focus_cb, + "entry_resource", "focus-out-event", account_widget_jabber_entry_focus_cb, + "entry_server", "focus-out-event", account_widget_jabber_entry_focus_cb, + "checkbutton_ssl", "toggled", account_widget_jabber_checkbutton_toggled_cb, + NULL); + + g_object_unref (glade); + + /* Set up remaining widgets */ + size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + + gtk_size_group_add_widget (size_group, label_id); + gtk_size_group_add_widget (size_group, label_password); + gtk_size_group_add_widget (size_group, label_resource); + gtk_size_group_add_widget (size_group, label_server); + gtk_size_group_add_widget (size_group, label_port); + + g_object_unref (size_group); + + gtk_widget_show (settings->vbox_settings); + + return settings->vbox_settings; +} + diff --git a/libempathy-gtk/empathy-account-widget-jabber.glade b/libempathy-gtk/empathy-account-widget-jabber.glade new file mode 100644 index 00000000..12eec757 --- /dev/null +++ b/libempathy-gtk/empathy-account-widget-jabber.glade @@ -0,0 +1,335 @@ + + + + + + + True + jabber account settings + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + False + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 6 + 3 + False + 6 + 12 + + + + True + Login I_D: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + entry_id + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + Pass_word: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + entry_password + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + Reso_urce: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + entry_resource + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + _Server: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + entry_server + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 3 + 4 + fill + + + + + + + True + _Port: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + spinbutton_port + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 4 + 5 + fill + + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 3 + 2 + 3 + + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 3 + 3 + 4 + + + + + + + True + True + Use encryption (SS_L) + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 3 + 5 + 6 + fill + + + + + + + True + True + 1 + 0 + True + GTK_UPDATE_ALWAYS + False + False + 5222 0 65556 1 10 10 + + + 1 + 3 + 4 + 5 + + + + + + + True + Forget password and clear the entry. + True + GTK_RELIEF_NORMAL + True + + + + True + gtk-clear + 1 + 0.5 + 0.5 + 0 + 0 + + + + + 2 + 3 + 1 + 2 + fill + + + + + + + True + True + True + False + 0 + + True + * + False + + + 1 + 2 + 1 + 2 + + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 3 + 0 + 1 + + + + + + + + diff --git a/libempathy-gtk/empathy-account-widget-jabber.h b/libempathy-gtk/empathy-account-widget-jabber.h new file mode 100644 index 00000000..99205c9a --- /dev/null +++ b/libempathy-gtk/empathy-account-widget-jabber.h @@ -0,0 +1,34 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Xavier Claessens + */ + +#ifndef __EMPATHY_ACCOUNT_WIDGET_JABBER_H__ +#define __EMPATHY_ACCOUNT_WIDGET_JABBER_H__ + +#include + +G_BEGIN_DECLS + +GtkWidget *empathy_account_widget_jabber_new (McAccount *account); + +G_END_DECLS + +#endif /* __EMPATHY_ACCOUNT_WIDGET_JABBER_H__ */ diff --git a/libempathy-gtk/empathy-accounts-dialog.c b/libempathy-gtk/empathy-accounts-dialog.c new file mode 100644 index 00000000..0e5f909c --- /dev/null +++ b/libempathy-gtk/empathy-accounts-dialog.c @@ -0,0 +1,1037 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2005-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Martyn Russell + * Xavier Claessens + */ + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "empathy-accounts-dialog.h" +#include "empathy-profile-chooser.h" +#include "empathy-account-widget-generic.h" +#include "empathy-account-widget-jabber.h" + +#define DEBUG_DOMAIN "AccountDialog" + +/* Flashing delay for icons (milliseconds). */ +#define FLASH_TIMEOUT 500 + +typedef struct { + GtkWidget *window; + + GtkWidget *alignment_settings; + + GtkWidget *vbox_details; + GtkWidget *frame_no_account; + GtkWidget *label_no_account; + GtkWidget *label_no_account_blurb; + + GtkWidget *treeview; + + GtkWidget *button_remove; + GtkWidget *button_connect; + + GtkWidget *frame_new_account; + GtkWidget *combobox_profile; + GtkWidget *entry_name; + GtkWidget *table_new_account; + GtkWidget *button_create; + GtkWidget *button_back; + + GtkWidget *image_type; + GtkWidget *label_name; + GtkWidget *label_type; + GtkWidget *settings_widget; + + gboolean connecting_show; + guint connecting_id; + gboolean account_changed; + + MissionControl *mc; + McAccountMonitor *monitor; +} EmpathyAccountsDialog; + +enum { + COL_NAME, + COL_STATUS, + COL_ACCOUNT_POINTER, + COL_COUNT +}; + +static void accounts_dialog_setup (EmpathyAccountsDialog *dialog); +static void accounts_dialog_update_account (EmpathyAccountsDialog *dialog, + McAccount *account); +static void accounts_dialog_model_setup (EmpathyAccountsDialog *dialog); +static void accounts_dialog_model_add_columns (EmpathyAccountsDialog *dialog); +static void accounts_dialog_model_select_first (EmpathyAccountsDialog *dialog); +static void accounts_dialog_model_pixbuf_data_func (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + EmpathyAccountsDialog *dialog); +static McAccount *accounts_dialog_model_get_selected (EmpathyAccountsDialog *dialog); +static void accounts_dialog_model_set_selected (EmpathyAccountsDialog *dialog, + McAccount *account); +static gboolean accounts_dialog_model_remove_selected (EmpathyAccountsDialog *dialog); +static void accounts_dialog_model_selection_changed (GtkTreeSelection *selection, + EmpathyAccountsDialog *dialog); +static void accounts_dialog_add_account (EmpathyAccountsDialog *dialog, + McAccount *account); +static void accounts_dialog_account_added_cb (McAccountMonitor *monitor, + gchar *unique_name, + EmpathyAccountsDialog *dialog); +static void accounts_dialog_account_removed_cb (McAccountMonitor *monitor, + gchar *unique_name, + EmpathyAccountsDialog *dialog); +static gboolean accounts_dialog_row_changed_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data); +static gboolean accounts_dialog_flash_connecting_cb (EmpathyAccountsDialog *dialog); +static void accounts_dialog_status_changed_cb (MissionControl *mc, + TelepathyConnectionStatus status, + McPresence presence, + TelepathyConnectionStatusReason reason, + const gchar *unique_name, + EmpathyAccountsDialog *dialog); +static void accounts_dialog_entry_name_changed_cb (GtkWidget *widget, + EmpathyAccountsDialog *dialog); +static void accounts_dialog_button_create_clicked_cb (GtkWidget *button, + EmpathyAccountsDialog *dialog); +static void accounts_dialog_button_back_clicked_cb (GtkWidget *button, + EmpathyAccountsDialog *dialog); +static void accounts_dialog_button_connect_clicked_cb (GtkWidget *button, + EmpathyAccountsDialog *dialog); +static void accounts_dialog_button_add_clicked_cb (GtkWidget *button, + EmpathyAccountsDialog *dialog); +static void accounts_dialog_remove_response_cb (GtkWidget *dialog, + gint response, + McAccount *account); +static void accounts_dialog_button_remove_clicked_cb (GtkWidget *button, + EmpathyAccountsDialog *dialog); +static void accounts_dialog_treeview_row_activated_cb (GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + EmpathyAccountsDialog *dialog); +static void accounts_dialog_response_cb (GtkWidget *widget, + gint response, + EmpathyAccountsDialog *dialog); +static void accounts_dialog_destroy_cb (GtkWidget *widget, + EmpathyAccountsDialog *dialog); + +static void +accounts_dialog_setup (EmpathyAccountsDialog *dialog) +{ + GtkTreeView *view; + GtkListStore *store; + GtkTreeSelection *selection; + GtkTreeIter iter; + GList *accounts, *l; + + view = GTK_TREE_VIEW (dialog->treeview); + store = GTK_LIST_STORE (gtk_tree_view_get_model (view)); + selection = gtk_tree_view_get_selection (view); + + accounts = mc_accounts_list (); + + for (l = accounts; l; l = l->next) { + McAccount *account; + const gchar *name; + TelepathyConnectionStatus status; + + account = l->data; + + name = mc_account_get_display_name (account); + if (!name) { + continue; + } + + status = mission_control_get_connection_status (dialog->mc, account, NULL); + + gtk_list_store_insert_with_values (store, &iter, + -1, + COL_NAME, name, + COL_STATUS, status, + COL_ACCOUNT_POINTER, account, + -1); + + accounts_dialog_status_changed_cb (dialog->mc, + status, + MC_PRESENCE_UNSET, + TP_CONN_STATUS_REASON_NONE_SPECIFIED, + mc_account_get_unique_name (account), + dialog); + + g_object_unref (account); + } + + g_list_free (accounts); +} + +static void +accounts_dialog_update_connect_button (EmpathyAccountsDialog *dialog) +{ + McAccount *account; + GtkWidget *image; + const gchar *stock_id; + const gchar *label; + + account = accounts_dialog_model_get_selected (dialog); + + if (!account) { + gtk_widget_set_sensitive (dialog->button_connect, FALSE); + return; + } + + if (mc_account_is_enabled (account)) { + label = _("Disable"); + stock_id = GTK_STOCK_DISCONNECT; + } else { + label = _("Enable"); + stock_id = GTK_STOCK_CONNECT; + } + + image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON); + + gtk_button_set_label (GTK_BUTTON (dialog->button_connect), label); + gtk_button_set_image (GTK_BUTTON (dialog->button_connect), image); +} + +static void +accounts_dialog_update_account (EmpathyAccountsDialog *dialog, + McAccount *account) +{ + if (dialog->settings_widget) { + gtk_widget_destroy (dialog->settings_widget); + dialog->settings_widget = NULL; + } + + if (!account) { + GtkTreeView *view; + GtkTreeModel *model; + + gtk_widget_show (dialog->frame_no_account); + gtk_widget_hide (dialog->vbox_details); + + gtk_widget_set_sensitive (dialog->button_connect, FALSE); + gtk_widget_set_sensitive (dialog->button_remove, FALSE); + + view = GTK_TREE_VIEW (dialog->treeview); + model = gtk_tree_view_get_model (view); + + if (gtk_tree_model_iter_n_children (model, NULL) > 0) { + gtk_label_set_markup (GTK_LABEL (dialog->label_no_account), + _("No Account Selected")); + gtk_label_set_markup (GTK_LABEL (dialog->label_no_account_blurb), + _("To add a new account, you can click on the " + "'Add' button and a new entry will be created " + "for you to start configuring.\n" + "\n" + "If you do not want to add an account, simply " + "click on the account you want to configure in " + "the list on the left.")); + } else { + gtk_label_set_markup (GTK_LABEL (dialog->label_no_account), + _("No Accounts Configured")); + gtk_label_set_markup (GTK_LABEL (dialog->label_no_account_blurb), + _("To add a new account, you can click on the " + "'Add' button and a new entry will be created " + "for you to start configuring.")); + } + } else { + McProfile *profile; + const gchar *config_ui; + + gtk_widget_hide (dialog->frame_no_account); + gtk_widget_show (dialog->vbox_details); + + profile = mc_account_get_profile (account); + config_ui = mc_profile_get_configuration_ui (profile); + + if (strcmp (config_ui, "jabber") == 0) { + dialog->settings_widget = + empathy_account_widget_jabber_new (account); + } else { + dialog->settings_widget = + empathy_account_widget_generic_new (account, + dialog->label_name); + } + + gtk_widget_grab_focus (dialog->settings_widget); + } + + if (dialog->settings_widget) { + gtk_container_add (GTK_CONTAINER (dialog->alignment_settings), + dialog->settings_widget); + } + + if (account) { + McProfile *profile; + + profile = mc_account_get_profile (account); + gtk_image_set_from_icon_name (GTK_IMAGE (dialog->image_type), + mc_profile_get_icon_name (profile), + GTK_ICON_SIZE_DIALOG); + + + gtk_label_set_text (GTK_LABEL (dialog->label_type), + mc_profile_get_display_name (profile)); + gtk_label_set_text (GTK_LABEL (dialog->label_name), + mc_account_get_display_name (account)); + } +} + +static void +accounts_dialog_model_setup (EmpathyAccountsDialog *dialog) +{ + GtkListStore *store; + GtkTreeSelection *selection; + + store = gtk_list_store_new (COL_COUNT, + G_TYPE_STRING, /* name */ + G_TYPE_UINT, /* status */ + MC_TYPE_ACCOUNT); /* account */ + + gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->treeview), + GTK_TREE_MODEL (store)); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->treeview)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + + g_signal_connect (selection, "changed", + G_CALLBACK (accounts_dialog_model_selection_changed), + dialog); + + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), + COL_NAME, GTK_SORT_ASCENDING); + + accounts_dialog_model_add_columns (dialog); + + g_object_unref (store); +} + +static void +accounts_dialog_model_add_columns (EmpathyAccountsDialog *dialog) +{ + GtkTreeView *view; + GtkTreeViewColumn *column; + GtkCellRenderer *cell; + + view = GTK_TREE_VIEW (dialog->treeview); + gtk_tree_view_set_headers_visible (view, TRUE); + + /* account name/status */ + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_title (column, _("Accounts")); + + cell = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, cell, FALSE); + gtk_tree_view_column_set_cell_data_func (column, cell, + (GtkTreeCellDataFunc) + accounts_dialog_model_pixbuf_data_func, + dialog, + NULL); + + cell = gtk_cell_renderer_text_new (); + g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL); + gtk_tree_view_column_pack_start (column, cell, TRUE); + gtk_tree_view_column_add_attribute (column, + cell, + "text", COL_NAME); + + gtk_tree_view_column_set_expand (column, TRUE); + gtk_tree_view_append_column (view, column); +} + +static void +accounts_dialog_model_select_first (EmpathyAccountsDialog *dialog) +{ + GtkTreeView *view; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + + /* select first */ + view = GTK_TREE_VIEW (dialog->treeview); + model = gtk_tree_view_get_model (view); + + if (gtk_tree_model_get_iter_first (model, &iter)) { + selection = gtk_tree_view_get_selection (view); + gtk_tree_selection_select_iter (selection, &iter); + } else { + accounts_dialog_update_account (dialog, NULL); + } +} + +static void +accounts_dialog_model_pixbuf_data_func (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + EmpathyAccountsDialog *dialog) +{ + McAccount *account; + const gchar *icon_name; + GdkPixbuf *pixbuf; + TelepathyConnectionStatus status; + + gtk_tree_model_get (model, iter, + COL_STATUS, &status, + COL_ACCOUNT_POINTER, &account, + -1); + + icon_name = empathy_icon_name_from_account (account); + pixbuf = empathy_pixbuf_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON); + + if (pixbuf) { + if (status == TP_CONN_STATUS_DISCONNECTED || + (status == TP_CONN_STATUS_CONNECTING && + !dialog->connecting_show)) { + GdkPixbuf *modded_pixbuf; + + modded_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, + TRUE, + 8, + gdk_pixbuf_get_width (pixbuf), + gdk_pixbuf_get_height (pixbuf)); + + gdk_pixbuf_saturate_and_pixelate (pixbuf, + modded_pixbuf, + 1.0, + TRUE); + g_object_unref (pixbuf); + pixbuf = modded_pixbuf; + } + } + + g_object_set (cell, + "visible", TRUE, + "pixbuf", pixbuf, + NULL); + + g_object_unref (account); + if (pixbuf) { + g_object_unref (pixbuf); + } +} + +static McAccount * +accounts_dialog_model_get_selected (EmpathyAccountsDialog *dialog) +{ + GtkTreeView *view; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + McAccount *account; + + view = GTK_TREE_VIEW (dialog->treeview); + selection = gtk_tree_view_get_selection (view); + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { + return NULL; + } + + gtk_tree_model_get (model, &iter, COL_ACCOUNT_POINTER, &account, -1); + + return account; +} + +static void +accounts_dialog_model_set_selected (EmpathyAccountsDialog *dialog, + McAccount *account) +{ + GtkTreeView *view; + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + gboolean ok; + + view = GTK_TREE_VIEW (dialog->treeview); + model = gtk_tree_view_get_model (view); + selection = gtk_tree_view_get_selection (view); + + for (ok = gtk_tree_model_get_iter_first (model, &iter); + ok; + ok = gtk_tree_model_iter_next (model, &iter)) { + McAccount *this_account; + gboolean equal; + + gtk_tree_model_get (model, &iter, + COL_ACCOUNT_POINTER, &this_account, + -1); + + equal = empathy_account_equal (this_account, account); + g_object_unref (this_account); + + if (equal) { + gtk_tree_selection_select_iter (selection, &iter); + break; + } + } +} + +static gboolean +accounts_dialog_model_remove_selected (EmpathyAccountsDialog *dialog) +{ + GtkTreeView *view; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + + view = GTK_TREE_VIEW (dialog->treeview); + selection = gtk_tree_view_get_selection (view); + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { + return FALSE; + } + + return gtk_list_store_remove (GTK_LIST_STORE (model), &iter); +} + +static void +accounts_dialog_model_selection_changed (GtkTreeSelection *selection, + EmpathyAccountsDialog *dialog) +{ + McAccount *account; + GtkTreeModel *model; + GtkTreeIter iter; + gboolean is_selection; + + is_selection = gtk_tree_selection_get_selected (selection, &model, &iter); + + gtk_widget_set_sensitive (dialog->button_remove, is_selection); + gtk_widget_set_sensitive (dialog->button_connect, is_selection); + + accounts_dialog_update_connect_button (dialog); + + account = accounts_dialog_model_get_selected (dialog); + accounts_dialog_update_account (dialog, account); + + if (account) { + g_object_unref (account); + } +} + +static void +accounts_dialog_add_account (EmpathyAccountsDialog *dialog, + McAccount *account) +{ + TelepathyConnectionStatus status; + const gchar *name; + GtkTreeView *view; + GtkTreeModel *model; + GtkListStore *store; + GtkTreeIter iter; + gboolean ok; + + view = GTK_TREE_VIEW (dialog->treeview); + model = gtk_tree_view_get_model (view); + store = GTK_LIST_STORE (model); + + for (ok = gtk_tree_model_get_iter_first (model, &iter); + ok; + ok = gtk_tree_model_iter_next (model, &iter)) { + McAccount *this_account; + gboolean equal; + + gtk_tree_model_get (model, &iter, + COL_ACCOUNT_POINTER, &this_account, + -1); + + equal = empathy_account_equal (this_account, account); + g_object_unref (this_account); + + if (equal) { + return; + } + } + + status = mission_control_get_connection_status (dialog->mc, account, NULL); + name = mc_account_get_display_name (account); + + g_return_if_fail (name != NULL); + + empathy_debug (DEBUG_DOMAIN, "Adding new account: %s", name); + + gtk_list_store_insert_with_values (store, &iter, + -1, + COL_NAME, name, + COL_STATUS, status, + COL_ACCOUNT_POINTER, account, + -1); +} + +static void +accounts_dialog_account_added_cb (McAccountMonitor *monitor, + gchar *unique_name, + EmpathyAccountsDialog *dialog) +{ + McAccount *account; + + account = mc_account_lookup (unique_name); + accounts_dialog_add_account (dialog, account); + g_object_unref (account); +} + +static void +accounts_dialog_account_removed_cb (McAccountMonitor *monitor, + gchar *unique_name, + EmpathyAccountsDialog *dialog) +{ + McAccount *account; + + account = mc_account_lookup (unique_name); + + accounts_dialog_model_set_selected (dialog, account); + accounts_dialog_model_remove_selected (dialog); + + g_object_unref (account); +} + +static gboolean +accounts_dialog_row_changed_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data) +{ + gtk_tree_model_row_changed (model, path, iter); + + return FALSE; +} + +static gboolean +accounts_dialog_flash_connecting_cb (EmpathyAccountsDialog *dialog) +{ + GtkTreeView *view; + GtkTreeModel *model; + + dialog->connecting_show = !dialog->connecting_show; + + view = GTK_TREE_VIEW (dialog->treeview); + model = gtk_tree_view_get_model (view); + + gtk_tree_model_foreach (model, accounts_dialog_row_changed_foreach, NULL); + + return TRUE; +} + +static void +accounts_dialog_status_changed_cb (MissionControl *mc, + TelepathyConnectionStatus status, + McPresence presence, + TelepathyConnectionStatusReason reason, + const gchar *unique_name, + EmpathyAccountsDialog *dialog) +{ + GtkTreeView *view; + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + gboolean ok; + McAccount *account; + GList *accounts, *l; + gboolean found = FALSE; + + /* Update the status in the model */ + view = GTK_TREE_VIEW (dialog->treeview); + selection = gtk_tree_view_get_selection (view); + model = gtk_tree_view_get_model (view); + account = mc_account_lookup (unique_name); + + empathy_debug (DEBUG_DOMAIN, "Status changed for account %s: " + "status=%d presence=%d", + unique_name, status, presence); + + for (ok = gtk_tree_model_get_iter_first (model, &iter); + ok; + ok = gtk_tree_model_iter_next (model, &iter)) { + McAccount *this_account; + gboolean equal; + + gtk_tree_model_get (model, &iter, + COL_ACCOUNT_POINTER, &this_account, + -1); + + equal = empathy_account_equal (this_account, account); + g_object_unref (this_account); + + if (equal) { + GtkTreePath *path; + + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + COL_STATUS, status, + -1); + + path = gtk_tree_model_get_path (model, &iter); + gtk_tree_model_row_changed (model, path, &iter); + gtk_tree_path_free (path); + + break; + } + } + + g_object_unref (account); + + /* Start to flash account if status is connecting */ + if (status == TP_CONN_STATUS_CONNECTING) { + if (!dialog->connecting_id) { + dialog->connecting_id = g_timeout_add (FLASH_TIMEOUT, + (GSourceFunc) accounts_dialog_flash_connecting_cb, + dialog); + } + + return; + } + + /* Stop to flash if no account is connecting */ + accounts = mc_accounts_list (); + for (l = accounts; l; l = l->next) { + McAccount *this_account; + + this_account = l->data; + + if (mission_control_get_connection_status (mc, this_account, NULL) == TP_CONN_STATUS_CONNECTING) { + found = TRUE; + break; + } + + g_object_unref (this_account); + } + g_list_free (accounts); + + if (!found && dialog->connecting_id) { + g_source_remove (dialog->connecting_id); + dialog->connecting_id = 0; + } + + gtk_widget_show (dialog->window); +} + +static void +accounts_dialog_entry_name_changed_cb (GtkWidget *widget, + EmpathyAccountsDialog *dialog) +{ + const gchar *str; + + str = gtk_entry_get_text (GTK_ENTRY (widget)); + gtk_widget_set_sensitive (dialog->button_create, !G_STR_EMPTY (str)); +} + +static void +accounts_dialog_button_create_clicked_cb (GtkWidget *button, + EmpathyAccountsDialog *dialog) +{ + McProfile *profile; + McAccount *account; + const gchar *str; + + /* Update widgets */ + gtk_widget_show (dialog->vbox_details); + gtk_widget_hide (dialog->frame_no_account); + gtk_widget_hide (dialog->frame_new_account); + + profile = empathy_profile_chooser_get_selected (dialog->combobox_profile); + + /* Create account */ + account = mc_account_create (profile); + + str = gtk_entry_get_text (GTK_ENTRY (dialog->entry_name)); + mc_account_set_display_name (account, str); + + accounts_dialog_add_account (dialog, account); + accounts_dialog_model_set_selected (dialog, account); + + g_object_unref (account); + g_object_unref (profile); +} + +static void +accounts_dialog_button_back_clicked_cb (GtkWidget *button, + EmpathyAccountsDialog *dialog) +{ + McAccount *account; + + gtk_widget_hide (dialog->vbox_details); + gtk_widget_hide (dialog->frame_no_account); + gtk_widget_hide (dialog->frame_new_account); + + account = accounts_dialog_model_get_selected (dialog); + accounts_dialog_update_account (dialog, account); +} + +static void +accounts_dialog_button_connect_clicked_cb (GtkWidget *button, + EmpathyAccountsDialog *dialog) +{ + McAccount *account; + gboolean enable; + + account = accounts_dialog_model_get_selected (dialog); + enable = (!mc_account_is_enabled (account)); + mc_account_set_enabled (account, enable); + accounts_dialog_update_connect_button (dialog); + + g_object_unref (account); +} + +static void +accounts_dialog_button_add_clicked_cb (GtkWidget *button, + EmpathyAccountsDialog *dialog) +{ + gtk_widget_hide (dialog->vbox_details); + gtk_widget_hide (dialog->frame_no_account); + gtk_widget_show (dialog->frame_new_account); + + gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->combobox_profile), 0); + gtk_entry_set_text (GTK_ENTRY (dialog->entry_name), ""); + gtk_widget_grab_focus (dialog->entry_name); +} + +static void +accounts_dialog_remove_response_cb (GtkWidget *dialog, + gint response, + McAccount *account) +{ + if (response == GTK_RESPONSE_YES) { + mc_account_delete (account); + } + + gtk_widget_destroy (dialog); +} + +static void +accounts_dialog_button_remove_clicked_cb (GtkWidget *button, + EmpathyAccountsDialog *dialog) +{ + McAccount *account; + GtkWidget *message_dialog; + + account = accounts_dialog_model_get_selected (dialog); + + if (!mc_account_is_complete (account)) { + accounts_dialog_model_remove_selected (dialog); + return; + } + message_dialog = gtk_message_dialog_new + (GTK_WINDOW (dialog->window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, + _("You are about to remove your %s account!\n" + "Are you sure you want to proceed?"), + mc_account_get_display_name (account)); + + gtk_message_dialog_format_secondary_text + (GTK_MESSAGE_DIALOG (message_dialog), + _("Any associated conversations and chat rooms will NOT be " + "removed if you decide to proceed.\n" + "\n" + "Should you decide to add the account back at a later time, " + "they will still be available.")); + + gtk_dialog_add_button (GTK_DIALOG (message_dialog), + GTK_STOCK_CANCEL, + GTK_RESPONSE_NO); + gtk_dialog_add_button (GTK_DIALOG (message_dialog), + GTK_STOCK_REMOVE, + GTK_RESPONSE_YES); + + g_signal_connect (message_dialog, "response", + G_CALLBACK (accounts_dialog_remove_response_cb), + account); + + gtk_widget_show (message_dialog); +} + +static void +accounts_dialog_treeview_row_activated_cb (GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + EmpathyAccountsDialog *dialog) +{ + + accounts_dialog_button_connect_clicked_cb (dialog->button_connect, + dialog); +} + +static void +accounts_dialog_response_cb (GtkWidget *widget, + gint response, + EmpathyAccountsDialog *dialog) +{ + gtk_widget_destroy (widget); +} + +static void +accounts_dialog_destroy_cb (GtkWidget *widget, + EmpathyAccountsDialog *dialog) +{ + GList *accounts, *l; + + /* Disconnect signals */ + g_signal_handlers_disconnect_by_func (dialog->monitor, + accounts_dialog_account_added_cb, + dialog); + g_signal_handlers_disconnect_by_func (dialog->monitor, + accounts_dialog_account_removed_cb, + dialog); + dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (dialog->mc), + "AccountStatusChanged", + G_CALLBACK (accounts_dialog_status_changed_cb), + dialog); + + /* Delete incomplete accounts */ + accounts = mc_accounts_list (); + for (l = accounts; l; l = l->next) { + McAccount *account; + + account = l->data; + if (!mc_account_is_complete (account)) { + /* FIXME: Warn the user the account is not complete + * and is going to be removed. */ + mc_account_delete (account); + } + + g_object_unref (account); + } + g_list_free (accounts); + + if (dialog->connecting_id) { + g_source_remove (dialog->connecting_id); + } + + g_object_unref (dialog->mc); + g_object_unref (dialog->monitor); + + g_free (dialog); +} + +GtkWidget * +empathy_accounts_dialog_show (GtkWindow *parent) +{ + static EmpathyAccountsDialog *dialog = NULL; + GladeXML *glade; + GtkWidget *bbox; + GtkWidget *button_close; + + if (dialog) { + gtk_window_present (GTK_WINDOW (dialog->window)); + return dialog->window; + } + + dialog = g_new0 (EmpathyAccountsDialog, 1); + + glade = empathy_glade_get_file ("empathy-accounts-dialog.glade", + "accounts_dialog", + NULL, + "accounts_dialog", &dialog->window, + "vbox_details", &dialog->vbox_details, + "frame_no_account", &dialog->frame_no_account, + "label_no_account", &dialog->label_no_account, + "label_no_account_blurb", &dialog->label_no_account_blurb, + "alignment_settings", &dialog->alignment_settings, + "dialog-action_area", &bbox, + "treeview", &dialog->treeview, + "frame_new_account", &dialog->frame_new_account, + "entry_name", &dialog->entry_name, + "table_new_account", &dialog->table_new_account, + "button_create", &dialog->button_create, + "button_back", &dialog->button_back, + "image_type", &dialog->image_type, + "label_type", &dialog->label_type, + "label_name", &dialog->label_name, + "button_remove", &dialog->button_remove, + "button_connect", &dialog->button_connect, + "button_close", &button_close, + NULL); + + empathy_glade_connect (glade, + dialog, + "accounts_dialog", "destroy", accounts_dialog_destroy_cb, + "accounts_dialog", "response", accounts_dialog_response_cb, + "button_create", "clicked", accounts_dialog_button_create_clicked_cb, + "button_back", "clicked", accounts_dialog_button_back_clicked_cb, + "entry_name", "changed", accounts_dialog_entry_name_changed_cb, + "treeview", "row-activated", accounts_dialog_treeview_row_activated_cb, + "button_connect", "clicked", accounts_dialog_button_connect_clicked_cb, + "button_add", "clicked", accounts_dialog_button_add_clicked_cb, + "button_remove", "clicked", accounts_dialog_button_remove_clicked_cb, + NULL); + + g_object_add_weak_pointer (G_OBJECT (dialog->window), (gpointer) &dialog); + + g_object_unref (glade); + + /* Create profile chooser */ + dialog->combobox_profile = empathy_profile_chooser_new (); + gtk_table_attach_defaults (GTK_TABLE (dialog->table_new_account), + dialog->combobox_profile, + 1, 2, + 0, 1); + gtk_widget_show (dialog->combobox_profile); + + /* Set up signalling */ + dialog->mc = empathy_mission_control_new (); + dialog->monitor = mc_account_monitor_new (); + + /* FIXME: connect account-enabled/disabled too */ + g_signal_connect (dialog->monitor, "account-created", + G_CALLBACK (accounts_dialog_account_added_cb), + dialog); + g_signal_connect (dialog->monitor, "account-deleted", + G_CALLBACK (accounts_dialog_account_removed_cb), + dialog); + dbus_g_proxy_connect_signal (DBUS_G_PROXY (dialog->mc), "AccountStatusChanged", + G_CALLBACK (accounts_dialog_status_changed_cb), + dialog, NULL); + + accounts_dialog_model_setup (dialog); + accounts_dialog_setup (dialog); + accounts_dialog_model_select_first (dialog); + + if (parent) { + gtk_window_set_transient_for (GTK_WINDOW (dialog->window), + GTK_WINDOW (parent)); + } + + gtk_widget_show (dialog->window); + + return dialog->window; +} + diff --git a/libempathy-gtk/empathy-accounts-dialog.glade b/libempathy-gtk/empathy-accounts-dialog.glade new file mode 100644 index 00000000..05ba64f8 --- /dev/null +++ b/libempathy-gtk/empathy-accounts-dialog.glade @@ -0,0 +1,757 @@ + + + + + + + 5 + Accounts + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + False + + + + True + False + 2 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + -6 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 6 + True + False + 18 + + + + True + False + 6 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + 200 + True + True + True + False + False + False + False + False + False + + + + + 0 + True + True + + + + + + True + False + 6 + + + + True + True + gtk-connect + False + GTK_RELIEF_NORMAL + True + + + 0 + False + False + + + + + + True + True + 6 + + + + True + True + gtk-add + True + GTK_RELIEF_NORMAL + True + + + 0 + True + True + + + + + + True + True + gtk-remove + True + GTK_RELIEF_NORMAL + True + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + False + False + + + + + 0 + False + False + + + + + + 415 + True + False + 18 + + + + True + False + 18 + + + + True + 0 + 0.5 + GTK_SHADOW_NONE + + + + True + 0.5 + 0.5 + 1 + 1 + 6 + 0 + 20 + 0 + + + + True + False + 6 + + + + True + 2 + 2 + False + 6 + 6 + + + + True + gtk-cut + 6 + 0.5 + 0 + 0 + 0 + + + 1 + 2 + 0 + 2 + + + + + + + + True + Imendio + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + 0 + False + 0 + + + 0 + 1 + 1 + 2 + + + + + + + True + Jabber + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + + + + + + 0 + True + True + + + + + + + + + + True + <b>Account</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + False + False + + + + + + True + 0 + 0.5 + GTK_SHADOW_NONE + + + + True + 0.5 + 0.5 + 1 + 1 + 6 + 0 + 20 + 0 + + + + + + + + + + True + <b>Settings</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + 0 + 0.5 + GTK_SHADOW_NONE + + + + True + 0.5 + 0.5 + 1 + 1 + 6 + 0 + 20 + 0 + + + + True + False + 12 + + + + True + 2 + 2 + False + 6 + 6 + + + + True + _Type: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + + + + + + + + True + _Name: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + entry_name + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + + + + + + + + True + A unique name for this account to identify it personally to you. + True + True + True + 0 + + True + * + False + + + 1 + 2 + 1 + 2 + + + + + + 0 + True + True + + + + + + True + False + 6 + + + + True + False + True + GTK_RELIEF_NORMAL + True + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-new + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Cr_eate + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + 0 + False + False + GTK_PACK_END + + + + + + True + True + gtk-go-back + True + GTK_RELIEF_NORMAL + True + + + 0 + False + False + GTK_PACK_END + + + + + 0 + False + False + GTK_PACK_END + + + + + + + + + + True + <b>New Account</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + False + True + + + + + + 0 + 0.5 + GTK_SHADOW_NONE + + + + True + 0.5 + 0.5 + 1 + 1 + 6 + 0 + 12 + 0 + + + + True + To add a new account, you can click on the 'Add' button and a new entry will be created for you to started configuring. + +If you do not want to add an account, simply click on the account you want to configure in the list on the left. + False + True + GTK_JUSTIFY_LEFT + True + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + + + + True + <b>No Account Selected</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + + diff --git a/libempathy-gtk/empathy-accounts-dialog.h b/libempathy-gtk/empathy-accounts-dialog.h new file mode 100644 index 00000000..db800b98 --- /dev/null +++ b/libempathy-gtk/empathy-accounts-dialog.h @@ -0,0 +1,35 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2005-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Martyn Russell + */ + +#ifndef __EMPATHY_ACCOUNTS_DIALOG_H__ +#define __EMPATHY_ACCOUNTS_DIALOG_H__ + +#include + +G_BEGIN_DECLS + +GtkWidget *empathy_accounts_dialog_show (GtkWindow *parent); + +G_END_DECLS + +#endif /* __EMPATHY_ACCOUNTS_DIALOG_H__ */ diff --git a/libempathy-gtk/empathy-cell-renderer-expander.c b/libempathy-gtk/empathy-cell-renderer-expander.c new file mode 100644 index 00000000..51930ab6 --- /dev/null +++ b/libempathy-gtk/empathy-cell-renderer-expander.c @@ -0,0 +1,482 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Kristian Rietveld + */ + +/* To do: + * - should probably cancel animation if model changes + * - need to handle case where node-in-animation is removed + * - it only handles a single animation at a time; but I guess users + * aren't fast enough to trigger two or more animations at once anyway :P + * (could guard for this by just cancelling the "old" animation, and + * start the new one). + */ + +#include + +#include "empathy-cell-renderer-expander.h" + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CELL_RENDERER_EXPANDER, EmpathyCellRendererExpanderPriv)) + +static void empathy_cell_renderer_expander_init (EmpathyCellRendererExpander *expander); +static void empathy_cell_renderer_expander_class_init (EmpathyCellRendererExpanderClass *klass); +static void empathy_cell_renderer_expander_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); +static void empathy_cell_renderer_expander_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void empathy_cell_renderer_expander_finalize (GObject *object); +static void empathy_cell_renderer_expander_get_size (GtkCellRenderer *cell, + GtkWidget *widget, + GdkRectangle *cell_area, + gint *x_offset, + gint *y_offset, + gint *width, + gint *height); +static void empathy_cell_renderer_expander_render (GtkCellRenderer *cell, + GdkWindow *window, + GtkWidget *widget, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GdkRectangle *expose_area, + GtkCellRendererState flags); +static gboolean empathy_cell_renderer_expander_activate (GtkCellRenderer *cell, + GdkEvent *event, + GtkWidget *widget, + const gchar *path, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GtkCellRendererState flags); + +enum { + PROP_0, + PROP_EXPANDER_STYLE, + PROP_EXPANDER_SIZE, + PROP_ACTIVATABLE +}; + +typedef struct _EmpathyCellRendererExpanderPriv EmpathyCellRendererExpanderPriv; + +struct _EmpathyCellRendererExpanderPriv { + GtkExpanderStyle expander_style; + gint expander_size; + + GtkTreeView *animation_view; + GtkTreeRowReference *animation_node; + GtkExpanderStyle animation_style; + guint animation_timeout; + GdkRectangle animation_area; + + guint activatable : 1; + guint animation_expanding : 1; +}; + +G_DEFINE_TYPE (EmpathyCellRendererExpander, empathy_cell_renderer_expander, GTK_TYPE_CELL_RENDERER) + +static void +empathy_cell_renderer_expander_init (EmpathyCellRendererExpander *expander) +{ + EmpathyCellRendererExpanderPriv *priv; + + priv = GET_PRIV (expander); + + priv->expander_style = GTK_EXPANDER_COLLAPSED; + priv->expander_size = 12; + priv->activatable = TRUE; + priv->animation_node = NULL; + + GTK_CELL_RENDERER (expander)->xpad = 2; + GTK_CELL_RENDERER (expander)->ypad = 2; + GTK_CELL_RENDERER (expander)->mode = GTK_CELL_RENDERER_MODE_ACTIVATABLE; +} + +static void +empathy_cell_renderer_expander_class_init (EmpathyCellRendererExpanderClass *klass) +{ + GObjectClass *object_class; + GtkCellRendererClass *cell_class; + + object_class = G_OBJECT_CLASS (klass); + cell_class = GTK_CELL_RENDERER_CLASS (klass); + + object_class->finalize = empathy_cell_renderer_expander_finalize; + + object_class->get_property = empathy_cell_renderer_expander_get_property; + object_class->set_property = empathy_cell_renderer_expander_set_property; + + cell_class->get_size = empathy_cell_renderer_expander_get_size; + cell_class->render = empathy_cell_renderer_expander_render; + cell_class->activate = empathy_cell_renderer_expander_activate; + + g_object_class_install_property (object_class, + PROP_EXPANDER_STYLE, + g_param_spec_enum ("expander-style", + "Expander Style", + "Style to use when painting the expander", + GTK_TYPE_EXPANDER_STYLE, + GTK_EXPANDER_COLLAPSED, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_EXPANDER_SIZE, + g_param_spec_int ("expander-size", + "Expander Size", + "The size of the expander", + 0, + G_MAXINT, + 12, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_ACTIVATABLE, + g_param_spec_boolean ("activatable", + "Activatable", + "The expander can be activated", + TRUE, + G_PARAM_READWRITE)); + + g_type_class_add_private (object_class, sizeof (EmpathyCellRendererExpanderPriv)); +} + +static void +empathy_cell_renderer_expander_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + EmpathyCellRendererExpander *expander; + EmpathyCellRendererExpanderPriv *priv; + + expander = EMPATHY_CELL_RENDERER_EXPANDER (object); + priv = GET_PRIV (expander); + + switch (param_id) { + case PROP_EXPANDER_STYLE: + g_value_set_enum (value, priv->expander_style); + break; + + case PROP_EXPANDER_SIZE: + g_value_set_int (value, priv->expander_size); + break; + + case PROP_ACTIVATABLE: + g_value_set_boolean (value, priv->activatable); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +empathy_cell_renderer_expander_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + EmpathyCellRendererExpander *expander; + EmpathyCellRendererExpanderPriv *priv; + + expander = EMPATHY_CELL_RENDERER_EXPANDER (object); + priv = GET_PRIV (expander); + + switch (param_id) { + case PROP_EXPANDER_STYLE: + priv->expander_style = g_value_get_enum (value); + break; + + case PROP_EXPANDER_SIZE: + priv->expander_size = g_value_get_int (value); + break; + + case PROP_ACTIVATABLE: + priv->activatable = g_value_get_boolean (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +empathy_cell_renderer_expander_finalize (GObject *object) +{ + EmpathyCellRendererExpanderPriv *priv; + + priv = GET_PRIV (object); + + if (priv->animation_timeout) { + g_source_remove (priv->animation_timeout); + priv->animation_timeout = 0; + } + + if (priv->animation_node) { + gtk_tree_row_reference_free (priv->animation_node); + } + + (* G_OBJECT_CLASS (empathy_cell_renderer_expander_parent_class)->finalize) (object); +} + +GtkCellRenderer * +empathy_cell_renderer_expander_new (void) +{ + return g_object_new (EMPATHY_TYPE_CELL_RENDERER_EXPANDER, NULL); +} + +static void +empathy_cell_renderer_expander_get_size (GtkCellRenderer *cell, + GtkWidget *widget, + GdkRectangle *cell_area, + gint *x_offset, + gint *y_offset, + gint *width, + gint *height) +{ + EmpathyCellRendererExpander *expander; + EmpathyCellRendererExpanderPriv *priv; + + expander = (EmpathyCellRendererExpander*) cell; + priv = GET_PRIV (expander); + + if (cell_area) { + if (x_offset) { + *x_offset = cell->xalign * (cell_area->width - (priv->expander_size + (2 * cell->xpad))); + *x_offset = MAX (*x_offset, 0); + } + + if (y_offset) { + *y_offset = cell->yalign * (cell_area->height - (priv->expander_size + (2 * cell->ypad))); + *y_offset = MAX (*y_offset, 0); + } + } else { + if (x_offset) + *x_offset = 0; + + if (y_offset) + *y_offset = 0; + } + + if (width) + *width = cell->xpad * 2 + priv->expander_size; + + if (height) + *height = cell->ypad * 2 + priv->expander_size; +} + +static void +empathy_cell_renderer_expander_render (GtkCellRenderer *cell, + GdkWindow *window, + GtkWidget *widget, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GdkRectangle *expose_area, + GtkCellRendererState flags) +{ + EmpathyCellRendererExpander *expander; + EmpathyCellRendererExpanderPriv *priv; + GtkExpanderStyle expander_style; + gint x_offset, y_offset; + + expander = (EmpathyCellRendererExpander*) cell; + priv = GET_PRIV (expander); + + if (priv->animation_node) { + GtkTreePath *path; + GdkRectangle rect; + + /* Not sure if I like this ... */ + path = gtk_tree_row_reference_get_path (priv->animation_node); + gtk_tree_view_get_background_area (priv->animation_view, path, + NULL, &rect); + gtk_tree_path_free (path); + + if (background_area->y == rect.y) + expander_style = priv->animation_style; + else + expander_style = priv->expander_style; + } else + expander_style = priv->expander_style; + + empathy_cell_renderer_expander_get_size (cell, widget, cell_area, + &x_offset, &y_offset, + NULL, NULL); + + gtk_paint_expander (widget->style, + window, + GTK_STATE_NORMAL, + expose_area, + widget, + "treeview", + cell_area->x + x_offset + cell->xpad + priv->expander_size / 2, + cell_area->y + y_offset + cell->ypad + priv->expander_size / 2, + expander_style); +} + +static void +invalidate_node (GtkTreeView *tree_view, + GtkTreePath *path) +{ + GdkWindow *bin_window; + GdkRectangle rect; + + bin_window = gtk_tree_view_get_bin_window (tree_view); + + gtk_tree_view_get_background_area (tree_view, path, NULL, &rect); + + rect.x = 0; + rect.width = GTK_WIDGET (tree_view)->allocation.width; + + gdk_window_invalidate_rect (bin_window, &rect, TRUE); +} + +static gboolean +do_animation (EmpathyCellRendererExpander *expander) +{ + EmpathyCellRendererExpanderPriv *priv; + GtkTreePath *path; + gboolean done = FALSE; + + priv = GET_PRIV (expander); + + if (priv->animation_expanding) { + if (priv->animation_style == GTK_EXPANDER_SEMI_COLLAPSED) + priv->animation_style = GTK_EXPANDER_SEMI_EXPANDED; + else if (priv->animation_style == GTK_EXPANDER_SEMI_EXPANDED) { + priv->animation_style = GTK_EXPANDER_EXPANDED; + done = TRUE; + } + } else { + if (priv->animation_style == GTK_EXPANDER_SEMI_EXPANDED) + priv->animation_style = GTK_EXPANDER_SEMI_COLLAPSED; + else if (priv->animation_style == GTK_EXPANDER_SEMI_COLLAPSED) { + priv->animation_style = GTK_EXPANDER_COLLAPSED; + done = TRUE; + } + } + + path = gtk_tree_row_reference_get_path (priv->animation_node); + invalidate_node (priv->animation_view, path); + gtk_tree_path_free (path); + + if (done) { + gtk_tree_row_reference_free (priv->animation_node); + priv->animation_node = NULL; + priv->animation_timeout = 0; + } + + return !done; +} + +static gboolean +animation_timeout (gpointer data) +{ + gboolean retval; + + GDK_THREADS_ENTER (); + + retval = do_animation (data); + + GDK_THREADS_LEAVE (); + + return retval; +} + +static void +empathy_cell_renderer_expander_start_animation (EmpathyCellRendererExpander *expander, + GtkTreeView *tree_view, + GtkTreePath *path, + gboolean expanding, + GdkRectangle *background_area) +{ + EmpathyCellRendererExpanderPriv *priv; + + priv = GET_PRIV (expander); + + if (expanding) { + priv->animation_style = GTK_EXPANDER_SEMI_COLLAPSED; + } else { + priv->animation_style = GTK_EXPANDER_SEMI_EXPANDED; + } + + invalidate_node (tree_view, path); + + priv->animation_expanding = expanding; + priv->animation_view = tree_view; + priv->animation_node = gtk_tree_row_reference_new (gtk_tree_view_get_model (tree_view), path); + priv->animation_timeout = g_timeout_add (50, animation_timeout, expander); +} + +static gboolean +empathy_cell_renderer_expander_activate (GtkCellRenderer *cell, + GdkEvent *event, + GtkWidget *widget, + const gchar *path_string, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GtkCellRendererState flags) +{ + EmpathyCellRendererExpander *expander; + EmpathyCellRendererExpanderPriv *priv; + GtkTreePath *path; + gboolean animate; + gboolean expanding; + + expander = EMPATHY_CELL_RENDERER_EXPANDER (cell); + priv = GET_PRIV (cell); + + if (!GTK_IS_TREE_VIEW (widget) || !priv->activatable) + return FALSE; + + path = gtk_tree_path_new_from_string (path_string); + + if (gtk_tree_path_get_depth (path) > 1) { + gtk_tree_path_free (path); + return TRUE; + } + + g_object_get (gtk_widget_get_settings (GTK_WIDGET (widget)), + "gtk-enable-animations", &animate, + NULL); + + if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (widget), path)) { + gtk_tree_view_collapse_row (GTK_TREE_VIEW (widget), path); + expanding = FALSE; + } else { + gtk_tree_view_expand_row (GTK_TREE_VIEW (widget), path, FALSE); + expanding = TRUE; + } + + if (animate) { + empathy_cell_renderer_expander_start_animation (expander, + GTK_TREE_VIEW (widget), + path, + expanding, + background_area); + } + + gtk_tree_path_free (path); + + return TRUE; +} diff --git a/libempathy-gtk/empathy-cell-renderer-expander.h b/libempathy-gtk/empathy-cell-renderer-expander.h new file mode 100644 index 00000000..d7e5f74b --- /dev/null +++ b/libempathy-gtk/empathy-cell-renderer-expander.h @@ -0,0 +1,59 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Kristian Rietveld + */ + +#ifndef __EMPATHY_CELL_RENDERER_EXPANDER_H__ +#define __EMPATHY_CELL_RENDERER_EXPANDER_H__ + +#include + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_CELL_RENDERER_EXPANDER (empathy_cell_renderer_expander_get_type ()) +#define EMPATHY_CELL_RENDERER_EXPANDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMPATHY_TYPE_CELL_RENDERER_EXPANDER, EmpathyCellRendererExpander)) +#define EMPATHY_CELL_RENDERER_EXPANDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EMPATHY_TYPE_CELL_RENDERER_EXPANDER, EmpathyCellRendererExpanderClass)) +#define EMPATHY_IS_CELL_RENDERER_EXPANDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMPATHY_TYPE_CELL_RENDERER_EXPANDER)) +#define EMPATHY_IS_CELL_RENDERER_EXPANDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EMPATHY_TYPE_CELL_RENDERER_EXPANDER)) +#define EMPATHY_CELL_RENDERER_EXPANDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_CELL_RENDERER_EXPANDER, EmpathyCellRendererExpanderClass)) + +typedef struct _EmpathyCellRendererExpander EmpathyCellRendererExpander; +typedef struct _EmpathyCellRendererExpanderClass EmpathyCellRendererExpanderClass; + +struct _EmpathyCellRendererExpander { + GtkCellRenderer parent; +}; + +struct _EmpathyCellRendererExpanderClass { + GtkCellRendererClass parent_class; + + /* Padding for future expansion */ + void (*_gtk_reserved1) (void); + void (*_gtk_reserved2) (void); + void (*_gtk_reserved3) (void); + void (*_gtk_reserved4) (void); +}; + +GType empathy_cell_renderer_expander_get_type (void) G_GNUC_CONST; +GtkCellRenderer *empathy_cell_renderer_expander_new (void); + +G_END_DECLS + +#endif /* __EMPATHY_CELL_RENDERER_EXPANDER_H__ */ diff --git a/libempathy-gtk/empathy-cell-renderer-text.c b/libempathy-gtk/empathy-cell-renderer-text.c new file mode 100644 index 00000000..d48de32b --- /dev/null +++ b/libempathy-gtk/empathy-cell-renderer-text.c @@ -0,0 +1,368 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + */ + +#include "config.h" + +#include + +#include "empathy-cell-renderer-text.h" + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CELL_RENDERER_TEXT, EmpathyCellRendererTextPriv)) + +struct _EmpathyCellRendererTextPriv { + gchar *name; + gchar *status; + gboolean is_group; + + gboolean is_valid; + gboolean is_selected; + + gboolean show_status; +}; + +static void empathy_cell_renderer_text_class_init (EmpathyCellRendererTextClass *klass); +static void empathy_cell_renderer_text_init (EmpathyCellRendererText *cell); +static void cell_renderer_text_finalize (GObject *object); +static void cell_renderer_text_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); +static void cell_renderer_text_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void cell_renderer_text_get_size (GtkCellRenderer *cell, + GtkWidget *widget, + GdkRectangle *cell_area, + gint *x_offset, + gint *y_offset, + gint *width, + gint *height); +static void cell_renderer_text_render (GtkCellRenderer *cell, + GdkDrawable *window, + GtkWidget *widget, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GdkRectangle *expose_area, + GtkCellRendererState flags); +static void cell_renderer_text_update_text (EmpathyCellRendererText *cell, + GtkWidget *widget, + gboolean selected); + +/* Properties */ +enum { + PROP_0, + PROP_NAME, + PROP_STATUS, + PROP_IS_GROUP, + PROP_SHOW_STATUS, +}; + +G_DEFINE_TYPE (EmpathyCellRendererText, empathy_cell_renderer_text, GTK_TYPE_CELL_RENDERER_TEXT); + +static void +empathy_cell_renderer_text_class_init (EmpathyCellRendererTextClass *klass) +{ + GObjectClass *object_class; + GtkCellRendererClass *cell_class; + + object_class = G_OBJECT_CLASS (klass); + cell_class = GTK_CELL_RENDERER_CLASS (klass); + + object_class->finalize = cell_renderer_text_finalize; + + object_class->get_property = cell_renderer_text_get_property; + object_class->set_property = cell_renderer_text_set_property; + + cell_class->get_size = cell_renderer_text_get_size; + cell_class->render = cell_renderer_text_render; + + g_object_class_install_property (object_class, + PROP_NAME, + g_param_spec_string ("name", + "Name", + "Contact name", + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_STATUS, + g_param_spec_string ("status", + "Status", + "Contact status string", + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_IS_GROUP, + g_param_spec_boolean ("is_group", + "Is group", + "Whether this cell is a group", + FALSE, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_SHOW_STATUS, + g_param_spec_boolean ("show-status", + "Show status", + "Whether to show the status line", + TRUE, + G_PARAM_READWRITE)); + + g_type_class_add_private (object_class, sizeof (EmpathyCellRendererTextPriv)); +} + +static void +empathy_cell_renderer_text_init (EmpathyCellRendererText *cell) +{ + EmpathyCellRendererTextPriv *priv; + + priv = GET_PRIV (cell); + + g_object_set (cell, + "ellipsize", PANGO_ELLIPSIZE_END, + NULL); + + priv->name = g_strdup (""); + priv->status = g_strdup (""); + priv->show_status = TRUE; +} + +static void +cell_renderer_text_finalize (GObject *object) +{ + EmpathyCellRendererText *cell; + EmpathyCellRendererTextPriv *priv; + + cell = EMPATHY_CELL_RENDERER_TEXT (object); + priv = GET_PRIV (cell); + + g_free (priv->name); + g_free (priv->status); + + (G_OBJECT_CLASS (empathy_cell_renderer_text_parent_class)->finalize) (object); +} + +static void +cell_renderer_text_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + EmpathyCellRendererText *cell; + EmpathyCellRendererTextPriv *priv; + + cell = EMPATHY_CELL_RENDERER_TEXT (object); + priv = GET_PRIV (cell); + + switch (param_id) { + case PROP_NAME: + g_value_set_string (value, priv->name); + break; + case PROP_STATUS: + g_value_set_string (value, priv->status); + break; + case PROP_IS_GROUP: + g_value_set_boolean (value, priv->is_group); + break; + case PROP_SHOW_STATUS: + g_value_set_boolean (value, priv->show_status); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +cell_renderer_text_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + EmpathyCellRendererText *cell; + EmpathyCellRendererTextPriv *priv; + const gchar *str; + + cell = EMPATHY_CELL_RENDERER_TEXT (object); + priv = GET_PRIV (cell); + + switch (param_id) { + case PROP_NAME: + g_free (priv->name); + str = g_value_get_string (value); + priv->name = g_strdup (str ? str : ""); + g_strdelimit (priv->name, "\n\r\t", ' '); + priv->is_valid = FALSE; + break; + case PROP_STATUS: + g_free (priv->status); + str = g_value_get_string (value); + priv->status = g_strdup (str ? str : ""); + g_strdelimit (priv->status, "\n\r\t", ' '); + priv->is_valid = FALSE; + break; + case PROP_IS_GROUP: + priv->is_group = g_value_get_boolean (value); + priv->is_valid = FALSE; + break; + case PROP_SHOW_STATUS: + priv->show_status = g_value_get_boolean (value); + priv->is_valid = FALSE; + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +cell_renderer_text_get_size (GtkCellRenderer *cell, + GtkWidget *widget, + GdkRectangle *cell_area, + gint *x_offset, + gint *y_offset, + gint *width, + gint *height) +{ + EmpathyCellRendererText *celltext; + EmpathyCellRendererTextPriv *priv; + + celltext = EMPATHY_CELL_RENDERER_TEXT (cell); + priv = GET_PRIV (cell); + + /* Only update if not already valid so we get the right size. */ + cell_renderer_text_update_text (celltext, widget, priv->is_selected); + + (GTK_CELL_RENDERER_CLASS (empathy_cell_renderer_text_parent_class)->get_size) (cell, widget, + cell_area, + x_offset, y_offset, + width, height); +} + +static void +cell_renderer_text_render (GtkCellRenderer *cell, + GdkWindow *window, + GtkWidget *widget, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GdkRectangle *expose_area, + GtkCellRendererState flags) +{ + EmpathyCellRendererText *celltext; + + celltext = EMPATHY_CELL_RENDERER_TEXT (cell); + + cell_renderer_text_update_text (celltext, + widget, + (flags & GTK_CELL_RENDERER_SELECTED)); + + (GTK_CELL_RENDERER_CLASS (empathy_cell_renderer_text_parent_class)->render) ( + cell, window, + widget, + background_area, + cell_area, + expose_area, flags); +} + +static void +cell_renderer_text_update_text (EmpathyCellRendererText *cell, + GtkWidget *widget, + gboolean selected) +{ + EmpathyCellRendererTextPriv *priv; + PangoAttrList *attr_list; + PangoAttribute *attr_color, *attr_style, *attr_size; + GtkStyle *style; + gchar *str; + + priv = GET_PRIV (cell); + + if (priv->is_valid && priv->is_selected == selected) { + return; + } + + if (priv->is_group) { + g_object_set (cell, + "visible", TRUE, + "weight", PANGO_WEIGHT_BOLD, + "text", priv->name, + "attributes", NULL, + "xpad", 1, + "ypad", 1, + NULL); + + priv->is_selected = selected; + priv->is_valid = TRUE; + return; + } + + style = gtk_widget_get_style (widget); + + attr_list = pango_attr_list_new (); + + attr_style = pango_attr_style_new (PANGO_STYLE_ITALIC); + attr_style->start_index = strlen (priv->name) + 1; + attr_style->end_index = -1; + pango_attr_list_insert (attr_list, attr_style); + + if (!selected) { + GdkColor color; + + color = style->text_aa[GTK_STATE_NORMAL]; + + attr_color = pango_attr_foreground_new (color.red, color.green, color.blue); + attr_color->start_index = attr_style->start_index; + attr_color->end_index = -1; + pango_attr_list_insert (attr_list, attr_color); + } + + attr_size = pango_attr_size_new (pango_font_description_get_size (style->font_desc) / 1.2); + + attr_size->start_index = attr_style->start_index; + attr_size->end_index = -1; + pango_attr_list_insert (attr_list, attr_size); + + if (!priv->status || !priv->status[0] || !priv->show_status) { + str = g_strdup (priv->name); + } else { + str = g_strdup_printf ("%s\n%s", priv->name, priv->status); + } + + g_object_set (cell, + "visible", TRUE, + "weight", PANGO_WEIGHT_NORMAL, + "text", str, + "attributes", attr_list, + "xpad", 0, + "ypad", 1, + NULL); + + g_free (str); + pango_attr_list_unref (attr_list); + + priv->is_selected = selected; + priv->is_valid = TRUE; +} + +GtkCellRenderer * +empathy_cell_renderer_text_new (void) +{ + return g_object_new (EMPATHY_TYPE_CELL_RENDERER_TEXT, NULL); +} diff --git a/libempathy-gtk/empathy-cell-renderer-text.h b/libempathy-gtk/empathy-cell-renderer-text.h new file mode 100644 index 00000000..76cef312 --- /dev/null +++ b/libempathy-gtk/empathy-cell-renderer-text.h @@ -0,0 +1,56 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + */ + +#ifndef __EMPATHY_CELL_RENDERER_TEXT_H__ +#define __EMPATHY_CELL_RENDERER_TEXT_H__ + +#include + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_CELL_RENDERER_TEXT (empathy_cell_renderer_text_get_type ()) +#define EMPATHY_CELL_RENDERER_TEXT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_CELL_RENDERER_TEXT, EmpathyCellRendererText)) +#define EMPATHY_CELL_RENDERER_TEXT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_CELL_RENDERER_TEXT, EmpathyCellRendererTextClass)) +#define EMPATHY_IS_CELL_RENDERER_TEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_CELL_RENDERER_TEXT)) +#define EMPATHY_IS_CELL_RENDERER_TEXT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_CELL_RENDERER_TEXT)) +#define EMPATHY_CELL_RENDERER_TEXT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_CELL_RENDERER_TEXT, EmpathyCellRendererTextClass)) + +typedef struct _EmpathyCellRendererText EmpathyCellRendererText; +typedef struct _EmpathyCellRendererTextClass EmpathyCellRendererTextClass; +typedef struct _EmpathyCellRendererTextPriv EmpathyCellRendererTextPriv; + +struct _EmpathyCellRendererText { + GtkCellRendererText parent; + + EmpathyCellRendererTextPriv *priv; +}; + +struct _EmpathyCellRendererTextClass { + GtkCellRendererTextClass parent_class; +}; + +GType empathy_cell_renderer_text_get_type (void) G_GNUC_CONST; +GtkCellRenderer * empathy_cell_renderer_text_new (void); + +G_END_DECLS + +#endif /* __EMPATHY_CELL_RENDERER_TEXT_H__ */ diff --git a/libempathy-gtk/empathy-chat-view.c b/libempathy-gtk/empathy-chat-view.c new file mode 100644 index 00000000..fda26867 --- /dev/null +++ b/libempathy-gtk/empathy-chat-view.c @@ -0,0 +1,2226 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2002-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Richard Hult + * Martyn Russell + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "empathy-chat-view.h" +#include "empathy-chat.h" +#include "empathy-preferences.h" +#include "empathy-theme-manager.h" +#include "empathy-ui-utils.h" + +#define DEBUG_DOMAIN "ChatView" + +/* Number of seconds between timestamps when using normal mode, 5 minutes. */ +#define TIMESTAMP_INTERVAL 300 + +#define MAX_LINES 800 +#define MAX_SCROLL_TIME 0.4 /* seconds */ +#define SCROLL_DELAY 33 /* milliseconds */ + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CHAT_VIEW, EmpathyChatViewPriv)) + +typedef enum { + BLOCK_TYPE_NONE, + BLOCK_TYPE_SELF, + BLOCK_TYPE_OTHER, + BLOCK_TYPE_EVENT, + BLOCK_TYPE_TIME, + BLOCK_TYPE_INVITE +} BlockType; + +struct _EmpathyChatViewPriv { + GtkTextBuffer *buffer; + + gboolean irc_style; + time_t last_timestamp; + BlockType last_block_type; + + gboolean allow_scrolling; + guint scroll_timeout; + GTimer *scroll_time; + gboolean is_group_chat; + + GtkTextMark *find_mark_previous; + GtkTextMark *find_mark_next; + gboolean find_wrapped; + gboolean find_last_direction; + + /* This is for the group chat so we know if the "other" last contact + * changed, so we know whether to insert a header or not. + */ + EmpathyContact *last_contact; + + guint notify_system_fonts_id; + guint notify_show_avatars_id; +}; + +typedef struct { + EmpathySmiley smiley; + const gchar *pattern; +} EmpathySmileyPattern; + +static const EmpathySmileyPattern smileys[] = { + /* Forward smileys. */ + { EMPATHY_SMILEY_NORMAL, ":)" }, + { EMPATHY_SMILEY_WINK, ";)" }, + { EMPATHY_SMILEY_WINK, ";-)" }, + { EMPATHY_SMILEY_BIGEYE, "=)" }, + { EMPATHY_SMILEY_NOSE, ":-)" }, + { EMPATHY_SMILEY_CRY, ":'(" }, + { EMPATHY_SMILEY_SAD, ":(" }, + { EMPATHY_SMILEY_SAD, ":-(" }, + { EMPATHY_SMILEY_SCEPTICAL, ":/" }, + { EMPATHY_SMILEY_SCEPTICAL, ":\\" }, + { EMPATHY_SMILEY_BIGSMILE, ":D" }, + { EMPATHY_SMILEY_BIGSMILE, ":-D" }, + { EMPATHY_SMILEY_INDIFFERENT, ":|" }, + { EMPATHY_SMILEY_TOUNGE, ":p" }, + { EMPATHY_SMILEY_TOUNGE, ":-p" }, + { EMPATHY_SMILEY_TOUNGE, ":P" }, + { EMPATHY_SMILEY_TOUNGE, ":-P" }, + { EMPATHY_SMILEY_TOUNGE, ";p" }, + { EMPATHY_SMILEY_TOUNGE, ";-p" }, + { EMPATHY_SMILEY_TOUNGE, ";P" }, + { EMPATHY_SMILEY_TOUNGE, ";-P" }, + { EMPATHY_SMILEY_SHOCKED, ":o" }, + { EMPATHY_SMILEY_SHOCKED, ":-o" }, + { EMPATHY_SMILEY_SHOCKED, ":O" }, + { EMPATHY_SMILEY_SHOCKED, ":-O" }, + { EMPATHY_SMILEY_COOL, "8)" }, + { EMPATHY_SMILEY_COOL, "B)" }, + { EMPATHY_SMILEY_SORRY, "*|" }, + { EMPATHY_SMILEY_KISS, ":*" }, + { EMPATHY_SMILEY_SHUTUP, ":#" }, + { EMPATHY_SMILEY_SHUTUP, ":-#" }, + { EMPATHY_SMILEY_YAWN, "|O" }, + { EMPATHY_SMILEY_CONFUSED, ":S" }, + { EMPATHY_SMILEY_CONFUSED, ":s" }, + { EMPATHY_SMILEY_ANGEL, "<)" }, + { EMPATHY_SMILEY_OOOH, ":x" }, + { EMPATHY_SMILEY_LOOKAWAY, "*)" }, + { EMPATHY_SMILEY_LOOKAWAY, "*-)" }, + { EMPATHY_SMILEY_BLUSH, "*S" }, + { EMPATHY_SMILEY_BLUSH, "*s" }, + { EMPATHY_SMILEY_BLUSH, "*$" }, + { EMPATHY_SMILEY_COOLBIGSMILE, "8D" }, + { EMPATHY_SMILEY_ANGRY, ":@" }, + { EMPATHY_SMILEY_BOSS, "@)" }, + { EMPATHY_SMILEY_MONKEY, "#)" }, + { EMPATHY_SMILEY_SILLY, "O)" }, + { EMPATHY_SMILEY_SICK, "+o(" }, + + /* Backward smileys. */ + { EMPATHY_SMILEY_NORMAL, "(:" }, + { EMPATHY_SMILEY_WINK, "(;" }, + { EMPATHY_SMILEY_WINK, "(-;" }, + { EMPATHY_SMILEY_BIGEYE, "(=" }, + { EMPATHY_SMILEY_NOSE, "(-:" }, + { EMPATHY_SMILEY_CRY, ")':" }, + { EMPATHY_SMILEY_SAD, "):" }, + { EMPATHY_SMILEY_SAD, ")-:" }, + { EMPATHY_SMILEY_SCEPTICAL, "/:" }, + { EMPATHY_SMILEY_SCEPTICAL, "//:" }, + { EMPATHY_SMILEY_INDIFFERENT, "|:" }, + { EMPATHY_SMILEY_TOUNGE, "d:" }, + { EMPATHY_SMILEY_TOUNGE, "d-:" }, + { EMPATHY_SMILEY_TOUNGE, "d;" }, + { EMPATHY_SMILEY_TOUNGE, "d-;" }, + { EMPATHY_SMILEY_SHOCKED, "o:" }, + { EMPATHY_SMILEY_SHOCKED, "O:" }, + { EMPATHY_SMILEY_COOL, "(8" }, + { EMPATHY_SMILEY_COOL, "(B" }, + { EMPATHY_SMILEY_SORRY, "|*" }, + { EMPATHY_SMILEY_KISS, "*:" }, + { EMPATHY_SMILEY_SHUTUP, "#:" }, + { EMPATHY_SMILEY_SHUTUP, "#-:" }, + { EMPATHY_SMILEY_YAWN, "O|" }, + { EMPATHY_SMILEY_CONFUSED, "S:" }, + { EMPATHY_SMILEY_CONFUSED, "s:" }, + { EMPATHY_SMILEY_ANGEL, "(>" }, + { EMPATHY_SMILEY_OOOH, "x:" }, + { EMPATHY_SMILEY_LOOKAWAY, "(*" }, + { EMPATHY_SMILEY_LOOKAWAY, "(-*" }, + { EMPATHY_SMILEY_BLUSH, "S*" }, + { EMPATHY_SMILEY_BLUSH, "s*" }, + { EMPATHY_SMILEY_BLUSH, "$*" }, + { EMPATHY_SMILEY_ANGRY, "@:" }, + { EMPATHY_SMILEY_BOSS, "(@" }, + { EMPATHY_SMILEY_MONKEY, "#)" }, + { EMPATHY_SMILEY_SILLY, "(O" }, + { EMPATHY_SMILEY_SICK, ")o+" } +}; + +static void empathy_chat_view_class_init (EmpathyChatViewClass *klass); +static void empathy_chat_view_init (EmpathyChatView *view); +static void chat_view_finalize (GObject *object); +static gboolean chat_view_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time); +static void chat_view_size_allocate (GtkWidget *widget, + GtkAllocation *alloc); +static void chat_view_setup_tags (EmpathyChatView *view); +static void chat_view_system_font_update (EmpathyChatView *view); +static void chat_view_notify_system_font_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data); +static void chat_view_notify_show_avatars_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data); +static void chat_view_populate_popup (EmpathyChatView *view, + GtkMenu *menu, + gpointer user_data); +static gboolean chat_view_event_cb (EmpathyChatView *view, + GdkEventMotion *event, + GtkTextTag *tag); +static gboolean chat_view_url_event_cb (GtkTextTag *tag, + GObject *object, + GdkEvent *event, + GtkTextIter *iter, + GtkTextBuffer *buffer); +static void chat_view_open_address_cb (GtkMenuItem *menuitem, + const gchar *url); +static void chat_view_copy_address_cb (GtkMenuItem *menuitem, + const gchar *url); +static void chat_view_clear_view_cb (GtkMenuItem *menuitem, + EmpathyChatView *view); +static void chat_view_insert_text_with_emoticons (GtkTextBuffer *buf, + GtkTextIter *iter, + const gchar *str); +static gboolean chat_view_is_scrolled_down (EmpathyChatView *view); +static void chat_view_theme_changed_cb (EmpathyThemeManager *manager, + EmpathyChatView *view); +static void chat_view_maybe_append_date_and_time (EmpathyChatView *view, + EmpathyMessage *msg); +static void chat_view_append_spacing (EmpathyChatView *view); +static void chat_view_append_text (EmpathyChatView *view, + const gchar *body, + const gchar *tag); +static void chat_view_maybe_append_fancy_header (EmpathyChatView *view, + EmpathyMessage *msg); +static void chat_view_append_irc_action (EmpathyChatView *view, + EmpathyMessage *msg); +static void chat_view_append_fancy_action (EmpathyChatView *view, + EmpathyMessage *msg); +static void chat_view_append_irc_message (EmpathyChatView *view, + EmpathyMessage *msg); +static void chat_view_append_fancy_message (EmpathyChatView *view, + EmpathyMessage *msg); +static GdkPixbuf *chat_view_pad_to_size (GdkPixbuf *pixbuf, + gint width, + gint height, + gint extra_padding_right); + +G_DEFINE_TYPE (EmpathyChatView, empathy_chat_view, GTK_TYPE_TEXT_VIEW); + +static void +empathy_chat_view_class_init (EmpathyChatViewClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->finalize = chat_view_finalize; + widget_class->size_allocate = chat_view_size_allocate; + widget_class->drag_motion = chat_view_drag_motion; + + g_type_class_add_private (object_class, sizeof (EmpathyChatViewPriv)); +} + +static void +empathy_chat_view_init (EmpathyChatView *view) +{ + EmpathyChatViewPriv *priv; + gboolean show_avatars; + + priv = GET_PRIV (view); + + priv->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); + + priv->last_block_type = BLOCK_TYPE_NONE; + priv->last_timestamp = 0; + + priv->allow_scrolling = TRUE; + + priv->is_group_chat = FALSE; + + g_object_set (view, + "wrap-mode", GTK_WRAP_WORD_CHAR, + "editable", FALSE, + "cursor-visible", FALSE, + NULL); + + priv->notify_system_fonts_id = + empathy_conf_notify_add (empathy_conf_get (), + "/desktop/gnome/interface/document_font_name", + chat_view_notify_system_font_cb, + view); + chat_view_system_font_update (view); + + priv->notify_show_avatars_id = + empathy_conf_notify_add (empathy_conf_get (), + EMPATHY_PREFS_UI_SHOW_AVATARS, + chat_view_notify_show_avatars_cb, + view); + + chat_view_setup_tags (view); + + empathy_theme_manager_apply_saved (empathy_theme_manager_get (), view); + + show_avatars = FALSE; + empathy_conf_get_bool (empathy_conf_get (), + EMPATHY_PREFS_UI_SHOW_AVATARS, + &show_avatars); + + empathy_theme_manager_update_show_avatars (empathy_theme_manager_get (), + view, show_avatars); + + g_signal_connect (view, + "populate-popup", + G_CALLBACK (chat_view_populate_popup), + NULL); + + g_signal_connect_object (empathy_theme_manager_get (), + "theme-changed", + G_CALLBACK (chat_view_theme_changed_cb), + view, + 0); +} + +static void +chat_view_finalize (GObject *object) +{ + EmpathyChatView *view; + EmpathyChatViewPriv *priv; + + view = EMPATHY_CHAT_VIEW (object); + priv = GET_PRIV (view); + + empathy_debug (DEBUG_DOMAIN, "finalize: %p", object); + + empathy_conf_notify_remove (empathy_conf_get (), priv->notify_system_fonts_id); + empathy_conf_notify_remove (empathy_conf_get (), priv->notify_show_avatars_id); + + if (priv->last_contact) { + g_object_unref (priv->last_contact); + } + if (priv->scroll_time) { + g_timer_destroy (priv->scroll_time); + } + if (priv->scroll_timeout) { + g_source_remove (priv->scroll_timeout); + } + + G_OBJECT_CLASS (empathy_chat_view_parent_class)->finalize (object); +} + +static gboolean +chat_view_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time) +{ + /* Don't handle drag motion, since we don't want the view to scroll as + * the result of dragging something across it. + */ + + return FALSE; +} + +static void +chat_view_size_allocate (GtkWidget *widget, + GtkAllocation *alloc) +{ + gboolean down; + + down = chat_view_is_scrolled_down (EMPATHY_CHAT_VIEW (widget)); + + GTK_WIDGET_CLASS (empathy_chat_view_parent_class)->size_allocate (widget, alloc); + + if (down) { + GtkAdjustment *adj; + + adj = GTK_TEXT_VIEW (widget)->vadjustment; + gtk_adjustment_set_value (adj, adj->upper - adj->page_size); + } +} + +static void +chat_view_setup_tags (EmpathyChatView *view) +{ + EmpathyChatViewPriv *priv; + GtkTextTag *tag; + + priv = GET_PRIV (view); + + gtk_text_buffer_create_tag (priv->buffer, + "cut", + NULL); + + /* FIXME: Move to the theme and come up with something that looks a bit + * nicer. + */ + gtk_text_buffer_create_tag (priv->buffer, + "highlight", + "background", "yellow", + NULL); + + tag = gtk_text_buffer_create_tag (priv->buffer, + "link", + NULL); + + g_signal_connect (tag, + "event", + G_CALLBACK (chat_view_url_event_cb), + priv->buffer); + + g_signal_connect (view, + "motion-notify-event", + G_CALLBACK (chat_view_event_cb), + tag); +} + +static void +chat_view_system_font_update (EmpathyChatView *view) +{ + PangoFontDescription *font_description = NULL; + gchar *font_name; + + if (empathy_conf_get_string (empathy_conf_get (), + "/desktop/gnome/interface/document_font_name", + &font_name) && font_name) { + font_description = pango_font_description_from_string (font_name); + g_free (font_name); + } else { + font_description = NULL; + } + + gtk_widget_modify_font (GTK_WIDGET (view), font_description); + + if (font_description) { + pango_font_description_free (font_description); + } +} + +static void +chat_view_notify_system_font_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data) +{ + EmpathyChatView *view; + gboolean show_avatars = FALSE; + + view = user_data; + + chat_view_system_font_update (view); + + /* Ugly, again, to adjust the vertical position of the nick... Will fix + * this when reworking the theme manager so that view register + * themselves with it instead of the other way around. + */ + empathy_conf_get_bool (conf, + EMPATHY_PREFS_UI_SHOW_AVATARS, + &show_avatars); + + empathy_theme_manager_update_show_avatars (empathy_theme_manager_get (), + view, show_avatars); +} + +static void +chat_view_notify_show_avatars_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data) +{ + EmpathyChatView *view; + EmpathyChatViewPriv *priv; + gboolean show_avatars = FALSE; + + view = user_data; + priv = GET_PRIV (view); + + empathy_conf_get_bool (conf, key, &show_avatars); + + empathy_theme_manager_update_show_avatars (empathy_theme_manager_get (), + view, show_avatars); +} + +static void +chat_view_populate_popup (EmpathyChatView *view, + GtkMenu *menu, + gpointer user_data) +{ + EmpathyChatViewPriv *priv; + GtkTextTagTable *table; + GtkTextTag *tag; + gint x, y; + GtkTextIter iter, start, end; + GtkWidget *item; + gchar *str = NULL; + + priv = GET_PRIV (view); + + /* Clear menu item */ + if (gtk_text_buffer_get_char_count (priv->buffer) > 0) { + item = gtk_menu_item_new (); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + + item = gtk_image_menu_item_new_from_stock (GTK_STOCK_CLEAR, NULL); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + + g_signal_connect (item, + "activate", + G_CALLBACK (chat_view_clear_view_cb), + view); + } + + /* Link context menu items */ + table = gtk_text_buffer_get_tag_table (priv->buffer); + tag = gtk_text_tag_table_lookup (table, "link"); + + gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y); + + gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view), + GTK_TEXT_WINDOW_WIDGET, + x, y, + &x, &y); + + gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view), &iter, x, y); + + start = end = iter; + + if (gtk_text_iter_backward_to_tag_toggle (&start, tag) && + gtk_text_iter_forward_to_tag_toggle (&end, tag)) { + str = gtk_text_buffer_get_text (priv->buffer, + &start, &end, FALSE); + } + + if (G_STR_EMPTY (str)) { + g_free (str); + return; + } + + /* NOTE: Set data just to get the string freed when not needed. */ + g_object_set_data_full (G_OBJECT (menu), + "url", str, + (GDestroyNotify) g_free); + + item = gtk_menu_item_new (); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + + item = gtk_menu_item_new_with_mnemonic (_("_Copy Link Address")); + g_signal_connect (item, + "activate", + G_CALLBACK (chat_view_copy_address_cb), + str); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + + item = gtk_menu_item_new_with_mnemonic (_("_Open Link")); + g_signal_connect (item, + "activate", + G_CALLBACK (chat_view_open_address_cb), + str); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); +} + +static gboolean +chat_view_event_cb (EmpathyChatView *view, + GdkEventMotion *event, + GtkTextTag *tag) +{ + static GdkCursor *hand = NULL; + static GdkCursor *beam = NULL; + GtkTextWindowType type; + GtkTextIter iter; + GdkWindow *win; + gint x, y, buf_x, buf_y; + + type = gtk_text_view_get_window_type (GTK_TEXT_VIEW (view), + event->window); + + if (type != GTK_TEXT_WINDOW_TEXT) { + return FALSE; + } + + /* Get where the pointer really is. */ + win = gtk_text_view_get_window (GTK_TEXT_VIEW (view), type); + if (!win) { + return FALSE; + } + + gdk_window_get_pointer (win, &x, &y, NULL); + + /* Get the iter where the cursor is at */ + gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view), type, + x, y, + &buf_x, &buf_y); + + gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view), + &iter, + buf_x, buf_y); + + if (gtk_text_iter_has_tag (&iter, tag)) { + if (!hand) { + hand = gdk_cursor_new (GDK_HAND2); + beam = gdk_cursor_new (GDK_XTERM); + } + gdk_window_set_cursor (win, hand); + } else { + if (!beam) { + beam = gdk_cursor_new (GDK_XTERM); + } + gdk_window_set_cursor (win, beam); + } + + return FALSE; +} + +static gboolean +chat_view_url_event_cb (GtkTextTag *tag, + GObject *object, + GdkEvent *event, + GtkTextIter *iter, + GtkTextBuffer *buffer) +{ + GtkTextIter start, end; + gchar *str; + + /* If the link is being selected, don't do anything. */ + gtk_text_buffer_get_selection_bounds (buffer, &start, &end); + if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end)) { + return FALSE; + } + + if (event->type == GDK_BUTTON_RELEASE && event->button.button == 1) { + start = end = *iter; + + if (gtk_text_iter_backward_to_tag_toggle (&start, tag) && + gtk_text_iter_forward_to_tag_toggle (&end, tag)) { + str = gtk_text_buffer_get_text (buffer, + &start, + &end, + FALSE); + + empathy_url_show (str); + g_free (str); + } + } + + return FALSE; +} + +static void +chat_view_open_address_cb (GtkMenuItem *menuitem, const gchar *url) +{ + empathy_url_show (url); +} + +static void +chat_view_copy_address_cb (GtkMenuItem *menuitem, const gchar *url) +{ + GtkClipboard *clipboard; + + clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); + gtk_clipboard_set_text (clipboard, url, -1); + + clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY); + gtk_clipboard_set_text (clipboard, url, -1); +} + +static void +chat_view_clear_view_cb (GtkMenuItem *menuitem, EmpathyChatView *view) +{ + empathy_chat_view_clear (view); +} + +static void +chat_view_insert_text_with_emoticons (GtkTextBuffer *buf, + GtkTextIter *iter, + const gchar *str) +{ + const gchar *p; + gunichar c, prev_c; + gint i; + gint match; + gint submatch; + gboolean use_smileys = FALSE; + + empathy_conf_get_bool (empathy_conf_get (), + EMPATHY_PREFS_CHAT_SHOW_SMILEYS, + &use_smileys); + + if (!use_smileys) { + gtk_text_buffer_insert (buf, iter, str, -1); + return; + } + + while (*str) { + gint smileys_index[G_N_ELEMENTS (smileys)]; + GdkPixbuf *pixbuf; + gint len; + const gchar *start; + + memset (smileys_index, 0, sizeof (smileys_index)); + + match = -1; + submatch = -1; + p = str; + prev_c = 0; + + while (*p) { + c = g_utf8_get_char (p); + + if (match != -1 && g_unichar_isspace (c)) { + break; + } else { + match = -1; + } + + if (submatch != -1 || prev_c == 0 || g_unichar_isspace (prev_c)) { + submatch = -1; + + for (i = 0; i < G_N_ELEMENTS (smileys); i++) { + /* Only try to match if we already have + * a beginning match for the pattern, or + * if it's the first character in the + * pattern, if it's not in the middle of + * a word. + */ + if (((smileys_index[i] == 0 && (prev_c == 0 || g_unichar_isspace (prev_c))) || + smileys_index[i] > 0) && + smileys[i].pattern[smileys_index[i]] == c) { + submatch = i; + + smileys_index[i]++; + if (!smileys[i].pattern[smileys_index[i]]) { + match = i; + } + } else { + smileys_index[i] = 0; + } + } + } + + prev_c = c; + p = g_utf8_next_char (p); + } + + if (match == -1) { + gtk_text_buffer_insert (buf, iter, str, -1); + return; + } + + start = p - strlen (smileys[match].pattern); + + if (start > str) { + len = start - str; + gtk_text_buffer_insert (buf, iter, str, len); + } + + pixbuf = empathy_chat_view_get_smiley_image (smileys[match].smiley); + gtk_text_buffer_insert_pixbuf (buf, iter, pixbuf); + + gtk_text_buffer_insert (buf, iter, " ", 1); + + str = g_utf8_find_next_char (p, NULL); + } +} + +static gboolean +chat_view_is_scrolled_down (EmpathyChatView *view) +{ + GtkWidget *sw; + + sw = gtk_widget_get_parent (GTK_WIDGET (view)); + if (GTK_IS_SCROLLED_WINDOW (sw)) { + GtkAdjustment *vadj; + + vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (sw)); + + if (vadj->value + vadj->page_size / 2 < vadj->upper - vadj->page_size) { + return FALSE; + } + } + + return TRUE; +} + +static void +chat_view_maybe_trim_buffer (EmpathyChatView *view) +{ + EmpathyChatViewPriv *priv; + GtkTextIter top, bottom; + gint line; + gint remove; + GtkTextTagTable *table; + GtkTextTag *tag; + + priv = GET_PRIV (view); + + gtk_text_buffer_get_end_iter (priv->buffer, &bottom); + line = gtk_text_iter_get_line (&bottom); + if (line < MAX_LINES) { + return; + } + + remove = line - MAX_LINES; + gtk_text_buffer_get_start_iter (priv->buffer, &top); + + bottom = top; + if (!gtk_text_iter_forward_lines (&bottom, remove)) { + return; + } + + /* Track backwords to a place where we can safely cut, we don't do it in + * the middle of a tag. + */ + table = gtk_text_buffer_get_tag_table (priv->buffer); + tag = gtk_text_tag_table_lookup (table, "cut"); + if (!tag) { + return; + } + + if (!gtk_text_iter_forward_to_tag_toggle (&bottom, tag)) { + return; + } + + if (!gtk_text_iter_equal (&top, &bottom)) { + gtk_text_buffer_delete (priv->buffer, &top, &bottom); + } +} + +static void +chat_view_maybe_append_date_and_time (EmpathyChatView *view, + EmpathyMessage *msg) +{ + EmpathyChatViewPriv *priv; + const gchar *tag; + time_t timestamp; + GDate *date, *last_date; + GtkTextIter iter; + gboolean append_date, append_time; + GString *str; + + priv = GET_PRIV (view); + + if (priv->irc_style) { + tag = "irc-time"; + } else { + tag = "fancy-time"; + } + + if (priv->last_block_type == BLOCK_TYPE_TIME) { + return; + } + + str = g_string_new (NULL); + + timestamp = 0; + if (msg) { + timestamp = empathy_message_get_timestamp (msg); + } + + if (timestamp <= 0) { + timestamp = empathy_time_get_current (); + } + + date = g_date_new (); + g_date_set_time (date, timestamp); + + last_date = g_date_new (); + g_date_set_time (last_date, priv->last_timestamp); + + append_date = FALSE; + append_time = FALSE; + + if (g_date_compare (date, last_date) > 0) { + append_date = TRUE; + append_time = TRUE; + } + + if (priv->last_timestamp + TIMESTAMP_INTERVAL < timestamp) { + append_time = TRUE; + } + + if (append_time || append_date) { + chat_view_append_spacing (view); + + g_string_append (str, "- "); + } + + if (append_date) { + gchar buf[256]; + + g_date_strftime (buf, 256, _("%A %d %B %Y"), date); + g_string_append (str, buf); + + if (append_time) { + g_string_append (str, ", "); + } + } + + g_date_free (date); + g_date_free (last_date); + + if (append_time) { + gchar *tmp; + + tmp = empathy_time_to_string_local (timestamp, EMPATHY_TIME_FORMAT_DISPLAY_SHORT); + g_string_append (str, tmp); + g_free (tmp); + } + + if (append_time || append_date) { + g_string_append (str, " -\n"); + + gtk_text_buffer_get_end_iter (priv->buffer, &iter); + gtk_text_buffer_insert_with_tags_by_name (priv->buffer, + &iter, + str->str, -1, + tag, + NULL); + + priv->last_block_type = BLOCK_TYPE_TIME; + priv->last_timestamp = timestamp; + } + + g_string_free (str, TRUE); +} + +static void +chat_view_append_spacing (EmpathyChatView *view) +{ + EmpathyChatViewPriv *priv; + const gchar *tag; + GtkTextIter iter; + + priv = GET_PRIV (view); + + if (priv->irc_style) { + tag = "irc-spacing"; + } else { + tag = "fancy-spacing"; + } + + gtk_text_buffer_get_end_iter (priv->buffer, &iter); + gtk_text_buffer_insert_with_tags_by_name (priv->buffer, + &iter, + "\n", + -1, + "cut", + tag, + NULL); +} + +static void +chat_view_append_text (EmpathyChatView *view, + const gchar *body, + const gchar *tag) +{ + EmpathyChatViewPriv *priv; + GtkTextIter start_iter, end_iter; + GtkTextMark *mark; + GtkTextIter iter; + gint num_matches, i; + GArray *start, *end; + const gchar *link_tag; + + priv = GET_PRIV (view); + + if (priv->irc_style) { + link_tag = "irc-link"; + } else { + link_tag = "fancy-link"; + } + + gtk_text_buffer_get_end_iter (priv->buffer, &start_iter); + mark = gtk_text_buffer_create_mark (priv->buffer, NULL, &start_iter, TRUE); + + start = g_array_new (FALSE, FALSE, sizeof (gint)); + end = g_array_new (FALSE, FALSE, sizeof (gint)); + + num_matches = empathy_regex_match (EMPATHY_REGEX_ALL, body, start, end); + + if (num_matches == 0) { + gtk_text_buffer_get_end_iter (priv->buffer, &iter); + chat_view_insert_text_with_emoticons (priv->buffer, &iter, body); + } else { + gint last = 0; + gint s = 0, e = 0; + gchar *tmp; + + for (i = 0; i < num_matches; i++) { + s = g_array_index (start, gint, i); + e = g_array_index (end, gint, i); + + if (s > last) { + tmp = empathy_substring (body, last, s); + + gtk_text_buffer_get_end_iter (priv->buffer, &iter); + chat_view_insert_text_with_emoticons (priv->buffer, + &iter, + tmp); + g_free (tmp); + } + + tmp = empathy_substring (body, s, e); + + gtk_text_buffer_get_end_iter (priv->buffer, &iter); + gtk_text_buffer_insert_with_tags_by_name (priv->buffer, + &iter, + tmp, + -1, + link_tag, + "link", + NULL); + + g_free (tmp); + + last = e; + } + + if (e < strlen (body)) { + tmp = empathy_substring (body, e, strlen (body)); + + gtk_text_buffer_get_end_iter (priv->buffer, &iter); + chat_view_insert_text_with_emoticons (priv->buffer, + &iter, + tmp); + g_free (tmp); + } + } + + g_array_free (start, TRUE); + g_array_free (end, TRUE); + + gtk_text_buffer_get_end_iter (priv->buffer, &iter); + gtk_text_buffer_insert (priv->buffer, &iter, "\n", 1); + + /* Apply the style to the inserted text. */ + gtk_text_buffer_get_iter_at_mark (priv->buffer, &start_iter, mark); + gtk_text_buffer_get_end_iter (priv->buffer, &end_iter); + + gtk_text_buffer_apply_tag_by_name (priv->buffer, + tag, + &start_iter, + &end_iter); + + gtk_text_buffer_delete_mark (priv->buffer, mark); +} + +static void +chat_view_maybe_append_fancy_header (EmpathyChatView *view, + EmpathyMessage *msg) +{ + EmpathyChatViewPriv *priv; + EmpathyContact *sender; + const gchar *name; + gboolean header; + GtkTextIter iter; + gchar *tmp; + const gchar *tag; + const gchar *avatar_tag; + const gchar *line_top_tag; + const gchar *line_bottom_tag; + gboolean from_self; + GdkPixbuf *pixbuf = NULL; + GdkPixbuf *avatar = NULL; + + priv = GET_PRIV (view); + + sender = empathy_message_get_sender (msg); + name = empathy_contact_get_name (sender); + from_self = empathy_contact_is_user (sender); + + empathy_debug (DEBUG_DOMAIN, "Maybe add fancy header"); + + if (from_self) { + tag = "fancy-header-self"; + line_top_tag = "fancy-line-top-self"; + line_bottom_tag = "fancy-line-bottom-self"; + } else { + tag = "fancy-header-other"; + line_top_tag = "fancy-line-top-other"; + line_bottom_tag = "fancy-line-bottom-other"; + } + + header = FALSE; + + /* Only insert a header if the previously inserted block is not the same + * as this one. This catches all the different cases: + */ + if (priv->last_block_type != BLOCK_TYPE_SELF && + priv->last_block_type != BLOCK_TYPE_OTHER) { + header = TRUE; + } + else if (from_self && priv->last_block_type == BLOCK_TYPE_OTHER) { + header = TRUE; + } + else if (!from_self && priv->last_block_type == BLOCK_TYPE_SELF) { + header = TRUE; + } + else if (!from_self && + (!priv->last_contact || + !empathy_contact_equal (sender, priv->last_contact))) { + header = TRUE; + } + + if (!header) { + return; + } + + chat_view_append_spacing (view); + + gtk_text_buffer_get_end_iter (priv->buffer, &iter); + gtk_text_buffer_insert_with_tags_by_name (priv->buffer, + &iter, + "\n", + -1, + line_top_tag, + NULL); + + /* FIXME: we should have a cash of avatar pixbufs */ + pixbuf = empathy_pixbuf_avatar_from_contact_scaled (sender, 32, 32); + if (pixbuf) { + avatar = chat_view_pad_to_size (pixbuf, 32, 32, 6); + g_object_unref (pixbuf); + } + + if (avatar) { + GtkTextIter start; + + gtk_text_buffer_get_end_iter (priv->buffer, &iter); + gtk_text_buffer_insert_pixbuf (priv->buffer, &iter, avatar); + + gtk_text_buffer_get_end_iter (priv->buffer, &iter); + start = iter; + gtk_text_iter_backward_char (&start); + + if (from_self) { + gtk_text_buffer_apply_tag_by_name (priv->buffer, + "fancy-avatar-self", + &start, &iter); + avatar_tag = "fancy-header-self-avatar"; + } else { + gtk_text_buffer_apply_tag_by_name (priv->buffer, + "fancy-avatar-other", + &start, &iter); + avatar_tag = "fancy-header-other-avatar"; + } + + g_object_unref (avatar); + } else { + avatar_tag = NULL; + } + + tmp = g_strdup_printf ("%s\n", name); + + gtk_text_buffer_get_end_iter (priv->buffer, &iter); + gtk_text_buffer_insert_with_tags_by_name (priv->buffer, + &iter, + tmp, + -1, + tag, + avatar_tag, + NULL); + g_free (tmp); + + gtk_text_buffer_get_end_iter (priv->buffer, &iter); + gtk_text_buffer_insert_with_tags_by_name (priv->buffer, + &iter, + "\n", + -1, + line_bottom_tag, + NULL); +} + +static void +chat_view_append_irc_action (EmpathyChatView *view, + EmpathyMessage *msg) +{ + EmpathyChatViewPriv *priv; + EmpathyContact *sender; + const gchar *name; + GtkTextIter iter; + const gchar *body; + gchar *tmp; + const gchar *tag; + + priv = GET_PRIV (view); + + empathy_debug (DEBUG_DOMAIN, "Add IRC action"); + + sender = empathy_message_get_sender (msg); + name = empathy_contact_get_name (sender); + + if (empathy_contact_is_user (sender)) { + tag = "irc-action-self"; + } else { + tag = "irc-action-other"; + } + + if (priv->last_block_type != BLOCK_TYPE_SELF && + priv->last_block_type != BLOCK_TYPE_OTHER) { + chat_view_append_spacing (view); + } + + gtk_text_buffer_get_end_iter (priv->buffer, &iter); + + tmp = g_strdup_printf (" * %s ", name); + gtk_text_buffer_insert_with_tags_by_name (priv->buffer, + &iter, + tmp, + -1, + "cut", + tag, + NULL); + g_free (tmp); + + body = empathy_message_get_body (msg); + chat_view_append_text (view, body, tag); +} + +static void +chat_view_append_fancy_action (EmpathyChatView *view, + EmpathyMessage *msg) +{ + EmpathyChatViewPriv *priv; + EmpathyContact *sender; + const gchar *name; + const gchar *body; + GtkTextIter iter; + gchar *tmp; + const gchar *tag; + const gchar *line_tag; + + priv = GET_PRIV (view); + + empathy_debug (DEBUG_DOMAIN, "Add fancy action"); + + sender = empathy_message_get_sender (msg); + name = empathy_contact_get_name (sender); + + if (empathy_contact_is_user (sender)) { + tag = "fancy-action-self"; + line_tag = "fancy-line-self"; + } else { + tag = "fancy-action-other"; + line_tag = "fancy-line-other"; + } + + tmp = g_strdup_printf (" * %s ", name); + gtk_text_buffer_get_end_iter (priv->buffer, &iter); + gtk_text_buffer_insert_with_tags_by_name (priv->buffer, + &iter, + tmp, + -1, + tag, + NULL); + g_free (tmp); + + body = empathy_message_get_body (msg); + chat_view_append_text (view, body, tag); +} + +static void +chat_view_append_irc_message (EmpathyChatView *view, + EmpathyMessage *msg) +{ + EmpathyChatViewPriv *priv; + EmpathyContact *sender; + const gchar *name; + const gchar *body; + const gchar *nick_tag; + const gchar *body_tag; + GtkTextIter iter; + gchar *tmp; + + priv = GET_PRIV (view); + + empathy_debug (DEBUG_DOMAIN, "Add IRC message"); + + body = empathy_message_get_body (msg); + sender = empathy_message_get_sender (msg); + name = empathy_contact_get_name (sender); + + if (empathy_contact_is_user (sender)) { + nick_tag = "irc-nick-self"; + body_tag = "irc-body-self"; + } else { + if (empathy_chat_should_highlight_nick (msg)) { + nick_tag = "irc-nick-highlight"; + } else { + nick_tag = "irc-nick-other"; + } + + body_tag = "irc-body-other"; + } + + if (priv->last_block_type != BLOCK_TYPE_SELF && + priv->last_block_type != BLOCK_TYPE_OTHER) { + chat_view_append_spacing (view); + } + + gtk_text_buffer_get_end_iter (priv->buffer, &iter); + + /* The nickname. */ + tmp = g_strdup_printf ("%s: ", name); + gtk_text_buffer_insert_with_tags_by_name (priv->buffer, + &iter, + tmp, + -1, + "cut", + nick_tag, + NULL); + g_free (tmp); + + /* The text body. */ + chat_view_append_text (view, body, body_tag); +} + +static void +chat_view_append_fancy_message (EmpathyChatView *view, + EmpathyMessage *msg) +{ + EmpathyChatViewPriv *priv; + EmpathyContact *sender; + const gchar *body; + const gchar *tag; + + priv = GET_PRIV (view); + + sender = empathy_message_get_sender (msg); + + if (empathy_contact_is_user (sender)) { + tag = "fancy-body-self"; + } else { + tag = "fancy-body-other"; + + /* FIXME: Might want to support nick highlighting here... */ + } + + body = empathy_message_get_body (msg); + chat_view_append_text (view, body, tag); +} + +static void +chat_view_theme_changed_cb (EmpathyThemeManager *manager, + EmpathyChatView *view) +{ + EmpathyChatViewPriv *priv; + gboolean show_avatars = FALSE; + gboolean theme_rooms = FALSE; + + priv = GET_PRIV (view); + + priv->last_block_type = BLOCK_TYPE_NONE; + + empathy_conf_get_bool (empathy_conf_get (), + EMPATHY_PREFS_CHAT_THEME_CHAT_ROOM, + &theme_rooms); + if (!theme_rooms && priv->is_group_chat) { + empathy_theme_manager_apply (manager, view, NULL); + } else { + empathy_theme_manager_apply_saved (manager, view); + } + + /* Needed for now to update the "rise" property of the names to get it + * vertically centered. + */ + empathy_conf_get_bool (empathy_conf_get (), + EMPATHY_PREFS_UI_SHOW_AVATARS, + &show_avatars); + empathy_theme_manager_update_show_avatars (manager, view, show_avatars); +} + +/* Pads a pixbuf to the specified size, by centering it in a larger transparent + * pixbuf. Returns a new ref. + */ +static GdkPixbuf * +chat_view_pad_to_size (GdkPixbuf *pixbuf, + gint width, + gint height, + gint extra_padding_right) +{ + gint src_width, src_height; + GdkPixbuf *padded; + gint x_offset, y_offset; + + src_width = gdk_pixbuf_get_width (pixbuf); + src_height = gdk_pixbuf_get_height (pixbuf); + + x_offset = (width - src_width) / 2; + y_offset = (height - src_height) / 2; + + padded = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (pixbuf), + TRUE, /* alpha */ + gdk_pixbuf_get_bits_per_sample (pixbuf), + width + extra_padding_right, + height); + + gdk_pixbuf_fill (padded, 0); + + gdk_pixbuf_copy_area (pixbuf, + 0, /* source coords */ + 0, + src_width, + src_height, + padded, + x_offset, /* dest coords */ + y_offset); + + return padded; +} + +EmpathyChatView * +empathy_chat_view_new (void) +{ + return g_object_new (EMPATHY_TYPE_CHAT_VIEW, NULL); +} + +/* The name is optional, if NULL, the sender for msg is used. */ +void +empathy_chat_view_append_message (EmpathyChatView *view, + EmpathyMessage *msg) +{ + EmpathyChatViewPriv *priv; + EmpathyContact *sender; + const gchar *body; + gboolean scroll_down; + + g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view)); + g_return_if_fail (EMPATHY_IS_MESSAGE (msg)); + + priv = GET_PRIV (view); + + body = empathy_message_get_body (msg); + if (!body) { + return; + } + + scroll_down = chat_view_is_scrolled_down (view); + + chat_view_maybe_trim_buffer (view); + chat_view_maybe_append_date_and_time (view, msg); + + sender = empathy_message_get_sender (msg); + + if (!priv->irc_style) { + chat_view_maybe_append_fancy_header (view, msg); + } + + if (empathy_message_get_type (msg) == EMPATHY_MESSAGE_TYPE_ACTION) { + if (priv->irc_style) { + chat_view_append_irc_action (view, msg); + } else { + chat_view_append_fancy_action (view, msg); + } + } else { + if (priv->irc_style) { + chat_view_append_irc_message (view, msg); + } else { + chat_view_append_fancy_message (view, msg); + } + } + + /* Reset the last inserted contact. */ + if (priv->last_contact) { + g_object_unref (priv->last_contact); + } + + if (empathy_contact_is_user (sender)) { + priv->last_block_type = BLOCK_TYPE_SELF; + priv->last_contact = NULL; + } else { + priv->last_block_type = BLOCK_TYPE_OTHER; + priv->last_contact = g_object_ref (sender); + } + + if (scroll_down) { + empathy_chat_view_scroll_down (view); + } +} + +void +empathy_chat_view_append_event (EmpathyChatView *view, + const gchar *str) +{ + EmpathyChatViewPriv *priv; + gboolean bottom; + GtkTextIter iter; + gchar *msg; + const gchar *tag; + + g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view)); + g_return_if_fail (!G_STR_EMPTY (str)); + + priv = GET_PRIV (view); + + bottom = chat_view_is_scrolled_down (view); + + chat_view_maybe_trim_buffer (view); + + if (priv->irc_style) { + tag = "irc-event"; + msg = g_strdup_printf (" - %s\n", str); + } else { + tag = "fancy-event"; + msg = g_strdup_printf (" - %s\n", str); + } + + if (priv->last_block_type != BLOCK_TYPE_EVENT) { + /* Comment out for now. */ + /*chat_view_append_spacing (view);*/ + } + + chat_view_maybe_append_date_and_time (view, NULL); + + gtk_text_buffer_get_end_iter (priv->buffer, &iter); + + gtk_text_buffer_insert_with_tags_by_name (priv->buffer, &iter, + msg, -1, + tag, + NULL); + g_free (msg); + + if (bottom) { + empathy_chat_view_scroll_down (view); + } + + priv->last_block_type = BLOCK_TYPE_EVENT; +} + +void +empathy_chat_view_append_button (EmpathyChatView *view, + const gchar *message, + GtkWidget *button1, + GtkWidget *button2) +{ + EmpathyChatViewPriv *priv; + GtkTextChildAnchor *anchor; + GtkTextIter iter; + gboolean bottom; + const gchar *tag; + + g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view)); + g_return_if_fail (button1 != NULL); + + priv = GET_PRIV (view); + + if (priv->irc_style) { + tag = "irc-invite"; + } else { + tag = "fancy-invite"; + } + + bottom = chat_view_is_scrolled_down (view); + + chat_view_maybe_append_date_and_time (view, NULL); + + if (message) { + chat_view_append_text (view, message, tag); + } + + gtk_text_buffer_get_end_iter (priv->buffer, &iter); + + anchor = gtk_text_buffer_create_child_anchor (priv->buffer, &iter); + gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view), button1, anchor); + gtk_widget_show (button1); + + gtk_text_buffer_insert_with_tags_by_name (priv->buffer, + &iter, + " ", + 1, + tag, + NULL); + + if (button2) { + gtk_text_buffer_get_end_iter (priv->buffer, &iter); + + anchor = gtk_text_buffer_create_child_anchor (priv->buffer, &iter); + gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view), button2, anchor); + gtk_widget_show (button2); + + gtk_text_buffer_insert_with_tags_by_name (priv->buffer, + &iter, + " ", + 1, + tag, + NULL); + } + + gtk_text_buffer_get_end_iter (priv->buffer, &iter); + gtk_text_buffer_insert_with_tags_by_name (priv->buffer, + &iter, + "\n\n", + 2, + tag, + NULL); + + if (bottom) { + empathy_chat_view_scroll_down (view); + } + + priv->last_block_type = BLOCK_TYPE_INVITE; +} + +void +empathy_chat_view_scroll (EmpathyChatView *view, + gboolean allow_scrolling) +{ + EmpathyChatViewPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view)); + + priv = GET_PRIV (view); + + priv->allow_scrolling = allow_scrolling; + + empathy_debug (DEBUG_DOMAIN, "Scrolling %s", + allow_scrolling ? "enabled" : "disabled"); +} + +/* Code stolen from pidgin/gtkimhtml.c */ +static gboolean +chat_view_scroll_cb (EmpathyChatView *view) +{ + EmpathyChatViewPriv *priv; + GtkAdjustment *adj; + gdouble max_val; + + priv = GET_PRIV (view); + adj = GTK_TEXT_VIEW (view)->vadjustment; + max_val = adj->upper - adj->page_size; + + g_return_val_if_fail (priv->scroll_time != NULL, FALSE); + + if (g_timer_elapsed (priv->scroll_time, NULL) > MAX_SCROLL_TIME) { + /* time's up. jump to the end and kill the timer */ + gtk_adjustment_set_value (adj, max_val); + g_timer_destroy (priv->scroll_time); + priv->scroll_time = NULL; + priv->scroll_timeout = 0; + return FALSE; + } + + /* scroll by 1/3rd the remaining distance */ + gtk_adjustment_set_value (adj, gtk_adjustment_get_value (adj) + ((max_val - gtk_adjustment_get_value (adj)) / 3)); + return TRUE; +} + +void +empathy_chat_view_scroll_down (EmpathyChatView *view) +{ + EmpathyChatViewPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view)); + + priv = GET_PRIV (view); + + if (!priv->allow_scrolling) { + return; + } + + empathy_debug (DEBUG_DOMAIN, "Scrolling down"); + + if (priv->scroll_time) { + g_timer_reset (priv->scroll_time); + } else { + priv->scroll_time = g_timer_new(); + } + if (!priv->scroll_timeout) { + priv->scroll_timeout = g_timeout_add (SCROLL_DELAY, + (GSourceFunc) chat_view_scroll_cb, + view); + } +} + +gboolean +empathy_chat_view_get_selection_bounds (EmpathyChatView *view, + GtkTextIter *start, + GtkTextIter *end) +{ + GtkTextBuffer *buffer; + + g_return_val_if_fail (EMPATHY_IS_CHAT_VIEW (view), FALSE); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); + + return gtk_text_buffer_get_selection_bounds (buffer, start, end); +} + +void +empathy_chat_view_clear (EmpathyChatView *view) +{ + GtkTextBuffer *buffer; + EmpathyChatViewPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view)); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); + gtk_text_buffer_set_text (buffer, "", -1); + + /* We set these back to the initial values so we get + * timestamps when clearing the window to know when + * conversations start. + */ + priv = GET_PRIV (view); + + priv->last_block_type = BLOCK_TYPE_NONE; + priv->last_timestamp = 0; +} + +gboolean +empathy_chat_view_find_previous (EmpathyChatView *view, + const gchar *search_criteria, + gboolean new_search) +{ + EmpathyChatViewPriv *priv; + GtkTextBuffer *buffer; + GtkTextIter iter_at_mark; + GtkTextIter iter_match_start; + GtkTextIter iter_match_end; + gboolean found; + gboolean from_start = FALSE; + + g_return_val_if_fail (EMPATHY_IS_CHAT_VIEW (view), FALSE); + g_return_val_if_fail (search_criteria != NULL, FALSE); + + priv = GET_PRIV (view); + + buffer = priv->buffer; + + if (G_STR_EMPTY (search_criteria)) { + if (priv->find_mark_previous) { + gtk_text_buffer_get_start_iter (buffer, &iter_at_mark); + + gtk_text_buffer_move_mark (buffer, + priv->find_mark_previous, + &iter_at_mark); + gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view), + priv->find_mark_previous, + 0.0, + TRUE, + 0.0, + 0.0); + gtk_text_buffer_select_range (buffer, + &iter_at_mark, + &iter_at_mark); + } + + return FALSE; + } + + if (new_search) { + from_start = TRUE; + } + + if (priv->find_mark_previous) { + gtk_text_buffer_get_iter_at_mark (buffer, + &iter_at_mark, + priv->find_mark_previous); + } else { + gtk_text_buffer_get_end_iter (buffer, &iter_at_mark); + from_start = TRUE; + } + + priv->find_last_direction = FALSE; + + found = empathy_text_iter_backward_search (&iter_at_mark, + search_criteria, + &iter_match_start, + &iter_match_end, + NULL); + + if (!found) { + gboolean result = FALSE; + + if (from_start) { + return result; + } + + /* Here we wrap around. */ + if (!new_search && !priv->find_wrapped) { + priv->find_wrapped = TRUE; + result = empathy_chat_view_find_previous (view, + search_criteria, + FALSE); + priv->find_wrapped = FALSE; + } + + return result; + } + + /* Set new mark and show on screen */ + if (!priv->find_mark_previous) { + priv->find_mark_previous = gtk_text_buffer_create_mark (buffer, NULL, + &iter_match_start, + TRUE); + } else { + gtk_text_buffer_move_mark (buffer, + priv->find_mark_previous, + &iter_match_start); + } + + if (!priv->find_mark_next) { + priv->find_mark_next = gtk_text_buffer_create_mark (buffer, NULL, + &iter_match_end, + TRUE); + } else { + gtk_text_buffer_move_mark (buffer, + priv->find_mark_next, + &iter_match_end); + } + + gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view), + priv->find_mark_previous, + 0.0, + TRUE, + 0.5, + 0.5); + + gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &iter_match_start); + gtk_text_buffer_move_mark_by_name (buffer, "insert", &iter_match_end); + + return TRUE; +} + +gboolean +empathy_chat_view_find_next (EmpathyChatView *view, + const gchar *search_criteria, + gboolean new_search) +{ + EmpathyChatViewPriv *priv; + GtkTextBuffer *buffer; + GtkTextIter iter_at_mark; + GtkTextIter iter_match_start; + GtkTextIter iter_match_end; + gboolean found; + gboolean from_start = FALSE; + + g_return_val_if_fail (EMPATHY_IS_CHAT_VIEW (view), FALSE); + g_return_val_if_fail (search_criteria != NULL, FALSE); + + priv = GET_PRIV (view); + + buffer = priv->buffer; + + if (G_STR_EMPTY (search_criteria)) { + if (priv->find_mark_next) { + gtk_text_buffer_get_start_iter (buffer, &iter_at_mark); + + gtk_text_buffer_move_mark (buffer, + priv->find_mark_next, + &iter_at_mark); + gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view), + priv->find_mark_next, + 0.0, + TRUE, + 0.0, + 0.0); + gtk_text_buffer_select_range (buffer, + &iter_at_mark, + &iter_at_mark); + } + + return FALSE; + } + + if (new_search) { + from_start = TRUE; + } + + if (priv->find_mark_next) { + gtk_text_buffer_get_iter_at_mark (buffer, + &iter_at_mark, + priv->find_mark_next); + } else { + gtk_text_buffer_get_start_iter (buffer, &iter_at_mark); + from_start = TRUE; + } + + priv->find_last_direction = TRUE; + + found = empathy_text_iter_forward_search (&iter_at_mark, + search_criteria, + &iter_match_start, + &iter_match_end, + NULL); + + if (!found) { + gboolean result = FALSE; + + if (from_start) { + return result; + } + + /* Here we wrap around. */ + if (!new_search && !priv->find_wrapped) { + priv->find_wrapped = TRUE; + result = empathy_chat_view_find_next (view, + search_criteria, + FALSE); + priv->find_wrapped = FALSE; + } + + return result; + } + + /* Set new mark and show on screen */ + if (!priv->find_mark_next) { + priv->find_mark_next = gtk_text_buffer_create_mark (buffer, NULL, + &iter_match_end, + TRUE); + } else { + gtk_text_buffer_move_mark (buffer, + priv->find_mark_next, + &iter_match_end); + } + + if (!priv->find_mark_previous) { + priv->find_mark_previous = gtk_text_buffer_create_mark (buffer, NULL, + &iter_match_start, + TRUE); + } else { + gtk_text_buffer_move_mark (buffer, + priv->find_mark_previous, + &iter_match_start); + } + + gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view), + priv->find_mark_next, + 0.0, + TRUE, + 0.5, + 0.5); + + gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &iter_match_start); + gtk_text_buffer_move_mark_by_name (buffer, "insert", &iter_match_end); + + return TRUE; +} + + +void +empathy_chat_view_find_abilities (EmpathyChatView *view, + const gchar *search_criteria, + gboolean *can_do_previous, + gboolean *can_do_next) +{ + EmpathyChatViewPriv *priv; + GtkTextBuffer *buffer; + GtkTextIter iter_at_mark; + GtkTextIter iter_match_start; + GtkTextIter iter_match_end; + + g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view)); + g_return_if_fail (search_criteria != NULL); + g_return_if_fail (can_do_previous != NULL && can_do_next != NULL); + + priv = GET_PRIV (view); + + buffer = priv->buffer; + + if (can_do_previous) { + if (priv->find_mark_previous) { + gtk_text_buffer_get_iter_at_mark (buffer, + &iter_at_mark, + priv->find_mark_previous); + } else { + gtk_text_buffer_get_start_iter (buffer, &iter_at_mark); + } + + *can_do_previous = empathy_text_iter_backward_search (&iter_at_mark, + search_criteria, + &iter_match_start, + &iter_match_end, + NULL); + } + + if (can_do_next) { + if (priv->find_mark_next) { + gtk_text_buffer_get_iter_at_mark (buffer, + &iter_at_mark, + priv->find_mark_next); + } else { + gtk_text_buffer_get_start_iter (buffer, &iter_at_mark); + } + + *can_do_next = empathy_text_iter_forward_search (&iter_at_mark, + search_criteria, + &iter_match_start, + &iter_match_end, + NULL); + } +} + +void +empathy_chat_view_highlight (EmpathyChatView *view, + const gchar *text) +{ + GtkTextBuffer *buffer; + GtkTextIter iter; + GtkTextIter iter_start; + GtkTextIter iter_end; + GtkTextIter iter_match_start; + GtkTextIter iter_match_end; + gboolean found; + + g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view)); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); + + gtk_text_buffer_get_start_iter (buffer, &iter); + + gtk_text_buffer_get_bounds (buffer, &iter_start, &iter_end); + gtk_text_buffer_remove_tag_by_name (buffer, "highlight", + &iter_start, + &iter_end); + + if (G_STR_EMPTY (text)) { + return; + } + + while (1) { + found = empathy_text_iter_forward_search (&iter, + text, + &iter_match_start, + &iter_match_end, + NULL); + + if (!found) { + break; + } + + gtk_text_buffer_apply_tag_by_name (buffer, "highlight", + &iter_match_start, + &iter_match_end); + + iter = iter_match_end; + gtk_text_iter_forward_char (&iter); + } +} + +void +empathy_chat_view_copy_clipboard (EmpathyChatView *view) +{ + GtkTextBuffer *buffer; + GtkClipboard *clipboard; + + g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view)); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); + clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); + + gtk_text_buffer_copy_clipboard (buffer, clipboard); +} + +gboolean +empathy_chat_view_get_irc_style (EmpathyChatView *view) +{ + EmpathyChatViewPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CHAT_VIEW (view), FALSE); + + priv = GET_PRIV (view); + + return priv->irc_style; +} + +void +empathy_chat_view_set_irc_style (EmpathyChatView *view, + gboolean irc_style) +{ + EmpathyChatViewPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view)); + + priv = GET_PRIV (view); + + priv->irc_style = irc_style; +} + +void +empathy_chat_view_set_margin (EmpathyChatView *view, + gint margin) +{ + EmpathyChatViewPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view)); + + priv = GET_PRIV (view); + + g_object_set (view, + "left-margin", margin, + "right-margin", margin, + NULL); +} + +GdkPixbuf * +empathy_chat_view_get_smiley_image (EmpathySmiley smiley) +{ + static GdkPixbuf *pixbufs[EMPATHY_SMILEY_COUNT]; + static gboolean inited = FALSE; + + if (!inited) { + gint i; + + for (i = 0; i < EMPATHY_SMILEY_COUNT; i++) { + pixbufs[i] = empathy_pixbuf_from_smiley (i, GTK_ICON_SIZE_MENU); + } + + inited = TRUE; + } + + return pixbufs[smiley]; +} + +const gchar * +empathy_chat_view_get_smiley_text (EmpathySmiley smiley) +{ + gint i; + + for (i = 0; i < G_N_ELEMENTS (smileys); i++) { + if (smileys[i].smiley != smiley) { + continue; + } + + return smileys[i].pattern; + } + + return NULL; +} + +GtkWidget * +empathy_chat_view_get_smiley_menu (GCallback callback, + gpointer user_data, + GtkTooltips *tooltips) +{ + GtkWidget *menu; + gint x; + gint y; + gint i; + + g_return_val_if_fail (callback != NULL, NULL); + + menu = gtk_menu_new (); + + for (i = 0, x = 0, y = 0; i < EMPATHY_SMILEY_COUNT; i++) { + GtkWidget *item; + GtkWidget *image; + GdkPixbuf *pixbuf; + const gchar *smiley_text; + + pixbuf = empathy_chat_view_get_smiley_image (i); + if (!pixbuf) { + continue; + } + + image = gtk_image_new_from_pixbuf (pixbuf); + + item = gtk_image_menu_item_new_with_label (""); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); + + gtk_menu_attach (GTK_MENU (menu), item, + x, x + 1, y, y + 1); + + smiley_text = empathy_chat_view_get_smiley_text (i); + + gtk_tooltips_set_tip (tooltips, + item, + smiley_text, + NULL); + + g_object_set_data (G_OBJECT (item), "smiley_text", (gpointer) smiley_text); + g_signal_connect (item, "activate", callback, user_data); + + if (x > 3) { + y++; + x = 0; + } else { + x++; + } + } + + gtk_widget_show_all (menu); + + return menu; +} + +/* FIXME: Do we really need this? Better to do it internally only at setup time, + * we will never change it on the fly. + */ +void +empathy_chat_view_set_is_group_chat (EmpathyChatView *view, + gboolean is_group_chat) +{ + EmpathyChatViewPriv *priv; + gboolean theme_rooms = FALSE; + + g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view)); + + priv = GET_PRIV (view); + + priv->is_group_chat = is_group_chat; + + empathy_conf_get_bool (empathy_conf_get (), + EMPATHY_PREFS_CHAT_THEME_CHAT_ROOM, + &theme_rooms); + + if (!theme_rooms && is_group_chat) { + empathy_theme_manager_apply (empathy_theme_manager_get (), + view, + NULL); + } else { + empathy_theme_manager_apply_saved (empathy_theme_manager_get (), + view); + } +} diff --git a/libempathy-gtk/empathy-chat-view.h b/libempathy-gtk/empathy-chat-view.h new file mode 100644 index 00000000..4478e211 --- /dev/null +++ b/libempathy-gtk/empathy-chat-view.h @@ -0,0 +1,134 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2002-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Richard Hult + * Martyn Russell + */ + +#ifndef __EMPATHY_CHAT_VIEW_H__ +#define __EMPATHY_CHAT_VIEW_H__ + +#include +#include + +#include +#include + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_CHAT_VIEW (empathy_chat_view_get_type ()) +#define EMPATHY_CHAT_VIEW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_CHAT_VIEW, EmpathyChatView)) +#define EMPATHY_CHAT_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_CHAT_VIEW, EmpathyChatViewClass)) +#define EMPATHY_IS_CHAT_VIEW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_CHAT_VIEW)) +#define EMPATHY_IS_CHAT_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_CHAT_VIEW)) +#define EMPATHY_CHAT_VIEW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_CHAT_VIEW, EmpathyChatViewClass)) + +typedef struct _EmpathyChatView EmpathyChatView; +typedef struct _EmpathyChatViewClass EmpathyChatViewClass; +typedef struct _EmpathyChatViewPriv EmpathyChatViewPriv; + +struct _EmpathyChatView { + GtkTextView parent; +}; + +struct _EmpathyChatViewClass { + GtkTextViewClass parent_class; +}; + +typedef enum { + EMPATHY_SMILEY_NORMAL, /* :) */ + EMPATHY_SMILEY_WINK, /* ;) */ + EMPATHY_SMILEY_BIGEYE, /* =) */ + EMPATHY_SMILEY_NOSE, /* :-) */ + EMPATHY_SMILEY_CRY, /* :'( */ + EMPATHY_SMILEY_SAD, /* :( */ + EMPATHY_SMILEY_SCEPTICAL, /* :/ */ + EMPATHY_SMILEY_BIGSMILE, /* :D */ + EMPATHY_SMILEY_INDIFFERENT, /* :| */ + EMPATHY_SMILEY_TOUNGE, /* :p */ + EMPATHY_SMILEY_SHOCKED, /* :o */ + EMPATHY_SMILEY_COOL, /* 8) */ + EMPATHY_SMILEY_SORRY, /* *| */ + EMPATHY_SMILEY_KISS, /* :* */ + EMPATHY_SMILEY_SHUTUP, /* :# */ + EMPATHY_SMILEY_YAWN, /* |O */ + EMPATHY_SMILEY_CONFUSED, /* :$ */ + EMPATHY_SMILEY_ANGEL, /* <) */ + EMPATHY_SMILEY_OOOH, /* :x */ + EMPATHY_SMILEY_LOOKAWAY, /* *) */ + EMPATHY_SMILEY_BLUSH, /* *S */ + EMPATHY_SMILEY_COOLBIGSMILE, /* 8D */ + EMPATHY_SMILEY_ANGRY, /* :@ */ + EMPATHY_SMILEY_BOSS, /* @) */ + EMPATHY_SMILEY_MONKEY, /* #) */ + EMPATHY_SMILEY_SILLY, /* O) */ + EMPATHY_SMILEY_SICK, /* +o( */ + + EMPATHY_SMILEY_COUNT +} EmpathySmiley; + +GType empathy_chat_view_get_type (void) G_GNUC_CONST; +EmpathyChatView *empathy_chat_view_new (void); +void empathy_chat_view_append_message (EmpathyChatView *view, + EmpathyMessage *msg); +void empathy_chat_view_append_event (EmpathyChatView *view, + const gchar *str); +void empathy_chat_view_append_button (EmpathyChatView *view, + const gchar *message, + GtkWidget *button1, + GtkWidget *button2); +void empathy_chat_view_set_margin (EmpathyChatView *view, + gint margin); +void empathy_chat_view_scroll (EmpathyChatView *view, + gboolean allow_scrolling); +void empathy_chat_view_scroll_down (EmpathyChatView *view); +gboolean empathy_chat_view_get_selection_bounds (EmpathyChatView *view, + GtkTextIter *start, + GtkTextIter *end); +void empathy_chat_view_clear (EmpathyChatView *view); +gboolean empathy_chat_view_find_previous (EmpathyChatView *view, + const gchar *search_criteria, + gboolean new_search); +gboolean empathy_chat_view_find_next (EmpathyChatView *view, + const gchar *search_criteria, + gboolean new_search); +void empathy_chat_view_find_abilities (EmpathyChatView *view, + const gchar *search_criteria, + gboolean *can_do_previous, + gboolean *can_do_next); +void empathy_chat_view_highlight (EmpathyChatView *view, + const gchar *text); +void empathy_chat_view_copy_clipboard (EmpathyChatView *view); +gboolean empathy_chat_view_get_irc_style (EmpathyChatView *view); +void empathy_chat_view_set_irc_style (EmpathyChatView *view, + gboolean irc_style); +void empathy_chat_view_set_margin (EmpathyChatView *view, + gint margin); +GdkPixbuf * empathy_chat_view_get_smiley_image (EmpathySmiley smiley); +const gchar * empathy_chat_view_get_smiley_text (EmpathySmiley smiley); +GtkWidget * empathy_chat_view_get_smiley_menu (GCallback callback, + gpointer user_data, + GtkTooltips *tooltips); +void empathy_chat_view_set_is_group_chat (EmpathyChatView *view, + gboolean is_group_chat); + +G_END_DECLS + +#endif /* __EMPATHY_CHAT_VIEW_H__ */ diff --git a/libempathy-gtk/empathy-chat-window.c b/libempathy-gtk/empathy-chat-window.c new file mode 100644 index 00000000..7d48abf8 --- /dev/null +++ b/libempathy-gtk/empathy-chat-window.c @@ -0,0 +1,1901 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2003-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Richard Hult + * Martyn Russell + * Geert-Jan Van den Bogaerde + * Xavier Claessens + */ + +#include "config.h" + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "empathy-chat-window.h" +#include "empathy-images.h" +//#include "empathy-chat-invite.h" +#include "empathy-contact-dialogs.h" +#include "empathy-log-window.h" +#include "empathy-new-chatroom-dialog.h" +#include "empathy-preferences.h" +#include "empathy-private-chat.h" +#include "empathy-group-chat.h" +//#include "empathy-sound.h" +#include "empathy-ui-utils.h" + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CHAT_WINDOW, EmpathyChatWindowPriv)) + +#define DEBUG_DOMAIN "ChatWindow" + +#define URGENCY_TIMEOUT 60*1000 + +struct _EmpathyChatWindowPriv { + EmpathyChatroomManager *chatroom_manager; + GList *chats; + GList *chats_new_msg; + GList *chats_composing; + + EmpathyChat *current_chat; + + gboolean page_added; + gboolean dnd_same_window; + + guint urgency_timeout_id; + + GtkWidget *dialog; + GtkWidget *notebook; + + GtkTooltips *tooltips; + + /* Menu items. */ + GtkWidget *menu_conv_clear; + GtkWidget *menu_conv_insert_smiley; + GtkWidget *menu_conv_log; + GtkWidget *menu_conv_separator; + GtkWidget *menu_conv_add_contact; + GtkWidget *menu_conv_info; + GtkWidget *menu_conv_close; + + GtkWidget *menu_room; + GtkWidget *menu_room_set_topic; + GtkWidget *menu_room_join_new; + GtkWidget *menu_room_invite; + GtkWidget *menu_room_add; + GtkWidget *menu_room_show_contacts; + + GtkWidget *menu_edit_cut; + GtkWidget *menu_edit_copy; + GtkWidget *menu_edit_paste; + + GtkWidget *menu_tabs_next; + GtkWidget *menu_tabs_prev; + GtkWidget *menu_tabs_left; + GtkWidget *menu_tabs_right; + GtkWidget *menu_tabs_detach; + + guint save_geometry_id; +}; + +static void empathy_chat_window_class_init (EmpathyChatWindowClass *klass); +static void empathy_chat_window_init (EmpathyChatWindow *window); +static void empathy_chat_window_finalize (GObject *object); +static void chat_window_accel_cb (GtkAccelGroup *accelgroup, + GObject *object, + guint key, + GdkModifierType mod, + EmpathyChatWindow *window); +static void chat_window_close_clicked_cb (GtkWidget *button, + EmpathyChat *chat); +static GtkWidget *chat_window_create_label (EmpathyChatWindow *window, + EmpathyChat *chat); +static void chat_window_update_status (EmpathyChatWindow *window, + EmpathyChat *chat); +static void chat_window_update_title (EmpathyChatWindow *window, + EmpathyChat *chat); +static void chat_window_update_menu (EmpathyChatWindow *window); +static gboolean chat_window_save_geometry_timeout_cb (EmpathyChatWindow *window); +static gboolean chat_window_configure_event_cb (GtkWidget *widget, + GdkEventConfigure *event, + EmpathyChatWindow *window); +static void chat_window_conv_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window); +static void chat_window_clear_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window); +static void chat_window_info_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window); +static void chat_window_add_contact_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window); +static void chat_window_log_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window); +static void chat_window_show_contacts_toggled_cb (GtkWidget *menuitem, + EmpathyChatWindow *window); +static void chat_window_edit_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window); +static void chat_window_insert_smiley_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window); +static void chat_window_close_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window); +static void chat_window_room_set_topic_activate_cb(GtkWidget *menuitem, + EmpathyChatWindow *window); +static void chat_window_room_join_new_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window); +static void chat_window_room_invite_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window); +static void chat_window_room_add_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window); +static void chat_window_cut_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window); +static void chat_window_copy_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window); +static void chat_window_paste_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window); +static void chat_window_tabs_left_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window); +static void chat_window_tabs_right_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window); +static void chat_window_detach_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window); +static gboolean chat_window_delete_event_cb (GtkWidget *dialog, + GdkEvent *event, + EmpathyChatWindow *window); +static void chat_window_status_changed_cb (EmpathyChat *chat, + EmpathyChatWindow *window); +static void chat_window_update_tooltip (EmpathyChatWindow *window, + EmpathyChat *chat); +static void chat_window_name_changed_cb (EmpathyChat *chat, + const gchar *name, + EmpathyChatWindow *window); +static void chat_window_composing_cb (EmpathyChat *chat, + gboolean is_composing, + EmpathyChatWindow *window); +static void chat_window_new_message_cb (EmpathyChat *chat, + EmpathyMessage *message, + gboolean is_backlog, + EmpathyChatWindow *window); +static GtkNotebook* chat_window_detach_hook (GtkNotebook *source, + GtkWidget *page, + gint x, + gint y, + gpointer user_data); +static void chat_window_page_switched_cb (GtkNotebook *notebook, + GtkNotebookPage *page, + gint page_num, + EmpathyChatWindow *window); +static void chat_window_page_reordered_cb (GtkNotebook *notebook, + GtkWidget *widget, + guint page_num, + EmpathyChatWindow *window); +static void chat_window_page_added_cb (GtkNotebook *notebook, + GtkWidget *child, + guint page_num, + EmpathyChatWindow *window); +static void chat_window_page_removed_cb (GtkNotebook *notebook, + GtkWidget *child, + guint page_num, + EmpathyChatWindow *window); +static gboolean chat_window_focus_in_event_cb (GtkWidget *widget, + GdkEvent *event, + EmpathyChatWindow *window); +static void chat_window_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + int x, + int y, + GtkSelectionData *selection, + guint info, + guint time, + EmpathyChatWindow *window); +static void chat_window_set_urgency_hint (EmpathyChatWindow *window, + gboolean urgent); + + +static GList *chat_windows = NULL; + +static const guint tab_accel_keys[] = { + GDK_1, GDK_2, GDK_3, GDK_4, GDK_5, + GDK_6, GDK_7, GDK_8, GDK_9, GDK_0 +}; + +typedef enum { + DND_DRAG_TYPE_CONTACT_ID, + DND_DRAG_TYPE_TAB +} DndDragType; + +static const GtkTargetEntry drag_types_dest[] = { + { "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID }, + { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, DND_DRAG_TYPE_TAB }, +}; + +G_DEFINE_TYPE (EmpathyChatWindow, empathy_chat_window, G_TYPE_OBJECT); + +static void +empathy_chat_window_class_init (EmpathyChatWindowClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = empathy_chat_window_finalize; + + g_type_class_add_private (object_class, sizeof (EmpathyChatWindowPriv)); + + /* Set up a style for the close button with no focus padding. */ + gtk_rc_parse_string ( + "style \"empathy-close-button-style\"\n" + "{\n" + " GtkWidget::focus-padding = 0\n" + " xthickness = 0\n" + " ythickness = 0\n" + "}\n" + "widget \"*.empathy-close-button\" style \"empathy-close-button-style\""); + + gtk_notebook_set_window_creation_hook (chat_window_detach_hook, NULL, NULL); +} + +static void +empathy_chat_window_init (EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + GladeXML *glade; + GtkAccelGroup *accel_group; + GtkWidget *image; + GClosure *closure; + GtkWidget *menu_conv; + GtkWidget *menu; + gint i; + GtkWidget *chat_vbox; + + priv = GET_PRIV (window); + + priv->tooltips = g_object_ref_sink (gtk_tooltips_new ()); + + glade = empathy_glade_get_file ("empathy-chat.glade", + "chat_window", + NULL, + "chat_window", &priv->dialog, + "chat_vbox", &chat_vbox, + "menu_conv", &menu_conv, + "menu_conv_clear", &priv->menu_conv_clear, + "menu_conv_insert_smiley", &priv->menu_conv_insert_smiley, + "menu_conv_log", &priv->menu_conv_log, + "menu_conv_separator", &priv->menu_conv_separator, + "menu_conv_add_contact", &priv->menu_conv_add_contact, + "menu_conv_info", &priv->menu_conv_info, + "menu_conv_close", &priv->menu_conv_close, + "menu_room", &priv->menu_room, + "menu_room_set_topic", &priv->menu_room_set_topic, + "menu_room_join_new", &priv->menu_room_join_new, + "menu_room_invite", &priv->menu_room_invite, + "menu_room_add", &priv->menu_room_add, + "menu_room_show_contacts", &priv->menu_room_show_contacts, + "menu_edit_cut", &priv->menu_edit_cut, + "menu_edit_copy", &priv->menu_edit_copy, + "menu_edit_paste", &priv->menu_edit_paste, + "menu_tabs_next", &priv->menu_tabs_next, + "menu_tabs_prev", &priv->menu_tabs_prev, + "menu_tabs_left", &priv->menu_tabs_left, + "menu_tabs_right", &priv->menu_tabs_right, + "menu_tabs_detach", &priv->menu_tabs_detach, + NULL); + + empathy_glade_connect (glade, + window, + "chat_window", "configure-event", chat_window_configure_event_cb, + "menu_conv", "activate", chat_window_conv_activate_cb, + "menu_conv_clear", "activate", chat_window_clear_activate_cb, + "menu_conv_log", "activate", chat_window_log_activate_cb, + "menu_conv_add_contact", "activate", chat_window_add_contact_activate_cb, + "menu_conv_info", "activate", chat_window_info_activate_cb, + "menu_conv_close", "activate", chat_window_close_activate_cb, + "menu_room_set_topic", "activate", chat_window_room_set_topic_activate_cb, + "menu_room_join_new", "activate", chat_window_room_join_new_activate_cb, + "menu_room_invite", "activate", chat_window_room_invite_activate_cb, + "menu_room_add", "activate", chat_window_room_add_activate_cb, + "menu_edit", "activate", chat_window_edit_activate_cb, + "menu_edit_cut", "activate", chat_window_cut_activate_cb, + "menu_edit_copy", "activate", chat_window_copy_activate_cb, + "menu_edit_paste", "activate", chat_window_paste_activate_cb, + "menu_tabs_left", "activate", chat_window_tabs_left_activate_cb, + "menu_tabs_right", "activate", chat_window_tabs_right_activate_cb, + "menu_tabs_detach", "activate", chat_window_detach_activate_cb, + NULL); + + g_object_unref (glade); + + /* Set up chatroom manager */ + priv->chatroom_manager = empathy_chatroom_manager_new (); + g_signal_connect_swapped (priv->chatroom_manager, "chatroom-added", + G_CALLBACK (chat_window_update_menu), + window); + g_signal_connect_swapped (priv->chatroom_manager, "chatroom-removed", + G_CALLBACK (chat_window_update_menu), + window); + + priv->notebook = gtk_notebook_new (); + gtk_notebook_set_group_id (GTK_NOTEBOOK (priv->notebook), 1); + gtk_box_pack_start (GTK_BOX (chat_vbox), priv->notebook, TRUE, TRUE, 0); + gtk_widget_show (priv->notebook); + + /* Set up accels */ + accel_group = gtk_accel_group_new (); + gtk_window_add_accel_group (GTK_WINDOW (priv->dialog), accel_group); + + for (i = 0; i < G_N_ELEMENTS (tab_accel_keys); i++) { + closure = g_cclosure_new (G_CALLBACK (chat_window_accel_cb), + window, + NULL); + gtk_accel_group_connect (accel_group, + tab_accel_keys[i], + GDK_MOD1_MASK, + 0, + closure); + } + + g_object_unref (accel_group); + + /* Set the contact information menu item image to the Empathy + * stock image + */ + image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (priv->menu_conv_info)); + gtk_image_set_from_icon_name (GTK_IMAGE (image), + EMPATHY_IMAGE_CONTACT_INFORMATION, + GTK_ICON_SIZE_MENU); + + /* Set up smiley menu */ + menu = empathy_chat_view_get_smiley_menu ( + G_CALLBACK (chat_window_insert_smiley_activate_cb), + window, + priv->tooltips); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (priv->menu_conv_insert_smiley), menu); + + /* Set up signals we can't do with glade since we may need to + * block/unblock them at some later stage. + */ + + g_signal_connect (priv->dialog, + "delete_event", + G_CALLBACK (chat_window_delete_event_cb), + window); + + g_signal_connect (priv->menu_room_show_contacts, + "toggled", + G_CALLBACK (chat_window_show_contacts_toggled_cb), + window); + + g_signal_connect_swapped (priv->menu_tabs_prev, + "activate", + G_CALLBACK (gtk_notebook_prev_page), + priv->notebook); + g_signal_connect_swapped (priv->menu_tabs_next, + "activate", + G_CALLBACK (gtk_notebook_next_page), + priv->notebook); + + g_signal_connect (priv->dialog, + "focus_in_event", + G_CALLBACK (chat_window_focus_in_event_cb), + window); + g_signal_connect_after (priv->notebook, + "switch_page", + G_CALLBACK (chat_window_page_switched_cb), + window); + g_signal_connect (priv->notebook, + "page_reordered", + G_CALLBACK (chat_window_page_reordered_cb), + window); + g_signal_connect (priv->notebook, + "page_added", + G_CALLBACK (chat_window_page_added_cb), + window); + g_signal_connect (priv->notebook, + "page_removed", + G_CALLBACK (chat_window_page_removed_cb), + window); + + /* Set up drag and drop */ + gtk_drag_dest_set (GTK_WIDGET (priv->notebook), + GTK_DEST_DEFAULT_ALL, + drag_types_dest, + G_N_ELEMENTS (drag_types_dest), + GDK_ACTION_MOVE); + + g_signal_connect (priv->notebook, + "drag-data-received", + G_CALLBACK (chat_window_drag_data_received), + window); + + chat_windows = g_list_prepend (chat_windows, window); + + /* Set up private details */ + priv->chats = NULL; + priv->chats_new_msg = NULL; + priv->chats_composing = NULL; + priv->current_chat = NULL; +} + +/* Returns the window to open a new tab in if there is only one window + * visble, otherwise, returns NULL indicating that a new window should + * be added. + */ +EmpathyChatWindow * +empathy_chat_window_get_default (void) +{ + GList *l; + gboolean separate_windows = TRUE; + + empathy_conf_get_bool (empathy_conf_get (), + EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS, + &separate_windows); + + if (separate_windows) { + /* Always create a new window */ + return NULL; + } + + for (l = chat_windows; l; l = l->next) { + EmpathyChatWindow *chat_window; + GtkWidget *dialog; + GdkWindow *window; + gboolean visible; + + chat_window = l->data; + + dialog = empathy_chat_window_get_dialog (chat_window); + window = dialog->window; + + g_object_get (dialog, + "visible", &visible, + NULL); + + visible = visible && !(gdk_window_get_state (window) & GDK_WINDOW_STATE_ICONIFIED); + + if (visible) { + /* Found a visible window on this desktop */ + return chat_window; + } + } + + return NULL; +} + +static void +empathy_chat_window_finalize (GObject *object) +{ + EmpathyChatWindow *window; + EmpathyChatWindowPriv *priv; + + window = EMPATHY_CHAT_WINDOW (object); + priv = GET_PRIV (window); + + empathy_debug (DEBUG_DOMAIN, "Finalized: %p", object); + + if (priv->save_geometry_id != 0) { + g_source_remove (priv->save_geometry_id); + } + + if (priv->urgency_timeout_id != 0) { + g_source_remove (priv->urgency_timeout_id); + } + + chat_windows = g_list_remove (chat_windows, window); + gtk_widget_destroy (priv->dialog); + g_object_unref (priv->tooltips); + + g_signal_handlers_disconnect_by_func (priv->chatroom_manager, + chat_window_update_menu, + window); + g_object_unref (priv->chatroom_manager); + + G_OBJECT_CLASS (empathy_chat_window_parent_class)->finalize (object); +} + +static void +chat_window_accel_cb (GtkAccelGroup *accelgroup, + GObject *object, + guint key, + GdkModifierType mod, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + gint num = -1; + gint i; + + priv = GET_PRIV (window); + + for (i = 0; i < G_N_ELEMENTS (tab_accel_keys); i++) { + if (tab_accel_keys[i] == key) { + num = i; + break; + } + } + + if (num != -1) { + gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), num); + } +} + +static void +chat_window_close_clicked_cb (GtkWidget *button, + EmpathyChat *chat) +{ + EmpathyChatWindow *window; + + window = empathy_chat_get_window (chat); + empathy_chat_window_remove_chat (window, chat); +} + +static void +chat_window_close_button_style_set_cb (GtkWidget *button, + GtkStyle *previous_style, + gpointer user_data) +{ + gint h, w; + + gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (button), + GTK_ICON_SIZE_MENU, &w, &h); + + gtk_widget_set_size_request (button, w, h); +} + +static GtkWidget * +chat_window_create_label (EmpathyChatWindow *window, + EmpathyChat *chat) +{ + EmpathyChatWindowPriv *priv; + GtkWidget *hbox; + GtkWidget *name_label; + GtkWidget *status_image; + GtkWidget *close_button; + GtkWidget *close_image; + GtkWidget *event_box; + GtkWidget *event_box_hbox; + PangoAttrList *attr_list; + PangoAttribute *attr; + + priv = GET_PRIV (window); + + /* The spacing between the button and the label. */ + hbox = gtk_hbox_new (FALSE, 0); + + event_box = gtk_event_box_new (); + gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE); + + name_label = gtk_label_new (empathy_chat_get_name (chat)); + gtk_label_set_ellipsize (GTK_LABEL (name_label), PANGO_ELLIPSIZE_END); + + attr_list = pango_attr_list_new (); + attr = pango_attr_scale_new (1/1.2); + attr->start_index = 0; + attr->end_index = -1; + pango_attr_list_insert (attr_list, attr); + gtk_label_set_attributes (GTK_LABEL (name_label), attr_list); + pango_attr_list_unref (attr_list); + + gtk_misc_set_padding (GTK_MISC (name_label), 2, 0); + gtk_misc_set_alignment (GTK_MISC (name_label), 0.0, 0.5); + g_object_set_data (G_OBJECT (chat), "chat-window-tab-label", name_label); + + status_image = gtk_image_new (); + + /* Spacing between the icon and label. */ + event_box_hbox = gtk_hbox_new (FALSE, 0); + + gtk_box_pack_start (GTK_BOX (event_box_hbox), status_image, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (event_box_hbox), name_label, TRUE, TRUE, 0); + + g_object_set_data (G_OBJECT (chat), "chat-window-tab-image", status_image); + g_object_set_data (G_OBJECT (chat), "chat-window-tab-tooltip-widget", event_box); + + close_button = gtk_button_new (); + gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE); + + /* We don't want focus/keynav for the button to avoid clutter, and + * Ctrl-W works anyway. + */ + GTK_WIDGET_UNSET_FLAGS (close_button, GTK_CAN_FOCUS); + GTK_WIDGET_UNSET_FLAGS (close_button, GTK_CAN_DEFAULT); + + /* Set the name to make the special rc style match. */ + gtk_widget_set_name (close_button, "empathy-close-button"); + + close_image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU); + + gtk_container_add (GTK_CONTAINER (close_button), close_image); + + gtk_container_add (GTK_CONTAINER (event_box), event_box_hbox); + gtk_box_pack_start (GTK_BOX (hbox), event_box, TRUE, TRUE, 0); + gtk_box_pack_end (GTK_BOX (hbox), close_button, FALSE, FALSE, 0); + + /* React to theme changes and also used to setup the initial size + * correctly. + */ + g_signal_connect (close_button, + "style-set", + G_CALLBACK (chat_window_close_button_style_set_cb), + chat); + + g_signal_connect (close_button, + "clicked", + G_CALLBACK (chat_window_close_clicked_cb), + chat); + + /* Set up tooltip */ + chat_window_update_tooltip (window, chat); + + gtk_widget_show_all (hbox); + + return hbox; +} + +static void +chat_window_update_status (EmpathyChatWindow *window, + EmpathyChat *chat) +{ + EmpathyChatWindowPriv *priv; + GtkImage *image; + const gchar *icon_name = NULL; + + priv = GET_PRIV (window); + + if (g_list_find (priv->chats_new_msg, chat)) { + icon_name = EMPATHY_IMAGE_MESSAGE; + } + else if (g_list_find (priv->chats_composing, chat)) { + icon_name = EMPATHY_IMAGE_TYPING; + } + else { + icon_name = empathy_chat_get_status_icon_name (chat); + } + image = g_object_get_data (G_OBJECT (chat), "chat-window-tab-image"); + gtk_image_set_from_icon_name (image, icon_name, GTK_ICON_SIZE_MENU); + + chat_window_update_title (window, chat); + chat_window_update_tooltip (window, chat); +} + +static void +chat_window_update_title (EmpathyChatWindow *window, + EmpathyChat *chat) +{ + EmpathyChatWindowPriv *priv; + const gchar *str; + gchar *title; + gint n_chats; + + priv = GET_PRIV (window); + + n_chats = g_list_length (priv->chats); + if (n_chats == 1) { + if (priv->chats_new_msg) { + title = g_strdup_printf ( + "%s - %s", + empathy_chat_get_name (priv->current_chat), + _("New Message")); + } + else if (empathy_chat_is_group_chat (priv->current_chat)) { + title = g_strdup_printf ( + "%s - %s", + empathy_chat_get_name (priv->current_chat), + _("Chat Room")); + } else { + title = g_strdup_printf ( + "%s - %s", + empathy_chat_get_name (priv->current_chat), + _("Conversation")); + } + } else { + if (priv->chats_new_msg) { + GString *names; + GList *l; + gint n_messages = 0; + + names = g_string_new (NULL); + + for (l = priv->chats_new_msg; l; l = l->next) { + n_messages++; + g_string_append (names, + empathy_chat_get_name (l->data)); + if (l->next) { + g_string_append (names, ", "); + } + } + + str = ngettext ("New Message", "New Messages", n_messages); + title = g_strdup_printf ("%s - %s", names->str, str); + g_string_free (names, TRUE); + } else { + str = ngettext ("Conversation", "Conversations (%d)", n_chats); + title = g_strdup_printf (str, n_chats); + } + } + + gtk_window_set_title (GTK_WINDOW (priv->dialog), title); + g_free (title); + + if (priv->chats_new_msg) { + gtk_window_set_icon_name (GTK_WINDOW (priv->dialog), + EMPATHY_IMAGE_MESSAGE); + } else { + gtk_window_set_icon_name (GTK_WINDOW (priv->dialog), NULL); + } +} + +static void +chat_window_update_menu (EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + gboolean first_page; + gboolean last_page; + gboolean is_connected; + gint num_pages; + gint page_num; + + priv = GET_PRIV (window); + + /* Notebook pages */ + page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)); + num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook)); + first_page = (page_num == 0); + last_page = (page_num == (num_pages - 1)); + + gtk_widget_set_sensitive (priv->menu_tabs_next, !last_page); + gtk_widget_set_sensitive (priv->menu_tabs_prev, !first_page); + gtk_widget_set_sensitive (priv->menu_tabs_detach, num_pages > 1); + gtk_widget_set_sensitive (priv->menu_tabs_left, !first_page); + gtk_widget_set_sensitive (priv->menu_tabs_right, !last_page); + + is_connected = empathy_chat_is_connected (priv->current_chat); + + if (empathy_chat_is_group_chat (priv->current_chat)) { + EmpathyGroupChat *group_chat; + EmpathyChatroom *chatroom; + gboolean show_contacts; + + group_chat = EMPATHY_GROUP_CHAT (priv->current_chat); + + /* Show / Hide widgets */ + gtk_widget_show (priv->menu_room); + + gtk_widget_hide (priv->menu_conv_add_contact); + gtk_widget_hide (priv->menu_conv_info); + gtk_widget_hide (priv->menu_conv_separator); + + /* Can we add this room to our favourites and are we + * connected to the room? + */ + chatroom = empathy_chatroom_manager_find (priv->chatroom_manager, + priv->current_chat->account, + empathy_chat_get_id (priv->current_chat)); + + gtk_widget_set_sensitive (priv->menu_room_add, chatroom == NULL); + gtk_widget_set_sensitive (priv->menu_conv_insert_smiley, is_connected); + gtk_widget_set_sensitive (priv->menu_room_join_new, is_connected); + gtk_widget_set_sensitive (priv->menu_room_invite, is_connected); + + /* We need to block the signal here because all we are + * really trying to do is check or uncheck the menu + * item. If we don't do this we get funny behaviour + * with 2 or more group chat windows where showing + * contacts doesn't do anything. + */ + show_contacts = empathy_group_chat_get_show_contacts (group_chat); + + g_signal_handlers_block_by_func (priv->menu_room_show_contacts, + chat_window_show_contacts_toggled_cb, + window); + + g_object_set (priv->menu_room_show_contacts, + "active", show_contacts, + NULL); + + g_signal_handlers_unblock_by_func (priv->menu_room_show_contacts, + chat_window_show_contacts_toggled_cb, + window); + } else { + EmpathyPrivateChat *chat; + EmpathySubscription subscription; + EmpathyContact *contact; + + chat = EMPATHY_PRIVATE_CHAT (priv->current_chat); + + /* Show / Hide widgets */ + gtk_widget_hide (priv->menu_room); + + contact = empathy_private_chat_get_contact (chat); + subscription = empathy_contact_get_subscription (contact); + if (!(subscription & EMPATHY_SUBSCRIPTION_FROM)) { + gtk_widget_show (priv->menu_conv_add_contact); + } else { + gtk_widget_hide (priv->menu_conv_add_contact); + } + + gtk_widget_show (priv->menu_conv_separator); + gtk_widget_show (priv->menu_conv_info); + + /* Are we connected? */ + gtk_widget_set_sensitive (priv->menu_conv_insert_smiley, is_connected); + gtk_widget_set_sensitive (priv->menu_conv_add_contact, is_connected); + gtk_widget_set_sensitive (priv->menu_conv_info, is_connected); + } +} + +static void +chat_window_insert_smiley_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + EmpathyChat *chat; + GtkTextBuffer *buffer; + GtkTextIter iter; + const gchar *smiley; + + priv = GET_PRIV (window); + + chat = priv->current_chat; + + smiley = g_object_get_data (G_OBJECT (menuitem), "smiley_text"); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); + gtk_text_buffer_get_end_iter (buffer, &iter); + gtk_text_buffer_insert (buffer, &iter, + smiley, -1); +} + +static void +chat_window_clear_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + + priv = GET_PRIV (window); + + empathy_chat_clear (priv->current_chat); +} + +static void +chat_window_add_contact_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + //EmpathyContact *contact; + + priv = GET_PRIV (window); + + //contact = empathy_chat_get_contact (priv->current_chat); + + // FIXME: empathy_add_contact_dialog_show (NULL, contact); +} + +static void +chat_window_log_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + + priv = GET_PRIV (window); + + empathy_log_window_show (priv->current_chat->account, + empathy_chat_get_id (priv->current_chat), + empathy_chat_is_group_chat (priv->current_chat), + GTK_WINDOW (priv->dialog)); +} + +static void +chat_window_info_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + EmpathyContact *contact; + + priv = GET_PRIV (window); + + contact = empathy_private_chat_get_contact (EMPATHY_PRIVATE_CHAT (priv->current_chat)); + + empathy_contact_information_dialog_show (contact, + GTK_WINDOW (priv->dialog), + FALSE); +} + +static gboolean +chat_window_save_geometry_timeout_cb (EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + gint x, y, w, h; + + priv = GET_PRIV (window); + + gtk_window_get_size (GTK_WINDOW (priv->dialog), &w, &h); + gtk_window_get_position (GTK_WINDOW (priv->dialog), &x, &y); + + empathy_chat_save_geometry (priv->current_chat, x, y, w, h); + + priv->save_geometry_id = 0; + + return FALSE; +} + +static gboolean +chat_window_configure_event_cb (GtkWidget *widget, + GdkEventConfigure *event, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + + priv = GET_PRIV (window); + + /* Only save geometry information if there is ONE chat visible. */ + if (g_list_length (priv->chats) > 1) { + return FALSE; + } + + if (priv->save_geometry_id != 0) { + g_source_remove (priv->save_geometry_id); + } + + priv->save_geometry_id = + g_timeout_add (500, + (GSourceFunc) chat_window_save_geometry_timeout_cb, + window); + + return FALSE; +} + +static void +chat_window_conv_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + EmpathyLogManager *manager; + gboolean log_exists = FALSE; + + priv = GET_PRIV (window); + + manager = empathy_log_manager_new (); + log_exists = empathy_log_manager_exists (manager, + priv->current_chat->account, + empathy_chat_get_id (priv->current_chat), + empathy_chat_is_group_chat (priv->current_chat)); + g_object_unref (manager); + + gtk_widget_set_sensitive (priv->menu_conv_log, log_exists); +} + +static void +chat_window_show_contacts_toggled_cb (GtkWidget *menuitem, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + gboolean show; + + priv = GET_PRIV (window); + + g_return_if_fail (priv->current_chat != NULL); + + show = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (priv->menu_room_show_contacts)); + empathy_group_chat_set_show_contacts (EMPATHY_GROUP_CHAT (priv->current_chat), show); +} + +static void +chat_window_close_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + + priv = GET_PRIV (window); + + g_return_if_fail (priv->current_chat != NULL); + + empathy_chat_window_remove_chat (window, priv->current_chat); +} + +static void +chat_window_room_set_topic_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + + priv = GET_PRIV (window); + + if (empathy_chat_is_group_chat (priv->current_chat)) { + EmpathyGroupChat *group_chat; + + group_chat = EMPATHY_GROUP_CHAT (priv->current_chat); + empathy_group_chat_set_topic (group_chat); + } +} + +static void +chat_window_room_join_new_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + + priv = GET_PRIV (window); + + empathy_new_chatroom_dialog_show (GTK_WINDOW (priv->dialog)); +} + +static void +chat_window_room_invite_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window) +{ +/* FIXME: + EmpathyChatWindowPriv *priv; + EmpathyContact *own_contact; + EmpathyChatroomId id = 0; + + priv = GET_PRIV (window); + own_contact = empathy_chat_get_own_contact (priv->current_chat); + + if (empathy_chat_is_group_chat (priv->current_chat)) { + EmpathyGroupChat *group_chat; + + group_chat = EMPATHY_GROUP_CHAT (priv->current_chat); + id = empathy_group_chat_get_chatroom_id (group_chat); + } + + empathy_chat_invite_dialog_show (own_contact, id); +*/ +} + +static void +chat_window_room_add_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + EmpathyChatroomManager *manager; + EmpathyChatroom *chatroom; + + priv = GET_PRIV (window); + + g_return_if_fail (priv->current_chat != NULL); + + if (!empathy_chat_is_group_chat (priv->current_chat)) { + return; + } + + chatroom = empathy_chatroom_new_full (priv->current_chat->account, + empathy_chat_get_id (priv->current_chat), + empathy_chat_get_name (priv->current_chat), + FALSE); + + manager = empathy_chatroom_manager_new (); + empathy_chatroom_manager_add (manager, chatroom); + chat_window_update_menu (window); + + g_object_unref (chatroom); + g_object_unref (manager); +} + +static void +chat_window_edit_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + GtkClipboard *clipboard; + GtkTextBuffer *buffer; + gboolean text_available; + + priv = GET_PRIV (window); + + g_return_if_fail (priv->current_chat != NULL); + + if (!empathy_chat_is_connected (priv->current_chat)) { + gtk_widget_set_sensitive (priv->menu_edit_copy, FALSE); + gtk_widget_set_sensitive (priv->menu_edit_cut, FALSE); + gtk_widget_set_sensitive (priv->menu_edit_paste, FALSE); + return; + } + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->current_chat->input_text_view)); + if (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL)) { + gtk_widget_set_sensitive (priv->menu_edit_copy, TRUE); + gtk_widget_set_sensitive (priv->menu_edit_cut, TRUE); + } else { + gboolean selection; + + selection = empathy_chat_view_get_selection_bounds (priv->current_chat->view, + NULL, NULL); + + gtk_widget_set_sensitive (priv->menu_edit_cut, FALSE); + gtk_widget_set_sensitive (priv->menu_edit_copy, selection); + } + + clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); + text_available = gtk_clipboard_wait_is_text_available (clipboard); + gtk_widget_set_sensitive (priv->menu_edit_paste, text_available); +} + +static void +chat_window_cut_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHAT_WINDOW (window)); + + priv = GET_PRIV (window); + + empathy_chat_cut (priv->current_chat); +} + +static void +chat_window_copy_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHAT_WINDOW (window)); + + priv = GET_PRIV (window); + + empathy_chat_copy (priv->current_chat); +} + +static void +chat_window_paste_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHAT_WINDOW (window)); + + priv = GET_PRIV (window); + + empathy_chat_paste (priv->current_chat); +} + +static void +chat_window_tabs_left_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + EmpathyChat *chat; + gint index; + + priv = GET_PRIV (window); + + chat = priv->current_chat; + index = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)); + if (index <= 0) { + return; + } + + gtk_notebook_reorder_child (GTK_NOTEBOOK (priv->notebook), + empathy_chat_get_widget (chat), + index - 1); + + chat_window_update_menu (window); + chat_window_update_status (window, chat); +} + +static void +chat_window_tabs_right_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + EmpathyChat *chat; + gint index; + + priv = GET_PRIV (window); + + chat = priv->current_chat; + index = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)); + + gtk_notebook_reorder_child (GTK_NOTEBOOK (priv->notebook), + empathy_chat_get_widget (chat), + index + 1); + + chat_window_update_menu (window); + chat_window_update_status (window, chat); +} + +static void +chat_window_detach_activate_cb (GtkWidget *menuitem, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + EmpathyChatWindow *new_window; + EmpathyChat *chat; + + priv = GET_PRIV (window); + + chat = priv->current_chat; + new_window = empathy_chat_window_new (); + + empathy_chat_window_move_chat (window, new_window, chat); + + priv = GET_PRIV (new_window); + gtk_widget_show (priv->dialog); +} + +static gboolean +chat_window_delete_event_cb (GtkWidget *dialog, + GdkEvent *event, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + GList *list; + GList *l; + + priv = GET_PRIV (window); + + empathy_debug (DEBUG_DOMAIN, "Delete event received"); + + list = g_list_copy (priv->chats); + + for (l = list; l; l = l->next) { + empathy_chat_window_remove_chat (window, l->data); + } + + g_list_free (list); + + return TRUE; +} + +static void +chat_window_status_changed_cb (EmpathyChat *chat, + EmpathyChatWindow *window) +{ + chat_window_update_menu (window); + chat_window_update_status (window, chat); +} + +static void +chat_window_update_tooltip (EmpathyChatWindow *window, + EmpathyChat *chat) +{ + EmpathyChatWindowPriv *priv; + GtkWidget *widget; + gchar *current_tooltip; + gchar *str; + + priv = GET_PRIV (window); + + current_tooltip = empathy_chat_get_tooltip (chat); + + if (g_list_find (priv->chats_composing, chat)) { + str = g_strconcat (current_tooltip, "\n", _("Typing a message."), NULL); + g_free (current_tooltip); + } else { + str = current_tooltip; + } + + widget = g_object_get_data (G_OBJECT (chat), "chat-window-tab-tooltip-widget"); + gtk_tooltips_set_tip (priv->tooltips, + widget, + str, + NULL); + + g_free (str); +} + +static void +chat_window_name_changed_cb (EmpathyChat *chat, + const gchar *name, + EmpathyChatWindow *window) +{ + GtkLabel *label; + + label = g_object_get_data (G_OBJECT (chat), "chat-window-tab-label"); + + gtk_label_set_text (label, name); +} + +static void +chat_window_composing_cb (EmpathyChat *chat, + gboolean is_composing, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + + priv = GET_PRIV (window); + + if (is_composing && !g_list_find (priv->chats_composing, chat)) { + priv->chats_composing = g_list_prepend (priv->chats_composing, chat); + } else { + priv->chats_composing = g_list_remove (priv->chats_composing, chat); + } + + chat_window_update_status (window, chat); +} + +static void +chat_window_new_message_cb (EmpathyChat *chat, + EmpathyMessage *message, + gboolean is_backlog, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + gboolean has_focus; + gboolean needs_urgency; + + priv = GET_PRIV (window); + + has_focus = empathy_chat_window_has_focus (window); + + if (has_focus && priv->current_chat == chat) { + empathy_debug (DEBUG_DOMAIN, "New message, we have focus"); + return; + } + + empathy_debug (DEBUG_DOMAIN, "New message, no focus"); + + needs_urgency = FALSE; + if (empathy_chat_is_group_chat (chat)) { + if (!is_backlog && + empathy_chat_should_highlight_nick (message)) { + empathy_debug (DEBUG_DOMAIN, "Highlight this nick"); + needs_urgency = TRUE; + } + } else { + needs_urgency = TRUE; + } + + if (needs_urgency && !has_focus) { + chat_window_set_urgency_hint (window, TRUE); + } + + if (!is_backlog && + !g_list_find (priv->chats_new_msg, chat)) { + priv->chats_new_msg = g_list_prepend (priv->chats_new_msg, chat); + chat_window_update_status (window, chat); + } +} + +static GtkNotebook * +chat_window_detach_hook (GtkNotebook *source, + GtkWidget *page, + gint x, + gint y, + gpointer user_data) +{ + EmpathyChatWindowPriv *priv; + EmpathyChatWindow *window, *new_window; + EmpathyChat *chat; + + chat = g_object_get_data (G_OBJECT (page), "chat"); + window = empathy_chat_get_window (chat); + + new_window = empathy_chat_window_new (); + priv = GET_PRIV (new_window); + + empathy_debug (DEBUG_DOMAIN, "Detach hook called"); + + empathy_chat_window_move_chat (window, new_window, chat); + + gtk_window_move (GTK_WINDOW (priv->dialog), x, y); + gtk_widget_show (priv->dialog); + + return NULL; +} + +static void +chat_window_page_switched_cb (GtkNotebook *notebook, + GtkNotebookPage *page, + gint page_num, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + EmpathyChat *chat; + GtkWidget *child; + + empathy_debug (DEBUG_DOMAIN, "Page switched"); + + priv = GET_PRIV (window); + + child = gtk_notebook_get_nth_page (notebook, page_num); + chat = g_object_get_data (G_OBJECT (child), "chat"); + + if (priv->page_added) { + priv->page_added = FALSE; + empathy_chat_scroll_down (chat); + } + else if (priv->current_chat == chat) { + return; + } + + priv->current_chat = chat; + priv->chats_new_msg = g_list_remove (priv->chats_new_msg, chat); + + chat_window_update_menu (window); + chat_window_update_status (window, chat); +} + +static void +chat_window_page_reordered_cb (GtkNotebook *notebook, + GtkWidget *widget, + guint page_num, + EmpathyChatWindow *window) +{ + empathy_debug (DEBUG_DOMAIN, "Page reordered"); + + chat_window_update_menu (window); +} + +static void +chat_window_page_added_cb (GtkNotebook *notebook, + GtkWidget *child, + guint page_num, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + EmpathyChat *chat; + + priv = GET_PRIV (window); + + /* If we just received DND to the same window, we don't want + * to do anything here like removing the tab and then readding + * it, so we return here and in "page-added". + */ + if (priv->dnd_same_window) { + empathy_debug (DEBUG_DOMAIN, "Page added (back to the same window)"); + priv->dnd_same_window = FALSE; + return; + } + + empathy_debug (DEBUG_DOMAIN, "Page added"); + + /* Get chat object */ + chat = g_object_get_data (G_OBJECT (child), "chat"); + + /* Set the chat window */ + empathy_chat_set_window (chat, window); + + /* Connect chat signals for this window */ + g_signal_connect (chat, "status-changed", + G_CALLBACK (chat_window_status_changed_cb), + window); + g_signal_connect (chat, "name-changed", + G_CALLBACK (chat_window_name_changed_cb), + window); + g_signal_connect (chat, "composing", + G_CALLBACK (chat_window_composing_cb), + window); + g_signal_connect (chat, "new-message", + G_CALLBACK (chat_window_new_message_cb), + window); + + /* Set flag so we know to perform some special operations on + * switch page due to the new page being added. + */ + priv->page_added = TRUE; + + /* Get list of chats up to date */ + priv->chats = g_list_append (priv->chats, chat); +} + +static void +chat_window_page_removed_cb (GtkNotebook *notebook, + GtkWidget *child, + guint page_num, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + EmpathyChat *chat; + + priv = GET_PRIV (window); + + /* If we just received DND to the same window, we don't want + * to do anything here like removing the tab and then readding + * it, so we return here and in "page-added". + */ + if (priv->dnd_same_window) { + empathy_debug (DEBUG_DOMAIN, "Page removed (and will be readded to same window)"); + return; + } + + empathy_debug (DEBUG_DOMAIN, "Page removed"); + + /* Get chat object */ + chat = g_object_get_data (G_OBJECT (child), "chat"); + + /* Unset the window associated with a chat */ + empathy_chat_set_window (chat, NULL); + + /* Disconnect all signal handlers for this chat and this window */ + g_signal_handlers_disconnect_by_func (chat, + G_CALLBACK (chat_window_status_changed_cb), + window); + g_signal_handlers_disconnect_by_func (chat, + G_CALLBACK (chat_window_name_changed_cb), + window); + g_signal_handlers_disconnect_by_func (chat, + G_CALLBACK (chat_window_composing_cb), + window); + g_signal_handlers_disconnect_by_func (chat, + G_CALLBACK (chat_window_new_message_cb), + window); + + /* Keep list of chats up to date */ + priv->chats = g_list_remove (priv->chats, chat); + priv->chats_new_msg = g_list_remove (priv->chats_new_msg, chat); + priv->chats_composing = g_list_remove (priv->chats_composing, chat); + + if (priv->chats == NULL) { + g_object_unref (window); + } else { + chat_window_update_menu (window); + chat_window_update_title (window, NULL); + } +} + +static gboolean +chat_window_focus_in_event_cb (GtkWidget *widget, + GdkEvent *event, + EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + + empathy_debug (DEBUG_DOMAIN, "Focus in event, updating title"); + + priv = GET_PRIV (window); + + priv->chats_new_msg = g_list_remove (priv->chats_new_msg, priv->current_chat); + + chat_window_set_urgency_hint (window, FALSE); + + /* Update the title, since we now mark all unread messages as read. */ + chat_window_update_status (window, priv->current_chat); + + return FALSE; +} + +static void +chat_window_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + int x, + int y, + GtkSelectionData *selection, + guint info, + guint time, + EmpathyChatWindow *window) +{ + /* FIXME: DnD of contact do not seems to work... */ + if (info == DND_DRAG_TYPE_CONTACT_ID) { + EmpathyContactManager *manager; + EmpathyContact *contact; + EmpathyChat *chat; + EmpathyChatWindow *old_window; + McAccount *account; + const gchar *id = NULL; + + if (selection) { + id = (const gchar*) selection->data; + } + + empathy_debug (DEBUG_DOMAIN, "DND contact from roster with id:'%s'", id); + + manager = empathy_contact_manager_new (); + contact = empathy_contact_list_find (EMPATHY_CONTACT_LIST (manager), id); + g_object_unref (manager); + + if (!contact) { + empathy_debug (DEBUG_DOMAIN, "DND contact from roster not found"); + return; + } + + account = empathy_contact_get_account (contact); + chat = empathy_chat_window_find_chat (account, id); + old_window = empathy_chat_get_window (chat); + + if (old_window) { + if (old_window == window) { + gtk_drag_finish (context, TRUE, FALSE, time); + return; + } + + empathy_chat_window_move_chat (old_window, window, chat); + } else { + empathy_chat_window_add_chat (window, chat); + } + + /* Added to take care of any outstanding chat events */ + empathy_chat_present (chat); + + /* We should return TRUE to remove the data when doing + * GDK_ACTION_MOVE, but we don't here otherwise it has + * weird consequences, and we handle that internally + * anyway with add_chat() and remove_chat(). + */ + gtk_drag_finish (context, TRUE, FALSE, time); + } + else if (info == DND_DRAG_TYPE_TAB) { + EmpathyChat *chat = NULL; + EmpathyChatWindow *old_window; + GtkWidget **child = NULL; + + empathy_debug (DEBUG_DOMAIN, "DND tab"); + + if (selection) { + child = (void*) selection->data; + } + + if (child) { + chat = g_object_get_data (G_OBJECT (*child), "chat"); + } + + old_window = empathy_chat_get_window (chat); + if (old_window) { + EmpathyChatWindowPriv *priv; + + priv = GET_PRIV (window); + + if (old_window == window) { + empathy_debug (DEBUG_DOMAIN, "DND tab (within same window)"); + priv->dnd_same_window = TRUE; + gtk_drag_finish (context, TRUE, FALSE, time); + return; + } + + priv->dnd_same_window = FALSE; + } + + /* We should return TRUE to remove the data when doing + * GDK_ACTION_MOVE, but we don't here otherwise it has + * weird consequences, and we handle that internally + * anyway with add_chat() and remove_chat(). + */ + gtk_drag_finish (context, TRUE, FALSE, time); + } else { + empathy_debug (DEBUG_DOMAIN, "DND from unknown source"); + gtk_drag_finish (context, FALSE, FALSE, time); + } +} + +static gboolean +chat_window_urgency_timeout_func (EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + + priv = GET_PRIV (window); + + empathy_debug (DEBUG_DOMAIN, "Turning off urgency hint"); + gtk_window_set_urgency_hint (GTK_WINDOW (priv->dialog), FALSE); + + priv->urgency_timeout_id = 0; + + return FALSE; +} + +static void +chat_window_set_urgency_hint (EmpathyChatWindow *window, + gboolean urgent) +{ + EmpathyChatWindowPriv *priv; + + priv = GET_PRIV (window); + + if (!urgent) { + /* Remove any existing hint and timeout. */ + if (priv->urgency_timeout_id) { + empathy_debug (DEBUG_DOMAIN, "Turning off urgency hint"); + gtk_window_set_urgency_hint (GTK_WINDOW (priv->dialog), FALSE); + g_source_remove (priv->urgency_timeout_id); + priv->urgency_timeout_id = 0; + } + return; + } + + /* Add a new hint and renew any exising timeout or add a new one. */ + if (priv->urgency_timeout_id) { + g_source_remove (priv->urgency_timeout_id); + } else { + empathy_debug (DEBUG_DOMAIN, "Turning on urgency hint"); + gtk_window_set_urgency_hint (GTK_WINDOW (priv->dialog), TRUE); + } + + priv->urgency_timeout_id = g_timeout_add ( + URGENCY_TIMEOUT, + (GSourceFunc) chat_window_urgency_timeout_func, + window); +} + +EmpathyChatWindow * +empathy_chat_window_new (void) +{ + return EMPATHY_CHAT_WINDOW (g_object_new (EMPATHY_TYPE_CHAT_WINDOW, NULL)); +} + +GtkWidget * +empathy_chat_window_get_dialog (EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + + g_return_val_if_fail (window != NULL, NULL); + + priv = GET_PRIV (window); + + return priv->dialog; +} + +void +empathy_chat_window_add_chat (EmpathyChatWindow *window, + EmpathyChat *chat) +{ + EmpathyChatWindowPriv *priv; + GtkWidget *label; + GtkWidget *child; + + priv = GET_PRIV (window); + + /* Reference the chat object */ + g_object_ref (chat); + + /* Set the chat window */ + empathy_chat_set_window (chat, window); + + if (g_list_length (priv->chats) == 0) { + gint x, y, w, h; + + empathy_chat_load_geometry (chat, &x, &y, &w, &h); + + if (x >= 0 && y >= 0) { + /* Let the window manager position it if we don't have + * good x, y coordinates. + */ + gtk_window_move (GTK_WINDOW (priv->dialog), x, y); + } + + if (w > 0 && h > 0) { + /* Use the defaults from the glade file if we don't have + * good w, h geometry. + */ + gtk_window_resize (GTK_WINDOW (priv->dialog), w, h); + } + } + + child = empathy_chat_get_widget (chat); + label = chat_window_create_label (window, chat); + + gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), child, label); + gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (priv->notebook), child, TRUE); + gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (priv->notebook), child, TRUE); + gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (priv->notebook), child, + TRUE, TRUE, GTK_PACK_START); + + empathy_debug (DEBUG_DOMAIN, + "Chat added (%d references)", + G_OBJECT (chat)->ref_count); +} + +void +empathy_chat_window_remove_chat (EmpathyChatWindow *window, + EmpathyChat *chat) +{ + EmpathyChatWindowPriv *priv; + gint position; + + priv = GET_PRIV (window); + + position = gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook), + empathy_chat_get_widget (chat)); + gtk_notebook_remove_page (GTK_NOTEBOOK (priv->notebook), position); + + empathy_debug (DEBUG_DOMAIN, + "Chat removed (%d references)", + G_OBJECT (chat)->ref_count - 1); + + g_object_unref (chat); +} + +void +empathy_chat_window_move_chat (EmpathyChatWindow *old_window, + EmpathyChatWindow *new_window, + EmpathyChat *chat) +{ + GtkWidget *widget; + + g_return_if_fail (EMPATHY_IS_CHAT_WINDOW (old_window)); + g_return_if_fail (EMPATHY_IS_CHAT_WINDOW (new_window)); + g_return_if_fail (EMPATHY_IS_CHAT (chat)); + + widget = empathy_chat_get_widget (chat); + + empathy_debug (DEBUG_DOMAIN, + "Chat moving with widget:%p (%d references)", + widget, + G_OBJECT (widget)->ref_count); + + /* We reference here to make sure we don't loose the widget + * and the EmpathyChat object during the move. + */ + g_object_ref (chat); + g_object_ref (widget); + + empathy_chat_window_remove_chat (old_window, chat); + empathy_chat_window_add_chat (new_window, chat); + + g_object_unref (widget); + g_object_unref (chat); +} + +void +empathy_chat_window_switch_to_chat (EmpathyChatWindow *window, + EmpathyChat *chat) +{ + EmpathyChatWindowPriv *priv; + gint page_num; + + priv = GET_PRIV (window); + + page_num = gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook), + empathy_chat_get_widget (chat)); + gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), + page_num); +} + +gboolean +empathy_chat_window_has_focus (EmpathyChatWindow *window) +{ + EmpathyChatWindowPriv *priv; + gboolean has_focus; + + g_return_val_if_fail (EMPATHY_IS_CHAT_WINDOW (window), FALSE); + + priv = GET_PRIV (window); + + g_object_get (priv->dialog, "has-toplevel-focus", &has_focus, NULL); + + return has_focus; +} + +EmpathyChat * +empathy_chat_window_find_chat (McAccount *account, + const gchar *id) +{ + GList *l; + + for (l = chat_windows; l; l = l->next) { + EmpathyChatWindowPriv *priv; + EmpathyChatWindow *window; + GList *ll; + + window = l->data; + priv = GET_PRIV (window); + + for (ll = priv->chats; ll; ll = ll->next) { + EmpathyChat *chat; + + chat = ll->data; + + if (empathy_account_equal (account, chat->account) && + strcmp (id, empathy_chat_get_id (chat)) == 0) { + return chat; + } + } + } + + return NULL; +} + diff --git a/libempathy-gtk/empathy-chat-window.h b/libempathy-gtk/empathy-chat-window.h new file mode 100644 index 00000000..c79f7519 --- /dev/null +++ b/libempathy-gtk/empathy-chat-window.h @@ -0,0 +1,80 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2003-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Richard Hult + * Martyn Russell + * Geert-Jan Van den Bogaerde + * Xavier Claessens + */ + +#ifndef __EMPATHY_CHAT_WINDOW_H__ +#define __EMPATHY_CHAT_WINDOW_H__ + +#include + +#include + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_CHAT_WINDOW (empathy_chat_window_get_type ()) +#define EMPATHY_CHAT_WINDOW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_CHAT_WINDOW, EmpathyChatWindow)) +#define EMPATHY_CHAT_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_CHAT_WINDOW, EmpathyChatWindowClass)) +#define EMPATHY_IS_CHAT_WINDOW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_CHAT_WINDOW)) +#define EMPATHY_IS_CHAT_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_CHAT_WINDOW)) +#define EMPATHY_CHAT_WINDOW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_CHAT_WINDOW, EmpathyChatWindowClass)) + +typedef struct _EmpathyChatWindow EmpathyChatWindow; +typedef struct _EmpathyChatWindowClass EmpathyChatWindowClass; +typedef struct _EmpathyChatWindowPriv EmpathyChatWindowPriv; + +#include "empathy-chat.h" + +struct _EmpathyChatWindow { + GObject parent; +}; + +struct _EmpathyChatWindowClass { + GObjectClass parent_class; +}; + +GType empathy_chat_window_get_type (void); +EmpathyChatWindow *empathy_chat_window_get_default (void); + +EmpathyChatWindow *empathy_chat_window_new (void); + +GtkWidget * empathy_chat_window_get_dialog (EmpathyChatWindow *window); + +void empathy_chat_window_add_chat (EmpathyChatWindow *window, + EmpathyChat *chat); +void empathy_chat_window_remove_chat (EmpathyChatWindow *window, + EmpathyChat *chat); +void empathy_chat_window_move_chat (EmpathyChatWindow *old_window, + EmpathyChatWindow *new_window, + EmpathyChat *chat); +void empathy_chat_window_switch_to_chat (EmpathyChatWindow *window, + EmpathyChat *chat); +gboolean empathy_chat_window_has_focus (EmpathyChatWindow *window); +EmpathyChat * empathy_chat_window_find_chat (McAccount *account, + const gchar *id); + +G_END_DECLS + +#endif /* __EMPATHY_CHAT_WINDOW_H__ */ diff --git a/libempathy-gtk/empathy-chat.c b/libempathy-gtk/empathy-chat.c new file mode 100644 index 00000000..0000e5d5 --- /dev/null +++ b/libempathy-gtk/empathy-chat.c @@ -0,0 +1,1561 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2002-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Richard Hult + * Martyn Russell + * Geert-Jan Van den Bogaerde + * Xavier Claessens + */ + +#include "config.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "empathy-chat.h" +#include "empathy-chat-window.h" +#include "empathy-geometry.h" +#include "empathy-preferences.h" +#include "empathy-spell.h" +#include "empathy-spell-dialog.h" +#include "empathy-ui-utils.h" + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CHAT, EmpathyChatPriv)) + +#define DEBUG_DOMAIN "Chat" + +#define CHAT_DIR_CREATE_MODE (S_IRUSR | S_IWUSR | S_IXUSR) +#define CHAT_FILE_CREATE_MODE (S_IRUSR | S_IWUSR) + +#define IS_ENTER(v) (v == GDK_Return || v == GDK_ISO_Enter || v == GDK_KP_Enter) + +#define MAX_INPUT_HEIGHT 150 + +#define COMPOSING_STOP_TIMEOUT 5 + +struct _EmpathyChatPriv { + EmpathyContactManager *manager; + EmpathyLogManager *log_manager; + EmpathyTpChat *tp_chat; + EmpathyChatWindow *window; + GtkTooltips *tooltips; + guint composing_stop_timeout_id; + gboolean sensitive; + gchar *id; + GSList *sent_messages; + gint sent_messages_index; + GList *compositors; + guint scroll_idle_id; + gboolean first_tp_chat; + EmpathyTime time_joined; + /* Used to automatically shrink a window that has temporarily + * grown due to long input. + */ + gint padding_height; + gint default_window_height; + gint last_input_height; + gboolean vscroll_visible; +}; + +typedef struct { + EmpathyChat *chat; + gchar *word; + + GtkTextIter start; + GtkTextIter end; +} EmpathyChatSpell; + +static void empathy_chat_class_init (EmpathyChatClass *klass); +static void empathy_chat_init (EmpathyChat *chat); +static void chat_finalize (GObject *object); +static void chat_destroy_cb (EmpathyTpChat *tp_chat, + EmpathyChat *chat); +static void chat_send (EmpathyChat *chat, + const gchar *msg); +static void chat_input_text_view_send (EmpathyChat *chat); +static void chat_message_received_cb (EmpathyTpChat *tp_chat, + EmpathyMessage *message, + EmpathyChat *chat); +void chat_sent_message_add (EmpathyChat *chat, + const gchar *str); +const gchar * chat_sent_message_get_next (EmpathyChat *chat); +const gchar * chat_sent_message_get_last (EmpathyChat *chat); +static gboolean chat_input_key_press_event_cb (GtkWidget *widget, + GdkEventKey *event, + EmpathyChat *chat); +static void chat_input_text_buffer_changed_cb (GtkTextBuffer *buffer, + EmpathyChat *chat); +static gboolean chat_text_view_focus_in_event_cb (GtkWidget *widget, + GdkEvent *event, + EmpathyChat *chat); +static void chat_text_view_scroll_hide_cb (GtkWidget *widget, + EmpathyChat *chat); +static void chat_text_view_size_allocate_cb (GtkWidget *widget, + GtkAllocation *allocation, + EmpathyChat *chat); +static void chat_text_view_realize_cb (GtkWidget *widget, + EmpathyChat *chat); +static void chat_text_populate_popup_cb (GtkTextView *view, + GtkMenu *menu, + EmpathyChat *chat); +static void chat_text_check_word_spelling_cb (GtkMenuItem *menuitem, + EmpathyChatSpell *chat_spell); +static EmpathyChatSpell *chat_spell_new (EmpathyChat *chat, + const gchar *word, + GtkTextIter start, + GtkTextIter end); +static void chat_spell_free (EmpathyChatSpell *chat_spell); +static void chat_composing_start (EmpathyChat *chat); +static void chat_composing_stop (EmpathyChat *chat); +static void chat_composing_remove_timeout (EmpathyChat *chat); +static gboolean chat_composing_stop_timeout_cb (EmpathyChat *chat); +static void chat_state_changed_cb (EmpathyTpChat *tp_chat, + EmpathyContact *contact, + TelepathyChannelChatState state, + EmpathyChat *chat); +static void chat_add_logs (EmpathyChat *chat); +static gboolean chat_scroll_down_idle_func (EmpathyChat *chat); + +enum { + COMPOSING, + NEW_MESSAGE, + NAME_CHANGED, + STATUS_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE (EmpathyChat, empathy_chat, G_TYPE_OBJECT); + +static void +empathy_chat_class_init (EmpathyChatClass *klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = chat_finalize; + + signals[COMPOSING] = + g_signal_new ("composing", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, + 1, G_TYPE_BOOLEAN); + + signals[NEW_MESSAGE] = + g_signal_new ("new-message", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + empathy_marshal_VOID__OBJECT_BOOLEAN, + G_TYPE_NONE, + 2, EMPATHY_TYPE_MESSAGE, G_TYPE_BOOLEAN); + + signals[NAME_CHANGED] = + g_signal_new ("name-changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, G_TYPE_POINTER); + + signals[STATUS_CHANGED] = + g_signal_new ("status-changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + g_type_class_add_private (object_class, sizeof (EmpathyChatPriv)); +} + +static void +empathy_chat_init (EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + GtkTextBuffer *buffer; + + chat->view = empathy_chat_view_new (); + chat->input_text_view = gtk_text_view_new (); + + chat->is_first_char = TRUE; + + g_object_set (chat->input_text_view, + "pixels-above-lines", 2, + "pixels-below-lines", 2, + "pixels-inside-wrap", 1, + "right-margin", 2, + "left-margin", 2, + "wrap-mode", GTK_WRAP_WORD_CHAR, + NULL); + + priv = GET_PRIV (chat); + + priv->manager = empathy_contact_manager_new (); + priv->log_manager = empathy_log_manager_new (); + priv->tooltips = g_object_ref_sink (gtk_tooltips_new ()); + priv->default_window_height = -1; + priv->vscroll_visible = FALSE; + priv->sensitive = TRUE; + priv->sent_messages = NULL; + priv->sent_messages_index = -1; + priv->first_tp_chat = TRUE; + + g_signal_connect (chat->input_text_view, + "key_press_event", + G_CALLBACK (chat_input_key_press_event_cb), + chat); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); + g_signal_connect (buffer, + "changed", + G_CALLBACK (chat_input_text_buffer_changed_cb), + chat); + g_signal_connect (chat->view, + "focus_in_event", + G_CALLBACK (chat_text_view_focus_in_event_cb), + chat); + + g_signal_connect (chat->input_text_view, + "size_allocate", + G_CALLBACK (chat_text_view_size_allocate_cb), + chat); + + g_signal_connect (chat->input_text_view, + "realize", + G_CALLBACK (chat_text_view_realize_cb), + chat); + + g_signal_connect (GTK_TEXT_VIEW (chat->input_text_view), + "populate_popup", + G_CALLBACK (chat_text_populate_popup_cb), + chat); + + /* create misspelt words identification tag */ + gtk_text_buffer_create_tag (buffer, + "misspelled", + "underline", PANGO_UNDERLINE_ERROR, + NULL); +} + +static void +chat_finalize (GObject *object) +{ + EmpathyChat *chat; + EmpathyChatPriv *priv; + + chat = EMPATHY_CHAT (object); + priv = GET_PRIV (chat); + + empathy_debug (DEBUG_DOMAIN, "Finalized: %p", object); + + g_slist_foreach (priv->sent_messages, (GFunc) g_free, NULL); + g_slist_free (priv->sent_messages); + + g_list_foreach (priv->compositors, (GFunc) g_object_unref, NULL); + g_list_free (priv->compositors); + + chat_composing_remove_timeout (chat); + g_object_unref (chat->account); + g_object_unref (priv->manager); + g_object_unref (priv->log_manager); + g_object_unref (priv->tooltips); + + if (priv->tp_chat) { + g_object_unref (priv->tp_chat); + } + + if (priv->scroll_idle_id) { + g_source_remove (priv->scroll_idle_id); + } + + g_free (priv->id); + + G_OBJECT_CLASS (empathy_chat_parent_class)->finalize (object); +} + +static void +chat_destroy_cb (EmpathyTpChat *tp_chat, + EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + + priv = GET_PRIV (chat); + + if (priv->tp_chat) { + g_object_unref (priv->tp_chat); + priv->tp_chat = NULL; + } + priv->sensitive = FALSE; + + empathy_chat_view_append_event (chat->view, _("Disconnected")); + gtk_widget_set_sensitive (chat->input_text_view, FALSE); + + if (EMPATHY_CHAT_GET_CLASS (chat)->set_tp_chat) { + EMPATHY_CHAT_GET_CLASS (chat)->set_tp_chat (chat, NULL); + } +} + +static void +chat_send (EmpathyChat *chat, + const gchar *msg) +{ + EmpathyChatPriv *priv; + EmpathyMessage *message; + + priv = GET_PRIV (chat); + + if (G_STR_EMPTY (msg)) { + return; + } + + chat_sent_message_add (chat, msg); + + if (g_str_has_prefix (msg, "/clear")) { + empathy_chat_view_clear (chat->view); + return; + } + + /* FIXME: add here something to let group/privrate chat handle + * some special messages */ + + message = empathy_message_new (msg); + + empathy_tp_chat_send (priv->tp_chat, message); + + g_object_unref (message); +} + +static void +chat_input_text_view_send (EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + GtkTextBuffer *buffer; + GtkTextIter start, end; + gchar *msg; + + priv = GET_PRIV (chat); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); + + gtk_text_buffer_get_bounds (buffer, &start, &end); + msg = gtk_text_buffer_get_text (buffer, &start, &end, FALSE); + + /* clear the input field */ + gtk_text_buffer_set_text (buffer, "", -1); + + chat_send (chat, msg); + + g_free (msg); + + chat->is_first_char = TRUE; +} + +static void +chat_message_received_cb (EmpathyTpChat *tp_chat, + EmpathyMessage *message, + EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + EmpathyContact *sender; + EmpathyTime timestamp; + + priv = GET_PRIV (chat); + + sender = empathy_message_get_sender (message); + empathy_debug (DEBUG_DOMAIN, "Appending message ('%s')", + empathy_contact_get_name (sender)); + + /* Log the message only if it's not backlog */ + timestamp = empathy_message_get_timestamp (message); + if (timestamp >= priv->time_joined) { + empathy_log_manager_add_message (priv->log_manager, + empathy_chat_get_id (chat), + empathy_chat_is_group_chat (chat), + message); + } + + empathy_chat_view_append_message (chat->view, message); + + if (empathy_chat_should_play_sound (chat)) { + // FIXME: empathy_sound_play (EMPATHY_SOUND_CHAT); + } + + g_signal_emit (chat, signals[NEW_MESSAGE], 0, message, FALSE); +} + +void +chat_sent_message_add (EmpathyChat *chat, + const gchar *str) +{ + EmpathyChatPriv *priv; + GSList *list; + GSList *item; + + priv = GET_PRIV (chat); + + /* Save the sent message in our repeat buffer */ + list = priv->sent_messages; + + /* Remove any other occurances of this msg */ + while ((item = g_slist_find_custom (list, str, (GCompareFunc) strcmp)) != NULL) { + list = g_slist_remove_link (list, item); + g_free (item->data); + g_slist_free1 (item); + } + + /* Trim the list to the last 10 items */ + while (g_slist_length (list) > 10) { + item = g_slist_last (list); + if (item) { + list = g_slist_remove_link (list, item); + g_free (item->data); + g_slist_free1 (item); + } + } + + /* Add new message */ + list = g_slist_prepend (list, g_strdup (str)); + + /* Set list and reset the index */ + priv->sent_messages = list; + priv->sent_messages_index = -1; +} + +const gchar * +chat_sent_message_get_next (EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + gint max; + + priv = GET_PRIV (chat); + + if (!priv->sent_messages) { + empathy_debug (DEBUG_DOMAIN, + "No sent messages, next message is NULL"); + return NULL; + } + + max = g_slist_length (priv->sent_messages) - 1; + + if (priv->sent_messages_index < max) { + priv->sent_messages_index++; + } + + empathy_debug (DEBUG_DOMAIN, + "Returning next message index:%d", + priv->sent_messages_index); + + return g_slist_nth_data (priv->sent_messages, priv->sent_messages_index); +} + +const gchar * +chat_sent_message_get_last (EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CHAT (chat), NULL); + + priv = GET_PRIV (chat); + + if (!priv->sent_messages) { + empathy_debug (DEBUG_DOMAIN, + "No sent messages, last message is NULL"); + return NULL; + } + + if (priv->sent_messages_index >= 0) { + priv->sent_messages_index--; + } + + empathy_debug (DEBUG_DOMAIN, + "Returning last message index:%d", + priv->sent_messages_index); + + return g_slist_nth_data (priv->sent_messages, priv->sent_messages_index); +} + +static gboolean +chat_input_key_press_event_cb (GtkWidget *widget, + GdkEventKey *event, + EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + GtkAdjustment *adj; + gdouble val; + GtkWidget *text_view_sw; + + priv = GET_PRIV (chat); + + if (event->keyval == GDK_Tab && !(event->state & GDK_CONTROL_MASK)) { + return TRUE; + } + + /* Catch ctrl+up/down so we can traverse messages we sent */ + if ((event->state & GDK_CONTROL_MASK) && + (event->keyval == GDK_Up || + event->keyval == GDK_Down)) { + GtkTextBuffer *buffer; + const gchar *str; + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); + + if (event->keyval == GDK_Up) { + str = chat_sent_message_get_next (chat); + } else { + str = chat_sent_message_get_last (chat); + } + + g_signal_handlers_block_by_func (buffer, + chat_input_text_buffer_changed_cb, + chat); + gtk_text_buffer_set_text (buffer, str ? str : "", -1); + g_signal_handlers_unblock_by_func (buffer, + chat_input_text_buffer_changed_cb, + chat); + + return TRUE; + } + + /* Catch enter but not ctrl/shift-enter */ + if (IS_ENTER (event->keyval) && !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))) { + GtkTextView *view; + + /* This is to make sure that kinput2 gets the enter. And if + * it's handled there we shouldn't send on it. This is because + * kinput2 uses Enter to commit letters. See: + * http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=104299 + */ + + view = GTK_TEXT_VIEW (chat->input_text_view); + if (gtk_im_context_filter_keypress (view->im_context, event)) { + GTK_TEXT_VIEW (chat->input_text_view)->need_im_reset = TRUE; + return TRUE; + } + + chat_input_text_view_send (chat); + return TRUE; + } + + text_view_sw = gtk_widget_get_parent (GTK_WIDGET (chat->view)); + + if (IS_ENTER (event->keyval) && (event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))) { + /* Newline for shift-enter. */ + return FALSE; + } + else if ((event->state & GDK_CONTROL_MASK) != GDK_CONTROL_MASK && + event->keyval == GDK_Page_Up) { + adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (text_view_sw)); + gtk_adjustment_set_value (adj, adj->value - adj->page_size); + + return TRUE; + } + else if ((event->state & GDK_CONTROL_MASK) != GDK_CONTROL_MASK && + event->keyval == GDK_Page_Down) { + adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (text_view_sw)); + val = MIN (adj->value + adj->page_size, adj->upper - adj->page_size); + gtk_adjustment_set_value (adj, val); + + return TRUE; + } + + return FALSE; +} + +static gboolean +chat_text_view_focus_in_event_cb (GtkWidget *widget, + GdkEvent *event, + EmpathyChat *chat) +{ + gtk_widget_grab_focus (chat->input_text_view); + + return TRUE; +} + +static void +chat_input_text_buffer_changed_cb (GtkTextBuffer *buffer, + EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + GtkTextIter start, end; + gchar *str; + gboolean spell_checker = FALSE; + + priv = GET_PRIV (chat); + + if (gtk_text_buffer_get_char_count (buffer) == 0) { + chat_composing_stop (chat); + } else { + chat_composing_start (chat); + } + + empathy_conf_get_bool (empathy_conf_get (), + EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED, + &spell_checker); + + if (chat->is_first_char) { + GtkRequisition req; + gint window_height; + GtkWidget *dialog; + GtkAllocation *allocation; + + /* Save the window's size */ + dialog = empathy_chat_window_get_dialog (priv->window); + gtk_window_get_size (GTK_WINDOW (dialog), + NULL, &window_height); + + gtk_widget_size_request (chat->input_text_view, &req); + + allocation = >K_WIDGET (chat->view)->allocation; + + priv->default_window_height = window_height; + priv->last_input_height = req.height; + priv->padding_height = window_height - req.height - allocation->height; + + chat->is_first_char = FALSE; + } + + gtk_text_buffer_get_start_iter (buffer, &start); + + if (!spell_checker) { + gtk_text_buffer_get_end_iter (buffer, &end); + gtk_text_buffer_remove_tag_by_name (buffer, "misspelled", &start, &end); + return; + } + + if (!empathy_spell_supported ()) { + return; + } + + /* NOTE: this is really inefficient, we shouldn't have to + reiterate the whole buffer each time and check each work + every time. */ + while (TRUE) { + gboolean correct = FALSE; + + /* if at start */ + if (gtk_text_iter_is_start (&start)) { + end = start; + + if (!gtk_text_iter_forward_word_end (&end)) { + /* no whole word yet */ + break; + } + } else { + if (!gtk_text_iter_forward_word_end (&end)) { + /* must be the end of the buffer */ + break; + } + + start = end; + gtk_text_iter_backward_word_start (&start); + } + + str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE); + + /* spell check string */ + if (!empathy_chat_get_is_command (str)) { + correct = empathy_spell_check (str); + } else { + correct = TRUE; + } + + if (!correct) { + gtk_text_buffer_apply_tag_by_name (buffer, "misspelled", &start, &end); + } else { + gtk_text_buffer_remove_tag_by_name (buffer, "misspelled", &start, &end); + } + + g_free (str); + + /* set start iter to the end iters position */ + start = end; + } +} + +typedef struct { + GtkWidget *window; + gint width; + gint height; +} ChangeSizeData; + +static gboolean +chat_change_size_in_idle_cb (ChangeSizeData *data) +{ + gtk_window_resize (GTK_WINDOW (data->window), + data->width, data->height); + + return FALSE; +} + +static void +chat_text_view_scroll_hide_cb (GtkWidget *widget, + EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + GtkWidget *sw; + + priv = GET_PRIV (chat); + + priv->vscroll_visible = FALSE; + g_signal_handlers_disconnect_by_func (widget, chat_text_view_scroll_hide_cb, chat); + + sw = gtk_widget_get_parent (chat->input_text_view); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), + GTK_POLICY_NEVER, + GTK_POLICY_NEVER); + g_object_set (sw, "height-request", -1, NULL); +} + +static void +chat_text_view_size_allocate_cb (GtkWidget *widget, + GtkAllocation *allocation, + EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + gint width; + GtkWidget *dialog; + ChangeSizeData *data; + gint window_height; + gint new_height; + GtkAllocation *view_allocation; + gint current_height; + gint diff; + GtkWidget *sw; + + priv = GET_PRIV (chat); + + if (priv->default_window_height <= 0) { + return; + } + + sw = gtk_widget_get_parent (widget); + if (sw->allocation.height >= MAX_INPUT_HEIGHT && !priv->vscroll_visible) { + GtkWidget *vscroll; + + priv->vscroll_visible = TRUE; + gtk_widget_set_size_request (sw, sw->allocation.width, MAX_INPUT_HEIGHT); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); + vscroll = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (sw)); + g_signal_connect (vscroll, "hide", + G_CALLBACK (chat_text_view_scroll_hide_cb), + chat); + } + + if (priv->last_input_height <= allocation->height) { + priv->last_input_height = allocation->height; + return; + } + + diff = priv->last_input_height - allocation->height; + priv->last_input_height = allocation->height; + + view_allocation = >K_WIDGET (chat->view)->allocation; + + dialog = empathy_chat_window_get_dialog (priv->window); + gtk_window_get_size (GTK_WINDOW (dialog), NULL, ¤t_height); + + new_height = view_allocation->height + priv->padding_height + allocation->height - diff; + + if (new_height <= priv->default_window_height) { + window_height = priv->default_window_height; + } else { + window_height = new_height; + } + + if (current_height <= window_height) { + return; + } + + /* Restore the window's size */ + gtk_window_get_size (GTK_WINDOW (dialog), &width, NULL); + + data = g_new0 (ChangeSizeData, 1); + data->window = dialog; + data->width = width; + data->height = window_height; + + g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, + (GSourceFunc) chat_change_size_in_idle_cb, + data, g_free); +} + +static void +chat_text_view_realize_cb (GtkWidget *widget, + EmpathyChat *chat) +{ + empathy_debug (DEBUG_DOMAIN, "Setting focus to the input text view"); + gtk_widget_grab_focus (widget); +} + +static void +chat_insert_smiley_activate_cb (GtkWidget *menuitem, + EmpathyChat *chat) +{ + GtkTextBuffer *buffer; + GtkTextIter iter; + const gchar *smiley; + + smiley = g_object_get_data (G_OBJECT (menuitem), "smiley_text"); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); + + gtk_text_buffer_get_end_iter (buffer, &iter); + gtk_text_buffer_insert (buffer, &iter, smiley, -1); + + gtk_text_buffer_get_end_iter (buffer, &iter); + gtk_text_buffer_insert (buffer, &iter, " ", -1); +} + +static void +chat_text_populate_popup_cb (GtkTextView *view, + GtkMenu *menu, + EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + GtkTextBuffer *buffer; + GtkTextTagTable *table; + GtkTextTag *tag; + gint x, y; + GtkTextIter iter, start, end; + GtkWidget *item; + gchar *str = NULL; + EmpathyChatSpell *chat_spell; + GtkWidget *smiley_menu; + + priv = GET_PRIV (chat); + + /* Add the emoticon menu. */ + item = gtk_separator_menu_item_new (); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + + item = gtk_menu_item_new_with_mnemonic (_("Insert Smiley")); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + + smiley_menu = empathy_chat_view_get_smiley_menu ( + G_CALLBACK (chat_insert_smiley_activate_cb), + chat, + priv->tooltips); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), smiley_menu); + + /* Add the spell check menu item. */ + buffer = gtk_text_view_get_buffer (view); + table = gtk_text_buffer_get_tag_table (buffer); + + tag = gtk_text_tag_table_lookup (table, "misspelled"); + + gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y); + + gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view), + GTK_TEXT_WINDOW_WIDGET, + x, y, + &x, &y); + + gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view), &iter, x, y); + + start = end = iter; + + if (gtk_text_iter_backward_to_tag_toggle (&start, tag) && + gtk_text_iter_forward_to_tag_toggle (&end, tag)) { + + str = gtk_text_buffer_get_text (buffer, + &start, &end, FALSE); + } + + if (G_STR_EMPTY (str)) { + return; + } + + chat_spell = chat_spell_new (chat, str, start, end); + + g_object_set_data_full (G_OBJECT (menu), + "chat_spell", chat_spell, + (GDestroyNotify) chat_spell_free); + + item = gtk_separator_menu_item_new (); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + + item = gtk_menu_item_new_with_mnemonic (_("_Check Word Spelling...")); + g_signal_connect (item, + "activate", + G_CALLBACK (chat_text_check_word_spelling_cb), + chat_spell); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); +} + +static void +chat_text_check_word_spelling_cb (GtkMenuItem *menuitem, + EmpathyChatSpell *chat_spell) +{ + empathy_spell_dialog_show (chat_spell->chat, + chat_spell->start, + chat_spell->end, + chat_spell->word); +} + +static EmpathyChatSpell * +chat_spell_new (EmpathyChat *chat, + const gchar *word, + GtkTextIter start, + GtkTextIter end) +{ + EmpathyChatSpell *chat_spell; + + chat_spell = g_new0 (EmpathyChatSpell, 1); + + chat_spell->chat = g_object_ref (chat); + chat_spell->word = g_strdup (word); + chat_spell->start = start; + chat_spell->end = end; + + return chat_spell; +} + +static void +chat_spell_free (EmpathyChatSpell *chat_spell) +{ + g_object_unref (chat_spell->chat); + g_free (chat_spell->word); + g_free (chat_spell); +} + +static void +chat_composing_start (EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + + priv = GET_PRIV (chat); + + if (priv->composing_stop_timeout_id) { + /* Just restart the timeout */ + chat_composing_remove_timeout (chat); + } else { + empathy_tp_chat_set_state (priv->tp_chat, + TP_CHANNEL_CHAT_STATE_COMPOSING); + } + + priv->composing_stop_timeout_id = g_timeout_add ( + 1000 * COMPOSING_STOP_TIMEOUT, + (GSourceFunc) chat_composing_stop_timeout_cb, + chat); +} + +static void +chat_composing_stop (EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + + priv = GET_PRIV (chat); + + chat_composing_remove_timeout (chat); + empathy_tp_chat_set_state (priv->tp_chat, + TP_CHANNEL_CHAT_STATE_ACTIVE); +} + +static void +chat_composing_remove_timeout (EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + + priv = GET_PRIV (chat); + + if (priv->composing_stop_timeout_id) { + g_source_remove (priv->composing_stop_timeout_id); + priv->composing_stop_timeout_id = 0; + } +} + +static gboolean +chat_composing_stop_timeout_cb (EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + + priv = GET_PRIV (chat); + + priv->composing_stop_timeout_id = 0; + empathy_tp_chat_set_state (priv->tp_chat, + TP_CHANNEL_CHAT_STATE_PAUSED); + + return FALSE; +} + +static void +chat_state_changed_cb (EmpathyTpChat *tp_chat, + EmpathyContact *contact, + TelepathyChannelChatState state, + EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + GList *l; + gboolean was_composing; + + priv = GET_PRIV (chat); + + if (empathy_contact_is_user (contact)) { + /* We don't care about our own chat state */ + return; + } + + was_composing = (priv->compositors != NULL); + + /* Find the contact in the list. After that l is the list elem or NULL */ + for (l = priv->compositors; l; l = l->next) { + if (empathy_contact_equal (contact, l->data)) { + break; + } + } + + switch (state) { + case TP_CHANNEL_CHAT_STATE_GONE: + case TP_CHANNEL_CHAT_STATE_INACTIVE: + case TP_CHANNEL_CHAT_STATE_ACTIVE: + /* Contact is not composing */ + if (l) { + priv->compositors = g_list_remove_link (priv->compositors, l); + g_object_unref (l->data); + g_list_free1 (l); + } + break; + case TP_CHANNEL_CHAT_STATE_PAUSED: + case TP_CHANNEL_CHAT_STATE_COMPOSING: + /* Contact is composing */ + if (!l) { + priv->compositors = g_list_prepend (priv->compositors, + g_object_ref (contact)); + } + break; + default: + g_assert_not_reached (); + } + + empathy_debug (DEBUG_DOMAIN, "Was composing: %s now composing: %s", + was_composing ? "yes" : "no", + priv->compositors ? "yes" : "no"); + + if ((was_composing && !priv->compositors) || + (!was_composing && priv->compositors)) { + /* Composing state changed */ + g_signal_emit (chat, signals[COMPOSING], 0, + priv->compositors != NULL); + } +} + +static void +chat_add_logs (EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + GList *messages, *l; + guint num_messages; + guint i; + + priv = GET_PRIV (chat); + + /* Do not display backlog for chatrooms */ + if (empathy_chat_is_group_chat (chat)) { + return; + } + + /* Turn off scrolling temporarily */ + empathy_chat_view_scroll (chat->view, FALSE); + + /* Add messages from last conversation */ + messages = empathy_log_manager_get_last_messages (priv->log_manager, + chat->account, + empathy_chat_get_id (chat), + empathy_chat_is_group_chat (chat)); + num_messages = g_list_length (messages); + + for (l = messages, i = 0; l; l = l->next, i++) { + EmpathyMessage *message; + + message = l->data; + + /* Only add 10 last messages */ + if (num_messages - i > 10) { + g_object_unref (message); + continue; + } + + + empathy_chat_view_append_message (chat->view, message); + g_object_unref (message); + } + g_list_free (messages); + + /* Turn back on scrolling */ + empathy_chat_view_scroll (chat->view, TRUE); + + /* Scroll to the most recent messages, we reference the chat + * for the duration of the scroll func. + */ + priv->scroll_idle_id = g_idle_add ((GSourceFunc) chat_scroll_down_idle_func, + g_object_ref (chat)); +} + +/* Scroll down after the back-log has been received. */ +static gboolean +chat_scroll_down_idle_func (EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + + priv = GET_PRIV (chat); + + empathy_chat_scroll_down (chat); + g_object_unref (chat); + + priv->scroll_idle_id = 0; + + return FALSE; +} + +gboolean +empathy_chat_get_is_command (const gchar *str) +{ + g_return_val_if_fail (str != NULL, FALSE); + + if (str[0] != '/') { + return FALSE; + } + + if (g_str_has_prefix (str, "/me")) { + return TRUE; + } + else if (g_str_has_prefix (str, "/nick")) { + return TRUE; + } + else if (g_str_has_prefix (str, "/topic")) { + return TRUE; + } + + return FALSE; +} + +void +empathy_chat_correct_word (EmpathyChat *chat, + GtkTextIter start, + GtkTextIter end, + const gchar *new_word) +{ + GtkTextBuffer *buffer; + + g_return_if_fail (chat != NULL); + g_return_if_fail (new_word != NULL); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); + + gtk_text_buffer_delete (buffer, &start, &end); + gtk_text_buffer_insert (buffer, &start, + new_word, + -1); +} + +const gchar * +empathy_chat_get_name (EmpathyChat *chat) +{ + g_return_val_if_fail (EMPATHY_IS_CHAT (chat), NULL); + + if (EMPATHY_CHAT_GET_CLASS (chat)->get_name) { + return EMPATHY_CHAT_GET_CLASS (chat)->get_name (chat); + } + + return NULL; +} + +gchar * +empathy_chat_get_tooltip (EmpathyChat *chat) +{ + g_return_val_if_fail (EMPATHY_IS_CHAT (chat), NULL); + + if (EMPATHY_CHAT_GET_CLASS (chat)->get_tooltip) { + return EMPATHY_CHAT_GET_CLASS (chat)->get_tooltip (chat); + } + + return NULL; +} + +const gchar * +empathy_chat_get_status_icon_name (EmpathyChat *chat) +{ + g_return_val_if_fail (EMPATHY_IS_CHAT (chat), NULL); + + if (EMPATHY_CHAT_GET_CLASS (chat)->get_status_icon_name) { + return EMPATHY_CHAT_GET_CLASS (chat)->get_status_icon_name (chat); + } + + return NULL; +} + +GtkWidget * +empathy_chat_get_widget (EmpathyChat *chat) +{ + g_return_val_if_fail (EMPATHY_IS_CHAT (chat), NULL); + + if (EMPATHY_CHAT_GET_CLASS (chat)->get_widget) { + return EMPATHY_CHAT_GET_CLASS (chat)->get_widget (chat); + } + + return NULL; +} + +gboolean +empathy_chat_is_group_chat (EmpathyChat *chat) +{ + g_return_val_if_fail (EMPATHY_IS_CHAT (chat), FALSE); + + if (EMPATHY_CHAT_GET_CLASS (chat)->is_group_chat) { + return EMPATHY_CHAT_GET_CLASS (chat)->is_group_chat (chat); + } + + return FALSE; +} + +gboolean +empathy_chat_is_connected (EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CHAT (chat), FALSE); + + priv = GET_PRIV (chat); + + return (priv->tp_chat != NULL); +} + +void +empathy_chat_save_geometry (EmpathyChat *chat, + gint x, + gint y, + gint w, + gint h) +{ + empathy_geometry_save (empathy_chat_get_id (chat), x, y, w, h); +} + +void +empathy_chat_load_geometry (EmpathyChat *chat, + gint *x, + gint *y, + gint *w, + gint *h) +{ + empathy_geometry_load (empathy_chat_get_id (chat), x, y, w, h); +} + +void +empathy_chat_set_tp_chat (EmpathyChat *chat, + EmpathyTpChat *tp_chat) +{ + EmpathyChatPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHAT (chat)); + g_return_if_fail (EMPATHY_IS_TP_CHAT (tp_chat)); + + priv = GET_PRIV (chat); + + if (tp_chat == priv->tp_chat) { + return; + } + + if (priv->tp_chat) { + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_message_received_cb, + chat); + g_signal_handlers_disconnect_by_func (priv->tp_chat, + chat_destroy_cb, + chat); + g_object_unref (priv->tp_chat); + } + + g_free (priv->id); + priv->tp_chat = g_object_ref (tp_chat); + priv->id = g_strdup (empathy_tp_chat_get_id (tp_chat)); + priv->time_joined = empathy_time_get_current (); + + if (priv->first_tp_chat) { + chat_add_logs (chat); + priv->first_tp_chat = FALSE; + } + + g_signal_connect (tp_chat, "message-received", + G_CALLBACK (chat_message_received_cb), + chat); + g_signal_connect (tp_chat, "chat-state-changed", + G_CALLBACK (chat_state_changed_cb), + chat); + g_signal_connect (tp_chat, "destroy", + G_CALLBACK (chat_destroy_cb), + chat); + + empathy_tp_chat_request_pending (tp_chat); + + if (!priv->sensitive) { + gtk_widget_set_sensitive (chat->input_text_view, TRUE); + empathy_chat_view_append_event (chat->view, _("Connected")); + priv->sensitive = TRUE; + } + + if (EMPATHY_CHAT_GET_CLASS (chat)->set_tp_chat) { + EMPATHY_CHAT_GET_CLASS (chat)->set_tp_chat (chat, tp_chat); + } + +} + +const gchar * +empathy_chat_get_id (EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + + priv = GET_PRIV (chat); + + return priv->id; +} + +void +empathy_chat_clear (EmpathyChat *chat) +{ + g_return_if_fail (EMPATHY_IS_CHAT (chat)); + + empathy_chat_view_clear (chat->view); +} + +void +empathy_chat_set_window (EmpathyChat *chat, + EmpathyChatWindow *window) +{ + EmpathyChatPriv *priv; + + priv = GET_PRIV (chat); + priv->window = window; +} + +EmpathyChatWindow * +empathy_chat_get_window (EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + + priv = GET_PRIV (chat); + + return priv->window; +} + +void +empathy_chat_scroll_down (EmpathyChat *chat) +{ + g_return_if_fail (EMPATHY_IS_CHAT (chat)); + + empathy_chat_view_scroll_down (chat->view); +} + +void +empathy_chat_cut (EmpathyChat *chat) +{ + GtkTextBuffer *buffer; + + g_return_if_fail (EMPATHY_IS_CHAT (chat)); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); + if (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL)) { + GtkClipboard *clipboard; + + clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); + + gtk_text_buffer_cut_clipboard (buffer, clipboard, TRUE); + } +} + +void +empathy_chat_copy (EmpathyChat *chat) +{ + GtkTextBuffer *buffer; + + g_return_if_fail (EMPATHY_IS_CHAT (chat)); + + if (empathy_chat_view_get_selection_bounds (chat->view, NULL, NULL)) { + empathy_chat_view_copy_clipboard (chat->view); + return; + } + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); + if (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL)) { + GtkClipboard *clipboard; + + clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); + + gtk_text_buffer_copy_clipboard (buffer, clipboard); + } +} + +void +empathy_chat_paste (EmpathyChat *chat) +{ + GtkTextBuffer *buffer; + GtkClipboard *clipboard; + + g_return_if_fail (EMPATHY_IS_CHAT (chat)); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); + clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); + + gtk_text_buffer_paste_clipboard (buffer, clipboard, NULL, TRUE); +} + +void +empathy_chat_present (EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHAT (chat)); + + priv = GET_PRIV (chat); + + if (priv->window == NULL) { + EmpathyChatWindow *window; + + window = empathy_chat_window_get_default (); + if (!window) { + window = empathy_chat_window_new (); + } + + empathy_chat_window_add_chat (window, chat); + } + + empathy_chat_window_switch_to_chat (priv->window, chat); + empathy_window_present ( + GTK_WINDOW (empathy_chat_window_get_dialog (priv->window)), + TRUE); + + gtk_widget_grab_focus (chat->input_text_view); +} + +gboolean +empathy_chat_should_play_sound (EmpathyChat *chat) +{ + EmpathyChatWindow *window; + gboolean play = TRUE; + + g_return_val_if_fail (EMPATHY_IS_CHAT (chat), FALSE); + + window = empathy_chat_get_window (chat); + if (!window) { + return TRUE; + } + + play = !empathy_chat_window_has_focus (window); + + return play; +} + +gboolean +empathy_chat_should_highlight_nick (EmpathyMessage *message) +{ + EmpathyContact *contact; + const gchar *msg, *to; + gchar *cf_msg, *cf_to; + gchar *ch; + gboolean ret_val; + + g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), FALSE); + + empathy_debug (DEBUG_DOMAIN, "Highlighting nickname"); + + ret_val = FALSE; + + msg = empathy_message_get_body (message); + if (!msg) { + return FALSE; + } + + contact = empathy_message_get_receiver (message); + if (!contact || !empathy_contact_is_user (contact)) { + return FALSE; + } + + to = empathy_contact_get_name (contact); + if (!to) { + return FALSE; + } + + cf_msg = g_utf8_casefold (msg, -1); + cf_to = g_utf8_casefold (to, -1); + + ch = strstr (cf_msg, cf_to); + if (ch == NULL) { + goto finished; + } + + if (ch != cf_msg) { + /* Not first in the message */ + if ((*(ch - 1) != ' ') && + (*(ch - 1) != ',') && + (*(ch - 1) != '.')) { + goto finished; + } + } + + ch = ch + strlen (cf_to); + if (ch >= cf_msg + strlen (cf_msg)) { + ret_val = TRUE; + goto finished; + } + + if ((*ch == ' ') || + (*ch == ',') || + (*ch == '.') || + (*ch == ':')) { + ret_val = TRUE; + goto finished; + } + +finished: + g_free (cf_msg); + g_free (cf_to); + + return ret_val; +} + diff --git a/libempathy-gtk/empathy-chat.glade b/libempathy-gtk/empathy-chat.glade new file mode 100644 index 00000000..d07bf77e --- /dev/null +++ b/libempathy-gtk/empathy-chat.glade @@ -0,0 +1,699 @@ + + + + + + + Chat + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 350 + 250 + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 4 + True + False + 3 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_ALWAYS + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + + + + 0 + True + True + + + + + + True + True + GTK_POLICY_NEVER + GTK_POLICY_NEVER + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + + + + 0 + False + False + + + + + + + + Chat + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 350 + 250 + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 0 + + + + True + GTK_PACK_DIRECTION_LTR + GTK_PACK_DIRECTION_LTR + + + + True + _Conversation + True + + + + + + + True + C_lear + True + + + + True + gtk-clear + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Insert _Smiley + True + + + + + + True + + + + + + True + _View Previous Conversations + True + + + + + True + gtk-justify-left + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + _Add Contact... + True + + + + True + gtk-add + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Contact Infor_mation + True + + + + True + gtk-info + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + _Close + True + + + + + True + gtk-close + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + + _Room + True + + + + + + + True + Change _Topic... + True + + + + + + True + + + + + + True + Join _New... + True + + + + True + gtk-new + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + In_vite... + True + + + + + + True + + + + + + True + _Add To Favorites + True + + + + True + gtk-add + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + _Show Contacts + True + True + + + + + + + + + + + True + _Edit + True + + + + + + + True + Cu_t + True + + + + + True + gtk-cut + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + _Copy + True + + + + + True + gtk-copy + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + _Paste + True + + + + + True + gtk-paste + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + + True + _Tabs + True + + + + + + + True + _Previous Tab + True + + + + + + + True + _Next Tab + True + + + + + + + True + + + + + + True + Move Tab _Left + True + + + + + + True + Move Tab _Right + True + + + + + + True + _Detach Tab + True + + + + + + + + + 0 + False + False + + + + + + + + + + + + 5 + Invite + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + True + 275 + 225 + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + False + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + + True + False + True + True + True + In_vite + True + GTK_RELIEF_NORMAL + True + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 5 + True + False + 18 + + + + True + False + 6 + + + + True + Select who would you like to invite: + False + True + GTK_JUSTIFY_LEFT + True + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + False + False + True + False + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + False + 6 + + + + True + Invitation _message: + True + True + GTK_JUSTIFY_LEFT + True + False + 0 + 0.5 + 0 + 0 + entry + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + You have been invited to join a chat conference. + True + * + True + 40 + + + 0 + False + False + + + + + 0 + False + False + + + + + 0 + True + True + + + + + + + diff --git a/libempathy-gtk/empathy-chat.h b/libempathy-gtk/empathy-chat.h new file mode 100644 index 00000000..8eedf64e --- /dev/null +++ b/libempathy-gtk/empathy-chat.h @@ -0,0 +1,123 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2002-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Richard Hult + * Martyn Russell + * Geert-Jan Van den Bogaerde + * Xavier Claessens + */ + +#ifndef __EMPATHY_CHAT_H__ +#define __EMPATHY_CHAT_H__ + +#include + +#include +#include +#include + +#include "empathy-chat-view.h" +#include "empathy-spell.h" + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_CHAT (empathy_chat_get_type ()) +#define EMPATHY_CHAT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_CHAT, EmpathyChat)) +#define EMPATHY_CHAT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_CHAT, EmpathyChatClass)) +#define EMPATHY_IS_CHAT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_CHAT)) +#define EMPATHY_IS_CHAT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_CHAT)) +#define EMPATHY_CHAT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_CHAT, EmpathyChatClass)) + +typedef struct _EmpathyChat EmpathyChat; +typedef struct _EmpathyChatClass EmpathyChatClass; +typedef struct _EmpathyChatPriv EmpathyChatPriv; + +#include "empathy-chat-window.h" + +struct _EmpathyChat { + GObject parent; + + /* Protected */ + EmpathyChatView *view; + EmpathyTpChat *tp_chat; + GtkWidget *input_text_view; + gboolean is_first_char; + McAccount *account; +}; + +struct _EmpathyChatClass { + GObjectClass parent; + + /* VTable */ + const gchar * (*get_name) (EmpathyChat *chat); + gchar * (*get_tooltip) (EmpathyChat *chat); + const gchar * (*get_status_icon_name)(EmpathyChat *chat); + GtkWidget * (*get_widget) (EmpathyChat *chat); + gboolean (*is_group_chat) (EmpathyChat *chat); + void (*set_tp_chat) (EmpathyChat *chat, + EmpathyTpChat *tp_chat); +}; + +GType empathy_chat_get_type (void); + +EmpathyChatView * empathy_chat_get_view (EmpathyChat *chat); +EmpathyChatWindow *empathy_chat_get_window (EmpathyChat *chat); +void empathy_chat_set_window (EmpathyChat *chat, + EmpathyChatWindow *window); +void empathy_chat_present (EmpathyChat *chat); +void empathy_chat_clear (EmpathyChat *chat); +void empathy_chat_scroll_down (EmpathyChat *chat); +void empathy_chat_cut (EmpathyChat *chat); +void empathy_chat_copy (EmpathyChat *chat); +void empathy_chat_paste (EmpathyChat *chat); +const gchar * empathy_chat_get_name (EmpathyChat *chat); +gchar * empathy_chat_get_tooltip (EmpathyChat *chat); +const gchar * empathy_chat_get_status_icon_name (EmpathyChat *chat); +GtkWidget * empathy_chat_get_widget (EmpathyChat *chat); +gboolean empathy_chat_is_group_chat (EmpathyChat *chat); +gboolean empathy_chat_is_connected (EmpathyChat *chat); + +void empathy_chat_save_geometry (EmpathyChat *chat, + gint x, + gint y, + gint w, + gint h); +void empathy_chat_load_geometry (EmpathyChat *chat, + gint *x, + gint *y, + gint *w, + gint *h); +void empathy_chat_set_tp_chat (EmpathyChat *chat, + EmpathyTpChat *tp_chat); +const gchar * empathy_chat_get_id (EmpathyChat *chat); + +/* For spell checker dialog to correct the misspelled word. */ +gboolean empathy_chat_get_is_command (const gchar *str); +void empathy_chat_correct_word (EmpathyChat *chat, + GtkTextIter start, + GtkTextIter end, + const gchar *new_word); +gboolean empathy_chat_should_play_sound (EmpathyChat *chat); +gboolean empathy_chat_should_highlight_nick (EmpathyMessage *message); + +G_END_DECLS + +#endif /* __EMPATHY_CHAT_H__ */ diff --git a/libempathy-gtk/empathy-chatrooms-window.c b/libempathy-gtk/empathy-chatrooms-window.c new file mode 100644 index 00000000..c049e366 --- /dev/null +++ b/libempathy-gtk/empathy-chatrooms-window.c @@ -0,0 +1,575 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Xavier Claessens + * Martyn Russell + * Mikael Hallendal + */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "empathy-account-chooser.h" +#include "empathy-chatrooms-window.h" +//#include "empathy-edit-chatroom-dialog.h" +#include "empathy-new-chatroom-dialog.h" +#include "empathy-ui-utils.h" + +typedef struct { + EmpathyChatroomManager *manager; + + GtkWidget *window; + GtkWidget *hbox_account; + GtkWidget *label_account; + GtkWidget *account_chooser; + GtkWidget *treeview; + GtkWidget *button_remove; + GtkWidget *button_edit; + GtkWidget *button_close; + + gint room_column; +} EmpathyChatroomsWindow; + +static void chatrooms_window_destroy_cb (GtkWidget *widget, + EmpathyChatroomsWindow *window); +static void chatrooms_window_model_setup (EmpathyChatroomsWindow *window); +static void chatrooms_window_model_add_columns (EmpathyChatroomsWindow *window); +static void chatrooms_window_model_refresh_data (EmpathyChatroomsWindow *window, + gboolean first_time); +static void chatrooms_window_model_add (EmpathyChatroomsWindow *window, + EmpathyChatroom *chatroom, + gboolean set_active); +static void chatrooms_window_model_cell_auto_connect_toggled (GtkCellRendererToggle *cell, + gchar *path_string, + EmpathyChatroomsWindow *window); +static EmpathyChatroom * chatrooms_window_model_get_selected (EmpathyChatroomsWindow *window); +static void chatrooms_window_model_action_selected (EmpathyChatroomsWindow *window); +static void chatrooms_window_row_activated_cb (GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + EmpathyChatroomsWindow *window); +static void chatrooms_window_button_remove_clicked_cb (GtkWidget *widget, + EmpathyChatroomsWindow *window); +static void chatrooms_window_button_edit_clicked_cb (GtkWidget *widget, + EmpathyChatroomsWindow *window); +static void chatrooms_window_button_close_clicked_cb (GtkWidget *widget, + EmpathyChatroomsWindow *window); +static void chatrooms_window_chatroom_added_cb (EmpathyChatroomManager *manager, + EmpathyChatroom *chatroom, + EmpathyChatroomsWindow *window); +static void chatrooms_window_chatroom_removed_cb (EmpathyChatroomManager *manager, + EmpathyChatroom *chatroom, + EmpathyChatroomsWindow *window); +static gboolean chatrooms_window_remove_chatroom_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + EmpathyChatroom *chatroom); +static void chatrooms_window_account_changed_cb (GtkWidget *combo_box, + EmpathyChatroomsWindow *window); + +enum { + COL_IMAGE, + COL_NAME, + COL_ROOM, + COL_AUTO_CONNECT, + COL_POINTER, + COL_COUNT +}; + +void +empathy_chatrooms_window_show (GtkWindow *parent) +{ + static EmpathyChatroomsWindow *window = NULL; + GladeXML *glade; + + if (window) { + gtk_window_present (GTK_WINDOW (window->window)); + return; + } + + window = g_new0 (EmpathyChatroomsWindow, 1); + + glade = empathy_glade_get_file ("empathy-chatrooms-window.glade", + "chatrooms_window", + NULL, + "chatrooms_window", &window->window, + "hbox_account", &window->hbox_account, + "label_account", &window->label_account, + "treeview", &window->treeview, + "button_edit", &window->button_edit, + "button_remove", &window->button_remove, + "button_close", &window->button_close, + NULL); + + empathy_glade_connect (glade, + window, + "chatrooms_window", "destroy", chatrooms_window_destroy_cb, + "button_remove", "clicked", chatrooms_window_button_remove_clicked_cb, + "button_edit", "clicked", chatrooms_window_button_edit_clicked_cb, + "button_close", "clicked", chatrooms_window_button_close_clicked_cb, + NULL); + + g_object_unref (glade); + + g_object_add_weak_pointer (G_OBJECT (window->window), (gpointer) &window); + + /* Get the session and chat room manager */ + window->manager = empathy_chatroom_manager_new (); + + g_signal_connect (window->manager, "chatroom-added", + G_CALLBACK (chatrooms_window_chatroom_added_cb), + window); + g_signal_connect (window->manager, "chatroom-removed", + G_CALLBACK (chatrooms_window_chatroom_removed_cb), + window); + + /* Account chooser for chat rooms */ + window->account_chooser = empathy_account_chooser_new (); + empathy_account_chooser_set_account (EMPATHY_ACCOUNT_CHOOSER (window->account_chooser), NULL); + g_object_set (window->account_chooser, + "can-select-all", TRUE, + "has-all-option", TRUE, + NULL); + + gtk_box_pack_start (GTK_BOX (window->hbox_account), + window->account_chooser, + TRUE, TRUE, 0); + + g_signal_connect (window->account_chooser, "changed", + G_CALLBACK (chatrooms_window_account_changed_cb), + window); + + gtk_widget_show (window->account_chooser); + + /* Set up chatrooms */ + chatrooms_window_model_setup (window); + + /* Set focus */ + gtk_widget_grab_focus (window->treeview); + + /* Last touches */ + if (parent) { + gtk_window_set_transient_for (GTK_WINDOW (window->window), + GTK_WINDOW (parent)); + } + + gtk_widget_show (window->window); +} + +static void +chatrooms_window_destroy_cb (GtkWidget *widget, + EmpathyChatroomsWindow *window) +{ + g_object_unref (window->manager); + g_free (window); +} + +static void +chatrooms_window_model_setup (EmpathyChatroomsWindow *window) +{ + GtkTreeView *view; + GtkListStore *store; + GtkTreeSelection *selection; + + /* View */ + view = GTK_TREE_VIEW (window->treeview); + + g_signal_connect (view, "row-activated", + G_CALLBACK (chatrooms_window_row_activated_cb), + window); + + /* Store */ + store = gtk_list_store_new (COL_COUNT, + G_TYPE_STRING, /* Image */ + G_TYPE_STRING, /* Name */ + G_TYPE_STRING, /* Room */ + G_TYPE_BOOLEAN, /* Auto start */ + EMPATHY_TYPE_CHATROOM); /* Chatroom */ + + gtk_tree_view_set_model (view, GTK_TREE_MODEL (store)); + + /* Selection */ + selection = gtk_tree_view_get_selection (view); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + + /* Columns */ + chatrooms_window_model_add_columns (window); + + /* Add data */ + chatrooms_window_model_refresh_data (window, TRUE); + + /* Clean up */ + g_object_unref (store); +} + +static void +chatrooms_window_model_add_columns (EmpathyChatroomsWindow *window) +{ + GtkTreeView *view; + GtkTreeModel *model; + GtkTreeViewColumn *column; + GtkCellRenderer *cell; + gint count; + + view = GTK_TREE_VIEW (window->treeview); + model = gtk_tree_view_get_model (view); + + gtk_tree_view_set_headers_visible (view, TRUE); + gtk_tree_view_set_headers_clickable (view, TRUE); + + /* Name & Status */ + column = gtk_tree_view_column_new (); + count = gtk_tree_view_append_column (view, column); + + gtk_tree_view_column_set_title (column, _("Name")); + gtk_tree_view_column_set_expand (column, TRUE); + gtk_tree_view_column_set_sort_column_id (column, count - 1); + + cell = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, cell, FALSE); + gtk_tree_view_column_add_attribute (column, cell, "icon-name", COL_IMAGE); + + cell = gtk_cell_renderer_text_new (); + g_object_set (cell, + "xpad", 4, + "ypad", 1, + NULL); + gtk_tree_view_column_pack_start (column, cell, TRUE); + gtk_tree_view_column_add_attribute (column, cell, "text", COL_NAME); + + /* Room */ + cell = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Room"), cell, + "text", COL_ROOM, + NULL); + count = gtk_tree_view_append_column (view, column); + gtk_tree_view_column_set_sort_column_id (column, count - 1); + window->room_column = count - 1; + + /* Chatroom auto connect */ + cell = gtk_cell_renderer_toggle_new (); + column = gtk_tree_view_column_new_with_attributes (_("Auto Connect"), cell, + "active", COL_AUTO_CONNECT, + NULL); + count = gtk_tree_view_append_column (view, column); + gtk_tree_view_column_set_sort_column_id (column, count - 1); + + g_signal_connect (cell, "toggled", + G_CALLBACK (chatrooms_window_model_cell_auto_connect_toggled), + window); + + /* Sort model */ + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), 0, + GTK_SORT_ASCENDING); +} + +static void +chatrooms_window_model_refresh_data (EmpathyChatroomsWindow *window, + gboolean first_time) +{ + GtkTreeView *view; + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkListStore *store; + GtkTreeIter iter; + GtkTreeViewColumn *column; + EmpathyAccountChooser *account_chooser; + McAccount *account; + GList *chatrooms, *l; + + view = GTK_TREE_VIEW (window->treeview); + selection = gtk_tree_view_get_selection (view); + model = gtk_tree_view_get_model (view); + store = GTK_LIST_STORE (model); + + /* Look up chatrooms */ + account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser); + account = empathy_account_chooser_get_account (account_chooser); + + chatrooms = empathy_chatroom_manager_get_chatrooms (window->manager, account); + + /* Sort out columns, we only show the server column for + * selected protocol types, such as Jabber. + */ + if (account) { + column = gtk_tree_view_get_column (view, window->room_column); + gtk_tree_view_column_set_visible (column, TRUE); + } else { + column = gtk_tree_view_get_column (view, window->room_column); + gtk_tree_view_column_set_visible (column, FALSE); + } + + /* Clean out the store */ + gtk_list_store_clear (store); + + /* Populate with chatroom list. */ + for (l = chatrooms; l; l = l->next) { + chatrooms_window_model_add (window, l->data, FALSE); + } + + if (gtk_tree_model_get_iter_first (model, &iter)) { + gtk_tree_selection_select_iter (selection, &iter); + } + + if (account) { + g_object_unref (account); + } + + g_list_free (chatrooms); +} + +static void +chatrooms_window_model_add (EmpathyChatroomsWindow *window, + EmpathyChatroom *chatroom, + gboolean set_active) +{ + GtkTreeView *view; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkListStore *store; + GtkTreeIter iter; + + view = GTK_TREE_VIEW (window->treeview); + selection = gtk_tree_view_get_selection (view); + model = gtk_tree_view_get_model (view); + store = GTK_LIST_STORE (model); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + COL_NAME, empathy_chatroom_get_name (chatroom), + COL_ROOM, empathy_chatroom_get_room (chatroom), + COL_AUTO_CONNECT, empathy_chatroom_get_auto_connect (chatroom), + COL_POINTER, chatroom, + -1); + + if (set_active) { + gtk_tree_selection_select_iter (selection, &iter); + } +} + +static void +chatrooms_window_model_cell_auto_connect_toggled (GtkCellRendererToggle *cell, + gchar *path_string, + EmpathyChatroomsWindow *window) +{ + EmpathyChatroom *chatroom; + gboolean enabled; + GtkTreeView *view; + GtkTreeModel *model; + GtkListStore *store; + GtkTreePath *path; + GtkTreeIter iter; + + view = GTK_TREE_VIEW (window->treeview); + model = gtk_tree_view_get_model (view); + store = GTK_LIST_STORE (model); + + path = gtk_tree_path_new_from_string (path_string); + + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get (model, &iter, + COL_AUTO_CONNECT, &enabled, + COL_POINTER, &chatroom, + -1); + + enabled = !enabled; + + empathy_chatroom_set_auto_connect (chatroom, enabled); + empathy_chatroom_manager_store (window->manager); + + gtk_list_store_set (store, &iter, COL_AUTO_CONNECT, enabled, -1); + gtk_tree_path_free (path); + g_object_unref (chatroom); +} + +static EmpathyChatroom * +chatrooms_window_model_get_selected (EmpathyChatroomsWindow *window) +{ + GtkTreeView *view; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + EmpathyChatroom *chatroom = NULL; + + view = GTK_TREE_VIEW (window->treeview); + selection = gtk_tree_view_get_selection (view); + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + gtk_tree_model_get (model, &iter, COL_POINTER, &chatroom, -1); + } + + return chatroom; +} + +static void +chatrooms_window_model_action_selected (EmpathyChatroomsWindow *window) +{ + EmpathyChatroom *chatroom; + GtkTreeView *view; + GtkTreeModel *model; + + view = GTK_TREE_VIEW (window->treeview); + model = gtk_tree_view_get_model (view); + + chatroom = chatrooms_window_model_get_selected (window); + if (!chatroom) { + return; + } + + //empathy_edit_chatroom_dialog_show (GTK_WINDOW (window->window), chatroom); + + g_object_unref (chatroom); +} + +static void +chatrooms_window_row_activated_cb (GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + EmpathyChatroomsWindow *window) +{ + if (GTK_WIDGET_IS_SENSITIVE (window->button_edit)) { + chatrooms_window_model_action_selected (window); + } +} + +static void +chatrooms_window_button_remove_clicked_cb (GtkWidget *widget, + EmpathyChatroomsWindow *window) +{ + EmpathyChatroom *chatroom; + GtkTreeView *view; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + + /* Remove from treeview */ + view = GTK_TREE_VIEW (window->treeview); + selection = gtk_tree_view_get_selection (view); + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { + return; + } + + gtk_tree_model_get (model, &iter, COL_POINTER, &chatroom, -1); + gtk_list_store_remove (GTK_LIST_STORE (model), &iter); + + /* Remove from config */ + empathy_chatroom_manager_remove (window->manager, chatroom); + + g_object_unref (chatroom); +} + +static void +chatrooms_window_button_edit_clicked_cb (GtkWidget *widget, + EmpathyChatroomsWindow *window) +{ + EmpathyChatroom *chatroom; + + chatroom = chatrooms_window_model_get_selected (window); + if (!chatroom) { + return; + } + + //empathy_edit_chatroom_dialog_show (GTK_WINDOW (window->window), chatroom); + + g_object_unref (chatroom); +} + +static void +chatrooms_window_button_close_clicked_cb (GtkWidget *widget, + EmpathyChatroomsWindow *window) +{ + gtk_widget_destroy (window->window); +} + +static void +chatrooms_window_chatroom_added_cb (EmpathyChatroomManager *manager, + EmpathyChatroom *chatroom, + EmpathyChatroomsWindow *window) +{ + EmpathyAccountChooser *account_chooser; + McAccount *account; + + account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser); + account = empathy_account_chooser_get_account (account_chooser); + + if (!account) { + chatrooms_window_model_add (window, chatroom, FALSE); + } else { + if (empathy_account_equal (account, empathy_chatroom_get_account (chatroom))) { + chatrooms_window_model_add (window, chatroom, FALSE); + } + + g_object_unref (account); + } +} + +static void +chatrooms_window_chatroom_removed_cb (EmpathyChatroomManager *manager, + EmpathyChatroom *chatroom, + EmpathyChatroomsWindow *window) +{ + GtkTreeModel *model; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (window->treeview)); + + gtk_tree_model_foreach (model, + (GtkTreeModelForeachFunc) chatrooms_window_remove_chatroom_foreach, + chatroom); +} + +static gboolean +chatrooms_window_remove_chatroom_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + EmpathyChatroom *chatroom) +{ + EmpathyChatroom *this_chatroom; + + gtk_tree_model_get (model, iter, COL_POINTER, &this_chatroom, -1); + + if (empathy_chatroom_equal (chatroom, this_chatroom)) { + gtk_list_store_remove (GTK_LIST_STORE (model), iter); + g_object_unref (this_chatroom); + return TRUE; + } + + g_object_unref (this_chatroom); + + return FALSE; +} + +static void +chatrooms_window_account_changed_cb (GtkWidget *combo_box, + EmpathyChatroomsWindow *window) +{ + chatrooms_window_model_refresh_data (window, FALSE); +} + diff --git a/libempathy-gtk/empathy-chatrooms-window.glade b/libempathy-gtk/empathy-chatrooms-window.glade new file mode 100644 index 00000000..c5f5dc99 --- /dev/null +++ b/libempathy-gtk/empathy-chatrooms-window.glade @@ -0,0 +1,477 @@ + + + + + + + 5 + True + Edit Favorite Room + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + False + False + gtk-edit + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + False + + + + True + False + 2 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + + True + True + True + gtk-save + True + GTK_RELIEF_NORMAL + True + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 5 + True + 5 + 2 + False + 6 + 12 + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 3 + 4 + + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 2 + 3 + + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 1 + 2 + + + + + + + True + _Room: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + entry_room + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 3 + 4 + fill + + + + + + + True + S_erver: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + entry_server + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + _Nickname: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + entry_nickname + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + N_ame: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + entry_name + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + True + True + True + 0 + + True + * + False + 25 + + + 1 + 2 + 0 + 1 + + + + + + + True + Join this chat room when Empathy starts and you are connected + True + Join room on start_up + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 1 + 2 + 4 + 5 + fill + + + + + + 0 + True + True + + + + + + + + 12 + True + Manage Favorite Rooms + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 12 + + + + True + False + 18 + + + + True + False + 12 + + + + True + Account: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + True + + + + + + + + + 0 + False + True + + + + + + 150 + True + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + True + False + False + True + False + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + GTK_BUTTONBOX_END + 6 + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + True + gtk-remove + True + GTK_RELIEF_NORMAL + True + + + + + + True + False + True + True + gtk-edit + True + GTK_RELIEF_NORMAL + True + + + + + 0 + False + False + + + + + + + diff --git a/libempathy-gtk/empathy-chatrooms-window.h b/libempathy-gtk/empathy-chatrooms-window.h new file mode 100644 index 00000000..17908205 --- /dev/null +++ b/libempathy-gtk/empathy-chatrooms-window.h @@ -0,0 +1,35 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Xavier Claessens + * Martyn Russell + * Mikael Hallendal + */ + +#ifndef __EMPATHY_CHATROOMS_WINDOW_H__ +#define __EMPATHY_CHATROOMS_WINDOW_H__ + +G_BEGIN_DECLS + +void empathy_chatrooms_window_show (GtkWindow *parent); + +G_END_DECLS + +#endif /* __EMPATHY_CHATROOMS_WINDOW_H__ */ diff --git a/libempathy-gtk/empathy-contact-dialogs.c b/libempathy-gtk/empathy-contact-dialogs.c index 7d1e2603..659d9176 100644 --- a/libempathy-gtk/empathy-contact-dialogs.c +++ b/libempathy-gtk/empathy-contact-dialogs.c @@ -34,7 +34,7 @@ #include "empathy-contact-dialogs.h" #include "empathy-contact-widget.h" -#include "gossip-ui-utils.h" +#include "empathy-ui-utils.h" static GList *subscription_dialogs = NULL; static GList *information_dialogs = NULL; @@ -43,15 +43,15 @@ static GtkWidget *new_contact_dialog = NULL; static gint contact_dialogs_find (GtkDialog *dialog, - GossipContact *contact) + EmpathyContact *contact) { GtkWidget *contact_widget; - GossipContact *this_contact; + EmpathyContact *this_contact; contact_widget = g_object_get_data (G_OBJECT (dialog), "contact_widget"); this_contact = empathy_contact_widget_get_contact (contact_widget); - return !gossip_contact_equal (contact, this_contact); + return !empathy_contact_equal (contact, this_contact); } /* @@ -64,7 +64,7 @@ subscription_dialog_response_cb (GtkDialog *dialog, GtkWidget *contact_widget) { EmpathyContactManager *manager; - GossipContact *contact; + EmpathyContact *contact; manager = empathy_contact_manager_new (); contact = empathy_contact_widget_get_contact (contact_widget); @@ -84,7 +84,7 @@ subscription_dialog_response_cb (GtkDialog *dialog, } void -empathy_subscription_dialog_show (GossipContact *contact, +empathy_subscription_dialog_show (EmpathyContact *contact, GtkWindow *parent) { GtkWidget *dialog; @@ -92,7 +92,7 @@ empathy_subscription_dialog_show (GossipContact *contact, GtkWidget *contact_widget; GList *l; - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); l = g_list_find_custom (subscription_dialogs, contact, @@ -102,7 +102,7 @@ empathy_subscription_dialog_show (GossipContact *contact, return; } - gossip_glade_get_file_simple ("empathy-contact-dialogs.glade", + empathy_glade_get_file_simple ("empathy-contact-dialogs.glade", "subscription_request_dialog", NULL, "subscription_request_dialog", &dialog, @@ -143,7 +143,7 @@ contact_information_response_cb (GtkDialog *dialog, } void -empathy_contact_information_dialog_show (GossipContact *contact, +empathy_contact_information_dialog_show (EmpathyContact *contact, GtkWindow *parent, gboolean edit) { @@ -152,7 +152,7 @@ empathy_contact_information_dialog_show (GossipContact *contact, GtkWidget *contact_widget; GList *l; - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); l = g_list_find_custom (information_dialogs, contact, @@ -205,7 +205,7 @@ new_contact_response_cb (GtkDialog *dialog, GtkWidget *contact_widget) { EmpathyContactManager *manager; - GossipContact *contact; + EmpathyContact *contact; manager = empathy_contact_manager_new (); contact = empathy_contact_widget_get_contact (contact_widget); diff --git a/libempathy-gtk/empathy-contact-dialogs.h b/libempathy-gtk/empathy-contact-dialogs.h index 55b5a186..560ae8f2 100644 --- a/libempathy-gtk/empathy-contact-dialogs.h +++ b/libempathy-gtk/empathy-contact-dialogs.h @@ -25,13 +25,13 @@ #include -#include +#include G_BEGIN_DECLS -void empathy_subscription_dialog_show (GossipContact *contact, +void empathy_subscription_dialog_show (EmpathyContact *contact, GtkWindow *parent); -void empathy_contact_information_dialog_show (GossipContact *contact, +void empathy_contact_information_dialog_show (EmpathyContact *contact, GtkWindow *parent, gboolean edit); void empathy_new_contact_dialog_show (GtkWindow *parent); diff --git a/libempathy-gtk/empathy-contact-groups.c b/libempathy-gtk/empathy-contact-groups.c new file mode 100644 index 00000000..1e5fabe2 --- /dev/null +++ b/libempathy-gtk/empathy-contact-groups.c @@ -0,0 +1,286 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2005-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Martyn Russell + */ + +#include "config.h" + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include "empathy-contact-groups.h" + +#define DEBUG_DOMAIN "ContactGroups" + +#define CONTACT_GROUPS_XML_FILENAME "contact-groups.xml" +#define CONTACT_GROUPS_DTD_FILENAME "empathy-contact-groups.dtd" + +typedef struct { + gchar *name; + gboolean expanded; +} ContactGroup; + +static void contact_groups_file_parse (const gchar *filename); +static gboolean contact_groups_file_save (void); +static ContactGroup *contact_group_new (const gchar *name, + gboolean expanded); +static void contact_group_free (ContactGroup *group); + +static GList *groups = NULL; + +void +empathy_contact_groups_get_all (void) +{ + gchar *dir; + gchar *file_with_path; + + /* If already set up clean up first */ + if (groups) { + g_list_foreach (groups, (GFunc)contact_group_free, NULL); + g_list_free (groups); + groups = NULL; + } + + dir = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, NULL); + file_with_path = g_build_filename (dir, CONTACT_GROUPS_XML_FILENAME, NULL); + g_free (dir); + + if (g_file_test (file_with_path, G_FILE_TEST_EXISTS)) { + contact_groups_file_parse (file_with_path); + } + + g_free (file_with_path); +} + +static void +contact_groups_file_parse (const gchar *filename) +{ + xmlParserCtxtPtr ctxt; + xmlDocPtr doc; + xmlNodePtr contacts; + xmlNodePtr account; + xmlNodePtr node; + + empathy_debug (DEBUG_DOMAIN, "Attempting to parse file:'%s'...", filename); + + ctxt = xmlNewParserCtxt (); + + /* Parse and validate the file. */ + doc = xmlCtxtReadFile (ctxt, filename, NULL, 0); + if (!doc) { + g_warning ("Failed to parse file:'%s'", filename); + xmlFreeParserCtxt (ctxt); + return; + } + + if (!empathy_xml_validate (doc, CONTACT_GROUPS_DTD_FILENAME)) { + g_warning ("Failed to validate file:'%s'", filename); + xmlFreeDoc(doc); + xmlFreeParserCtxt (ctxt); + return; + } + + /* The root node, contacts. */ + contacts = xmlDocGetRootElement (doc); + + account = NULL; + node = contacts->children; + while (node) { + if (strcmp ((gchar *) node->name, "account") == 0) { + account = node; + break; + } + node = node->next; + } + + node = NULL; + if (account) { + node = account->children; + } + + while (node) { + if (strcmp ((gchar *) node->name, "group") == 0) { + gchar *name; + gchar *expanded_str; + gboolean expanded; + ContactGroup *contact_group; + + name = (gchar *) xmlGetProp (node, "name"); + expanded_str = (gchar *) xmlGetProp (node, "expanded"); + + if (expanded_str && strcmp (expanded_str, "yes") == 0) { + expanded = TRUE; + } else { + expanded = FALSE; + } + + contact_group = contact_group_new (name, expanded); + groups = g_list_append (groups, contact_group); + + xmlFree (name); + xmlFree (expanded_str); + } + + node = node->next; + } + + empathy_debug (DEBUG_DOMAIN, "Parsed %d contact groups", g_list_length (groups)); + + xmlFreeDoc(doc); + xmlFreeParserCtxt (ctxt); +} + +static ContactGroup * +contact_group_new (const gchar *name, + gboolean expanded) +{ + ContactGroup *group; + + group = g_new0 (ContactGroup, 1); + + group->name = g_strdup (name); + group->expanded = expanded; + + return group; +} + +static void +contact_group_free (ContactGroup *group) +{ + g_return_if_fail (group != NULL); + + g_free (group->name); + + g_free (group); +} + +static gboolean +contact_groups_file_save (void) +{ + xmlDocPtr doc; + xmlNodePtr root; + xmlNodePtr node; + GList *l; + gchar *dir; + gchar *file; + + dir = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, NULL); + g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR); + file = g_build_filename (dir, CONTACT_GROUPS_XML_FILENAME, NULL); + g_free (dir); + + doc = xmlNewDoc ("1.0"); + root = xmlNewNode (NULL, "contacts"); + xmlDocSetRootElement (doc, root); + + node = xmlNewChild (root, NULL, "account", NULL); + xmlNewProp (node, "name", "Default"); + + for (l = groups; l; l = l->next) { + ContactGroup *cg; + xmlNodePtr subnode; + + cg = l->data; + + subnode = xmlNewChild (node, NULL, "group", NULL); + xmlNewProp (subnode, "expanded", cg->expanded ? "yes" : "no"); + xmlNewProp (subnode, "name", cg->name); + } + + /* Make sure the XML is indented properly */ + xmlIndentTreeOutput = 1; + + empathy_debug (DEBUG_DOMAIN, "Saving file:'%s'", file); + xmlSaveFormatFileEnc (file, doc, "utf-8", 1); + xmlFreeDoc (doc); + + xmlCleanupParser (); + xmlMemoryDump (); + + g_free (file); + + return TRUE; +} + +gboolean +empathy_contact_group_get_expanded (const gchar *group) +{ + GList *l; + gboolean default_val = TRUE; + + g_return_val_if_fail (group != NULL, default_val); + + for (l = groups; l; l = l->next) { + ContactGroup *cg = l->data; + + if (!cg || !cg->name) { + continue; + } + + if (strcmp (cg->name, group) == 0) { + return cg->expanded; + } + } + + return default_val; +} + +void +empathy_contact_group_set_expanded (const gchar *group, + gboolean expanded) +{ + GList *l; + ContactGroup *cg; + gboolean changed = FALSE; + + g_return_if_fail (group != NULL); + + for (l = groups; l; l = l->next) { + ContactGroup *cg = l->data; + + if (!cg || !cg->name) { + continue; + } + + if (strcmp (cg->name, group) == 0) { + cg->expanded = expanded; + changed = TRUE; + break; + } + } + + /* if here... we don't have a ContactGroup for the group. */ + if (!changed) { + cg = contact_group_new (group, expanded); + groups = g_list_append (groups, cg); + } + + contact_groups_file_save (); +} diff --git a/libempathy-gtk/empathy-contact-groups.dtd b/libempathy-gtk/empathy-contact-groups.dtd new file mode 100644 index 00000000..b4de2260 --- /dev/null +++ b/libempathy-gtk/empathy-contact-groups.dtd @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/libempathy-gtk/empathy-contact-groups.h b/libempathy-gtk/empathy-contact-groups.h new file mode 100644 index 00000000..e2e9810e --- /dev/null +++ b/libempathy-gtk/empathy-contact-groups.h @@ -0,0 +1,38 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2005 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Martyn Russell + */ + +#ifndef __EMPATHY_CONTACT_GROUPS_H__ +#define __EMPATHY_CONTACT_GROUPS_H__ + +G_BEGIN_DECLS + +#include + +void empathy_contact_groups_get_all (void); + +gboolean empathy_contact_group_get_expanded (const gchar *group); +void empathy_contact_group_set_expanded (const gchar *group, + gboolean expanded); + +G_END_DECLS + +#endif /* __EMPATHY_CONTACT_GROUPS_H__ */ diff --git a/libempathy-gtk/empathy-contact-list-store.c b/libempathy-gtk/empathy-contact-list-store.c new file mode 100644 index 00000000..44ea4483 --- /dev/null +++ b/libempathy-gtk/empathy-contact-list-store.c @@ -0,0 +1,1484 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2005-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Martyn Russell + * Xavier Claessens + */ + +#include "config.h" + +#include + +#include +#include + +#include + +#include "empathy-contact-list-store.h" +#include "empathy-contact-groups.h" +#include "empathy-ui-utils.h" + +#define DEBUG_DOMAIN "ContactListStore" + +/* Active users are those which have recently changed state + * (e.g. online, offline or from normal to a busy state). + */ + +/* Time user is shown as active */ +#define ACTIVE_USER_SHOW_TIME 7000 + +/* Time after connecting which we wait before active users are enabled */ +#define ACTIVE_USER_WAIT_TO_ENABLE_TIME 5000 + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CONTACT_LIST_STORE, EmpathyContactListStorePriv)) + +struct _EmpathyContactListStorePriv { + EmpathyContactList *list; + gboolean show_offline; + gboolean show_avatars; + gboolean is_compact; + gboolean show_active; + EmpathyContactListStoreSort sort_criterium; + guint inhibit_active; + + EmpathyContactGroupsFunc get_contact_groups; + gpointer get_contact_groups_data; +}; + +typedef struct { + GtkTreeIter iter; + const gchar *name; + gboolean found; +} FindGroup; + +typedef struct { + EmpathyContact *contact; + gboolean found; + GList *iters; +} FindContact; + +typedef struct { + EmpathyContactListStore *store; + EmpathyContact *contact; + gboolean remove; +} ShowActiveData; + +static void empathy_contact_list_store_class_init (EmpathyContactListStoreClass *klass); +static void empathy_contact_list_store_init (EmpathyContactListStore *list); +static void contact_list_store_finalize (GObject *object); +static void contact_list_store_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); +static void contact_list_store_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void contact_list_store_setup (EmpathyContactListStore *store); +static gboolean contact_list_store_inibit_active_cb (EmpathyContactListStore *store); +static void contact_list_store_contact_added_cb (EmpathyContactList *list_iface, + EmpathyContact *contact, + EmpathyContactListStore *store); +static void contact_list_store_add_contact (EmpathyContactListStore *store, + EmpathyContact *contact); +static void contact_list_store_contact_removed_cb (EmpathyContactList *list_iface, + EmpathyContact *contact, + EmpathyContactListStore *store); +static void contact_list_store_remove_contact (EmpathyContactListStore *store, + EmpathyContact *contact); +static void contact_list_store_contact_update (EmpathyContactListStore *store, + EmpathyContact *contact); +static void contact_list_store_contact_groups_updated_cb (EmpathyContact *contact, + GParamSpec *param, + EmpathyContactListStore *store); +static void contact_list_store_contact_updated_cb (EmpathyContact *contact, + GParamSpec *param, + EmpathyContactListStore *store); +static void contact_list_store_contact_set_active (EmpathyContactListStore *store, + EmpathyContact *contact, + gboolean active, + gboolean set_changed); +static ShowActiveData * contact_list_store_contact_active_new (EmpathyContactListStore *store, + EmpathyContact *contact, + gboolean remove); +static void contact_list_store_contact_active_free (ShowActiveData *data); +static gboolean contact_list_store_contact_active_cb (ShowActiveData *data); +static gboolean contact_list_store_get_group_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + FindGroup *fg); +static void contact_list_store_get_group (EmpathyContactListStore *store, + const gchar *name, + GtkTreeIter *iter_group_to_set, + GtkTreeIter *iter_separator_to_set, + gboolean *created); +static gint contact_list_store_state_sort_func (GtkTreeModel *model, + GtkTreeIter *iter_a, + GtkTreeIter *iter_b, + gpointer user_data); +static gint contact_list_store_name_sort_func (GtkTreeModel *model, + GtkTreeIter *iter_a, + GtkTreeIter *iter_b, + gpointer user_data); +static gboolean contact_list_store_find_contact_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + FindContact *fc); +static GList * contact_list_store_find_contact (EmpathyContactListStore *store, + EmpathyContact *contact); +static gboolean contact_list_store_update_list_mode_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + EmpathyContactListStore *store); + +enum { + PROP_0, + PROP_SHOW_OFFLINE, + PROP_SHOW_AVATARS, + PROP_IS_COMPACT, + PROP_SORT_CRITERIUM +}; + +GType +empathy_contact_list_store_sort_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) { + static const GEnumValue values[] = { + { EMPATHY_CONTACT_LIST_STORE_SORT_NAME, + "EMPATHY_CONTACT_LIST_STORE_SORT_NAME", + "name" }, + { EMPATHY_CONTACT_LIST_STORE_SORT_STATE, + "EMPATHY_CONTACT_LIST_STORE_SORT_STATE", + "state" }, + { 0, NULL, NULL } + }; + + etype = g_enum_register_static ("EmpathyContactListStoreSort", values); + } + + return etype; +} + +G_DEFINE_TYPE (EmpathyContactListStore, empathy_contact_list_store, GTK_TYPE_TREE_STORE); + +static void +empathy_contact_list_store_class_init (EmpathyContactListStoreClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = contact_list_store_finalize; + object_class->get_property = contact_list_store_get_property; + object_class->set_property = contact_list_store_set_property; + + g_object_class_install_property (object_class, + PROP_SHOW_OFFLINE, + g_param_spec_boolean ("show-offline", + "Show Offline", + "Whether contact list should display " + "offline contacts", + FALSE, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_SHOW_AVATARS, + g_param_spec_boolean ("show-avatars", + "Show Avatars", + "Whether contact list should display " + "avatars for contacts", + TRUE, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_IS_COMPACT, + g_param_spec_boolean ("is-compact", + "Is Compact", + "Whether the contact list is in compact mode or not", + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_SORT_CRITERIUM, + g_param_spec_enum ("sort-criterium", + "Sort citerium", + "The sort criterium to use for sorting the contact list", + EMPATHY_TYPE_CONTACT_LIST_STORE_SORT, + EMPATHY_CONTACT_LIST_STORE_SORT_NAME, + G_PARAM_READWRITE)); + + g_type_class_add_private (object_class, sizeof (EmpathyContactListStorePriv)); +} + +static void +empathy_contact_list_store_init (EmpathyContactListStore *store) +{ + EmpathyContactListStorePriv *priv; + + priv = GET_PRIV (store); + + priv->inhibit_active = g_timeout_add (ACTIVE_USER_WAIT_TO_ENABLE_TIME, + (GSourceFunc) contact_list_store_inibit_active_cb, + store); +} + +static void +contact_list_store_finalize (GObject *object) +{ + EmpathyContactListStorePriv *priv; + + priv = GET_PRIV (object); + + /* FIXME: disconnect all signals on the list and contacts */ + + if (priv->list) { + g_object_unref (priv->list); + } + + if (priv->inhibit_active) { + g_source_remove (priv->inhibit_active); + } + + G_OBJECT_CLASS (empathy_contact_list_store_parent_class)->finalize (object); +} + +static void +contact_list_store_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + EmpathyContactListStorePriv *priv; + + priv = GET_PRIV (object); + + switch (param_id) { + case PROP_SHOW_OFFLINE: + g_value_set_boolean (value, priv->show_offline); + break; + case PROP_SHOW_AVATARS: + g_value_set_boolean (value, priv->show_avatars); + break; + case PROP_IS_COMPACT: + g_value_set_boolean (value, priv->is_compact); + break; + case PROP_SORT_CRITERIUM: + g_value_set_enum (value, priv->sort_criterium); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + }; +} + +static void +contact_list_store_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + EmpathyContactListStorePriv *priv; + + priv = GET_PRIV (object); + + switch (param_id) { + case PROP_SHOW_OFFLINE: + empathy_contact_list_store_set_show_offline (EMPATHY_CONTACT_LIST_STORE (object), + g_value_get_boolean (value)); + break; + case PROP_SHOW_AVATARS: + empathy_contact_list_store_set_show_avatars (EMPATHY_CONTACT_LIST_STORE (object), + g_value_get_boolean (value)); + break; + case PROP_IS_COMPACT: + empathy_contact_list_store_set_is_compact (EMPATHY_CONTACT_LIST_STORE (object), + g_value_get_boolean (value)); + break; + case PROP_SORT_CRITERIUM: + empathy_contact_list_store_set_sort_criterium (EMPATHY_CONTACT_LIST_STORE (object), + g_value_get_enum (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + }; +} + +EmpathyContactListStore * +empathy_contact_list_store_new (EmpathyContactList *list_iface) +{ + EmpathyContactListStore *store; + EmpathyContactListStorePriv *priv; + GList *contacts, *l; + + g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST (list_iface), NULL); + + store = g_object_new (EMPATHY_TYPE_CONTACT_LIST_STORE, NULL); + priv = GET_PRIV (store); + + contact_list_store_setup (store); + priv->list = g_object_ref (list_iface); + + /* Signal connection. */ + g_signal_connect (priv->list, + "contact-added", + G_CALLBACK (contact_list_store_contact_added_cb), + store); + g_signal_connect (priv->list, + "contact-removed", + G_CALLBACK (contact_list_store_contact_removed_cb), + store); + + /* Add contacts already created. */ + contacts = empathy_contact_list_get_members (priv->list); + for (l = contacts; l; l = l->next) { + EmpathyContact *contact; + + contact = l->data; + + contact_list_store_contact_added_cb (priv->list, contact, store); + + g_object_unref (contact); + } + g_list_free (contacts); + + return store; +} + +EmpathyContactList * +empathy_contact_list_store_get_list_iface (EmpathyContactListStore *store) +{ + EmpathyContactListStorePriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store), FALSE); + + priv = GET_PRIV (store); + + return priv->list; +} + +gboolean +empathy_contact_list_store_get_show_offline (EmpathyContactListStore *store) +{ + EmpathyContactListStorePriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store), FALSE); + + priv = GET_PRIV (store); + + return priv->show_offline; +} + +void +empathy_contact_list_store_set_show_offline (EmpathyContactListStore *store, + gboolean show_offline) +{ + EmpathyContactListStorePriv *priv; + GList *contacts, *l; + gboolean show_active; + + g_return_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store)); + + priv = GET_PRIV (store); + + priv->show_offline = show_offline; + show_active = priv->show_active; + + /* Disable temporarily. */ + priv->show_active = FALSE; + + contacts = empathy_contact_list_get_members (priv->list); + for (l = contacts; l; l = l->next) { + EmpathyContact *contact; + + contact = EMPATHY_CONTACT (l->data); + + contact_list_store_contact_update (store, contact); + + g_object_unref (contact); + } + g_list_free (contacts); + + /* Restore to original setting. */ + priv->show_active = show_active; +} + +gboolean +empathy_contact_list_store_get_show_avatars (EmpathyContactListStore *store) +{ + EmpathyContactListStorePriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store), TRUE); + + priv = GET_PRIV (store); + + return priv->show_avatars; +} + +void +empathy_contact_list_store_set_show_avatars (EmpathyContactListStore *store, + gboolean show_avatars) +{ + EmpathyContactListStorePriv *priv; + GtkTreeModel *model; + + g_return_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store)); + + priv = GET_PRIV (store); + + priv->show_avatars = show_avatars; + + model = GTK_TREE_MODEL (store); + + gtk_tree_model_foreach (model, + (GtkTreeModelForeachFunc) + contact_list_store_update_list_mode_foreach, + store); +} + +gboolean +empathy_contact_list_store_get_is_compact (EmpathyContactListStore *store) +{ + EmpathyContactListStorePriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store), TRUE); + + priv = GET_PRIV (store); + + return priv->is_compact; +} + +void +empathy_contact_list_store_set_is_compact (EmpathyContactListStore *store, + gboolean is_compact) +{ + EmpathyContactListStorePriv *priv; + GtkTreeModel *model; + + g_return_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store)); + + priv = GET_PRIV (store); + + priv->is_compact = is_compact; + + model = GTK_TREE_MODEL (store); + + gtk_tree_model_foreach (model, + (GtkTreeModelForeachFunc) + contact_list_store_update_list_mode_foreach, + store); +} + +EmpathyContactListStoreSort +empathy_contact_list_store_get_sort_criterium (EmpathyContactListStore *store) +{ + EmpathyContactListStorePriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store), 0); + + priv = GET_PRIV (store); + + return priv->sort_criterium; +} + +void +empathy_contact_list_store_set_sort_criterium (EmpathyContactListStore *store, + EmpathyContactListStoreSort sort_criterium) +{ + EmpathyContactListStorePriv *priv; + + g_return_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store)); + + priv = GET_PRIV (store); + + priv->sort_criterium = sort_criterium; + + switch (sort_criterium) { + case EMPATHY_CONTACT_LIST_STORE_SORT_STATE: + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), + COL_STATUS, + GTK_SORT_ASCENDING); + break; + + case EMPATHY_CONTACT_LIST_STORE_SORT_NAME: + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), + COL_NAME, + GTK_SORT_ASCENDING); + break; + } +} + +gboolean +empathy_contact_list_store_row_separator_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gboolean is_separator = FALSE; + + g_return_val_if_fail (GTK_IS_TREE_MODEL (model), FALSE); + + gtk_tree_model_get (model, iter, + COL_IS_SEPARATOR, &is_separator, + -1); + + return is_separator; +} + +gchar * +empathy_contact_list_store_get_parent_group (GtkTreeModel *model, + GtkTreePath *path, + gboolean *path_is_group) +{ + GtkTreeIter parent_iter, iter; + gchar *name = NULL; + gboolean is_group; + + g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL); + + if (path_is_group) { + *path_is_group = FALSE; + } + + if (!gtk_tree_model_get_iter (model, &iter, path)) { + return NULL; + } + + gtk_tree_model_get (model, &iter, + COL_IS_GROUP, &is_group, + COL_NAME, &name, + -1); + + if (!is_group) { + g_free (name); + name = NULL; + + if (!gtk_tree_model_iter_parent (model, &parent_iter, &iter)) { + return NULL; + } + + iter = parent_iter; + + gtk_tree_model_get (model, &iter, + COL_IS_GROUP, &is_group, + COL_NAME, &name, + -1); + if (!is_group) { + g_free (name); + return NULL; + } + } + + if (path_is_group) { + *path_is_group = TRUE; + } + + return name; +} + +gboolean +empathy_contact_list_store_search_equal_func (GtkTreeModel *model, + gint column, + const gchar *key, + GtkTreeIter *iter, + gpointer search_data) +{ + gchar *name, *name_folded; + gchar *key_folded; + gboolean ret; + + g_return_val_if_fail (GTK_IS_TREE_MODEL (model), FALSE); + + if (!key) { + return FALSE; + } + + gtk_tree_model_get (model, iter, COL_NAME, &name, -1); + + if (!name) { + return FALSE; + } + + name_folded = g_utf8_casefold (name, -1); + key_folded = g_utf8_casefold (key, -1); + + if (name_folded && key_folded && + strstr (name_folded, key_folded)) { + ret = FALSE; + } else { + ret = TRUE; + } + + g_free (name); + g_free (name_folded); + g_free (key_folded); + + return ret; +} + +void +empathy_contact_list_store_set_contact_groups_func (EmpathyContactListStore *store, + EmpathyContactGroupsFunc func, + gpointer user_data) +{ + EmpathyContactListStorePriv *priv; + GList *contacts, *l; + + g_return_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store)); + + priv = GET_PRIV (store); + + if (func) { + priv->get_contact_groups = func; + priv->get_contact_groups_data = user_data; + } else { + priv->get_contact_groups = NULL; + priv->get_contact_groups_data = NULL; + } + + /* If we set a custom function to get contacts groups we have to + * disconnect our default notify::groups signal and wait for the user + * to call himself empathy_contact_list_store_update_contact_groups () + * when needed. If func is NULL we come back to default. + */ + contacts = empathy_contact_list_get_members (priv->list); + for (l = contacts; l; l = l->next) { + EmpathyContact *contact; + + contact = l->data; + + if (func) { + g_signal_handlers_disconnect_by_func (contact, + G_CALLBACK (contact_list_store_contact_groups_updated_cb), + store); + } else { + g_signal_connect (contact, "notify::groups", + G_CALLBACK (contact_list_store_contact_groups_updated_cb), + store); + } + + empathy_contact_list_store_update_contact_groups (store, contact); + + g_object_unref (contact); + } + g_list_free (contacts); +} + +void +empathy_contact_list_store_update_contact_groups (EmpathyContactListStore *store, + EmpathyContact *contact) +{ + EmpathyContactListStorePriv *priv; + gboolean show_active; + + g_return_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store)); + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + + priv = GET_PRIV (store); + + empathy_debug (DEBUG_DOMAIN, "Contact:'%s' updating groups", + empathy_contact_get_name (contact)); + + /* We do this to make sure the groups are correct, if not, we + * would have to check the groups already set up for each + * contact and then see what has been updated. + */ + show_active = priv->show_active; + priv->show_active = FALSE; + contact_list_store_remove_contact (store, contact); + contact_list_store_add_contact (store, contact); + priv->show_active = show_active; +} + +static void +contact_list_store_setup (EmpathyContactListStore *store) +{ + EmpathyContactListStorePriv *priv; + GType types[] = {G_TYPE_STRING, /* Status icon-name */ + GDK_TYPE_PIXBUF, /* Avatar pixbuf */ + G_TYPE_BOOLEAN, /* Avatar pixbuf visible */ + G_TYPE_STRING, /* Name */ + G_TYPE_STRING, /* Status string */ + G_TYPE_BOOLEAN, /* Show status */ + EMPATHY_TYPE_CONTACT, /* Contact type */ + G_TYPE_BOOLEAN, /* Is group */ + G_TYPE_BOOLEAN, /* Is active */ + G_TYPE_BOOLEAN, /* Is online */ + G_TYPE_BOOLEAN}; /* Is separator */ + + priv = GET_PRIV (store); + + gtk_tree_store_set_column_types (GTK_TREE_STORE (store), COL_COUNT, types); + + /* Set up sorting */ + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store), + COL_NAME, + contact_list_store_name_sort_func, + store, NULL); + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store), + COL_STATUS, + contact_list_store_state_sort_func, + store, NULL); + + priv->sort_criterium = EMPATHY_CONTACT_LIST_STORE_SORT_NAME; + empathy_contact_list_store_set_sort_criterium (store, priv->sort_criterium); +} + +static gboolean +contact_list_store_inibit_active_cb (EmpathyContactListStore *store) +{ + EmpathyContactListStorePriv *priv; + + priv = GET_PRIV (store); + + priv->show_active = TRUE; + priv->inhibit_active = 0; + + return FALSE; +} + +static void +contact_list_store_contact_added_cb (EmpathyContactList *list_iface, + EmpathyContact *contact, + EmpathyContactListStore *store) +{ + EmpathyContactListStorePriv *priv; + + priv = GET_PRIV (store); + + empathy_debug (DEBUG_DOMAIN, + "Contact:'%s' added", + empathy_contact_get_name (contact)); + + if (!priv->get_contact_groups) { + g_signal_connect (contact, "notify::groups", + G_CALLBACK (contact_list_store_contact_groups_updated_cb), + store); + } + g_signal_connect (contact, "notify::presence", + G_CALLBACK (contact_list_store_contact_updated_cb), + store); + g_signal_connect (contact, "notify::name", + G_CALLBACK (contact_list_store_contact_updated_cb), + store); + g_signal_connect (contact, "notify::avatar", + G_CALLBACK (contact_list_store_contact_updated_cb), + store); + g_signal_connect (contact, "notify::type", + G_CALLBACK (contact_list_store_contact_updated_cb), + store); + + contact_list_store_add_contact (store, contact); +} + +static void +contact_list_store_add_contact (EmpathyContactListStore *store, + EmpathyContact *contact) +{ + EmpathyContactListStorePriv *priv; + GtkTreeIter iter; + GList *groups, *l; + + priv = GET_PRIV (store); + + if (!priv->show_offline && !empathy_contact_is_online (contact)) { + return; + } + + /* If no groups just add it at the top level. */ + if (priv->get_contact_groups) { + groups = priv->get_contact_groups (contact, + priv->get_contact_groups_data); + } else { + groups = empathy_contact_get_groups (contact); + } + + if (!groups) { + gtk_tree_store_append (GTK_TREE_STORE (store), &iter, NULL); + gtk_tree_store_set (GTK_TREE_STORE (store), &iter, + COL_NAME, empathy_contact_get_name (contact), + COL_CONTACT, contact, + COL_IS_GROUP, FALSE, + COL_IS_SEPARATOR, FALSE, + -1); + } + + /* Else add to each group. */ + for (l = groups; l; l = l->next) { + GtkTreeIter iter_group; + const gchar *name; + + name = l->data; + if (!name) { + continue; + } + + contact_list_store_get_group (store, name, &iter_group, NULL, NULL); + + gtk_tree_store_insert_after (GTK_TREE_STORE (store), &iter, + &iter_group, NULL); + gtk_tree_store_set (GTK_TREE_STORE (store), &iter, + COL_NAME, empathy_contact_get_name (contact), + COL_CONTACT, contact, + COL_IS_GROUP, FALSE, + COL_IS_SEPARATOR, FALSE, + -1); + } + + contact_list_store_contact_update (store, contact); +} + +static void +contact_list_store_contact_removed_cb (EmpathyContactList *list_iface, + EmpathyContact *contact, + EmpathyContactListStore *store) +{ + empathy_debug (DEBUG_DOMAIN, "Contact:'%s' removed", + empathy_contact_get_name (contact)); + + /* Disconnect signals */ + g_signal_handlers_disconnect_by_func (contact, + G_CALLBACK (contact_list_store_contact_groups_updated_cb), + store); + g_signal_handlers_disconnect_by_func (contact, + G_CALLBACK (contact_list_store_contact_updated_cb), + store); + + contact_list_store_remove_contact (store, contact); +} + +static void +contact_list_store_remove_contact (EmpathyContactListStore *store, + EmpathyContact *contact) +{ + EmpathyContactListStorePriv *priv; + GtkTreeModel *model; + GList *iters, *l; + + priv = GET_PRIV (store); + + iters = contact_list_store_find_contact (store, contact); + if (!iters) { + return; + } + + /* Clean up model */ + model = GTK_TREE_MODEL (store); + + for (l = iters; l; l = l->next) { + GtkTreeIter parent; + + /* NOTE: it is only <= 2 here because we have + * separators after the group name, otherwise it + * should be 1. + */ + if (gtk_tree_model_iter_parent (model, &parent, l->data) && + gtk_tree_model_iter_n_children (model, &parent) <= 2) { + gtk_tree_store_remove (GTK_TREE_STORE (store), &parent); + } else { + gtk_tree_store_remove (GTK_TREE_STORE (store), l->data); + } + } + + g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL); + g_list_free (iters); +} + +static void +contact_list_store_contact_update (EmpathyContactListStore *store, + EmpathyContact *contact) +{ + EmpathyContactListStorePriv *priv; + ShowActiveData *data; + GtkTreeModel *model; + GList *iters, *l; + gboolean in_list; + gboolean should_be_in_list; + gboolean was_online = TRUE; + gboolean now_online = FALSE; + gboolean set_model = FALSE; + gboolean do_remove = FALSE; + gboolean do_set_active = FALSE; + gboolean do_set_refresh = FALSE; + GdkPixbuf *pixbuf_avatar; + + priv = GET_PRIV (store); + + model = GTK_TREE_MODEL (store); + + iters = contact_list_store_find_contact (store, contact); + if (!iters) { + in_list = FALSE; + } else { + in_list = TRUE; + } + + /* Get online state now. */ + now_online = empathy_contact_is_online (contact); + + if (priv->show_offline || now_online) { + should_be_in_list = TRUE; + } else { + should_be_in_list = FALSE; + } + + if (!in_list && !should_be_in_list) { + /* Nothing to do. */ + empathy_debug (DEBUG_DOMAIN, + "Contact:'%s' in list:NO, should be:NO", + empathy_contact_get_name (contact)); + + g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL); + g_list_free (iters); + return; + } + else if (in_list && !should_be_in_list) { + empathy_debug (DEBUG_DOMAIN, + "Contact:'%s' in list:YES, should be:NO", + empathy_contact_get_name (contact)); + + if (priv->show_active) { + do_remove = TRUE; + do_set_active = TRUE; + do_set_refresh = TRUE; + + set_model = TRUE; + empathy_debug (DEBUG_DOMAIN, "Remove item (after timeout)"); + } else { + empathy_debug (DEBUG_DOMAIN, "Remove item (now)!"); + contact_list_store_remove_contact (store, contact); + } + } + else if (!in_list && should_be_in_list) { + empathy_debug (DEBUG_DOMAIN, + "Contact:'%s' in list:NO, should be:YES", + empathy_contact_get_name (contact)); + + contact_list_store_add_contact (store, contact); + + if (priv->show_active) { + do_set_active = TRUE; + + empathy_debug (DEBUG_DOMAIN, "Set active (contact added)"); + } + } else { + empathy_debug (DEBUG_DOMAIN, + "Contact:'%s' in list:YES, should be:YES", + empathy_contact_get_name (contact)); + + /* Get online state before. */ + if (iters && g_list_length (iters) > 0) { + gtk_tree_model_get (model, iters->data, + COL_IS_ONLINE, &was_online, + -1); + } + + /* Is this really an update or an online/offline. */ + if (priv->show_active) { + if (was_online != now_online) { + do_set_active = TRUE; + do_set_refresh = TRUE; + + empathy_debug (DEBUG_DOMAIN, "Set active (contact updated %s)", + was_online ? "online -> offline" : + "offline -> online"); + } else { + /* Was TRUE for presence updates. */ + /* do_set_active = FALSE; */ + do_set_refresh = TRUE; + + empathy_debug (DEBUG_DOMAIN, "Set active (contact updated)"); + } + } + + set_model = TRUE; + } + + pixbuf_avatar = empathy_pixbuf_avatar_from_contact_scaled (contact, 32, 32); + for (l = iters; l && set_model; l = l->next) { + gtk_tree_store_set (GTK_TREE_STORE (store), l->data, + COL_ICON_STATUS, empathy_icon_name_for_contact (contact), + COL_PIXBUF_AVATAR, pixbuf_avatar, + COL_PIXBUF_AVATAR_VISIBLE, priv->show_avatars, + COL_NAME, empathy_contact_get_name (contact), + COL_STATUS, empathy_contact_get_status (contact), + COL_STATUS_VISIBLE, !priv->is_compact, + COL_IS_GROUP, FALSE, + COL_IS_ONLINE, now_online, + COL_IS_SEPARATOR, FALSE, + -1); + } + + if (pixbuf_avatar) { + g_object_unref (pixbuf_avatar); + } + + if (priv->show_active && do_set_active) { + contact_list_store_contact_set_active (store, contact, do_set_active, do_set_refresh); + + if (do_set_active) { + data = contact_list_store_contact_active_new (store, contact, do_remove); + g_timeout_add (ACTIVE_USER_SHOW_TIME, + (GSourceFunc) contact_list_store_contact_active_cb, + data); + } + } + + /* FIXME: when someone goes online then offline quickly, the + * first timeout sets the user to be inactive and the second + * timeout removes the user from the contact list, really we + * should remove the first timeout. + */ + g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL); + g_list_free (iters); +} + +static void +contact_list_store_contact_groups_updated_cb (EmpathyContact *contact, + GParamSpec *param, + EmpathyContactListStore *store) +{ + empathy_contact_list_store_update_contact_groups (store, contact); +} + +static void +contact_list_store_contact_updated_cb (EmpathyContact *contact, + GParamSpec *param, + EmpathyContactListStore *store) +{ + empathy_debug (DEBUG_DOMAIN, + "Contact:'%s' updated, checking roster is in sync...", + empathy_contact_get_name (contact)); + + contact_list_store_contact_update (store, contact); +} + +static void +contact_list_store_contact_set_active (EmpathyContactListStore *store, + EmpathyContact *contact, + gboolean active, + gboolean set_changed) +{ + EmpathyContactListStorePriv *priv; + GtkTreeModel *model; + GList *iters, *l; + + priv = GET_PRIV (store); + model = GTK_TREE_MODEL (store); + + iters = contact_list_store_find_contact (store, contact); + for (l = iters; l; l = l->next) { + GtkTreePath *path; + + gtk_tree_store_set (GTK_TREE_STORE (store), l->data, + COL_IS_ACTIVE, active, + -1); + + empathy_debug (DEBUG_DOMAIN, "Set item %s", active ? "active" : "inactive"); + + if (set_changed) { + path = gtk_tree_model_get_path (model, l->data); + gtk_tree_model_row_changed (model, path, l->data); + gtk_tree_path_free (path); + } + } + + g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL); + g_list_free (iters); + +} + +static ShowActiveData * +contact_list_store_contact_active_new (EmpathyContactListStore *store, + EmpathyContact *contact, + gboolean remove) +{ + ShowActiveData *data; + + empathy_debug (DEBUG_DOMAIN, + "Contact:'%s' now active, and %s be removed", + empathy_contact_get_name (contact), + remove ? "WILL" : "WILL NOT"); + + data = g_slice_new0 (ShowActiveData); + + data->store = g_object_ref (store); + data->contact = g_object_ref (contact); + data->remove = remove; + + return data; +} + +static void +contact_list_store_contact_active_free (ShowActiveData *data) +{ + g_object_unref (data->contact); + g_object_unref (data->store); + + g_slice_free (ShowActiveData, data); +} + +static gboolean +contact_list_store_contact_active_cb (ShowActiveData *data) +{ + EmpathyContactListStorePriv *priv; + + priv = GET_PRIV (data->store); + + if (data->remove && + !priv->show_offline && + !empathy_contact_is_online (data->contact)) { + empathy_debug (DEBUG_DOMAIN, + "Contact:'%s' active timeout, removing item", + empathy_contact_get_name (data->contact)); + contact_list_store_remove_contact (data->store, data->contact); + } + + empathy_debug (DEBUG_DOMAIN, + "Contact:'%s' no longer active", + empathy_contact_get_name (data->contact)); + + contact_list_store_contact_set_active (data->store, + data->contact, + FALSE, + TRUE); + + contact_list_store_contact_active_free (data); + + return FALSE; +} + +static gboolean +contact_list_store_get_group_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + FindGroup *fg) +{ + gchar *str; + gboolean is_group; + + /* Groups are only at the top level. */ + if (gtk_tree_path_get_depth (path) != 1) { + return FALSE; + } + + gtk_tree_model_get (model, iter, + COL_NAME, &str, + COL_IS_GROUP, &is_group, + -1); + + if (is_group && strcmp (str, fg->name) == 0) { + fg->found = TRUE; + fg->iter = *iter; + } + + g_free (str); + + return fg->found; +} + +static void +contact_list_store_get_group (EmpathyContactListStore *store, + const gchar *name, + GtkTreeIter *iter_group_to_set, + GtkTreeIter *iter_separator_to_set, + gboolean *created) +{ + EmpathyContactListStorePriv *priv; + GtkTreeModel *model; + GtkTreeIter iter_group; + GtkTreeIter iter_separator; + FindGroup fg; + + priv = GET_PRIV (store); + + memset (&fg, 0, sizeof (fg)); + + fg.name = name; + + model = GTK_TREE_MODEL (store); + gtk_tree_model_foreach (model, + (GtkTreeModelForeachFunc) contact_list_store_get_group_foreach, + &fg); + + if (!fg.found) { + if (created) { + *created = TRUE; + } + + gtk_tree_store_append (GTK_TREE_STORE (store), &iter_group, NULL); + gtk_tree_store_set (GTK_TREE_STORE (store), &iter_group, + COL_ICON_STATUS, NULL, + COL_NAME, name, + COL_IS_GROUP, TRUE, + COL_IS_ACTIVE, FALSE, + COL_IS_SEPARATOR, FALSE, + -1); + + if (iter_group_to_set) { + *iter_group_to_set = iter_group; + } + + gtk_tree_store_append (GTK_TREE_STORE (store), + &iter_separator, + &iter_group); + gtk_tree_store_set (GTK_TREE_STORE (store), &iter_separator, + COL_IS_SEPARATOR, TRUE, + -1); + + if (iter_separator_to_set) { + *iter_separator_to_set = iter_separator; + } + } else { + if (created) { + *created = FALSE; + } + + if (iter_group_to_set) { + *iter_group_to_set = fg.iter; + } + + iter_separator = fg.iter; + + if (gtk_tree_model_iter_next (model, &iter_separator)) { + gboolean is_separator; + + gtk_tree_model_get (model, &iter_separator, + COL_IS_SEPARATOR, &is_separator, + -1); + + if (is_separator && iter_separator_to_set) { + *iter_separator_to_set = iter_separator; + } + } + } +} + +static gint +contact_list_store_state_sort_func (GtkTreeModel *model, + GtkTreeIter *iter_a, + GtkTreeIter *iter_b, + gpointer user_data) +{ + gint ret_val = 0; + gchar *name_a, *name_b; + gboolean is_separator_a, is_separator_b; + EmpathyContact *contact_a, *contact_b; + EmpathyPresence *presence_a, *presence_b; + McPresence state_a, state_b; + + gtk_tree_model_get (model, iter_a, + COL_NAME, &name_a, + COL_CONTACT, &contact_a, + COL_IS_SEPARATOR, &is_separator_a, + -1); + gtk_tree_model_get (model, iter_b, + COL_NAME, &name_b, + COL_CONTACT, &contact_b, + COL_IS_SEPARATOR, &is_separator_b, + -1); + + /* Separator or group? */ + if (is_separator_a || is_separator_b) { + if (is_separator_a) { + ret_val = -1; + } else if (is_separator_b) { + ret_val = 1; + } + } else if (!contact_a && contact_b) { + ret_val = 1; + } else if (contact_a && !contact_b) { + ret_val = -1; + } else if (!contact_a && !contact_b) { + /* Handle groups */ + ret_val = g_utf8_collate (name_a, name_b); + } + + if (ret_val) { + goto free_and_out; + } + + /* If we managed to get this far, we can start looking at + * the presences. + */ + presence_a = empathy_contact_get_presence (EMPATHY_CONTACT (contact_a)); + presence_b = empathy_contact_get_presence (EMPATHY_CONTACT (contact_b)); + + if (!presence_a && presence_b) { + ret_val = 1; + } else if (presence_a && !presence_b) { + ret_val = -1; + } else if (!presence_a && !presence_b) { + /* Both offline, sort by name */ + ret_val = g_utf8_collate (name_a, name_b); + } else { + state_a = empathy_presence_get_state (presence_a); + state_b = empathy_presence_get_state (presence_b); + + if (state_a < state_b) { + ret_val = -1; + } else if (state_a > state_b) { + ret_val = 1; + } else { + /* Fallback: compare by name */ + ret_val = g_utf8_collate (name_a, name_b); + } + } + +free_and_out: + g_free (name_a); + g_free (name_b); + + if (contact_a) { + g_object_unref (contact_a); + } + + if (contact_b) { + g_object_unref (contact_b); + } + + return ret_val; +} + +static gint +contact_list_store_name_sort_func (GtkTreeModel *model, + GtkTreeIter *iter_a, + GtkTreeIter *iter_b, + gpointer user_data) +{ + gchar *name_a, *name_b; + EmpathyContact *contact_a, *contact_b; + gboolean is_separator_a, is_separator_b; + gint ret_val; + + gtk_tree_model_get (model, iter_a, + COL_NAME, &name_a, + COL_CONTACT, &contact_a, + COL_IS_SEPARATOR, &is_separator_a, + -1); + gtk_tree_model_get (model, iter_b, + COL_NAME, &name_b, + COL_CONTACT, &contact_b, + COL_IS_SEPARATOR, &is_separator_b, + -1); + + /* If contact is NULL it means it's a group. */ + + if (is_separator_a || is_separator_b) { + if (is_separator_a) { + ret_val = -1; + } else if (is_separator_b) { + ret_val = 1; + } + } else if (!contact_a && contact_b) { + ret_val = 1; + } else if (contact_a && !contact_b) { + ret_val = -1; + } else { + ret_val = g_utf8_collate (name_a, name_b); + } + + g_free (name_a); + g_free (name_b); + + if (contact_a) { + g_object_unref (contact_a); + } + + if (contact_b) { + g_object_unref (contact_b); + } + + return ret_val; +} + +static gboolean +contact_list_store_find_contact_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + FindContact *fc) +{ + EmpathyContact *contact; + + gtk_tree_model_get (model, iter, + COL_CONTACT, &contact, + -1); + + if (!contact) { + return FALSE; + } + + if (empathy_contact_equal (contact, fc->contact)) { + fc->found = TRUE; + fc->iters = g_list_append (fc->iters, gtk_tree_iter_copy (iter)); + } + g_object_unref (contact); + + return FALSE; +} + +static GList * +contact_list_store_find_contact (EmpathyContactListStore *store, + EmpathyContact *contact) +{ + EmpathyContactListStorePriv *priv; + GtkTreeModel *model; + GList *l = NULL; + FindContact fc; + + priv = GET_PRIV (store); + + memset (&fc, 0, sizeof (fc)); + + fc.contact = contact; + + model = GTK_TREE_MODEL (store); + gtk_tree_model_foreach (model, + (GtkTreeModelForeachFunc) contact_list_store_find_contact_foreach, + &fc); + + if (fc.found) { + l = fc.iters; + } + + return l; +} + +static gboolean +contact_list_store_update_list_mode_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + EmpathyContactListStore *store) +{ + EmpathyContactListStorePriv *priv; + gboolean show_avatar = FALSE; + + priv = GET_PRIV (store); + + if (priv->show_avatars && !priv->is_compact) { + show_avatar = TRUE; + } + + gtk_tree_store_set (GTK_TREE_STORE (store), iter, + COL_PIXBUF_AVATAR_VISIBLE, show_avatar, + COL_STATUS_VISIBLE, !priv->is_compact, + -1); + + return FALSE; +} + diff --git a/libempathy-gtk/empathy-contact-list-store.h b/libempathy-gtk/empathy-contact-list-store.h new file mode 100644 index 00000000..2e40e8c7 --- /dev/null +++ b/libempathy-gtk/empathy-contact-list-store.h @@ -0,0 +1,122 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2005-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Martyn Russell + * Xavier Claessens + */ + +#ifndef __EMPATHY_CONTACT_LIST_STORE_H__ +#define __EMPATHY_CONTACT_LIST_STORE_H__ + +#include + +#include +#include + +G_BEGIN_DECLS + +/* + * EmpathyContactListStoreSort + */ +#define EMPATHY_TYPE_CONTACT_LIST_STORE_SORT (empathy_contact_list_store_sort_get_type ()) + +typedef enum { + EMPATHY_CONTACT_LIST_STORE_SORT_STATE, + EMPATHY_CONTACT_LIST_STORE_SORT_NAME +} EmpathyContactListStoreSort; + +GType empathy_contact_list_store_sort_get_type (void) G_GNUC_CONST; + +/* + * EmpathyContactListStore + */ +#define EMPATHY_TYPE_CONTACT_LIST_STORE (empathy_contact_list_store_get_type ()) +#define EMPATHY_CONTACT_LIST_STORE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_CONTACT_LIST_STORE, EmpathyContactListStore)) +#define EMPATHY_CONTACT_LIST_STORE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_CONTACT_LIST_STORE, EmpathyContactListStoreClass)) +#define EMPATHY_IS_CONTACT_LIST_STORE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_CONTACT_LIST_STORE)) +#define EMPATHY_IS_CONTACT_LIST_STORE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_CONTACT_LIST_STORE)) +#define EMPATHY_CONTACT_LIST_STORE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_CONTACT_LIST_STORE, EmpathyContactListStoreClass)) + +typedef struct _EmpathyContactListStore EmpathyContactListStore; +typedef struct _EmpathyContactListStoreClass EmpathyContactListStoreClass; +typedef struct _EmpathyContactListStorePriv EmpathyContactListStorePriv; + +enum { + COL_ICON_STATUS, + COL_PIXBUF_AVATAR, + COL_PIXBUF_AVATAR_VISIBLE, + COL_NAME, + COL_STATUS, + COL_STATUS_VISIBLE, + COL_CONTACT, + COL_IS_GROUP, + COL_IS_ACTIVE, + COL_IS_ONLINE, + COL_IS_SEPARATOR, + COL_COUNT +} EmpathyContactListStoreCol; + +struct _EmpathyContactListStore { + GtkTreeStore parent; +}; + +struct _EmpathyContactListStoreClass { + GtkTreeStoreClass parent_class; +}; +typedef GList * (*EmpathyContactGroupsFunc) (EmpathyContact *contact, + gpointer user_data); + +GType empathy_contact_list_store_get_type (void) G_GNUC_CONST; +EmpathyContactListStore * empathy_contact_list_store_new (EmpathyContactList *list_iface); +EmpathyContactList * empathy_contact_list_store_get_list_iface (EmpathyContactListStore *store); +gboolean empathy_contact_list_store_get_show_offline (EmpathyContactListStore *store); +void empathy_contact_list_store_set_show_offline (EmpathyContactListStore *store, + gboolean show_offline); +gboolean empathy_contact_list_store_get_show_avatars (EmpathyContactListStore *store); +void empathy_contact_list_store_set_show_avatars (EmpathyContactListStore *store, + gboolean show_avatars); +gboolean empathy_contact_list_store_get_is_compact (EmpathyContactListStore *store); +void empathy_contact_list_store_set_is_compact (EmpathyContactListStore *store, + gboolean is_compact); +EmpathyContactListStoreSort empathy_contact_list_store_get_sort_criterium (EmpathyContactListStore *store); +void empathy_contact_list_store_set_sort_criterium (EmpathyContactListStore *store, + EmpathyContactListStoreSort sort_criterium); +gboolean empathy_contact_list_store_row_separator_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data); +gchar * empathy_contact_list_store_get_parent_group (GtkTreeModel *model, + GtkTreePath *path, + gboolean *path_is_group); +gboolean empathy_contact_list_store_search_equal_func (GtkTreeModel *model, + gint column, + const gchar *key, + GtkTreeIter *iter, + gpointer search_data); +void empathy_contact_list_store_set_contact_groups_func (EmpathyContactListStore*store, + EmpathyContactGroupsFunc func, + gpointer user_data); +void empathy_contact_list_store_update_contact_groups (EmpathyContactListStore *store, + EmpathyContact *contact); + +G_END_DECLS + +#endif /* __EMPATHY_CONTACT_LIST_STORE_H__ */ + diff --git a/libempathy-gtk/empathy-contact-list-view.c b/libempathy-gtk/empathy-contact-list-view.c new file mode 100644 index 00000000..2a5cf340 --- /dev/null +++ b/libempathy-gtk/empathy-contact-list-view.c @@ -0,0 +1,1524 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2005-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Martyn Russell + * Xavier Claessens + */ + +#include "config.h" + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "empathy-contact-list-view.h" +#include "empathy-contact-list-store.h" +#include "empathy-images.h" +#include "empathy-contact-groups.h" +#include "empathy-cell-renderer-expander.h" +#include "empathy-cell-renderer-text.h" +#include "empathy-ui-utils.h" +#include "empathy-contact-dialogs.h" +//#include "empathy-chat-invite.h" +//#include "empathy-ft-window.h" +#include "empathy-log-window.h" + +#define DEBUG_DOMAIN "ContactListView" + +/* Flashing delay for icons (milliseconds). */ +#define FLASH_TIMEOUT 500 + +/* Active users are those which have recently changed state + * (e.g. online, offline or from normal to a busy state). + */ + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CONTACT_LIST_VIEW, EmpathyContactListViewPriv)) + +struct _EmpathyContactListViewPriv { + EmpathyContactListStore *store; + GtkUIManager *ui; + GtkTreeRowReference *drag_row; + GtkTreeModel *filter; + gchar *filter_text; + + EmpathyContactListViewDragReceivedFunc drag_received; + gpointer drag_received_data; +}; + +typedef struct { + EmpathyContactListView *view; + GtkTreePath *path; + guint timeout_id; +} DragMotionData; + +typedef struct { + EmpathyContactListView *view; + EmpathyContact *contact; + gboolean remove; +} ShowActiveData; + +static void empathy_contact_list_view_class_init (EmpathyContactListViewClass *klass); +static void empathy_contact_list_view_init (EmpathyContactListView *list); +static void contact_list_view_finalize (GObject *object); +static void contact_list_view_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); +static void contact_list_view_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void contact_list_view_setup (EmpathyContactListView *view); +static void contact_list_view_row_has_child_toggled_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + EmpathyContactListView *view); +static void contact_list_view_contact_received (EmpathyContactListView *view, + EmpathyContact *contact, + GdkDragAction action, + const gchar *old_group, + const gchar *new_group); +static void contact_list_view_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection, + guint info, + guint time); +static gboolean contact_list_view_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time); +static gboolean contact_list_view_drag_motion_cb (DragMotionData *data); +static void contact_list_view_drag_begin (GtkWidget *widget, + GdkDragContext *context); +static void contact_list_view_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection, + guint info, + guint time); +static void contact_list_view_drag_end (GtkWidget *widget, + GdkDragContext *context); +static gboolean contact_list_view_drag_drop (GtkWidget *widget, + GdkDragContext *drag_context, + gint x, + gint y, + guint time); +static void contact_list_view_cell_set_background (EmpathyContactListView *view, + GtkCellRenderer *cell, + gboolean is_group, + gboolean is_active); +static void contact_list_view_pixbuf_cell_data_func (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + EmpathyContactListView *view); +static void contact_list_view_avatar_cell_data_func (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + EmpathyContactListView *view); +static void contact_list_view_text_cell_data_func (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + EmpathyContactListView *view); +static void contact_list_view_expander_cell_data_func (GtkTreeViewColumn *column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + EmpathyContactListView *view); +static GtkWidget * contact_list_view_get_contact_menu (EmpathyContactListView *view, + gboolean can_send_file, + gboolean can_show_log); +static gboolean contact_list_view_button_press_event_cb (EmpathyContactListView *view, + GdkEventButton *event, + gpointer user_data); +static void contact_list_view_row_activated_cb (EmpathyContactListView *view, + GtkTreePath *path, + GtkTreeViewColumn *col, + gpointer user_data); +static void contact_list_view_row_expand_or_collapse_cb (EmpathyContactListView *view, + GtkTreeIter *iter, + GtkTreePath *path, + gpointer user_data); +static gboolean contact_list_view_filter_show_contact (EmpathyContact *contact, + const gchar *filter); +static gboolean contact_list_view_filter_show_group (EmpathyContactListView *view, + const gchar *group, + const gchar *filter); +static gboolean contact_list_view_filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + EmpathyContactListView *view); +static void contact_list_view_action_cb (GtkAction *action, + EmpathyContactListView *view); +static void contact_list_view_action_activated (EmpathyContactListView *view, + EmpathyContact *contact); + +enum { + PROP_0, + PROP_FILTER, +}; + +static const GtkActionEntry entries[] = { + { "ContactMenu", NULL, + N_("_Contact"), NULL, NULL, + NULL + }, + { "GroupMenu", NULL, + N_("_Group"),NULL, NULL, + NULL + }, + { "Chat", EMPATHY_IMAGE_MESSAGE, + N_("_Chat"), NULL, N_("Chat with contact"), + G_CALLBACK (contact_list_view_action_cb) + }, + { "Information", EMPATHY_IMAGE_CONTACT_INFORMATION, + N_("Infor_mation"), "I", N_("View contact information"), + G_CALLBACK (contact_list_view_action_cb) + }, + { "Rename", NULL, + N_("Re_name"), NULL, N_("Rename"), + G_CALLBACK (contact_list_view_action_cb) + }, + { "Edit", GTK_STOCK_EDIT, + N_("_Edit"), NULL, N_("Edit the groups and name for this contact"), + G_CALLBACK (contact_list_view_action_cb) + }, + { "Remove", GTK_STOCK_REMOVE, + N_("_Remove"), NULL, N_("Remove contact"), + G_CALLBACK (contact_list_view_action_cb) + }, + { "Invite", EMPATHY_IMAGE_GROUP_MESSAGE, + N_("_Invite to Chat Room"), NULL, N_("Invite to a currently open chat room"), + G_CALLBACK (contact_list_view_action_cb) + }, + { "SendFile", NULL, + N_("_Send File..."), NULL, N_("Send a file"), + G_CALLBACK (contact_list_view_action_cb) + }, + { "Log", GTK_STOCK_JUSTIFY_LEFT, + N_("_View Previous Conversations"), NULL, N_("View previous conversations with this contact"), + G_CALLBACK (contact_list_view_action_cb) + }, +}; + +static guint n_entries = G_N_ELEMENTS (entries); + +static const gchar *ui_info = + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + +enum DndDragType { + DND_DRAG_TYPE_CONTACT_ID, + DND_DRAG_TYPE_URL, + DND_DRAG_TYPE_STRING, +}; + +static const GtkTargetEntry drag_types_dest[] = { + { "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID }, + { "text/uri-list", 0, DND_DRAG_TYPE_URL }, + { "text/plain", 0, DND_DRAG_TYPE_STRING }, + { "STRING", 0, DND_DRAG_TYPE_STRING }, +}; + +static const GtkTargetEntry drag_types_source[] = { + { "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID }, +}; + +static GdkAtom drag_atoms_dest[G_N_ELEMENTS (drag_types_dest)]; +static GdkAtom drag_atoms_source[G_N_ELEMENTS (drag_types_source)]; + +enum { + DRAG_CONTACT_RECEIVED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +G_DEFINE_TYPE (EmpathyContactListView, empathy_contact_list_view, GTK_TYPE_TREE_VIEW); + +static void +empathy_contact_list_view_class_init (EmpathyContactListViewClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->finalize = contact_list_view_finalize; + object_class->get_property = contact_list_view_get_property; + object_class->set_property = contact_list_view_set_property; + + widget_class->drag_data_received = contact_list_view_drag_data_received; + widget_class->drag_drop = contact_list_view_drag_drop; + widget_class->drag_begin = contact_list_view_drag_begin; + widget_class->drag_data_get = contact_list_view_drag_data_get; + widget_class->drag_end = contact_list_view_drag_end; + /* FIXME: noticed but when you drag the row over the treeview + * fast, it seems to stop redrawing itself, if we don't + * connect this signal, all is fine. + */ + widget_class->drag_motion = contact_list_view_drag_motion; + + signals[DRAG_CONTACT_RECEIVED] = + g_signal_new ("drag-contact-received", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + empathy_marshal_VOID__OBJECT_STRING_STRING, + G_TYPE_NONE, + 3, EMPATHY_TYPE_CONTACT, G_TYPE_STRING, G_TYPE_STRING); + + g_object_class_install_property (object_class, + PROP_FILTER, + g_param_spec_string ("filter", + "Filter", + "The text to use to filter the contact list", + NULL, + G_PARAM_READWRITE)); + + g_type_class_add_private (object_class, sizeof (EmpathyContactListViewPriv)); +} + +static void +empathy_contact_list_view_init (EmpathyContactListView *view) +{ + EmpathyContactListViewPriv *priv; + GtkActionGroup *action_group; + GError *error = NULL; + + priv = GET_PRIV (view); + + /* Get saved group states. */ + empathy_contact_groups_get_all (); + + /* Set up UI Manager */ + priv->ui = gtk_ui_manager_new (); + + action_group = gtk_action_group_new ("Actions"); + gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE); + gtk_action_group_add_actions (action_group, entries, n_entries, view); + gtk_ui_manager_insert_action_group (priv->ui, action_group, 0); + + if (!gtk_ui_manager_add_ui_from_string (priv->ui, ui_info, -1, &error)) { + g_warning ("Could not build contact menus from string:'%s'", error->message); + g_error_free (error); + } + + g_object_unref (action_group); + + gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (view), + empathy_contact_list_store_row_separator_func, + NULL, NULL); + + /* Connect to tree view signals rather than override. */ + g_signal_connect (view, + "button-press-event", + G_CALLBACK (contact_list_view_button_press_event_cb), + NULL); + g_signal_connect (view, + "row-activated", + G_CALLBACK (contact_list_view_row_activated_cb), + NULL); + g_signal_connect (view, + "row-expanded", + G_CALLBACK (contact_list_view_row_expand_or_collapse_cb), + GINT_TO_POINTER (TRUE)); + g_signal_connect (view, + "row-collapsed", + G_CALLBACK (contact_list_view_row_expand_or_collapse_cb), + GINT_TO_POINTER (FALSE)); +} + +static void +contact_list_view_finalize (GObject *object) +{ + EmpathyContactListViewPriv *priv; + + priv = GET_PRIV (object); + + if (priv->ui) { + g_object_unref (priv->ui); + } + if (priv->store) { + g_object_unref (priv->store); + } + if (priv->filter) { + g_object_unref (priv->filter); + } + g_free (priv->filter_text); + + G_OBJECT_CLASS (empathy_contact_list_view_parent_class)->finalize (object); +} + +static void +contact_list_view_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + EmpathyContactListViewPriv *priv; + + priv = GET_PRIV (object); + + switch (param_id) { + case PROP_FILTER: + g_value_set_string (value, priv->filter_text); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + }; +} + +static void +contact_list_view_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + EmpathyContactListViewPriv *priv; + + priv = GET_PRIV (object); + + switch (param_id) { + case PROP_FILTER: + empathy_contact_list_view_set_filter (EMPATHY_CONTACT_LIST_VIEW (object), + g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + }; +} + +EmpathyContactListView * +empathy_contact_list_view_new (EmpathyContactListStore *store) +{ + EmpathyContactListViewPriv *priv; + EmpathyContactListView *view; + + view = g_object_new (EMPATHY_TYPE_CONTACT_LIST_VIEW, NULL); + priv = GET_PRIV (view); + + priv->store = g_object_ref (store); + contact_list_view_setup (view); + + return view; +} + +EmpathyContact * +empathy_contact_list_view_get_selected (EmpathyContactListView *view) +{ + EmpathyContactListViewPriv *priv; + GtkTreeSelection *selection; + GtkTreeIter iter; + GtkTreeModel *model; + EmpathyContact *contact; + + g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view), NULL); + + priv = GET_PRIV (view); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { + return NULL; + } + + gtk_tree_model_get (model, &iter, COL_CONTACT, &contact, -1); + + return contact; +} + +gchar * +empathy_contact_list_view_get_selected_group (EmpathyContactListView *view) +{ + EmpathyContactListViewPriv *priv; + GtkTreeSelection *selection; + GtkTreeIter iter; + GtkTreeModel *model; + gboolean is_group; + gchar *name; + + g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view), NULL); + + priv = GET_PRIV (view); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { + return NULL; + } + + gtk_tree_model_get (model, &iter, + COL_IS_GROUP, &is_group, + COL_NAME, &name, + -1); + + if (!is_group) { + g_free (name); + return NULL; + } + + return name; +} + +GtkWidget * +empathy_contact_list_view_get_group_menu (EmpathyContactListView *view) +{ + EmpathyContactListViewPriv *priv; + GtkWidget *widget; + + g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view), NULL); + + priv = GET_PRIV (view); + + widget = gtk_ui_manager_get_widget (priv->ui, "/Group"); + + return widget; +} + +GtkWidget * +empathy_contact_list_view_get_contact_menu (EmpathyContactListView *view, + EmpathyContact *contact) +{ + EmpathyLogManager *log_manager; + gboolean can_show_log; + gboolean can_send_file; + + g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view), NULL); + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + + log_manager = empathy_log_manager_new (); + can_show_log = empathy_log_manager_exists (log_manager, + empathy_contact_get_account (contact), + empathy_contact_get_id (contact), + FALSE); + can_send_file = FALSE; + g_object_unref (log_manager); + + return contact_list_view_get_contact_menu (view, + can_send_file, + can_show_log); +} + +void +empathy_contact_list_view_set_filter (EmpathyContactListView *view, + const gchar *filter) +{ + EmpathyContactListViewPriv *priv; + + g_return_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view)); + + priv = GET_PRIV (view); + + g_free (priv->filter_text); + if (filter) { + priv->filter_text = g_utf8_casefold (filter, -1); + } else { + priv->filter_text = NULL; + } + + empathy_debug (DEBUG_DOMAIN, "Refiltering with filter:'%s' (case folded)", filter); + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter)); +} + +void +empathy_contact_list_view_set_drag_received_func (EmpathyContactListView *view, + EmpathyContactListViewDragReceivedFunc func, + gpointer user_data) +{ + EmpathyContactListViewPriv *priv; + + g_return_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view)); + + priv = GET_PRIV (view); + + if (func) { + priv->drag_received = func; + priv->drag_received_data = user_data; + } else { + priv->drag_received = NULL; + priv->drag_received_data = NULL; + } +} + +static void +contact_list_view_setup (EmpathyContactListView *view) +{ + EmpathyContactListViewPriv *priv; + GtkCellRenderer *cell; + GtkTreeViewColumn *col; + gint i; + + priv = GET_PRIV (view); + + /* Create filter */ + priv->filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (priv->store), NULL); + + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (priv->filter), + (GtkTreeModelFilterVisibleFunc) + contact_list_view_filter_func, + view, NULL); + gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (view), + empathy_contact_list_store_search_equal_func, + view, NULL); + g_signal_connect (priv->filter, "row-has-child-toggled", + G_CALLBACK (contact_list_view_row_has_child_toggled_cb), + view); + gtk_tree_view_set_model (GTK_TREE_VIEW (view), priv->filter); + + + /* Setup view */ + g_object_set (view, + "headers-visible", FALSE, + "reorderable", TRUE, + "show-expanders", FALSE, + NULL); + + col = gtk_tree_view_column_new (); + + /* State */ + cell = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (col, cell, FALSE); + gtk_tree_view_column_set_cell_data_func ( + col, cell, + (GtkTreeCellDataFunc) contact_list_view_pixbuf_cell_data_func, + view, NULL); + + g_object_set (cell, + "xpad", 5, + "ypad", 1, + "visible", FALSE, + NULL); + + /* Name */ + cell = empathy_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (col, cell, TRUE); + gtk_tree_view_column_set_cell_data_func ( + col, cell, + (GtkTreeCellDataFunc) contact_list_view_text_cell_data_func, + view, NULL); + + gtk_tree_view_column_add_attribute (col, cell, + "name", COL_NAME); + gtk_tree_view_column_add_attribute (col, cell, + "status", COL_STATUS); + gtk_tree_view_column_add_attribute (col, cell, + "is_group", COL_IS_GROUP); + + /* Avatar */ + cell = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (col, cell, FALSE); + gtk_tree_view_column_set_cell_data_func ( + col, cell, + (GtkTreeCellDataFunc) contact_list_view_avatar_cell_data_func, + view, NULL); + + g_object_set (cell, + "xpad", 0, + "ypad", 0, + "visible", FALSE, + "width", 32, + "height", 32, + NULL); + + /* Expander */ + cell = empathy_cell_renderer_expander_new (); + gtk_tree_view_column_pack_end (col, cell, FALSE); + gtk_tree_view_column_set_cell_data_func ( + col, cell, + (GtkTreeCellDataFunc) contact_list_view_expander_cell_data_func, + view, NULL); + + /* Actually add the column now we have added all cell renderers */ + gtk_tree_view_append_column (GTK_TREE_VIEW (view), col); + + /* Drag & Drop. */ + for (i = 0; i < G_N_ELEMENTS (drag_types_dest); ++i) { + drag_atoms_dest[i] = gdk_atom_intern (drag_types_dest[i].target, + FALSE); + } + + for (i = 0; i < G_N_ELEMENTS (drag_types_source); ++i) { + drag_atoms_source[i] = gdk_atom_intern (drag_types_source[i].target, + FALSE); + } + + /* Note: We support the COPY action too, but need to make the + * MOVE action the default. + */ + gtk_drag_source_set (GTK_WIDGET (view), + GDK_BUTTON1_MASK, + drag_types_source, + G_N_ELEMENTS (drag_types_source), + GDK_ACTION_MOVE); + + gtk_drag_dest_set (GTK_WIDGET (view), + GTK_DEST_DEFAULT_ALL, + drag_types_dest, + G_N_ELEMENTS (drag_types_dest), + GDK_ACTION_MOVE | GDK_ACTION_LINK); +} + +static void +contact_list_view_row_has_child_toggled_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + EmpathyContactListView *view) +{ + gboolean is_group = FALSE; + gchar *name = NULL; + + gtk_tree_model_get (model, iter, + COL_IS_GROUP, &is_group, + COL_NAME, &name, + -1); + + if (!is_group || G_STR_EMPTY (name)) { + g_free (name); + return; + } + + if (empathy_contact_group_get_expanded (name)) { + g_signal_handlers_block_by_func (view, + contact_list_view_row_expand_or_collapse_cb, + GINT_TO_POINTER (TRUE)); + gtk_tree_view_expand_row (GTK_TREE_VIEW (view), path, TRUE); + g_signal_handlers_unblock_by_func (view, + contact_list_view_row_expand_or_collapse_cb, + GINT_TO_POINTER (TRUE)); + } else { + g_signal_handlers_block_by_func (view, + contact_list_view_row_expand_or_collapse_cb, + GINT_TO_POINTER (FALSE)); + gtk_tree_view_collapse_row (GTK_TREE_VIEW (view), path); + g_signal_handlers_unblock_by_func (view, + contact_list_view_row_expand_or_collapse_cb, + GINT_TO_POINTER (FALSE)); + } + + g_free (name); +} + +static void +contact_list_view_contact_received (EmpathyContactListView *view, + EmpathyContact *contact, + GdkDragAction action, + const gchar *old_group, + const gchar *new_group) +{ + EmpathyContactListViewPriv *priv; + GList *groups, *l; + GList *new_groups_list = NULL; + + priv = GET_PRIV (view); + + groups = empathy_contact_get_groups (contact); + for (l = groups; l; l = l->next) { + gchar *str; + + str = l->data; + + if (action == GDK_ACTION_MOVE && + old_group != NULL && + strcmp (str, old_group) == 0) { + continue; + } + + if (new_group && strcmp (str, new_group) == 0) { + /* Otherwise we set it twice */ + continue; + } + + new_groups_list = g_list_prepend (new_groups_list, g_strdup (str)); + } + + if (new_group) { + new_groups_list = g_list_prepend (new_groups_list, g_strdup (new_group)); + } + + empathy_contact_set_groups (contact, new_groups_list); +} + +static void +contact_list_view_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection, + guint info, + guint time) +{ + EmpathyContactListViewPriv *priv; + EmpathyContactList *list; + GtkTreeModel *model; + GtkTreePath *path; + GtkTreeViewDropPosition position; + EmpathyContact *contact; + const gchar *id; + gchar *new_group = NULL; + gchar *old_group = NULL; + gboolean is_row; + + priv = GET_PRIV (widget); + + id = (const gchar*) selection->data; + empathy_debug (DEBUG_DOMAIN, "Received %s%s drag & drop contact from roster with id:'%s'", + context->action == GDK_ACTION_MOVE ? "move" : "", + context->action == GDK_ACTION_COPY ? "copy" : "", + id); + + /* FIXME: This is ambigous, an id can come from multiple accounts */ + list = empathy_contact_list_store_get_list_iface (priv->store); + contact = empathy_contact_list_find (list, id); + + if (!contact) { + empathy_debug (DEBUG_DOMAIN, "No contact found associated with drag & drop"); + return; + } + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); + + /* Get source group information. */ + if (priv->drag_row) { + path = gtk_tree_row_reference_get_path (priv->drag_row); + if (path) { + old_group = empathy_contact_list_store_get_parent_group (model, path, NULL); + gtk_tree_path_free (path); + } + } + + /* Get destination group information. */ + is_row = gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget), + x, + y, + &path, + &position); + + if (is_row) { + new_group = empathy_contact_list_store_get_parent_group (model, path, NULL); + gtk_tree_path_free (path); + } + + empathy_debug (DEBUG_DOMAIN, + "contact '%s' dragged from '%s' to '%s'", + empathy_contact_get_name (contact), + old_group, new_group); + + if (priv->drag_received) { + priv->drag_received (contact, + context->action, + old_group, + new_group, + priv->drag_received_data); + } else { + contact_list_view_contact_received (EMPATHY_CONTACT_LIST_VIEW (widget), + contact, + context->action, + old_group, + new_group); + } + + g_free (old_group); + g_free (new_group); + + gtk_drag_finish (context, TRUE, FALSE, GDK_CURRENT_TIME); +} + +static gboolean +contact_list_view_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time) +{ + static DragMotionData *dm = NULL; + GtkTreePath *path; + gboolean is_row; + gboolean is_different = FALSE; + gboolean cleanup = TRUE; + + is_row = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), + x, + y, + &path, + NULL, + NULL, + NULL); + + cleanup &= (!dm); + + if (is_row) { + cleanup &= (dm && gtk_tree_path_compare (dm->path, path) != 0); + is_different = (!dm || (dm && gtk_tree_path_compare (dm->path, path) != 0)); + } else { + cleanup &= FALSE; + } + + if (!is_different && !cleanup) { + return TRUE; + } + + if (dm) { + gtk_tree_path_free (dm->path); + if (dm->timeout_id) { + g_source_remove (dm->timeout_id); + } + + g_free (dm); + + dm = NULL; + } + + if (!gtk_tree_view_row_expanded (GTK_TREE_VIEW (widget), path)) { + dm = g_new0 (DragMotionData, 1); + + dm->view = EMPATHY_CONTACT_LIST_VIEW (widget); + dm->path = gtk_tree_path_copy (path); + + dm->timeout_id = g_timeout_add ( + 1500, + (GSourceFunc) contact_list_view_drag_motion_cb, + dm); + } + + return TRUE; +} + +static gboolean +contact_list_view_drag_motion_cb (DragMotionData *data) +{ + gtk_tree_view_expand_row (GTK_TREE_VIEW (data->view), + data->path, + FALSE); + + data->timeout_id = 0; + + return FALSE; +} + +static void +contact_list_view_drag_begin (GtkWidget *widget, + GdkDragContext *context) +{ + EmpathyContactListViewPriv *priv; + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreePath *path; + GtkTreeIter iter; + + priv = GET_PRIV (widget); + + GTK_WIDGET_CLASS (empathy_contact_list_view_parent_class)->drag_begin (widget, + context); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { + return; + } + + path = gtk_tree_model_get_path (model, &iter); + priv->drag_row = gtk_tree_row_reference_new (model, path); + gtk_tree_path_free (path); +} + +static void +contact_list_view_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection, + guint info, + guint time) +{ + EmpathyContactListViewPriv *priv; + GtkTreePath *src_path; + GtkTreeIter iter; + GtkTreeModel *model; + EmpathyContact *contact; + const gchar *id; + + priv = GET_PRIV (widget); + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); + if (!priv->drag_row) { + return; + } + + src_path = gtk_tree_row_reference_get_path (priv->drag_row); + if (!src_path) { + return; + } + + if (!gtk_tree_model_get_iter (model, &iter, src_path)) { + gtk_tree_path_free (src_path); + return; + } + + gtk_tree_path_free (src_path); + + contact = empathy_contact_list_view_get_selected (EMPATHY_CONTACT_LIST_VIEW (widget)); + if (!contact) { + return; + } + + id = empathy_contact_get_id (contact); + g_object_unref (contact); + + switch (info) { + case DND_DRAG_TYPE_CONTACT_ID: + gtk_selection_data_set (selection, drag_atoms_source[info], 8, + (guchar*)id, strlen (id) + 1); + break; + + default: + return; + } +} + +static void +contact_list_view_drag_end (GtkWidget *widget, + GdkDragContext *context) +{ + EmpathyContactListViewPriv *priv; + + priv = GET_PRIV (widget); + + GTK_WIDGET_CLASS (empathy_contact_list_view_parent_class)->drag_end (widget, + context); + + if (priv->drag_row) { + gtk_tree_row_reference_free (priv->drag_row); + priv->drag_row = NULL; + } +} + +static gboolean +contact_list_view_drag_drop (GtkWidget *widget, + GdkDragContext *drag_context, + gint x, + gint y, + guint time) +{ + return FALSE; +} + +static void +contact_list_view_cell_set_background (EmpathyContactListView *view, + GtkCellRenderer *cell, + gboolean is_group, + gboolean is_active) +{ + GdkColor color; + GtkStyle *style; + + style = gtk_widget_get_style (GTK_WIDGET (view)); + + if (!is_group) { + if (is_active) { + color = style->bg[GTK_STATE_SELECTED]; + + /* Here we take the current theme colour and add it to + * the colour for white and average the two. This + * gives a colour which is inline with the theme but + * slightly whiter. + */ + color.red = (color.red + (style->white).red) / 2; + color.green = (color.green + (style->white).green) / 2; + color.blue = (color.blue + (style->white).blue) / 2; + + g_object_set (cell, + "cell-background-gdk", &color, + NULL); + } else { + g_object_set (cell, + "cell-background-gdk", NULL, + NULL); + } + } else { + g_object_set (cell, + "cell-background-gdk", NULL, + NULL); + } +} + +static void +contact_list_view_pixbuf_cell_data_func (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + EmpathyContactListView *view) +{ + gchar *icon_name; + gboolean is_group; + gboolean is_active; + + gtk_tree_model_get (model, iter, + COL_IS_GROUP, &is_group, + COL_IS_ACTIVE, &is_active, + COL_ICON_STATUS, &icon_name, + -1); + + g_object_set (cell, + "visible", !is_group, + "icon-name", icon_name, + NULL); + + g_free (icon_name); + + contact_list_view_cell_set_background (view, cell, is_group, is_active); +} + +static void +contact_list_view_avatar_cell_data_func (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + EmpathyContactListView *view) +{ + GdkPixbuf *pixbuf; + gboolean show_avatar; + gboolean is_group; + gboolean is_active; + + gtk_tree_model_get (model, iter, + COL_PIXBUF_AVATAR, &pixbuf, + COL_PIXBUF_AVATAR_VISIBLE, &show_avatar, + COL_IS_GROUP, &is_group, + COL_IS_ACTIVE, &is_active, + -1); + + g_object_set (cell, + "visible", !is_group && show_avatar, + "pixbuf", pixbuf, + NULL); + + if (pixbuf) { + g_object_unref (pixbuf); + } + + contact_list_view_cell_set_background (view, cell, is_group, is_active); +} + +static void +contact_list_view_text_cell_data_func (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + EmpathyContactListView *view) +{ + gboolean is_group; + gboolean is_active; + gboolean show_status; + + gtk_tree_model_get (model, iter, + COL_IS_GROUP, &is_group, + COL_IS_ACTIVE, &is_active, + COL_STATUS_VISIBLE, &show_status, + -1); + + g_object_set (cell, + "show-status", show_status, + NULL); + + contact_list_view_cell_set_background (view, cell, is_group, is_active); +} + +static void +contact_list_view_expander_cell_data_func (GtkTreeViewColumn *column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + EmpathyContactListView *view) +{ + gboolean is_group; + gboolean is_active; + + gtk_tree_model_get (model, iter, + COL_IS_GROUP, &is_group, + COL_IS_ACTIVE, &is_active, + -1); + + if (gtk_tree_model_iter_has_child (model, iter)) { + GtkTreePath *path; + gboolean row_expanded; + + path = gtk_tree_model_get_path (model, iter); + row_expanded = gtk_tree_view_row_expanded (GTK_TREE_VIEW (column->tree_view), path); + gtk_tree_path_free (path); + + g_object_set (cell, + "visible", TRUE, + "expander-style", row_expanded ? GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED, + NULL); + } else { + g_object_set (cell, "visible", FALSE, NULL); + } + + contact_list_view_cell_set_background (view, cell, is_group, is_active); +} + +static GtkWidget * +contact_list_view_get_contact_menu (EmpathyContactListView *view, + gboolean can_send_file, + gboolean can_show_log) +{ + EmpathyContactListViewPriv *priv; + GtkAction *action; + GtkWidget *widget; + + priv = GET_PRIV (view); + + /* Sort out sensitive items */ + action = gtk_ui_manager_get_action (priv->ui, "/Contact/Log"); + gtk_action_set_sensitive (action, can_show_log); + + action = gtk_ui_manager_get_action (priv->ui, "/Contact/SendFile"); + gtk_action_set_visible (action, can_send_file); + + widget = gtk_ui_manager_get_widget (priv->ui, "/Contact"); + + return widget; +} + +static gboolean +contact_list_view_button_press_event_cb (EmpathyContactListView *view, + GdkEventButton *event, + gpointer user_data) +{ + EmpathyContactListViewPriv *priv; + EmpathyContact *contact; + GtkTreePath *path; + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + gboolean row_exists; + GtkWidget *menu; + + if (event->button != 3) { + return FALSE; + } + + priv = GET_PRIV (view); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); + + gtk_widget_grab_focus (GTK_WIDGET (view)); + + row_exists = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (view), + event->x, event->y, + &path, + NULL, NULL, NULL); + if (!row_exists) { + return FALSE; + } + + gtk_tree_selection_unselect_all (selection); + gtk_tree_selection_select_path (selection, path); + + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_path_free (path); + + gtk_tree_model_get (model, &iter, COL_CONTACT, &contact, -1); + + if (contact) { + menu = empathy_contact_list_view_get_contact_menu (view, contact); + g_object_unref (contact); + } else { + menu = empathy_contact_list_view_get_group_menu (view); + } + + if (!menu) { + return FALSE; + } + + gtk_widget_show (menu); + + gtk_menu_popup (GTK_MENU (menu), + NULL, NULL, NULL, NULL, + event->button, event->time); + + return TRUE; +} + +static void +contact_list_view_row_activated_cb (EmpathyContactListView *view, + GtkTreePath *path, + GtkTreeViewColumn *col, + gpointer user_data) +{ + EmpathyContact *contact; + GtkTreeModel *model; + GtkTreeIter iter; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); + + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get (model, &iter, COL_CONTACT, &contact, -1); + + if (contact) { + contact_list_view_action_activated (view, contact); + g_object_unref (contact); + } +} + +static void +contact_list_view_row_expand_or_collapse_cb (EmpathyContactListView *view, + GtkTreeIter *iter, + GtkTreePath *path, + gpointer user_data) +{ + GtkTreeModel *model; + gchar *name; + gboolean expanded; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); + + gtk_tree_model_get (model, iter, + COL_NAME, &name, + -1); + + expanded = GPOINTER_TO_INT (user_data); + empathy_contact_group_set_expanded (name, expanded); + + g_free (name); +} + +static gboolean +contact_list_view_filter_show_contact (EmpathyContact *contact, + const gchar *filter) +{ + gchar *str; + gboolean visible; + + /* Check contact id */ + str = g_utf8_casefold (empathy_contact_get_id (contact), -1); + visible = G_STR_EMPTY (str) || strstr (str, filter); + g_free (str); + + if (visible) { + return TRUE; + } + + /* Check contact name */ + str = g_utf8_casefold (empathy_contact_get_name (contact), -1); + visible = G_STR_EMPTY (str) || strstr (str, filter); + g_free (str); + + return visible; +} + +static gboolean +contact_list_view_filter_show_group (EmpathyContactListView *view, + const gchar *group, + const gchar *filter) +{ + EmpathyContactListViewPriv *priv; + EmpathyContactList *list; + GList *contacts, *l; + gchar *str; + gboolean show_group = FALSE; + + priv = GET_PRIV (view); + + str = g_utf8_casefold (group, -1); + if (!str) { + return FALSE; + } + + /* If the filter is the partially the group name, we show the + * whole group. + */ + if (strstr (str, filter)) { + g_free (str); + return TRUE; + } + + /* At this point, we need to check in advance if this + * group should be shown because a contact we want to + * show exists in it. + */ + list = empathy_contact_list_store_get_list_iface (priv->store); + contacts = empathy_contact_list_get_members (list); + for (l = contacts; l && !show_group; l = l->next) { + if (!empathy_contact_is_in_group (l->data, group)) { + g_object_unref (l->data); + continue; + } + + if (contact_list_view_filter_show_contact (l->data, filter)) { + show_group = TRUE; + } + g_object_unref (l->data); + } + g_list_free (contacts); + g_free (str); + + return show_group; +} + +static gboolean +contact_list_view_filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + EmpathyContactListView *view) +{ + EmpathyContactListViewPriv *priv; + gboolean is_group; + gboolean is_separator; + gboolean visible = TRUE; + + priv = GET_PRIV (view); + + if (G_STR_EMPTY (priv->filter_text)) { + return TRUE; + } + + /* Check to see if iter matches any group names */ + gtk_tree_model_get (model, iter, + COL_IS_GROUP, &is_group, + COL_IS_SEPARATOR, &is_separator, + -1); + + if (is_group) { + gchar *name; + + gtk_tree_model_get (model, iter, COL_NAME, &name, -1); + visible &= contact_list_view_filter_show_group (view, + name, + priv->filter_text); + g_free (name); + } else if (is_separator) { + /* Do nothing here */ + } else { + EmpathyContact *contact; + + /* Check contact id */ + gtk_tree_model_get (model, iter, COL_CONTACT, &contact, -1); + visible &= contact_list_view_filter_show_contact (contact, + priv->filter_text); + g_object_unref (contact); + } + + return visible; +} + +static void +contact_list_view_action_cb (GtkAction *action, + EmpathyContactListView *view) +{ + EmpathyContactListViewPriv *priv; + EmpathyContact *contact; + const gchar *name; + gchar *group; + GtkWindow *parent; + + priv = GET_PRIV (view); + + name = gtk_action_get_name (action); + if (!name) { + return; + } + + empathy_debug (DEBUG_DOMAIN, "Action:'%s' activated", name); + + contact = empathy_contact_list_view_get_selected (view); + group = empathy_contact_list_view_get_selected_group (view); + parent = empathy_get_toplevel_window (GTK_WIDGET (view)); + + if (contact && strcmp (name, "Chat") == 0) { + contact_list_view_action_activated (view, contact); + } + else if (contact && strcmp (name, "Information") == 0) { + empathy_contact_information_dialog_show (contact, parent, FALSE); + } + else if (contact && strcmp (name, "Edit") == 0) { + empathy_contact_information_dialog_show (contact, parent, TRUE); + } + else if (contact && strcmp (name, "Remove") == 0) { + /* FIXME: Ask for confirmation */ + EmpathyContactList *list; + + list = empathy_contact_list_store_get_list_iface (priv->store); + empathy_contact_list_remove (list, contact, + _("Sorry, I don't want you in my contact list anymore.")); + } + else if (contact && strcmp (name, "Invite") == 0) { + } + else if (contact && strcmp (name, "SendFile") == 0) { + } + else if (contact && strcmp (name, "Log") == 0) { + empathy_log_window_show (empathy_contact_get_account (contact), + empathy_contact_get_id (contact), + FALSE, + parent); + } + else if (group && strcmp (name, "Rename") == 0) { + } + + g_free (group); + if (contact) { + g_object_unref (contact); + } +} + +static void +contact_list_view_action_activated (EmpathyContactListView *view, + EmpathyContact *contact) +{ + MissionControl *mc; + + mc = empathy_mission_control_new (); + mission_control_request_channel (mc, + empathy_contact_get_account (contact), + TP_IFACE_CHANNEL_TYPE_TEXT, + empathy_contact_get_handle (contact), + TP_HANDLE_TYPE_CONTACT, + NULL, NULL); + g_object_unref (mc); +} + diff --git a/libempathy-gtk/empathy-contact-list-view.h b/libempathy-gtk/empathy-contact-list-view.h new file mode 100644 index 00000000..4d7cf1cb --- /dev/null +++ b/libempathy-gtk/empathy-contact-list-view.h @@ -0,0 +1,78 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2005-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Martyn Russell + * Xavier Claessens + */ + +#ifndef __EMPATHY_CONTACT_LIST_VIEW_H__ +#define __EMPATHY_CONTACT_LIST_VIEW_H__ + +#include + +#include + +#include "empathy-contact-list-store.h" + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_CONTACT_LIST_VIEW (empathy_contact_list_view_get_type ()) +#define EMPATHY_CONTACT_LIST_VIEW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_CONTACT_LIST_VIEW, EmpathyContactListView)) +#define EMPATHY_CONTACT_LIST_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_CONTACT_LIST_VIEW, EmpathyContactListViewClass)) +#define EMPATHY_IS_CONTACT_LIST_VIEW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_CONTACT_LIST_VIEW)) +#define EMPATHY_IS_CONTACT_LIST_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_CONTACT_LIST_VIEW)) +#define EMPATHY_CONTACT_LIST_VIEW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_CONTACT_LIST_VIEW, EmpathyContactListViewClass)) + +typedef struct _EmpathyContactListView EmpathyContactListView; +typedef struct _EmpathyContactListViewClass EmpathyContactListViewClass; +typedef struct _EmpathyContactListViewPriv EmpathyContactListViewPriv; + +struct _EmpathyContactListView { + GtkTreeView parent; +}; + +struct _EmpathyContactListViewClass { + GtkTreeViewClass parent_class; +}; + +typedef void (*EmpathyContactListViewDragReceivedFunc) (EmpathyContact *contact, + GdkDragAction action, + const gchar *old_group, + const gchar *new_group, + gpointer user_data); + +GType empathy_contact_list_view_get_type (void) G_GNUC_CONST; +EmpathyContactListView *empathy_contact_list_view_new (EmpathyContactListStore *store); +EmpathyContact * empathy_contact_list_view_get_selected (EmpathyContactListView *view); +gchar * empathy_contact_list_view_get_selected_group (EmpathyContactListView *view); +GtkWidget * empathy_contact_list_view_get_contact_menu (EmpathyContactListView *view, + EmpathyContact *contact); +GtkWidget * empathy_contact_list_view_get_group_menu (EmpathyContactListView *view); +void empathy_contact_list_view_set_filter (EmpathyContactListView *view, + const gchar *filter); +void empathy_contact_list_view_set_drag_received_func (EmpathyContactListView *view, + EmpathyContactListViewDragReceivedFunc func, + gpointer user_data); + +G_END_DECLS + +#endif /* __EMPATHY_CONTACT_LIST_VIEW_H__ */ + diff --git a/libempathy-gtk/empathy-contact-widget.c b/libempathy-gtk/empathy-contact-widget.c index ac43700d..2f56a6e5 100644 --- a/libempathy-gtk/empathy-contact-widget.c +++ b/libempathy-gtk/empathy-contact-widget.c @@ -34,11 +34,11 @@ #include #include "empathy-contact-widget.h" -#include "gossip-account-chooser.h" -#include "gossip-ui-utils.h" +#include "empathy-account-chooser.h" +#include "empathy-ui-utils.h" typedef struct { - GossipContact *contact; + EmpathyContact *contact; gboolean is_user; gboolean editable; gboolean can_change_contact; @@ -89,7 +89,7 @@ static void contact_widget_destroy_cb (GtkWidget EmpathyContactWidget *information); static void contact_widget_remove_contact (EmpathyContactWidget *information); static void contact_widget_set_contact (EmpathyContactWidget *information, - GossipContact *contact); + EmpathyContact *contact); static void contact_widget_contact_setup (EmpathyContactWidget *information); static void contact_widget_contact_update (EmpathyContactWidget *information); static gboolean contact_widget_update_contact (EmpathyContactWidget *information); @@ -139,7 +139,7 @@ enum { }; GtkWidget * -empathy_contact_widget_new (GossipContact *contact, +empathy_contact_widget_new (EmpathyContact *contact, gboolean editable) { EmpathyContactWidget *information; @@ -148,14 +148,14 @@ empathy_contact_widget_new (GossipContact *contact, information = g_slice_new0 (EmpathyContactWidget); information->editable = editable; if (contact) { - information->is_user = gossip_contact_is_user (contact); + information->is_user = empathy_contact_is_user (contact); information->can_change_contact = FALSE; } else { information->is_user = FALSE; information->can_change_contact = TRUE; } - glade = gossip_glade_get_file ("empathy-contact-widget.glade", + glade = empathy_glade_get_file ("empathy-contact-widget.glade", "vbox_contact_widget", NULL, "vbox_contact_widget", &information->vbox_contact_widget, @@ -178,7 +178,7 @@ empathy_contact_widget_new (GossipContact *contact, "hbox_client_requested", &information->hbow_client_requested, NULL); - gossip_glade_connect (glade, + empathy_glade_connect (glade, information, "vbox_contact_widget", "destroy", contact_widget_destroy_cb, "entry_group", "changed", contact_widget_entry_group_changed_cb, @@ -205,7 +205,7 @@ empathy_contact_widget_new (GossipContact *contact, return information->vbox_contact_widget; } -GossipContact * +EmpathyContact * empathy_contact_widget_get_contact (GtkWidget *widget) { EmpathyContactWidget *information; @@ -252,7 +252,7 @@ contact_widget_remove_contact (EmpathyContactWidget *information) static void contact_widget_set_contact (EmpathyContactWidget *information, - GossipContact *contact) + EmpathyContact *contact) { contact_widget_remove_contact (information); if (contact) { @@ -269,7 +269,7 @@ contact_widget_set_contact (EmpathyContactWidget *information, static void contact_widget_contact_setup (EmpathyContactWidget *information) { - /* FIXME: Use GossipAvatarImage if (editable && is_user) */ + /* FIXME: Use EmpathyAvatarImage if (editable && is_user) */ information->widget_avatar = gtk_image_new (); gtk_box_pack_end (GTK_BOX (information->hbox_contact), information->widget_avatar, @@ -278,7 +278,7 @@ contact_widget_contact_setup (EmpathyContactWidget *information) /* Setup account label/chooser */ if (information->can_change_contact) { - information->widget_account = gossip_account_chooser_new (); + information->widget_account = empathy_account_chooser_new (); g_signal_connect (information->widget_account, "changed", G_CALLBACK (contact_widget_account_changed_cb), information); @@ -340,8 +340,8 @@ contact_widget_contact_update (EmpathyContactWidget *information) G_CALLBACK (contact_widget_avatar_notify_cb), information); - account = gossip_contact_get_account (information->contact); - id = gossip_contact_get_id (information->contact); + account = empathy_contact_get_account (information->contact); + id = empathy_contact_get_id (information->contact); } /* Update account widget */ @@ -350,7 +350,7 @@ contact_widget_contact_update (EmpathyContactWidget *information) g_signal_handlers_block_by_func (information->widget_account, contact_widget_account_changed_cb, information); - gossip_account_chooser_set_account (GOSSIP_ACCOUNT_CHOOSER (information->widget_account), + empathy_account_chooser_set_account (EMPATHY_ACCOUNT_CHOOSER (information->widget_account), account); g_signal_handlers_unblock_by_func (information->widget_account, contact_widget_account_changed_cb, @@ -396,12 +396,12 @@ contact_widget_update_contact (EmpathyContactWidget *information) McAccount *account; const gchar *id; - account = gossip_account_chooser_get_account (GOSSIP_ACCOUNT_CHOOSER (information->widget_account)); + account = empathy_account_chooser_get_account (EMPATHY_ACCOUNT_CHOOSER (information->widget_account)); id = gtk_entry_get_text (GTK_ENTRY (information->widget_id)); if (account && !G_STR_EMPTY (id)) { EmpathyContactManager *manager; - GossipContact *contact; + EmpathyContact *contact; manager = empathy_contact_manager_new (); contact = empathy_contact_manager_create (manager, account, id); @@ -441,7 +441,7 @@ contact_widget_entry_alias_focus_event_cb (GtkEditable *editable, const gchar *name; name = gtk_entry_get_text (GTK_ENTRY (editable)); - gossip_contact_set_name (information->contact, name); + empathy_contact_set_name (information->contact, name); } return FALSE; @@ -452,10 +452,10 @@ contact_widget_name_notify_cb (EmpathyContactWidget *information) { if (information->editable) { gtk_entry_set_text (GTK_ENTRY (information->widget_alias), - gossip_contact_get_name (information->contact)); + empathy_contact_get_name (information->contact)); } else { gtk_label_set_label (GTK_LABEL (information->widget_alias), - gossip_contact_get_name (information->contact)); + empathy_contact_get_name (information->contact)); } } @@ -463,9 +463,9 @@ static void contact_widget_presence_notify_cb (EmpathyContactWidget *information) { gtk_label_set_text (GTK_LABEL (information->label_status), - gossip_contact_get_status (information->contact)); + empathy_contact_get_status (information->contact)); gtk_image_set_from_icon_name (GTK_IMAGE (information->image_state), - gossip_icon_name_for_contact (information->contact), + empathy_icon_name_for_contact (information->contact), GTK_ICON_SIZE_BUTTON); } @@ -475,7 +475,7 @@ contact_widget_avatar_notify_cb (EmpathyContactWidget *information) { GdkPixbuf *avatar_pixbuf; - avatar_pixbuf = gossip_pixbuf_avatar_from_contact_scaled (information->contact, + avatar_pixbuf = empathy_pixbuf_avatar_from_contact_scaled (information->contact, 48, 48); if (avatar_pixbuf) { @@ -602,7 +602,7 @@ contact_widget_groups_populate_data (EmpathyContactWidget *information) manager = empathy_contact_manager_new (); all_groups = empathy_contact_manager_get_groups (manager); - my_groups = gossip_contact_get_groups (information->contact); + my_groups = empathy_contact_get_groups (information->contact); g_object_unref (manager); for (l = all_groups; l; l = l->next) { @@ -724,9 +724,9 @@ contact_widget_cell_toggled (GtkCellRendererToggle *cell, if (group) { if (enabled) { - gossip_contact_remove_group (information->contact, group); + empathy_contact_remove_group (information->contact, group); } else { - gossip_contact_add_group (information->contact, group); + empathy_contact_add_group (information->contact, group); } g_free (group); @@ -778,7 +778,7 @@ contact_widget_button_group_clicked_cb (GtkButton *button, COL_ENABLED, TRUE, -1); - gossip_contact_add_group (information->contact, group); + empathy_contact_add_group (information->contact, group); } static void diff --git a/libempathy-gtk/empathy-contact-widget.h b/libempathy-gtk/empathy-contact-widget.h index 3d33c405..f48d15e7 100644 --- a/libempathy-gtk/empathy-contact-widget.h +++ b/libempathy-gtk/empathy-contact-widget.h @@ -25,13 +25,13 @@ #include -#include +#include G_BEGIN_DECLS -GtkWidget * empathy_contact_widget_new (GossipContact *contact, +GtkWidget * empathy_contact_widget_new (EmpathyContact *contact, gboolean editable); -GossipContact *empathy_contact_widget_get_contact (GtkWidget *widget); +EmpathyContact *empathy_contact_widget_get_contact (GtkWidget *widget); G_END_DECLS #endif /* __EMPATHY_CONTACT_WIDGET_H__ */ diff --git a/libempathy-gtk/empathy-geometry.c b/libempathy-gtk/empathy-geometry.c new file mode 100644 index 00000000..531d21a9 --- /dev/null +++ b/libempathy-gtk/empathy-geometry.c @@ -0,0 +1,186 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Martyn Russell + * Xavier Claessens + */ + +#include "config.h" + +#include + +#include +#include + +#include + +#include "empathy-geometry.h" + +#define DEBUG_DOMAIN "Geometry" + +#define GEOMETRY_DIR_CREATE_MODE (S_IRUSR | S_IWUSR | S_IXUSR) +#define GEOMETRY_FILE_CREATE_MODE (S_IRUSR | S_IWUSR) + +#define GEOMETRY_KEY_FILENAME "geometry.ini" +#define GEOMETRY_FORMAT "%d,%d,%d,%d" +#define GEOMETRY_GROUP_NAME "geometry" + +static gchar *geometry_get_filename (void); + +static gchar * +geometry_get_filename (void) +{ + gchar *dir; + gchar *filename; + + dir = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, NULL); + if (!g_file_test (dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { + empathy_debug (DEBUG_DOMAIN, "Creating directory:'%s'", dir); + g_mkdir_with_parents (dir, GEOMETRY_DIR_CREATE_MODE); + } + + filename = g_build_filename (dir, GEOMETRY_KEY_FILENAME, NULL); + g_free (dir); + + return filename; +} + +void +empathy_geometry_save (const gchar *name, + gint x, + gint y, + gint w, + gint h) +{ + GError *error = NULL; + GKeyFile *key_file; + gchar *filename; + GdkScreen *screen; + gint max_width; + gint max_height; + gchar *content; + gsize length; + gchar *str; + + empathy_debug (DEBUG_DOMAIN, "Saving window geometry: x:%d, y:%d, w:%d, h:%d\n", + x, y, w, h); + + screen = gdk_screen_get_default (); + max_width = gdk_screen_get_width (screen); + max_height = gdk_screen_get_height (screen); + + w = CLAMP (w, 100, max_width); + h = CLAMP (h, 100, max_height); + + x = CLAMP (x, 0, max_width - w); + y = CLAMP (y, 0, max_height - h); + + str = g_strdup_printf (GEOMETRY_FORMAT, x, y, w, h); + + key_file = g_key_file_new (); + + filename = geometry_get_filename (); + + g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL); + g_key_file_set_string (key_file, GEOMETRY_GROUP_NAME, name, str); + + g_free (str); + + content = g_key_file_to_data (key_file, &length, NULL); + if (!g_file_set_contents (filename, content, length, &error)) { + g_warning ("Couldn't save window geometry, error:%d->'%s'", + error->code, error->message); + g_error_free (error); + } + + g_free (content); + g_free (filename); + g_key_file_free (key_file); +} + +void +empathy_geometry_load (const gchar *name, + gint *x, + gint *y, + gint *w, + gint *h) +{ + GKeyFile *key_file; + gchar *filename; + gchar *str = NULL; + + if (x) { + *x = -1; + } + + if (y) { + *y = -1; + } + + if (w) { + *w = -1; + } + + if (h) { + *h = -1; + } + + key_file = g_key_file_new (); + + filename = geometry_get_filename (); + + if (g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL)) { + str = g_key_file_get_string (key_file, GEOMETRY_GROUP_NAME, name, NULL); + } + + if (str) { + gint tmp_x, tmp_y, tmp_w, tmp_h; + + sscanf (str, GEOMETRY_FORMAT, &tmp_x, &tmp_y, &tmp_w, &tmp_h); + + if (x) { + *x = tmp_x; + } + + if (y) { + *y = tmp_y; + } + + if (w) { + *w = tmp_w; + } + + if (h) { + *h = tmp_h; + } + + g_free (str); + } + + empathy_debug (DEBUG_DOMAIN, "Loading window geometry: x:%d, y:%d, w:%d, h:%d\n", + x ? *x : -1, + y ? *y : -1, + w ? *w : -1, + h ? *h : -1); + + g_free (filename); + g_key_file_free (key_file); +} + diff --git a/libempathy-gtk/empathy-geometry.h b/libempathy-gtk/empathy-geometry.h new file mode 100644 index 00000000..512b6469 --- /dev/null +++ b/libempathy-gtk/empathy-geometry.h @@ -0,0 +1,45 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Martyn Russell + * Xavier Claessens + */ + +#ifndef __EMPATHY_GEOMETRY_H__ +#define __EMPATHY_GEOMETRY_H__ + +#include + +G_BEGIN_DECLS + +void empathy_geometry_save (const gchar *name, + gint x, + gint y, + gint w, + gint h); +void empathy_geometry_load (const gchar *name, + gint *x, + gint *y, + gint *w, + gint *h); + +G_END_DECLS + +#endif /* __EMPATHY_GEOMETRY_H__ */ diff --git a/libempathy-gtk/empathy-group-chat.c b/libempathy-gtk/empathy-group-chat.c new file mode 100644 index 00000000..623547d9 --- /dev/null +++ b/libempathy-gtk/empathy-group-chat.c @@ -0,0 +1,707 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2002-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Richard Hult + * Martyn Russell + * Xavier Claessens + */ + +#include "config.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "empathy-group-chat.h" +#include "empathy-chat.h" +#include "empathy-chat-view.h" +#include "empathy-contact-list-store.h" +#include "empathy-contact-list-view.h" +//#include "empathy-chat-invite.h" +//#include "empathy-sound.h" +#include "empathy-images.h" +#include "empathy-ui-utils.h" + +#define DEBUG_DOMAIN "GroupChat" + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_GROUP_CHAT, EmpathyGroupChatPriv)) + +struct _EmpathyGroupChatPriv { + EmpathyContactListStore *store; + EmpathyContactListView *view; + EmpathyTpChatroom *tp_chat; + + GtkWidget *widget; + GtkWidget *hpaned; + GtkWidget *vbox_left; + GtkWidget *scrolled_window_chat; + GtkWidget *scrolled_window_input; + GtkWidget *scrolled_window_contacts; + GtkWidget *hbox_topic; + GtkWidget *label_topic; + + gchar *topic; + gchar *name; + GCompletion *completion; + + gint contacts_width; + gboolean contacts_visible; +}; + +static void group_chat_finalize (GObject *object); +static void group_chat_create_ui (EmpathyGroupChat *chat); +static void group_chat_widget_destroy_cb (GtkWidget *widget, + EmpathyGroupChat *chat); +static void group_chat_contact_added_cb (EmpathyTpChatroom *tp_chat, + EmpathyContact *contact, + EmpathyGroupChat *chat); +static void group_chat_contact_removed_cb (EmpathyTpChatroom *tp_chat, + EmpathyContact *contact, + EmpathyGroupChat *chat); +/*static void group_chat_topic_changed_cb (EmpathyTpChatroom *tp_chat, + const gchar *new_topic, + EmpathyGroupChat *chat);*/ +static void group_chat_topic_entry_activate_cb (GtkWidget *entry, + GtkDialog *dialog); +static void group_chat_topic_response_cb (GtkWidget *dialog, + gint response, + EmpathyGroupChat *chat); +static const gchar * group_chat_get_name (EmpathyChat *chat); +static gchar * group_chat_get_tooltip (EmpathyChat *chat); +static const gchar * group_chat_get_status_icon_name (EmpathyChat *chat); +static GtkWidget * group_chat_get_widget (EmpathyChat *chat); +static gboolean group_chat_is_group_chat (EmpathyChat *chat); +static void group_chat_set_tp_chat (EmpathyChat *chat, + EmpathyTpChat *tp_chat); +static void group_chat_subject_notify_cb (EmpathyTpChat *tp_chat, + GParamSpec *param, + EmpathyGroupChat *chat); +static void group_chat_name_notify_cb (EmpathyTpChat *tp_chat, + GParamSpec *param, + EmpathyGroupChat *chat); +/*static gboolean group_chat_key_press_event (GtkWidget *widget, + GdkEventKey *event, + EmpathyGroupChat *chat);*/ +static gint group_chat_contacts_completion_func (const gchar *s1, + const gchar *s2, + gsize n); + +G_DEFINE_TYPE (EmpathyGroupChat, empathy_group_chat, EMPATHY_TYPE_CHAT) + +static void +empathy_group_chat_class_init (EmpathyGroupChatClass *klass) +{ + GObjectClass *object_class; + EmpathyChatClass *chat_class; + + object_class = G_OBJECT_CLASS (klass); + chat_class = EMPATHY_CHAT_CLASS (klass); + + object_class->finalize = group_chat_finalize; + + chat_class->get_name = group_chat_get_name; + chat_class->get_tooltip = group_chat_get_tooltip; + chat_class->get_status_icon_name = group_chat_get_status_icon_name; + chat_class->get_widget = group_chat_get_widget; + chat_class->is_group_chat = group_chat_is_group_chat; + chat_class->set_tp_chat = group_chat_set_tp_chat; + + g_type_class_add_private (object_class, sizeof (EmpathyGroupChatPriv)); +} + +static void +empathy_group_chat_init (EmpathyGroupChat *chat) +{ + EmpathyGroupChatPriv *priv; + EmpathyChatView *chatview; + + priv = GET_PRIV (chat); + + priv->contacts_visible = TRUE; + + chatview = EMPATHY_CHAT_VIEW (EMPATHY_CHAT (chat)->view); + empathy_chat_view_set_is_group_chat (chatview, TRUE); + + group_chat_create_ui (chat); +} + +static void +group_chat_finalize (GObject *object) +{ + EmpathyGroupChat *chat; + EmpathyGroupChatPriv *priv; + + empathy_debug (DEBUG_DOMAIN, "Finalized:%p", object); + + chat = EMPATHY_GROUP_CHAT (object); + priv = GET_PRIV (chat); + + g_free (priv->name); + g_free (priv->topic); + g_object_unref (priv->store); + g_object_unref (priv->tp_chat); + g_completion_free (priv->completion); + + G_OBJECT_CLASS (empathy_group_chat_parent_class)->finalize (object); +} + +EmpathyGroupChat * +empathy_group_chat_new (McAccount *account, + TpChan *tp_chan) +{ + EmpathyGroupChat *chat; + EmpathyGroupChatPriv *priv; + + g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + g_return_val_if_fail (TELEPATHY_IS_CHAN (tp_chan), NULL); + + chat = g_object_new (EMPATHY_TYPE_GROUP_CHAT, NULL); + + priv = GET_PRIV (chat); + + EMPATHY_CHAT (chat)->account = g_object_ref (account); + priv->tp_chat = empathy_tp_chatroom_new (account, tp_chan); + empathy_chat_set_tp_chat (EMPATHY_CHAT (chat), EMPATHY_TP_CHAT (priv->tp_chat)); + + return chat; +} + +gboolean +empathy_group_chat_get_show_contacts (EmpathyGroupChat *chat) +{ + EmpathyGroupChat *group_chat; + EmpathyGroupChatPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_GROUP_CHAT (chat), FALSE); + + group_chat = EMPATHY_GROUP_CHAT (chat); + priv = GET_PRIV (group_chat); + + return priv->contacts_visible; +} + +void +empathy_group_chat_set_show_contacts (EmpathyGroupChat *chat, + gboolean show) +{ + EmpathyGroupChat *group_chat; + EmpathyGroupChatPriv *priv; + + g_return_if_fail (EMPATHY_IS_GROUP_CHAT (chat)); + + group_chat = EMPATHY_GROUP_CHAT (chat); + priv = GET_PRIV (group_chat); + + priv->contacts_visible = show; + + if (show) { + gtk_widget_show (priv->scrolled_window_contacts); + gtk_paned_set_position (GTK_PANED (priv->hpaned), + priv->contacts_width); + } else { + priv->contacts_width = gtk_paned_get_position (GTK_PANED (priv->hpaned)); + gtk_widget_hide (priv->scrolled_window_contacts); + } +} + +void +empathy_group_chat_set_topic (EmpathyGroupChat *chat) +{ + EmpathyGroupChatPriv *priv; + EmpathyChatWindow *chat_window; + GtkWidget *chat_dialog; + GtkWidget *dialog; + GtkWidget *entry; + GtkWidget *hbox; + const gchar *topic; + + g_return_if_fail (EMPATHY_IS_GROUP_CHAT (chat)); + + priv = GET_PRIV (chat); + + chat_window = empathy_chat_get_window (EMPATHY_CHAT (chat)); + chat_dialog = empathy_chat_window_get_dialog (chat_window); + + dialog = gtk_message_dialog_new (GTK_WINDOW (chat_dialog), + 0, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_OK_CANCEL, + _("Enter the new topic you want to set for this room:")); + + topic = gtk_label_get_text (GTK_LABEL (priv->label_topic)); + + hbox = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), + hbox, FALSE, TRUE, 4); + + entry = gtk_entry_new (); + gtk_entry_set_text (GTK_ENTRY (entry), topic); + gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1); + + gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 4); + + g_object_set (GTK_MESSAGE_DIALOG (dialog)->label, "use-markup", TRUE, NULL); + g_object_set_data (G_OBJECT (dialog), "entry", entry); + + g_signal_connect (entry, "activate", + G_CALLBACK (group_chat_topic_entry_activate_cb), + dialog); + g_signal_connect (dialog, "response", + G_CALLBACK (group_chat_topic_response_cb), + chat); + + gtk_widget_show_all (dialog); +} + +static void +group_chat_create_ui (EmpathyGroupChat *chat) +{ + EmpathyGroupChatPriv *priv; + GladeXML *glade; + GList *list = NULL; + + priv = GET_PRIV (chat); + + glade = empathy_glade_get_file ("empathy-group-chat.glade", + "group_chat_widget", + NULL, + "group_chat_widget", &priv->widget, + "hpaned", &priv->hpaned, + "vbox_left", &priv->vbox_left, + "scrolled_window_chat", &priv->scrolled_window_chat, + "scrolled_window_input", &priv->scrolled_window_input, + "hbox_topic", &priv->hbox_topic, + "label_topic", &priv->label_topic, + "scrolled_window_contacts", &priv->scrolled_window_contacts, + NULL); + + empathy_glade_connect (glade, + chat, + "group_chat_widget", "destroy", group_chat_widget_destroy_cb, + NULL); + + g_object_unref (glade); + + g_object_set_data (G_OBJECT (priv->widget), "chat", g_object_ref (chat)); + + /* Add room GtkTextView. */ + gtk_container_add (GTK_CONTAINER (priv->scrolled_window_chat), + GTK_WIDGET (EMPATHY_CHAT (chat)->view)); + gtk_widget_show (GTK_WIDGET (EMPATHY_CHAT (chat)->view)); + + /* Add input GtkTextView */ + gtk_container_add (GTK_CONTAINER (priv->scrolled_window_input), + EMPATHY_CHAT (chat)->input_text_view); + gtk_widget_show (EMPATHY_CHAT (chat)->input_text_view); + + /* Add nick name completion */ + priv->completion = g_completion_new (NULL); + g_completion_set_compare (priv->completion, + group_chat_contacts_completion_func); + + /* Set widget focus order */ + list = g_list_append (NULL, priv->scrolled_window_input); + gtk_container_set_focus_chain (GTK_CONTAINER (priv->vbox_left), list); + g_list_free (list); + + list = g_list_append (NULL, priv->vbox_left); + list = g_list_append (list, priv->scrolled_window_contacts); + gtk_container_set_focus_chain (GTK_CONTAINER (priv->hpaned), list); + g_list_free (list); + + list = g_list_append (NULL, priv->hpaned); + list = g_list_append (list, priv->hbox_topic); + gtk_container_set_focus_chain (GTK_CONTAINER (priv->widget), list); + g_list_free (list); +} + +static void +group_chat_widget_destroy_cb (GtkWidget *widget, + EmpathyGroupChat *chat) +{ + empathy_debug (DEBUG_DOMAIN, "Destroyed"); + + g_object_unref (chat); +} + +static void +group_chat_contact_added_cb (EmpathyTpChatroom *tp_chat, + EmpathyContact *contact, + EmpathyGroupChat *chat) +{ + EmpathyGroupChatPriv *priv; + gchar *str; + + priv = GET_PRIV (chat); + + str = g_strdup_printf (_("%s has joined the room"), + empathy_contact_get_name (contact)); + empathy_chat_view_append_event (EMPATHY_CHAT (chat)->view, str); + g_free (str); +} + +static void +group_chat_contact_removed_cb (EmpathyTpChatroom *tp_chat, + EmpathyContact *contact, + EmpathyGroupChat *chat) +{ + EmpathyGroupChatPriv *priv; + gchar *str; + + priv = GET_PRIV (chat); + + str = g_strdup_printf (_("%s has left the room"), + empathy_contact_get_name (contact)); + empathy_chat_view_append_event (EMPATHY_CHAT (chat)->view, str); + g_free (str); +} + +static void +group_chat_topic_entry_activate_cb (GtkWidget *entry, + GtkDialog *dialog) +{ + gtk_dialog_response (dialog, GTK_RESPONSE_OK); +} + +static void +group_chat_topic_response_cb (GtkWidget *dialog, + gint response, + EmpathyGroupChat *chat) +{ + if (response == GTK_RESPONSE_OK) { + GtkWidget *entry; + const gchar *topic; + + entry = g_object_get_data (G_OBJECT (dialog), "entry"); + topic = gtk_entry_get_text (GTK_ENTRY (entry)); + + if (!G_STR_EMPTY (topic)) { + EmpathyGroupChatPriv *priv; + + priv = GET_PRIV (chat); + + empathy_tp_chatroom_set_topic (priv->tp_chat, topic); + } + } + + gtk_widget_destroy (dialog); +} + +static const gchar * +group_chat_get_name (EmpathyChat *chat) +{ + EmpathyGroupChat *group_chat; + EmpathyGroupChatPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_GROUP_CHAT (chat), NULL); + + group_chat = EMPATHY_GROUP_CHAT (chat); + priv = GET_PRIV (group_chat); + + if (!priv->name) { + const gchar *id; + const gchar *server; + + id = empathy_chat_get_id (chat); + server = strstr (id, "@"); + + if (server) { + priv->name = g_strndup (id, server - id); + } else { + priv->name = g_strdup (id); + } + } + + return priv->name; +} + +static gchar * +group_chat_get_tooltip (EmpathyChat *chat) +{ + EmpathyGroupChat *group_chat; + EmpathyGroupChatPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_GROUP_CHAT (chat), NULL); + + group_chat = EMPATHY_GROUP_CHAT (chat); + priv = GET_PRIV (group_chat); + + if (priv->topic) { + gchar *topic, *tmp; + + topic = g_strdup_printf (_("Topic: %s"), priv->topic); + tmp = g_strdup_printf ("%s\n%s", priv->name, topic); + g_free (topic); + + return tmp; + } + + return g_strdup (priv->name); +} + +static const gchar * +group_chat_get_status_icon_name (EmpathyChat *chat) +{ + return EMPATHY_IMAGE_GROUP_MESSAGE; +} + +static GtkWidget * +group_chat_get_widget (EmpathyChat *chat) +{ + EmpathyGroupChat *group_chat; + EmpathyGroupChatPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_GROUP_CHAT (chat), NULL); + + group_chat = EMPATHY_GROUP_CHAT (chat); + priv = GET_PRIV (group_chat); + + return priv->widget; +} + +static gboolean +group_chat_is_group_chat (EmpathyChat *chat) +{ + g_return_val_if_fail (EMPATHY_IS_GROUP_CHAT (chat), FALSE); + + return TRUE; +} + +static void +group_chat_set_tp_chat (EmpathyChat *chat, + EmpathyTpChat *tp_chat) +{ + EmpathyGroupChat *group_chat; + EmpathyGroupChatPriv *priv; + + g_return_if_fail (EMPATHY_IS_GROUP_CHAT (chat)); + + group_chat = EMPATHY_GROUP_CHAT (chat); + priv = GET_PRIV (group_chat); + + /* Free all resources related to tp_chat */ + if (priv->tp_chat) { + g_object_unref (priv->tp_chat); + priv->tp_chat = NULL; + } + if (priv->view) { + gtk_widget_destroy (GTK_WIDGET (priv->view)); + g_object_unref (priv->store); + } + g_free (priv->name); + g_free (priv->topic); + priv->name = NULL; + priv->topic = NULL; + + if (!tp_chat) { + /* We are no more connected */ + gtk_widget_set_sensitive (priv->hbox_topic, FALSE); + gtk_widget_set_sensitive (priv->scrolled_window_contacts, FALSE); + return; + } + + /* We are connected */ + gtk_widget_set_sensitive (priv->hbox_topic, TRUE); + gtk_widget_set_sensitive (priv->scrolled_window_contacts, TRUE); + + priv->tp_chat = g_object_ref (tp_chat); + + /* FIXME: Ask the user before accepting */ + empathy_tp_chatroom_accept_invitation (priv->tp_chat); + + /* Create contact list */ + priv->store = empathy_contact_list_store_new (EMPATHY_CONTACT_LIST (priv->tp_chat)); + priv->view = empathy_contact_list_view_new (priv->store); + gtk_container_add (GTK_CONTAINER (priv->scrolled_window_contacts), + GTK_WIDGET (priv->view)); + gtk_widget_show (GTK_WIDGET (priv->view)); + + /* Connect signals */ + g_signal_connect (priv->tp_chat, "contact-added", + G_CALLBACK (group_chat_contact_added_cb), + chat); + g_signal_connect (priv->tp_chat, "contact-removed", + G_CALLBACK (group_chat_contact_removed_cb), + chat); + g_signal_connect (priv->tp_chat, "notify::subject", + G_CALLBACK (group_chat_subject_notify_cb), + chat); + g_signal_connect (priv->tp_chat, "notify::name", + G_CALLBACK (group_chat_name_notify_cb), + chat); +} + +static void +group_chat_subject_notify_cb (EmpathyTpChat *tp_chat, + GParamSpec *param, + EmpathyGroupChat *chat) +{ + EmpathyGroupChatPriv *priv; + gchar *str; + + priv = GET_PRIV (chat); + + g_free (priv->topic); + + g_object_get (priv->tp_chat, "subject", &priv->topic, NULL); + gtk_label_set_text (GTK_LABEL (priv->label_topic), priv->topic); + + str = g_strdup_printf (_("Topic set to: %s"), priv->topic); + empathy_chat_view_append_event (EMPATHY_CHAT (chat)->view, str); + g_free (str); +} + +static void +group_chat_name_notify_cb (EmpathyTpChat *tp_chat, + GParamSpec *param, + EmpathyGroupChat *chat) +{ + EmpathyGroupChatPriv *priv; + + priv = GET_PRIV (chat); + + g_free (priv->name); + g_object_get (priv->tp_chat, "name", &priv->name, NULL); +} + +#if 0 +static gboolean +group_chat_key_press_event (GtkWidget *widget, + GdkEventKey *event, + EmpathyGroupChat *chat) +{ + EmpathyGroupChatPriv *priv; + GtkAdjustment *adj; + gdouble val; + GtkTextBuffer *buffer; + GtkTextIter start, current; + gchar *nick, *completed; + gint len; + GList *list, *l, *completed_list; + gboolean is_start_of_buffer; + + priv = GET_PRIV (chat); + + if ((event->state & GDK_CONTROL_MASK) != GDK_CONTROL_MASK && + (event->state & GDK_SHIFT_MASK) != GDK_SHIFT_MASK && + event->keyval == GDK_Tab) { + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (EMPATHY_CHAT (chat)->input_text_view)); + gtk_text_buffer_get_iter_at_mark (buffer, ¤t, gtk_text_buffer_get_insert (buffer)); + + /* Get the start of the nick to complete. */ + gtk_text_buffer_get_iter_at_mark (buffer, &start, gtk_text_buffer_get_insert (buffer)); + gtk_text_iter_backward_word_start (&start); + is_start_of_buffer = gtk_text_iter_is_start (&start); + + nick = gtk_text_buffer_get_text (buffer, &start, ¤t, FALSE); + + g_completion_clear_items (priv->completion); + + len = strlen (nick); + + list = group_chat_get_nick_list (chat); + + g_completion_add_items (priv->completion, list); + + completed_list = g_completion_complete (priv->completion, + nick, + &completed); + + g_free (nick); + + if (completed) { + int len; + gchar *text; + + gtk_text_buffer_delete (buffer, &start, ¤t); + + len = g_list_length (completed_list); + + if (len == 1) { + /* If we only have one hit, use that text + * instead of the text in completed since the + * completed text will use the typed string + * which might be cased all wrong. + * Fixes #120876 + * */ + text = (gchar *) completed_list->data; + } else { + text = completed; + } + + gtk_text_buffer_insert_at_cursor (buffer, text, strlen (text)); + + if (len == 1) { + if (is_start_of_buffer) { + gtk_text_buffer_insert_at_cursor (buffer, ", ", 2); + } + } + + g_free (completed); + } + + g_completion_clear_items (priv->completion); + + for (l = list; l; l = l->next) { + g_free (l->data); + } + + g_list_free (list); + + return TRUE; + } + + return FALSE; +} +#endif + +static gint +group_chat_contacts_completion_func (const gchar *s1, + const gchar *s2, + gsize n) +{ + gchar *tmp, *nick1, *nick2; + gint ret; + + tmp = g_utf8_normalize (s1, -1, G_NORMALIZE_DEFAULT); + nick1 = g_utf8_casefold (tmp, -1); + g_free (tmp); + + tmp = g_utf8_normalize (s2, -1, G_NORMALIZE_DEFAULT); + nick2 = g_utf8_casefold (tmp, -1); + g_free (tmp); + + ret = strncmp (nick1, nick2, n); + + g_free (nick1); + g_free (nick2); + + return ret; +} + diff --git a/libempathy-gtk/empathy-group-chat.glade b/libempathy-gtk/empathy-group-chat.glade new file mode 100644 index 00000000..885afc5b --- /dev/null +++ b/libempathy-gtk/empathy-group-chat.glade @@ -0,0 +1,183 @@ + + + + + + + 6 + Group Chat + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 600 + 400 + True + False + empathy-group-message.png + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 4 + True + False + 6 + + + + True + False + 6 + + + + True + <b>Topic:</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + + False + True + GTK_JUSTIFY_LEFT + True + True + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_END + -1 + True + 0 + + + 0 + True + True + + + + + 2 + False + False + + + + + + True + True + + + + True + False + 6 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_ALWAYS + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + + + + 0 + True + True + + + + + + True + True + GTK_POLICY_NEVER + GTK_POLICY_NEVER + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + + + + 0 + False + True + + + + + True + True + + + + + + 0 + True + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + + + + False + False + + + + + 0 + True + True + + + + + + + diff --git a/libempathy-gtk/empathy-group-chat.h b/libempathy-gtk/empathy-group-chat.h new file mode 100644 index 00000000..fc756785 --- /dev/null +++ b/libempathy-gtk/empathy-group-chat.h @@ -0,0 +1,69 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2002-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Richard Hult + * Martyn Russell + * Xavier Claessens + */ + +#ifndef __EMPATHY_GROUP_CHAT_H__ +#define __EMPATHY_GROUP_CHAT_H__ + +G_BEGIN_DECLS + +#include + +#include + +#define EMPATHY_TYPE_GROUP_CHAT (empathy_group_chat_get_type ()) +#define EMPATHY_GROUP_CHAT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_GROUP_CHAT, EmpathyGroupChat)) +#define EMPATHY_GROUP_CHAT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_GROUP_CHAT, EmpathyGroupChatClass)) +#define EMPATHY_IS_GROUP_CHAT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_GROUP_CHAT)) +#define EMPATHY_IS_GROUP_CHAT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_GROUP_CHAT)) +#define EMPATHY_GROUP_CHAT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_GROUP_CHAT, EmpathyGroupChatClass)) + +typedef struct _EmpathyGroupChat EmpathyGroupChat; +typedef struct _EmpathyGroupChatClass EmpathyGroupChatClass; +typedef struct _EmpathyGroupChatPriv EmpathyGroupChatPriv; + +#include "empathy-chat.h" + +struct _EmpathyGroupChat { + EmpathyChat parent; + + EmpathyGroupChatPriv *priv; +}; + +struct _EmpathyGroupChatClass { + EmpathyChatClass parent_class; +}; + +GType empathy_group_chat_get_type (void) G_GNUC_CONST; +EmpathyGroupChat *empathy_group_chat_new (McAccount *account, + TpChan *tp_chan); +gboolean empathy_group_chat_get_show_contacts (EmpathyGroupChat *chat); +void empathy_group_chat_set_show_contacts (EmpathyGroupChat *chat, + gboolean show); +void empathy_group_chat_set_topic (EmpathyGroupChat *chat); + +G_END_DECLS + +#endif /* __EMPATHY_GROUP_CHAT_H__ */ diff --git a/libempathy-gtk/empathy-log-window.c b/libempathy-gtk/empathy-log-window.c new file mode 100644 index 00000000..53eb39c8 --- /dev/null +++ b/libempathy-gtk/empathy-log-window.c @@ -0,0 +1,1118 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Martyn Russell + * Xavier Claessens + */ + +#include "config.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "empathy-log-window.h" +#include "empathy-account-chooser.h" +#include "empathy-chat-view.h" +#include "empathy-ui-utils.h" + +#define DEBUG_DOMAIN "LogWindow" + +typedef struct { + GtkWidget *window; + + GtkWidget *notebook; + + GtkWidget *entry_find; + GtkWidget *button_find; + GtkWidget *treeview_find; + GtkWidget *scrolledwindow_find; + EmpathyChatView *chatview_find; + GtkWidget *button_previous; + GtkWidget *button_next; + + GtkWidget *vbox_chats; + GtkWidget *account_chooser_chats; + GtkWidget *entry_chats; + GtkWidget *calendar_chats; + GtkWidget *treeview_chats; + GtkWidget *scrolledwindow_chats; + EmpathyChatView *chatview_chats; + + gchar *last_find; + + EmpathyLogManager *log_manager; +} EmpathyLogWindow; + +static void +log_window_destroy_cb (GtkWidget *widget, + EmpathyLogWindow *window); +static void +log_window_entry_find_changed_cb (GtkWidget *entry, + EmpathyLogWindow *window); +static void +log_window_find_changed_cb (GtkTreeSelection *selection, + EmpathyLogWindow *window); +static void +log_window_find_populate (EmpathyLogWindow *window, + const gchar *search_criteria); +static void +log_window_find_setup (EmpathyLogWindow *window); +static void +log_window_button_find_clicked_cb (GtkWidget *widget, + EmpathyLogWindow *window); +static void +log_window_button_next_clicked_cb (GtkWidget *widget, + EmpathyLogWindow *window); +static void +log_window_button_previous_clicked_cb (GtkWidget *widget, + EmpathyLogWindow *window); +static void +log_window_chats_changed_cb (GtkTreeSelection *selection, + EmpathyLogWindow *window); +static void +log_window_chats_populate (EmpathyLogWindow *window); +static void +log_window_chats_setup (EmpathyLogWindow *window); +static void +log_window_chats_accounts_changed_cb (GtkWidget *combobox, + EmpathyLogWindow *window); +static void +log_window_chats_new_message_cb (EmpathyContact *own_contact, + EmpathyMessage *message, + EmpathyLogWindow *window); +static void +log_window_chats_set_selected (EmpathyLogWindow *window, + McAccount *account, + const gchar *chat_id, + gboolean is_chatroom); +static gboolean +log_window_chats_get_selected (EmpathyLogWindow *window, + McAccount **account, + gchar **chat_id, + gboolean *is_chatroom); +static void +log_window_chats_get_messages (EmpathyLogWindow *window, + const gchar *date_to_show); +static void +log_window_calendar_chats_day_selected_cb (GtkWidget *calendar, + EmpathyLogWindow *window); +static void +log_window_calendar_chats_month_changed_cb (GtkWidget *calendar, + EmpathyLogWindow *window); +static void +log_window_entry_chats_changed_cb (GtkWidget *entry, + EmpathyLogWindow *window); +static void +log_window_entry_chats_activate_cb (GtkWidget *entry, + EmpathyLogWindow *window); + +enum { + COL_FIND_ACCOUNT_ICON, + COL_FIND_ACCOUNT_NAME, + COL_FIND_ACCOUNT, + COL_FIND_CHAT_NAME, + COL_FIND_CHAT_ID, + COL_FIND_IS_CHATROOM, + COL_FIND_DATE, + COL_FIND_DATE_READABLE, + COL_FIND_COUNT +}; + +enum { + COL_CHAT_ICON, + COL_CHAT_NAME, + COL_CHAT_ACCOUNT, + COL_CHAT_ID, + COL_CHAT_IS_CHATROOM, + COL_CHAT_COUNT +}; + +void +empathy_log_window_show (McAccount *account, + const gchar *chat_id, + gboolean is_chatroom, + GtkWindow *parent) +{ + static EmpathyLogWindow *window = NULL; + EmpathyAccountChooser *account_chooser; + GList *accounts; + gint account_num; + GladeXML *glade; + + if (window) { + gtk_window_present (GTK_WINDOW (window->window)); + + if (account && chat_id) { + gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), 1); + log_window_chats_set_selected (window, account, + chat_id, is_chatroom); + } + + return; + } + + window = g_new0 (EmpathyLogWindow, 1); + window->log_manager = empathy_log_manager_new (); + + glade = empathy_glade_get_file ("empathy-log-window.glade", + "log_window", + NULL, + "log_window", &window->window, + "notebook", &window->notebook, + "entry_find", &window->entry_find, + "button_find", &window->button_find, + "treeview_find", &window->treeview_find, + "scrolledwindow_find", &window->scrolledwindow_find, + "button_previous", &window->button_previous, + "button_next", &window->button_next, + "entry_chats", &window->entry_chats, + "calendar_chats", &window->calendar_chats, + "vbox_chats", &window->vbox_chats, + "treeview_chats", &window->treeview_chats, + "scrolledwindow_chats", &window->scrolledwindow_chats, + NULL); + empathy_glade_connect (glade, + window, + "log_window", "destroy", log_window_destroy_cb, + "entry_find", "changed", log_window_entry_find_changed_cb, + "button_previous", "clicked", log_window_button_previous_clicked_cb, + "button_next", "clicked", log_window_button_next_clicked_cb, + "button_find", "clicked", log_window_button_find_clicked_cb, + "entry_chats", "changed", log_window_entry_chats_changed_cb, + "entry_chats", "activate", log_window_entry_chats_activate_cb, + NULL); + + g_object_unref (glade); + + g_object_add_weak_pointer (G_OBJECT (window->window), + (gpointer) &window); + + /* We set this up here so we can block it when needed. */ + g_signal_connect (window->calendar_chats, "day-selected", + G_CALLBACK (log_window_calendar_chats_day_selected_cb), + window); + g_signal_connect (window->calendar_chats, "month-changed", + G_CALLBACK (log_window_calendar_chats_month_changed_cb), + window); + + /* Configure Search EmpathyChatView */ + window->chatview_find = empathy_chat_view_new (); + gtk_container_add (GTK_CONTAINER (window->scrolledwindow_find), + GTK_WIDGET (window->chatview_find)); + gtk_widget_show (GTK_WIDGET (window->chatview_find)); + + /* Configure Contacts EmpathyChatView */ + window->chatview_chats = empathy_chat_view_new (); + gtk_container_add (GTK_CONTAINER (window->scrolledwindow_chats), + GTK_WIDGET (window->chatview_chats)); + gtk_widget_show (GTK_WIDGET (window->chatview_chats)); + + /* Account chooser for chats */ + window->account_chooser_chats = empathy_account_chooser_new (); + account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser_chats); + empathy_account_chooser_set_can_select_all (account_chooser, TRUE); + + gtk_box_pack_start (GTK_BOX (window->vbox_chats), + window->account_chooser_chats, + FALSE, TRUE, 0); + + g_signal_connect (window->account_chooser_chats, "changed", + G_CALLBACK (log_window_chats_accounts_changed_cb), + window); + + /* Populate */ + accounts = mc_accounts_list (); + account_num = g_list_length (accounts); + mc_accounts_list_free (accounts); + + if (account_num > 1) { + gtk_widget_show (window->vbox_chats); + gtk_widget_show (window->account_chooser_chats); + } else { + gtk_widget_hide (window->vbox_chats); + gtk_widget_hide (window->account_chooser_chats); + } + + /* Search List */ + log_window_find_setup (window); + + /* Contacts */ + log_window_chats_setup (window); + log_window_chats_populate (window); + + /* Select chat */ + if (account && chat_id) { + gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), 1); + log_window_chats_set_selected (window, account, + chat_id, is_chatroom); + } + + if (parent) { + gtk_window_set_transient_for (GTK_WINDOW (window->window), + GTK_WINDOW (parent)); + } + + gtk_widget_show (window->window); +} + +static void +log_window_destroy_cb (GtkWidget *widget, + EmpathyLogWindow *window) +{ + g_signal_handlers_disconnect_by_func (window->log_manager, + log_window_chats_new_message_cb, + window); + + g_free (window->last_find); + g_object_unref (window->log_manager); + + g_free (window); +} + +/* + * Search code. + */ +static void +log_window_entry_find_changed_cb (GtkWidget *entry, + EmpathyLogWindow *window) +{ + const gchar *str; + gboolean is_sensitive = TRUE; + + str = gtk_entry_get_text (GTK_ENTRY (window->entry_find)); + + is_sensitive &= !G_STR_EMPTY (str); + is_sensitive &= + !window->last_find || + (window->last_find && strcmp (window->last_find, str) != 0); + + gtk_widget_set_sensitive (window->button_find, is_sensitive); +} + +static void +log_window_find_changed_cb (GtkTreeSelection *selection, + EmpathyLogWindow *window) +{ + GtkTreeView *view; + GtkTreeModel *model; + GtkTreeIter iter; + McAccount *account; + gchar *chat_id; + gboolean is_chatroom; + gchar *date; + EmpathyMessage *message; + GList *messages; + GList *l; + gboolean can_do_previous; + gboolean can_do_next; + + /* Get selected information */ + view = GTK_TREE_VIEW (window->treeview_find); + model = gtk_tree_view_get_model (view); + + if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) { + gtk_widget_set_sensitive (window->button_previous, FALSE); + gtk_widget_set_sensitive (window->button_next, FALSE); + + empathy_chat_view_clear (window->chatview_find); + + return; + } + + gtk_widget_set_sensitive (window->button_previous, TRUE); + gtk_widget_set_sensitive (window->button_next, TRUE); + + gtk_tree_model_get (model, &iter, + COL_FIND_ACCOUNT, &account, + COL_FIND_CHAT_ID, &chat_id, + COL_FIND_IS_CHATROOM, &is_chatroom, + COL_FIND_DATE, &date, + -1); + + /* Clear all current messages shown in the textview */ + empathy_chat_view_clear (window->chatview_find); + + /* Turn off scrolling temporarily */ + empathy_chat_view_scroll (window->chatview_find, FALSE); + + /* Get messages */ + messages = empathy_log_manager_get_messages_for_date (window->log_manager, + account, + chat_id, + is_chatroom, + date); + g_object_unref (account); + g_free (date); + g_free (chat_id); + + for (l = messages; l; l = l->next) { + message = l->data; + empathy_chat_view_append_message (window->chatview_find, message); + g_object_unref (message); + } + g_list_free (messages); + + /* Scroll to the most recent messages */ + empathy_chat_view_scroll (window->chatview_find, TRUE); + + /* Highlight and find messages */ + empathy_chat_view_highlight (window->chatview_find, + window->last_find); + empathy_chat_view_find_next (window->chatview_find, + window->last_find, + TRUE); + empathy_chat_view_find_abilities (window->chatview_find, + window->last_find, + &can_do_previous, + &can_do_next); + gtk_widget_set_sensitive (window->button_previous, can_do_previous); + gtk_widget_set_sensitive (window->button_next, can_do_next); + gtk_widget_set_sensitive (window->button_find, FALSE); +} + +static void +log_window_find_populate (EmpathyLogWindow *window, + const gchar *search_criteria) +{ + GList *hits, *l; + + GtkTreeView *view; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkListStore *store; + GtkTreeIter iter; + + view = GTK_TREE_VIEW (window->treeview_find); + model = gtk_tree_view_get_model (view); + selection = gtk_tree_view_get_selection (view); + store = GTK_LIST_STORE (model); + + empathy_chat_view_clear (window->chatview_find); + + gtk_list_store_clear (store); + + if (G_STR_EMPTY (search_criteria)) { + /* Just clear the search. */ + return; + } + + hits = empathy_log_manager_search_new (window->log_manager, search_criteria); + + for (l = hits; l; l = l->next) { + EmpathyLogSearchHit *hit; + const gchar *account_name; + const gchar *account_icon; + gchar *date_readable; + + hit = l->data; + + /* Protect against invalid data (corrupt or old log files. */ + if (!hit->account || !hit->chat_id) { + continue; + } + + date_readable = empathy_log_manager_get_date_readable (hit->date); + account_name = mc_account_get_display_name (hit->account); + account_icon = empathy_icon_name_from_account (hit->account); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + COL_FIND_ACCOUNT_ICON, account_icon, + COL_FIND_ACCOUNT_NAME, account_name, + COL_FIND_ACCOUNT, hit->account, + COL_FIND_CHAT_NAME, hit->chat_id, /* FIXME */ + COL_FIND_CHAT_ID, hit->chat_id, + COL_FIND_IS_CHATROOM, hit->is_chatroom, + COL_FIND_DATE, hit->date, + COL_FIND_DATE_READABLE, date_readable, + -1); + + g_free (date_readable); + + /* FIXME: Update COL_FIND_CHAT_NAME */ + if (hit->is_chatroom) { + } else { + } + } + + if (hits) { + empathy_log_manager_search_free (hits); + } +} + +static void +log_window_find_setup (EmpathyLogWindow *window) +{ + GtkTreeView *view; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeSortable *sortable; + GtkTreeViewColumn *column; + GtkListStore *store; + GtkCellRenderer *cell; + gint offset; + + view = GTK_TREE_VIEW (window->treeview_find); + selection = gtk_tree_view_get_selection (view); + + /* New store */ + store = gtk_list_store_new (COL_FIND_COUNT, + G_TYPE_STRING, /* account icon name */ + G_TYPE_STRING, /* account name */ + MC_TYPE_ACCOUNT, /* account */ + G_TYPE_STRING, /* chat name */ + G_TYPE_STRING, /* chat id */ + G_TYPE_BOOLEAN, /* is chatroom */ + G_TYPE_STRING, /* date */ + G_TYPE_STRING); /* date_readable */ + + model = GTK_TREE_MODEL (store); + sortable = GTK_TREE_SORTABLE (store); + + gtk_tree_view_set_model (view, model); + + /* New column */ + column = gtk_tree_view_column_new (); + + cell = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, cell, FALSE); + gtk_tree_view_column_add_attribute (column, cell, + "icon-name", + COL_FIND_ACCOUNT_ICON); + + cell = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, cell, TRUE); + gtk_tree_view_column_add_attribute (column, cell, + "text", + COL_FIND_ACCOUNT_NAME); + + gtk_tree_view_column_set_title (column, _("Account")); + gtk_tree_view_append_column (view, column); + + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_column_set_clickable (column, TRUE); + + cell = gtk_cell_renderer_text_new (); + offset = gtk_tree_view_insert_column_with_attributes (view, -1, _("Conversation"), + cell, "text", COL_FIND_CHAT_NAME, + NULL); + + column = gtk_tree_view_get_column (view, offset - 1); + gtk_tree_view_column_set_sort_column_id (column, COL_FIND_CHAT_NAME); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_column_set_clickable (column, TRUE); + + cell = gtk_cell_renderer_text_new (); + offset = gtk_tree_view_insert_column_with_attributes (view, -1, _("Date"), + cell, "text", COL_FIND_DATE_READABLE, + NULL); + + column = gtk_tree_view_get_column (view, offset - 1); + gtk_tree_view_column_set_sort_column_id (column, COL_FIND_DATE); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_column_set_clickable (column, TRUE); + + /* Set up treeview properties */ + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + gtk_tree_sortable_set_sort_column_id (sortable, + COL_FIND_DATE, + GTK_SORT_ASCENDING); + + /* Set up signals */ + g_signal_connect (selection, "changed", + G_CALLBACK (log_window_find_changed_cb), + window); + + g_object_unref (store); +} + +static void +log_window_button_find_clicked_cb (GtkWidget *widget, + EmpathyLogWindow *window) +{ + const gchar *str; + + str = gtk_entry_get_text (GTK_ENTRY (window->entry_find)); + + /* Don't find the same crap again */ + if (window->last_find && strcmp (window->last_find, str) == 0) { + return; + } + + g_free (window->last_find); + window->last_find = g_strdup (str); + + log_window_find_populate (window, str); +} + +static void +log_window_button_next_clicked_cb (GtkWidget *widget, + EmpathyLogWindow *window) +{ + if (window->last_find) { + gboolean can_do_previous; + gboolean can_do_next; + + empathy_chat_view_find_next (window->chatview_find, + window->last_find, + FALSE); + empathy_chat_view_find_abilities (window->chatview_find, + window->last_find, + &can_do_previous, + &can_do_next); + gtk_widget_set_sensitive (window->button_previous, can_do_previous); + gtk_widget_set_sensitive (window->button_next, can_do_next); + } +} + +static void +log_window_button_previous_clicked_cb (GtkWidget *widget, + EmpathyLogWindow *window) +{ + if (window->last_find) { + gboolean can_do_previous; + gboolean can_do_next; + + empathy_chat_view_find_previous (window->chatview_find, + window->last_find, + FALSE); + empathy_chat_view_find_abilities (window->chatview_find, + window->last_find, + &can_do_previous, + &can_do_next); + gtk_widget_set_sensitive (window->button_previous, can_do_previous); + gtk_widget_set_sensitive (window->button_next, can_do_next); + } +} + +/* + * Chats Code + */ + +static void +log_window_chats_changed_cb (GtkTreeSelection *selection, + EmpathyLogWindow *window) +{ + /* Use last date by default */ + gtk_calendar_clear_marks (GTK_CALENDAR (window->calendar_chats)); + + log_window_chats_get_messages (window, NULL); +} + +static void +log_window_chats_populate (EmpathyLogWindow *window) +{ + EmpathyAccountChooser *account_chooser; + McAccount *account; + GList *chats, *l; + + GtkTreeView *view; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkListStore *store; + GtkTreeIter iter; + + account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser_chats); + account = empathy_account_chooser_get_account (account_chooser); + + view = GTK_TREE_VIEW (window->treeview_chats); + model = gtk_tree_view_get_model (view); + selection = gtk_tree_view_get_selection (view); + store = GTK_LIST_STORE (model); + + /* Block signals to stop the logs being retrieved prematurely */ + g_signal_handlers_block_by_func (selection, + log_window_chats_changed_cb, + window); + + gtk_list_store_clear (store); + + chats = empathy_log_manager_get_chats (window->log_manager, account); + for (l = chats; l; l = l->next) { + EmpathyLogSearchHit *hit; + + hit = l->data; + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + COL_CHAT_ICON, "empathy-available", /* FIXME */ + COL_CHAT_NAME, hit->chat_id, + COL_CHAT_ACCOUNT, account, + COL_CHAT_ID, hit->chat_id, + COL_CHAT_IS_CHATROOM, hit->is_chatroom, + -1); + + /* FIXME: Update COL_CHAT_ICON/NAME */ + if (hit->is_chatroom) { + } else { + } + } + empathy_log_manager_search_free (chats); + + /* Unblock signals */ + g_signal_handlers_unblock_by_func (selection, + log_window_chats_changed_cb, + window); + + + g_object_unref (account); +} + +static void +log_window_chats_setup (EmpathyLogWindow *window) +{ + GtkTreeView *view; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeSortable *sortable; + GtkTreeViewColumn *column; + GtkListStore *store; + GtkCellRenderer *cell; + + view = GTK_TREE_VIEW (window->treeview_chats); + selection = gtk_tree_view_get_selection (view); + + /* new store */ + store = gtk_list_store_new (COL_CHAT_COUNT, + G_TYPE_STRING, /* icon */ + G_TYPE_STRING, /* name */ + MC_TYPE_ACCOUNT, /* account */ + G_TYPE_STRING, /* id */ + G_TYPE_BOOLEAN); /* is chatroom */ + + model = GTK_TREE_MODEL (store); + sortable = GTK_TREE_SORTABLE (store); + + gtk_tree_view_set_model (view, model); + + /* new column */ + column = gtk_tree_view_column_new (); + + cell = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, cell, FALSE); + gtk_tree_view_column_add_attribute (column, cell, + "icon-name", + COL_CHAT_ICON); + + cell = gtk_cell_renderer_text_new (); + g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL); + gtk_tree_view_column_pack_start (column, cell, TRUE); + gtk_tree_view_column_add_attribute (column, cell, + "text", + COL_CHAT_NAME); + + gtk_tree_view_append_column (view, column); + + /* set up treeview properties */ + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + gtk_tree_sortable_set_sort_column_id (sortable, + COL_CHAT_NAME, + GTK_SORT_ASCENDING); + + /* set up signals */ + g_signal_connect (selection, "changed", + G_CALLBACK (log_window_chats_changed_cb), + window); + + g_object_unref (store); +} + +static void +log_window_chats_accounts_changed_cb (GtkWidget *combobox, + EmpathyLogWindow *window) +{ + /* Clear all current messages shown in the textview */ + empathy_chat_view_clear (window->chatview_chats); + + log_window_chats_populate (window); +} + +static void +log_window_chats_new_message_cb (EmpathyContact *own_contact, + EmpathyMessage *message, + EmpathyLogWindow *window) +{ + empathy_chat_view_append_message (window->chatview_chats, message); + + /* Scroll to the most recent messages */ + empathy_chat_view_scroll_down (window->chatview_chats); +} + +static void +log_window_chats_set_selected (EmpathyLogWindow *window, + McAccount *account, + const gchar *chat_id, + gboolean is_chatroom) +{ + EmpathyAccountChooser *account_chooser; + GtkTreeView *view; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + GtkTreePath *path; + gboolean ok; + + account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser_chats); + empathy_account_chooser_set_account (account_chooser, account); + + view = GTK_TREE_VIEW (window->treeview_chats); + model = gtk_tree_view_get_model (view); + selection = gtk_tree_view_get_selection (view); + + if (!gtk_tree_model_get_iter_first (model, &iter)) { + return; + } + + for (ok = TRUE; ok; ok = gtk_tree_model_iter_next (model, &iter)) { + McAccount *this_account; + gchar *this_chat_id; + gboolean this_is_chatroom; + + gtk_tree_model_get (model, &iter, + COL_CHAT_ACCOUNT, &this_account, + COL_CHAT_ID, &this_chat_id, + COL_CHAT_IS_CHATROOM, &this_is_chatroom, + -1); + + if (empathy_account_equal (this_account, account) && + strcmp (this_chat_id, chat_id) == 0 && + this_is_chatroom == is_chatroom) { + gtk_tree_selection_select_iter (selection, &iter); + path = gtk_tree_model_get_path (model, &iter); + gtk_tree_view_scroll_to_cell (view, path, NULL, TRUE, 0.5, 0.0); + gtk_tree_path_free (path); + g_object_unref (this_account); + g_free (this_chat_id); + break; + } + + g_object_unref (this_account); + g_free (this_chat_id); + } +} + +static gboolean +log_window_chats_get_selected (EmpathyLogWindow *window, + McAccount **account, + gchar **chat_id, + gboolean *is_chatroom) +{ + GtkTreeView *view; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + gchar *id = NULL; + McAccount *acc = NULL; + gboolean room = FALSE; + + view = GTK_TREE_VIEW (window->treeview_chats); + model = gtk_tree_view_get_model (view); + selection = gtk_tree_view_get_selection (view); + + if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) { + return FALSE; + } + + gtk_tree_model_get (model, &iter, + COL_CHAT_ACCOUNT, &acc, + COL_CHAT_ID, &id, + COL_CHAT_IS_CHATROOM, &room, + -1); + + if (chat_id) { + *chat_id = id; + } else { + g_free (id); + } + if (account) { + *account = acc; + } else { + g_object_unref (acc); + } + if (is_chatroom) { + *is_chatroom = room; + } + + return TRUE; +} + +static void +log_window_chats_get_messages (EmpathyLogWindow *window, + const gchar *date_to_show) +{ + McAccount *account; + gchar *chat_id; + gboolean is_chatroom; + EmpathyMessage *message; + GList *messages; + GList *dates = NULL; + GList *l; + const gchar *date; + guint year_selected; + guint year; + guint month; + guint month_selected; + guint day; + + if (!log_window_chats_get_selected (window, &account, + &chat_id, &is_chatroom)) { + return; + } + + g_signal_handlers_block_by_func (window->calendar_chats, + log_window_calendar_chats_day_selected_cb, + window); + + /* Either use the supplied date or get the last */ + date = date_to_show; + if (!date) { + gboolean day_selected = FALSE; + + /* Get a list of dates and show them on the calendar */ + dates = empathy_log_manager_get_dates (window->log_manager, + account, chat_id, + is_chatroom); + + for (l = dates; l; l = l->next) { + const gchar *str; + + str = l->data; + if (!str) { + continue; + } + + sscanf (str, "%4d%2d%2d", &year, &month, &day); + gtk_calendar_get_date (GTK_CALENDAR (window->calendar_chats), + &year_selected, + &month_selected, + NULL); + + month_selected++; + + if (!l->next) { + date = str; + } + + if (year != year_selected || month != month_selected) { + continue; + } + + + empathy_debug (DEBUG_DOMAIN, "Marking date:'%s'", str); + gtk_calendar_mark_day (GTK_CALENDAR (window->calendar_chats), day); + + if (l->next) { + continue; + } + + day_selected = TRUE; + + gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats), day); + } + + if (!day_selected) { + /* Unselect the day in the calendar */ + gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats), 0); + } + } else { + sscanf (date, "%4d%2d%2d", &year, &month, &day); + gtk_calendar_get_date (GTK_CALENDAR (window->calendar_chats), + &year_selected, + &month_selected, + NULL); + + month_selected++; + + if (year != year_selected && month != month_selected) { + day = 0; + } + + gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats), day); + } + g_signal_handlers_unblock_by_func (window->calendar_chats, + log_window_calendar_chats_day_selected_cb, + window); + + /* Clear all current messages shown in the textview */ + empathy_chat_view_clear (window->chatview_chats); + + /* Turn off scrolling temporarily */ + empathy_chat_view_scroll (window->chatview_find, FALSE); + + /* Get messages */ + messages = empathy_log_manager_get_messages_for_date (window->log_manager, + account, chat_id, + is_chatroom, + date); + + for (l = messages; l; l = l->next) { + message = l->data; + + empathy_chat_view_append_message (window->chatview_chats, + message); + g_object_unref (message); + } + g_list_free (messages); + + g_list_foreach (dates, (GFunc) g_free, NULL); + g_list_free (dates); + + g_object_unref (account); + g_free (chat_id); + + /* Turn back on scrolling */ + empathy_chat_view_scroll (window->chatview_find, TRUE); + + /* Scroll to the most recent messages */ + empathy_chat_view_scroll_down (window->chatview_chats); + + /* Give the search entry main focus */ + gtk_widget_grab_focus (window->entry_chats); +} + +static void +log_window_calendar_chats_day_selected_cb (GtkWidget *calendar, + EmpathyLogWindow *window) +{ + guint year; + guint month; + guint day; + + gchar *date; + + gtk_calendar_get_date (GTK_CALENDAR (calendar), &year, &month, &day); + + /* We need this hear because it appears that the months start from 0 */ + month++; + + date = g_strdup_printf ("%4.4d%2.2d%2.2d", year, month, day); + + empathy_debug (DEBUG_DOMAIN, "Currently selected date is:'%s'", date); + + log_window_chats_get_messages (window, date); + + g_free (date); +} + +static void +log_window_calendar_chats_month_changed_cb (GtkWidget *calendar, + EmpathyLogWindow *window) +{ + McAccount *account; + gchar *chat_id; + gboolean is_chatroom; + guint year_selected; + guint month_selected; + + GList *dates; + GList *l; + + gtk_calendar_clear_marks (GTK_CALENDAR (calendar)); + + if (!log_window_chats_get_selected (window, &account, + &chat_id, &is_chatroom)) { + empathy_debug (DEBUG_DOMAIN, "No chat selected to get dates for..."); + return; + } + + g_object_get (calendar, + "month", &month_selected, + "year", &year_selected, + NULL); + + /* We need this hear because it appears that the months start from 0 */ + month_selected++; + + /* Get the log object for this contact */ + dates = empathy_log_manager_get_dates (window->log_manager, account, + chat_id, is_chatroom); + g_object_unref (account); + g_free (chat_id); + + for (l = dates; l; l = l->next) { + const gchar *str; + guint year; + guint month; + guint day; + + str = l->data; + if (!str) { + continue; + } + + sscanf (str, "%4d%2d%2d", &year, &month, &day); + + if (year == year_selected && month == month_selected) { + empathy_debug (DEBUG_DOMAIN, "Marking date:'%s'", str); + gtk_calendar_mark_day (GTK_CALENDAR (window->calendar_chats), day); + } + } + + g_list_foreach (dates, (GFunc) g_free, NULL); + g_list_free (dates); + + empathy_debug (DEBUG_DOMAIN, + "Currently showing month %d and year %d", + month_selected, year_selected); +} + +static void +log_window_entry_chats_changed_cb (GtkWidget *entry, + EmpathyLogWindow *window) +{ + const gchar *str; + + str = gtk_entry_get_text (GTK_ENTRY (window->entry_chats)); + empathy_chat_view_highlight (window->chatview_chats, str); + + if (str) { + empathy_chat_view_find_next (window->chatview_chats, + str, + TRUE); + } +} + +static void +log_window_entry_chats_activate_cb (GtkWidget *entry, + EmpathyLogWindow *window) +{ + const gchar *str; + + str = gtk_entry_get_text (GTK_ENTRY (window->entry_chats)); + + if (str) { + empathy_chat_view_find_next (window->chatview_chats, + str, + FALSE); + } +} + diff --git a/libempathy-gtk/empathy-log-window.glade b/libempathy-gtk/empathy-log-window.glade new file mode 100644 index 00000000..4309a354 --- /dev/null +++ b/libempathy-gtk/empathy-log-window.glade @@ -0,0 +1,470 @@ + + + + + + + View Previous Conversations + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 640 + 450 + True + False + gtk-justify-left + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 2 + True + True + True + True + GTK_POS_TOP + False + False + + + + 12 + True + False + 6 + + + + True + False + 12 + + + + True + _For: + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + entry_find + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + True + 0 + + True + * + True + + + 0 + True + True + + + + + + True + False + True + True + True + gtk-find + True + GTK_RELIEF_NORMAL + False + + + 0 + False + False + + + + + 0 + False + False + + + + + + True + True + 120 + + + + True + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + False + False + False + False + False + False + + + + + True + False + + + + + + True + False + 6 + + + + True + True + GTK_POLICY_NEVER + GTK_POLICY_ALWAYS + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + + + + 0 + True + True + + + + + + True + False + 12 + + + + + + + + True + False + True + gtk-media-next + True + GTK_RELIEF_NORMAL + False + + + 0 + False + False + GTK_PACK_END + + + + + + True + False + True + gtk-media-previous + True + GTK_RELIEF_NORMAL + False + + + 0 + False + False + GTK_PACK_END + + + + + 0 + False + False + + + + + True + True + + + + + 0 + True + True + + + + + False + True + + + + + + True + Search + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + 12 + True + 2 + 2 + False + 6 + 6 + + + + True + False + 6 + + + + True + gtk-find + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + * + True + + + 0 + True + True + + + + + 1 + 2 + 0 + 1 + fill + fill + + + + + + True + False + 6 + + + + 150 + True + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + False + False + True + False + False + False + + + + + 0 + True + True + + + + + + True + True + GTK_CALENDAR_SHOW_HEADING|GTK_CALENDAR_SHOW_DAY_NAMES + + + 0 + False + False + + + + + 0 + 1 + 1 + 2 + fill + + + + + + True + True + GTK_POLICY_NEVER + GTK_POLICY_ALWAYS + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + + + + 1 + 2 + 1 + 2 + + + + + + True + False + 6 + + + + + + + 0 + 1 + 0 + 1 + fill + fill + + + + + False + True + + + + + + True + Conversations + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + + diff --git a/libempathy-gtk/empathy-log-window.h b/libempathy-gtk/empathy-log-window.h new file mode 100644 index 00000000..09a98639 --- /dev/null +++ b/libempathy-gtk/empathy-log-window.h @@ -0,0 +1,39 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Martyn Russell + * Xavier Claessens + */ + +#ifndef __EMPATHY_LOG_WINDOW_H__ +#define __EMPATHY_LOG_WINDOW_H__ + +#include + +G_BEGIN_DECLS + +void empathy_log_window_show (McAccount *account, + const gchar *chat_id, + gboolean chatroom, + GtkWindow *parent); + +G_END_DECLS + +#endif /* __EMPATHY_LOG_WINDOW_H__ */ diff --git a/libempathy-gtk/empathy-main-window.c b/libempathy-gtk/empathy-main-window.c index 0e7b1fdd..7f61afcd 100644 --- a/libempathy-gtk/empathy-main-window.c +++ b/libempathy-gtk/empathy-main-window.c @@ -27,30 +27,30 @@ #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include "empathy-main-window.h" #include "empathy-contact-dialogs.h" #include "ephy-spinner.h" -#include "gossip-contact-list-store.h" -#include "gossip-contact-list-view.h" -#include "gossip-presence-chooser.h" -#include "gossip-ui-utils.h" -#include "gossip-status-presets.h" -#include "gossip-geometry.h" -#include "gossip-preferences.h" -#include "gossip-accounts-dialog.h" -#include "gossip-about-dialog.h" -#include "gossip-new-chatroom-dialog.h" -#include "gossip-chatrooms-window.h" -#include "gossip-log-window.h" +#include "empathy-contact-list-store.h" +#include "empathy-contact-list-view.h" +#include "empathy-presence-chooser.h" +#include "empathy-ui-utils.h" +#include "empathy-status-presets.h" +#include "empathy-geometry.h" +#include "empathy-preferences.h" +#include "empathy-accounts-dialog.h" +#include "empathy-about-dialog.h" +#include "empathy-new-chatroom-dialog.h" +#include "empathy-chatrooms-window.h" +#include "empathy-log-window.h" #define DEBUG_DOMAIN "MainWindow" @@ -64,10 +64,10 @@ #define GEOMETRY_NAME "main-window" typedef struct { - GossipContactListView *list_view; - GossipContactListStore *list_store; + EmpathyContactListView *list_view; + EmpathyContactListStore *list_store; MissionControl *mc; - GossipChatroomManager *chatroom_manager; + EmpathyChatroomManager *chatroom_manager; /* Main widgets */ GtkWidget *window; @@ -102,18 +102,18 @@ typedef struct { static void main_window_destroy_cb (GtkWidget *widget, EmpathyMainWindow *window); static void main_window_favorite_chatroom_menu_setup (EmpathyMainWindow *window); -static void main_window_favorite_chatroom_menu_added_cb (GossipChatroomManager *manager, - GossipChatroom *chatroom, +static void main_window_favorite_chatroom_menu_added_cb (EmpathyChatroomManager *manager, + EmpathyChatroom *chatroom, EmpathyMainWindow *window); -static void main_window_favorite_chatroom_menu_removed_cb (GossipChatroomManager *manager, - GossipChatroom *chatroom, +static void main_window_favorite_chatroom_menu_removed_cb (EmpathyChatroomManager *manager, + EmpathyChatroom *chatroom, EmpathyMainWindow *window); static void main_window_favorite_chatroom_menu_activate_cb (GtkMenuItem *menu_item, - GossipChatroom *chatroom); + EmpathyChatroom *chatroom); static void main_window_favorite_chatroom_menu_update (EmpathyMainWindow *window); static void main_window_favorite_chatroom_menu_add (EmpathyMainWindow *window, - GossipChatroom *chatroom); -static void main_window_favorite_chatroom_join (GossipChatroom *chatroom); + EmpathyChatroom *chatroom); +static void main_window_favorite_chatroom_join (EmpathyChatroom *chatroom); static void main_window_chat_quit_cb (GtkWidget *widget, EmpathyMainWindow *window); static void main_window_chat_new_message_cb (GtkWidget *widget, @@ -161,16 +161,16 @@ static gboolean main_window_configure_event_timeout_cb (EmpathyMainWindo static gboolean main_window_configure_event_cb (GtkWidget *widget, GdkEventConfigure *event, EmpathyMainWindow *window); -static void main_window_notify_show_offline_cb (GossipConf *conf, +static void main_window_notify_show_offline_cb (EmpathyConf *conf, const gchar *key, gpointer check_menu_item); -static void main_window_notify_show_avatars_cb (GossipConf *conf, +static void main_window_notify_show_avatars_cb (EmpathyConf *conf, const gchar *key, EmpathyMainWindow *window); -static void main_window_notify_compact_contact_list_cb (GossipConf *conf, +static void main_window_notify_compact_contact_list_cb (EmpathyConf *conf, const gchar *key, EmpathyMainWindow *window); -static void main_window_notify_sort_criterium_cb (GossipConf *conf, +static void main_window_notify_sort_criterium_cb (EmpathyConf *conf, const gchar *key, EmpathyMainWindow *window); @@ -180,7 +180,7 @@ empathy_main_window_show (void) static EmpathyMainWindow *window = NULL; EmpathyContactList *list_iface; GladeXML *glade; - GossipConf *conf; + EmpathyConf *conf; GtkWidget *sw; GtkWidget *show_offline_widget; GtkWidget *ebox; @@ -199,7 +199,7 @@ empathy_main_window_show (void) window = g_new0 (EmpathyMainWindow, 1); /* Set up interface */ - glade = gossip_glade_get_file ("empathy-main-window.glade", + glade = empathy_glade_get_file ("empathy-main-window.glade", "main_window", NULL, "main_window", &window->window, @@ -214,7 +214,7 @@ empathy_main_window_show (void) "roster_scrolledwindow", &sw, NULL); - gossip_glade_connect (glade, + empathy_glade_connect (glade, window, "main_window", "destroy", main_window_destroy_cb, "main_window", "configure_event", main_window_configure_event_cb, @@ -239,7 +239,7 @@ empathy_main_window_show (void) g_object_unref (glade); window->tooltips = g_object_ref_sink (gtk_tooltips_new ()); - window->mc = gossip_mission_control_new (); + window->mc = empathy_mission_control_new (); dbus_g_proxy_connect_signal (DBUS_G_PROXY (window->mc), "AccountStatusChanged", G_CALLBACK (main_window_status_changed_cb), window, NULL); @@ -251,7 +251,7 @@ empathy_main_window_show (void) gtk_widget_hide (window->edit_context_separator); /* Set up presence chooser */ - window->presence_chooser = gossip_presence_chooser_new (); + window->presence_chooser = empathy_presence_chooser_new (); gtk_widget_show (window->presence_chooser); item = gtk_tool_item_new (); gtk_widget_show (GTK_WIDGET (item)); @@ -284,12 +284,12 @@ empathy_main_window_show (void) window); /* Set up contact list. */ - gossip_status_presets_get_all (); + empathy_status_presets_get_all (); list_iface = EMPATHY_CONTACT_LIST (empathy_contact_manager_new ()); empathy_contact_list_setup (list_iface); - window->list_store = gossip_contact_list_store_new (list_iface); - window->list_view = gossip_contact_list_view_new (window->list_store); + window->list_store = empathy_contact_list_store_new (list_iface); + window->list_view = empathy_contact_list_view_new (window->list_store); g_object_unref (list_iface); gtk_widget_show (GTK_WIDGET (window->list_view)); @@ -300,13 +300,13 @@ empathy_main_window_show (void) main_window_accels_load (); /* Set window size. */ - gossip_geometry_load (GEOMETRY_NAME, &x, &y, &w, &h); + empathy_geometry_load (GEOMETRY_NAME, &x, &y, &w, &h); if (w >= 1 && h >= 1) { /* Use the defaults from the glade file if we * don't have good w, h geometry. */ - gossip_debug (DEBUG_DOMAIN, "Configuring window default size w:%d, h:%d", w, h); + empathy_debug (DEBUG_DOMAIN, "Configuring window default size w:%d, h:%d", w, h); gtk_window_set_default_size (GTK_WINDOW (window->window), w, h); } @@ -314,18 +314,18 @@ empathy_main_window_show (void) /* Let the window manager position it if we * don't have good x, y coordinates. */ - gossip_debug (DEBUG_DOMAIN, "Configuring window default position x:%d, y:%d", x, y); + empathy_debug (DEBUG_DOMAIN, "Configuring window default position x:%d, y:%d", x, y); gtk_window_move (GTK_WINDOW (window->window), x, y); } - conf = gossip_conf_get (); + conf = empathy_conf_get (); /* Show offline ? */ - gossip_conf_get_bool (conf, - GOSSIP_PREFS_CONTACTS_SHOW_OFFLINE, + empathy_conf_get_bool (conf, + EMPATHY_PREFS_CONTACTS_SHOW_OFFLINE, &show_offline); - gossip_conf_notify_add (conf, - GOSSIP_PREFS_CONTACTS_SHOW_OFFLINE, + empathy_conf_notify_add (conf, + EMPATHY_PREFS_CONTACTS_SHOW_OFFLINE, main_window_notify_show_offline_cb, show_offline_widget); @@ -333,32 +333,32 @@ empathy_main_window_show (void) show_offline); /* Show avatars ? */ - gossip_conf_get_bool (conf, - GOSSIP_PREFS_UI_SHOW_AVATARS, + empathy_conf_get_bool (conf, + EMPATHY_PREFS_UI_SHOW_AVATARS, &show_avatars); - gossip_conf_notify_add (conf, - GOSSIP_PREFS_UI_SHOW_AVATARS, - (GossipConfNotifyFunc) main_window_notify_show_avatars_cb, + empathy_conf_notify_add (conf, + EMPATHY_PREFS_UI_SHOW_AVATARS, + (EmpathyConfNotifyFunc) main_window_notify_show_avatars_cb, window); - gossip_contact_list_store_set_show_avatars (window->list_store, show_avatars); + empathy_contact_list_store_set_show_avatars (window->list_store, show_avatars); /* Is compact ? */ - gossip_conf_get_bool (conf, - GOSSIP_PREFS_UI_COMPACT_CONTACT_LIST, + empathy_conf_get_bool (conf, + EMPATHY_PREFS_UI_COMPACT_CONTACT_LIST, &compact_contact_list); - gossip_conf_notify_add (conf, - GOSSIP_PREFS_UI_COMPACT_CONTACT_LIST, - (GossipConfNotifyFunc) main_window_notify_compact_contact_list_cb, + empathy_conf_notify_add (conf, + EMPATHY_PREFS_UI_COMPACT_CONTACT_LIST, + (EmpathyConfNotifyFunc) main_window_notify_compact_contact_list_cb, window); - gossip_contact_list_store_set_is_compact (window->list_store, compact_contact_list); + empathy_contact_list_store_set_is_compact (window->list_store, compact_contact_list); /* Sort criterium */ - gossip_conf_notify_add (conf, - GOSSIP_PREFS_CONTACTS_SORT_CRITERIUM, - (GossipConfNotifyFunc) main_window_notify_sort_criterium_cb, + empathy_conf_notify_add (conf, + EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM, + (EmpathyConfNotifyFunc) main_window_notify_sort_criterium_cb, window); main_window_notify_sort_criterium_cb (conf, - GOSSIP_PREFS_CONTACTS_SORT_CRITERIUM, + EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM, window); main_window_update_status (window); @@ -396,8 +396,8 @@ main_window_favorite_chatroom_menu_setup (EmpathyMainWindow *window) { GList *chatrooms, *l; - window->chatroom_manager = gossip_chatroom_manager_new (); - chatrooms = gossip_chatroom_manager_get_chatrooms (window->chatroom_manager, NULL); + window->chatroom_manager = empathy_chatroom_manager_new (); + chatrooms = empathy_chatroom_manager_get_chatrooms (window->chatroom_manager, NULL); window->room_menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (window->room)); for (l = chatrooms; l; l = l->next) { @@ -421,8 +421,8 @@ main_window_favorite_chatroom_menu_setup (EmpathyMainWindow *window) } static void -main_window_favorite_chatroom_menu_added_cb (GossipChatroomManager *manager, - GossipChatroom *chatroom, +main_window_favorite_chatroom_menu_added_cb (EmpathyChatroomManager *manager, + EmpathyChatroom *chatroom, EmpathyMainWindow *window) { main_window_favorite_chatroom_menu_add (window, chatroom); @@ -431,8 +431,8 @@ main_window_favorite_chatroom_menu_added_cb (GossipChatroomManager *manager, } static void -main_window_favorite_chatroom_menu_removed_cb (GossipChatroomManager *manager, - GossipChatroom *chatroom, +main_window_favorite_chatroom_menu_removed_cb (EmpathyChatroomManager *manager, + EmpathyChatroom *chatroom, EmpathyMainWindow *window) { GtkWidget *menu_item; @@ -447,7 +447,7 @@ main_window_favorite_chatroom_menu_removed_cb (GossipChatroomManager *manager, static void main_window_favorite_chatroom_menu_activate_cb (GtkMenuItem *menu_item, - GossipChatroom *chatroom) + EmpathyChatroom *chatroom) { main_window_favorite_chatroom_join (chatroom); } @@ -457,7 +457,7 @@ main_window_favorite_chatroom_menu_update (EmpathyMainWindow *window) { GList *chatrooms; - chatrooms = gossip_chatroom_manager_get_chatrooms (window->chatroom_manager, NULL); + chatrooms = empathy_chatroom_manager_get_chatrooms (window->chatroom_manager, NULL); if (chatrooms) { gtk_widget_show (window->room_sep); @@ -471,7 +471,7 @@ main_window_favorite_chatroom_menu_update (EmpathyMainWindow *window) static void main_window_favorite_chatroom_menu_add (EmpathyMainWindow *window, - GossipChatroom *chatroom) + EmpathyChatroom *chatroom) { GtkWidget *menu_item; const gchar *name; @@ -480,7 +480,7 @@ main_window_favorite_chatroom_menu_add (EmpathyMainWindow *window, return; } - name = gossip_chatroom_get_name (chatroom); + name = empathy_chatroom_get_name (chatroom); menu_item = gtk_menu_item_new_with_label (name); g_object_set_data (G_OBJECT (chatroom), "menu_item", menu_item); @@ -495,17 +495,17 @@ main_window_favorite_chatroom_menu_add (EmpathyMainWindow *window, } static void -main_window_favorite_chatroom_join (GossipChatroom *chatroom) +main_window_favorite_chatroom_join (EmpathyChatroom *chatroom) { MissionControl *mc; McAccount *account; const gchar *room; - mc = gossip_mission_control_new (); - account = gossip_chatroom_get_account (chatroom); - room = gossip_chatroom_get_room (chatroom); + mc = empathy_mission_control_new (); + account = empathy_chatroom_get_account (chatroom); + room = empathy_chatroom_get_room (chatroom); - gossip_debug (DEBUG_DOMAIN, "Requesting channel for '%s'", room); + empathy_debug (DEBUG_DOMAIN, "Requesting channel for '%s'", room); mission_control_request_channel_with_string_handle (mc, account, @@ -527,21 +527,21 @@ static void main_window_chat_new_message_cb (GtkWidget *widget, EmpathyMainWindow *window) { - //gossip_new_message_dialog_show (GTK_WINDOW (window->window)); + //empathy_new_message_dialog_show (GTK_WINDOW (window->window)); } static void main_window_chat_history_cb (GtkWidget *widget, EmpathyMainWindow *window) { - gossip_log_window_show (NULL, NULL, FALSE, GTK_WINDOW (window->window)); + empathy_log_window_show (NULL, NULL, FALSE, GTK_WINDOW (window->window)); } static void main_window_room_join_new_cb (GtkWidget *widget, EmpathyMainWindow *window) { - gossip_new_chatroom_dialog_show (GTK_WINDOW (window->window)); + empathy_new_chatroom_dialog_show (GTK_WINDOW (window->window)); } static void @@ -550,7 +550,7 @@ main_window_room_join_favorites_cb (GtkWidget *widget, { GList *chatrooms, *l; - chatrooms = gossip_chatroom_manager_get_chatrooms (window->chatroom_manager, NULL); + chatrooms = empathy_chatroom_manager_get_chatrooms (window->chatroom_manager, NULL); for (l = chatrooms; l; l = l->next) { main_window_favorite_chatroom_join (l->data); } @@ -561,7 +561,7 @@ static void main_window_room_manage_favorites_cb (GtkWidget *widget, EmpathyMainWindow *window) { - gossip_chatrooms_window_show (GTK_WINDOW (window->window)); + empathy_chatrooms_window_show (GTK_WINDOW (window->window)); } static void @@ -579,14 +579,14 @@ main_window_chat_show_offline_cb (GtkCheckMenuItem *item, current = gtk_check_menu_item_get_active (item); - gossip_conf_set_bool (gossip_conf_get (), - GOSSIP_PREFS_CONTACTS_SHOW_OFFLINE, + empathy_conf_set_bool (empathy_conf_get (), + EMPATHY_PREFS_CONTACTS_SHOW_OFFLINE, current); /* Turn off sound just while we alter the contact list. */ - // FIXME: gossip_sound_set_enabled (FALSE); - gossip_contact_list_store_set_show_offline (window->list_store, current); - //gossip_sound_set_enabled (TRUE); + // FIXME: empathy_sound_set_enabled (FALSE); + empathy_contact_list_store_set_show_offline (window->list_store, current); + //empathy_sound_set_enabled (TRUE); } static gboolean @@ -594,14 +594,14 @@ main_window_edit_button_press_event_cb (GtkWidget *widget, GdkEventButton *event, EmpathyMainWindow *window) { - GossipContact *contact; + EmpathyContact *contact; gchar *group; if (!event->button == 1) { return FALSE; } - group = gossip_contact_list_view_get_selected_group (window->list_view); + group = empathy_contact_list_view_get_selected_group (window->list_view); if (group) { GtkMenuItem *item; GtkWidget *label; @@ -614,7 +614,7 @@ main_window_edit_button_press_event_cb (GtkWidget *widget, gtk_widget_show (window->edit_context); gtk_widget_show (window->edit_context_separator); - submenu = gossip_contact_list_view_get_group_menu (window->list_view); + submenu = empathy_contact_list_view_get_group_menu (window->list_view); gtk_menu_item_set_submenu (item, submenu); g_free (group); @@ -622,7 +622,7 @@ main_window_edit_button_press_event_cb (GtkWidget *widget, return FALSE; } - contact = gossip_contact_list_view_get_selected (window->list_view); + contact = empathy_contact_list_view_get_selected (window->list_view); if (contact) { GtkMenuItem *item; GtkWidget *label; @@ -635,7 +635,7 @@ main_window_edit_button_press_event_cb (GtkWidget *widget, gtk_widget_show (window->edit_context); gtk_widget_show (window->edit_context_separator); - submenu = gossip_contact_list_view_get_contact_menu (window->list_view, + submenu = empathy_contact_list_view_get_contact_menu (window->list_view, contact); gtk_menu_item_set_submenu (item, submenu); @@ -654,35 +654,35 @@ static void main_window_edit_accounts_cb (GtkWidget *widget, EmpathyMainWindow *window) { - gossip_accounts_dialog_show (GTK_WINDOW (window->window)); + empathy_accounts_dialog_show (GTK_WINDOW (window->window)); } static void main_window_edit_personal_information_cb (GtkWidget *widget, EmpathyMainWindow *window) { - //gossip_vcard_dialog_show (GTK_WINDOW (window->window)); + //empathy_vcard_dialog_show (GTK_WINDOW (window->window)); } static void main_window_edit_preferences_cb (GtkWidget *widget, EmpathyMainWindow *window) { - gossip_preferences_show (GTK_WINDOW (window->window)); + empathy_preferences_show (GTK_WINDOW (window->window)); } static void main_window_help_about_cb (GtkWidget *widget, EmpathyMainWindow *window) { - gossip_about_dialog_new (GTK_WINDOW (window->window)); + empathy_about_dialog_new (GTK_WINDOW (window->window)); } static void main_window_help_contents_cb (GtkWidget *widget, EmpathyMainWindow *window) { - //gossip_help_show (); + //empathy_help_show (); } static gboolean @@ -695,7 +695,7 @@ main_window_throbber_button_press_event_cb (GtkWidget *throbber_ebox, return FALSE; } - gossip_accounts_dialog_show (GTK_WINDOW (window->window)); + empathy_accounts_dialog_show (GTK_WINDOW (window->window)); return FALSE; } @@ -770,7 +770,7 @@ main_window_accels_load (void) filename = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, ACCELS_FILENAME, NULL); if (g_file_test (filename, G_FILE_TEST_EXISTS)) { - gossip_debug (DEBUG_DOMAIN, "Loading from:'%s'", filename); + empathy_debug (DEBUG_DOMAIN, "Loading from:'%s'", filename); gtk_accel_map_load (filename); } @@ -788,7 +788,7 @@ main_window_accels_save (void) file_with_path = g_build_filename (dir, ACCELS_FILENAME, NULL); g_free (dir); - gossip_debug (DEBUG_DOMAIN, "Saving to:'%s'", file_with_path); + empathy_debug (DEBUG_DOMAIN, "Saving to:'%s'", file_with_path); gtk_accel_map_save (file_with_path); g_free (file_with_path); @@ -833,7 +833,7 @@ main_window_configure_event_timeout_cb (EmpathyMainWindow *window) gtk_window_get_size (GTK_WINDOW (window->window), &w, &h); gtk_window_get_position (GTK_WINDOW (window->window), &x, &y); - gossip_geometry_save (GEOMETRY_NAME, x, y, w, h); + empathy_geometry_save (GEOMETRY_NAME, x, y, w, h); window->size_timeout_id = 0; @@ -857,63 +857,63 @@ main_window_configure_event_cb (GtkWidget *widget, } static void -main_window_notify_show_offline_cb (GossipConf *conf, +main_window_notify_show_offline_cb (EmpathyConf *conf, const gchar *key, gpointer check_menu_item) { gboolean show_offline; - if (gossip_conf_get_bool (conf, key, &show_offline)) { + if (empathy_conf_get_bool (conf, key, &show_offline)) { gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (check_menu_item), show_offline); } } static void -main_window_notify_show_avatars_cb (GossipConf *conf, +main_window_notify_show_avatars_cb (EmpathyConf *conf, const gchar *key, EmpathyMainWindow *window) { gboolean show_avatars; - if (gossip_conf_get_bool (conf, key, &show_avatars)) { - gossip_contact_list_store_set_show_avatars (window->list_store, + if (empathy_conf_get_bool (conf, key, &show_avatars)) { + empathy_contact_list_store_set_show_avatars (window->list_store, show_avatars); } } static void -main_window_notify_compact_contact_list_cb (GossipConf *conf, +main_window_notify_compact_contact_list_cb (EmpathyConf *conf, const gchar *key, EmpathyMainWindow *window) { gboolean compact_contact_list; - if (gossip_conf_get_bool (conf, key, &compact_contact_list)) { - gossip_contact_list_store_set_is_compact (window->list_store, + if (empathy_conf_get_bool (conf, key, &compact_contact_list)) { + empathy_contact_list_store_set_is_compact (window->list_store, compact_contact_list); } } static void -main_window_notify_sort_criterium_cb (GossipConf *conf, +main_window_notify_sort_criterium_cb (EmpathyConf *conf, const gchar *key, EmpathyMainWindow *window) { gchar *str = NULL; - if (gossip_conf_get_string (conf, key, &str)) { + if (empathy_conf_get_string (conf, key, &str)) { GType type; GEnumClass *enum_class; GEnumValue *enum_value; - type = gossip_contact_list_store_sort_get_type (); + type = empathy_contact_list_store_sort_get_type (); enum_class = G_ENUM_CLASS (g_type_class_peek (type)); enum_value = g_enum_get_value_by_nick (enum_class, str); g_free (str); if (enum_value) { - gossip_contact_list_store_set_sort_criterium (window->list_store, + empathy_contact_list_store_set_sort_criterium (window->list_store, enum_value->value); } } diff --git a/libempathy-gtk/empathy-new-chatroom-dialog.c b/libempathy-gtk/empathy-new-chatroom-dialog.c new file mode 100644 index 00000000..31f61078 --- /dev/null +++ b/libempathy-gtk/empathy-new-chatroom-dialog.c @@ -0,0 +1,690 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Martyn Russell + * Xavier Claessens + */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "empathy-new-chatroom-dialog.h" +#include "empathy-account-chooser.h" +//#include "empathy-chatrooms-window.h" +#include "empathy-ui-utils.h" +#include "ephy-spinner.h" + +#define DEBUG_DOMAIN "NewChatroomDialog" + +typedef struct { + GtkWidget *window; + + GtkWidget *vbox_widgets; + + GtkWidget *hbox_account; + GtkWidget *label_account; + GtkWidget *account_chooser; + + GtkWidget *hbox_server; + GtkWidget *label_server; + GtkWidget *entry_server; + GtkWidget *togglebutton_refresh; + + GtkWidget *hbox_room; + GtkWidget *label_room; + GtkWidget *entry_room; + + GtkWidget *hbox_nick; + GtkWidget *label_nick; + GtkWidget *entry_nick; + + GtkWidget *vbox_browse; + GtkWidget *image_status; + GtkWidget *label_status; + GtkWidget *hbox_status; + GtkWidget *throbber; + GtkWidget *treeview; + GtkTreeModel *model; + GtkTreeModel *filter; + + GtkWidget *button_join; + GtkWidget *button_close; +} EmpathyNewChatroomDialog; + +typedef struct { + guint handle; + gchar *channel_type; + gchar *name; + gchar *id; +} EmpathyRoomListItem; + +enum { + COL_IMAGE, + COL_NAME, + COL_POINTER, + COL_COUNT +}; + +static void new_chatroom_dialog_response_cb (GtkWidget *widget, + gint response, + EmpathyNewChatroomDialog *dialog); +static void new_chatroom_dialog_destroy_cb (GtkWidget *widget, + EmpathyNewChatroomDialog *dialog); +static void new_chatroom_dialog_model_setup (EmpathyNewChatroomDialog *dialog); +static void new_chatroom_dialog_model_add_columns (EmpathyNewChatroomDialog *dialog); +static void new_chatroom_dialog_update_buttons (EmpathyNewChatroomDialog *dialog); +static void new_chatroom_dialog_update_widgets (EmpathyNewChatroomDialog *dialog); +static void new_chatroom_dialog_account_changed_cb (GtkComboBox *combobox, + EmpathyNewChatroomDialog *dialog); +static void new_chatroom_dialog_model_add (EmpathyNewChatroomDialog *dialog, + EmpathyRoomListItem *item); +static void new_chatroom_dialog_model_clear (EmpathyNewChatroomDialog *dialog); +static GList * new_chatroom_dialog_model_get_selected (EmpathyNewChatroomDialog *dialog); +static gboolean new_chatroom_dialog_model_filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + EmpathyNewChatroomDialog *dialog); +static void new_chatroom_dialog_model_row_activated_cb (GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + EmpathyNewChatroomDialog *dialog); +static void new_chatroom_dialog_model_row_inserted_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + EmpathyNewChatroomDialog *dialog); +static void new_chatroom_dialog_model_row_deleted_cb (GtkTreeModel *model, + GtkTreePath *path, + EmpathyNewChatroomDialog *dialog); +static void new_chatroom_dialog_model_selection_changed (GtkTreeSelection *selection, + EmpathyNewChatroomDialog *dialog); +static void new_chatroom_dialog_join (EmpathyNewChatroomDialog *dialog); +static void new_chatroom_dialog_entry_changed_cb (GtkWidget *entry, + EmpathyNewChatroomDialog *dialog); +static void new_chatroom_dialog_browse_start (EmpathyNewChatroomDialog *dialog); +static void new_chatroom_dialog_browse_stop (EmpathyNewChatroomDialog *dialog); +static void new_chatroom_dialog_entry_server_activate_cb (GtkWidget *widget, + EmpathyNewChatroomDialog *dialog); +static void new_chatroom_dialog_togglebutton_refresh_toggled_cb (GtkWidget *widget, + EmpathyNewChatroomDialog *dialog); + +static EmpathyNewChatroomDialog *dialog_p = NULL; + +void +empathy_new_chatroom_dialog_show (GtkWindow *parent) +{ + EmpathyNewChatroomDialog *dialog; + GladeXML *glade; + GList *accounts; + gint account_num; + GtkSizeGroup *size_group; + + if (dialog_p) { + gtk_window_present (GTK_WINDOW (dialog_p->window)); + return; + } + + dialog_p = dialog = g_new0 (EmpathyNewChatroomDialog, 1); + + glade = empathy_glade_get_file ("empathy-new-chatroom-dialog.glade", + "new_chatroom_dialog", + NULL, + "new_chatroom_dialog", &dialog->window, + "hbox_account", &dialog->hbox_account, + "label_account", &dialog->label_account, + "vbox_widgets", &dialog->vbox_widgets, + "label_server", &dialog->label_server, + "label_room", &dialog->label_room, + "label_nick", &dialog->label_nick, + "hbox_server", &dialog->hbox_server, + "hbox_room", &dialog->hbox_room, + "hbox_nick", &dialog->hbox_nick, + "entry_server", &dialog->entry_server, + "entry_room", &dialog->entry_room, + "entry_nick", &dialog->entry_nick, + "togglebutton_refresh", &dialog->togglebutton_refresh, + "vbox_browse", &dialog->vbox_browse, + "image_status", &dialog->image_status, + "label_status", &dialog->label_status, + "hbox_status", &dialog->hbox_status, + "treeview", &dialog->treeview, + "button_join", &dialog->button_join, + NULL); + + empathy_glade_connect (glade, + dialog, + "new_chatroom_dialog", "response", new_chatroom_dialog_response_cb, + "new_chatroom_dialog", "destroy", new_chatroom_dialog_destroy_cb, + "entry_nick", "changed", new_chatroom_dialog_entry_changed_cb, + "entry_server", "changed", new_chatroom_dialog_entry_changed_cb, + "entry_server", "activate", new_chatroom_dialog_entry_server_activate_cb, + "entry_room", "changed", new_chatroom_dialog_entry_changed_cb, + "togglebutton_refresh", "toggled", new_chatroom_dialog_togglebutton_refresh_toggled_cb, + NULL); + + g_object_unref (glade); + + g_object_add_weak_pointer (G_OBJECT (dialog->window), (gpointer) &dialog_p); + + /* Label alignment */ + size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + + gtk_size_group_add_widget (size_group, dialog->label_account); + gtk_size_group_add_widget (size_group, dialog->label_server); + gtk_size_group_add_widget (size_group, dialog->label_room); + gtk_size_group_add_widget (size_group, dialog->label_nick); + + g_object_unref (size_group); + + /* Account chooser for custom */ + dialog->account_chooser = empathy_account_chooser_new (); + gtk_box_pack_start (GTK_BOX (dialog->hbox_account), + dialog->account_chooser, + TRUE, TRUE, 0); + gtk_widget_show (dialog->account_chooser); + + g_signal_connect (GTK_COMBO_BOX (dialog->account_chooser), "changed", + G_CALLBACK (new_chatroom_dialog_account_changed_cb), + dialog); + + /* Populate */ + accounts = mc_accounts_list (); + account_num = g_list_length (accounts); + + g_list_foreach (accounts, (GFunc) g_object_unref, NULL); + g_list_free (accounts); + + if (account_num > 1) { + gtk_widget_show (dialog->hbox_account); + } else { + /* Show no accounts combo box */ + gtk_widget_hide (dialog->hbox_account); + } + + /* Add throbber */ + dialog->throbber = ephy_spinner_new (); + ephy_spinner_set_size (EPHY_SPINNER (dialog->throbber), GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_widget_show (dialog->throbber); + + gtk_box_pack_start (GTK_BOX (dialog->hbox_status), dialog->throbber, + FALSE, FALSE, 0); + + /* Set up chatrooms treeview */ + new_chatroom_dialog_model_setup (dialog); + + /* Set things up according to the account type */ + new_chatroom_dialog_update_widgets (dialog); + + if (parent) { + gtk_window_set_transient_for (GTK_WINDOW (dialog->window), + GTK_WINDOW (parent)); + } + + gtk_widget_show (dialog->window); +} + +static void +new_chatroom_dialog_response_cb (GtkWidget *widget, + gint response, + EmpathyNewChatroomDialog *dialog) +{ + if (response == GTK_RESPONSE_OK) { + new_chatroom_dialog_join (dialog); + } + + gtk_widget_destroy (widget); +} + +static void +new_chatroom_dialog_destroy_cb (GtkWidget *widget, + EmpathyNewChatroomDialog *dialog) +{ + g_object_unref (dialog->model); + g_object_unref (dialog->filter); + + g_free (dialog); +} + +static void +new_chatroom_dialog_model_setup (EmpathyNewChatroomDialog *dialog) +{ + GtkTreeView *view; + GtkListStore *store; + GtkTreeSelection *selection; + + /* View */ + view = GTK_TREE_VIEW (dialog->treeview); + + g_signal_connect (view, "row-activated", + G_CALLBACK (new_chatroom_dialog_model_row_activated_cb), + dialog); + + /* Store/Model */ + store = gtk_list_store_new (COL_COUNT, + G_TYPE_STRING, /* Image */ + G_TYPE_STRING, /* Text */ + G_TYPE_POINTER); /* infos */ + + dialog->model = GTK_TREE_MODEL (store); + + /* Filter */ + dialog->filter = gtk_tree_model_filter_new (dialog->model, NULL); + + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (dialog->filter), + (GtkTreeModelFilterVisibleFunc) + new_chatroom_dialog_model_filter_func, + dialog, + NULL); + + gtk_tree_view_set_model (view, dialog->filter); + + g_signal_connect (dialog->filter, "row-inserted", + G_CALLBACK (new_chatroom_dialog_model_row_inserted_cb), + dialog); + g_signal_connect (dialog->filter, "row-deleted", + G_CALLBACK (new_chatroom_dialog_model_row_deleted_cb), + dialog); + + /* Selection */ + selection = gtk_tree_view_get_selection (view); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), + COL_NAME, GTK_SORT_ASCENDING); + + g_signal_connect (selection, "changed", + G_CALLBACK (new_chatroom_dialog_model_selection_changed), dialog); + + /* Columns */ + new_chatroom_dialog_model_add_columns (dialog); +} + +static void +new_chatroom_dialog_model_add_columns (EmpathyNewChatroomDialog *dialog) +{ + GtkTreeView *view; + GtkTreeViewColumn *column; + GtkCellRenderer *cell; + + view = GTK_TREE_VIEW (dialog->treeview); + gtk_tree_view_set_headers_visible (view, FALSE); + + /* Chatroom pointer */ + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_title (column, _("Chat Rooms")); + + cell = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, cell, FALSE); + + cell = gtk_cell_renderer_text_new (); + g_object_set (cell, + "xpad", (guint) 4, + "ypad", (guint) 1, + "ellipsize", PANGO_ELLIPSIZE_END, + NULL); + + gtk_tree_view_column_pack_start (column, cell, TRUE); + + gtk_tree_view_column_set_expand (column, TRUE); + gtk_tree_view_append_column (view, column); +} + +static void +new_chatroom_dialog_update_buttons (EmpathyNewChatroomDialog *dialog) +{ + GtkButton *button; + GtkWidget *image; + GtkTreeView *view; + GtkTreeModel *model; + guint items; + const gchar *room; + + /* Sort out Join button. */ + button = GTK_BUTTON (dialog->button_join); + + image = gtk_button_get_image (button); + if (!image) { + image = gtk_image_new (); + gtk_button_set_image (button, image); + } + //gtk_button_set_use_stock (button, FALSE); + + room = gtk_entry_get_text (GTK_ENTRY (dialog->entry_room)); + + /* Collect necessary information first. */ + view = GTK_TREE_VIEW (dialog->treeview); + model = gtk_tree_view_get_model (view); + items = gtk_tree_model_iter_n_children (model, NULL); + + if (items < 1 && !G_STR_EMPTY (room)) { + gtk_button_set_label (button, _("Create")); + gtk_image_set_from_stock (GTK_IMAGE (image), + GTK_STOCK_NEW, + GTK_ICON_SIZE_BUTTON); + } else { + gtk_button_set_label (button, _("Join")); + gtk_image_set_from_stock (GTK_IMAGE (image), + GTK_STOCK_EXECUTE, + GTK_ICON_SIZE_BUTTON); + } + + gtk_widget_set_sensitive (dialog->button_join, !G_STR_EMPTY (room)); +} + +static void +new_chatroom_dialog_update_widgets (EmpathyNewChatroomDialog *dialog) +{ + EmpathyAccountChooser *account_chooser; + McAccount *account; + McProfile *profile; + const gchar *protocol; + + account_chooser = EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser); + account = empathy_account_chooser_get_account (account_chooser); + profile = mc_account_get_profile (account); + protocol = mc_profile_get_protocol_name (profile); + + /* hardcode here known protocols */ + if (strcmp (protocol, "jabber") == 0) { + const gchar *server; + + server = mc_profile_get_default_account_domain (profile); + if (server) { + gchar *conference_server; + + conference_server = g_strconcat ("conference.", + server, NULL); + gtk_entry_set_text (GTK_ENTRY (dialog->entry_server), + conference_server); + g_free (conference_server); + } + + gtk_widget_show (dialog->hbox_server); + gtk_widget_show (dialog->hbox_nick); + gtk_widget_show (dialog->vbox_browse); + + } + else if (strcmp (protocol, "salut") == 0) { + gtk_widget_hide (dialog->hbox_server); + gtk_widget_show (dialog->hbox_nick); + gtk_widget_show (dialog->vbox_browse); + } + else if (strcmp (protocol, "irc") == 0) { + gtk_widget_hide (dialog->hbox_server); + gtk_widget_hide (dialog->hbox_nick); + gtk_widget_show (dialog->vbox_browse); + } else { + gtk_widget_hide (dialog->hbox_server); + gtk_widget_hide (dialog->hbox_nick); + gtk_widget_hide (dialog->vbox_browse); + } + + new_chatroom_dialog_update_buttons (dialog); + + /* Final set up of the dialog */ + gtk_widget_grab_focus (dialog->entry_room); + + g_object_unref (account); + g_object_unref (profile); +} + +static void +new_chatroom_dialog_account_changed_cb (GtkComboBox *combobox, + EmpathyNewChatroomDialog *dialog) +{ + new_chatroom_dialog_update_widgets (dialog); +} + +static void +new_chatroom_dialog_model_add (EmpathyNewChatroomDialog *dialog, + EmpathyRoomListItem *item) +{ + GtkTreeView *view; + GtkTreeSelection *selection; + GtkListStore *store; + GtkTreeIter iter; + + /* Add to model */ + view = GTK_TREE_VIEW (dialog->treeview); + selection = gtk_tree_view_get_selection (view); + store = GTK_LIST_STORE (dialog->model); + + gtk_list_store_append (store, &iter); + + gtk_list_store_set (store, &iter, + COL_NAME, item->name, + COL_POINTER, item, + -1); +} + +static void +new_chatroom_dialog_model_clear (EmpathyNewChatroomDialog *dialog) +{ + GtkListStore *store; + + store = GTK_LIST_STORE (dialog->model); + gtk_list_store_clear (store); +} + +static GList * +new_chatroom_dialog_model_get_selected (EmpathyNewChatroomDialog *dialog) +{ + GtkTreeView *view; + GtkTreeModel *model; + GtkTreeSelection *selection; + GList *rows, *l; + GList *chatrooms = NULL; + + view = GTK_TREE_VIEW (dialog->treeview); + selection = gtk_tree_view_get_selection (view); + model = gtk_tree_view_get_model (view); + + rows = gtk_tree_selection_get_selected_rows (selection, NULL); + for (l = rows; l; l = l->next) { + GtkTreeIter iter; + EmpathyRoomListItem *chatroom; + + if (!gtk_tree_model_get_iter (model, &iter, l->data)) { + continue; + } + + gtk_tree_model_get (model, &iter, COL_POINTER, &chatroom, -1); + chatrooms = g_list_append (chatrooms, chatroom); + } + + g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL); + g_list_free (rows); + + return chatrooms; +} + +static gboolean +new_chatroom_dialog_model_filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + EmpathyNewChatroomDialog *dialog) +{ + EmpathyRoomListItem *chatroom; + const gchar *text; + gchar *room_nocase; + gchar *text_nocase; + gboolean found = FALSE; + + gtk_tree_model_get (model, iter, COL_POINTER, &chatroom, -1); + + if (!chatroom) { + return TRUE; + } + + text = gtk_entry_get_text (GTK_ENTRY (dialog->entry_room)); + + /* Casefold */ + room_nocase = g_utf8_casefold (chatroom->id, -1); + text_nocase = g_utf8_casefold (text, -1); + + /* Compare */ + if (g_utf8_strlen (text_nocase, -1) < 1 || + strstr (room_nocase, text_nocase)) { + found = TRUE; + } + + g_free (room_nocase); + g_free (text_nocase); + + return found; +} + +static void +new_chatroom_dialog_model_row_activated_cb (GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + EmpathyNewChatroomDialog *dialog) +{ + gtk_widget_activate (dialog->button_join); +} + +static void +new_chatroom_dialog_model_row_inserted_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + EmpathyNewChatroomDialog *dialog) +{ + new_chatroom_dialog_update_buttons (dialog); +} + +static void +new_chatroom_dialog_model_row_deleted_cb (GtkTreeModel *model, + GtkTreePath *path, + EmpathyNewChatroomDialog *dialog) +{ + new_chatroom_dialog_update_buttons (dialog); +} + +static void +new_chatroom_dialog_model_selection_changed (GtkTreeSelection *selection, + EmpathyNewChatroomDialog *dialog) +{ + new_chatroom_dialog_update_buttons (dialog); +} + +static void +new_chatroom_dialog_join (EmpathyNewChatroomDialog *dialog) +{ + McAccount *account; + EmpathyAccountChooser *account_chooser; + MissionControl *mc; + GList *chatrooms, *l; + const gchar *room; + const gchar *server = NULL; + gchar *room_name = NULL; + + chatrooms = new_chatroom_dialog_model_get_selected (dialog); + if (chatrooms) { + for (l = chatrooms; l; l = l->next) { + /* Join it */ + } + g_list_free (chatrooms); + return; + } + + room = gtk_entry_get_text (GTK_ENTRY (dialog->entry_room)); + if (GTK_WIDGET_VISIBLE (dialog->hbox_server)) { + server = gtk_entry_get_text (GTK_ENTRY (dialog->entry_server)); + } + account_chooser = EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser); + account = empathy_account_chooser_get_account (account_chooser); + + if (!G_STR_EMPTY (server)) { + room_name = g_strconcat (room, "@", server, NULL); + } else { + room_name = g_strdup (room); + } + + empathy_debug (DEBUG_DOMAIN, "Requesting channel for '%s'", room_name); + + mc = empathy_mission_control_new (); + mission_control_request_channel_with_string_handle (mc, + account, + TP_IFACE_CHANNEL_TYPE_TEXT, + room_name, + TP_HANDLE_TYPE_ROOM, + NULL, NULL); + g_free (room_name); + g_object_unref (mc); +} + +static void +new_chatroom_dialog_entry_changed_cb (GtkWidget *entry, + EmpathyNewChatroomDialog *dialog) +{ + if (entry == dialog->entry_room) { + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (dialog->filter)); + } + + new_chatroom_dialog_update_buttons (dialog); +} + +static void +new_chatroom_dialog_browse_start (EmpathyNewChatroomDialog *dialog) +{ + if (0) { + new_chatroom_dialog_model_clear (dialog); + new_chatroom_dialog_model_add (dialog, NULL); + } +} + +static void +new_chatroom_dialog_browse_stop (EmpathyNewChatroomDialog *dialog) +{ +} + +static void +new_chatroom_dialog_entry_server_activate_cb (GtkWidget *widget, + EmpathyNewChatroomDialog *dialog) +{ + new_chatroom_dialog_togglebutton_refresh_toggled_cb (dialog->togglebutton_refresh, + dialog); +} + +static void +new_chatroom_dialog_togglebutton_refresh_toggled_cb (GtkWidget *widget, + EmpathyNewChatroomDialog *dialog) +{ + gboolean toggled; + + toggled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if (toggled) { + new_chatroom_dialog_browse_start (dialog); + } else { + new_chatroom_dialog_browse_stop (dialog); + } +} + diff --git a/libempathy-gtk/empathy-new-chatroom-dialog.glade b/libempathy-gtk/empathy-new-chatroom-dialog.glade new file mode 100644 index 00000000..49bdadb6 --- /dev/null +++ b/libempathy-gtk/empathy-new-chatroom-dialog.glade @@ -0,0 +1,519 @@ + + + + + + + 5 + True + Join New + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 350 + False + False + gtk-new + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + False + + + + True + False + 6 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + -7 + + + + + + True + False + True + True + True + GTK_RELIEF_NORMAL + True + -5 + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-execute + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Join + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + 0 + False + True + GTK_PACK_END + + + + + + 5 + True + False + 18 + + + + True + False + 12 + + + + True + Account: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + True + + + + + + + + + 0 + True + True + + + + + + True + False + 6 + + + + True + False + 12 + + + + True + _Server: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + entry_server + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + * + False + 25 + + + 0 + True + True + + + + + + True + True + Re_fresh + True + GTK_RELIEF_NORMAL + True + False + False + + + 0 + False + False + + + + + 0 + True + True + + + + + + True + False + 12 + + + + True + _Room: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + entry_room + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + Enter the room name to join here or click on one or more rooms in the list. + True + True + True + 0 + + True + * + True + 32 + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + False + 12 + + + + True + _Nickname: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + entry_nick + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + * + False + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + False + 6 + + + + True + False + 6 + + + + True + False + 3 + + + + True + 2 + gtk-find + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Browse: + False + False + GTK_JUSTIFY_LEFT + True + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + True + True + + + + + 0 + True + True + + + + + + + + + 0 + True + True + + + + + + 150 + True + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + This list represents all chat rooms hosted on the server you have entered. + True + False + False + False + True + False + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + False + False + + + + + + + diff --git a/libempathy-gtk/empathy-new-chatroom-dialog.h b/libempathy-gtk/empathy-new-chatroom-dialog.h new file mode 100644 index 00000000..2a126085 --- /dev/null +++ b/libempathy-gtk/empathy-new-chatroom-dialog.h @@ -0,0 +1,34 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Martyn Russell + * Xavier Claessens + */ + +#ifndef __EMPATHY_NEW_CHATROOMS_WINDOW_H__ +#define __EMPATHY_NEW_CHATROOMS_WINDOW_H__ + +G_BEGIN_DECLS + +void empathy_new_chatroom_dialog_show (GtkWindow *parent); + +G_END_DECLS + +#endif /* __EMPATHY_NEW_CHATROOMS_WINDOW_H__ */ diff --git a/libempathy-gtk/empathy-preferences.c b/libempathy-gtk/empathy-preferences.c new file mode 100644 index 00000000..7c9a27b6 --- /dev/null +++ b/libempathy-gtk/empathy-preferences.c @@ -0,0 +1,985 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2003-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Richard Hult + * Martyn Russell + */ + +#include "config.h" + +#include + +#include +#include +#include + +#include + +#include "empathy-preferences.h" +#include "empathy-ui-utils.h" +#include "empathy-theme-manager.h" +#include "empathy-spell.h" +#include "empathy-contact-list-store.h" + +typedef struct { + GtkWidget *dialog; + + GtkWidget *notebook; + + GtkWidget *checkbutton_show_avatars; + GtkWidget *checkbutton_compact_contact_list; + GtkWidget *checkbutton_show_smileys; + GtkWidget *combobox_chat_theme; + GtkWidget *checkbutton_theme_chat_room; + GtkWidget *checkbutton_separate_chat_windows; + GtkWidget *radiobutton_contact_list_sort_by_name; + GtkWidget *radiobutton_contact_list_sort_by_state; + + GtkWidget *checkbutton_sounds_for_messages; + GtkWidget *checkbutton_sounds_when_busy; + GtkWidget *checkbutton_sounds_when_away; + GtkWidget *checkbutton_popups_when_available; + + GtkWidget *treeview_spell_checker; + GtkWidget *checkbutton_spell_checker; + + GList *notify_ids; +} EmpathyPreferences; + +static void preferences_setup_widgets (EmpathyPreferences *preferences); +static void preferences_languages_setup (EmpathyPreferences *preferences); +static void preferences_languages_add (EmpathyPreferences *preferences); +static void preferences_languages_save (EmpathyPreferences *preferences); +static gboolean preferences_languages_save_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gchar **languages); +static void preferences_languages_load (EmpathyPreferences *preferences); +static gboolean preferences_languages_load_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gchar **languages); +static void preferences_languages_cell_toggled_cb (GtkCellRendererToggle *cell, + gchar *path_string, + EmpathyPreferences *preferences); +static void preferences_themes_setup (EmpathyPreferences *preferences); +static void preferences_widget_sync_bool (const gchar *key, + GtkWidget *widget); +static void preferences_widget_sync_int (const gchar *key, + GtkWidget *widget); +static void preferences_widget_sync_string (const gchar *key, + GtkWidget *widget); +static void preferences_widget_sync_string_combo (const gchar *key, + GtkWidget *widget); +static void preferences_notify_int_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data); +static void preferences_notify_string_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data); +static void preferences_notify_string_combo_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data); +static void preferences_notify_bool_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data); +static void preferences_notify_sensitivity_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data); +static void preferences_hookup_spin_button (EmpathyPreferences *preferences, + const gchar *key, + GtkWidget *widget); +static void preferences_hookup_entry (EmpathyPreferences *preferences, + const gchar *key, + GtkWidget *widget); +static void preferences_hookup_toggle_button (EmpathyPreferences *preferences, + const gchar *key, + GtkWidget *widget); +static void preferences_hookup_radio_button (EmpathyPreferences *preferences, + const gchar *key, + GtkWidget *widget); +static void preferences_hookup_string_combo (EmpathyPreferences *preferences, + const gchar *key, + GtkWidget *widget); +static void preferences_hookup_sensitivity (EmpathyPreferences *preferences, + const gchar *key, + GtkWidget *widget); +static void preferences_spin_button_value_changed_cb (GtkWidget *button, + gpointer user_data); +static void preferences_entry_value_changed_cb (GtkWidget *entry, + gpointer user_data); +static void preferences_toggle_button_toggled_cb (GtkWidget *button, + gpointer user_data); +static void preferences_radio_button_toggled_cb (GtkWidget *button, + gpointer user_data); +static void preferences_string_combo_changed_cb (GtkWidget *button, + gpointer user_data); +static void preferences_destroy_cb (GtkWidget *widget, + EmpathyPreferences *preferences); +static void preferences_response_cb (GtkWidget *widget, + gint response, + EmpathyPreferences *preferences); + +enum { + COL_LANG_ENABLED, + COL_LANG_CODE, + COL_LANG_NAME, + COL_LANG_COUNT +}; + +enum { + COL_COMBO_VISIBLE_NAME, + COL_COMBO_NAME, + COL_COMBO_COUNT +}; + +static void +preferences_setup_widgets (EmpathyPreferences *preferences) +{ + preferences_hookup_toggle_button (preferences, + EMPATHY_PREFS_SOUNDS_FOR_MESSAGES, + preferences->checkbutton_sounds_for_messages); + preferences_hookup_toggle_button (preferences, + EMPATHY_PREFS_SOUNDS_WHEN_AWAY, + preferences->checkbutton_sounds_when_away); + preferences_hookup_toggle_button (preferences, + EMPATHY_PREFS_SOUNDS_WHEN_BUSY, + preferences->checkbutton_sounds_when_busy); + preferences_hookup_toggle_button (preferences, + EMPATHY_PREFS_POPUPS_WHEN_AVAILABLE, + preferences->checkbutton_popups_when_available); + + preferences_hookup_sensitivity (preferences, + EMPATHY_PREFS_SOUNDS_FOR_MESSAGES, + preferences->checkbutton_sounds_when_away); + preferences_hookup_sensitivity (preferences, + EMPATHY_PREFS_SOUNDS_FOR_MESSAGES, + preferences->checkbutton_sounds_when_busy); + + preferences_hookup_toggle_button (preferences, + EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS, + preferences->checkbutton_separate_chat_windows); + + preferences_hookup_toggle_button (preferences, + EMPATHY_PREFS_UI_SHOW_AVATARS, + preferences->checkbutton_show_avatars); + + preferences_hookup_toggle_button (preferences, + EMPATHY_PREFS_UI_COMPACT_CONTACT_LIST, + preferences->checkbutton_compact_contact_list); + + preferences_hookup_toggle_button (preferences, + EMPATHY_PREFS_CHAT_SHOW_SMILEYS, + preferences->checkbutton_show_smileys); + + preferences_hookup_string_combo (preferences, + EMPATHY_PREFS_CHAT_THEME, + preferences->combobox_chat_theme); + + preferences_hookup_toggle_button (preferences, + EMPATHY_PREFS_CHAT_THEME_CHAT_ROOM, + preferences->checkbutton_theme_chat_room); + + preferences_hookup_toggle_button (preferences, + EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED, + preferences->checkbutton_spell_checker); + preferences_hookup_sensitivity (preferences, + EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED, + preferences->treeview_spell_checker); + + preferences_hookup_radio_button (preferences, + EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM, + preferences->radiobutton_contact_list_sort_by_name); +} + +static void +preferences_languages_setup (EmpathyPreferences *preferences) +{ + GtkTreeView *view; + GtkListStore *store; + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + guint col_offset; + + view = GTK_TREE_VIEW (preferences->treeview_spell_checker); + + store = gtk_list_store_new (COL_LANG_COUNT, + G_TYPE_BOOLEAN, /* enabled */ + G_TYPE_STRING, /* code */ + G_TYPE_STRING); /* name */ + + gtk_tree_view_set_model (view, GTK_TREE_MODEL (store)); + + selection = gtk_tree_view_get_selection (view); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + + model = GTK_TREE_MODEL (store); + + renderer = gtk_cell_renderer_toggle_new (); + g_signal_connect (renderer, "toggled", + G_CALLBACK (preferences_languages_cell_toggled_cb), + preferences); + + column = gtk_tree_view_column_new_with_attributes (NULL, renderer, + "active", COL_LANG_ENABLED, + NULL); + + gtk_tree_view_append_column (view, column); + + renderer = gtk_cell_renderer_text_new (); + col_offset = gtk_tree_view_insert_column_with_attributes (view, + -1, _("Language"), + renderer, + "text", COL_LANG_NAME, + NULL); + + g_object_set_data (G_OBJECT (renderer), + "column", GINT_TO_POINTER (COL_LANG_NAME)); + + column = gtk_tree_view_get_column (view, col_offset - 1); + gtk_tree_view_column_set_sort_column_id (column, COL_LANG_NAME); + gtk_tree_view_column_set_resizable (column, FALSE); + gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); + + g_object_unref (store); +} + +static void +preferences_languages_add (EmpathyPreferences *preferences) +{ + GtkTreeView *view; + GtkListStore *store; + GList *codes, *l; + + view = GTK_TREE_VIEW (preferences->treeview_spell_checker); + store = GTK_LIST_STORE (gtk_tree_view_get_model (view)); + + codes = empathy_spell_get_language_codes (); + for (l = codes; l; l = l->next) { + GtkTreeIter iter; + const gchar *code; + const gchar *name; + + code = l->data; + name = empathy_spell_get_language_name (code); + if (!name) { + continue; + } + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + COL_LANG_CODE, code, + COL_LANG_NAME, name, + -1); + } + + empathy_spell_free_language_codes (codes); +} + +static void +preferences_languages_save (EmpathyPreferences *preferences) +{ + GtkTreeView *view; + GtkTreeModel *model; + + gchar *languages = NULL; + + view = GTK_TREE_VIEW (preferences->treeview_spell_checker); + model = gtk_tree_view_get_model (view); + + gtk_tree_model_foreach (model, + (GtkTreeModelForeachFunc) preferences_languages_save_foreach, + &languages); + + if (!languages) { + /* Default to english */ + languages = g_strdup ("en"); + } + + empathy_conf_set_string (empathy_conf_get (), + EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES, + languages); + + g_free (languages); +} + +static gboolean +preferences_languages_save_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gchar **languages) +{ + gboolean enabled; + gchar *code; + + if (!languages) { + return TRUE; + } + + gtk_tree_model_get (model, iter, COL_LANG_ENABLED, &enabled, -1); + if (!enabled) { + return FALSE; + } + + gtk_tree_model_get (model, iter, COL_LANG_CODE, &code, -1); + if (!code) { + return FALSE; + } + + if (!(*languages)) { + *languages = g_strdup (code); + } else { + gchar *str = *languages; + *languages = g_strdup_printf ("%s,%s", str, code); + g_free (str); + } + + g_free (code); + + return FALSE; +} + +static void +preferences_languages_load (EmpathyPreferences *preferences) +{ + GtkTreeView *view; + GtkTreeModel *model; + gchar *value; + gchar **vlanguages; + + if (!empathy_conf_get_string (empathy_conf_get (), + EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES, + &value) || !value) { + return; + } + + vlanguages = g_strsplit (value, ",", -1); + g_free (value); + + view = GTK_TREE_VIEW (preferences->treeview_spell_checker); + model = gtk_tree_view_get_model (view); + + gtk_tree_model_foreach (model, + (GtkTreeModelForeachFunc) preferences_languages_load_foreach, + vlanguages); + + g_strfreev (vlanguages); +} + +static gboolean +preferences_languages_load_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gchar **languages) +{ + gchar *code; + gchar *lang; + gint i; + gboolean found = FALSE; + + if (!languages) { + return TRUE; + } + + gtk_tree_model_get (model, iter, COL_LANG_CODE, &code, -1); + if (!code) { + return FALSE; + } + + for (i = 0, lang = languages[i]; lang; lang = languages[++i]) { + if (strcmp (lang, code) == 0) { + found = TRUE; + } + } + + gtk_list_store_set (GTK_LIST_STORE (model), iter, COL_LANG_ENABLED, found, -1); + return FALSE; +} + +static void +preferences_languages_cell_toggled_cb (GtkCellRendererToggle *cell, + gchar *path_string, + EmpathyPreferences *preferences) +{ + GtkTreeView *view; + GtkTreeModel *model; + GtkListStore *store; + GtkTreePath *path; + GtkTreeIter iter; + gboolean enabled; + + view = GTK_TREE_VIEW (preferences->treeview_spell_checker); + model = gtk_tree_view_get_model (view); + store = GTK_LIST_STORE (model); + + path = gtk_tree_path_new_from_string (path_string); + + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get (model, &iter, COL_LANG_ENABLED, &enabled, -1); + + enabled ^= 1; + + gtk_list_store_set (store, &iter, COL_LANG_ENABLED, enabled, -1); + gtk_tree_path_free (path); + + preferences_languages_save (preferences); +} + +static void +preferences_themes_setup (EmpathyPreferences *preferences) +{ + GtkComboBox *combo; + GtkListStore *model; + GtkTreeIter iter; + const gchar **themes; + gint i; + + combo = GTK_COMBO_BOX (preferences->combobox_chat_theme); + + model = gtk_list_store_new (COL_COMBO_COUNT, + G_TYPE_STRING, + G_TYPE_STRING); + + themes = empathy_theme_manager_get_themes (); + for (i = 0; themes[i]; i += 2) { + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, + COL_COMBO_VISIBLE_NAME, _(themes[i + 1]), + COL_COMBO_NAME, themes[i], + -1); + } + + gtk_combo_box_set_model (combo, GTK_TREE_MODEL (model)); + g_object_unref (model); +} + +static void +preferences_widget_sync_bool (const gchar *key, GtkWidget *widget) +{ + gboolean value; + + if (empathy_conf_get_bool (empathy_conf_get (), key, &value)) { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), value); + } +} + +static void +preferences_widget_sync_int (const gchar *key, GtkWidget *widget) +{ + gint value; + + if (empathy_conf_get_int (empathy_conf_get (), key, &value)) { + if (GTK_IS_SPIN_BUTTON (widget)) { + gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value); + } + } +} + +static void +preferences_widget_sync_string (const gchar *key, GtkWidget *widget) +{ + gchar *value; + + if (empathy_conf_get_string (empathy_conf_get (), key, &value) && value) { + if (GTK_IS_ENTRY (widget)) { + gtk_entry_set_text (GTK_ENTRY (widget), value); + } else if (GTK_IS_RADIO_BUTTON (widget)) { + if (strcmp (key, EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM) == 0) { + GType type; + GEnumClass *enum_class; + GEnumValue *enum_value; + GSList *list; + GtkWidget *toggle_widget; + + /* Get index from new string */ + type = empathy_contact_list_store_sort_get_type (); + enum_class = G_ENUM_CLASS (g_type_class_peek (type)); + enum_value = g_enum_get_value_by_nick (enum_class, value); + + if (enum_value) { + list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget)); + toggle_widget = g_slist_nth_data (list, enum_value->value); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle_widget), TRUE); + } + } else { + g_warning ("Unhandled key:'%s' just had string change", key); + } + } + + g_free (value); + } +} + +static void +preferences_widget_sync_string_combo (const gchar *key, GtkWidget *widget) +{ + gchar *value; + GtkTreeModel *model; + GtkTreeIter iter; + gboolean found; + + if (!empathy_conf_get_string (empathy_conf_get (), key, &value)) { + return; + } + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget)); + + found = FALSE; + if (value && gtk_tree_model_get_iter_first (model, &iter)) { + gchar *name; + + do { + gtk_tree_model_get (model, &iter, + COL_COMBO_NAME, &name, + -1); + + if (strcmp (name, value) == 0) { + found = TRUE; + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter); + break; + } else { + found = FALSE; + } + + g_free (name); + } while (gtk_tree_model_iter_next (model, &iter)); + } + + /* Fallback to the first one. */ + if (!found) { + if (gtk_tree_model_get_iter_first (model, &iter)) { + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter); + } + } + + g_free (value); +} + +static void +preferences_notify_int_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data) +{ + preferences_widget_sync_int (key, user_data); +} + +static void +preferences_notify_string_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data) +{ + preferences_widget_sync_string (key, user_data); +} + +static void +preferences_notify_string_combo_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data) +{ + preferences_widget_sync_string_combo (key, user_data); +} + +static void +preferences_notify_bool_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data) +{ + preferences_widget_sync_bool (key, user_data); +} + +static void +preferences_notify_sensitivity_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data) +{ + gboolean value; + + if (empathy_conf_get_bool (conf, key, &value)) { + gtk_widget_set_sensitive (GTK_WIDGET (user_data), value); + } +} + +static void +preferences_add_id (EmpathyPreferences *preferences, guint id) +{ + preferences->notify_ids = g_list_prepend (preferences->notify_ids, + GUINT_TO_POINTER (id)); +} + +static void +preferences_hookup_spin_button (EmpathyPreferences *preferences, + const gchar *key, + GtkWidget *widget) +{ + guint id; + + /* Silence warning. */ + if (0) { + preferences_hookup_spin_button (preferences, key, widget); + } + + preferences_widget_sync_int (key, widget); + + g_object_set_data_full (G_OBJECT (widget), "key", + g_strdup (key), g_free); + + g_signal_connect (widget, + "value_changed", + G_CALLBACK (preferences_spin_button_value_changed_cb), + NULL); + + id = empathy_conf_notify_add (empathy_conf_get (), + key, + preferences_notify_int_cb, + widget); + if (id) { + preferences_add_id (preferences, id); + } +} + +static void +preferences_hookup_entry (EmpathyPreferences *preferences, + const gchar *key, + GtkWidget *widget) +{ + guint id; + + if (0) { /* Silent warning before we use this function. */ + preferences_hookup_entry (preferences, key, widget); + } + + preferences_widget_sync_string (key, widget); + + g_object_set_data_full (G_OBJECT (widget), "key", + g_strdup (key), g_free); + + g_signal_connect (widget, + "changed", + G_CALLBACK (preferences_entry_value_changed_cb), + NULL); + + id = empathy_conf_notify_add (empathy_conf_get (), + key, + preferences_notify_string_cb, + widget); + if (id) { + preferences_add_id (preferences, id); + } +} + +static void +preferences_hookup_toggle_button (EmpathyPreferences *preferences, + const gchar *key, + GtkWidget *widget) +{ + guint id; + + preferences_widget_sync_bool (key, widget); + + g_object_set_data_full (G_OBJECT (widget), "key", + g_strdup (key), g_free); + + g_signal_connect (widget, + "toggled", + G_CALLBACK (preferences_toggle_button_toggled_cb), + NULL); + + id = empathy_conf_notify_add (empathy_conf_get (), + key, + preferences_notify_bool_cb, + widget); + if (id) { + preferences_add_id (preferences, id); + } +} + +static void +preferences_hookup_radio_button (EmpathyPreferences *preferences, + const gchar *key, + GtkWidget *widget) +{ + GSList *group, *l; + guint id; + + preferences_widget_sync_string (key, widget); + + group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget)); + for (l = group; l; l = l->next) { + g_signal_connect (l->data, + "toggled", + G_CALLBACK (preferences_radio_button_toggled_cb), + NULL); + + g_object_set_data_full (G_OBJECT (l->data), "key", + g_strdup (key), g_free); + } + + id = empathy_conf_notify_add (empathy_conf_get (), + key, + preferences_notify_string_cb, + widget); + if (id) { + preferences_add_id (preferences, id); + } +} + +static void +preferences_hookup_string_combo (EmpathyPreferences *preferences, + const gchar *key, + GtkWidget *widget) +{ + guint id; + + preferences_widget_sync_string_combo (key, widget); + + g_object_set_data_full (G_OBJECT (widget), "key", + g_strdup (key), g_free); + + g_signal_connect (widget, + "changed", + G_CALLBACK (preferences_string_combo_changed_cb), + NULL); + + id = empathy_conf_notify_add (empathy_conf_get (), + key, + preferences_notify_string_combo_cb, + widget); + if (id) { + preferences_add_id (preferences, id); + } +} + +static void +preferences_hookup_sensitivity (EmpathyPreferences *preferences, + const gchar *key, + GtkWidget *widget) +{ + gboolean value; + guint id; + + if (empathy_conf_get_bool (empathy_conf_get (), key, &value)) { + gtk_widget_set_sensitive (widget, value); + } + + id = empathy_conf_notify_add (empathy_conf_get (), + key, + preferences_notify_sensitivity_cb, + widget); + if (id) { + preferences_add_id (preferences, id); + } +} + +static void +preferences_spin_button_value_changed_cb (GtkWidget *button, + gpointer user_data) +{ + const gchar *key; + + key = g_object_get_data (G_OBJECT (button), "key"); + + empathy_conf_set_int (empathy_conf_get (), + key, + gtk_spin_button_get_value (GTK_SPIN_BUTTON (button))); +} + +static void +preferences_entry_value_changed_cb (GtkWidget *entry, + gpointer user_data) +{ + const gchar *key; + + key = g_object_get_data (G_OBJECT (entry), "key"); + + empathy_conf_set_string (empathy_conf_get (), + key, + gtk_entry_get_text (GTK_ENTRY (entry))); +} + +static void +preferences_toggle_button_toggled_cb (GtkWidget *button, + gpointer user_data) +{ + const gchar *key; + + key = g_object_get_data (G_OBJECT (button), "key"); + + empathy_conf_set_bool (empathy_conf_get (), + key, + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))); +} + +static void +preferences_radio_button_toggled_cb (GtkWidget *button, + gpointer user_data) +{ + const gchar *key; + const gchar *value = NULL; + + if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) { + return; + } + + key = g_object_get_data (G_OBJECT (button), "key"); + + if (key && strcmp (key, EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM) == 0) { + GSList *group; + GType type; + GEnumClass *enum_class; + GEnumValue *enum_value; + + group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button)); + + /* Get string from index */ + type = empathy_contact_list_store_sort_get_type (); + enum_class = G_ENUM_CLASS (g_type_class_peek (type)); + enum_value = g_enum_get_value (enum_class, g_slist_index (group, button)); + + if (!enum_value) { + g_warning ("No GEnumValue for EmpathyContactListSort with GtkRadioButton index:%d", + g_slist_index (group, button)); + return; + } + + value = enum_value->value_nick; + } + + empathy_conf_set_string (empathy_conf_get (), key, value); +} + +static void +preferences_string_combo_changed_cb (GtkWidget *combo, + gpointer user_data) +{ + const gchar *key; + GtkTreeModel *model; + GtkTreeIter iter; + gchar *name; + + key = g_object_get_data (G_OBJECT (combo), "key"); + + if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) { + model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo)); + + gtk_tree_model_get (model, &iter, + COL_COMBO_NAME, &name, + -1); + empathy_conf_set_string (empathy_conf_get (), key, name); + g_free (name); + } +} + +static void +preferences_response_cb (GtkWidget *widget, + gint response, + EmpathyPreferences *preferences) +{ + gtk_widget_destroy (widget); +} + +static void +preferences_destroy_cb (GtkWidget *widget, + EmpathyPreferences *preferences) +{ + GList *l; + + for (l = preferences->notify_ids; l; l = l->next) { + guint id; + + id = GPOINTER_TO_UINT (l->data); + empathy_conf_notify_remove (empathy_conf_get (), id); + } + + g_list_free (preferences->notify_ids); + g_free (preferences); +} + +GtkWidget * +empathy_preferences_show (GtkWindow *parent) +{ + static EmpathyPreferences *preferences; + GladeXML *glade; + + if (preferences) { + gtk_window_present (GTK_WINDOW (preferences->dialog)); + return preferences->dialog; + } + + preferences = g_new0 (EmpathyPreferences, 1); + + glade = empathy_glade_get_file ( + "empathy-preferences.glade", + "preferences_dialog", + NULL, + "preferences_dialog", &preferences->dialog, + "notebook", &preferences->notebook, + "checkbutton_show_avatars", &preferences->checkbutton_show_avatars, + "checkbutton_compact_contact_list", &preferences->checkbutton_compact_contact_list, + "checkbutton_show_smileys", &preferences->checkbutton_show_smileys, + "combobox_chat_theme", &preferences->combobox_chat_theme, + "checkbutton_theme_chat_room", &preferences->checkbutton_theme_chat_room, + "checkbutton_separate_chat_windows", &preferences->checkbutton_separate_chat_windows, + "radiobutton_contact_list_sort_by_name", &preferences->radiobutton_contact_list_sort_by_name, + "radiobutton_contact_list_sort_by_state", &preferences->radiobutton_contact_list_sort_by_state, + "checkbutton_sounds_for_messages", &preferences->checkbutton_sounds_for_messages, + "checkbutton_sounds_when_busy", &preferences->checkbutton_sounds_when_busy, + "checkbutton_sounds_when_away", &preferences->checkbutton_sounds_when_away, + "checkbutton_popups_when_available", &preferences->checkbutton_popups_when_available, + "treeview_spell_checker", &preferences->treeview_spell_checker, + "checkbutton_spell_checker", &preferences->checkbutton_spell_checker, + NULL); + + empathy_glade_connect (glade, + preferences, + "preferences_dialog", "destroy", preferences_destroy_cb, + "preferences_dialog", "response", preferences_response_cb, + NULL); + + g_object_unref (glade); + + g_object_add_weak_pointer (G_OBJECT (preferences->dialog), (gpointer) &preferences); + + preferences_themes_setup (preferences); + + preferences_setup_widgets (preferences); + + preferences_languages_setup (preferences); + preferences_languages_add (preferences); + preferences_languages_load (preferences); + + if (empathy_spell_supported ()) { + GtkWidget *page; + + page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (preferences->notebook), 2); + gtk_widget_show (page); + } + + if (parent) { + gtk_window_set_transient_for (GTK_WINDOW (preferences->dialog), + GTK_WINDOW (parent)); + } + + gtk_widget_show (preferences->dialog); + + return preferences->dialog; +} + diff --git a/libempathy-gtk/empathy-preferences.glade b/libempathy-gtk/empathy-preferences.glade new file mode 100644 index 00000000..c5cd5147 --- /dev/null +++ b/libempathy-gtk/empathy-preferences.glade @@ -0,0 +1,1092 @@ + + + + + + + + 5 + Preferences + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + True + False + gtk-preferences + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + False + + + + True + False + 2 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + -6 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 5 + True + True + True + True + GTK_POS_TOP + False + False + + + + 12 + True + False + 18 + + + + True + 0 + 0.5 + GTK_SHADOW_NONE + + + + True + 0.5 + 0.5 + 1 + 1 + 6 + 0 + 12 + 0 + + + + True + False + 6 + + + + True + Avatars are user chosen images shown in the contact list + True + Show _avatars + True + GTK_RELIEF_NORMAL + True + True + False + True + + + 0 + False + False + + + + + + True + True + Show co_mpact contact list + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Show _smileys as images + True + GTK_RELIEF_NORMAL + True + True + False + True + + + 0 + False + False + + + + + + + + + + True + <b>Appearance</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + False + False + + + + + + True + 0 + 0.5 + GTK_SHADOW_NONE + + + + True + 0.5 + 0.5 + 1 + 1 + 6 + 0 + 12 + 0 + + + + True + True + _Open new chats in separate windows + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + + + + + True + <b>Behaviour</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + False + False + + + + + True + 0 + 0.5 + GTK_SHADOW_NONE + + + + True + 0.5 + 0.5 + 1 + 1 + 6 + 0 + 12 + 0 + + + + True + False + 0 + + + + True + True + Sort by _name + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Sort by s_tate + True + GTK_RELIEF_NORMAL + True + False + False + True + radiobutton_contact_list_sort_by_name + + + 0 + False + False + + + + + + + + + + True + <b>Contact List</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + False + True + + + + + + True + General + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + 12 + True + False + 18 + + + + True + 0 + 0.5 + GTK_SHADOW_NONE + + + + True + 0.5 + 0.5 + 1 + 1 + 6 + 0 + 12 + 0 + + + + True + False + 6 + + + + True + True + _Play sound when messages arrive + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Enable sounds when _busy + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Enable sounds when _away + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + + + + + True + <b>Audio</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + False + False + + + + + + True + 0 + 0.5 + GTK_SHADOW_NONE + + + + True + 0.5 + 0.5 + 1 + 1 + 6 + 0 + 12 + 0 + + + + True + True + Display notifications when contacts come _online + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + + + + + True + <b>Visual</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + False + False + + + + + False + True + + + + + + True + Notifications + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + 12 + False + 18 + + + + True + 0 + 0.5 + GTK_SHADOW_NONE + + + + True + 0.5 + 0.5 + 1 + 1 + 6 + 0 + 12 + 0 + + + + True + False + 6 + + + + True + False + 0 + + + + True + False + 6 + + + + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + False + False + True + False + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + False + 6 + + + + True + gtk-dialog-info + 4 + 0.5 + 0 + 0 + 0 + + + 0 + False + True + + + + + + True + <small>The list of languages reflects only the languages for which you have a dictionary installed.</small> + False + True + GTK_JUSTIFY_LEFT + True + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + True + True + + + + + 0 + False + True + + + + + + + + + + True + <b>Languages</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + + True + 0 + 0.5 + GTK_SHADOW_NONE + + + + True + 0.5 + 0.5 + 1 + 1 + 6 + 0 + 12 + 0 + + + + True + True + _Enable spell checking + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + + + + + True + <b>Options</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + False + True + + + + + False + True + + + + + + True + Spell Checking + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + 12 + True + False + 18 + + + + True + 0 + 0.5 + GTK_SHADOW_NONE + + + + True + 0.5 + 0.5 + 1 + 1 + 6 + 0 + 12 + 0 + + + + True + False + 6 + + + + True + False + 12 + + + + True + Chat Th_eme: + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + combobox_chat_theme + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + + False + True + + + 0 + False + False + + + + + 0 + True + True + + + + + + + + + + True + <b>Appearance</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + False + False + + + + + + True + 0 + 0.5 + GTK_SHADOW_NONE + + + + True + 0.5 + 0.5 + 1 + 1 + 6 + 0 + 12 + 0 + + + + True + True + _Use for chat rooms + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + + + + + True + <b>Options</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + False + False + + + + + False + True + + + + + + True + Themes + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + 0 + True + True + + + + + + + diff --git a/libempathy-gtk/empathy-preferences.h b/libempathy-gtk/empathy-preferences.h new file mode 100644 index 00000000..dc058d7e --- /dev/null +++ b/libempathy-gtk/empathy-preferences.h @@ -0,0 +1,58 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2003-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Richard Hult + * Martyn Russell + */ + +#ifndef __EMPATHY_PREFERENCES_H__ +#define __EMPATHY_PREFERENCES_H__ + +#include + +G_BEGIN_DECLS + +#define EMPATHY_PREFS_PATH "/apps/empathy" + +#define EMPATHY_PREFS_SOUNDS_FOR_MESSAGES EMPATHY_PREFS_PATH "/notifications/sounds_for_messages" +#define EMPATHY_PREFS_SOUNDS_WHEN_AWAY EMPATHY_PREFS_PATH "/notifications/sounds_when_away" +#define EMPATHY_PREFS_SOUNDS_WHEN_BUSY EMPATHY_PREFS_PATH "/notifications/sounds_when_busy" +#define EMPATHY_PREFS_POPUPS_WHEN_AVAILABLE EMPATHY_PREFS_PATH "/notifications/popups_when_available" +#define EMPATHY_PREFS_CHAT_SHOW_SMILEYS EMPATHY_PREFS_PATH "/conversation/graphical_smileys" +#define EMPATHY_PREFS_CHAT_THEME EMPATHY_PREFS_PATH "/conversation/theme" +#define EMPATHY_PREFS_CHAT_THEME_CHAT_ROOM EMPATHY_PREFS_PATH "/conversation/theme_chat_room" +#define EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES EMPATHY_PREFS_PATH "/conversation/spell_checker_languages" +#define EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED EMPATHY_PREFS_PATH "/conversation/spell_checker_enabled" +#define EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS EMPATHY_PREFS_PATH "/ui/separate_chat_windows" +#define EMPATHY_PREFS_UI_MAIN_WINDOW_HIDDEN EMPATHY_PREFS_PATH "/ui/main_window_hidden" +#define EMPATHY_PREFS_UI_AVATAR_DIRECTORY EMPATHY_PREFS_PATH "/ui/avatar_directory" +#define EMPATHY_PREFS_UI_SHOW_AVATARS EMPATHY_PREFS_PATH "/ui/show_avatars" +#define EMPATHY_PREFS_UI_COMPACT_CONTACT_LIST EMPATHY_PREFS_PATH "/ui/compact_contact_list" +#define EMPATHY_PREFS_CONTACTS_SHOW_OFFLINE EMPATHY_PREFS_PATH "/contacts/show_offline" +#define EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM EMPATHY_PREFS_PATH "/contacts/sort_criterium" +#define EMPATHY_PREFS_HINTS_CLOSE_MAIN_WINDOW EMPATHY_PREFS_PATH "/hints/close_main_window" + +GtkWidget * empathy_preferences_show (GtkWindow *parent); + +G_END_DECLS + +#endif /* __EMPATHY_PREFERENCES_H__ */ + + diff --git a/libempathy-gtk/empathy-presence-chooser.c b/libempathy-gtk/empathy-presence-chooser.c new file mode 100644 index 00000000..f8522c98 --- /dev/null +++ b/libempathy-gtk/empathy-presence-chooser.c @@ -0,0 +1,979 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2005-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Richard Hult + * Martyn Russell + */ + +#include "config.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "empathy-ui-utils.h" +#include "empathy-images.h" +#include "empathy-presence-chooser.h" +#include "empathy-status-presets.h" + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_PRESENCE_CHOOSER, EmpathyPresenceChooserPriv)) + +#define DEBUG_DOMAIN "PresenceChooser" + +/* Flashing delay for icons (milliseconds). */ +#define FLASH_TIMEOUT 500 + +typedef struct { + EmpathyIdle *idle; + + GtkWidget *hbox; + GtkWidget *image; + GtkWidget *label; + GtkWidget *menu; + + McPresence last_state; + + McPresence flash_state_1; + McPresence flash_state_2; + guint flash_timeout_id; + + /* The handle the kind of unnessecary scroll support. */ + guint scroll_timeout_id; + McPresence scroll_state; + gchar *scroll_status; +} EmpathyPresenceChooserPriv; + +typedef struct { + McPresence state; + const gchar *status; +} StateAndStatus; + +/* States to be listed in the menu */ +static McPresence states[] = {MC_PRESENCE_AVAILABLE, + MC_PRESENCE_DO_NOT_DISTURB, + MC_PRESENCE_AWAY}; + +static void empathy_presence_chooser_class_init (EmpathyPresenceChooserClass *klass); +static void empathy_presence_chooser_init (EmpathyPresenceChooser *chooser); +static void presence_chooser_finalize (GObject *object); +static void presence_chooser_presence_changed_cb (EmpathyPresenceChooser *chooser); +static void presence_chooser_reset_scroll_timeout (EmpathyPresenceChooser *chooser); +static gboolean presence_chooser_scroll_timeout_cb (EmpathyPresenceChooser *chooser); +static gboolean presence_chooser_scroll_event_cb (EmpathyPresenceChooser *chooser, + GdkEventScroll *event, + gpointer user_data); +static GList * presence_chooser_get_presets (EmpathyPresenceChooser *chooser); +static StateAndStatus *presence_chooser_state_and_status_new (McPresence state, + const gchar *status); +static gboolean presence_chooser_flash_timeout_cb (EmpathyPresenceChooser *chooser); +static void presence_chooser_flash_start (EmpathyPresenceChooser *chooser, + McPresence state_1, + McPresence state_2); +static void presence_chooser_flash_stop (EmpathyPresenceChooser *chooser, + McPresence state); +static gboolean presence_chooser_button_press_event_cb (GtkWidget *chooser, + GdkEventButton *event, + gpointer user_data); +static void presence_chooser_toggled_cb (GtkWidget *chooser, + gpointer user_data); +static void presence_chooser_menu_popup (EmpathyPresenceChooser *chooser); +static void presence_chooser_menu_popdown (EmpathyPresenceChooser *chooser); +static void presence_chooser_menu_selection_done_cb (GtkMenuShell *menushell, + EmpathyPresenceChooser *chooser); +static void presence_chooser_menu_destroy_cb (GtkWidget *menu, + EmpathyPresenceChooser *chooser); +static void presence_chooser_menu_detach (GtkWidget *attach_widget, + GtkMenu *menu); +static void presence_chooser_menu_align_func (GtkMenu *menu, + gint *x, + gint *y, + gboolean *push_in, + GtkWidget *widget); +static void presence_chooser_menu_add_item (GtkWidget *menu, + const gchar *str, + McPresence state, + gboolean custom); +static void presence_chooser_clear_activate_cb (GtkWidget *item, + gpointer user_data); +static void presence_chooser_clear_response_cb (GtkWidget *widget, + gint response, + gpointer user_data); +static void presence_chooser_noncustom_activate_cb (GtkWidget *item, + gpointer user_data); +static void presence_chooser_set_state (McPresence state, + const gchar *status, + gboolean save); +static void presence_chooser_custom_activate_cb (GtkWidget *item, + gpointer user_data); +static void presence_chooser_show_dialog (McPresence state); +static void presence_chooser_dialog_response_cb (GtkWidget *dialog, + gint response, + gpointer user_data); + +G_DEFINE_TYPE (EmpathyPresenceChooser, empathy_presence_chooser, GTK_TYPE_TOGGLE_BUTTON); + +static void +empathy_presence_chooser_class_init (EmpathyPresenceChooserClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = presence_chooser_finalize; + + g_type_class_add_private (object_class, sizeof (EmpathyPresenceChooserPriv)); +} + +static void +empathy_presence_chooser_init (EmpathyPresenceChooser *chooser) +{ + EmpathyPresenceChooserPriv *priv; + GtkWidget *arrow; + GtkWidget *alignment; + + priv = GET_PRIV (chooser); + + gtk_button_set_relief (GTK_BUTTON (chooser), GTK_RELIEF_NONE); + gtk_button_set_focus_on_click (GTK_BUTTON (chooser), FALSE); + + alignment = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment); + gtk_container_add (GTK_CONTAINER (chooser), alignment); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 1, 0); + + priv->hbox = gtk_hbox_new (FALSE, 1); + gtk_widget_show (priv->hbox); + gtk_container_add (GTK_CONTAINER (alignment), priv->hbox); + + priv->image = gtk_image_new (); + gtk_widget_show (priv->image); + gtk_box_pack_start (GTK_BOX (priv->hbox), priv->image, FALSE, TRUE, 0); + + priv->label = gtk_label_new (NULL); + gtk_widget_show (priv->label); + gtk_box_pack_start (GTK_BOX (priv->hbox), priv->label, TRUE, TRUE, 0); + gtk_label_set_ellipsize (GTK_LABEL (priv->label), PANGO_ELLIPSIZE_END); + gtk_misc_set_alignment (GTK_MISC (priv->label), 0, 0.5); + gtk_misc_set_padding (GTK_MISC (priv->label), 4, 1); + + alignment = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment); + gtk_box_pack_start (GTK_BOX (priv->hbox), alignment, FALSE, FALSE, 0); + + arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT); + gtk_widget_show (arrow); + gtk_container_add (GTK_CONTAINER (alignment), arrow); + + g_signal_connect (chooser, "toggled", + G_CALLBACK (presence_chooser_toggled_cb), + NULL); + g_signal_connect (chooser, "button-press-event", + G_CALLBACK (presence_chooser_button_press_event_cb), + NULL); + g_signal_connect (chooser, "scroll-event", + G_CALLBACK (presence_chooser_scroll_event_cb), + NULL); + + priv->idle = empathy_idle_new (); + presence_chooser_presence_changed_cb (chooser); + g_signal_connect_swapped (priv->idle, "notify", + G_CALLBACK (presence_chooser_presence_changed_cb), + chooser); +} + +static void +presence_chooser_finalize (GObject *object) +{ + EmpathyPresenceChooserPriv *priv; + + priv = GET_PRIV (object); + + if (priv->flash_timeout_id) { + g_source_remove (priv->flash_timeout_id); + } + + if (priv->scroll_timeout_id) { + g_source_remove (priv->scroll_timeout_id); + } + + g_signal_handlers_disconnect_by_func (priv->idle, + presence_chooser_presence_changed_cb, + object); + g_object_unref (priv->idle); + + G_OBJECT_CLASS (empathy_presence_chooser_parent_class)->finalize (object); +} + +GtkWidget * +empathy_presence_chooser_new (void) +{ + GtkWidget *chooser; + + chooser = g_object_new (EMPATHY_TYPE_PRESENCE_CHOOSER, NULL); + + return chooser; +} + +static void +presence_chooser_presence_changed_cb (EmpathyPresenceChooser *chooser) +{ + EmpathyPresenceChooserPriv *priv; + McPresence state; + McPresence flash_state; + const gchar *status; + + priv = GET_PRIV (chooser); + + state = empathy_idle_get_state (priv->idle); + status = empathy_idle_get_status (priv->idle); + flash_state = empathy_idle_get_flash_state (priv->idle); + + presence_chooser_reset_scroll_timeout (chooser); + gtk_label_set_text (GTK_LABEL (priv->label), status); + + if (flash_state != MC_PRESENCE_UNSET) { + presence_chooser_flash_start (chooser, state, flash_state); + } else { + presence_chooser_flash_stop (chooser, state); + } +} + +static void +presence_chooser_reset_scroll_timeout (EmpathyPresenceChooser *chooser) +{ + EmpathyPresenceChooserPriv *priv; + + priv = GET_PRIV (chooser); + + if (priv->scroll_timeout_id) { + g_source_remove (priv->scroll_timeout_id); + priv->scroll_timeout_id = 0; + } + + g_free (priv->scroll_status); + priv->scroll_status = NULL; +} + +static gboolean +presence_chooser_scroll_timeout_cb (EmpathyPresenceChooser *chooser) +{ + EmpathyPresenceChooserPriv *priv; + + priv = GET_PRIV (chooser); + + priv->scroll_timeout_id = 0; + + empathy_idle_set_presence (priv->idle, + priv->scroll_state, + priv->scroll_status); + + g_free (priv->scroll_status); + priv->scroll_status = NULL; + + return FALSE; +} + +static gboolean +presence_chooser_scroll_event_cb (EmpathyPresenceChooser *chooser, + GdkEventScroll *event, + gpointer user_data) +{ + EmpathyPresenceChooserPriv *priv; + GList *list, *l; + const gchar *current_status; + StateAndStatus *sas; + gboolean match; + + priv = GET_PRIV (chooser); + + switch (event->direction) { + case GDK_SCROLL_UP: + break; + case GDK_SCROLL_DOWN: + break; + default: + return FALSE; + } + + current_status = gtk_label_get_text (GTK_LABEL (priv->label)); + + /* Get the list of presets, which in this context means all the items + * without a trailing "...". + */ + list = presence_chooser_get_presets (chooser); + sas = NULL; + match = FALSE; + for (l = list; l; l = l->next) { + sas = l->data; + + if (sas->state == priv->last_state && + strcmp (sas->status, current_status) == 0) { + sas = NULL; + match = TRUE; + if (event->direction == GDK_SCROLL_UP) { + if (l->prev) { + sas = l->prev->data; + } + } + else if (event->direction == GDK_SCROLL_DOWN) { + if (l->next) { + sas = l->next->data; + } + } + break; + } + + sas = NULL; + } + + if (sas) { + presence_chooser_reset_scroll_timeout (chooser); + + priv->scroll_status = g_strdup (sas->status); + priv->scroll_state = sas->state; + + priv->scroll_timeout_id = + g_timeout_add (500, + (GSourceFunc) presence_chooser_scroll_timeout_cb, + chooser); + + presence_chooser_flash_stop (chooser, sas->state); + gtk_label_set_text (GTK_LABEL (priv->label), sas->status); + } + else if (!match) { + const gchar *status; + /* If we didn't get any match at all, it means the last state + * was a custom one. Just switch to the first one. + */ + status = empathy_presence_state_get_default_status (states[0]); + + presence_chooser_reset_scroll_timeout (chooser); + empathy_idle_set_presence (priv->idle, states[0], status); + } + + g_list_foreach (list, (GFunc) g_free, NULL); + g_list_free (list); + + return TRUE; +} + +static GList * +presence_chooser_get_presets (EmpathyPresenceChooser *chooser) +{ + GList *list = NULL; + guint i; + + for (i = 0; i < G_N_ELEMENTS (states); i++) { + GList *presets, *p; + StateAndStatus *sas; + const gchar *status; + + status = empathy_presence_state_get_default_status (states[i]); + sas = presence_chooser_state_and_status_new (states[i], status); + list = g_list_append (list, sas); + + presets = empathy_status_presets_get (states[i], 5); + for (p = presets; p; p = p->next) { + sas = presence_chooser_state_and_status_new (states[i], p->data); + list = g_list_append (list, sas); + } + g_list_free (presets); + } + + return list; +} + +static StateAndStatus * +presence_chooser_state_and_status_new (McPresence state, + const gchar *status) +{ + StateAndStatus *sas; + + sas = g_new0 (StateAndStatus, 1); + + sas->state = state; + sas->status = status; + + return sas; +} + +static gboolean +presence_chooser_flash_timeout_cb (EmpathyPresenceChooser *chooser) +{ + EmpathyPresenceChooserPriv *priv; + McPresence state; + static gboolean on = FALSE; + + priv = GET_PRIV (chooser); + + if (on) { + state = priv->flash_state_1; + } else { + state = priv->flash_state_2; + } + + gtk_image_set_from_icon_name (GTK_IMAGE (priv->image), + empathy_icon_name_for_presence_state (state), + GTK_ICON_SIZE_MENU); + + on = !on; + + return TRUE; +} + +static void +presence_chooser_flash_start (EmpathyPresenceChooser *chooser, + McPresence state_1, + McPresence state_2) +{ + EmpathyPresenceChooserPriv *priv; + + g_return_if_fail (EMPATHY_IS_PRESENCE_CHOOSER (chooser)); + + priv = GET_PRIV (chooser); + + priv->flash_state_1 = state_1; + priv->flash_state_2 = state_2; + + if (!priv->flash_timeout_id) { + priv->flash_timeout_id = g_timeout_add (FLASH_TIMEOUT, + (GSourceFunc) presence_chooser_flash_timeout_cb, + chooser); + } +} + +static void +presence_chooser_flash_stop (EmpathyPresenceChooser *chooser, + McPresence state) +{ + EmpathyPresenceChooserPriv *priv; + + g_return_if_fail (EMPATHY_IS_PRESENCE_CHOOSER (chooser)); + + priv = GET_PRIV (chooser); + + if (priv->flash_timeout_id) { + g_source_remove (priv->flash_timeout_id); + priv->flash_timeout_id = 0; + } + + gtk_image_set_from_icon_name (GTK_IMAGE (priv->image), + empathy_icon_name_for_presence_state (state), + GTK_ICON_SIZE_MENU); + + priv->last_state = state; +} + +static gboolean +presence_chooser_button_press_event_cb (GtkWidget *chooser, + GdkEventButton *event, + gpointer user_data) +{ + if (event->button != 1 || event->type != GDK_BUTTON_PRESS) { + return FALSE; + } + + if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (chooser))) { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (chooser), TRUE); + return TRUE; + } + + return FALSE; +} + +static void +presence_chooser_toggled_cb (GtkWidget *chooser, + gpointer user_data) +{ + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (chooser))) { + presence_chooser_menu_popup (EMPATHY_PRESENCE_CHOOSER (chooser)); + } else { + presence_chooser_menu_popdown (EMPATHY_PRESENCE_CHOOSER (chooser)); + } +} + +static void +presence_chooser_menu_popup (EmpathyPresenceChooser *chooser) +{ + EmpathyPresenceChooserPriv *priv; + GtkWidget *menu; + + priv = GET_PRIV (chooser); + + if (priv->menu) { + return; + } + + menu = empathy_presence_chooser_create_menu (); + + g_signal_connect_after (menu, "selection-done", + G_CALLBACK (presence_chooser_menu_selection_done_cb), + chooser); + + g_signal_connect (menu, "destroy", + G_CALLBACK (presence_chooser_menu_destroy_cb), + chooser); + + gtk_menu_attach_to_widget (GTK_MENU (menu), + GTK_WIDGET (chooser), + presence_chooser_menu_detach); + + gtk_menu_popup (GTK_MENU (menu), + NULL, NULL, + (GtkMenuPositionFunc) presence_chooser_menu_align_func, + chooser, + 1, + gtk_get_current_event_time ()); + + priv->menu = menu; +} + +static void +presence_chooser_menu_popdown (EmpathyPresenceChooser *chooser) +{ + EmpathyPresenceChooserPriv *priv; + + priv = GET_PRIV (chooser); + + if (priv->menu) { + gtk_widget_destroy (priv->menu); + } +} + +static void +presence_chooser_menu_selection_done_cb (GtkMenuShell *menushell, + EmpathyPresenceChooser *chooser) +{ + gtk_widget_destroy (GTK_WIDGET (menushell)); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (chooser), FALSE); +} + +static void +presence_chooser_menu_destroy_cb (GtkWidget *menu, + EmpathyPresenceChooser *chooser) +{ + EmpathyPresenceChooserPriv *priv; + + priv = GET_PRIV (chooser); + + priv->menu = NULL; +} + +static void +presence_chooser_menu_detach (GtkWidget *attach_widget, + GtkMenu *menu) +{ + /* We don't need to do anything, but attaching the menu means + * we don't own the ref count and it is cleaned up properly. + */ +} + +static void +presence_chooser_menu_align_func (GtkMenu *menu, + gint *x, + gint *y, + gboolean *push_in, + GtkWidget *widget) +{ + GtkRequisition req; + GdkScreen *screen; + gint screen_height; + + gtk_widget_size_request (GTK_WIDGET (menu), &req); + + gdk_window_get_origin (widget->window, x, y); + + *x += widget->allocation.x + 1; + *y += widget->allocation.y; + + screen = gtk_widget_get_screen (GTK_WIDGET (menu)); + screen_height = gdk_screen_get_height (screen); + + if (req.height > screen_height) { + /* Too big for screen height anyway. */ + *y = 0; + return; + } + + if ((*y + req.height + widget->allocation.height) > screen_height) { + /* Can't put it below the button. */ + *y -= req.height; + *y += 1; + } else { + /* Put menu below button. */ + *y += widget->allocation.height; + *y -= 1; + } + + *push_in = FALSE; +} + +GtkWidget * +empathy_presence_chooser_create_menu (void) +{ + const gchar *status; + GtkWidget *menu; + GtkWidget *item; + GtkWidget *image; + guint i; + + menu = gtk_menu_new (); + + for (i = 0; i < G_N_ELEMENTS (states); i++) { + GList *list, *l; + + status = empathy_presence_state_get_default_status (states[i]); + presence_chooser_menu_add_item (menu, + status, + states[i], + FALSE); + + list = empathy_status_presets_get (states[i], 5); + for (l = list; l; l = l->next) { + presence_chooser_menu_add_item (menu, + l->data, + states[i], + FALSE); + } + g_list_free (list); + + presence_chooser_menu_add_item (menu, + _("Custom message..."), + states[i], + TRUE); + + /* Separator. */ + item = gtk_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + } + + /* Offline to disconnect */ + status = empathy_presence_state_get_default_status (MC_PRESENCE_OFFLINE); + presence_chooser_menu_add_item (menu, + status, + MC_PRESENCE_OFFLINE, + FALSE); + /* Separator. */ + item = gtk_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + + /* Clear list */ + item = gtk_image_menu_item_new_with_label (_("Clear List...")); + image = gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show (image); + gtk_widget_show (item); + + g_signal_connect (item, + "activate", + G_CALLBACK (presence_chooser_clear_activate_cb), + NULL); + + return menu; +} + +static void +presence_chooser_menu_add_item (GtkWidget *menu, + const gchar *str, + McPresence state, + gboolean custom) +{ + GtkWidget *item; + GtkWidget *image; + const gchar *icon_name; + + item = gtk_image_menu_item_new_with_label (str); + icon_name = empathy_icon_name_for_presence_state (state); + + if (custom) { + g_signal_connect (item, "activate", + G_CALLBACK (presence_chooser_custom_activate_cb), + NULL); + } else { + g_signal_connect (item, "activate", + G_CALLBACK (presence_chooser_noncustom_activate_cb), + NULL); + } + + image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); + gtk_widget_show (image); + + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); + gtk_widget_show (item); + + g_object_set_data_full (G_OBJECT (item), + "status", g_strdup (str), + (GDestroyNotify) g_free); + + g_object_set_data (G_OBJECT (item), "state", GINT_TO_POINTER (state)); + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); +} + +static void +presence_chooser_clear_activate_cb (GtkWidget *item, + gpointer user_data) +{ + GtkWidget *dialog; + GtkWidget *toplevel; + GtkWindow *parent = NULL; + + toplevel = gtk_widget_get_toplevel (item); + if (GTK_WIDGET_TOPLEVEL (toplevel) && + GTK_IS_WINDOW (toplevel)) { + GtkWindow *window; + gboolean visible; + + window = GTK_WINDOW (toplevel); + visible = empathy_window_get_is_visible (window); + + if (visible) { + parent = window; + } + } + + dialog = gtk_message_dialog_new (GTK_WINDOW (parent), + 0, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, + _("Are you sure you want to clear the list?")); + + gtk_message_dialog_format_secondary_text ( + GTK_MESSAGE_DIALOG (dialog), + _("This will remove any custom messages you have " + "added to the list of preset status messages.")); + + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + _("Clear List"), GTK_RESPONSE_OK, + NULL); + + gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), FALSE); + + g_signal_connect (dialog, "response", + G_CALLBACK (presence_chooser_clear_response_cb), + NULL); + + gtk_widget_show (dialog); +} + +static void +presence_chooser_clear_response_cb (GtkWidget *widget, + gint response, + gpointer user_data) +{ + if (response == GTK_RESPONSE_OK) { + empathy_status_presets_reset (); + } + + gtk_widget_destroy (widget); +} + +static void +presence_chooser_noncustom_activate_cb (GtkWidget *item, + gpointer user_data) +{ + McPresence state; + const gchar *status; + + status = g_object_get_data (G_OBJECT (item), "status"); + state = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "state")); + + presence_chooser_set_state (state, status, FALSE); +} + +static void +presence_chooser_set_state (McPresence state, + const gchar *status, + gboolean save) +{ + EmpathyIdle *idle; + + if (!G_STR_EMPTY (status)) { + const gchar *default_status; + + /* Only store the value if it differs from the default ones. */ + default_status = empathy_presence_state_get_default_status (state); + if (save && strcmp (status, default_status) != 0) { + empathy_status_presets_set_last (state, status); + } + } + + idle = empathy_idle_new (); + empathy_idle_set_presence (idle, state, status); + g_object_unref (idle); +} + +static void +presence_chooser_custom_activate_cb (GtkWidget *item, + gpointer user_data) +{ + McPresence state; + + state = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "state")); + + presence_chooser_show_dialog (state); +} + +static void +presence_chooser_show_dialog (McPresence state) +{ + static GtkWidget *dialog = NULL; + static GtkListStore *store[LAST_MC_PRESENCE]; + GladeXML *glade; + GtkWidget *image; + GtkWidget *combo; + GtkWidget *entry; + GtkWidget *checkbutton; + const gchar *default_status; + + if (dialog) { + gtk_widget_destroy (dialog); + dialog = NULL; + } else { + guint i; + + for (i = 0; i < LAST_MC_PRESENCE; i++) { + store[i] = NULL; + } + } + + glade = empathy_glade_get_file ("empathy-presence-chooser.glade", + "status_message_dialog", + NULL, + "status_message_dialog", &dialog, + "comboentry_status", &combo, + "image_status", &image, + "checkbutton_add", &checkbutton, + NULL); + + g_object_unref (glade); + + g_signal_connect (dialog, "destroy", + G_CALLBACK (gtk_widget_destroyed), + &dialog); + g_signal_connect (dialog, "response", + G_CALLBACK (presence_chooser_dialog_response_cb), + NULL); + + gtk_image_set_from_icon_name (GTK_IMAGE (image), + empathy_icon_name_for_presence_state (state), + GTK_ICON_SIZE_MENU); + + if (!store[state]) { + GList *presets, *l; + GtkTreeIter iter; + + store[state] = gtk_list_store_new (1, G_TYPE_STRING); + + presets = empathy_status_presets_get (state, -1); + for (l = presets; l; l = l->next) { + gtk_list_store_append (store[state], &iter); + gtk_list_store_set (store[state], &iter, 0, l->data, -1); + } + + g_list_free (presets); + } + + default_status = empathy_presence_state_get_default_status (state); + + entry = GTK_BIN (combo)->child; + gtk_entry_set_text (GTK_ENTRY (entry), default_status); + gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); + gtk_entry_set_width_chars (GTK_ENTRY (entry), 25); + + gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (store[state])); + gtk_combo_box_entry_set_text_column (GTK_COMBO_BOX_ENTRY (combo), 0); + + /* FIXME: Set transian for a window ? */ + + g_object_set_data (G_OBJECT (dialog), "store", store[state]); + g_object_set_data (G_OBJECT (dialog), "entry", entry); + g_object_set_data (G_OBJECT (dialog), "checkbutton", checkbutton); + g_object_set_data (G_OBJECT (dialog), "state", GINT_TO_POINTER (state)); + + gtk_widget_show_all (dialog); +} + +static void +presence_chooser_dialog_response_cb (GtkWidget *dialog, + gint response, + gpointer user_data) +{ + if (response == GTK_RESPONSE_OK) { + GtkWidget *entry; + GtkWidget *checkbutton; + GtkListStore *store; + GtkTreeModel *model; + GtkTreeIter iter; + McPresence state; + const gchar *status; + gboolean save; + gboolean duplicate = FALSE; + gboolean has_next; + + entry = g_object_get_data (G_OBJECT (dialog), "entry"); + status = gtk_entry_get_text (GTK_ENTRY (entry)); + store = g_object_get_data (G_OBJECT (dialog), "store"); + model = GTK_TREE_MODEL (store); + + has_next = gtk_tree_model_get_iter_first (model, &iter); + while (has_next) { + gchar *str; + + gtk_tree_model_get (model, &iter, + 0, &str, + -1); + + if (strcmp (status, str) == 0) { + g_free (str); + duplicate = TRUE; + break; + } + + g_free (str); + + has_next = gtk_tree_model_iter_next (model, &iter); + } + + if (!duplicate) { + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, status, -1); + } + + checkbutton = g_object_get_data (G_OBJECT (dialog), "checkbutton"); + save = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton)); + state = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), "state")); + + presence_chooser_set_state (state, status, save); + } + + gtk_widget_destroy (dialog); +} + diff --git a/libempathy-gtk/empathy-presence-chooser.glade b/libempathy-gtk/empathy-presence-chooser.glade new file mode 100644 index 00000000..f9f1d4eb --- /dev/null +++ b/libempathy-gtk/empathy-presence-chooser.glade @@ -0,0 +1,173 @@ + + + + + + + + 5 + Status Message Presets + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + False + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + False + + + + True + False + 2 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + + True + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + True + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 5 + True + False + 6 + + + + True + False + 6 + + + + True + 0.5 + 0.5 + 0 + 0 + + + 0 + False + True + + + + + + True + Enter status message: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + False + True + True + + + 0 + False + False + + + + + + True + True + _Add to status message list + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + 0 + True + True + + + + + + + diff --git a/libempathy-gtk/empathy-presence-chooser.h b/libempathy-gtk/empathy-presence-chooser.h new file mode 100644 index 00000000..09023c27 --- /dev/null +++ b/libempathy-gtk/empathy-presence-chooser.h @@ -0,0 +1,58 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2005-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Richard Hult + * Martyn Russell + */ + +#ifndef __EMPATHY_PRESENCE_CHOOSER_H__ +#define __EMPATHY_PRESENCE_CHOOSER_H__ + +#include + +#include + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_PRESENCE_CHOOSER (empathy_presence_chooser_get_type ()) +#define EMPATHY_PRESENCE_CHOOSER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_PRESENCE_CHOOSER, EmpathyPresenceChooser)) +#define EMPATHY_PRESENCE_CHOOSER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_PRESENCE_CHOOSER, EmpathyPresenceChooserClass)) +#define EMPATHY_IS_PRESENCE_CHOOSER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_PRESENCE_CHOOSER)) +#define EMPATHY_IS_PRESENCE_CHOOSER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_PRESENCE_CHOOSER)) +#define EMPATHY_PRESENCE_CHOOSER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_PRESENCE_CHOOSER, EmpathyPresenceChooserClass)) + +typedef struct _EmpathyPresenceChooser EmpathyPresenceChooser; +typedef struct _EmpathyPresenceChooserClass EmpathyPresenceChooserClass; + +struct _EmpathyPresenceChooser { + GtkToggleButton parent; +}; + +struct _EmpathyPresenceChooserClass { + GtkToggleButtonClass parent_class; +}; + +GType empathy_presence_chooser_get_type (void) G_GNUC_CONST; +GtkWidget *empathy_presence_chooser_new (void); +GtkWidget *empathy_presence_chooser_create_menu (void); + +G_END_DECLS + +#endif /* __EMPATHY_PRESENCE_CHOOSER_H__ */ + diff --git a/libempathy-gtk/empathy-private-chat.c b/libempathy-gtk/empathy-private-chat.c new file mode 100644 index 00000000..ddc0633e --- /dev/null +++ b/libempathy-gtk/empathy-private-chat.c @@ -0,0 +1,374 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2002-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Richard Hult + * Martyn Russell + * Geert-Jan Van den Bogaerde + * Xavier Claessens + */ + +#include "config.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include +//#include + +#include "empathy-private-chat.h" +#include "empathy-chat-view.h" +#include "empathy-chat.h" +#include "empathy-preferences.h" +//#include "empathy-sound.h" +#include "empathy-images.h" +#include "empathy-ui-utils.h" + +#define DEBUG_DOMAIN "PrivateChat" + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_PRIVATE_CHAT, EmpathyPrivateChatPriv)) + +struct _EmpathyPrivateChatPriv { + EmpathyContact *contact; + gchar *name; + + gboolean is_online; + + GtkWidget *widget; + GtkWidget *text_view_sw; +}; + +static void empathy_private_chat_class_init (EmpathyPrivateChatClass *klass); +static void empathy_private_chat_init (EmpathyPrivateChat *chat); +static void private_chat_finalize (GObject *object); +static void private_chat_create_ui (EmpathyPrivateChat *chat); +static void private_chat_contact_presence_updated_cb (EmpathyContact *contact, + GParamSpec *param, + EmpathyPrivateChat *chat); +static void private_chat_contact_updated_cb (EmpathyContact *contact, + GParamSpec *param, + EmpathyPrivateChat *chat); +static void private_chat_widget_destroy_cb (GtkWidget *widget, + EmpathyPrivateChat *chat); +static const gchar * private_chat_get_name (EmpathyChat *chat); +static gchar * private_chat_get_tooltip (EmpathyChat *chat); +static const gchar * private_chat_get_status_icon_name (EmpathyChat *chat); +static GtkWidget * private_chat_get_widget (EmpathyChat *chat); + +G_DEFINE_TYPE (EmpathyPrivateChat, empathy_private_chat, EMPATHY_TYPE_CHAT); + +static void +empathy_private_chat_class_init (EmpathyPrivateChatClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + EmpathyChatClass *chat_class = EMPATHY_CHAT_CLASS (klass); + + object_class->finalize = private_chat_finalize; + + chat_class->get_name = private_chat_get_name; + chat_class->get_tooltip = private_chat_get_tooltip; + chat_class->get_status_icon_name = private_chat_get_status_icon_name; + chat_class->get_widget = private_chat_get_widget; + chat_class->set_tp_chat = NULL; + + g_type_class_add_private (object_class, sizeof (EmpathyPrivateChatPriv)); +} + +static void +empathy_private_chat_init (EmpathyPrivateChat *chat) +{ + EmpathyPrivateChatPriv *priv; + + priv = GET_PRIV (chat); + + priv->is_online = FALSE; + + private_chat_create_ui (chat); +} + +static void +private_chat_finalize (GObject *object) +{ + EmpathyPrivateChat *chat; + EmpathyPrivateChatPriv *priv; + + chat = EMPATHY_PRIVATE_CHAT (object); + priv = GET_PRIV (chat); + + g_signal_handlers_disconnect_by_func (priv->contact, + private_chat_contact_updated_cb, + chat); + g_signal_handlers_disconnect_by_func (priv->contact, + private_chat_contact_presence_updated_cb, + chat); + + if (priv->contact) { + g_object_unref (priv->contact); + } + + g_free (priv->name); + + G_OBJECT_CLASS (empathy_private_chat_parent_class)->finalize (object); +} + +static void +private_chat_create_ui (EmpathyPrivateChat *chat) +{ + GladeXML *glade; + EmpathyPrivateChatPriv *priv; + GtkWidget *input_text_view_sw; + + priv = GET_PRIV (chat); + + glade = empathy_glade_get_file ("empathy-chat.glade", + "chat_widget", + NULL, + "chat_widget", &priv->widget, + "chat_view_sw", &priv->text_view_sw, + "input_text_view_sw", &input_text_view_sw, + NULL); + + empathy_glade_connect (glade, + chat, + "chat_widget", "destroy", private_chat_widget_destroy_cb, + NULL); + + g_object_unref (glade); + + g_object_set_data (G_OBJECT (priv->widget), "chat", g_object_ref (chat)); + + gtk_container_add (GTK_CONTAINER (priv->text_view_sw), + GTK_WIDGET (EMPATHY_CHAT (chat)->view)); + gtk_widget_show (GTK_WIDGET (EMPATHY_CHAT (chat)->view)); + + gtk_container_add (GTK_CONTAINER (input_text_view_sw), + EMPATHY_CHAT (chat)->input_text_view); + gtk_widget_show (EMPATHY_CHAT (chat)->input_text_view); +} + +static void +private_chat_contact_presence_updated_cb (EmpathyContact *contact, + GParamSpec *param, + EmpathyPrivateChat *chat) +{ + EmpathyPrivateChatPriv *priv; + + priv = GET_PRIV (chat); + + empathy_debug (DEBUG_DOMAIN, "Presence update for contact: %s", + empathy_contact_get_id (contact)); + + if (!empathy_contact_is_online (contact)) { + if (priv->is_online) { + gchar *msg; + + msg = g_strdup_printf (_("%s went offline"), + empathy_contact_get_name (priv->contact)); + empathy_chat_view_append_event (EMPATHY_CHAT (chat)->view, msg); + g_free (msg); + } + + priv->is_online = FALSE; + + g_signal_emit_by_name (chat, "composing", FALSE); + + } else { + if (!priv->is_online) { + gchar *msg; + + msg = g_strdup_printf (_("%s has come online"), + empathy_contact_get_name (priv->contact)); + empathy_chat_view_append_event (EMPATHY_CHAT (chat)->view, msg); + g_free (msg); + } + + priv->is_online = TRUE; + } + + g_signal_emit_by_name (chat, "status-changed"); +} + +static void +private_chat_contact_updated_cb (EmpathyContact *contact, + GParamSpec *param, + EmpathyPrivateChat *chat) +{ + EmpathyPrivateChatPriv *priv; + + priv = GET_PRIV (chat); + + if (strcmp (priv->name, empathy_contact_get_name (contact)) != 0) { + g_free (priv->name); + priv->name = g_strdup (empathy_contact_get_name (contact)); + g_signal_emit_by_name (chat, "name-changed", priv->name); + } +} + +static void +private_chat_widget_destroy_cb (GtkWidget *widget, + EmpathyPrivateChat *chat) +{ + empathy_debug (DEBUG_DOMAIN, "Destroyed"); + + g_object_unref (chat); +} + +static const gchar * +private_chat_get_name (EmpathyChat *chat) +{ + EmpathyPrivateChatPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_PRIVATE_CHAT (chat), NULL); + + priv = GET_PRIV (chat); + + return priv->name; +} + +static gchar * +private_chat_get_tooltip (EmpathyChat *chat) +{ + EmpathyPrivateChatPriv *priv; + const gchar *status; + + g_return_val_if_fail (EMPATHY_IS_PRIVATE_CHAT (chat), NULL); + + priv = GET_PRIV (chat); + + status = empathy_contact_get_status (priv->contact); + + return g_strdup_printf ("%s\n%s", + empathy_contact_get_id (priv->contact), + status); +} + +static const gchar * +private_chat_get_status_icon_name (EmpathyChat *chat) +{ + EmpathyPrivateChatPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_PRIVATE_CHAT (chat), NULL); + + priv = GET_PRIV (chat); + + return empathy_icon_name_for_contact (priv->contact); +} + +EmpathyContact * +empathy_private_chat_get_contact (EmpathyPrivateChat *chat) +{ + EmpathyPrivateChatPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_PRIVATE_CHAT (chat), NULL); + + priv = GET_PRIV (chat); + + return priv->contact; +} + +static GtkWidget * +private_chat_get_widget (EmpathyChat *chat) +{ + EmpathyPrivateChatPriv *priv; + + priv = GET_PRIV (chat); + + return priv->widget; +} + +static void +private_chat_setup (EmpathyPrivateChat *chat, + EmpathyContact *contact, + EmpathyTpChat *tp_chat) +{ + EmpathyPrivateChatPriv *priv; + + priv = GET_PRIV (chat); + + EMPATHY_CHAT (chat)->account = g_object_ref (empathy_contact_get_account (contact)); + priv->contact = g_object_ref (contact); + priv->name = g_strdup (empathy_contact_get_name (contact)); + + empathy_chat_set_tp_chat (EMPATHY_CHAT (chat), tp_chat); + + g_signal_connect (priv->contact, + "notify::name", + G_CALLBACK (private_chat_contact_updated_cb), + chat); + g_signal_connect (priv->contact, + "notify::presence", + G_CALLBACK (private_chat_contact_presence_updated_cb), + chat); + + priv->is_online = empathy_contact_is_online (priv->contact); +} + +EmpathyPrivateChat * +empathy_private_chat_new (McAccount *account, + TpChan *tp_chan) +{ + EmpathyPrivateChat *chat; + EmpathyTpChat *tp_chat; + EmpathyContactManager *manager; + EmpathyTpContactList *list; + EmpathyContact *contact; + + g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + g_return_val_if_fail (TELEPATHY_IS_CHAN (tp_chan), NULL); + + manager = empathy_contact_manager_new (); + list = empathy_contact_manager_get_list (manager, account); + contact = empathy_tp_contact_list_get_from_handle (list, tp_chan->handle); + + chat = g_object_new (EMPATHY_TYPE_PRIVATE_CHAT, NULL); + tp_chat = empathy_tp_chat_new (account, tp_chan); + + private_chat_setup (chat, contact, tp_chat); + + g_object_unref (tp_chat); + g_object_unref (contact); + g_object_unref (manager); + + return chat; +} + +EmpathyPrivateChat * +empathy_private_chat_new_with_contact (EmpathyContact *contact) +{ + EmpathyPrivateChat *chat; + EmpathyTpChat *tp_chat; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + + chat = g_object_new (EMPATHY_TYPE_PRIVATE_CHAT, NULL); + tp_chat = empathy_tp_chat_new_with_contact (contact); + + private_chat_setup (chat, contact, tp_chat); + g_object_unref (tp_chat); + + return chat; +} + diff --git a/libempathy-gtk/empathy-private-chat.h b/libempathy-gtk/empathy-private-chat.h new file mode 100644 index 00000000..b13eede7 --- /dev/null +++ b/libempathy-gtk/empathy-private-chat.h @@ -0,0 +1,68 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2002-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Richard Hult + * Martyn Russell + * Geert-Jan Van den Bogaerde + * Xavier Claessens + */ + +#ifndef __EMPATHY_PRIVATE_CHAT_H__ +#define __EMPATHY_PRIVATE_CHAT_H__ + +#include + +#include + +#include + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_PRIVATE_CHAT (empathy_private_chat_get_type ()) +#define EMPATHY_PRIVATE_CHAT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_PRIVATE_CHAT, EmpathyPrivateChat)) +#define EMPATHY_PRIVATE_CHAT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_PRIVATE_CHAT, EmpathyPrivateChatClass)) +#define EMPATHY_IS_PRIVATE_CHAT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_PRIVATE_CHAT)) +#define EMPATHY_IS_PRIVATE_CHAT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_PRIVATE_CHAT)) +#define EMPATHY_PRIVATE_CHAT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_PRIVATE_CHAT, EmpathyPrivateChatClass)) + +typedef struct _EmpathyPrivateChat EmpathyPrivateChat; +typedef struct _EmpathyPrivateChatClass EmpathyPrivateChatClass; +typedef struct _EmpathyPrivateChatPriv EmpathyPrivateChatPriv; + +#include "empathy-chat.h" + +struct _EmpathyPrivateChat { + EmpathyChat parent; +}; + +struct _EmpathyPrivateChatClass { + EmpathyChatClass parent; +}; + +GType empathy_private_chat_get_type (void); +EmpathyPrivateChat * empathy_private_chat_new (McAccount *account, + TpChan *tp_chan); +EmpathyPrivateChat * empathy_private_chat_new_with_contact (EmpathyContact *contact); +EmpathyContact * empathy_private_chat_get_contact (EmpathyPrivateChat *chat); + +G_END_DECLS + +#endif /* __EMPATHY_PRIVATE_CHAT_H__ */ diff --git a/libempathy-gtk/empathy-profile-chooser.c b/libempathy-gtk/empathy-profile-chooser.c new file mode 100644 index 00000000..1885c2fb --- /dev/null +++ b/libempathy-gtk/empathy-profile-chooser.c @@ -0,0 +1,106 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Xavier Claessens + */ + +#include + +#include +#include + +#include + +#include "empathy-profile-chooser.h" + +enum { + COL_ICON, + COL_LABEL, + COL_PROFILE, + COL_COUNT +}; + +McProfile* +empathy_profile_chooser_get_selected (GtkWidget *widget) +{ + GtkTreeModel *model; + GtkTreeIter iter; + McProfile *profile = NULL; + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget)); + if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter)) { + gtk_tree_model_get (model, &iter, + COL_PROFILE, &profile, + -1); + } + + return profile; +} + +GtkWidget * +empathy_profile_chooser_new (void) +{ + GList *profiles, *l; + GtkListStore *store; + GtkCellRenderer *renderer; + GtkWidget *combo_box; + GtkTreeIter iter; + + /* set up combo box with new store */ + store = gtk_list_store_new (COL_COUNT, + G_TYPE_STRING, /* Icon name */ + G_TYPE_STRING, /* Label */ + MC_TYPE_PROFILE); /* Profile */ + combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store)); + + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, FALSE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer, + "icon-name", COL_ICON, + NULL); + g_object_set (renderer, "stock-size", GTK_ICON_SIZE_BUTTON, NULL); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer, + "text", COL_LABEL, + NULL); + + profiles = mc_profiles_list (); + for (l = profiles; l; l = l->next) { + McProfile *profile; + + profile = l->data; + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + COL_ICON, mc_profile_get_icon_name (profile), + COL_LABEL, mc_profile_get_display_name (profile), + COL_PROFILE, profile, + -1); + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter); + } + + mc_profiles_free_list (profiles); + g_object_unref (store); + + return combo_box; +} + diff --git a/libempathy-gtk/empathy-profile-chooser.h b/libempathy-gtk/empathy-profile-chooser.h new file mode 100644 index 00000000..6a9c405a --- /dev/null +++ b/libempathy-gtk/empathy-profile-chooser.h @@ -0,0 +1,34 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Xavier Claessens + */ + +#ifndef __EMPATHY_PROTOCOL_CHOOSER_H__ +#define __EMPATHY_PROTOCOL_CHOOSER_H__ + +#include + +G_BEGIN_DECLS + +GtkWidget * empathy_profile_chooser_new (void); +McProfile * empathy_profile_chooser_get_selected (GtkWidget *widget); + +G_END_DECLS +#endif /* __EMPATHY_PROTOCOL_CHOOSER_H__ */ diff --git a/libempathy-gtk/empathy-spell-dialog.c b/libempathy-gtk/empathy-spell-dialog.c new file mode 100644 index 00000000..7f4d75a1 --- /dev/null +++ b/libempathy-gtk/empathy-spell-dialog.c @@ -0,0 +1,267 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "empathy-chat.h" +#include "empathy-spell-dialog.h" +#include "empathy-ui-utils.h" + +typedef struct { + GtkWidget *window; + GtkWidget *button_replace; + GtkWidget *label_word; + GtkWidget *treeview_words; + + EmpathyChat *chat; + + gchar *word; + GtkTextIter start; + GtkTextIter end; +} EmpathySpellDialog; + +enum { + COL_SPELL_WORD, + COL_SPELL_COUNT +}; + +static void spell_dialog_model_populate_columns (EmpathySpellDialog *dialog); +static void spell_dialog_model_populate_suggestions (EmpathySpellDialog *dialog); +static void spell_dialog_model_row_activated_cb (GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + EmpathySpellDialog *dialog); +static void spell_dialog_model_selection_changed_cb (GtkTreeSelection *treeselection, + EmpathySpellDialog *dialog); +static void spell_dialog_model_setup (EmpathySpellDialog *dialog); +static void spell_dialog_response_cb (GtkWidget *widget, + gint response, + EmpathySpellDialog *dialog); +static void spell_dialog_destroy_cb (GtkWidget *widget, + EmpathySpellDialog *dialog); + +static void +spell_dialog_model_populate_columns (EmpathySpellDialog *dialog) +{ + GtkTreeModel *model; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + guint col_offset; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview_words)); + + renderer = gtk_cell_renderer_text_new (); + col_offset = gtk_tree_view_insert_column_with_attributes ( + GTK_TREE_VIEW (dialog->treeview_words), + -1, _("Word"), + renderer, + "text", COL_SPELL_WORD, + NULL); + + g_object_set_data (G_OBJECT (renderer), + "column", GINT_TO_POINTER (COL_SPELL_WORD)); + + column = gtk_tree_view_get_column (GTK_TREE_VIEW (dialog->treeview_words), col_offset - 1); + gtk_tree_view_column_set_sort_column_id (column, COL_SPELL_WORD); + gtk_tree_view_column_set_resizable (column, FALSE); + gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); +} + +static void +spell_dialog_model_populate_suggestions (EmpathySpellDialog *dialog) +{ + GtkTreeModel *model; + GtkListStore *store; + GList *suggestions, *l; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview_words)); + store = GTK_LIST_STORE (model); + + suggestions = empathy_spell_get_suggestions (dialog->word); + for (l = suggestions; l; l=l->next) { + GtkTreeIter iter; + gchar *word; + + word = l->data; + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + COL_SPELL_WORD, word, + -1); + } + + empathy_spell_free_suggestions (suggestions); +} + +static void +spell_dialog_model_row_activated_cb (GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + EmpathySpellDialog *dialog) +{ + spell_dialog_response_cb (dialog->window, GTK_RESPONSE_OK, dialog); +} + +static void +spell_dialog_model_selection_changed_cb (GtkTreeSelection *treeselection, + EmpathySpellDialog *dialog) +{ + gint count; + + count = gtk_tree_selection_count_selected_rows (treeselection); + gtk_widget_set_sensitive (dialog->button_replace, (count == 1)); +} + +static void +spell_dialog_model_setup (EmpathySpellDialog *dialog) +{ + GtkTreeView *view; + GtkListStore *store; + GtkTreeSelection *selection; + + view = GTK_TREE_VIEW (dialog->treeview_words); + + g_signal_connect (view, "row-activated", + G_CALLBACK (spell_dialog_model_row_activated_cb), + dialog); + + store = gtk_list_store_new (COL_SPELL_COUNT, + G_TYPE_STRING); /* word */ + + gtk_tree_view_set_model (view, GTK_TREE_MODEL (store)); + + selection = gtk_tree_view_get_selection (view); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + + g_signal_connect (selection, "changed", + G_CALLBACK (spell_dialog_model_selection_changed_cb), + dialog); + + spell_dialog_model_populate_columns (dialog); + spell_dialog_model_populate_suggestions (dialog); + + g_object_unref (store); +} + +static void +spell_dialog_destroy_cb (GtkWidget *widget, + EmpathySpellDialog *dialog) +{ + g_object_unref (dialog->chat); + g_free (dialog->word); + + g_free (dialog); +} + +static void +spell_dialog_response_cb (GtkWidget *widget, + gint response, + EmpathySpellDialog *dialog) +{ + if (response == GTK_RESPONSE_OK) { + GtkTreeView *view; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + + gchar *new_word; + + view = GTK_TREE_VIEW (dialog->treeview_words); + selection = gtk_tree_view_get_selection (view); + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { + return; + } + + gtk_tree_model_get (model, &iter, COL_SPELL_WORD, &new_word, -1); + + empathy_chat_correct_word (dialog->chat, + dialog->start, + dialog->end, + new_word); + + g_free (new_word); + } + + gtk_widget_destroy (dialog->window); +} + +void +empathy_spell_dialog_show (EmpathyChat *chat, + GtkTextIter start, + GtkTextIter end, + const gchar *word) +{ + EmpathySpellDialog *dialog; + GladeXML *gui; + gchar *str; + + g_return_if_fail (chat != NULL); + g_return_if_fail (word != NULL); + + dialog = g_new0 (EmpathySpellDialog, 1); + + dialog->chat = g_object_ref (chat); + + dialog->word = g_strdup (word); + + dialog->start = start; + dialog->end = end; + + gui = empathy_glade_get_file ("empathy-spell-dialog.glade", + "spell_dialog", + NULL, + "spell_dialog", &dialog->window, + "button_replace", &dialog->button_replace, + "label_word", &dialog->label_word, + "treeview_words", &dialog->treeview_words, + NULL); + + empathy_glade_connect (gui, + dialog, + "spell_dialog", "response", spell_dialog_response_cb, + "spell_dialog", "destroy", spell_dialog_destroy_cb, + NULL); + + g_object_unref (gui); + + str = g_strdup_printf ("%s:\n%s", + _("Suggestions for the word"), + word); + + gtk_label_set_markup (GTK_LABEL (dialog->label_word), str); + g_free (str); + + spell_dialog_model_setup (dialog); + + gtk_widget_show (dialog->window); +} diff --git a/libempathy-gtk/empathy-spell-dialog.glade b/libempathy-gtk/empathy-spell-dialog.glade new file mode 100644 index 00000000..502fb0d1 --- /dev/null +++ b/libempathy-gtk/empathy-spell-dialog.glade @@ -0,0 +1,205 @@ + + + + + + + 5 + Spell Checker + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + True + 275 + 225 + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + False + + + + True + False + 2 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + + True + False + True + True + GTK_RELIEF_NORMAL + True + -5 + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-convert + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + _Replace + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + 0 + False + True + GTK_PACK_END + + + + + + 5 + True + False + 6 + + + + True + Suggestions for the word: + False + True + GTK_JUSTIFY_LEFT + True + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + False + False + True + False + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + + diff --git a/libempathy-gtk/empathy-spell-dialog.h b/libempathy-gtk/empathy-spell-dialog.h new file mode 100644 index 00000000..e6d2e4c7 --- /dev/null +++ b/libempathy-gtk/empathy-spell-dialog.h @@ -0,0 +1,39 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Martyn Russell + * Richard Hult + */ + +#ifndef __EMPATHY_SPELL_DIALOG_H__ +#define __EMPATHY_SPELL_DIALOG_H__ + +#include +#include "empathy-chat.h" + +G_BEGIN_DECLS + +void empathy_spell_dialog_show (EmpathyChat *chat, + GtkTextIter start, + GtkTextIter end, + const gchar *word); + +G_END_DECLS + +#endif /* __EMPATHY_SPELL_DIALOG_H__ */ diff --git a/libempathy-gtk/empathy-spell.c b/libempathy-gtk/empathy-spell.c new file mode 100644 index 00000000..88696cca --- /dev/null +++ b/libempathy-gtk/empathy-spell.c @@ -0,0 +1,452 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Martyn Russell + * Richard Hult + */ + +#include "config.h" + +#include +#include + +#include + +#ifdef HAVE_ASPELL +#include +#endif + +#include +#include + +#include "empathy-spell.h" +#include "empathy-preferences.h" + +#define DEBUG_DOMAIN "Spell" + +#ifdef HAVE_ASPELL + +/* Note: We could use aspell_reset_cache (NULL); periodically if we wanted + * to... + */ + +typedef struct { + AspellConfig *spell_config; + AspellCanHaveError *spell_possible_err; + AspellSpeller *spell_checker; +} SpellLanguage; + +#define ISO_CODES_DATADIR ISO_CODES_PREFIX "/share/xml/iso-codes" +#define ISO_CODES_LOCALESDIR ISO_CODES_PREFIX "/share/locale" + +static GHashTable *iso_code_names = NULL; +static GList *languages = NULL; +static gboolean empathy_conf_notify_inited = FALSE; + +static void +spell_iso_codes_parse_start_tag (GMarkupParseContext *ctx, + const gchar *element_name, + const gchar **attr_names, + const gchar **attr_values, + gpointer data, + GError **error) +{ + const gchar *ccode_longB, *ccode_longT, *ccode; + const gchar *lang_name; + + if (!g_str_equal (element_name, "iso_639_entry") || + attr_names == NULL || attr_values == NULL) { + return; + } + + ccode = NULL; + ccode_longB = NULL; + ccode_longT = NULL; + lang_name = NULL; + + while (*attr_names && *attr_values) { + if (g_str_equal (*attr_names, "iso_639_1_code")) { + if (**attr_values) { + ccode = *attr_values; + } + } + else if (g_str_equal (*attr_names, "iso_639_2B_code")) { + if (**attr_values) { + ccode_longB = *attr_values; + } + } + else if (g_str_equal (*attr_names, "iso_639_2T_code")) { + if (**attr_values) { + ccode_longT = *attr_values; + } + } + else if (g_str_equal (*attr_names, "name")) { + lang_name = *attr_values; + } + + attr_names++; + attr_values++; + } + + if (!lang_name) { + return; + } + + if (ccode) { + g_hash_table_insert (iso_code_names, + g_strdup (ccode), + g_strdup (lang_name)); + } + + if (ccode_longB) { + g_hash_table_insert (iso_code_names, + g_strdup (ccode_longB), + g_strdup (lang_name)); + } + + if (ccode_longT) { + g_hash_table_insert (iso_code_names, + g_strdup (ccode_longT), + g_strdup (lang_name)); + } +} + +static void +spell_iso_code_names_init (void) +{ + GError *err = NULL; + gchar *buf; + gsize buf_len; + + iso_code_names = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); + + bindtextdomain ("iso_639", ISO_CODES_LOCALESDIR); + bind_textdomain_codeset ("iso_639", "UTF-8"); + + /* FIXME: We should read this in chunks and pass to the parser. */ + if (g_file_get_contents (ISO_CODES_DATADIR "/iso_639.xml", &buf, &buf_len, &err)) { + GMarkupParseContext *ctx; + GMarkupParser parser = { + spell_iso_codes_parse_start_tag, + NULL, NULL, NULL, NULL + }; + + ctx = g_markup_parse_context_new (&parser, 0, NULL, NULL); + if (!g_markup_parse_context_parse (ctx, buf, buf_len, &err)) { + g_warning ("Failed to parse '%s': %s", + ISO_CODES_DATADIR"/iso_639.xml", + err->message); + g_error_free (err); + } + + g_markup_parse_context_free (ctx); + g_free (buf); + } else { + g_warning ("Failed to load '%s': %s", + ISO_CODES_DATADIR"/iso_639.xml", err->message); + g_error_free (err); + } +} + +static void +spell_notify_languages_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data) +{ + GList *l; + + empathy_debug (DEBUG_DOMAIN, "Resetting languages due to config change"); + + /* We just reset the languages list. */ + for (l = languages; l; l = l->next) { + SpellLanguage *lang; + + lang = l->data; + + delete_aspell_config (lang->spell_config); + delete_aspell_speller (lang->spell_checker); + + g_slice_free (SpellLanguage, lang); + } + + g_list_free (languages); + languages = NULL; +} + +static void +spell_setup_languages (void) +{ + gchar *str; + + if (!empathy_conf_notify_inited) { + empathy_conf_notify_add (empathy_conf_get (), + EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES, + spell_notify_languages_cb, NULL); + + empathy_conf_notify_inited = TRUE; + } + + if (languages) { + return; + } + + if (empathy_conf_get_string (empathy_conf_get (), + EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES, + &str) && str) { + gchar **strv; + gint i; + + strv = g_strsplit (str, ",", -1); + + i = 0; + while (strv && strv[i]) { + SpellLanguage *lang; + + empathy_debug (DEBUG_DOMAIN, "Setting up language:'%s'", strv[i]); + + lang = g_slice_new0 (SpellLanguage); + + lang->spell_config = new_aspell_config(); + + aspell_config_replace (lang->spell_config, "encoding", "utf-8"); + aspell_config_replace (lang->spell_config, "lang", strv[i++]); + + lang->spell_possible_err = new_aspell_speller (lang->spell_config); + + if (aspell_error_number (lang->spell_possible_err) == 0) { + lang->spell_checker = to_aspell_speller (lang->spell_possible_err); + languages = g_list_append (languages, lang); + } else { + delete_aspell_config (lang->spell_config); + g_slice_free (SpellLanguage, lang); + } + } + + if (strv) { + g_strfreev (strv); + } + + g_free (str); + } +} + +const char * +empathy_spell_get_language_name (const char *code) +{ + const gchar *name; + + g_return_val_if_fail (code != NULL, NULL); + + if (!iso_code_names) { + spell_iso_code_names_init (); + } + + name = g_hash_table_lookup (iso_code_names, code); + if (!name) { + return NULL; + } + + return dgettext ("iso_639", name); +} + +GList * +empathy_spell_get_language_codes (void) +{ + AspellConfig *config; + AspellDictInfoList *dlist; + AspellDictInfoEnumeration *dels; + const AspellDictInfo *entry; + GList *codes = NULL; + + config = new_aspell_config (); + dlist = get_aspell_dict_info_list (config); + dels = aspell_dict_info_list_elements (dlist); + + while ((entry = aspell_dict_info_enumeration_next (dels)) != 0) { + if (g_list_find_custom (codes, entry->code, (GCompareFunc) strcmp)) { + continue; + } + + codes = g_list_append (codes, g_strdup (entry->code)); + } + + delete_aspell_dict_info_enumeration (dels); + delete_aspell_config (config); + + return codes; +} + +void +empathy_spell_free_language_codes (GList *codes) +{ + g_list_foreach (codes, (GFunc) g_free, NULL); + g_list_free (codes); +} + +gboolean +empathy_spell_check (const gchar *word) +{ + GList *l; + gint n_langs; + gboolean correct = FALSE; + gint len; + const gchar *p; + gunichar c; + gboolean digit; + + g_return_val_if_fail (word != NULL, FALSE); + + spell_setup_languages (); + + if (!languages) { + empathy_debug (DEBUG_DOMAIN, "No languages to check against"); + return TRUE; + } + + /* Ignore certain cases like numbers, etc. */ + for (p = word, digit = TRUE; *p && digit; p = g_utf8_next_char (p)) { + c = g_utf8_get_char (p); + digit = g_unichar_isdigit (c); + } + + if (digit) { + /* We don't spell check digits. */ + empathy_debug (DEBUG_DOMAIN, "Not spell checking word:'%s', it is all digits", word); + return TRUE; + } + + len = strlen (word); + n_langs = g_list_length (languages); + for (l = languages; l; l = l->next) { + SpellLanguage *lang; + + lang = l->data; + + correct = aspell_speller_check (lang->spell_checker, word, len); + if (n_langs > 1 && correct) { + break; + } + } + + return correct; +} + +GList * +empathy_spell_get_suggestions (const gchar *word) +{ + GList *l1; + GList *l2 = NULL; + const AspellWordList *suggestions; + AspellStringEnumeration *elements; + const char *next; + gint len; + + g_return_val_if_fail (word != NULL, NULL); + + spell_setup_languages (); + + len = strlen (word); + + for (l1 = languages; l1; l1 = l1->next) { + SpellLanguage *lang; + + lang = l1->data; + + suggestions = aspell_speller_suggest (lang->spell_checker, + word, len); + + elements = aspell_word_list_elements (suggestions); + + while ((next = aspell_string_enumeration_next (elements))) { + l2 = g_list_append (l2, g_strdup (next)); + } + + delete_aspell_string_enumeration (elements); + } + + return l2; +} + +gboolean +empathy_spell_supported (void) +{ + if (g_getenv ("EMPATHY_SPELL_DISABLED")) { + empathy_debug (DEBUG_DOMAIN, "EMPATHY_SPELL_DISABLE env variable defined"); + return FALSE; + } + + return TRUE; +} + +#else /* not HAVE_ASPELL */ + +gboolean +empathy_spell_supported (void) +{ + return FALSE; +} + +GList * +empathy_spell_get_suggestions (const gchar *word) +{ + empathy_debug (DEBUG_DOMAIN, "Support disabled, could not get suggestions"); + + return NULL; +} + +gboolean +empathy_spell_check (const gchar *word) +{ + empathy_debug (DEBUG_DOMAIN, "Support disabled, could not check spelling"); + + return TRUE; +} + +const char * +empathy_spell_get_language_name (const char *lang) +{ + empathy_debug (DEBUG_DOMAIN, "Support disabled, could not get language name"); + + return NULL; +} + +GList * +empathy_spell_get_language_codes (void) +{ + empathy_debug (DEBUG_DOMAIN, "Support disabled, could not get language codes"); + + return NULL; +} + +void +empathy_spell_free_language_codes (GList *codes) +{ +} + +#endif /* HAVE_ASPELL */ + + +void +empathy_spell_free_suggestions (GList *suggestions) +{ + g_list_foreach (suggestions, (GFunc) g_free, NULL); + g_list_free (suggestions); +} + diff --git a/libempathy-gtk/empathy-spell.h b/libempathy-gtk/empathy-spell.h new file mode 100644 index 00000000..4f483cf3 --- /dev/null +++ b/libempathy-gtk/empathy-spell.h @@ -0,0 +1,39 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Martyn Russell + * Richard Hult + */ + +#ifndef __EMPATHY_SPELL_H__ +#define __EMPATHY_SPELL_H__ + +G_BEGIN_DECLS + +gboolean empathy_spell_supported (void); +const gchar *empathy_spell_get_language_name (const gchar *code); +GList *empathy_spell_get_language_codes (void); +void empathy_spell_free_language_codes (GList *codes); +gboolean empathy_spell_check (const gchar *word); +GList * empathy_spell_get_suggestions (const gchar *word); +void empathy_spell_free_suggestions (GList *suggestions); + +G_END_DECLS + +#endif /* __EMPATHY_SPELL_H__ */ diff --git a/libempathy-gtk/empathy-status-icon.c b/libempathy-gtk/empathy-status-icon.c index 17d274ee..b9c1af79 100644 --- a/libempathy-gtk/empathy-status-icon.c +++ b/libempathy-gtk/empathy-status-icon.c @@ -32,18 +32,18 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include "empathy-status-icon.h" #include "empathy-contact-dialogs.h" -#include "gossip-presence-chooser.h" -#include "gossip-preferences.h" -#include "gossip-ui-utils.h" -#include "gossip-accounts-dialog.h" +#include "empathy-presence-chooser.h" +#include "empathy-preferences.h" +#include "empathy-ui-utils.h" +#include "empathy-accounts-dialog.h" #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ @@ -106,7 +106,7 @@ static void status_icon_quit_cb (GtkWidget *windo static void status_icon_show_hide_window_cb (GtkWidget *widget, EmpathyStatusIcon *icon); static void status_icon_local_pending_cb (EmpathyContactManager *manager, - GossipContact *contact, + EmpathyContact *contact, gchar *message, EmpathyStatusIcon *icon); static void status_icon_event_subscribe_cb (StatusIconEvent *event); @@ -211,10 +211,10 @@ empathy_status_icon_new (GtkWindow *window) G_CALLBACK (status_icon_delete_event_cb), icon); - gossip_conf_get_bool (gossip_conf_get (), - GOSSIP_PREFS_UI_MAIN_WINDOW_HIDDEN, + empathy_conf_get_bool (empathy_conf_get (), + EMPATHY_PREFS_UI_MAIN_WINDOW_HIDDEN, &should_hide); - visible = gossip_window_get_is_visible (window); + visible = empathy_window_get_is_visible (window); if ((!should_hide && !visible) || (should_hide && visible)) { status_icon_toggle_visibility (icon); @@ -235,7 +235,7 @@ status_icon_idle_notify_cb (EmpathyStatusIcon *icon) if (flash_state != MC_PRESENCE_UNSET) { const gchar *icon_name; - icon_name = gossip_icon_name_for_presence_state (flash_state); + icon_name = empathy_icon_name_for_presence_state (flash_state); if (!priv->flash_state_event) { /* We are now flashing */ priv->flash_state_event = status_icon_event_new (icon, icon_name, NULL); @@ -293,7 +293,7 @@ status_icon_set_from_state (EmpathyStatusIcon *icon) priv = GET_PRIV (icon); state = empathy_idle_get_state (priv->idle); - icon_name = gossip_icon_name_for_presence_state (state); + icon_name = empathy_icon_name_for_presence_state (state); gtk_status_icon_set_from_icon_name (priv->icon, icon_name); } @@ -305,27 +305,27 @@ status_icon_toggle_visibility (EmpathyStatusIcon *icon) priv = GET_PRIV (icon); - visible = gossip_window_get_is_visible (GTK_WINDOW (priv->window)); + visible = empathy_window_get_is_visible (GTK_WINDOW (priv->window)); if (visible) { gtk_widget_hide (GTK_WIDGET (priv->window)); - gossip_conf_set_bool (gossip_conf_get (), - GOSSIP_PREFS_UI_MAIN_WINDOW_HIDDEN, TRUE); + empathy_conf_set_bool (empathy_conf_get (), + EMPATHY_PREFS_UI_MAIN_WINDOW_HIDDEN, TRUE); } else { GList *accounts; - gossip_window_present (GTK_WINDOW (priv->window), TRUE); - gossip_conf_set_bool (gossip_conf_get (), - GOSSIP_PREFS_UI_MAIN_WINDOW_HIDDEN, FALSE); + empathy_window_present (GTK_WINDOW (priv->window), TRUE); + empathy_conf_set_bool (empathy_conf_get (), + EMPATHY_PREFS_UI_MAIN_WINDOW_HIDDEN, FALSE); /* Show the accounts dialog if there is no enabled accounts */ accounts = mc_accounts_list_by_enabled (TRUE); if (accounts) { mc_accounts_list_free (accounts); } else { - gossip_debug (DEBUG_DOMAIN, + empathy_debug (DEBUG_DOMAIN, "No enabled account, Showing account dialog"); - gossip_accounts_dialog_show (GTK_WINDOW (priv->window)); + empathy_accounts_dialog_show (GTK_WINDOW (priv->window)); } } } @@ -367,7 +367,7 @@ status_icon_popup_menu_cb (GtkStatusIcon *status_icon, priv = GET_PRIV (icon); - show = gossip_window_get_is_visible (GTK_WINDOW (priv->window)); + show = empathy_window_get_is_visible (GTK_WINDOW (priv->window)); g_signal_handlers_block_by_func (priv->show_window_item, status_icon_show_hide_window_cb, @@ -378,7 +378,7 @@ status_icon_popup_menu_cb (GtkStatusIcon *status_icon, status_icon_show_hide_window_cb, icon); - submenu = gossip_presence_chooser_create_menu (); + submenu = empathy_presence_chooser_create_menu (); gtk_menu_item_set_submenu (GTK_MENU_ITEM (priv->status_item), submenu); @@ -398,7 +398,7 @@ status_icon_create_menu (EmpathyStatusIcon *icon) priv = GET_PRIV (icon); - glade = gossip_glade_get_file ("empathy-status-icon.glade", + glade = empathy_glade_get_file ("empathy-status-icon.glade", "tray_menu", NULL, "tray_menu", &priv->popup_menu, @@ -407,7 +407,7 @@ status_icon_create_menu (EmpathyStatusIcon *icon) "tray_status", &priv->status_item, NULL); - gossip_glade_connect (glade, + empathy_glade_connect (glade, icon, "tray_new_message", "activate", status_icon_new_message_cb, "tray_quit", "activate", status_icon_quit_cb, @@ -428,7 +428,7 @@ status_icon_new_message_cb (GtkWidget *widget, priv = GET_PRIV (icon); - //gossip_new_message_dialog_show (GTK_WINDOW (priv->window)); + //empathy_new_message_dialog_show (GTK_WINDOW (priv->window)); } static void @@ -447,7 +447,7 @@ status_icon_show_hide_window_cb (GtkWidget *widget, static void status_icon_local_pending_cb (EmpathyContactManager *manager, - GossipContact *contact, + EmpathyContact *contact, gchar *message, EmpathyStatusIcon *icon) { @@ -459,14 +459,14 @@ status_icon_local_pending_cb (EmpathyContactManager *manager, priv = GET_PRIV (icon); for (l = priv->events; l; l = l->next) { - if (gossip_contact_equal (contact, ((StatusIconEvent*)l->data)->user_data)) { + if (empathy_contact_equal (contact, ((StatusIconEvent*)l->data)->user_data)) { return; } } str = g_strdup_printf (_("Subscription requested for %s\n" "Message: %s"), - gossip_contact_get_name (contact), + empathy_contact_get_name (contact), message); event = status_icon_event_new (icon, GTK_STOCK_DIALOG_QUESTION, str); @@ -479,9 +479,9 @@ status_icon_local_pending_cb (EmpathyContactManager *manager, static void status_icon_event_subscribe_cb (StatusIconEvent *event) { - GossipContact *contact; + EmpathyContact *contact; - contact = GOSSIP_CONTACT (event->user_data); + contact = EMPATHY_CONTACT (event->user_data); empathy_subscription_dialog_show (contact, NULL); diff --git a/libempathy-gtk/empathy-status-presets.c b/libempathy-gtk/empathy-status-presets.c new file mode 100644 index 00000000..80ce4149 --- /dev/null +++ b/libempathy-gtk/empathy-status-presets.c @@ -0,0 +1,389 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2005-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Martyn Russell + */ + +#include "config.h" + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include "empathy-status-presets.h" + +#define DEBUG_DOMAIN "StatusPresets" + +#define STATUS_PRESETS_XML_FILENAME "status-presets.xml" +#define STATUS_PRESETS_DTD_FILENAME "empathy-status-presets.dtd" +#define STATUS_PRESETS_MAX_EACH 15 + +typedef struct { + gchar *status; + McPresence state; +} StatusPreset; + +static StatusPreset *status_preset_new (McPresence state, + const gchar *status); +static void status_preset_free (StatusPreset *status); +static void status_presets_file_parse (const gchar *filename); +const gchar * status_presets_get_state_as_str (McPresence state); +static gboolean status_presets_file_save (void); +static void status_presets_set_default (McPresence state, + const gchar *status); + +static GList *presets = NULL; +static StatusPreset *default_preset = NULL; + +static StatusPreset * +status_preset_new (McPresence state, + const gchar *status) +{ + StatusPreset *preset; + + preset = g_new0 (StatusPreset, 1); + + preset->status = g_strdup (status); + preset->state = state; + + return preset; +} + +static void +status_preset_free (StatusPreset *preset) +{ + g_free (preset->status); + g_free (preset); +} + +static void +status_presets_file_parse (const gchar *filename) +{ + xmlParserCtxtPtr ctxt; + xmlDocPtr doc; + xmlNodePtr presets_node; + xmlNodePtr node; + + empathy_debug (DEBUG_DOMAIN, "Attempting to parse file:'%s'...", filename); + + ctxt = xmlNewParserCtxt (); + + /* Parse and validate the file. */ + doc = xmlCtxtReadFile (ctxt, filename, NULL, 0); + if (!doc) { + g_warning ("Failed to parse file:'%s'", filename); + xmlFreeParserCtxt (ctxt); + return; + } + + if (!empathy_xml_validate (doc, STATUS_PRESETS_DTD_FILENAME)) { + g_warning ("Failed to validate file:'%s'", filename); + xmlFreeDoc(doc); + xmlFreeParserCtxt (ctxt); + return; + } + + /* The root node, presets. */ + presets_node = xmlDocGetRootElement (doc); + + node = presets_node->children; + while (node) { + if (strcmp ((gchar *) node->name, "status") == 0 || + strcmp ((gchar *) node->name, "default") == 0) { + McPresence state; + gchar *status; + gchar *state_str; + StatusPreset *preset; + gboolean is_default = FALSE; + + if (strcmp ((gchar *) node->name, "default") == 0) { + is_default = TRUE; + } + + status = (gchar *) xmlNodeGetContent (node); + state_str = (gchar *) xmlGetProp (node, "presence"); + + if (state_str) { + state = empathy_presence_state_from_str (state_str); + + if (is_default) { + empathy_debug (DEBUG_DOMAIN, + "Default status preset state is:'%s', status:'%s'", + state_str, status); + + status_presets_set_default (state, status); + } else { + preset = status_preset_new (state, status); + presets = g_list_append (presets, preset); + } + } + + xmlFree (status); + xmlFree (state_str); + } + + node = node->next; + } + + /* Use the default if not set */ + if (!default_preset) { + status_presets_set_default (MC_PRESENCE_OFFLINE, NULL); + } + + empathy_debug (DEBUG_DOMAIN, "Parsed %d status presets", g_list_length (presets)); + + xmlFreeDoc (doc); + xmlFreeParserCtxt (ctxt); +} + +void +empathy_status_presets_get_all (void) +{ + gchar *dir; + gchar *file_with_path; + + /* If already set up clean up first. */ + if (presets) { + g_list_foreach (presets, (GFunc) status_preset_free, NULL); + g_list_free (presets); + presets = NULL; + } + + dir = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, NULL); + g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR); + file_with_path = g_build_filename (dir, STATUS_PRESETS_XML_FILENAME, NULL); + g_free (dir); + + if (g_file_test (file_with_path, G_FILE_TEST_EXISTS)) { + status_presets_file_parse (file_with_path); + } + + g_free (file_with_path); +} + +static gboolean +status_presets_file_save (void) +{ + xmlDocPtr doc; + xmlNodePtr root; + GList *l; + gchar *dir; + gchar *file; + gint count[LAST_MC_PRESENCE]; + gint i; + + for (i = 0; i < LAST_MC_PRESENCE; i++) { + count[i] = 0; + } + + dir = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, NULL); + g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR); + file = g_build_filename (dir, STATUS_PRESETS_XML_FILENAME, NULL); + g_free (dir); + + doc = xmlNewDoc ("1.0"); + root = xmlNewNode (NULL, "presets"); + xmlDocSetRootElement (doc, root); + + if (default_preset) { + xmlNodePtr subnode; + xmlChar *state; + + state = (gchar*) empathy_presence_state_to_str (default_preset->state); + + subnode = xmlNewTextChild (root, NULL, "default", + default_preset->status); + xmlNewProp (subnode, "presence", state); + } + + for (l = presets; l; l = l->next) { + StatusPreset *sp; + xmlNodePtr subnode; + xmlChar *state; + + sp = l->data; + state = (gchar*) empathy_presence_state_to_str (sp->state); + + count[sp->state]++; + if (count[sp->state] > STATUS_PRESETS_MAX_EACH) { + continue; + } + + subnode = xmlNewTextChild (root, NULL, + "status", sp->status); + xmlNewProp (subnode, "presence", state); + } + + /* Make sure the XML is indented properly */ + xmlIndentTreeOutput = 1; + + empathy_debug (DEBUG_DOMAIN, "Saving file:'%s'", file); + xmlSaveFormatFileEnc (file, doc, "utf-8", 1); + xmlFreeDoc (doc); + + g_free (file); + + return TRUE; +} + +GList * +empathy_status_presets_get (McPresence state, + gint max_number) +{ + GList *list = NULL; + GList *l; + gint i; + + i = 0; + for (l = presets; l; l = l->next) { + StatusPreset *sp; + + sp = l->data; + + if (sp->state != state) { + continue; + } + + list = g_list_append (list, sp->status); + i++; + + if (max_number != -1 && i >= max_number) { + break; + } + } + + return list; +} + +void +empathy_status_presets_set_last (McPresence state, + const gchar *status) +{ + GList *l; + StatusPreset *preset; + gint num; + + /* Remove any duplicate. */ + for (l = presets; l; l = l->next) { + preset = l->data; + + if (state == preset->state) { + if (strcmp (status, preset->status) == 0) { + status_preset_free (preset); + presets = g_list_delete_link (presets, l); + break; + } + } + } + + preset = status_preset_new (state, status); + presets = g_list_prepend (presets, preset); + + num = 0; + for (l = presets; l; l = l->next) { + preset = l->data; + + if (state != preset->state) { + continue; + } + + num++; + + if (num > STATUS_PRESETS_MAX_EACH) { + status_preset_free (preset); + presets = g_list_delete_link (presets, l); + break; + } + } + + status_presets_file_save (); +} + +void +empathy_status_presets_reset (void) +{ + g_list_foreach (presets, (GFunc) status_preset_free, NULL); + g_list_free (presets); + + presets = NULL; + + status_presets_set_default (MC_PRESENCE_AVAILABLE, NULL); + + status_presets_file_save (); +} + +McPresence +empathy_status_presets_get_default_state (void) +{ + if (!default_preset) { + return MC_PRESENCE_OFFLINE; + } + + return default_preset->state; +} + +const gchar * +empathy_status_presets_get_default_status (void) +{ + if (!default_preset || + !default_preset->status) { + return NULL; + } + + return default_preset->status; +} + +static void +status_presets_set_default (McPresence state, + const gchar *status) +{ + if (default_preset) { + status_preset_free (default_preset); + } + + default_preset = status_preset_new (state, status); +} + +void +empathy_status_presets_set_default (McPresence state, + const gchar *status) +{ + status_presets_set_default (state, status); + status_presets_file_save (); +} + +void +empathy_status_presets_clear_default (void) +{ + if (default_preset) { + status_preset_free (default_preset); + default_preset = NULL; + } + + status_presets_file_save (); +} diff --git a/libempathy-gtk/empathy-status-presets.dtd b/libempathy-gtk/empathy-status-presets.dtd new file mode 100644 index 00000000..872be6b4 --- /dev/null +++ b/libempathy-gtk/empathy-status-presets.dtd @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/libempathy-gtk/empathy-status-presets.h b/libempathy-gtk/empathy-status-presets.h new file mode 100644 index 00000000..41df5592 --- /dev/null +++ b/libempathy-gtk/empathy-status-presets.h @@ -0,0 +1,44 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2005-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Martyn Russell + */ + +#ifndef __EMPATHY_STATUS_PRESETS_H__ +#define __EMPATHY_STATUS_PRESETS_H__ + +#include + +G_BEGIN_DECLS + +void empathy_status_presets_get_all (void); +GList * empathy_status_presets_get (McPresence state, + gint max_number); +void empathy_status_presets_set_last (McPresence state, + const gchar *status); +void empathy_status_presets_reset (void); +McPresence empathy_status_presets_get_default_state (void); +const gchar * empathy_status_presets_get_default_status (void); +void empathy_status_presets_set_default (McPresence state, + const gchar *status); +void empathy_status_presets_clear_default (void); + +G_END_DECLS + +#endif /* __EMPATHY_STATUS_PRESETS_H__ */ diff --git a/libempathy-gtk/empathy-theme-manager.c b/libempathy-gtk/empathy-theme-manager.c new file mode 100644 index 00000000..268760a5 --- /dev/null +++ b/libempathy-gtk/empathy-theme-manager.c @@ -0,0 +1,1045 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2005-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Richard Hult + */ + +#include "config.h" + +#include + +#include +#include + +#include +#include + +#include "empathy-chat-view.h" +#include "empathy-preferences.h" +#include "empathy-theme-manager.h" + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_THEME_MANAGER, EmpathyThemeManagerPriv)) + +typedef struct { + gchar *name; + guint name_notify_id; + guint room_notify_id; + + gboolean show_avatars; + guint show_avatars_notify_id; + + gboolean irc_style; +} EmpathyThemeManagerPriv; + +static void theme_manager_finalize (GObject *object); +static void theme_manager_notify_name_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data); +static void theme_manager_notify_room_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data); +static void theme_manager_notify_show_avatars_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data); +static void theme_manager_ensure_tag_by_name (GtkTextBuffer *buffer, + const gchar *name); +static gboolean theme_manager_ensure_theme_exists (const gchar *name); +static GtkTextTag *theme_manager_init_tag_by_name (GtkTextTagTable *table, + const gchar *name); +static void theme_manager_add_tag (GtkTextTagTable *table, + GtkTextTag *tag); +static void theme_manager_fixup_tag_table (EmpathyThemeManager *theme_manager, + EmpathyChatView *view); +static void theme_manager_apply_theme_classic (EmpathyThemeManager *manager, + EmpathyChatView *view); +static void theme_manager_apply_theme_clean (EmpathyThemeManager *manager, + EmpathyChatView *view); +static void theme_manager_apply_theme_blue (EmpathyThemeManager *manager, + EmpathyChatView *view); +static void theme_manager_apply_theme (EmpathyThemeManager *manager, + EmpathyChatView *view, + const gchar *name); + +enum { + THEME_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static const gchar *themes[] = { + "classic", N_("Classic"), + "simple", N_("Simple"), + "clean", N_("Clean"), + "blue", N_("Blue"), + NULL +}; + +G_DEFINE_TYPE (EmpathyThemeManager, empathy_theme_manager, G_TYPE_OBJECT); + +static void +empathy_theme_manager_class_init (EmpathyThemeManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + signals[THEME_CHANGED] = + g_signal_new ("theme-changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + g_type_class_add_private (object_class, sizeof (EmpathyThemeManagerPriv)); + + object_class->finalize = theme_manager_finalize; +} + +static void +empathy_theme_manager_init (EmpathyThemeManager *manager) +{ + EmpathyThemeManagerPriv *priv; + + priv = GET_PRIV (manager); + + priv->name_notify_id = + empathy_conf_notify_add (empathy_conf_get (), + EMPATHY_PREFS_CHAT_THEME, + theme_manager_notify_name_cb, + manager); + + priv->room_notify_id = + empathy_conf_notify_add (empathy_conf_get (), + EMPATHY_PREFS_CHAT_THEME_CHAT_ROOM, + theme_manager_notify_room_cb, + manager); + + empathy_conf_get_string (empathy_conf_get (), + EMPATHY_PREFS_CHAT_THEME, + &priv->name); + + /* Unused right now, but will be used soon. */ + priv->show_avatars_notify_id = + empathy_conf_notify_add (empathy_conf_get (), + EMPATHY_PREFS_UI_SHOW_AVATARS, + theme_manager_notify_show_avatars_cb, + manager); + + empathy_conf_get_bool (empathy_conf_get (), + EMPATHY_PREFS_UI_SHOW_AVATARS, + &priv->show_avatars); +} + +static void +theme_manager_finalize (GObject *object) +{ + EmpathyThemeManagerPriv *priv; + + priv = GET_PRIV (object); + + empathy_conf_notify_remove (empathy_conf_get (), priv->name_notify_id); + empathy_conf_notify_remove (empathy_conf_get (), priv->room_notify_id); + empathy_conf_notify_remove (empathy_conf_get (), priv->show_avatars_notify_id); + + g_free (priv->name); + + G_OBJECT_CLASS (empathy_theme_manager_parent_class)->finalize (object); +} + +static void +theme_manager_notify_name_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data) +{ + EmpathyThemeManager *manager; + EmpathyThemeManagerPriv *priv; + gchar *name; + + manager = user_data; + priv = GET_PRIV (manager); + + g_free (priv->name); + + name = NULL; + if (!empathy_conf_get_string (conf, key, &name) || + name == NULL || name[0] == 0) { + priv->name = g_strdup ("classic"); + g_free (name); + } else { + priv->name = name; + } + + g_signal_emit (manager, signals[THEME_CHANGED], 0, NULL); +} + +static void +theme_manager_notify_room_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data) +{ + g_signal_emit (user_data, signals[THEME_CHANGED], 0, NULL); +} + +static void +theme_manager_notify_show_avatars_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data) +{ + EmpathyThemeManager *manager; + EmpathyThemeManagerPriv *priv; + gboolean value; + + manager = user_data; + priv = GET_PRIV (manager); + + if (!empathy_conf_get_bool (conf, key, &value)) { + priv->show_avatars = FALSE; + } else { + priv->show_avatars = value; + } +} + +static void +theme_manager_ensure_tag_by_name (GtkTextBuffer *buffer, + const gchar *name) +{ + GtkTextTagTable *table; + GtkTextTag *tag; + + table = gtk_text_buffer_get_tag_table (buffer); + tag = gtk_text_tag_table_lookup (table, name); + + if (!tag) { + gtk_text_buffer_create_tag (buffer, + name, + NULL); + } +} + +static gboolean +theme_manager_ensure_theme_exists (const gchar *name) +{ + gint i; + + if (G_STR_EMPTY (name)) { + return FALSE; + } + + for (i = 0; themes[i]; i += 2) { + if (strcmp (themes[i], name) == 0) { + return TRUE; + } + } + + return FALSE; +} + +static GtkTextTag * +theme_manager_init_tag_by_name (GtkTextTagTable *table, + const gchar *name) +{ + GtkTextTag *tag; + + tag = gtk_text_tag_table_lookup (table, name); + + if (!tag) { + return gtk_text_tag_new (name); + } + + /* Clear the old values so that we don't affect the new theme. */ + g_object_set (tag, + "background-set", FALSE, + "foreground-set", FALSE, + "invisible-set", FALSE, + "justification-set", FALSE, + "paragraph-background-set", FALSE, + "pixels-above-lines-set", FALSE, + "pixels-below-lines-set", FALSE, + "rise-set", FALSE, + "scale-set", FALSE, + "size-set", FALSE, + "style-set", FALSE, + "weight-set", FALSE, + NULL); + + return tag; +} + +static void +theme_manager_add_tag (GtkTextTagTable *table, + GtkTextTag *tag) +{ + gchar *name; + GtkTextTag *check_tag; + + g_object_get (tag, "name", &name, NULL); + check_tag = gtk_text_tag_table_lookup (table, name); + g_free (name); + if (check_tag) { + return; + } + + gtk_text_tag_table_add (table, tag); + + g_object_unref (tag); +} + +static void +theme_manager_fixup_tag_table (EmpathyThemeManager *theme_manager, + EmpathyChatView *view) +{ + GtkTextBuffer *buffer; + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); + + /* "Fancy" style tags. */ + theme_manager_ensure_tag_by_name (buffer, "fancy-header-self"); + theme_manager_ensure_tag_by_name (buffer, "fancy-header-self-avatar"); + theme_manager_ensure_tag_by_name (buffer, "fancy-avatar-self"); + theme_manager_ensure_tag_by_name (buffer, "fancy-line-top-self"); + theme_manager_ensure_tag_by_name (buffer, "fancy-line-bottom-self"); + theme_manager_ensure_tag_by_name (buffer, "fancy-body-self"); + theme_manager_ensure_tag_by_name (buffer, "fancy-action-self"); + theme_manager_ensure_tag_by_name (buffer, "fancy-highlight-self"); + + theme_manager_ensure_tag_by_name (buffer, "fancy-header-other"); + theme_manager_ensure_tag_by_name (buffer, "fancy-header-other-avatar"); + theme_manager_ensure_tag_by_name (buffer, "fancy-avatar-other"); + theme_manager_ensure_tag_by_name (buffer, "fancy-line-top-other"); + theme_manager_ensure_tag_by_name (buffer, "fancy-line-bottom-other"); + theme_manager_ensure_tag_by_name (buffer, "fancy-body-other"); + theme_manager_ensure_tag_by_name (buffer, "fancy-action-other"); + theme_manager_ensure_tag_by_name (buffer, "fancy-highlight-other"); + + theme_manager_ensure_tag_by_name (buffer, "fancy-spacing"); + theme_manager_ensure_tag_by_name (buffer, "fancy-time"); + theme_manager_ensure_tag_by_name (buffer, "fancy-event"); + theme_manager_ensure_tag_by_name (buffer, "fancy-invite"); + theme_manager_ensure_tag_by_name (buffer, "fancy-link"); + + /* IRC style tags. */ + theme_manager_ensure_tag_by_name (buffer, "irc-nick-self"); + theme_manager_ensure_tag_by_name (buffer, "irc-body-self"); + theme_manager_ensure_tag_by_name (buffer, "irc-action-self"); + + theme_manager_ensure_tag_by_name (buffer, "irc-nick-other"); + theme_manager_ensure_tag_by_name (buffer, "irc-body-other"); + theme_manager_ensure_tag_by_name (buffer, "irc-action-other"); + + theme_manager_ensure_tag_by_name (buffer, "irc-nick-highlight"); + theme_manager_ensure_tag_by_name (buffer, "irc-spacing"); + theme_manager_ensure_tag_by_name (buffer, "irc-time"); + theme_manager_ensure_tag_by_name (buffer, "irc-event"); + theme_manager_ensure_tag_by_name (buffer, "irc-invite"); + theme_manager_ensure_tag_by_name (buffer, "irc-link"); +} + +static void +theme_manager_apply_theme_classic (EmpathyThemeManager *manager, + EmpathyChatView *view) +{ + EmpathyThemeManagerPriv *priv; + GtkTextBuffer *buffer; + GtkTextTagTable *table; + GtkTextTag *tag; + + priv = GET_PRIV (manager); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); + table = gtk_text_buffer_get_tag_table (buffer); + + priv->irc_style = TRUE; + + tag = theme_manager_init_tag_by_name (table, "irc-spacing"); + g_object_set (tag, + "size", 2000, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "irc-nick-self"); + g_object_set (tag, + "foreground", "sea green", + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "irc-body-self"); + g_object_set (tag, + /* To get the default theme color: */ + "foreground-set", FALSE, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "irc-action-self"); + g_object_set (tag, + "foreground", "brown4", + "style", PANGO_STYLE_ITALIC, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "irc-nick-highlight"); + g_object_set (tag, + "foreground", "indian red", + "weight", PANGO_WEIGHT_BOLD, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "irc-nick-other"); + g_object_set (tag, + "foreground", "skyblue4", + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "irc-body-other"); + g_object_set (tag, + /* To get the default theme color: */ + "foreground-set", FALSE, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "irc-action-other"); + g_object_set (tag, + "foreground", "brown4", + "style", PANGO_STYLE_ITALIC, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "irc-time"); + g_object_set (tag, + "foreground", "darkgrey", + "justification", GTK_JUSTIFY_CENTER, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "irc-event"); + g_object_set (tag, + "foreground", "PeachPuff4", + "justification", GTK_JUSTIFY_LEFT, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "irc-invite"); + g_object_set (tag, + "foreground", "sienna", + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "irc-link"); + g_object_set (tag, + "foreground", "steelblue", + "underline", PANGO_UNDERLINE_SINGLE, + NULL); + theme_manager_add_tag (table, tag); +} + +static void +theme_manager_apply_theme_simple (EmpathyThemeManager *manager, + EmpathyChatView *view) +{ + EmpathyThemeManagerPriv *priv; + GtkTextBuffer *buffer; + GtkTextTagTable *table; + GtkTextTag *tag; + GtkWidget *widget; + GtkStyle *style; + + priv = GET_PRIV (manager); + + widget = gtk_entry_new (); + style = gtk_widget_get_style (widget); + gtk_widget_destroy (widget); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); + table = gtk_text_buffer_get_tag_table (buffer); + + priv->irc_style = FALSE; + + tag = theme_manager_init_tag_by_name (table, "fancy-spacing"); + g_object_set (tag, + "size", 3000, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-header-self"); + g_object_set (tag, + "weight", PANGO_WEIGHT_BOLD, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-header-self-avatar"); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-avatar-self"); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-line-top-self"); + g_object_set (tag, + "size", 6 * PANGO_SCALE, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-line-bottom-self"); + g_object_set (tag, + "size", 1, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-body-self"); + g_object_set (tag, + "pixels-above-lines", 2, + "pixels-below-lines", 2, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-action-self"); + g_object_set (tag, + "foreground-gdk", &style->base[GTK_STATE_SELECTED], + "style", PANGO_STYLE_ITALIC, + "pixels-above-lines", 2, + "pixels-below-lines", 2, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-highlight-self"); + g_object_set (tag, + "weight", PANGO_WEIGHT_BOLD, + "pixels-above-lines", 2, + "pixels-below-lines", 2, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-header-other"); + g_object_set (tag, + "weight", PANGO_WEIGHT_BOLD, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-header-other-avatar"); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-avatar-other"); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-line-top-other"); + g_object_set (tag, + "size", 6 * PANGO_SCALE, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-line-bottom-other"); + g_object_set (tag, + "size", 1, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-body-other"); + g_object_set (tag, + "pixels-above-lines", 2, + "pixels-below-lines", 2, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-action-other"); + g_object_set (tag, + "foreground-gdk", &style->base[GTK_STATE_SELECTED], + "style", PANGO_STYLE_ITALIC, + "pixels-above-lines", 2, + "pixels-below-lines", 2, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-highlight-other"); + g_object_set (tag, + "weight", PANGO_WEIGHT_BOLD, + "pixels-above-lines", 2, + "pixels-below-lines", 2, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-time"); + g_object_set (tag, + "foreground", "darkgrey", + "justification", GTK_JUSTIFY_CENTER, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-event"); + g_object_set (tag, + "foreground", "darkgrey", + "justification", GTK_JUSTIFY_LEFT, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-invite"); + g_object_set (tag, + "foreground", "darkgrey", + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-link"); + g_object_set (tag, + "foreground-gdk", &style->base[GTK_STATE_SELECTED], + "underline", PANGO_UNDERLINE_SINGLE, + NULL); + theme_manager_add_tag (table, tag); +} + +static void +theme_manager_apply_theme_clean (EmpathyThemeManager *manager, + EmpathyChatView *view) +{ + EmpathyThemeManagerPriv *priv; + GtkTextBuffer *buffer; + GtkTextTagTable *table; + GtkTextTag *tag; + + priv = GET_PRIV (manager); + + /* Inherit the simple theme. */ + theme_manager_apply_theme_simple (manager, view); + +#define ELEGANT_HEAD "#efefdf" +#define ELEGANT_LINE "#e3e3d3" + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); + table = gtk_text_buffer_get_tag_table (buffer); + + tag = theme_manager_init_tag_by_name (table, "fancy-spacing"); + g_object_set (tag, + "size", PANGO_SCALE * 10, + NULL); + + tag = theme_manager_init_tag_by_name (table, "fancy-header-self"); + g_object_set (tag, + "foreground", "black", + "weight", PANGO_WEIGHT_BOLD, + "paragraph-background", ELEGANT_HEAD, + "pixels-above-lines", 2, + "pixels-below-lines", 2, + NULL); + + tag = theme_manager_init_tag_by_name (table, "fancy-avatar-self"); + g_object_set (tag, + "paragraph-background", ELEGANT_HEAD, + "pixels-above-lines", 2, + "pixels-below-lines", 2, + NULL); + + tag = theme_manager_init_tag_by_name (table, "fancy-line-top-self"); + g_object_set (tag, + "size", 1 * PANGO_SCALE, + "paragraph-background", ELEGANT_LINE, + NULL); + + tag = theme_manager_init_tag_by_name (table, "fancy-line-bottom-self"); + g_object_set (tag, + "size", 1 * PANGO_SCALE, + NULL); + + tag = theme_manager_init_tag_by_name (table, "fancy-action-self"); + g_object_set (tag, + "foreground", "brown4", + "style", PANGO_STYLE_ITALIC, + NULL); + + tag = theme_manager_init_tag_by_name (table, "fancy-highlight-self"); + g_object_set (tag, + "foreground", "black", + "weight", PANGO_WEIGHT_BOLD, + NULL); + + tag = theme_manager_init_tag_by_name (table, "fancy-header-other"); + g_object_set (tag, + "foreground", "black", + "weight", PANGO_WEIGHT_BOLD, + "paragraph-background", ELEGANT_HEAD, + "pixels-above-lines", 2, + "pixels-below-lines", 2, + NULL); + + tag = theme_manager_init_tag_by_name (table, "fancy-avatar-other"); + g_object_set (tag, + "paragraph-background", ELEGANT_HEAD, + "pixels-above-lines", 2, + "pixels-below-lines", 2, + NULL); + + tag = theme_manager_init_tag_by_name (table, "fancy-line-top-other"); + g_object_set (tag, + "size", 1 * PANGO_SCALE, + "paragraph-background", ELEGANT_LINE, + NULL); + + tag = theme_manager_init_tag_by_name (table, "fancy-line-bottom-other"); + g_object_set (tag, + "size", 1 * PANGO_SCALE, + NULL); + + tag = theme_manager_init_tag_by_name (table, "fancy-action-other"); + g_object_set (tag, + "foreground", "brown4", + "style", PANGO_STYLE_ITALIC, + NULL); + + tag = theme_manager_init_tag_by_name (table, "fancy-time"); + g_object_set (tag, + "foreground", "darkgrey", + "justification", GTK_JUSTIFY_CENTER, + NULL); + + tag = theme_manager_init_tag_by_name (table, "fancy-event"); + g_object_set (tag, + "foreground", "darkgrey", + "justification", GTK_JUSTIFY_LEFT, + NULL); + + tag = theme_manager_init_tag_by_name (table, "fancy-invite"); + g_object_set (tag, + "foreground", "sienna", + NULL); + + tag = theme_manager_init_tag_by_name (table, "fancy-link"); + g_object_set (tag, + "foreground", "#49789e", + "underline", PANGO_UNDERLINE_SINGLE, + NULL); +} + +static void +theme_manager_apply_theme_blue (EmpathyThemeManager *manager, + EmpathyChatView *view) +{ + EmpathyThemeManagerPriv *priv; + GtkTextBuffer *buffer; + GtkTextTagTable *table; + GtkTextTag *tag; + + priv = GET_PRIV (manager); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); + table = gtk_text_buffer_get_tag_table (buffer); + + priv->irc_style = FALSE; + +#define BLUE_BODY_SELF "#dcdcdc" +#define BLUE_HEAD_SELF "#b9b9b9" +#define BLUE_LINE_SELF "#aeaeae" + +#define BLUE_BODY_OTHER "#adbdc8" +#define BLUE_HEAD_OTHER "#88a2b4" +#define BLUE_LINE_OTHER "#7f96a4" + + tag = theme_manager_init_tag_by_name (table, "fancy-spacing"); + g_object_set (tag, + "size", 3000, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-header-self"); + g_object_set (tag, + "foreground", "black", + "paragraph-background", BLUE_HEAD_SELF, + "weight", PANGO_WEIGHT_BOLD, + "pixels-above-lines", 2, + "pixels-below-lines", 2, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-header-self-avatar"); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-avatar-self"); + g_object_set (tag, + "paragraph-background", BLUE_HEAD_SELF, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-line-top-self"); + g_object_set (tag, + "size", 1, + "paragraph-background", BLUE_LINE_SELF, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-line-bottom-self"); + g_object_set (tag, + "size", 1, + "paragraph-background", BLUE_LINE_SELF, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-body-self"); + g_object_set (tag, + "foreground", "black", + "paragraph-background", BLUE_BODY_SELF, + "pixels-above-lines", 4, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-action-self"); + g_object_set (tag, + "foreground", "brown4", + "style", PANGO_STYLE_ITALIC, + "paragraph-background", BLUE_BODY_SELF, + "pixels-above-lines", 4, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-highlight-self"); + g_object_set (tag, + "foreground", "black", + "weight", PANGO_WEIGHT_BOLD, + "paragraph-background", BLUE_BODY_SELF, + "pixels-above-lines", 4, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-header-other"); + g_object_set (tag, + "foreground", "black", + "paragraph-background", BLUE_HEAD_OTHER, + "weight", PANGO_WEIGHT_BOLD, + "pixels-above-lines", 2, + "pixels-below-lines", 2, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-header-other-avatar"); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-avatar-other"); + g_object_set (tag, + "paragraph-background", BLUE_HEAD_OTHER, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-line-top-other"); + g_object_set (tag, + "size", 1, + "paragraph-background", BLUE_LINE_OTHER, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-line-bottom-other"); + g_object_set (tag, + "size", 1, + "paragraph-background", BLUE_LINE_OTHER, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-body-other"); + g_object_set (tag, + "foreground", "black", + "paragraph-background", BLUE_BODY_OTHER, + "pixels-above-lines", 4, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-action-other"); + g_object_set (tag, + "foreground", "brown4", + "style", PANGO_STYLE_ITALIC, + "paragraph-background", BLUE_BODY_OTHER, + "pixels-above-lines", 4, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-highlight-other"); + g_object_set (tag, + "foreground", "black", + "weight", PANGO_WEIGHT_BOLD, + "paragraph-background", BLUE_BODY_OTHER, + "pixels-above-lines", 4, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-time"); + g_object_set (tag, + "foreground", "darkgrey", + "justification", GTK_JUSTIFY_CENTER, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-event"); + g_object_set (tag, + "foreground", BLUE_LINE_OTHER, + "justification", GTK_JUSTIFY_LEFT, + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-invite"); + g_object_set (tag, + "foreground", "sienna", + NULL); + theme_manager_add_tag (table, tag); + + tag = theme_manager_init_tag_by_name (table, "fancy-link"); + g_object_set (tag, + "foreground", "#49789e", + "underline", PANGO_UNDERLINE_SINGLE, + NULL); + theme_manager_add_tag (table, tag); +} + +static void +theme_manager_apply_theme (EmpathyThemeManager *manager, + EmpathyChatView *view, + const gchar *name) +{ + EmpathyThemeManagerPriv *priv; + gint margin; + + priv = GET_PRIV (manager); + + /* Make sure all tags are present. Note: not useful now but when we have + * user defined theme it will be. + */ + theme_manager_fixup_tag_table (manager, view); + + if (theme_manager_ensure_theme_exists (name)) { + if (strcmp (name, "clean") == 0) { + theme_manager_apply_theme_clean (manager, view); + margin = 3; + } + else if (strcmp (name, "simple") == 0) { + theme_manager_apply_theme_simple (manager, view); + margin = 3; + } + else if (strcmp (name, "blue") == 0) { + theme_manager_apply_theme_blue (manager, view); + margin = 0; + } else { + theme_manager_apply_theme_classic (manager, view); + margin = 3; + } + } else { + theme_manager_apply_theme_classic (manager, view); + margin = 3; + } + + empathy_chat_view_set_margin (view, margin); + empathy_chat_view_set_irc_style (view, priv->irc_style); +} + +EmpathyThemeManager * +empathy_theme_manager_get (void) +{ + static EmpathyThemeManager *manager = NULL; + + if (!manager) { + manager = g_object_new (EMPATHY_TYPE_THEME_MANAGER, NULL); + } + + return manager; +} + +const gchar ** +empathy_theme_manager_get_themes (void) +{ + return themes; +} + +void +empathy_theme_manager_apply (EmpathyThemeManager *manager, + EmpathyChatView *view, + const gchar *name) +{ + EmpathyThemeManagerPriv *priv; + + priv = GET_PRIV (manager); + + theme_manager_apply_theme (manager, view, name); +} + +void +empathy_theme_manager_apply_saved (EmpathyThemeManager *manager, + EmpathyChatView *view) +{ + EmpathyThemeManagerPriv *priv; + + priv = GET_PRIV (manager); + + theme_manager_apply_theme (manager, view, priv->name); +} + +/* FIXME: A bit ugly. We should probably change the scheme so that instead of + * the manager signalling, views are registered and applied to automatically. + */ +void +empathy_theme_manager_update_show_avatars (EmpathyThemeManager *manager, + EmpathyChatView *view, + gboolean show) +{ + EmpathyThemeManagerPriv *priv; + GtkTextBuffer *buffer; + GtkTextTagTable *table; + GtkTextTag *tag_text_self, *tag_text_other; + GtkTextTag *tag_image_self, *tag_image_other; + + priv = GET_PRIV (manager); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); + table = gtk_text_buffer_get_tag_table (buffer); + + tag_text_self = gtk_text_tag_table_lookup (table, "fancy-header-self-avatar"); + tag_text_other = gtk_text_tag_table_lookup (table, "fancy-header-other-avatar"); + + tag_image_self = gtk_text_tag_table_lookup (table, "fancy-avatar-self"); + tag_image_other = gtk_text_tag_table_lookup (table, "fancy-avatar-other"); + + if (!show) { + g_object_set (tag_text_self, + "rise", 0, + NULL); + g_object_set (tag_text_other, + "rise", 0, + NULL); + g_object_set (tag_image_self, + "invisible", TRUE, + NULL); + g_object_set (tag_image_other, + "invisible", TRUE, + NULL); + } else { + GtkTextAttributes *attrs; + gint size; + gint rise; + + attrs = gtk_text_view_get_default_attributes (GTK_TEXT_VIEW (view)); + size = pango_font_description_get_size (attrs->font); + rise = MAX (0, (32 * PANGO_SCALE - size) / 2.0); + + g_object_set (tag_text_self, + "rise", rise, + NULL); + g_object_set (tag_text_other, + "rise", rise, + NULL); + g_object_set (tag_image_self, + "invisible", FALSE, + NULL); + g_object_set (tag_image_other, + "invisible", FALSE, + NULL); + + gtk_text_attributes_unref (attrs); + } +} + diff --git a/libempathy-gtk/empathy-theme-manager.h b/libempathy-gtk/empathy-theme-manager.h new file mode 100644 index 00000000..d20a916e --- /dev/null +++ b/libempathy-gtk/empathy-theme-manager.h @@ -0,0 +1,64 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2005-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Richard Hult + */ + +#ifndef __EMPATHY_THEME_MANAGER_H__ +#define __EMPATHY_THEME_MANAGER_H__ + +#include + +#include "empathy-chat-view.h" + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_THEME_MANAGER (empathy_theme_manager_get_type ()) +#define EMPATHY_THEME_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_THEME_MANAGER, EmpathyThemeManager)) +#define EMPATHY_THEME_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_THEME_MANAGER, EmpathyThemeManagerClass)) +#define EMPATHY_IS_THEME_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_THEME_MANAGER)) +#define EMPATHY_IS_THEME_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_THEME_MANAGER)) +#define EMPATHY_THEME_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_THEME_MANAGER, EmpathyThemeManagerClass)) + +typedef struct _EmpathyThemeManager EmpathyThemeManager; +typedef struct _EmpathyThemeManagerClass EmpathyThemeManagerClass; + +struct _EmpathyThemeManager { + GObject parent; +}; + +struct _EmpathyThemeManagerClass { + GObjectClass parent_class; +}; + +GType empathy_theme_manager_get_type (void) G_GNUC_CONST; +EmpathyThemeManager *empathy_theme_manager_get (void); +const gchar ** empathy_theme_manager_get_themes (void); +void empathy_theme_manager_apply (EmpathyThemeManager *manager, + EmpathyChatView *view, + const gchar *theme); +void empathy_theme_manager_apply_saved (EmpathyThemeManager *manager, + EmpathyChatView *view); +void empathy_theme_manager_update_show_avatars (EmpathyThemeManager *manager, + EmpathyChatView *view, + gboolean show); + +G_END_DECLS + +#endif /* __EMPATHY_THEME_MANAGER_H__ */ diff --git a/libempathy-gtk/empathy-ui-utils.c b/libempathy-gtk/empathy-ui-utils.c new file mode 100644 index 00000000..1331f3fb --- /dev/null +++ b/libempathy-gtk/empathy-ui-utils.c @@ -0,0 +1,1341 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2002-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Richard Hult + * Martyn Russell + * Xavier Claessens + * + * Part of this file is copied from GtkSourceView (gtksourceiter.c): + * Paolo Maggi + * Jeroen Zwartepoorte + */ + +#include + +#include +#include +#include +#include + +#include + +#include + +#include "empathy-ui-utils.h" +#include "empathy-images.h" + +#define DEBUG_DOMAIN "UiUtils" + +struct SizeData { + gint width; + gint height; + gboolean preserve_aspect_ratio; +}; + +static GladeXML * +get_glade_file (const gchar *filename, + const gchar *root, + const gchar *domain, + const gchar *first_required_widget, + va_list args) +{ + gchar *path; + GladeXML *gui; + const char *name; + GtkWidget **widget_ptr; + + path = g_build_filename (DATADIR, "empathy", filename, NULL); + gui = glade_xml_new (path, root, domain); + g_free (path); + + if (!gui) { + g_warning ("Couldn't find necessary glade file '%s'", filename); + return NULL; + } + + for (name = first_required_widget; name; name = va_arg (args, char *)) { + widget_ptr = va_arg (args, void *); + + *widget_ptr = glade_xml_get_widget (gui, name); + + if (!*widget_ptr) { + g_warning ("Glade file '%s' is missing widget '%s'.", + filename, name); + continue; + } + } + + return gui; +} + +void +empathy_glade_get_file_simple (const gchar *filename, + const gchar *root, + const gchar *domain, + const gchar *first_required_widget, ...) +{ + va_list args; + GladeXML *gui; + + va_start (args, first_required_widget); + + gui = get_glade_file (filename, + root, + domain, + first_required_widget, + args); + + va_end (args); + + if (!gui) { + return; + } + + g_object_unref (gui); +} + +GladeXML * +empathy_glade_get_file (const gchar *filename, + const gchar *root, + const gchar *domain, + const gchar *first_required_widget, ...) +{ + va_list args; + GladeXML *gui; + + va_start (args, first_required_widget); + + gui = get_glade_file (filename, + root, + domain, + first_required_widget, + args); + + va_end (args); + + if (!gui) { + return NULL; + } + + return gui; +} + +void +empathy_glade_connect (GladeXML *gui, + gpointer user_data, + gchar *first_widget, ...) +{ + va_list args; + const gchar *name; + const gchar *signal; + GtkWidget *widget; + gpointer *callback; + + va_start (args, first_widget); + + for (name = first_widget; name; name = va_arg (args, char *)) { + signal = va_arg (args, void *); + callback = va_arg (args, void *); + + widget = glade_xml_get_widget (gui, name); + if (!widget) { + g_warning ("Glade file is missing widget '%s', aborting", + name); + continue; + } + + g_signal_connect (widget, + signal, + G_CALLBACK (callback), + user_data); + } + + va_end (args); +} + +void +empathy_glade_setup_size_group (GladeXML *gui, + GtkSizeGroupMode mode, + gchar *first_widget, ...) +{ + va_list args; + GtkWidget *widget; + GtkSizeGroup *size_group; + const gchar *name; + + va_start (args, first_widget); + + size_group = gtk_size_group_new (mode); + + for (name = first_widget; name; name = va_arg (args, char *)) { + widget = glade_xml_get_widget (gui, name); + if (!widget) { + g_warning ("Glade file is missing widget '%s'", name); + continue; + } + + gtk_size_group_add_widget (size_group, widget); + } + + g_object_unref (size_group); + + va_end (args); +} + +GdkPixbuf * +empathy_pixbuf_from_icon_name (const gchar *icon_name, + GtkIconSize icon_size) +{ + GtkIconTheme *theme; + GdkPixbuf *pixbuf = NULL; + GError *error = NULL; + gint w, h; + gint size = 48; + + theme = gtk_icon_theme_get_default (); + + if (gtk_icon_size_lookup (icon_size, &w, &h)) { + size = (w + h) / 2; + } + + pixbuf = gtk_icon_theme_load_icon (theme, + icon_name, + size, + 0, + &error); + if (error) { + empathy_debug (DEBUG_DOMAIN, "Error loading icon: %s", error->message); + g_clear_error (&error); + } + + return pixbuf; +} + +GdkPixbuf * +empathy_pixbuf_from_smiley (EmpathySmiley type, + GtkIconSize icon_size) +{ + const gchar *icon_id; + + switch (type) { + case EMPATHY_SMILEY_NORMAL: /* :) */ + icon_id = "stock_smiley-1"; + break; + case EMPATHY_SMILEY_WINK: /* ;) */ + icon_id = "stock_smiley-3"; + break; + case EMPATHY_SMILEY_BIGEYE: /* =) */ + icon_id = "stock_smiley-2"; + break; + case EMPATHY_SMILEY_NOSE: /* :-) */ + icon_id = "stock_smiley-7"; + break; + case EMPATHY_SMILEY_CRY: /* :'( */ + icon_id = "stock_smiley-11"; + break; + case EMPATHY_SMILEY_SAD: /* :( */ + icon_id = "stock_smiley-4"; + break; + case EMPATHY_SMILEY_SCEPTICAL: /* :/ */ + icon_id = "stock_smiley-9"; + break; + case EMPATHY_SMILEY_BIGSMILE: /* :D */ + icon_id = "stock_smiley-6"; + break; + case EMPATHY_SMILEY_INDIFFERENT: /* :| */ + icon_id = "stock_smiley-8"; + break; + case EMPATHY_SMILEY_TOUNGE: /* :p */ + icon_id = "stock_smiley-10"; + break; + case EMPATHY_SMILEY_SHOCKED: /* :o */ + icon_id = "stock_smiley-5"; + break; + case EMPATHY_SMILEY_COOL: /* 8) */ + icon_id = "stock_smiley-15"; + break; + case EMPATHY_SMILEY_SORRY: /* *| */ + icon_id = "stock_smiley-12"; + break; + case EMPATHY_SMILEY_KISS: /* :* */ + icon_id = "stock_smiley-13"; + break; + case EMPATHY_SMILEY_SHUTUP: /* :# */ + icon_id = "stock_smiley-14"; + break; + case EMPATHY_SMILEY_YAWN: /* |O */ + icon_id = ""; + break; + case EMPATHY_SMILEY_CONFUSED: /* :$ */ + icon_id = "stock_smiley-17"; + break; + case EMPATHY_SMILEY_ANGEL: /* O) */ + icon_id = "stock_smiley-18"; + break; + case EMPATHY_SMILEY_OOOH: /* :x */ + icon_id = "stock_smiley-19"; + break; + case EMPATHY_SMILEY_LOOKAWAY: /* *) */ + icon_id = "stock_smiley-20"; + break; + case EMPATHY_SMILEY_BLUSH: /* *S */ + icon_id = "stock_smiley-23"; + break; + case EMPATHY_SMILEY_COOLBIGSMILE: /* 8D */ + icon_id = "stock_smiley-25"; + break; + case EMPATHY_SMILEY_ANGRY: /* :@ */ + icon_id = "stock_smiley-16"; + break; + case EMPATHY_SMILEY_BOSS: /* @) */ + icon_id = "stock_smiley-21"; + break; + case EMPATHY_SMILEY_MONKEY: /* #) */ + icon_id = "stock_smiley-22"; + break; + case EMPATHY_SMILEY_SILLY: /* O) */ + icon_id = "stock_smiley-24"; + break; + case EMPATHY_SMILEY_SICK: /* +o( */ + icon_id = "stock_smiley-26"; + break; + + default: + g_assert_not_reached (); + icon_id = NULL; + } + + + return empathy_pixbuf_from_icon_name (icon_id, icon_size); +} + +const gchar * +empathy_icon_name_from_account (McAccount *account) +{ + McProfile *profile; + + profile = mc_account_get_profile (account); + + return mc_profile_get_icon_name (profile); +} + +const gchar * +empathy_icon_name_for_presence_state (McPresence state) +{ + switch (state) { + case MC_PRESENCE_AVAILABLE: + return EMPATHY_IMAGE_AVAILABLE; + case MC_PRESENCE_DO_NOT_DISTURB: + return EMPATHY_IMAGE_BUSY; + case MC_PRESENCE_AWAY: + return EMPATHY_IMAGE_AWAY; + case MC_PRESENCE_EXTENDED_AWAY: + return EMPATHY_IMAGE_EXT_AWAY; + case MC_PRESENCE_HIDDEN: + case MC_PRESENCE_OFFLINE: + case MC_PRESENCE_UNSET: + return EMPATHY_IMAGE_OFFLINE; + default: + g_assert_not_reached (); + } + + return NULL; +} + +const gchar * +empathy_icon_name_for_presence (EmpathyPresence *presence) +{ + McPresence state; + + g_return_val_if_fail (EMPATHY_IS_PRESENCE (presence), + EMPATHY_IMAGE_OFFLINE); + + state = empathy_presence_get_state (presence); + + return empathy_icon_name_for_presence_state (state); +} + +const gchar * +empathy_icon_name_for_contact (EmpathyContact *contact) +{ + EmpathyPresence *presence; + EmpathySubscription subscription; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), + EMPATHY_IMAGE_OFFLINE); + + presence = empathy_contact_get_presence (contact); + if (presence) { + return empathy_icon_name_for_presence (presence); + } + + subscription = empathy_contact_get_subscription (contact); + if (!(subscription & EMPATHY_SUBSCRIPTION_FROM)) { + return EMPATHY_IMAGE_PENDING; + } + + return EMPATHY_IMAGE_OFFLINE; +} + +GdkPixbuf * +empathy_pixbuf_avatar_from_contact (EmpathyContact *contact) +{ + GdkPixbuf *pixbuf; + GdkPixbufLoader *loader; + EmpathyAvatar *avatar; + GError *error = NULL; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + + avatar = empathy_contact_get_avatar (contact); + if (!avatar) { + return NULL; + } + + loader = gdk_pixbuf_loader_new (); + + if (!gdk_pixbuf_loader_write (loader, avatar->data, avatar->len, &error)) { + g_warning ("Couldn't write avatar image:%p with " + "length:%" G_GSIZE_FORMAT " to pixbuf loader: %s", + avatar->data, avatar->len, error->message); + g_error_free (error); + return NULL; + } + + gdk_pixbuf_loader_close (loader, NULL); + + pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); + + g_object_ref (pixbuf); + g_object_unref (loader); + + return pixbuf; +} + +static void +pixbuf_from_avatar_size_prepared_cb (GdkPixbufLoader *loader, + int width, + int height, + struct SizeData *data) +{ + g_return_if_fail (width > 0 && height > 0); + + if (data->preserve_aspect_ratio && (data->width > 0 || data->height > 0)) { + if (width < data->width && height < data->height) { + width = width; + height = height; + } + + if (data->width < 0) { + width = width * (double) data->height / (gdouble) height; + height = data->height; + } else if (data->height < 0) { + height = height * (double) data->width / (double) width; + width = data->width; + } else if ((double) height * (double) data->width > + (double) width * (double) data->height) { + width = 0.5 + (double) width * (double) data->height / (double) height; + height = data->height; + } else { + height = 0.5 + (double) height * (double) data->width / (double) width; + width = data->width; + } + } else { + if (data->width > 0) { + width = data->width; + } + + if (data->height > 0) { + height = data->height; + } + } + + gdk_pixbuf_loader_set_size (loader, width, height); +} + +GdkPixbuf * +empathy_pixbuf_from_avatar_scaled (EmpathyAvatar *avatar, + gint width, + gint height) +{ + GdkPixbuf *pixbuf; + GdkPixbufLoader *loader; + struct SizeData data; + GError *error = NULL; + + if (!avatar) { + return NULL; + } + + data.width = width; + data.height = height; + data.preserve_aspect_ratio = TRUE; + + loader = gdk_pixbuf_loader_new (); + + g_signal_connect (loader, "size-prepared", + G_CALLBACK (pixbuf_from_avatar_size_prepared_cb), + &data); + + if (!gdk_pixbuf_loader_write (loader, avatar->data, avatar->len, &error)) { + g_warning ("Couldn't write avatar image:%p with " + "length:%" G_GSIZE_FORMAT " to pixbuf loader: %s", + avatar->data, avatar->len, error->message); + g_error_free (error); + return NULL; + } + + gdk_pixbuf_loader_close (loader, NULL); + + pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); + + g_object_ref (pixbuf); + g_object_unref (loader); + + return pixbuf; +} + +GdkPixbuf * +empathy_pixbuf_avatar_from_contact_scaled (EmpathyContact *contact, + gint width, + gint height) +{ + EmpathyAvatar *avatar; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + + avatar = empathy_contact_get_avatar (contact); + + return empathy_pixbuf_from_avatar_scaled (avatar, width, height); +} +/* Stolen from GtkSourceView, hence the weird intendation. Please keep it like + * that to make it easier to apply changes from the original code. + */ +#define GTK_TEXT_UNKNOWN_CHAR 0xFFFC + +/* this function acts like g_utf8_offset_to_pointer() except that if it finds a + * decomposable character it consumes the decomposition length from the given + * offset. So it's useful when the offset was calculated for the normalized + * version of str, but we need a pointer to str itself. */ +static const gchar * +pointer_from_offset_skipping_decomp (const gchar *str, gint offset) +{ + gchar *casefold, *normal; + const gchar *p, *q; + + p = str; + while (offset > 0) + { + q = g_utf8_next_char (p); + casefold = g_utf8_casefold (p, q - p); + normal = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); + offset -= g_utf8_strlen (normal, -1); + g_free (casefold); + g_free (normal); + p = q; + } + return p; +} + +static const gchar * +g_utf8_strcasestr (const gchar *haystack, const gchar *needle) +{ + gsize needle_len; + gsize haystack_len; + const gchar *ret = NULL; + gchar *p; + gchar *casefold; + gchar *caseless_haystack; + gint i; + + g_return_val_if_fail (haystack != NULL, NULL); + g_return_val_if_fail (needle != NULL, NULL); + + casefold = g_utf8_casefold (haystack, -1); + caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); + g_free (casefold); + + needle_len = g_utf8_strlen (needle, -1); + haystack_len = g_utf8_strlen (caseless_haystack, -1); + + if (needle_len == 0) + { + ret = (gchar *)haystack; + goto finally_1; + } + + if (haystack_len < needle_len) + { + ret = NULL; + goto finally_1; + } + + p = (gchar*)caseless_haystack; + needle_len = strlen (needle); + i = 0; + + while (*p) + { + if ((strncmp (p, needle, needle_len) == 0)) + { + ret = pointer_from_offset_skipping_decomp (haystack, i); + goto finally_1; + } + + p = g_utf8_next_char (p); + i++; + } + +finally_1: + g_free (caseless_haystack); + + return ret; +} + +static gboolean +g_utf8_caselessnmatch (const char *s1, const char *s2, + gssize n1, gssize n2) +{ + gchar *casefold; + gchar *normalized_s1; + gchar *normalized_s2; + gint len_s1; + gint len_s2; + gboolean ret = FALSE; + + g_return_val_if_fail (s1 != NULL, FALSE); + g_return_val_if_fail (s2 != NULL, FALSE); + g_return_val_if_fail (n1 > 0, FALSE); + g_return_val_if_fail (n2 > 0, FALSE); + + casefold = g_utf8_casefold (s1, n1); + normalized_s1 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); + g_free (casefold); + + casefold = g_utf8_casefold (s2, n2); + normalized_s2 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); + g_free (casefold); + + len_s1 = strlen (normalized_s1); + len_s2 = strlen (normalized_s2); + + if (len_s1 < len_s2) + goto finally_2; + + ret = (strncmp (normalized_s1, normalized_s2, len_s2) == 0); + +finally_2: + g_free (normalized_s1); + g_free (normalized_s2); + + return ret; +} + +static void +forward_chars_with_skipping (GtkTextIter *iter, + gint count, + gboolean skip_invisible, + gboolean skip_nontext, + gboolean skip_decomp) +{ + gint i; + + g_return_if_fail (count >= 0); + + i = count; + + while (i > 0) + { + gboolean ignored = FALSE; + + /* minimal workaround to avoid the infinite loop of bug #168247. + * It doesn't fix the problemjust the symptom... + */ + if (gtk_text_iter_is_end (iter)) + return; + + if (skip_nontext && gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR) + ignored = TRUE; + + if (!ignored && skip_invisible && + /* _gtk_text_btree_char_is_invisible (iter)*/ FALSE) + ignored = TRUE; + + if (!ignored && skip_decomp) + { + /* being UTF8 correct sucks; this accounts for extra + offsets coming from canonical decompositions of + UTF8 characters (e.g. accented characters) which + g_utf8_normalize() performs */ + gchar *normal; + gchar buffer[6]; + gint buffer_len; + + buffer_len = g_unichar_to_utf8 (gtk_text_iter_get_char (iter), buffer); + normal = g_utf8_normalize (buffer, buffer_len, G_NORMALIZE_NFD); + i -= (g_utf8_strlen (normal, -1) - 1); + g_free (normal); + } + + gtk_text_iter_forward_char (iter); + + if (!ignored) + --i; + } +} + +static gboolean +lines_match (const GtkTextIter *start, + const gchar **lines, + gboolean visible_only, + gboolean slice, + GtkTextIter *match_start, + GtkTextIter *match_end) +{ + GtkTextIter next; + gchar *line_text; + const gchar *found; + gint offset; + + if (*lines == NULL || **lines == '\0') + { + if (match_start) + *match_start = *start; + if (match_end) + *match_end = *start; + return TRUE; + } + + next = *start; + gtk_text_iter_forward_line (&next); + + /* No more text in buffer, but *lines is nonempty */ + if (gtk_text_iter_equal (start, &next)) + return FALSE; + + if (slice) + { + if (visible_only) + line_text = gtk_text_iter_get_visible_slice (start, &next); + else + line_text = gtk_text_iter_get_slice (start, &next); + } + else + { + if (visible_only) + line_text = gtk_text_iter_get_visible_text (start, &next); + else + line_text = gtk_text_iter_get_text (start, &next); + } + + if (match_start) /* if this is the first line we're matching */ + { + found = g_utf8_strcasestr (line_text, *lines); + } + else + { + /* If it's not the first line, we have to match from the + * start of the line. + */ + if (g_utf8_caselessnmatch (line_text, *lines, strlen (line_text), + strlen (*lines))) + found = line_text; + else + found = NULL; + } + + if (found == NULL) + { + g_free (line_text); + return FALSE; + } + + /* Get offset to start of search string */ + offset = g_utf8_strlen (line_text, found - line_text); + + next = *start; + + /* If match start needs to be returned, set it to the + * start of the search string. + */ + forward_chars_with_skipping (&next, offset, visible_only, !slice, FALSE); + if (match_start) + { + *match_start = next; + } + + /* Go to end of search string */ + forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1), visible_only, !slice, TRUE); + + g_free (line_text); + + ++lines; + + if (match_end) + *match_end = next; + + /* pass NULL for match_start, since we don't need to find the + * start again. + */ + return lines_match (&next, lines, visible_only, slice, NULL, match_end); +} + +/* strsplit () that retains the delimiter as part of the string. */ +static gchar ** +strbreakup (const char *string, + const char *delimiter, + gint max_tokens) +{ + GSList *string_list = NULL, *slist; + gchar **str_array, *s, *casefold, *new_string; + guint i, n = 1; + + g_return_val_if_fail (string != NULL, NULL); + g_return_val_if_fail (delimiter != NULL, NULL); + + if (max_tokens < 1) + max_tokens = G_MAXINT; + + s = strstr (string, delimiter); + if (s) + { + guint delimiter_len = strlen (delimiter); + + do + { + guint len; + + len = s - string + delimiter_len; + new_string = g_new (gchar, len + 1); + strncpy (new_string, string, len); + new_string[len] = 0; + casefold = g_utf8_casefold (new_string, -1); + g_free (new_string); + new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); + g_free (casefold); + string_list = g_slist_prepend (string_list, new_string); + n++; + string = s + delimiter_len; + s = strstr (string, delimiter); + } while (--max_tokens && s); + } + + if (*string) + { + n++; + casefold = g_utf8_casefold (string, -1); + new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); + g_free (casefold); + string_list = g_slist_prepend (string_list, new_string); + } + + str_array = g_new (gchar*, n); + + i = n - 1; + + str_array[i--] = NULL; + for (slist = string_list; slist; slist = slist->next) + str_array[i--] = slist->data; + + g_slist_free (string_list); + + return str_array; +} + +gboolean +empathy_text_iter_forward_search (const GtkTextIter *iter, + const gchar *str, + GtkTextIter *match_start, + GtkTextIter *match_end, + const GtkTextIter *limit) +{ + gchar **lines = NULL; + GtkTextIter match; + gboolean retval = FALSE; + GtkTextIter search; + gboolean visible_only; + gboolean slice; + + g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (str != NULL, FALSE); + + if (limit && gtk_text_iter_compare (iter, limit) >= 0) + return FALSE; + + if (*str == '\0') { + /* If we can move one char, return the empty string there */ + match = *iter; + + if (gtk_text_iter_forward_char (&match)) { + if (limit && gtk_text_iter_equal (&match, limit)) { + return FALSE; + } + + if (match_start) { + *match_start = match; + } + if (match_end) { + *match_end = match; + } + return TRUE; + } else { + return FALSE; + } + } + + visible_only = TRUE; + slice = FALSE; + + /* locate all lines */ + lines = strbreakup (str, "\n", -1); + + search = *iter; + + do { + /* This loop has an inefficient worst-case, where + * gtk_text_iter_get_text () is called repeatedly on + * a single line. + */ + GtkTextIter end; + + if (limit && gtk_text_iter_compare (&search, limit) >= 0) { + break; + } + + if (lines_match (&search, (const gchar**)lines, + visible_only, slice, &match, &end)) { + if (limit == NULL || + (limit && gtk_text_iter_compare (&end, limit) <= 0)) { + retval = TRUE; + + if (match_start) { + *match_start = match; + } + if (match_end) { + *match_end = end; + } + } + break; + } + } while (gtk_text_iter_forward_line (&search)); + + g_strfreev ((gchar**)lines); + + return retval; +} + +static const gchar * +g_utf8_strrcasestr (const gchar *haystack, const gchar *needle) +{ + gsize needle_len; + gsize haystack_len; + const gchar *ret = NULL; + gchar *p; + gchar *casefold; + gchar *caseless_haystack; + gint i; + + g_return_val_if_fail (haystack != NULL, NULL); + g_return_val_if_fail (needle != NULL, NULL); + + casefold = g_utf8_casefold (haystack, -1); + caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); + g_free (casefold); + + needle_len = g_utf8_strlen (needle, -1); + haystack_len = g_utf8_strlen (caseless_haystack, -1); + + if (needle_len == 0) + { + ret = (gchar *)haystack; + goto finally_1; + } + + if (haystack_len < needle_len) + { + ret = NULL; + goto finally_1; + } + + i = haystack_len - needle_len; + p = g_utf8_offset_to_pointer (caseless_haystack, i); + needle_len = strlen (needle); + + while (p >= caseless_haystack) + { + if (strncmp (p, needle, needle_len) == 0) + { + ret = pointer_from_offset_skipping_decomp (haystack, i); + goto finally_1; + } + + p = g_utf8_prev_char (p); + i--; + } + +finally_1: + g_free (caseless_haystack); + + return ret; +} + +static gboolean +backward_lines_match (const GtkTextIter *start, + const gchar **lines, + gboolean visible_only, + gboolean slice, + GtkTextIter *match_start, + GtkTextIter *match_end) +{ + GtkTextIter line, next; + gchar *line_text; + const gchar *found; + gint offset; + + if (*lines == NULL || **lines == '\0') + { + if (match_start) + *match_start = *start; + if (match_end) + *match_end = *start; + return TRUE; + } + + line = next = *start; + if (gtk_text_iter_get_line_offset (&next) == 0) + { + if (!gtk_text_iter_backward_line (&next)) + return FALSE; + } + else + gtk_text_iter_set_line_offset (&next, 0); + + if (slice) + { + if (visible_only) + line_text = gtk_text_iter_get_visible_slice (&next, &line); + else + line_text = gtk_text_iter_get_slice (&next, &line); + } + else + { + if (visible_only) + line_text = gtk_text_iter_get_visible_text (&next, &line); + else + line_text = gtk_text_iter_get_text (&next, &line); + } + + if (match_start) /* if this is the first line we're matching */ + { + found = g_utf8_strrcasestr (line_text, *lines); + } + else + { + /* If it's not the first line, we have to match from the + * start of the line. + */ + if (g_utf8_caselessnmatch (line_text, *lines, strlen (line_text), + strlen (*lines))) + found = line_text; + else + found = NULL; + } + + if (found == NULL) + { + g_free (line_text); + return FALSE; + } + + /* Get offset to start of search string */ + offset = g_utf8_strlen (line_text, found - line_text); + + forward_chars_with_skipping (&next, offset, visible_only, !slice, FALSE); + + /* If match start needs to be returned, set it to the + * start of the search string. + */ + if (match_start) + { + *match_start = next; + } + + /* Go to end of search string */ + forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1), visible_only, !slice, TRUE); + + g_free (line_text); + + ++lines; + + if (match_end) + *match_end = next; + + /* try to match the rest of the lines forward, passing NULL + * for match_start so lines_match will try to match the entire + * line */ + return lines_match (&next, lines, visible_only, + slice, NULL, match_end); +} + +gboolean +empathy_text_iter_backward_search (const GtkTextIter *iter, + const gchar *str, + GtkTextIter *match_start, + GtkTextIter *match_end, + const GtkTextIter *limit) +{ + gchar **lines = NULL; + GtkTextIter match; + gboolean retval = FALSE; + GtkTextIter search; + gboolean visible_only; + gboolean slice; + + g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (str != NULL, FALSE); + + if (limit && gtk_text_iter_compare (iter, limit) <= 0) + return FALSE; + + if (*str == '\0') + { + /* If we can move one char, return the empty string there */ + match = *iter; + + if (gtk_text_iter_backward_char (&match)) + { + if (limit && gtk_text_iter_equal (&match, limit)) + return FALSE; + + if (match_start) + *match_start = match; + if (match_end) + *match_end = match; + return TRUE; + } + else + { + return FALSE; + } + } + + visible_only = TRUE; + slice = TRUE; + + /* locate all lines */ + lines = strbreakup (str, "\n", -1); + + search = *iter; + + while (TRUE) + { + /* This loop has an inefficient worst-case, where + * gtk_text_iter_get_text () is called repeatedly on + * a single line. + */ + GtkTextIter end; + + if (limit && gtk_text_iter_compare (&search, limit) <= 0) + break; + + if (backward_lines_match (&search, (const gchar**)lines, + visible_only, slice, &match, &end)) + { + if (limit == NULL || (limit && + gtk_text_iter_compare (&end, limit) > 0)) + { + retval = TRUE; + + if (match_start) + *match_start = match; + if (match_end) + *match_end = end; + } + break; + } + + if (gtk_text_iter_get_line_offset (&search) == 0) + { + if (!gtk_text_iter_backward_line (&search)) + break; + } + else + { + gtk_text_iter_set_line_offset (&search, 0); + } + } + + g_strfreev ((gchar**)lines); + + return retval; +} + +static gboolean +window_get_is_on_current_workspace (GtkWindow *window) +{ + GdkWindow *gdk_window; + + gdk_window = GTK_WIDGET (window)->window; + if (gdk_window) { + return !(gdk_window_get_state (gdk_window) & + GDK_WINDOW_STATE_ICONIFIED); + } else { + return FALSE; + } +} + +/* Checks if the window is visible as in visible on the current workspace. */ +gboolean +empathy_window_get_is_visible (GtkWindow *window) +{ + gboolean visible; + + g_return_val_if_fail (window != NULL, FALSE); + + g_object_get (window, + "visible", &visible, + NULL); + + return visible && window_get_is_on_current_workspace (window); +} + +/* Takes care of moving the window to the current workspace. */ +void +empathy_window_present (GtkWindow *window, + gboolean steal_focus) +{ + gboolean visible; + gboolean on_current; + guint32 timestamp; + + g_return_if_fail (window != NULL); + + /* There are three cases: hidden, visible, visible on another + * workspace. + */ + + g_object_get (window, + "visible", &visible, + NULL); + + on_current = window_get_is_on_current_workspace (window); + + if (visible && !on_current) { + /* Hide it so present brings it to the current workspace. */ + gtk_widget_hide (GTK_WIDGET (window)); + } + + timestamp = gtk_get_current_event_time (); + if (steal_focus && timestamp != GDK_CURRENT_TIME) { + gtk_window_present_with_time (window, timestamp); + } else { + gtk_window_present (window); + } +} + +GtkWindow * +empathy_get_toplevel_window (GtkWidget *widget) +{ + GtkWidget *toplevel; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); + + toplevel = gtk_widget_get_toplevel (widget); + if (GTK_IS_WINDOW (toplevel)) { + return GTK_WINDOW (toplevel); + } + + return NULL; +} + +/* The URL opening code can't handle schemeless strings, so we try to be + * smart and add http if there is no scheme or doesn't look like a mail + * address. This should work in most cases, and let us click on strings + * like "www.gnome.org". + */ +static gchar * +fixup_url (const gchar *url) +{ + gchar *real_url; + + if (!g_str_has_prefix (url, "http://") && + !strstr (url, ":/") && + !strstr (url, "@")) { + real_url = g_strdup_printf ("http://%s", url); + } else { + real_url = g_strdup (url); + } + + return real_url; +} + +void +empathy_url_show (const char *url) +{ + gchar *real_url; + GnomeVFSResult res; + + real_url = fixup_url (url); + res = gnome_vfs_url_show (real_url); + if (res != GNOME_VFS_OK) { + empathy_debug (DEBUG_DOMAIN, "Couldn't show URL %s: %s", + real_url, + gnome_vfs_result_to_string (res)); + } + + g_free (real_url); +} + +static void +link_button_hook (GtkLinkButton *button, + const gchar *link, + gpointer user_data) +{ + empathy_url_show (link); +} + +GtkWidget * +empathy_link_button_new (const gchar *url, + const gchar *title) +{ + static gboolean hook = FALSE; + + if (!hook) { + hook = TRUE; + gtk_link_button_set_uri_hook (link_button_hook, NULL, NULL); + } + + return gtk_link_button_new_with_label (url, title); +} + +void +empathy_toggle_button_set_state_quietly (GtkWidget *widget, + GCallback callback, + gpointer user_data, + gboolean active) +{ + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget)); + + g_signal_handlers_block_by_func (widget, callback, user_data); + g_object_set (widget, "active", active, NULL); + g_signal_handlers_unblock_by_func (widget, callback, user_data); +} + diff --git a/libempathy-gtk/empathy-ui-utils.h b/libempathy-gtk/empathy-ui-utils.h new file mode 100644 index 00000000..070f9e2b --- /dev/null +++ b/libempathy-gtk/empathy-ui-utils.h @@ -0,0 +1,113 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2002-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Richard Hult + * Martyn Russell + * Xavier Claessens + * + * Part of this file is copied from GtkSourceView (gtksourceiter.c): + * Paolo Maggi + * Jeroen Zwartepoorte + */ + +#ifndef __EMPATHY_UI_UTILS_H__ +#define __EMPATHY_UI_UTILS_H__ + +#include +#include + +#include +#include + +#include +#include +#include + +#include "empathy-chat-view.h" + +G_BEGIN_DECLS + +#define G_STR_EMPTY(x) ((x) == NULL || (x)[0] == '\0') + +/* Glade */ +void empathy_glade_get_file_simple (const gchar *filename, + const gchar *root, + const gchar *domain, + const gchar *first_required_widget, + ...); +GladeXML * empathy_glade_get_file (const gchar *filename, + const gchar *root, + const gchar *domain, + const gchar *first_required_widget, + ...); +void empathy_glade_connect (GladeXML *gui, + gpointer user_data, + gchar *first_widget, + ...); +void empathy_glade_setup_size_group (GladeXML *gui, + GtkSizeGroupMode mode, + gchar *first_widget, + ...); +/* Pixbufs */ +GdkPixbuf * empathy_pixbuf_from_icon_name (const gchar *icon_name, + GtkIconSize icon_size); +GdkPixbuf * empathy_pixbuf_from_smiley (EmpathySmiley type, + GtkIconSize icon_size); +const gchar * empathy_icon_name_from_account (McAccount *account); +const gchar * empathy_icon_name_for_presence_state (McPresence state); +const gchar * empathy_icon_name_for_presence (EmpathyPresence *presence); +const gchar * empathy_icon_name_for_contact (EmpathyContact *contact); +GdkPixbuf * empathy_pixbuf_from_avatar_scaled (EmpathyAvatar *avatar, + gint width, + gint height); +GdkPixbuf * empathy_pixbuf_avatar_from_contact (EmpathyContact *contact); +GdkPixbuf * empathy_pixbuf_avatar_from_contact_scaled (EmpathyContact *contact, + gint width, + gint height); +/* Text view */ +gboolean empathy_text_iter_forward_search (const GtkTextIter *iter, + const gchar *str, + GtkTextIter *match_start, + GtkTextIter *match_end, + const GtkTextIter *limit); +gboolean empathy_text_iter_backward_search (const GtkTextIter *iter, + const gchar *str, + GtkTextIter *match_start, + GtkTextIter *match_end, + const GtkTextIter *limit); + +/* Windows */ +gboolean empathy_window_get_is_visible (GtkWindow *window); +void empathy_window_present (GtkWindow *window, + gboolean steal_focus); +GtkWindow *empathy_get_toplevel_window (GtkWidget *widget); +void empathy_url_show (const char *url); +void empathy_toggle_button_set_state_quietly (GtkWidget *widget, + GCallback callback, + gpointer user_data, + gboolean active); +GtkWidget *empathy_link_button_new (const gchar *url, + const gchar *title); + + +G_END_DECLS + +#endif /* __EMPATHY_UI_UTILS_H__ */ diff --git a/libempathy-gtk/gossip-about-dialog.c b/libempathy-gtk/gossip-about-dialog.c deleted file mode 100644 index d2c13faa..00000000 --- a/libempathy-gtk/gossip-about-dialog.c +++ /dev/null @@ -1,113 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Martyn Russell - * Xavier Claessens - */ - -#include "config.h" - -#include -#include -#include -#include - -#include "gossip-about-dialog.h" -#include "gossip-ui-utils.h" - -#define WEB_SITE "http://live.gnome.org/Empathy" - -static void about_dialog_activate_link_cb (GtkAboutDialog *about, - const gchar *link, - gpointer data); - -static const char *authors[] = { - "Mikael Hallendal", - "Richard Hult", - "Martyn Russell", - "Geert-Jan Van den Bogaerde", - "Kevin Dougherty", - "Eitan Isaacson", - "Xavier Claessens", - NULL -}; - -static const char *documenters[] = { - NULL -}; - -static const char *artists[] = { - "Andreas Nilsson ", - "Vinicius Depizzol ", - NULL -}; - -static const char *license[] = { - N_("Empathy 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."), - N_("Empathy 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."), - N_("You should have received a copy of the GNU General Public License " - "along with Empathy; if not, write to the Free Software Foundation, Inc., " - "51 Franklin Street, Fifth Floor, Boston, MA 02110-130159 USA") -}; - -static void -about_dialog_activate_link_cb (GtkAboutDialog *about, - const gchar *link, - gpointer data) -{ - gossip_url_show (link); -} - -void -gossip_about_dialog_new (GtkWindow *parent) -{ - gchar *license_trans; - - gtk_about_dialog_set_url_hook (about_dialog_activate_link_cb, NULL, NULL); - - license_trans = g_strconcat (_(license[0]), "\n\n", - _(license[1]), "\n\n", - _(license[2]), "\n\n", - NULL); - - gtk_show_about_dialog (parent, - "artists", artists, - "authors", authors, - "comments", _("An Instant Messaging client for GNOME"), - "license", license_trans, - "wrap-license", TRUE, - "copyright", "Imendio AB 2002-2007\nCollabora Ltd 2007", - "documenters", documenters, - "logo-icon-name", "empathy", - "translator-credits", _("translator-credits"), - "version", PACKAGE_VERSION, - "website", WEB_SITE, - NULL); - - g_free (license_trans); -} - - diff --git a/libempathy-gtk/gossip-about-dialog.h b/libempathy-gtk/gossip-about-dialog.h deleted file mode 100644 index 0e5b9d4f..00000000 --- a/libempathy-gtk/gossip-about-dialog.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Martyn Russell - */ - -#ifndef __GOSSIP_ABOUT_DIALOG_H__ -#define __GOSSIP_ABOUT_DIALOG_H__ - -#include - -G_BEGIN_DECLS - -void gossip_about_dialog_new (GtkWindow *parent); - -G_END_DECLS - -#endif /* __GOSSIP_ABOUT_DIALOG_H__ */ diff --git a/libempathy-gtk/gossip-account-chooser.c b/libempathy-gtk/gossip-account-chooser.c deleted file mode 100644 index dfed1bb5..00000000 --- a/libempathy-gtk/gossip-account-chooser.c +++ /dev/null @@ -1,637 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2005-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Martyn Russell - */ - -#include "config.h" - -#include - -#include -#include -#include - -#include -#include -#include - -#include - -#include "gossip-ui-utils.h" -#include "gossip-account-chooser.h" - -#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_ACCOUNT_CHOOSER, GossipAccountChooserPriv)) - -typedef struct { - MissionControl *mc; - McAccountMonitor *monitor; - - gboolean set_active_item; - gboolean can_select_all; - gboolean has_all_option; -} GossipAccountChooserPriv; - -typedef struct { - GossipAccountChooser *chooser; - McAccount *account; - gboolean set; -} SetAccountData; - -enum { - COL_ACCOUNT_IMAGE, - COL_ACCOUNT_TEXT, - COL_ACCOUNT_ENABLED, /* Usually tied to connected state */ - COL_ACCOUNT_POINTER, - COL_ACCOUNT_COUNT -}; - -static void account_chooser_finalize (GObject *object); -static void account_chooser_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec); -static void account_chooser_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec); -static void account_chooser_setup (GossipAccountChooser *chooser); -static void account_chooser_account_created_cb (McAccountMonitor *monitor, - const gchar *unique_name, - GossipAccountChooser *chooser); -static void account_chooser_account_add_foreach (McAccount *account, - GossipAccountChooser *chooser); -static void account_chooser_account_deleted_cb (McAccountMonitor *monitor, - const gchar *unique_name, - GossipAccountChooser *chooser); -static void account_chooser_account_remove_foreach (McAccount *account, - GossipAccountChooser *chooser); -static void account_chooser_update_iter (GossipAccountChooser *chooser, - GtkTreeIter *iter, - McAccount *account); -static void account_chooser_status_changed_cb (MissionControl *mc, - TelepathyConnectionStatus status, - McPresence presence, - TelepathyConnectionStatusReason reason, - const gchar *unique_name, - GossipAccountChooser *chooser); -static gboolean account_chooser_separator_func (GtkTreeModel *model, - GtkTreeIter *iter, - GossipAccountChooser *chooser); -static gboolean account_chooser_set_account_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - SetAccountData *data); -static gboolean account_chooser_set_enabled_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - GossipAccountChooser *chooser); - -enum { - PROP_0, - PROP_CAN_SELECT_ALL, - PROP_HAS_ALL_OPTION, -}; - -G_DEFINE_TYPE (GossipAccountChooser, gossip_account_chooser, GTK_TYPE_COMBO_BOX); - -static void -gossip_account_chooser_class_init (GossipAccountChooserClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = account_chooser_finalize; - object_class->get_property = account_chooser_get_property; - object_class->set_property = account_chooser_set_property; - - g_object_class_install_property (object_class, - PROP_CAN_SELECT_ALL, - g_param_spec_boolean ("can-select-all", - "Can Select All", - "Should the user be able to select offline accounts", - FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_HAS_ALL_OPTION, - g_param_spec_boolean ("has-all-option", - "Has All Option", - "Have a separate option in the list to mean ALL accounts", - FALSE, - G_PARAM_READWRITE)); - - g_type_class_add_private (object_class, sizeof (GossipAccountChooserPriv)); -} - -static void -gossip_account_chooser_init (GossipAccountChooser *chooser) -{ -} - -static void -account_chooser_finalize (GObject *object) -{ - GossipAccountChooser *chooser; - GossipAccountChooserPriv *priv; - - chooser = GOSSIP_ACCOUNT_CHOOSER (object); - priv = GET_PRIV (object); - - g_signal_handlers_disconnect_by_func (priv->monitor, - account_chooser_account_created_cb, - chooser); - g_signal_handlers_disconnect_by_func (priv->monitor, - account_chooser_account_deleted_cb, - chooser); - dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc), - "AccountStatusChanged", - G_CALLBACK (account_chooser_status_changed_cb), - chooser); - g_object_unref (priv->mc); - g_object_unref (priv->monitor); - - G_OBJECT_CLASS (gossip_account_chooser_parent_class)->finalize (object); -} - -static void -account_chooser_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec) -{ - GossipAccountChooserPriv *priv; - - priv = GET_PRIV (object); - - switch (param_id) { - case PROP_CAN_SELECT_ALL: - g_value_set_boolean (value, priv->can_select_all); - break; - case PROP_HAS_ALL_OPTION: - g_value_set_boolean (value, priv->has_all_option); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -static void -account_chooser_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec) -{ - GossipAccountChooserPriv *priv; - - priv = GET_PRIV (object); - - switch (param_id) { - case PROP_CAN_SELECT_ALL: - gossip_account_chooser_set_can_select_all (GOSSIP_ACCOUNT_CHOOSER (object), - g_value_get_boolean (value)); - break; - case PROP_HAS_ALL_OPTION: - gossip_account_chooser_set_has_all_option (GOSSIP_ACCOUNT_CHOOSER (object), - g_value_get_boolean (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -GtkWidget * -gossip_account_chooser_new (void) -{ - GossipAccountChooserPriv *priv; - McAccountMonitor *monitor; - GtkWidget *chooser; - - monitor = mc_account_monitor_new (); - chooser = g_object_new (GOSSIP_TYPE_ACCOUNT_CHOOSER, NULL); - - priv = GET_PRIV (chooser); - - priv->mc = gossip_mission_control_new (); - priv->monitor = mc_account_monitor_new (); - - g_signal_connect (priv->monitor, "account-created", - G_CALLBACK (account_chooser_account_created_cb), - chooser); - g_signal_connect (priv->monitor, "account-deleted", - G_CALLBACK (account_chooser_account_deleted_cb), - chooser); - dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc), "AccountStatusChanged", - G_CALLBACK (account_chooser_status_changed_cb), - chooser, NULL); - - account_chooser_setup (GOSSIP_ACCOUNT_CHOOSER (chooser)); - - return chooser; -} - -McAccount * -gossip_account_chooser_get_account (GossipAccountChooser *chooser) -{ - GossipAccountChooserPriv *priv; - McAccount *account; - GtkTreeModel *model; - GtkTreeIter iter; - - g_return_val_if_fail (GOSSIP_IS_ACCOUNT_CHOOSER (chooser), NULL); - - priv = GET_PRIV (chooser); - - model = gtk_combo_box_get_model (GTK_COMBO_BOX (chooser)); - gtk_combo_box_get_active_iter (GTK_COMBO_BOX (chooser), &iter); - - gtk_tree_model_get (model, &iter, COL_ACCOUNT_POINTER, &account, -1); - - return account; -} - -gboolean -gossip_account_chooser_set_account (GossipAccountChooser *chooser, - McAccount *account) -{ - GtkComboBox *combobox; - GtkTreeModel *model; - GtkTreeIter iter; - SetAccountData data; - - g_return_val_if_fail (GOSSIP_IS_ACCOUNT_CHOOSER (chooser), FALSE); - - combobox = GTK_COMBO_BOX (chooser); - model = gtk_combo_box_get_model (combobox); - gtk_combo_box_get_active_iter (combobox, &iter); - - data.chooser = chooser; - data.account = account; - - gtk_tree_model_foreach (model, - (GtkTreeModelForeachFunc) account_chooser_set_account_foreach, - &data); - - return data.set; -} - -gboolean -gossip_account_chooser_get_can_select_all (GossipAccountChooser *chooser) -{ - GossipAccountChooserPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_ACCOUNT_CHOOSER (chooser), FALSE); - - priv = GET_PRIV (chooser); - - return priv->can_select_all; -} - -void -gossip_account_chooser_set_can_select_all (GossipAccountChooser *chooser, - gboolean can_select_all) -{ - GossipAccountChooserPriv *priv; - GtkComboBox *combobox; - GtkTreeModel *model; - - g_return_if_fail (GOSSIP_IS_ACCOUNT_CHOOSER (chooser)); - - priv = GET_PRIV (chooser); - - if (priv->can_select_all == can_select_all) { - return; - } - - combobox = GTK_COMBO_BOX (chooser); - model = gtk_combo_box_get_model (combobox); - - priv->can_select_all = can_select_all; - - gtk_tree_model_foreach (model, - (GtkTreeModelForeachFunc) account_chooser_set_enabled_foreach, - chooser); - - g_object_notify (G_OBJECT (chooser), "can-select-all"); -} - -gboolean -gossip_account_chooser_get_has_all_option (GossipAccountChooser *chooser) -{ - GossipAccountChooserPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_ACCOUNT_CHOOSER (chooser), FALSE); - - priv = GET_PRIV (chooser); - - return priv->has_all_option; -} - -void -gossip_account_chooser_set_has_all_option (GossipAccountChooser *chooser, - gboolean has_all_option) -{ - GossipAccountChooserPriv *priv; - GtkComboBox *combobox; - GtkListStore *store; - GtkTreeModel *model; - GtkTreeIter iter; - - g_return_if_fail (GOSSIP_IS_ACCOUNT_CHOOSER (chooser)); - - priv = GET_PRIV (chooser); - - if (priv->has_all_option == has_all_option) { - return; - } - - combobox = GTK_COMBO_BOX (chooser); - model = gtk_combo_box_get_model (combobox); - store = GTK_LIST_STORE (model); - - priv->has_all_option = has_all_option; - - /* - * The first 2 options are the ALL and separator - */ - - if (has_all_option) { - gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser), - (GtkTreeViewRowSeparatorFunc) - account_chooser_separator_func, - chooser, - NULL); - - gtk_list_store_prepend (store, &iter); - gtk_list_store_set (store, &iter, - COL_ACCOUNT_TEXT, NULL, - COL_ACCOUNT_ENABLED, TRUE, - COL_ACCOUNT_POINTER, NULL, - -1); - - gtk_list_store_prepend (store, &iter); - gtk_list_store_set (store, &iter, - COL_ACCOUNT_TEXT, _("All"), - COL_ACCOUNT_ENABLED, TRUE, - COL_ACCOUNT_POINTER, NULL, - -1); - } else { - if (gtk_tree_model_get_iter_first (model, &iter)) { - if (gtk_list_store_remove (GTK_LIST_STORE (model), &iter)) { - gtk_list_store_remove (GTK_LIST_STORE (model), &iter); - } - } - - gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser), - (GtkTreeViewRowSeparatorFunc) - NULL, - NULL, - NULL); - } - - g_object_notify (G_OBJECT (chooser), "has-all-option"); -} - -static void -account_chooser_setup (GossipAccountChooser *chooser) -{ - GossipAccountChooserPriv *priv; - GList *accounts; - GtkListStore *store; - GtkCellRenderer *renderer; - GtkComboBox *combobox; - - priv = GET_PRIV (chooser); - - /* Set up combo box with new store */ - combobox = GTK_COMBO_BOX (chooser); - - gtk_cell_layout_clear (GTK_CELL_LAYOUT (combobox)); - - store = gtk_list_store_new (COL_ACCOUNT_COUNT, - G_TYPE_STRING, - G_TYPE_STRING, /* Name */ - G_TYPE_BOOLEAN, /* Enabled */ - MC_TYPE_ACCOUNT); - - gtk_combo_box_set_model (combobox, GTK_TREE_MODEL (store)); - - renderer = gtk_cell_renderer_pixbuf_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, FALSE); - gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer, - "icon-name", COL_ACCOUNT_IMAGE, - "sensitive", COL_ACCOUNT_ENABLED, - NULL); - g_object_set (renderer, "stock-size", GTK_ICON_SIZE_BUTTON, NULL); - - renderer = gtk_cell_renderer_text_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, TRUE); - gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer, - "text", COL_ACCOUNT_TEXT, - "sensitive", COL_ACCOUNT_ENABLED, - NULL); - - /* Populate accounts */ - accounts = mc_accounts_list (); - g_list_foreach (accounts, - (GFunc) account_chooser_account_add_foreach, - chooser); - - mc_accounts_list_free (accounts); - g_object_unref (store); -} - -static void -account_chooser_account_created_cb (McAccountMonitor *monitor, - const gchar *unique_name, - GossipAccountChooser *chooser) -{ - McAccount *account; - - account = mc_account_lookup (unique_name); - account_chooser_account_add_foreach (account, chooser); - g_object_unref (account); -} - -static void -account_chooser_account_add_foreach (McAccount *account, - GossipAccountChooser *chooser) -{ - GossipAccountChooserPriv *priv; - GtkListStore *store; - GtkComboBox *combobox; - GtkTreeIter iter; - - priv = GET_PRIV (chooser); - - combobox = GTK_COMBO_BOX (chooser); - store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox)); - - gtk_list_store_append (store, &iter); - account_chooser_update_iter (chooser, &iter, account); -} - -static void -account_chooser_account_deleted_cb (McAccountMonitor *monitor, - const gchar *unique_name, - GossipAccountChooser *chooser) -{ - McAccount *account; - - account = mc_account_lookup (unique_name); - account_chooser_account_remove_foreach (account, chooser); - g_object_unref (account); -} - -static void -account_chooser_account_remove_foreach (McAccount *account, - GossipAccountChooser *chooser) -{ - /* Fixme: TODO */ -} - -static void -account_chooser_update_iter (GossipAccountChooser *chooser, - GtkTreeIter *iter, - McAccount *account) -{ - GossipAccountChooserPriv *priv; - GtkListStore *store; - GtkComboBox *combobox; - TpConn *tp_conn; - const gchar *icon_name; - gboolean is_enabled; - - priv = GET_PRIV (chooser); - - combobox = GTK_COMBO_BOX (chooser); - store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox)); - - icon_name = gossip_icon_name_from_account (account); - tp_conn = mission_control_get_connection (priv->mc, account, NULL); - is_enabled = (tp_conn != NULL || priv->can_select_all); - - if (tp_conn) { - g_object_unref (tp_conn); - } - - gtk_list_store_set (store, iter, - COL_ACCOUNT_IMAGE, icon_name, - COL_ACCOUNT_TEXT, mc_account_get_display_name (account), - COL_ACCOUNT_ENABLED, is_enabled, - COL_ACCOUNT_POINTER, account, - -1); - - /* set first connected account as active account */ - if (priv->set_active_item == FALSE && is_enabled) { - priv->set_active_item = TRUE; - gtk_combo_box_set_active_iter (combobox, iter); - } -} - -static void -account_chooser_status_changed_cb (MissionControl *mc, - TelepathyConnectionStatus status, - McPresence presence, - TelepathyConnectionStatusReason reason, - const gchar *unique_name, - GossipAccountChooser *chooser) -{ - /* FIXME: implement */ -} - -static gboolean -account_chooser_separator_func (GtkTreeModel *model, - GtkTreeIter *iter, - GossipAccountChooser *chooser) -{ - GossipAccountChooserPriv *priv; - gchar *text; - gboolean is_separator; - - priv = GET_PRIV (chooser); - - if (!priv->has_all_option) { - return FALSE; - } - - gtk_tree_model_get (model, iter, COL_ACCOUNT_TEXT, &text, -1); - is_separator = text == NULL; - g_free (text); - - return is_separator; -} - -static gboolean -account_chooser_set_account_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - SetAccountData *data) -{ - McAccount *account; - gboolean equal; - - gtk_tree_model_get (model, iter, COL_ACCOUNT_POINTER, &account, -1); - - /* Special case so we can make it possible to select the All option */ - if (!data->account && !account) { - equal = TRUE; - } - else if ((data->account && !account) || (!data->account && account)) { - equal = FALSE; - } else { - equal = gossip_account_equal (data->account, account); - g_object_unref (account); - } - - if (equal) { - GtkComboBox *combobox; - - combobox = GTK_COMBO_BOX (data->chooser); - gtk_combo_box_set_active_iter (combobox, iter); - - data->set = TRUE; - } - - return equal; -} - -static gboolean -account_chooser_set_enabled_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - GossipAccountChooser *chooser) -{ - GossipAccountChooserPriv *priv; - McAccount *account; - - priv = GET_PRIV (chooser); - - gtk_tree_model_get (model, iter, COL_ACCOUNT_POINTER, &account, -1); - if (!account) { - return FALSE; - } - - account_chooser_update_iter (chooser, iter, account); - g_object_unref (account); - - return FALSE; -} - diff --git a/libempathy-gtk/gossip-account-chooser.h b/libempathy-gtk/gossip-account-chooser.h deleted file mode 100644 index b2d7c0cd..00000000 --- a/libempathy-gtk/gossip-account-chooser.h +++ /dev/null @@ -1,66 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2005-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Martyn Russell - */ - -#ifndef __GOSSIP_ACCOUNT_CHOOSER_H__ -#define __GOSSIP_ACCOUNT_CHOOSER_H__ - -#include - -#include - -G_BEGIN_DECLS - -#define GOSSIP_TYPE_ACCOUNT_CHOOSER (gossip_account_chooser_get_type ()) -#define GOSSIP_ACCOUNT_CHOOSER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOSSIP_TYPE_ACCOUNT_CHOOSER, GossipAccountChooser)) -#define GOSSIP_ACCOUNT_CHOOSER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GOSSIP_TYPE_ACCOUNT_CHOOSER, GossipAccountChooserClass)) -#define GOSSIP_IS_ACCOUNT_CHOOSER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOSSIP_TYPE_ACCOUNT_CHOOSER)) -#define GOSSIP_IS_ACCOUNT_CHOOSER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOSSIP_TYPE_ACCOUNT_CHOOSER)) -#define GOSSIP_ACCOUNT_CHOOSER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOSSIP_TYPE_ACCOUNT_CHOOSER, GossipAccountChooserClass)) - -typedef struct _GossipAccountChooser GossipAccountChooser; -typedef struct _GossipAccountChooserClass GossipAccountChooserClass; - -struct _GossipAccountChooser { - GtkComboBox parent; -}; - -struct _GossipAccountChooserClass { - GtkComboBoxClass parent_class; -}; - -GType gossip_account_chooser_get_type (void) G_GNUC_CONST; -GtkWidget * gossip_account_chooser_new (void); -McAccount * gossip_account_chooser_get_account (GossipAccountChooser *chooser); -gboolean gossip_account_chooser_set_account (GossipAccountChooser *chooser, - McAccount *account); -gboolean gossip_account_chooser_get_can_select_all (GossipAccountChooser *chooser); - -void gossip_account_chooser_set_can_select_all (GossipAccountChooser *chooser, - gboolean can_select_all); -gboolean gossip_account_chooser_get_has_all_option (GossipAccountChooser *chooser); -void gossip_account_chooser_set_has_all_option (GossipAccountChooser *chooser, - gboolean has_all_option); - -G_END_DECLS - -#endif /* __GOSSIP_ACCOUNT_CHOOSER_H__ */ - diff --git a/libempathy-gtk/gossip-account-widget-generic.c b/libempathy-gtk/gossip-account-widget-generic.c deleted file mode 100644 index 4ba0f9f2..00000000 --- a/libempathy-gtk/gossip-account-widget-generic.c +++ /dev/null @@ -1,310 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Xavier Claessens - * Martyn Russell - */ - -#include - -#include - -#include -#include - -#include -#include - -#include - -#include "gossip-account-widget-generic.h" - -typedef struct { - McAccount *account; - - GtkWidget *sw; - GtkWidget *table_settings; - GtkSizeGroup *size_group; - - guint n_rows; -} GossipAccountWidgetGeneric; - -static gboolean account_widget_generic_entry_focus_cb (GtkWidget *widget, - GdkEventFocus *event, - GossipAccountWidgetGeneric *settings); -static void account_widget_generic_int_changed_cb (GtkWidget *widget, - GossipAccountWidgetGeneric *settings); -static void account_widget_generic_checkbutton_toggled_cb (GtkWidget *widget, - GossipAccountWidgetGeneric *settings); -static gchar * account_widget_generic_format_param_name (const gchar *param_name); -static void account_widget_generic_setup_foreach (McProtocolParam *param, - GossipAccountWidgetGeneric *settings); -static void account_widget_generic_destroy_cb (GtkWidget *widget, - GossipAccountWidgetGeneric *settings); - -static gboolean -account_widget_generic_entry_focus_cb (GtkWidget *widget, - GdkEventFocus *event, - GossipAccountWidgetGeneric *settings) -{ - const gchar *str; - const gchar *param_name; - - str = gtk_entry_get_text (GTK_ENTRY (widget)); - param_name = g_object_get_data (G_OBJECT (widget), "param_name"); - - mc_account_set_param_string (settings->account, param_name, str); - - return FALSE; -} - -static void -account_widget_generic_int_changed_cb (GtkWidget *widget, - GossipAccountWidgetGeneric *settings) -{ - const gchar *param_name; - gint value; - - value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (widget)); - param_name = g_object_get_data (G_OBJECT (widget), "param_name"); - - mc_account_set_param_int (settings->account, param_name, value); -} - -static void -account_widget_generic_checkbutton_toggled_cb (GtkWidget *widget, - GossipAccountWidgetGeneric *settings) -{ - gboolean active; - const gchar *param_name; - - active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); - param_name = g_object_get_data (G_OBJECT (widget), "param_name"); - - mc_account_set_param_boolean (settings->account, param_name, active); -} - -static gchar * -account_widget_generic_format_param_name (const gchar *param_name) -{ - gchar *str; - gchar *p; - - str = g_strdup (param_name); - - if (str && g_ascii_isalpha (str[0])) { - str[0] = g_ascii_toupper (str[0]); - } - - while ((p = strchr (str, '-')) != NULL) { - if (p[1] != '\0' && g_ascii_isalpha (p[1])) { - p[0] = ' '; - p[1] = g_ascii_toupper (p[1]); - } - - p++; - } - - return str; -} - -static void -account_widget_generic_setup_foreach (McProtocolParam *param, - GossipAccountWidgetGeneric *settings) -{ - GtkWidget *widget; - gchar *param_name_formatted; - - param_name_formatted = account_widget_generic_format_param_name (param->name); - - gtk_table_resize (GTK_TABLE (settings->table_settings), - ++settings->n_rows, - 2); - - if (param->signature[0] == 's') { - gchar *str = NULL; - - str = g_strdup_printf (_("%s:"), param_name_formatted); - widget = gtk_label_new (str); - g_free (str); - - gtk_size_group_add_widget (settings->size_group, widget); - gtk_table_attach (GTK_TABLE (settings->table_settings), - widget, - 0, 1, - settings->n_rows - 1, settings->n_rows, - GTK_FILL, 0, - 0, 0); - - str = NULL; - widget = gtk_entry_new (); - mc_account_get_param_string (settings->account, - param->name, - &str); - if (str) { - gtk_entry_set_text (GTK_ENTRY (widget), str); - g_free (str); - } - - if (strstr (param->name, "password")) { - gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE); - } - - g_signal_connect (widget, "focus-out-event", - G_CALLBACK (account_widget_generic_entry_focus_cb), - settings); - - gtk_table_attach (GTK_TABLE (settings->table_settings), - widget, - 1, 2, - settings->n_rows - 1, settings->n_rows, - GTK_FILL | GTK_EXPAND, 0, - 0, 0); - } - else if (param->signature[0] == 'q' || - param->signature[0] == 'n') { - gchar *str = NULL; - gint value = 0; - - str = g_strdup_printf (_("%s:"), param_name_formatted); - widget = gtk_label_new (str); - g_free (str); - - gtk_size_group_add_widget (settings->size_group, widget); - gtk_table_attach (GTK_TABLE (settings->table_settings), - widget, - 0, 1, - settings->n_rows - 1, settings->n_rows, - GTK_FILL, 0, - 0, 0); - - widget = gtk_spin_button_new_with_range (0, G_MAXINT, 1); - mc_account_get_param_int (settings->account, - param->name, - &value); - gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value); - - g_signal_connect (widget, "value-changed", - G_CALLBACK (account_widget_generic_int_changed_cb), - settings); - - gtk_table_attach (GTK_TABLE (settings->table_settings), - widget, - 1, 2, - settings->n_rows - 1, settings->n_rows, - GTK_FILL | GTK_EXPAND, 0, - 0, 0); - } - else if (param->signature[0] == 'b') { - gboolean value = FALSE; - - mc_account_get_param_boolean (settings->account, - param->name, - &value); - - widget = gtk_check_button_new_with_label (param_name_formatted); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), value); - - g_signal_connect (widget, "toggled", - G_CALLBACK (account_widget_generic_checkbutton_toggled_cb), - settings); - - gtk_table_attach (GTK_TABLE (settings->table_settings), - widget, - 0, 2, - settings->n_rows - 1, settings->n_rows, - GTK_FILL | GTK_EXPAND, 0, - 0, 0); - } else { - g_assert_not_reached (); - } - - g_free (param_name_formatted); - - g_object_set_data_full (G_OBJECT (widget), "param_name", - g_strdup (param->name), g_free); -} - -static void -accounts_widget_generic_setup (GossipAccountWidgetGeneric *settings) -{ - McProtocol *protocol; - McProfile *profile; - GSList *params; - - profile = mc_account_get_profile (settings->account); - protocol = mc_profile_get_protocol (profile); - params = mc_protocol_get_params (protocol); - - g_slist_foreach (params, - (GFunc) account_widget_generic_setup_foreach, - settings); - - g_slist_free (params); -} - -static void -account_widget_generic_destroy_cb (GtkWidget *widget, - GossipAccountWidgetGeneric *settings) -{ - g_object_unref (settings->account); - g_object_unref (settings->size_group); - - g_free (settings); -} - -GtkWidget * -gossip_account_widget_generic_new (McAccount *account, - GtkWidget *label_name) -{ - GossipAccountWidgetGeneric *settings; - - g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); - g_return_val_if_fail (GTK_IS_WIDGET (label_name), NULL); - - settings = g_new0 (GossipAccountWidgetGeneric, 1); - - settings->account = g_object_ref (account); - - settings->table_settings = gtk_table_new (0, 2, FALSE); - gtk_table_set_row_spacings (GTK_TABLE (settings->table_settings), 6); - gtk_table_set_col_spacings (GTK_TABLE (settings->table_settings), 6); - settings->sw = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (settings->sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (settings->sw), - settings->table_settings); - - settings->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); - if (label_name) { - gtk_size_group_add_widget (settings->size_group, label_name); - } - - accounts_widget_generic_setup (settings); - - g_signal_connect (settings->sw, "destroy", - G_CALLBACK (account_widget_generic_destroy_cb), - settings); - - gtk_widget_show_all (settings->sw); - - return settings->sw; -} diff --git a/libempathy-gtk/gossip-account-widget-generic.h b/libempathy-gtk/gossip-account-widget-generic.h deleted file mode 100644 index 4b3c7eba..00000000 --- a/libempathy-gtk/gossip-account-widget-generic.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Xavier Claessens - * Martyn Russell - */ - -#ifndef __GOSSIP_ACCOUNT_WIDGET_GENERIC_H__ -#define __GOSSIP_ACCOUNT_WIDGET_GENERIC_H__ - -#include - -#include - -G_BEGIN_DECLS - -GtkWidget *gossip_account_widget_generic_new (McAccount *account, - GtkWidget *label_name); - -G_END_DECLS - -#endif /* __GOSSIP_ACCOUNT_WIDGET_GENERIC_H__ */ diff --git a/libempathy-gtk/gossip-account-widget-jabber.c b/libempathy-gtk/gossip-account-widget-jabber.c deleted file mode 100644 index e7334b4b..00000000 --- a/libempathy-gtk/gossip-account-widget-jabber.c +++ /dev/null @@ -1,281 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Xavier Claessens - */ - -#include "config.h" - -#include -#include -#include - -#include -#include -#include - -#include - -#include - -#include "gossip-account-widget-jabber.h" -#include "gossip-ui-utils.h" - -#define PORT_WITHOUT_SSL 5222 -#define PORT_WITH_SSL 5223 - -typedef struct { - McAccount *account; - - GtkWidget *vbox_settings; - GtkWidget *button_forget; - GtkWidget *entry_id; - GtkWidget *entry_password; - GtkWidget *entry_resource; - GtkWidget *entry_server; - GtkWidget *spinbutton_port; - GtkWidget *checkbutton_ssl; -} GossipAccountWidgetJabber; - -static gboolean account_widget_jabber_entry_focus_cb (GtkWidget *widget, - GdkEventFocus *event, - GossipAccountWidgetJabber *settings); -static void account_widget_jabber_entry_changed_cb (GtkWidget *widget, - GossipAccountWidgetJabber *settings); -static void account_widget_jabber_checkbutton_toggled_cb (GtkWidget *widget, - GossipAccountWidgetJabber *settings); -static void account_widget_jabber_value_changed_cb (GtkWidget *spinbutton, - GossipAccountWidgetJabber *settings); -static void account_widget_jabber_button_forget_clicked_cb (GtkWidget *button, - GossipAccountWidgetJabber *settings); -static void account_widget_jabber_destroy_cb (GtkWidget *widget, - GossipAccountWidgetJabber *settings); -static void account_widget_jabber_setup (GossipAccountWidgetJabber *settings); - -static gboolean -account_widget_jabber_entry_focus_cb (GtkWidget *widget, - GdkEventFocus *event, - GossipAccountWidgetJabber *settings) -{ - const gchar *param; - const gchar *str; - - if (widget == settings->entry_password) { - param = "password"; - } - else if (widget == settings->entry_resource) { - param = "resource"; - } - else if (widget == settings->entry_server) { - param = "server"; - } - else if (widget == settings->entry_id) { - param = "account"; - } else { - return FALSE; - } - - str = gtk_entry_get_text (GTK_ENTRY (widget)); - if (G_STR_EMPTY (str)) { - gchar *value = NULL; - - mc_account_get_param_string (settings->account, param, &value); - gtk_entry_set_text (GTK_ENTRY (widget), value ? value : ""); - g_free (value); - } else { - mc_account_set_param_string (settings->account, param, str); - } - - return FALSE; -} - -static void -account_widget_jabber_entry_changed_cb (GtkWidget *widget, - GossipAccountWidgetJabber *settings) -{ - if (widget == settings->entry_password) { - const gchar *str; - - str = gtk_entry_get_text (GTK_ENTRY (widget)); - gtk_widget_set_sensitive (settings->button_forget, !G_STR_EMPTY (str)); - } -} - -static void -account_widget_jabber_checkbutton_toggled_cb (GtkWidget *widget, - GossipAccountWidgetJabber *settings) -{ - if (widget == settings->checkbutton_ssl) { - gint port = 0; - gboolean old_ssl; - - mc_account_get_param_int (settings->account, "port", &port); - old_ssl = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); - - if (old_ssl) { - if (port == PORT_WITHOUT_SSL) { - port = PORT_WITH_SSL; - } - } else { - if (port == PORT_WITH_SSL) { - port = PORT_WITHOUT_SSL; - } - } - - mc_account_set_param_int (settings->account, "port", port); - mc_account_set_param_boolean (settings->account, "old-ssl", old_ssl); - gtk_spin_button_set_value (GTK_SPIN_BUTTON (settings->spinbutton_port), port); - } -} - -static void -account_widget_jabber_value_changed_cb (GtkWidget *spinbutton, - GossipAccountWidgetJabber *settings) -{ - if (spinbutton == settings->spinbutton_port) { - gdouble value; - - value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (spinbutton)); - mc_account_set_param_int (settings->account, "port", (gint) value); - } -} - -static void -account_widget_jabber_button_forget_clicked_cb (GtkWidget *button, - GossipAccountWidgetJabber *settings) -{ - mc_account_set_param_string (settings->account, "password", ""); - gtk_entry_set_text (GTK_ENTRY (settings->entry_password), ""); -} - -static void -account_widget_jabber_destroy_cb (GtkWidget *widget, - GossipAccountWidgetJabber *settings) -{ - g_object_unref (settings->account); - g_free (settings); -} - -static void -account_widget_jabber_setup (GossipAccountWidgetJabber *settings) -{ - gint port = 0; - gchar *id = NULL; - gchar *resource = NULL; - gchar *server = NULL; - gchar *password = NULL; - gboolean old_ssl = FALSE; - - mc_account_get_param_int (settings->account, "port", &port); - mc_account_get_param_string (settings->account, "account", &id); - mc_account_get_param_string (settings->account, "resource", &resource); - mc_account_get_param_string (settings->account, "server", &server); - mc_account_get_param_string (settings->account, "password", &password); - mc_account_get_param_boolean (settings->account, "old-ssl", &old_ssl); - - if (!id) { - McProfile *profile; - const gchar *server; - - profile = mc_account_get_profile (settings->account); - server = mc_profile_get_default_account_domain (profile); - if (server) { - id = g_strconcat ("user@", server, NULL); - } - g_object_unref (profile); - } - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (settings->checkbutton_ssl), old_ssl); - gtk_entry_set_text (GTK_ENTRY (settings->entry_id), id ? id : ""); - gtk_entry_set_text (GTK_ENTRY (settings->entry_password), password ? password : ""); - gtk_entry_set_text (GTK_ENTRY (settings->entry_resource), resource ? resource : ""); - gtk_entry_set_text (GTK_ENTRY (settings->entry_server), server ? server : ""); - gtk_spin_button_set_value (GTK_SPIN_BUTTON (settings->spinbutton_port), port); - - gtk_widget_set_sensitive (settings->button_forget, !G_STR_EMPTY (password)); - - g_free (id); - g_free (resource); - g_free (server); - g_free (password); -} - -GtkWidget * -gossip_account_widget_jabber_new (McAccount *account) -{ - GossipAccountWidgetJabber *settings; - GladeXML *glade; - GtkSizeGroup *size_group; - GtkWidget *label_id, *label_password; - GtkWidget *label_server, *label_resource, *label_port; - - settings = g_new0 (GossipAccountWidgetJabber, 1); - settings->account = g_object_ref (account); - - glade = gossip_glade_get_file ("gossip-account-widget-jabber.glade", - "vbox_jabber_settings", - NULL, - "vbox_jabber_settings", &settings->vbox_settings, - "button_forget", &settings->button_forget, - "label_id", &label_id, - "label_password", &label_password, - "label_resource", &label_resource, - "label_server", &label_server, - "label_port", &label_port, - "entry_id", &settings->entry_id, - "entry_password", &settings->entry_password, - "entry_resource", &settings->entry_resource, - "entry_server", &settings->entry_server, - "spinbutton_port", &settings->spinbutton_port, - "checkbutton_ssl", &settings->checkbutton_ssl, - NULL); - - account_widget_jabber_setup (settings); - - gossip_glade_connect (glade, - settings, - "vbox_jabber_settings", "destroy", account_widget_jabber_destroy_cb, - "button_forget", "clicked", account_widget_jabber_button_forget_clicked_cb, - "entry_password", "changed", account_widget_jabber_entry_changed_cb, - "spinbutton_port", "value-changed", account_widget_jabber_value_changed_cb, - "entry_id", "focus-out-event", account_widget_jabber_entry_focus_cb, - "entry_password", "focus-out-event", account_widget_jabber_entry_focus_cb, - "entry_resource", "focus-out-event", account_widget_jabber_entry_focus_cb, - "entry_server", "focus-out-event", account_widget_jabber_entry_focus_cb, - "checkbutton_ssl", "toggled", account_widget_jabber_checkbutton_toggled_cb, - NULL); - - g_object_unref (glade); - - /* Set up remaining widgets */ - size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); - - gtk_size_group_add_widget (size_group, label_id); - gtk_size_group_add_widget (size_group, label_password); - gtk_size_group_add_widget (size_group, label_resource); - gtk_size_group_add_widget (size_group, label_server); - gtk_size_group_add_widget (size_group, label_port); - - g_object_unref (size_group); - - gtk_widget_show (settings->vbox_settings); - - return settings->vbox_settings; -} - diff --git a/libempathy-gtk/gossip-account-widget-jabber.glade b/libempathy-gtk/gossip-account-widget-jabber.glade deleted file mode 100644 index 12eec757..00000000 --- a/libempathy-gtk/gossip-account-widget-jabber.glade +++ /dev/null @@ -1,335 +0,0 @@ - - - - - - - True - jabber account settings - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - False - False - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - 6 - 3 - False - 6 - 12 - - - - True - Login I_D: - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - entry_id - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 0 - 1 - fill - - - - - - - True - Pass_word: - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - entry_password - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 1 - 2 - fill - - - - - - - True - Reso_urce: - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - entry_resource - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 2 - 3 - fill - - - - - - - True - _Server: - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - entry_server - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 3 - 4 - fill - - - - - - - True - _Port: - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - spinbutton_port - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 4 - 5 - fill - - - - - - - True - True - True - True - 0 - - True - * - False - - - 1 - 3 - 2 - 3 - - - - - - - True - True - True - True - 0 - - True - * - False - - - 1 - 3 - 3 - 4 - - - - - - - True - True - Use encryption (SS_L) - True - GTK_RELIEF_NORMAL - True - False - False - True - - - 0 - 3 - 5 - 6 - fill - - - - - - - True - True - 1 - 0 - True - GTK_UPDATE_ALWAYS - False - False - 5222 0 65556 1 10 10 - - - 1 - 3 - 4 - 5 - - - - - - - True - Forget password and clear the entry. - True - GTK_RELIEF_NORMAL - True - - - - True - gtk-clear - 1 - 0.5 - 0.5 - 0 - 0 - - - - - 2 - 3 - 1 - 2 - fill - - - - - - - True - True - True - False - 0 - - True - * - False - - - 1 - 2 - 1 - 2 - - - - - - - True - True - True - True - 0 - - True - * - False - - - 1 - 3 - 0 - 1 - - - - - - - - diff --git a/libempathy-gtk/gossip-account-widget-jabber.h b/libempathy-gtk/gossip-account-widget-jabber.h deleted file mode 100644 index 0a967f7b..00000000 --- a/libempathy-gtk/gossip-account-widget-jabber.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Xavier Claessens - */ - -#ifndef __GOSSIP_ACCOUNT_WIDGET_JABBER_H__ -#define __GOSSIP_ACCOUNT_WIDGET_JABBER_H__ - -#include - -G_BEGIN_DECLS - -GtkWidget *gossip_account_widget_jabber_new (McAccount *account); - -G_END_DECLS - -#endif /* __GOSSIP_ACCOUNT_WIDGET_JABBER_H__ */ diff --git a/libempathy-gtk/gossip-accounts-dialog.c b/libempathy-gtk/gossip-accounts-dialog.c deleted file mode 100644 index 3abb9be3..00000000 --- a/libempathy-gtk/gossip-accounts-dialog.c +++ /dev/null @@ -1,1037 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2005-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Martyn Russell - * Xavier Claessens - */ - -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "gossip-accounts-dialog.h" -#include "gossip-profile-chooser.h" -#include "gossip-account-widget-generic.h" -#include "gossip-account-widget-jabber.h" - -#define DEBUG_DOMAIN "AccountDialog" - -/* Flashing delay for icons (milliseconds). */ -#define FLASH_TIMEOUT 500 - -typedef struct { - GtkWidget *window; - - GtkWidget *alignment_settings; - - GtkWidget *vbox_details; - GtkWidget *frame_no_account; - GtkWidget *label_no_account; - GtkWidget *label_no_account_blurb; - - GtkWidget *treeview; - - GtkWidget *button_remove; - GtkWidget *button_connect; - - GtkWidget *frame_new_account; - GtkWidget *combobox_profile; - GtkWidget *entry_name; - GtkWidget *table_new_account; - GtkWidget *button_create; - GtkWidget *button_back; - - GtkWidget *image_type; - GtkWidget *label_name; - GtkWidget *label_type; - GtkWidget *settings_widget; - - gboolean connecting_show; - guint connecting_id; - gboolean account_changed; - - MissionControl *mc; - McAccountMonitor *monitor; -} GossipAccountsDialog; - -enum { - COL_NAME, - COL_STATUS, - COL_ACCOUNT_POINTER, - COL_COUNT -}; - -static void accounts_dialog_setup (GossipAccountsDialog *dialog); -static void accounts_dialog_update_account (GossipAccountsDialog *dialog, - McAccount *account); -static void accounts_dialog_model_setup (GossipAccountsDialog *dialog); -static void accounts_dialog_model_add_columns (GossipAccountsDialog *dialog); -static void accounts_dialog_model_select_first (GossipAccountsDialog *dialog); -static void accounts_dialog_model_pixbuf_data_func (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - GossipAccountsDialog *dialog); -static McAccount *accounts_dialog_model_get_selected (GossipAccountsDialog *dialog); -static void accounts_dialog_model_set_selected (GossipAccountsDialog *dialog, - McAccount *account); -static gboolean accounts_dialog_model_remove_selected (GossipAccountsDialog *dialog); -static void accounts_dialog_model_selection_changed (GtkTreeSelection *selection, - GossipAccountsDialog *dialog); -static void accounts_dialog_add_account (GossipAccountsDialog *dialog, - McAccount *account); -static void accounts_dialog_account_added_cb (McAccountMonitor *monitor, - gchar *unique_name, - GossipAccountsDialog *dialog); -static void accounts_dialog_account_removed_cb (McAccountMonitor *monitor, - gchar *unique_name, - GossipAccountsDialog *dialog); -static gboolean accounts_dialog_row_changed_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gpointer user_data); -static gboolean accounts_dialog_flash_connecting_cb (GossipAccountsDialog *dialog); -static void accounts_dialog_status_changed_cb (MissionControl *mc, - TelepathyConnectionStatus status, - McPresence presence, - TelepathyConnectionStatusReason reason, - const gchar *unique_name, - GossipAccountsDialog *dialog); -static void accounts_dialog_entry_name_changed_cb (GtkWidget *widget, - GossipAccountsDialog *dialog); -static void accounts_dialog_button_create_clicked_cb (GtkWidget *button, - GossipAccountsDialog *dialog); -static void accounts_dialog_button_back_clicked_cb (GtkWidget *button, - GossipAccountsDialog *dialog); -static void accounts_dialog_button_connect_clicked_cb (GtkWidget *button, - GossipAccountsDialog *dialog); -static void accounts_dialog_button_add_clicked_cb (GtkWidget *button, - GossipAccountsDialog *dialog); -static void accounts_dialog_remove_response_cb (GtkWidget *dialog, - gint response, - McAccount *account); -static void accounts_dialog_button_remove_clicked_cb (GtkWidget *button, - GossipAccountsDialog *dialog); -static void accounts_dialog_treeview_row_activated_cb (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - GossipAccountsDialog *dialog); -static void accounts_dialog_response_cb (GtkWidget *widget, - gint response, - GossipAccountsDialog *dialog); -static void accounts_dialog_destroy_cb (GtkWidget *widget, - GossipAccountsDialog *dialog); - -static void -accounts_dialog_setup (GossipAccountsDialog *dialog) -{ - GtkTreeView *view; - GtkListStore *store; - GtkTreeSelection *selection; - GtkTreeIter iter; - GList *accounts, *l; - - view = GTK_TREE_VIEW (dialog->treeview); - store = GTK_LIST_STORE (gtk_tree_view_get_model (view)); - selection = gtk_tree_view_get_selection (view); - - accounts = mc_accounts_list (); - - for (l = accounts; l; l = l->next) { - McAccount *account; - const gchar *name; - TelepathyConnectionStatus status; - - account = l->data; - - name = mc_account_get_display_name (account); - if (!name) { - continue; - } - - status = mission_control_get_connection_status (dialog->mc, account, NULL); - - gtk_list_store_insert_with_values (store, &iter, - -1, - COL_NAME, name, - COL_STATUS, status, - COL_ACCOUNT_POINTER, account, - -1); - - accounts_dialog_status_changed_cb (dialog->mc, - status, - MC_PRESENCE_UNSET, - TP_CONN_STATUS_REASON_NONE_SPECIFIED, - mc_account_get_unique_name (account), - dialog); - - g_object_unref (account); - } - - g_list_free (accounts); -} - -static void -accounts_dialog_update_connect_button (GossipAccountsDialog *dialog) -{ - McAccount *account; - GtkWidget *image; - const gchar *stock_id; - const gchar *label; - - account = accounts_dialog_model_get_selected (dialog); - - if (!account) { - gtk_widget_set_sensitive (dialog->button_connect, FALSE); - return; - } - - if (mc_account_is_enabled (account)) { - label = _("Disable"); - stock_id = GTK_STOCK_DISCONNECT; - } else { - label = _("Enable"); - stock_id = GTK_STOCK_CONNECT; - } - - image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON); - - gtk_button_set_label (GTK_BUTTON (dialog->button_connect), label); - gtk_button_set_image (GTK_BUTTON (dialog->button_connect), image); -} - -static void -accounts_dialog_update_account (GossipAccountsDialog *dialog, - McAccount *account) -{ - if (dialog->settings_widget) { - gtk_widget_destroy (dialog->settings_widget); - dialog->settings_widget = NULL; - } - - if (!account) { - GtkTreeView *view; - GtkTreeModel *model; - - gtk_widget_show (dialog->frame_no_account); - gtk_widget_hide (dialog->vbox_details); - - gtk_widget_set_sensitive (dialog->button_connect, FALSE); - gtk_widget_set_sensitive (dialog->button_remove, FALSE); - - view = GTK_TREE_VIEW (dialog->treeview); - model = gtk_tree_view_get_model (view); - - if (gtk_tree_model_iter_n_children (model, NULL) > 0) { - gtk_label_set_markup (GTK_LABEL (dialog->label_no_account), - _("No Account Selected")); - gtk_label_set_markup (GTK_LABEL (dialog->label_no_account_blurb), - _("To add a new account, you can click on the " - "'Add' button and a new entry will be created " - "for you to start configuring.\n" - "\n" - "If you do not want to add an account, simply " - "click on the account you want to configure in " - "the list on the left.")); - } else { - gtk_label_set_markup (GTK_LABEL (dialog->label_no_account), - _("No Accounts Configured")); - gtk_label_set_markup (GTK_LABEL (dialog->label_no_account_blurb), - _("To add a new account, you can click on the " - "'Add' button and a new entry will be created " - "for you to start configuring.")); - } - } else { - McProfile *profile; - const gchar *config_ui; - - gtk_widget_hide (dialog->frame_no_account); - gtk_widget_show (dialog->vbox_details); - - profile = mc_account_get_profile (account); - config_ui = mc_profile_get_configuration_ui (profile); - - if (strcmp (config_ui, "jabber") == 0) { - dialog->settings_widget = - gossip_account_widget_jabber_new (account); - } else { - dialog->settings_widget = - gossip_account_widget_generic_new (account, - dialog->label_name); - } - - gtk_widget_grab_focus (dialog->settings_widget); - } - - if (dialog->settings_widget) { - gtk_container_add (GTK_CONTAINER (dialog->alignment_settings), - dialog->settings_widget); - } - - if (account) { - McProfile *profile; - - profile = mc_account_get_profile (account); - gtk_image_set_from_icon_name (GTK_IMAGE (dialog->image_type), - mc_profile_get_icon_name (profile), - GTK_ICON_SIZE_DIALOG); - - - gtk_label_set_text (GTK_LABEL (dialog->label_type), - mc_profile_get_display_name (profile)); - gtk_label_set_text (GTK_LABEL (dialog->label_name), - mc_account_get_display_name (account)); - } -} - -static void -accounts_dialog_model_setup (GossipAccountsDialog *dialog) -{ - GtkListStore *store; - GtkTreeSelection *selection; - - store = gtk_list_store_new (COL_COUNT, - G_TYPE_STRING, /* name */ - G_TYPE_UINT, /* status */ - MC_TYPE_ACCOUNT); /* account */ - - gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->treeview), - GTK_TREE_MODEL (store)); - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->treeview)); - gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); - - g_signal_connect (selection, "changed", - G_CALLBACK (accounts_dialog_model_selection_changed), - dialog); - - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), - COL_NAME, GTK_SORT_ASCENDING); - - accounts_dialog_model_add_columns (dialog); - - g_object_unref (store); -} - -static void -accounts_dialog_model_add_columns (GossipAccountsDialog *dialog) -{ - GtkTreeView *view; - GtkTreeViewColumn *column; - GtkCellRenderer *cell; - - view = GTK_TREE_VIEW (dialog->treeview); - gtk_tree_view_set_headers_visible (view, TRUE); - - /* account name/status */ - column = gtk_tree_view_column_new (); - gtk_tree_view_column_set_title (column, _("Accounts")); - - cell = gtk_cell_renderer_pixbuf_new (); - gtk_tree_view_column_pack_start (column, cell, FALSE); - gtk_tree_view_column_set_cell_data_func (column, cell, - (GtkTreeCellDataFunc) - accounts_dialog_model_pixbuf_data_func, - dialog, - NULL); - - cell = gtk_cell_renderer_text_new (); - g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL); - gtk_tree_view_column_pack_start (column, cell, TRUE); - gtk_tree_view_column_add_attribute (column, - cell, - "text", COL_NAME); - - gtk_tree_view_column_set_expand (column, TRUE); - gtk_tree_view_append_column (view, column); -} - -static void -accounts_dialog_model_select_first (GossipAccountsDialog *dialog) -{ - GtkTreeView *view; - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - - /* select first */ - view = GTK_TREE_VIEW (dialog->treeview); - model = gtk_tree_view_get_model (view); - - if (gtk_tree_model_get_iter_first (model, &iter)) { - selection = gtk_tree_view_get_selection (view); - gtk_tree_selection_select_iter (selection, &iter); - } else { - accounts_dialog_update_account (dialog, NULL); - } -} - -static void -accounts_dialog_model_pixbuf_data_func (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - GossipAccountsDialog *dialog) -{ - McAccount *account; - const gchar *icon_name; - GdkPixbuf *pixbuf; - TelepathyConnectionStatus status; - - gtk_tree_model_get (model, iter, - COL_STATUS, &status, - COL_ACCOUNT_POINTER, &account, - -1); - - icon_name = gossip_icon_name_from_account (account); - pixbuf = gossip_pixbuf_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON); - - if (pixbuf) { - if (status == TP_CONN_STATUS_DISCONNECTED || - (status == TP_CONN_STATUS_CONNECTING && - !dialog->connecting_show)) { - GdkPixbuf *modded_pixbuf; - - modded_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, - TRUE, - 8, - gdk_pixbuf_get_width (pixbuf), - gdk_pixbuf_get_height (pixbuf)); - - gdk_pixbuf_saturate_and_pixelate (pixbuf, - modded_pixbuf, - 1.0, - TRUE); - g_object_unref (pixbuf); - pixbuf = modded_pixbuf; - } - } - - g_object_set (cell, - "visible", TRUE, - "pixbuf", pixbuf, - NULL); - - g_object_unref (account); - if (pixbuf) { - g_object_unref (pixbuf); - } -} - -static McAccount * -accounts_dialog_model_get_selected (GossipAccountsDialog *dialog) -{ - GtkTreeView *view; - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - McAccount *account; - - view = GTK_TREE_VIEW (dialog->treeview); - selection = gtk_tree_view_get_selection (view); - - if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { - return NULL; - } - - gtk_tree_model_get (model, &iter, COL_ACCOUNT_POINTER, &account, -1); - - return account; -} - -static void -accounts_dialog_model_set_selected (GossipAccountsDialog *dialog, - McAccount *account) -{ - GtkTreeView *view; - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeIter iter; - gboolean ok; - - view = GTK_TREE_VIEW (dialog->treeview); - model = gtk_tree_view_get_model (view); - selection = gtk_tree_view_get_selection (view); - - for (ok = gtk_tree_model_get_iter_first (model, &iter); - ok; - ok = gtk_tree_model_iter_next (model, &iter)) { - McAccount *this_account; - gboolean equal; - - gtk_tree_model_get (model, &iter, - COL_ACCOUNT_POINTER, &this_account, - -1); - - equal = gossip_account_equal (this_account, account); - g_object_unref (this_account); - - if (equal) { - gtk_tree_selection_select_iter (selection, &iter); - break; - } - } -} - -static gboolean -accounts_dialog_model_remove_selected (GossipAccountsDialog *dialog) -{ - GtkTreeView *view; - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - - view = GTK_TREE_VIEW (dialog->treeview); - selection = gtk_tree_view_get_selection (view); - - if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { - return FALSE; - } - - return gtk_list_store_remove (GTK_LIST_STORE (model), &iter); -} - -static void -accounts_dialog_model_selection_changed (GtkTreeSelection *selection, - GossipAccountsDialog *dialog) -{ - McAccount *account; - GtkTreeModel *model; - GtkTreeIter iter; - gboolean is_selection; - - is_selection = gtk_tree_selection_get_selected (selection, &model, &iter); - - gtk_widget_set_sensitive (dialog->button_remove, is_selection); - gtk_widget_set_sensitive (dialog->button_connect, is_selection); - - accounts_dialog_update_connect_button (dialog); - - account = accounts_dialog_model_get_selected (dialog); - accounts_dialog_update_account (dialog, account); - - if (account) { - g_object_unref (account); - } -} - -static void -accounts_dialog_add_account (GossipAccountsDialog *dialog, - McAccount *account) -{ - TelepathyConnectionStatus status; - const gchar *name; - GtkTreeView *view; - GtkTreeModel *model; - GtkListStore *store; - GtkTreeIter iter; - gboolean ok; - - view = GTK_TREE_VIEW (dialog->treeview); - model = gtk_tree_view_get_model (view); - store = GTK_LIST_STORE (model); - - for (ok = gtk_tree_model_get_iter_first (model, &iter); - ok; - ok = gtk_tree_model_iter_next (model, &iter)) { - McAccount *this_account; - gboolean equal; - - gtk_tree_model_get (model, &iter, - COL_ACCOUNT_POINTER, &this_account, - -1); - - equal = gossip_account_equal (this_account, account); - g_object_unref (this_account); - - if (equal) { - return; - } - } - - status = mission_control_get_connection_status (dialog->mc, account, NULL); - name = mc_account_get_display_name (account); - - g_return_if_fail (name != NULL); - - gossip_debug (DEBUG_DOMAIN, "Adding new account: %s", name); - - gtk_list_store_insert_with_values (store, &iter, - -1, - COL_NAME, name, - COL_STATUS, status, - COL_ACCOUNT_POINTER, account, - -1); -} - -static void -accounts_dialog_account_added_cb (McAccountMonitor *monitor, - gchar *unique_name, - GossipAccountsDialog *dialog) -{ - McAccount *account; - - account = mc_account_lookup (unique_name); - accounts_dialog_add_account (dialog, account); - g_object_unref (account); -} - -static void -accounts_dialog_account_removed_cb (McAccountMonitor *monitor, - gchar *unique_name, - GossipAccountsDialog *dialog) -{ - McAccount *account; - - account = mc_account_lookup (unique_name); - - accounts_dialog_model_set_selected (dialog, account); - accounts_dialog_model_remove_selected (dialog); - - g_object_unref (account); -} - -static gboolean -accounts_dialog_row_changed_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gpointer user_data) -{ - gtk_tree_model_row_changed (model, path, iter); - - return FALSE; -} - -static gboolean -accounts_dialog_flash_connecting_cb (GossipAccountsDialog *dialog) -{ - GtkTreeView *view; - GtkTreeModel *model; - - dialog->connecting_show = !dialog->connecting_show; - - view = GTK_TREE_VIEW (dialog->treeview); - model = gtk_tree_view_get_model (view); - - gtk_tree_model_foreach (model, accounts_dialog_row_changed_foreach, NULL); - - return TRUE; -} - -static void -accounts_dialog_status_changed_cb (MissionControl *mc, - TelepathyConnectionStatus status, - McPresence presence, - TelepathyConnectionStatusReason reason, - const gchar *unique_name, - GossipAccountsDialog *dialog) -{ - GtkTreeView *view; - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeIter iter; - gboolean ok; - McAccount *account; - GList *accounts, *l; - gboolean found = FALSE; - - /* Update the status in the model */ - view = GTK_TREE_VIEW (dialog->treeview); - selection = gtk_tree_view_get_selection (view); - model = gtk_tree_view_get_model (view); - account = mc_account_lookup (unique_name); - - gossip_debug (DEBUG_DOMAIN, "Status changed for account %s: " - "status=%d presence=%d", - unique_name, status, presence); - - for (ok = gtk_tree_model_get_iter_first (model, &iter); - ok; - ok = gtk_tree_model_iter_next (model, &iter)) { - McAccount *this_account; - gboolean equal; - - gtk_tree_model_get (model, &iter, - COL_ACCOUNT_POINTER, &this_account, - -1); - - equal = gossip_account_equal (this_account, account); - g_object_unref (this_account); - - if (equal) { - GtkTreePath *path; - - gtk_list_store_set (GTK_LIST_STORE (model), &iter, - COL_STATUS, status, - -1); - - path = gtk_tree_model_get_path (model, &iter); - gtk_tree_model_row_changed (model, path, &iter); - gtk_tree_path_free (path); - - break; - } - } - - g_object_unref (account); - - /* Start to flash account if status is connecting */ - if (status == TP_CONN_STATUS_CONNECTING) { - if (!dialog->connecting_id) { - dialog->connecting_id = g_timeout_add (FLASH_TIMEOUT, - (GSourceFunc) accounts_dialog_flash_connecting_cb, - dialog); - } - - return; - } - - /* Stop to flash if no account is connecting */ - accounts = mc_accounts_list (); - for (l = accounts; l; l = l->next) { - McAccount *this_account; - - this_account = l->data; - - if (mission_control_get_connection_status (mc, this_account, NULL) == TP_CONN_STATUS_CONNECTING) { - found = TRUE; - break; - } - - g_object_unref (this_account); - } - g_list_free (accounts); - - if (!found && dialog->connecting_id) { - g_source_remove (dialog->connecting_id); - dialog->connecting_id = 0; - } - - gtk_widget_show (dialog->window); -} - -static void -accounts_dialog_entry_name_changed_cb (GtkWidget *widget, - GossipAccountsDialog *dialog) -{ - const gchar *str; - - str = gtk_entry_get_text (GTK_ENTRY (widget)); - gtk_widget_set_sensitive (dialog->button_create, !G_STR_EMPTY (str)); -} - -static void -accounts_dialog_button_create_clicked_cb (GtkWidget *button, - GossipAccountsDialog *dialog) -{ - McProfile *profile; - McAccount *account; - const gchar *str; - - /* Update widgets */ - gtk_widget_show (dialog->vbox_details); - gtk_widget_hide (dialog->frame_no_account); - gtk_widget_hide (dialog->frame_new_account); - - profile = gossip_profile_chooser_get_selected (dialog->combobox_profile); - - /* Create account */ - account = mc_account_create (profile); - - str = gtk_entry_get_text (GTK_ENTRY (dialog->entry_name)); - mc_account_set_display_name (account, str); - - accounts_dialog_add_account (dialog, account); - accounts_dialog_model_set_selected (dialog, account); - - g_object_unref (account); - g_object_unref (profile); -} - -static void -accounts_dialog_button_back_clicked_cb (GtkWidget *button, - GossipAccountsDialog *dialog) -{ - McAccount *account; - - gtk_widget_hide (dialog->vbox_details); - gtk_widget_hide (dialog->frame_no_account); - gtk_widget_hide (dialog->frame_new_account); - - account = accounts_dialog_model_get_selected (dialog); - accounts_dialog_update_account (dialog, account); -} - -static void -accounts_dialog_button_connect_clicked_cb (GtkWidget *button, - GossipAccountsDialog *dialog) -{ - McAccount *account; - gboolean enable; - - account = accounts_dialog_model_get_selected (dialog); - enable = (!mc_account_is_enabled (account)); - mc_account_set_enabled (account, enable); - accounts_dialog_update_connect_button (dialog); - - g_object_unref (account); -} - -static void -accounts_dialog_button_add_clicked_cb (GtkWidget *button, - GossipAccountsDialog *dialog) -{ - gtk_widget_hide (dialog->vbox_details); - gtk_widget_hide (dialog->frame_no_account); - gtk_widget_show (dialog->frame_new_account); - - gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->combobox_profile), 0); - gtk_entry_set_text (GTK_ENTRY (dialog->entry_name), ""); - gtk_widget_grab_focus (dialog->entry_name); -} - -static void -accounts_dialog_remove_response_cb (GtkWidget *dialog, - gint response, - McAccount *account) -{ - if (response == GTK_RESPONSE_YES) { - mc_account_delete (account); - } - - gtk_widget_destroy (dialog); -} - -static void -accounts_dialog_button_remove_clicked_cb (GtkWidget *button, - GossipAccountsDialog *dialog) -{ - McAccount *account; - GtkWidget *message_dialog; - - account = accounts_dialog_model_get_selected (dialog); - - if (!mc_account_is_complete (account)) { - accounts_dialog_model_remove_selected (dialog); - return; - } - message_dialog = gtk_message_dialog_new - (GTK_WINDOW (dialog->window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_NONE, - _("You are about to remove your %s account!\n" - "Are you sure you want to proceed?"), - mc_account_get_display_name (account)); - - gtk_message_dialog_format_secondary_text - (GTK_MESSAGE_DIALOG (message_dialog), - _("Any associated conversations and chat rooms will NOT be " - "removed if you decide to proceed.\n" - "\n" - "Should you decide to add the account back at a later time, " - "they will still be available.")); - - gtk_dialog_add_button (GTK_DIALOG (message_dialog), - GTK_STOCK_CANCEL, - GTK_RESPONSE_NO); - gtk_dialog_add_button (GTK_DIALOG (message_dialog), - GTK_STOCK_REMOVE, - GTK_RESPONSE_YES); - - g_signal_connect (message_dialog, "response", - G_CALLBACK (accounts_dialog_remove_response_cb), - account); - - gtk_widget_show (message_dialog); -} - -static void -accounts_dialog_treeview_row_activated_cb (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - GossipAccountsDialog *dialog) -{ - - accounts_dialog_button_connect_clicked_cb (dialog->button_connect, - dialog); -} - -static void -accounts_dialog_response_cb (GtkWidget *widget, - gint response, - GossipAccountsDialog *dialog) -{ - gtk_widget_destroy (widget); -} - -static void -accounts_dialog_destroy_cb (GtkWidget *widget, - GossipAccountsDialog *dialog) -{ - GList *accounts, *l; - - /* Disconnect signals */ - g_signal_handlers_disconnect_by_func (dialog->monitor, - accounts_dialog_account_added_cb, - dialog); - g_signal_handlers_disconnect_by_func (dialog->monitor, - accounts_dialog_account_removed_cb, - dialog); - dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (dialog->mc), - "AccountStatusChanged", - G_CALLBACK (accounts_dialog_status_changed_cb), - dialog); - - /* Delete incomplete accounts */ - accounts = mc_accounts_list (); - for (l = accounts; l; l = l->next) { - McAccount *account; - - account = l->data; - if (!mc_account_is_complete (account)) { - /* FIXME: Warn the user the account is not complete - * and is going to be removed. */ - mc_account_delete (account); - } - - g_object_unref (account); - } - g_list_free (accounts); - - if (dialog->connecting_id) { - g_source_remove (dialog->connecting_id); - } - - g_object_unref (dialog->mc); - g_object_unref (dialog->monitor); - - g_free (dialog); -} - -GtkWidget * -gossip_accounts_dialog_show (GtkWindow *parent) -{ - static GossipAccountsDialog *dialog = NULL; - GladeXML *glade; - GtkWidget *bbox; - GtkWidget *button_close; - - if (dialog) { - gtk_window_present (GTK_WINDOW (dialog->window)); - return dialog->window; - } - - dialog = g_new0 (GossipAccountsDialog, 1); - - glade = gossip_glade_get_file ("gossip-accounts-dialog.glade", - "accounts_dialog", - NULL, - "accounts_dialog", &dialog->window, - "vbox_details", &dialog->vbox_details, - "frame_no_account", &dialog->frame_no_account, - "label_no_account", &dialog->label_no_account, - "label_no_account_blurb", &dialog->label_no_account_blurb, - "alignment_settings", &dialog->alignment_settings, - "dialog-action_area", &bbox, - "treeview", &dialog->treeview, - "frame_new_account", &dialog->frame_new_account, - "entry_name", &dialog->entry_name, - "table_new_account", &dialog->table_new_account, - "button_create", &dialog->button_create, - "button_back", &dialog->button_back, - "image_type", &dialog->image_type, - "label_type", &dialog->label_type, - "label_name", &dialog->label_name, - "button_remove", &dialog->button_remove, - "button_connect", &dialog->button_connect, - "button_close", &button_close, - NULL); - - gossip_glade_connect (glade, - dialog, - "accounts_dialog", "destroy", accounts_dialog_destroy_cb, - "accounts_dialog", "response", accounts_dialog_response_cb, - "button_create", "clicked", accounts_dialog_button_create_clicked_cb, - "button_back", "clicked", accounts_dialog_button_back_clicked_cb, - "entry_name", "changed", accounts_dialog_entry_name_changed_cb, - "treeview", "row-activated", accounts_dialog_treeview_row_activated_cb, - "button_connect", "clicked", accounts_dialog_button_connect_clicked_cb, - "button_add", "clicked", accounts_dialog_button_add_clicked_cb, - "button_remove", "clicked", accounts_dialog_button_remove_clicked_cb, - NULL); - - g_object_add_weak_pointer (G_OBJECT (dialog->window), (gpointer) &dialog); - - g_object_unref (glade); - - /* Create profile chooser */ - dialog->combobox_profile = gossip_profile_chooser_new (); - gtk_table_attach_defaults (GTK_TABLE (dialog->table_new_account), - dialog->combobox_profile, - 1, 2, - 0, 1); - gtk_widget_show (dialog->combobox_profile); - - /* Set up signalling */ - dialog->mc = gossip_mission_control_new (); - dialog->monitor = mc_account_monitor_new (); - - /* FIXME: connect account-enabled/disabled too */ - g_signal_connect (dialog->monitor, "account-created", - G_CALLBACK (accounts_dialog_account_added_cb), - dialog); - g_signal_connect (dialog->monitor, "account-deleted", - G_CALLBACK (accounts_dialog_account_removed_cb), - dialog); - dbus_g_proxy_connect_signal (DBUS_G_PROXY (dialog->mc), "AccountStatusChanged", - G_CALLBACK (accounts_dialog_status_changed_cb), - dialog, NULL); - - accounts_dialog_model_setup (dialog); - accounts_dialog_setup (dialog); - accounts_dialog_model_select_first (dialog); - - if (parent) { - gtk_window_set_transient_for (GTK_WINDOW (dialog->window), - GTK_WINDOW (parent)); - } - - gtk_widget_show (dialog->window); - - return dialog->window; -} - diff --git a/libempathy-gtk/gossip-accounts-dialog.glade b/libempathy-gtk/gossip-accounts-dialog.glade deleted file mode 100644 index 05ba64f8..00000000 --- a/libempathy-gtk/gossip-accounts-dialog.glade +++ /dev/null @@ -1,757 +0,0 @@ - - - - - - - 5 - Accounts - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - False - False - - - - True - False - 2 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-close - True - GTK_RELIEF_NORMAL - True - -6 - - - - - 0 - False - True - GTK_PACK_END - - - - - - 6 - True - False - 18 - - - - True - False - 6 - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - 200 - True - True - True - False - False - False - False - False - False - - - - - 0 - True - True - - - - - - True - False - 6 - - - - True - True - gtk-connect - False - GTK_RELIEF_NORMAL - True - - - 0 - False - False - - - - - - True - True - 6 - - - - True - True - gtk-add - True - GTK_RELIEF_NORMAL - True - - - 0 - True - True - - - - - - True - True - gtk-remove - True - GTK_RELIEF_NORMAL - True - - - 0 - True - True - - - - - 0 - True - True - - - - - 0 - False - False - - - - - 0 - False - False - - - - - - 415 - True - False - 18 - - - - True - False - 18 - - - - True - 0 - 0.5 - GTK_SHADOW_NONE - - - - True - 0.5 - 0.5 - 1 - 1 - 6 - 0 - 20 - 0 - - - - True - False - 6 - - - - True - 2 - 2 - False - 6 - 6 - - - - True - gtk-cut - 6 - 0.5 - 0 - 0 - 0 - - - 1 - 2 - 0 - 2 - - - - - - - - True - Imendio - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - 0 - False - 0 - - - 0 - 1 - 1 - 2 - - - - - - - True - Jabber - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 0 - 1 - - - - - - 0 - True - True - - - - - - - - - - True - <b>Account</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - label_item - - - - - 0 - False - False - - - - - - True - 0 - 0.5 - GTK_SHADOW_NONE - - - - True - 0.5 - 0.5 - 1 - 1 - 6 - 0 - 20 - 0 - - - - - - - - - - True - <b>Settings</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - label_item - - - - - 0 - True - True - - - - - 0 - True - True - - - - - - 0 - 0.5 - GTK_SHADOW_NONE - - - - True - 0.5 - 0.5 - 1 - 1 - 6 - 0 - 20 - 0 - - - - True - False - 12 - - - - True - 2 - 2 - False - 6 - 6 - - - - True - _Type: - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 0 - 1 - - - - - - - - True - _Name: - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - entry_name - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 1 - 2 - - - - - - - - True - A unique name for this account to identify it personally to you. - True - True - True - 0 - - True - * - False - - - 1 - 2 - 1 - 2 - - - - - - 0 - True - True - - - - - - True - False - 6 - - - - True - False - True - GTK_RELIEF_NORMAL - True - - - - True - 0.5 - 0.5 - 0 - 0 - 0 - 0 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-new - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - Cr_eate - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - - - - 0 - False - False - GTK_PACK_END - - - - - - True - True - gtk-go-back - True - GTK_RELIEF_NORMAL - True - - - 0 - False - False - GTK_PACK_END - - - - - 0 - False - False - GTK_PACK_END - - - - - - - - - - True - <b>New Account</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - label_item - - - - - 0 - False - True - - - - - - 0 - 0.5 - GTK_SHADOW_NONE - - - - True - 0.5 - 0.5 - 1 - 1 - 6 - 0 - 12 - 0 - - - - True - To add a new account, you can click on the 'Add' button and a new entry will be created for you to started configuring. - -If you do not want to add an account, simply click on the account you want to configure in the list on the left. - False - True - GTK_JUSTIFY_LEFT - True - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - - True - <b>No Account Selected</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - label_item - - - - - 0 - False - False - - - - - 0 - True - True - - - - - 0 - True - True - - - - - - - diff --git a/libempathy-gtk/gossip-accounts-dialog.h b/libempathy-gtk/gossip-accounts-dialog.h deleted file mode 100644 index 5b058e6a..00000000 --- a/libempathy-gtk/gossip-accounts-dialog.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2005-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Martyn Russell - */ - -#ifndef __GOSSIP_ACCOUNTS_DIALOG_H__ -#define __GOSSIP_ACCOUNTS_DIALOG_H__ - -#include - -G_BEGIN_DECLS - -GtkWidget *gossip_accounts_dialog_show (GtkWindow *parent); - -G_END_DECLS - -#endif /* __GOSSIP_ACCOUNTS_DIALOG_H__ */ diff --git a/libempathy-gtk/gossip-cell-renderer-expander.c b/libempathy-gtk/gossip-cell-renderer-expander.c deleted file mode 100644 index e116ace7..00000000 --- a/libempathy-gtk/gossip-cell-renderer-expander.c +++ /dev/null @@ -1,482 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Kristian Rietveld - */ - -/* To do: - * - should probably cancel animation if model changes - * - need to handle case where node-in-animation is removed - * - it only handles a single animation at a time; but I guess users - * aren't fast enough to trigger two or more animations at once anyway :P - * (could guard for this by just cancelling the "old" animation, and - * start the new one). - */ - -#include - -#include "gossip-cell-renderer-expander.h" - -#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CELL_RENDERER_EXPANDER, GossipCellRendererExpanderPriv)) - -static void gossip_cell_renderer_expander_init (GossipCellRendererExpander *expander); -static void gossip_cell_renderer_expander_class_init (GossipCellRendererExpanderClass *klass); -static void gossip_cell_renderer_expander_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec); -static void gossip_cell_renderer_expander_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec); -static void gossip_cell_renderer_expander_finalize (GObject *object); -static void gossip_cell_renderer_expander_get_size (GtkCellRenderer *cell, - GtkWidget *widget, - GdkRectangle *cell_area, - gint *x_offset, - gint *y_offset, - gint *width, - gint *height); -static void gossip_cell_renderer_expander_render (GtkCellRenderer *cell, - GdkWindow *window, - GtkWidget *widget, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GdkRectangle *expose_area, - GtkCellRendererState flags); -static gboolean gossip_cell_renderer_expander_activate (GtkCellRenderer *cell, - GdkEvent *event, - GtkWidget *widget, - const gchar *path, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GtkCellRendererState flags); - -enum { - PROP_0, - PROP_EXPANDER_STYLE, - PROP_EXPANDER_SIZE, - PROP_ACTIVATABLE -}; - -typedef struct _GossipCellRendererExpanderPriv GossipCellRendererExpanderPriv; - -struct _GossipCellRendererExpanderPriv { - GtkExpanderStyle expander_style; - gint expander_size; - - GtkTreeView *animation_view; - GtkTreeRowReference *animation_node; - GtkExpanderStyle animation_style; - guint animation_timeout; - GdkRectangle animation_area; - - guint activatable : 1; - guint animation_expanding : 1; -}; - -G_DEFINE_TYPE (GossipCellRendererExpander, gossip_cell_renderer_expander, GTK_TYPE_CELL_RENDERER) - -static void -gossip_cell_renderer_expander_init (GossipCellRendererExpander *expander) -{ - GossipCellRendererExpanderPriv *priv; - - priv = GET_PRIV (expander); - - priv->expander_style = GTK_EXPANDER_COLLAPSED; - priv->expander_size = 12; - priv->activatable = TRUE; - priv->animation_node = NULL; - - GTK_CELL_RENDERER (expander)->xpad = 2; - GTK_CELL_RENDERER (expander)->ypad = 2; - GTK_CELL_RENDERER (expander)->mode = GTK_CELL_RENDERER_MODE_ACTIVATABLE; -} - -static void -gossip_cell_renderer_expander_class_init (GossipCellRendererExpanderClass *klass) -{ - GObjectClass *object_class; - GtkCellRendererClass *cell_class; - - object_class = G_OBJECT_CLASS (klass); - cell_class = GTK_CELL_RENDERER_CLASS (klass); - - object_class->finalize = gossip_cell_renderer_expander_finalize; - - object_class->get_property = gossip_cell_renderer_expander_get_property; - object_class->set_property = gossip_cell_renderer_expander_set_property; - - cell_class->get_size = gossip_cell_renderer_expander_get_size; - cell_class->render = gossip_cell_renderer_expander_render; - cell_class->activate = gossip_cell_renderer_expander_activate; - - g_object_class_install_property (object_class, - PROP_EXPANDER_STYLE, - g_param_spec_enum ("expander-style", - "Expander Style", - "Style to use when painting the expander", - GTK_TYPE_EXPANDER_STYLE, - GTK_EXPANDER_COLLAPSED, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_EXPANDER_SIZE, - g_param_spec_int ("expander-size", - "Expander Size", - "The size of the expander", - 0, - G_MAXINT, - 12, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_ACTIVATABLE, - g_param_spec_boolean ("activatable", - "Activatable", - "The expander can be activated", - TRUE, - G_PARAM_READWRITE)); - - g_type_class_add_private (object_class, sizeof (GossipCellRendererExpanderPriv)); -} - -static void -gossip_cell_renderer_expander_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec) -{ - GossipCellRendererExpander *expander; - GossipCellRendererExpanderPriv *priv; - - expander = GOSSIP_CELL_RENDERER_EXPANDER (object); - priv = GET_PRIV (expander); - - switch (param_id) { - case PROP_EXPANDER_STYLE: - g_value_set_enum (value, priv->expander_style); - break; - - case PROP_EXPANDER_SIZE: - g_value_set_int (value, priv->expander_size); - break; - - case PROP_ACTIVATABLE: - g_value_set_boolean (value, priv->activatable); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - } -} - -static void -gossip_cell_renderer_expander_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec) -{ - GossipCellRendererExpander *expander; - GossipCellRendererExpanderPriv *priv; - - expander = GOSSIP_CELL_RENDERER_EXPANDER (object); - priv = GET_PRIV (expander); - - switch (param_id) { - case PROP_EXPANDER_STYLE: - priv->expander_style = g_value_get_enum (value); - break; - - case PROP_EXPANDER_SIZE: - priv->expander_size = g_value_get_int (value); - break; - - case PROP_ACTIVATABLE: - priv->activatable = g_value_get_boolean (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - } -} - -static void -gossip_cell_renderer_expander_finalize (GObject *object) -{ - GossipCellRendererExpanderPriv *priv; - - priv = GET_PRIV (object); - - if (priv->animation_timeout) { - g_source_remove (priv->animation_timeout); - priv->animation_timeout = 0; - } - - if (priv->animation_node) { - gtk_tree_row_reference_free (priv->animation_node); - } - - (* G_OBJECT_CLASS (gossip_cell_renderer_expander_parent_class)->finalize) (object); -} - -GtkCellRenderer * -gossip_cell_renderer_expander_new (void) -{ - return g_object_new (GOSSIP_TYPE_CELL_RENDERER_EXPANDER, NULL); -} - -static void -gossip_cell_renderer_expander_get_size (GtkCellRenderer *cell, - GtkWidget *widget, - GdkRectangle *cell_area, - gint *x_offset, - gint *y_offset, - gint *width, - gint *height) -{ - GossipCellRendererExpander *expander; - GossipCellRendererExpanderPriv *priv; - - expander = (GossipCellRendererExpander*) cell; - priv = GET_PRIV (expander); - - if (cell_area) { - if (x_offset) { - *x_offset = cell->xalign * (cell_area->width - (priv->expander_size + (2 * cell->xpad))); - *x_offset = MAX (*x_offset, 0); - } - - if (y_offset) { - *y_offset = cell->yalign * (cell_area->height - (priv->expander_size + (2 * cell->ypad))); - *y_offset = MAX (*y_offset, 0); - } - } else { - if (x_offset) - *x_offset = 0; - - if (y_offset) - *y_offset = 0; - } - - if (width) - *width = cell->xpad * 2 + priv->expander_size; - - if (height) - *height = cell->ypad * 2 + priv->expander_size; -} - -static void -gossip_cell_renderer_expander_render (GtkCellRenderer *cell, - GdkWindow *window, - GtkWidget *widget, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GdkRectangle *expose_area, - GtkCellRendererState flags) -{ - GossipCellRendererExpander *expander; - GossipCellRendererExpanderPriv *priv; - GtkExpanderStyle expander_style; - gint x_offset, y_offset; - - expander = (GossipCellRendererExpander*) cell; - priv = GET_PRIV (expander); - - if (priv->animation_node) { - GtkTreePath *path; - GdkRectangle rect; - - /* Not sure if I like this ... */ - path = gtk_tree_row_reference_get_path (priv->animation_node); - gtk_tree_view_get_background_area (priv->animation_view, path, - NULL, &rect); - gtk_tree_path_free (path); - - if (background_area->y == rect.y) - expander_style = priv->animation_style; - else - expander_style = priv->expander_style; - } else - expander_style = priv->expander_style; - - gossip_cell_renderer_expander_get_size (cell, widget, cell_area, - &x_offset, &y_offset, - NULL, NULL); - - gtk_paint_expander (widget->style, - window, - GTK_STATE_NORMAL, - expose_area, - widget, - "treeview", - cell_area->x + x_offset + cell->xpad + priv->expander_size / 2, - cell_area->y + y_offset + cell->ypad + priv->expander_size / 2, - expander_style); -} - -static void -invalidate_node (GtkTreeView *tree_view, - GtkTreePath *path) -{ - GdkWindow *bin_window; - GdkRectangle rect; - - bin_window = gtk_tree_view_get_bin_window (tree_view); - - gtk_tree_view_get_background_area (tree_view, path, NULL, &rect); - - rect.x = 0; - rect.width = GTK_WIDGET (tree_view)->allocation.width; - - gdk_window_invalidate_rect (bin_window, &rect, TRUE); -} - -static gboolean -do_animation (GossipCellRendererExpander *expander) -{ - GossipCellRendererExpanderPriv *priv; - GtkTreePath *path; - gboolean done = FALSE; - - priv = GET_PRIV (expander); - - if (priv->animation_expanding) { - if (priv->animation_style == GTK_EXPANDER_SEMI_COLLAPSED) - priv->animation_style = GTK_EXPANDER_SEMI_EXPANDED; - else if (priv->animation_style == GTK_EXPANDER_SEMI_EXPANDED) { - priv->animation_style = GTK_EXPANDER_EXPANDED; - done = TRUE; - } - } else { - if (priv->animation_style == GTK_EXPANDER_SEMI_EXPANDED) - priv->animation_style = GTK_EXPANDER_SEMI_COLLAPSED; - else if (priv->animation_style == GTK_EXPANDER_SEMI_COLLAPSED) { - priv->animation_style = GTK_EXPANDER_COLLAPSED; - done = TRUE; - } - } - - path = gtk_tree_row_reference_get_path (priv->animation_node); - invalidate_node (priv->animation_view, path); - gtk_tree_path_free (path); - - if (done) { - gtk_tree_row_reference_free (priv->animation_node); - priv->animation_node = NULL; - priv->animation_timeout = 0; - } - - return !done; -} - -static gboolean -animation_timeout (gpointer data) -{ - gboolean retval; - - GDK_THREADS_ENTER (); - - retval = do_animation (data); - - GDK_THREADS_LEAVE (); - - return retval; -} - -static void -gossip_cell_renderer_expander_start_animation (GossipCellRendererExpander *expander, - GtkTreeView *tree_view, - GtkTreePath *path, - gboolean expanding, - GdkRectangle *background_area) -{ - GossipCellRendererExpanderPriv *priv; - - priv = GET_PRIV (expander); - - if (expanding) { - priv->animation_style = GTK_EXPANDER_SEMI_COLLAPSED; - } else { - priv->animation_style = GTK_EXPANDER_SEMI_EXPANDED; - } - - invalidate_node (tree_view, path); - - priv->animation_expanding = expanding; - priv->animation_view = tree_view; - priv->animation_node = gtk_tree_row_reference_new (gtk_tree_view_get_model (tree_view), path); - priv->animation_timeout = g_timeout_add (50, animation_timeout, expander); -} - -static gboolean -gossip_cell_renderer_expander_activate (GtkCellRenderer *cell, - GdkEvent *event, - GtkWidget *widget, - const gchar *path_string, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GtkCellRendererState flags) -{ - GossipCellRendererExpander *expander; - GossipCellRendererExpanderPriv *priv; - GtkTreePath *path; - gboolean animate; - gboolean expanding; - - expander = GOSSIP_CELL_RENDERER_EXPANDER (cell); - priv = GET_PRIV (cell); - - if (!GTK_IS_TREE_VIEW (widget) || !priv->activatable) - return FALSE; - - path = gtk_tree_path_new_from_string (path_string); - - if (gtk_tree_path_get_depth (path) > 1) { - gtk_tree_path_free (path); - return TRUE; - } - - g_object_get (gtk_widget_get_settings (GTK_WIDGET (widget)), - "gtk-enable-animations", &animate, - NULL); - - if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (widget), path)) { - gtk_tree_view_collapse_row (GTK_TREE_VIEW (widget), path); - expanding = FALSE; - } else { - gtk_tree_view_expand_row (GTK_TREE_VIEW (widget), path, FALSE); - expanding = TRUE; - } - - if (animate) { - gossip_cell_renderer_expander_start_animation (expander, - GTK_TREE_VIEW (widget), - path, - expanding, - background_area); - } - - gtk_tree_path_free (path); - - return TRUE; -} diff --git a/libempathy-gtk/gossip-cell-renderer-expander.h b/libempathy-gtk/gossip-cell-renderer-expander.h deleted file mode 100644 index 7df47466..00000000 --- a/libempathy-gtk/gossip-cell-renderer-expander.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Kristian Rietveld - */ - -#ifndef __GOSSIP_CELL_RENDERER_EXPANDER_H__ -#define __GOSSIP_CELL_RENDERER_EXPANDER_H__ - -#include - -G_BEGIN_DECLS - -#define GOSSIP_TYPE_CELL_RENDERER_EXPANDER (gossip_cell_renderer_expander_get_type ()) -#define GOSSIP_CELL_RENDERER_EXPANDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GOSSIP_TYPE_CELL_RENDERER_EXPANDER, GossipCellRendererExpander)) -#define GOSSIP_CELL_RENDERER_EXPANDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GOSSIP_TYPE_CELL_RENDERER_EXPANDER, GossipCellRendererExpanderClass)) -#define GOSSIP_IS_CELL_RENDERER_EXPANDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GOSSIP_TYPE_CELL_RENDERER_EXPANDER)) -#define GOSSIP_IS_CELL_RENDERER_EXPANDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GOSSIP_TYPE_CELL_RENDERER_EXPANDER)) -#define GOSSIP_CELL_RENDERER_EXPANDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GOSSIP_TYPE_CELL_RENDERER_EXPANDER, GossipCellRendererExpanderClass)) - -typedef struct _GossipCellRendererExpander GossipCellRendererExpander; -typedef struct _GossipCellRendererExpanderClass GossipCellRendererExpanderClass; - -struct _GossipCellRendererExpander { - GtkCellRenderer parent; -}; - -struct _GossipCellRendererExpanderClass { - GtkCellRendererClass parent_class; - - /* Padding for future expansion */ - void (*_gtk_reserved1) (void); - void (*_gtk_reserved2) (void); - void (*_gtk_reserved3) (void); - void (*_gtk_reserved4) (void); -}; - -GType gossip_cell_renderer_expander_get_type (void) G_GNUC_CONST; -GtkCellRenderer *gossip_cell_renderer_expander_new (void); - -G_END_DECLS - -#endif /* __GOSSIP_CELL_RENDERER_EXPANDER_H__ */ diff --git a/libempathy-gtk/gossip-cell-renderer-text.c b/libempathy-gtk/gossip-cell-renderer-text.c deleted file mode 100644 index 2b54eedf..00000000 --- a/libempathy-gtk/gossip-cell-renderer-text.c +++ /dev/null @@ -1,368 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2004-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - */ - -#include "config.h" - -#include - -#include "gossip-cell-renderer-text.h" - -#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CELL_RENDERER_TEXT, GossipCellRendererTextPriv)) - -struct _GossipCellRendererTextPriv { - gchar *name; - gchar *status; - gboolean is_group; - - gboolean is_valid; - gboolean is_selected; - - gboolean show_status; -}; - -static void gossip_cell_renderer_text_class_init (GossipCellRendererTextClass *klass); -static void gossip_cell_renderer_text_init (GossipCellRendererText *cell); -static void cell_renderer_text_finalize (GObject *object); -static void cell_renderer_text_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec); -static void cell_renderer_text_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec); -static void cell_renderer_text_get_size (GtkCellRenderer *cell, - GtkWidget *widget, - GdkRectangle *cell_area, - gint *x_offset, - gint *y_offset, - gint *width, - gint *height); -static void cell_renderer_text_render (GtkCellRenderer *cell, - GdkDrawable *window, - GtkWidget *widget, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GdkRectangle *expose_area, - GtkCellRendererState flags); -static void cell_renderer_text_update_text (GossipCellRendererText *cell, - GtkWidget *widget, - gboolean selected); - -/* Properties */ -enum { - PROP_0, - PROP_NAME, - PROP_STATUS, - PROP_IS_GROUP, - PROP_SHOW_STATUS, -}; - -G_DEFINE_TYPE (GossipCellRendererText, gossip_cell_renderer_text, GTK_TYPE_CELL_RENDERER_TEXT); - -static void -gossip_cell_renderer_text_class_init (GossipCellRendererTextClass *klass) -{ - GObjectClass *object_class; - GtkCellRendererClass *cell_class; - - object_class = G_OBJECT_CLASS (klass); - cell_class = GTK_CELL_RENDERER_CLASS (klass); - - object_class->finalize = cell_renderer_text_finalize; - - object_class->get_property = cell_renderer_text_get_property; - object_class->set_property = cell_renderer_text_set_property; - - cell_class->get_size = cell_renderer_text_get_size; - cell_class->render = cell_renderer_text_render; - - g_object_class_install_property (object_class, - PROP_NAME, - g_param_spec_string ("name", - "Name", - "Contact name", - NULL, - G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_STATUS, - g_param_spec_string ("status", - "Status", - "Contact status string", - NULL, - G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_IS_GROUP, - g_param_spec_boolean ("is_group", - "Is group", - "Whether this cell is a group", - FALSE, - G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_SHOW_STATUS, - g_param_spec_boolean ("show-status", - "Show status", - "Whether to show the status line", - TRUE, - G_PARAM_READWRITE)); - - g_type_class_add_private (object_class, sizeof (GossipCellRendererTextPriv)); -} - -static void -gossip_cell_renderer_text_init (GossipCellRendererText *cell) -{ - GossipCellRendererTextPriv *priv; - - priv = GET_PRIV (cell); - - g_object_set (cell, - "ellipsize", PANGO_ELLIPSIZE_END, - NULL); - - priv->name = g_strdup (""); - priv->status = g_strdup (""); - priv->show_status = TRUE; -} - -static void -cell_renderer_text_finalize (GObject *object) -{ - GossipCellRendererText *cell; - GossipCellRendererTextPriv *priv; - - cell = GOSSIP_CELL_RENDERER_TEXT (object); - priv = GET_PRIV (cell); - - g_free (priv->name); - g_free (priv->status); - - (G_OBJECT_CLASS (gossip_cell_renderer_text_parent_class)->finalize) (object); -} - -static void -cell_renderer_text_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec) -{ - GossipCellRendererText *cell; - GossipCellRendererTextPriv *priv; - - cell = GOSSIP_CELL_RENDERER_TEXT (object); - priv = GET_PRIV (cell); - - switch (param_id) { - case PROP_NAME: - g_value_set_string (value, priv->name); - break; - case PROP_STATUS: - g_value_set_string (value, priv->status); - break; - case PROP_IS_GROUP: - g_value_set_boolean (value, priv->is_group); - break; - case PROP_SHOW_STATUS: - g_value_set_boolean (value, priv->show_status); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - } -} - -static void -cell_renderer_text_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec) -{ - GossipCellRendererText *cell; - GossipCellRendererTextPriv *priv; - const gchar *str; - - cell = GOSSIP_CELL_RENDERER_TEXT (object); - priv = GET_PRIV (cell); - - switch (param_id) { - case PROP_NAME: - g_free (priv->name); - str = g_value_get_string (value); - priv->name = g_strdup (str ? str : ""); - g_strdelimit (priv->name, "\n\r\t", ' '); - priv->is_valid = FALSE; - break; - case PROP_STATUS: - g_free (priv->status); - str = g_value_get_string (value); - priv->status = g_strdup (str ? str : ""); - g_strdelimit (priv->status, "\n\r\t", ' '); - priv->is_valid = FALSE; - break; - case PROP_IS_GROUP: - priv->is_group = g_value_get_boolean (value); - priv->is_valid = FALSE; - break; - case PROP_SHOW_STATUS: - priv->show_status = g_value_get_boolean (value); - priv->is_valid = FALSE; - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - } -} - -static void -cell_renderer_text_get_size (GtkCellRenderer *cell, - GtkWidget *widget, - GdkRectangle *cell_area, - gint *x_offset, - gint *y_offset, - gint *width, - gint *height) -{ - GossipCellRendererText *celltext; - GossipCellRendererTextPriv *priv; - - celltext = GOSSIP_CELL_RENDERER_TEXT (cell); - priv = GET_PRIV (cell); - - /* Only update if not already valid so we get the right size. */ - cell_renderer_text_update_text (celltext, widget, priv->is_selected); - - (GTK_CELL_RENDERER_CLASS (gossip_cell_renderer_text_parent_class)->get_size) (cell, widget, - cell_area, - x_offset, y_offset, - width, height); -} - -static void -cell_renderer_text_render (GtkCellRenderer *cell, - GdkWindow *window, - GtkWidget *widget, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GdkRectangle *expose_area, - GtkCellRendererState flags) -{ - GossipCellRendererText *celltext; - - celltext = GOSSIP_CELL_RENDERER_TEXT (cell); - - cell_renderer_text_update_text (celltext, - widget, - (flags & GTK_CELL_RENDERER_SELECTED)); - - (GTK_CELL_RENDERER_CLASS (gossip_cell_renderer_text_parent_class)->render) ( - cell, window, - widget, - background_area, - cell_area, - expose_area, flags); -} - -static void -cell_renderer_text_update_text (GossipCellRendererText *cell, - GtkWidget *widget, - gboolean selected) -{ - GossipCellRendererTextPriv *priv; - PangoAttrList *attr_list; - PangoAttribute *attr_color, *attr_style, *attr_size; - GtkStyle *style; - gchar *str; - - priv = GET_PRIV (cell); - - if (priv->is_valid && priv->is_selected == selected) { - return; - } - - if (priv->is_group) { - g_object_set (cell, - "visible", TRUE, - "weight", PANGO_WEIGHT_BOLD, - "text", priv->name, - "attributes", NULL, - "xpad", 1, - "ypad", 1, - NULL); - - priv->is_selected = selected; - priv->is_valid = TRUE; - return; - } - - style = gtk_widget_get_style (widget); - - attr_list = pango_attr_list_new (); - - attr_style = pango_attr_style_new (PANGO_STYLE_ITALIC); - attr_style->start_index = strlen (priv->name) + 1; - attr_style->end_index = -1; - pango_attr_list_insert (attr_list, attr_style); - - if (!selected) { - GdkColor color; - - color = style->text_aa[GTK_STATE_NORMAL]; - - attr_color = pango_attr_foreground_new (color.red, color.green, color.blue); - attr_color->start_index = attr_style->start_index; - attr_color->end_index = -1; - pango_attr_list_insert (attr_list, attr_color); - } - - attr_size = pango_attr_size_new (pango_font_description_get_size (style->font_desc) / 1.2); - - attr_size->start_index = attr_style->start_index; - attr_size->end_index = -1; - pango_attr_list_insert (attr_list, attr_size); - - if (!priv->status || !priv->status[0] || !priv->show_status) { - str = g_strdup (priv->name); - } else { - str = g_strdup_printf ("%s\n%s", priv->name, priv->status); - } - - g_object_set (cell, - "visible", TRUE, - "weight", PANGO_WEIGHT_NORMAL, - "text", str, - "attributes", attr_list, - "xpad", 0, - "ypad", 1, - NULL); - - g_free (str); - pango_attr_list_unref (attr_list); - - priv->is_selected = selected; - priv->is_valid = TRUE; -} - -GtkCellRenderer * -gossip_cell_renderer_text_new (void) -{ - return g_object_new (GOSSIP_TYPE_CELL_RENDERER_TEXT, NULL); -} diff --git a/libempathy-gtk/gossip-cell-renderer-text.h b/libempathy-gtk/gossip-cell-renderer-text.h deleted file mode 100644 index 9b5a413b..00000000 --- a/libempathy-gtk/gossip-cell-renderer-text.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2004-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - */ - -#ifndef __GOSSIP_CELL_RENDERER_TEXT_H__ -#define __GOSSIP_CELL_RENDERER_TEXT_H__ - -#include - -G_BEGIN_DECLS - -#define GOSSIP_TYPE_CELL_RENDERER_TEXT (gossip_cell_renderer_text_get_type ()) -#define GOSSIP_CELL_RENDERER_TEXT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOSSIP_TYPE_CELL_RENDERER_TEXT, GossipCellRendererText)) -#define GOSSIP_CELL_RENDERER_TEXT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GOSSIP_TYPE_CELL_RENDERER_TEXT, GossipCellRendererTextClass)) -#define GOSSIP_IS_CELL_RENDERER_TEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOSSIP_TYPE_CELL_RENDERER_TEXT)) -#define GOSSIP_IS_CELL_RENDERER_TEXT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOSSIP_TYPE_CELL_RENDERER_TEXT)) -#define GOSSIP_CELL_RENDERER_TEXT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOSSIP_TYPE_CELL_RENDERER_TEXT, GossipCellRendererTextClass)) - -typedef struct _GossipCellRendererText GossipCellRendererText; -typedef struct _GossipCellRendererTextClass GossipCellRendererTextClass; -typedef struct _GossipCellRendererTextPriv GossipCellRendererTextPriv; - -struct _GossipCellRendererText { - GtkCellRendererText parent; - - GossipCellRendererTextPriv *priv; -}; - -struct _GossipCellRendererTextClass { - GtkCellRendererTextClass parent_class; -}; - -GType gossip_cell_renderer_text_get_type (void) G_GNUC_CONST; -GtkCellRenderer * gossip_cell_renderer_text_new (void); - -G_END_DECLS - -#endif /* __GOSSIP_CELL_RENDERER_TEXT_H__ */ diff --git a/libempathy-gtk/gossip-chat-manager.loT b/libempathy-gtk/gossip-chat-manager.loT deleted file mode 100644 index 3d0d3ab0..00000000 --- a/libempathy-gtk/gossip-chat-manager.loT +++ /dev/null @@ -1,7 +0,0 @@ -# gossip-chat-manager.lo - a libtool object file -# Generated by ltmain.sh - GNU libtool 1.5.22 Debian 1.5.22-4 (1.1220.2.365 2005/12/18 22:14:06) -# -# Please DO NOT delete this file! -# It is necessary for linking the library. - -# Name of the PIC object. diff --git a/libempathy-gtk/gossip-chat-view.c b/libempathy-gtk/gossip-chat-view.c deleted file mode 100644 index e8db2628..00000000 --- a/libempathy-gtk/gossip-chat-view.c +++ /dev/null @@ -1,2226 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2002-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Richard Hult - * Martyn Russell - */ - -#include "config.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "gossip-chat-view.h" -#include "gossip-chat.h" -#include "gossip-preferences.h" -#include "gossip-theme-manager.h" -#include "gossip-ui-utils.h" - -#define DEBUG_DOMAIN "ChatView" - -/* Number of seconds between timestamps when using normal mode, 5 minutes. */ -#define TIMESTAMP_INTERVAL 300 - -#define MAX_LINES 800 -#define MAX_SCROLL_TIME 0.4 /* seconds */ -#define SCROLL_DELAY 33 /* milliseconds */ - -#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CHAT_VIEW, GossipChatViewPriv)) - -typedef enum { - BLOCK_TYPE_NONE, - BLOCK_TYPE_SELF, - BLOCK_TYPE_OTHER, - BLOCK_TYPE_EVENT, - BLOCK_TYPE_TIME, - BLOCK_TYPE_INVITE -} BlockType; - -struct _GossipChatViewPriv { - GtkTextBuffer *buffer; - - gboolean irc_style; - time_t last_timestamp; - BlockType last_block_type; - - gboolean allow_scrolling; - guint scroll_timeout; - GTimer *scroll_time; - gboolean is_group_chat; - - GtkTextMark *find_mark_previous; - GtkTextMark *find_mark_next; - gboolean find_wrapped; - gboolean find_last_direction; - - /* This is for the group chat so we know if the "other" last contact - * changed, so we know whether to insert a header or not. - */ - GossipContact *last_contact; - - guint notify_system_fonts_id; - guint notify_show_avatars_id; -}; - -typedef struct { - GossipSmiley smiley; - const gchar *pattern; -} GossipSmileyPattern; - -static const GossipSmileyPattern smileys[] = { - /* Forward smileys. */ - { GOSSIP_SMILEY_NORMAL, ":)" }, - { GOSSIP_SMILEY_WINK, ";)" }, - { GOSSIP_SMILEY_WINK, ";-)" }, - { GOSSIP_SMILEY_BIGEYE, "=)" }, - { GOSSIP_SMILEY_NOSE, ":-)" }, - { GOSSIP_SMILEY_CRY, ":'(" }, - { GOSSIP_SMILEY_SAD, ":(" }, - { GOSSIP_SMILEY_SAD, ":-(" }, - { GOSSIP_SMILEY_SCEPTICAL, ":/" }, - { GOSSIP_SMILEY_SCEPTICAL, ":\\" }, - { GOSSIP_SMILEY_BIGSMILE, ":D" }, - { GOSSIP_SMILEY_BIGSMILE, ":-D" }, - { GOSSIP_SMILEY_INDIFFERENT, ":|" }, - { GOSSIP_SMILEY_TOUNGE, ":p" }, - { GOSSIP_SMILEY_TOUNGE, ":-p" }, - { GOSSIP_SMILEY_TOUNGE, ":P" }, - { GOSSIP_SMILEY_TOUNGE, ":-P" }, - { GOSSIP_SMILEY_TOUNGE, ";p" }, - { GOSSIP_SMILEY_TOUNGE, ";-p" }, - { GOSSIP_SMILEY_TOUNGE, ";P" }, - { GOSSIP_SMILEY_TOUNGE, ";-P" }, - { GOSSIP_SMILEY_SHOCKED, ":o" }, - { GOSSIP_SMILEY_SHOCKED, ":-o" }, - { GOSSIP_SMILEY_SHOCKED, ":O" }, - { GOSSIP_SMILEY_SHOCKED, ":-O" }, - { GOSSIP_SMILEY_COOL, "8)" }, - { GOSSIP_SMILEY_COOL, "B)" }, - { GOSSIP_SMILEY_SORRY, "*|" }, - { GOSSIP_SMILEY_KISS, ":*" }, - { GOSSIP_SMILEY_SHUTUP, ":#" }, - { GOSSIP_SMILEY_SHUTUP, ":-#" }, - { GOSSIP_SMILEY_YAWN, "|O" }, - { GOSSIP_SMILEY_CONFUSED, ":S" }, - { GOSSIP_SMILEY_CONFUSED, ":s" }, - { GOSSIP_SMILEY_ANGEL, "<)" }, - { GOSSIP_SMILEY_OOOH, ":x" }, - { GOSSIP_SMILEY_LOOKAWAY, "*)" }, - { GOSSIP_SMILEY_LOOKAWAY, "*-)" }, - { GOSSIP_SMILEY_BLUSH, "*S" }, - { GOSSIP_SMILEY_BLUSH, "*s" }, - { GOSSIP_SMILEY_BLUSH, "*$" }, - { GOSSIP_SMILEY_COOLBIGSMILE, "8D" }, - { GOSSIP_SMILEY_ANGRY, ":@" }, - { GOSSIP_SMILEY_BOSS, "@)" }, - { GOSSIP_SMILEY_MONKEY, "#)" }, - { GOSSIP_SMILEY_SILLY, "O)" }, - { GOSSIP_SMILEY_SICK, "+o(" }, - - /* Backward smileys. */ - { GOSSIP_SMILEY_NORMAL, "(:" }, - { GOSSIP_SMILEY_WINK, "(;" }, - { GOSSIP_SMILEY_WINK, "(-;" }, - { GOSSIP_SMILEY_BIGEYE, "(=" }, - { GOSSIP_SMILEY_NOSE, "(-:" }, - { GOSSIP_SMILEY_CRY, ")':" }, - { GOSSIP_SMILEY_SAD, "):" }, - { GOSSIP_SMILEY_SAD, ")-:" }, - { GOSSIP_SMILEY_SCEPTICAL, "/:" }, - { GOSSIP_SMILEY_SCEPTICAL, "//:" }, - { GOSSIP_SMILEY_INDIFFERENT, "|:" }, - { GOSSIP_SMILEY_TOUNGE, "d:" }, - { GOSSIP_SMILEY_TOUNGE, "d-:" }, - { GOSSIP_SMILEY_TOUNGE, "d;" }, - { GOSSIP_SMILEY_TOUNGE, "d-;" }, - { GOSSIP_SMILEY_SHOCKED, "o:" }, - { GOSSIP_SMILEY_SHOCKED, "O:" }, - { GOSSIP_SMILEY_COOL, "(8" }, - { GOSSIP_SMILEY_COOL, "(B" }, - { GOSSIP_SMILEY_SORRY, "|*" }, - { GOSSIP_SMILEY_KISS, "*:" }, - { GOSSIP_SMILEY_SHUTUP, "#:" }, - { GOSSIP_SMILEY_SHUTUP, "#-:" }, - { GOSSIP_SMILEY_YAWN, "O|" }, - { GOSSIP_SMILEY_CONFUSED, "S:" }, - { GOSSIP_SMILEY_CONFUSED, "s:" }, - { GOSSIP_SMILEY_ANGEL, "(>" }, - { GOSSIP_SMILEY_OOOH, "x:" }, - { GOSSIP_SMILEY_LOOKAWAY, "(*" }, - { GOSSIP_SMILEY_LOOKAWAY, "(-*" }, - { GOSSIP_SMILEY_BLUSH, "S*" }, - { GOSSIP_SMILEY_BLUSH, "s*" }, - { GOSSIP_SMILEY_BLUSH, "$*" }, - { GOSSIP_SMILEY_ANGRY, "@:" }, - { GOSSIP_SMILEY_BOSS, "(@" }, - { GOSSIP_SMILEY_MONKEY, "#)" }, - { GOSSIP_SMILEY_SILLY, "(O" }, - { GOSSIP_SMILEY_SICK, ")o+" } -}; - -static void gossip_chat_view_class_init (GossipChatViewClass *klass); -static void gossip_chat_view_init (GossipChatView *view); -static void chat_view_finalize (GObject *object); -static gboolean chat_view_drag_motion (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint time); -static void chat_view_size_allocate (GtkWidget *widget, - GtkAllocation *alloc); -static void chat_view_setup_tags (GossipChatView *view); -static void chat_view_system_font_update (GossipChatView *view); -static void chat_view_notify_system_font_cb (GossipConf *conf, - const gchar *key, - gpointer user_data); -static void chat_view_notify_show_avatars_cb (GossipConf *conf, - const gchar *key, - gpointer user_data); -static void chat_view_populate_popup (GossipChatView *view, - GtkMenu *menu, - gpointer user_data); -static gboolean chat_view_event_cb (GossipChatView *view, - GdkEventMotion *event, - GtkTextTag *tag); -static gboolean chat_view_url_event_cb (GtkTextTag *tag, - GObject *object, - GdkEvent *event, - GtkTextIter *iter, - GtkTextBuffer *buffer); -static void chat_view_open_address_cb (GtkMenuItem *menuitem, - const gchar *url); -static void chat_view_copy_address_cb (GtkMenuItem *menuitem, - const gchar *url); -static void chat_view_clear_view_cb (GtkMenuItem *menuitem, - GossipChatView *view); -static void chat_view_insert_text_with_emoticons (GtkTextBuffer *buf, - GtkTextIter *iter, - const gchar *str); -static gboolean chat_view_is_scrolled_down (GossipChatView *view); -static void chat_view_theme_changed_cb (GossipThemeManager *manager, - GossipChatView *view); -static void chat_view_maybe_append_date_and_time (GossipChatView *view, - GossipMessage *msg); -static void chat_view_append_spacing (GossipChatView *view); -static void chat_view_append_text (GossipChatView *view, - const gchar *body, - const gchar *tag); -static void chat_view_maybe_append_fancy_header (GossipChatView *view, - GossipMessage *msg); -static void chat_view_append_irc_action (GossipChatView *view, - GossipMessage *msg); -static void chat_view_append_fancy_action (GossipChatView *view, - GossipMessage *msg); -static void chat_view_append_irc_message (GossipChatView *view, - GossipMessage *msg); -static void chat_view_append_fancy_message (GossipChatView *view, - GossipMessage *msg); -static GdkPixbuf *chat_view_pad_to_size (GdkPixbuf *pixbuf, - gint width, - gint height, - gint extra_padding_right); - -G_DEFINE_TYPE (GossipChatView, gossip_chat_view, GTK_TYPE_TEXT_VIEW); - -static void -gossip_chat_view_class_init (GossipChatViewClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - - object_class->finalize = chat_view_finalize; - widget_class->size_allocate = chat_view_size_allocate; - widget_class->drag_motion = chat_view_drag_motion; - - g_type_class_add_private (object_class, sizeof (GossipChatViewPriv)); -} - -static void -gossip_chat_view_init (GossipChatView *view) -{ - GossipChatViewPriv *priv; - gboolean show_avatars; - - priv = GET_PRIV (view); - - priv->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); - - priv->last_block_type = BLOCK_TYPE_NONE; - priv->last_timestamp = 0; - - priv->allow_scrolling = TRUE; - - priv->is_group_chat = FALSE; - - g_object_set (view, - "wrap-mode", GTK_WRAP_WORD_CHAR, - "editable", FALSE, - "cursor-visible", FALSE, - NULL); - - priv->notify_system_fonts_id = - gossip_conf_notify_add (gossip_conf_get (), - "/desktop/gnome/interface/document_font_name", - chat_view_notify_system_font_cb, - view); - chat_view_system_font_update (view); - - priv->notify_show_avatars_id = - gossip_conf_notify_add (gossip_conf_get (), - GOSSIP_PREFS_UI_SHOW_AVATARS, - chat_view_notify_show_avatars_cb, - view); - - chat_view_setup_tags (view); - - gossip_theme_manager_apply_saved (gossip_theme_manager_get (), view); - - show_avatars = FALSE; - gossip_conf_get_bool (gossip_conf_get (), - GOSSIP_PREFS_UI_SHOW_AVATARS, - &show_avatars); - - gossip_theme_manager_update_show_avatars (gossip_theme_manager_get (), - view, show_avatars); - - g_signal_connect (view, - "populate-popup", - G_CALLBACK (chat_view_populate_popup), - NULL); - - g_signal_connect_object (gossip_theme_manager_get (), - "theme-changed", - G_CALLBACK (chat_view_theme_changed_cb), - view, - 0); -} - -static void -chat_view_finalize (GObject *object) -{ - GossipChatView *view; - GossipChatViewPriv *priv; - - view = GOSSIP_CHAT_VIEW (object); - priv = GET_PRIV (view); - - gossip_debug (DEBUG_DOMAIN, "finalize: %p", object); - - gossip_conf_notify_remove (gossip_conf_get (), priv->notify_system_fonts_id); - gossip_conf_notify_remove (gossip_conf_get (), priv->notify_show_avatars_id); - - if (priv->last_contact) { - g_object_unref (priv->last_contact); - } - if (priv->scroll_time) { - g_timer_destroy (priv->scroll_time); - } - if (priv->scroll_timeout) { - g_source_remove (priv->scroll_timeout); - } - - G_OBJECT_CLASS (gossip_chat_view_parent_class)->finalize (object); -} - -static gboolean -chat_view_drag_motion (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint time) -{ - /* Don't handle drag motion, since we don't want the view to scroll as - * the result of dragging something across it. - */ - - return FALSE; -} - -static void -chat_view_size_allocate (GtkWidget *widget, - GtkAllocation *alloc) -{ - gboolean down; - - down = chat_view_is_scrolled_down (GOSSIP_CHAT_VIEW (widget)); - - GTK_WIDGET_CLASS (gossip_chat_view_parent_class)->size_allocate (widget, alloc); - - if (down) { - GtkAdjustment *adj; - - adj = GTK_TEXT_VIEW (widget)->vadjustment; - gtk_adjustment_set_value (adj, adj->upper - adj->page_size); - } -} - -static void -chat_view_setup_tags (GossipChatView *view) -{ - GossipChatViewPriv *priv; - GtkTextTag *tag; - - priv = GET_PRIV (view); - - gtk_text_buffer_create_tag (priv->buffer, - "cut", - NULL); - - /* FIXME: Move to the theme and come up with something that looks a bit - * nicer. - */ - gtk_text_buffer_create_tag (priv->buffer, - "highlight", - "background", "yellow", - NULL); - - tag = gtk_text_buffer_create_tag (priv->buffer, - "link", - NULL); - - g_signal_connect (tag, - "event", - G_CALLBACK (chat_view_url_event_cb), - priv->buffer); - - g_signal_connect (view, - "motion-notify-event", - G_CALLBACK (chat_view_event_cb), - tag); -} - -static void -chat_view_system_font_update (GossipChatView *view) -{ - PangoFontDescription *font_description = NULL; - gchar *font_name; - - if (gossip_conf_get_string (gossip_conf_get (), - "/desktop/gnome/interface/document_font_name", - &font_name) && font_name) { - font_description = pango_font_description_from_string (font_name); - g_free (font_name); - } else { - font_description = NULL; - } - - gtk_widget_modify_font (GTK_WIDGET (view), font_description); - - if (font_description) { - pango_font_description_free (font_description); - } -} - -static void -chat_view_notify_system_font_cb (GossipConf *conf, - const gchar *key, - gpointer user_data) -{ - GossipChatView *view; - gboolean show_avatars = FALSE; - - view = user_data; - - chat_view_system_font_update (view); - - /* Ugly, again, to adjust the vertical position of the nick... Will fix - * this when reworking the theme manager so that view register - * themselves with it instead of the other way around. - */ - gossip_conf_get_bool (conf, - GOSSIP_PREFS_UI_SHOW_AVATARS, - &show_avatars); - - gossip_theme_manager_update_show_avatars (gossip_theme_manager_get (), - view, show_avatars); -} - -static void -chat_view_notify_show_avatars_cb (GossipConf *conf, - const gchar *key, - gpointer user_data) -{ - GossipChatView *view; - GossipChatViewPriv *priv; - gboolean show_avatars = FALSE; - - view = user_data; - priv = GET_PRIV (view); - - gossip_conf_get_bool (conf, key, &show_avatars); - - gossip_theme_manager_update_show_avatars (gossip_theme_manager_get (), - view, show_avatars); -} - -static void -chat_view_populate_popup (GossipChatView *view, - GtkMenu *menu, - gpointer user_data) -{ - GossipChatViewPriv *priv; - GtkTextTagTable *table; - GtkTextTag *tag; - gint x, y; - GtkTextIter iter, start, end; - GtkWidget *item; - gchar *str = NULL; - - priv = GET_PRIV (view); - - /* Clear menu item */ - if (gtk_text_buffer_get_char_count (priv->buffer) > 0) { - item = gtk_menu_item_new (); - gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - item = gtk_image_menu_item_new_from_stock (GTK_STOCK_CLEAR, NULL); - gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - g_signal_connect (item, - "activate", - G_CALLBACK (chat_view_clear_view_cb), - view); - } - - /* Link context menu items */ - table = gtk_text_buffer_get_tag_table (priv->buffer); - tag = gtk_text_tag_table_lookup (table, "link"); - - gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y); - - gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view), - GTK_TEXT_WINDOW_WIDGET, - x, y, - &x, &y); - - gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view), &iter, x, y); - - start = end = iter; - - if (gtk_text_iter_backward_to_tag_toggle (&start, tag) && - gtk_text_iter_forward_to_tag_toggle (&end, tag)) { - str = gtk_text_buffer_get_text (priv->buffer, - &start, &end, FALSE); - } - - if (G_STR_EMPTY (str)) { - g_free (str); - return; - } - - /* NOTE: Set data just to get the string freed when not needed. */ - g_object_set_data_full (G_OBJECT (menu), - "url", str, - (GDestroyNotify) g_free); - - item = gtk_menu_item_new (); - gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - item = gtk_menu_item_new_with_mnemonic (_("_Copy Link Address")); - g_signal_connect (item, - "activate", - G_CALLBACK (chat_view_copy_address_cb), - str); - gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - item = gtk_menu_item_new_with_mnemonic (_("_Open Link")); - g_signal_connect (item, - "activate", - G_CALLBACK (chat_view_open_address_cb), - str); - gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); -} - -static gboolean -chat_view_event_cb (GossipChatView *view, - GdkEventMotion *event, - GtkTextTag *tag) -{ - static GdkCursor *hand = NULL; - static GdkCursor *beam = NULL; - GtkTextWindowType type; - GtkTextIter iter; - GdkWindow *win; - gint x, y, buf_x, buf_y; - - type = gtk_text_view_get_window_type (GTK_TEXT_VIEW (view), - event->window); - - if (type != GTK_TEXT_WINDOW_TEXT) { - return FALSE; - } - - /* Get where the pointer really is. */ - win = gtk_text_view_get_window (GTK_TEXT_VIEW (view), type); - if (!win) { - return FALSE; - } - - gdk_window_get_pointer (win, &x, &y, NULL); - - /* Get the iter where the cursor is at */ - gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view), type, - x, y, - &buf_x, &buf_y); - - gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view), - &iter, - buf_x, buf_y); - - if (gtk_text_iter_has_tag (&iter, tag)) { - if (!hand) { - hand = gdk_cursor_new (GDK_HAND2); - beam = gdk_cursor_new (GDK_XTERM); - } - gdk_window_set_cursor (win, hand); - } else { - if (!beam) { - beam = gdk_cursor_new (GDK_XTERM); - } - gdk_window_set_cursor (win, beam); - } - - return FALSE; -} - -static gboolean -chat_view_url_event_cb (GtkTextTag *tag, - GObject *object, - GdkEvent *event, - GtkTextIter *iter, - GtkTextBuffer *buffer) -{ - GtkTextIter start, end; - gchar *str; - - /* If the link is being selected, don't do anything. */ - gtk_text_buffer_get_selection_bounds (buffer, &start, &end); - if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end)) { - return FALSE; - } - - if (event->type == GDK_BUTTON_RELEASE && event->button.button == 1) { - start = end = *iter; - - if (gtk_text_iter_backward_to_tag_toggle (&start, tag) && - gtk_text_iter_forward_to_tag_toggle (&end, tag)) { - str = gtk_text_buffer_get_text (buffer, - &start, - &end, - FALSE); - - gossip_url_show (str); - g_free (str); - } - } - - return FALSE; -} - -static void -chat_view_open_address_cb (GtkMenuItem *menuitem, const gchar *url) -{ - gossip_url_show (url); -} - -static void -chat_view_copy_address_cb (GtkMenuItem *menuitem, const gchar *url) -{ - GtkClipboard *clipboard; - - clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); - gtk_clipboard_set_text (clipboard, url, -1); - - clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY); - gtk_clipboard_set_text (clipboard, url, -1); -} - -static void -chat_view_clear_view_cb (GtkMenuItem *menuitem, GossipChatView *view) -{ - gossip_chat_view_clear (view); -} - -static void -chat_view_insert_text_with_emoticons (GtkTextBuffer *buf, - GtkTextIter *iter, - const gchar *str) -{ - const gchar *p; - gunichar c, prev_c; - gint i; - gint match; - gint submatch; - gboolean use_smileys = FALSE; - - gossip_conf_get_bool (gossip_conf_get (), - GOSSIP_PREFS_CHAT_SHOW_SMILEYS, - &use_smileys); - - if (!use_smileys) { - gtk_text_buffer_insert (buf, iter, str, -1); - return; - } - - while (*str) { - gint smileys_index[G_N_ELEMENTS (smileys)]; - GdkPixbuf *pixbuf; - gint len; - const gchar *start; - - memset (smileys_index, 0, sizeof (smileys_index)); - - match = -1; - submatch = -1; - p = str; - prev_c = 0; - - while (*p) { - c = g_utf8_get_char (p); - - if (match != -1 && g_unichar_isspace (c)) { - break; - } else { - match = -1; - } - - if (submatch != -1 || prev_c == 0 || g_unichar_isspace (prev_c)) { - submatch = -1; - - for (i = 0; i < G_N_ELEMENTS (smileys); i++) { - /* Only try to match if we already have - * a beginning match for the pattern, or - * if it's the first character in the - * pattern, if it's not in the middle of - * a word. - */ - if (((smileys_index[i] == 0 && (prev_c == 0 || g_unichar_isspace (prev_c))) || - smileys_index[i] > 0) && - smileys[i].pattern[smileys_index[i]] == c) { - submatch = i; - - smileys_index[i]++; - if (!smileys[i].pattern[smileys_index[i]]) { - match = i; - } - } else { - smileys_index[i] = 0; - } - } - } - - prev_c = c; - p = g_utf8_next_char (p); - } - - if (match == -1) { - gtk_text_buffer_insert (buf, iter, str, -1); - return; - } - - start = p - strlen (smileys[match].pattern); - - if (start > str) { - len = start - str; - gtk_text_buffer_insert (buf, iter, str, len); - } - - pixbuf = gossip_chat_view_get_smiley_image (smileys[match].smiley); - gtk_text_buffer_insert_pixbuf (buf, iter, pixbuf); - - gtk_text_buffer_insert (buf, iter, " ", 1); - - str = g_utf8_find_next_char (p, NULL); - } -} - -static gboolean -chat_view_is_scrolled_down (GossipChatView *view) -{ - GtkWidget *sw; - - sw = gtk_widget_get_parent (GTK_WIDGET (view)); - if (GTK_IS_SCROLLED_WINDOW (sw)) { - GtkAdjustment *vadj; - - vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (sw)); - - if (vadj->value + vadj->page_size / 2 < vadj->upper - vadj->page_size) { - return FALSE; - } - } - - return TRUE; -} - -static void -chat_view_maybe_trim_buffer (GossipChatView *view) -{ - GossipChatViewPriv *priv; - GtkTextIter top, bottom; - gint line; - gint remove; - GtkTextTagTable *table; - GtkTextTag *tag; - - priv = GET_PRIV (view); - - gtk_text_buffer_get_end_iter (priv->buffer, &bottom); - line = gtk_text_iter_get_line (&bottom); - if (line < MAX_LINES) { - return; - } - - remove = line - MAX_LINES; - gtk_text_buffer_get_start_iter (priv->buffer, &top); - - bottom = top; - if (!gtk_text_iter_forward_lines (&bottom, remove)) { - return; - } - - /* Track backwords to a place where we can safely cut, we don't do it in - * the middle of a tag. - */ - table = gtk_text_buffer_get_tag_table (priv->buffer); - tag = gtk_text_tag_table_lookup (table, "cut"); - if (!tag) { - return; - } - - if (!gtk_text_iter_forward_to_tag_toggle (&bottom, tag)) { - return; - } - - if (!gtk_text_iter_equal (&top, &bottom)) { - gtk_text_buffer_delete (priv->buffer, &top, &bottom); - } -} - -static void -chat_view_maybe_append_date_and_time (GossipChatView *view, - GossipMessage *msg) -{ - GossipChatViewPriv *priv; - const gchar *tag; - time_t timestamp; - GDate *date, *last_date; - GtkTextIter iter; - gboolean append_date, append_time; - GString *str; - - priv = GET_PRIV (view); - - if (priv->irc_style) { - tag = "irc-time"; - } else { - tag = "fancy-time"; - } - - if (priv->last_block_type == BLOCK_TYPE_TIME) { - return; - } - - str = g_string_new (NULL); - - timestamp = 0; - if (msg) { - timestamp = gossip_message_get_timestamp (msg); - } - - if (timestamp <= 0) { - timestamp = gossip_time_get_current (); - } - - date = g_date_new (); - g_date_set_time (date, timestamp); - - last_date = g_date_new (); - g_date_set_time (last_date, priv->last_timestamp); - - append_date = FALSE; - append_time = FALSE; - - if (g_date_compare (date, last_date) > 0) { - append_date = TRUE; - append_time = TRUE; - } - - if (priv->last_timestamp + TIMESTAMP_INTERVAL < timestamp) { - append_time = TRUE; - } - - if (append_time || append_date) { - chat_view_append_spacing (view); - - g_string_append (str, "- "); - } - - if (append_date) { - gchar buf[256]; - - g_date_strftime (buf, 256, _("%A %d %B %Y"), date); - g_string_append (str, buf); - - if (append_time) { - g_string_append (str, ", "); - } - } - - g_date_free (date); - g_date_free (last_date); - - if (append_time) { - gchar *tmp; - - tmp = gossip_time_to_string_local (timestamp, GOSSIP_TIME_FORMAT_DISPLAY_SHORT); - g_string_append (str, tmp); - g_free (tmp); - } - - if (append_time || append_date) { - g_string_append (str, " -\n"); - - gtk_text_buffer_get_end_iter (priv->buffer, &iter); - gtk_text_buffer_insert_with_tags_by_name (priv->buffer, - &iter, - str->str, -1, - tag, - NULL); - - priv->last_block_type = BLOCK_TYPE_TIME; - priv->last_timestamp = timestamp; - } - - g_string_free (str, TRUE); -} - -static void -chat_view_append_spacing (GossipChatView *view) -{ - GossipChatViewPriv *priv; - const gchar *tag; - GtkTextIter iter; - - priv = GET_PRIV (view); - - if (priv->irc_style) { - tag = "irc-spacing"; - } else { - tag = "fancy-spacing"; - } - - gtk_text_buffer_get_end_iter (priv->buffer, &iter); - gtk_text_buffer_insert_with_tags_by_name (priv->buffer, - &iter, - "\n", - -1, - "cut", - tag, - NULL); -} - -static void -chat_view_append_text (GossipChatView *view, - const gchar *body, - const gchar *tag) -{ - GossipChatViewPriv *priv; - GtkTextIter start_iter, end_iter; - GtkTextMark *mark; - GtkTextIter iter; - gint num_matches, i; - GArray *start, *end; - const gchar *link_tag; - - priv = GET_PRIV (view); - - if (priv->irc_style) { - link_tag = "irc-link"; - } else { - link_tag = "fancy-link"; - } - - gtk_text_buffer_get_end_iter (priv->buffer, &start_iter); - mark = gtk_text_buffer_create_mark (priv->buffer, NULL, &start_iter, TRUE); - - start = g_array_new (FALSE, FALSE, sizeof (gint)); - end = g_array_new (FALSE, FALSE, sizeof (gint)); - - num_matches = gossip_regex_match (GOSSIP_REGEX_ALL, body, start, end); - - if (num_matches == 0) { - gtk_text_buffer_get_end_iter (priv->buffer, &iter); - chat_view_insert_text_with_emoticons (priv->buffer, &iter, body); - } else { - gint last = 0; - gint s = 0, e = 0; - gchar *tmp; - - for (i = 0; i < num_matches; i++) { - s = g_array_index (start, gint, i); - e = g_array_index (end, gint, i); - - if (s > last) { - tmp = gossip_substring (body, last, s); - - gtk_text_buffer_get_end_iter (priv->buffer, &iter); - chat_view_insert_text_with_emoticons (priv->buffer, - &iter, - tmp); - g_free (tmp); - } - - tmp = gossip_substring (body, s, e); - - gtk_text_buffer_get_end_iter (priv->buffer, &iter); - gtk_text_buffer_insert_with_tags_by_name (priv->buffer, - &iter, - tmp, - -1, - link_tag, - "link", - NULL); - - g_free (tmp); - - last = e; - } - - if (e < strlen (body)) { - tmp = gossip_substring (body, e, strlen (body)); - - gtk_text_buffer_get_end_iter (priv->buffer, &iter); - chat_view_insert_text_with_emoticons (priv->buffer, - &iter, - tmp); - g_free (tmp); - } - } - - g_array_free (start, TRUE); - g_array_free (end, TRUE); - - gtk_text_buffer_get_end_iter (priv->buffer, &iter); - gtk_text_buffer_insert (priv->buffer, &iter, "\n", 1); - - /* Apply the style to the inserted text. */ - gtk_text_buffer_get_iter_at_mark (priv->buffer, &start_iter, mark); - gtk_text_buffer_get_end_iter (priv->buffer, &end_iter); - - gtk_text_buffer_apply_tag_by_name (priv->buffer, - tag, - &start_iter, - &end_iter); - - gtk_text_buffer_delete_mark (priv->buffer, mark); -} - -static void -chat_view_maybe_append_fancy_header (GossipChatView *view, - GossipMessage *msg) -{ - GossipChatViewPriv *priv; - GossipContact *sender; - const gchar *name; - gboolean header; - GtkTextIter iter; - gchar *tmp; - const gchar *tag; - const gchar *avatar_tag; - const gchar *line_top_tag; - const gchar *line_bottom_tag; - gboolean from_self; - GdkPixbuf *pixbuf = NULL; - GdkPixbuf *avatar = NULL; - - priv = GET_PRIV (view); - - sender = gossip_message_get_sender (msg); - name = gossip_contact_get_name (sender); - from_self = gossip_contact_is_user (sender); - - gossip_debug (DEBUG_DOMAIN, "Maybe add fancy header"); - - if (from_self) { - tag = "fancy-header-self"; - line_top_tag = "fancy-line-top-self"; - line_bottom_tag = "fancy-line-bottom-self"; - } else { - tag = "fancy-header-other"; - line_top_tag = "fancy-line-top-other"; - line_bottom_tag = "fancy-line-bottom-other"; - } - - header = FALSE; - - /* Only insert a header if the previously inserted block is not the same - * as this one. This catches all the different cases: - */ - if (priv->last_block_type != BLOCK_TYPE_SELF && - priv->last_block_type != BLOCK_TYPE_OTHER) { - header = TRUE; - } - else if (from_self && priv->last_block_type == BLOCK_TYPE_OTHER) { - header = TRUE; - } - else if (!from_self && priv->last_block_type == BLOCK_TYPE_SELF) { - header = TRUE; - } - else if (!from_self && - (!priv->last_contact || - !gossip_contact_equal (sender, priv->last_contact))) { - header = TRUE; - } - - if (!header) { - return; - } - - chat_view_append_spacing (view); - - gtk_text_buffer_get_end_iter (priv->buffer, &iter); - gtk_text_buffer_insert_with_tags_by_name (priv->buffer, - &iter, - "\n", - -1, - line_top_tag, - NULL); - - /* FIXME: we should have a cash of avatar pixbufs */ - pixbuf = gossip_pixbuf_avatar_from_contact_scaled (sender, 32, 32); - if (pixbuf) { - avatar = chat_view_pad_to_size (pixbuf, 32, 32, 6); - g_object_unref (pixbuf); - } - - if (avatar) { - GtkTextIter start; - - gtk_text_buffer_get_end_iter (priv->buffer, &iter); - gtk_text_buffer_insert_pixbuf (priv->buffer, &iter, avatar); - - gtk_text_buffer_get_end_iter (priv->buffer, &iter); - start = iter; - gtk_text_iter_backward_char (&start); - - if (from_self) { - gtk_text_buffer_apply_tag_by_name (priv->buffer, - "fancy-avatar-self", - &start, &iter); - avatar_tag = "fancy-header-self-avatar"; - } else { - gtk_text_buffer_apply_tag_by_name (priv->buffer, - "fancy-avatar-other", - &start, &iter); - avatar_tag = "fancy-header-other-avatar"; - } - - g_object_unref (avatar); - } else { - avatar_tag = NULL; - } - - tmp = g_strdup_printf ("%s\n", name); - - gtk_text_buffer_get_end_iter (priv->buffer, &iter); - gtk_text_buffer_insert_with_tags_by_name (priv->buffer, - &iter, - tmp, - -1, - tag, - avatar_tag, - NULL); - g_free (tmp); - - gtk_text_buffer_get_end_iter (priv->buffer, &iter); - gtk_text_buffer_insert_with_tags_by_name (priv->buffer, - &iter, - "\n", - -1, - line_bottom_tag, - NULL); -} - -static void -chat_view_append_irc_action (GossipChatView *view, - GossipMessage *msg) -{ - GossipChatViewPriv *priv; - GossipContact *sender; - const gchar *name; - GtkTextIter iter; - const gchar *body; - gchar *tmp; - const gchar *tag; - - priv = GET_PRIV (view); - - gossip_debug (DEBUG_DOMAIN, "Add IRC action"); - - sender = gossip_message_get_sender (msg); - name = gossip_contact_get_name (sender); - - if (gossip_contact_is_user (sender)) { - tag = "irc-action-self"; - } else { - tag = "irc-action-other"; - } - - if (priv->last_block_type != BLOCK_TYPE_SELF && - priv->last_block_type != BLOCK_TYPE_OTHER) { - chat_view_append_spacing (view); - } - - gtk_text_buffer_get_end_iter (priv->buffer, &iter); - - tmp = g_strdup_printf (" * %s ", name); - gtk_text_buffer_insert_with_tags_by_name (priv->buffer, - &iter, - tmp, - -1, - "cut", - tag, - NULL); - g_free (tmp); - - body = gossip_message_get_body (msg); - chat_view_append_text (view, body, tag); -} - -static void -chat_view_append_fancy_action (GossipChatView *view, - GossipMessage *msg) -{ - GossipChatViewPriv *priv; - GossipContact *sender; - const gchar *name; - const gchar *body; - GtkTextIter iter; - gchar *tmp; - const gchar *tag; - const gchar *line_tag; - - priv = GET_PRIV (view); - - gossip_debug (DEBUG_DOMAIN, "Add fancy action"); - - sender = gossip_message_get_sender (msg); - name = gossip_contact_get_name (sender); - - if (gossip_contact_is_user (sender)) { - tag = "fancy-action-self"; - line_tag = "fancy-line-self"; - } else { - tag = "fancy-action-other"; - line_tag = "fancy-line-other"; - } - - tmp = g_strdup_printf (" * %s ", name); - gtk_text_buffer_get_end_iter (priv->buffer, &iter); - gtk_text_buffer_insert_with_tags_by_name (priv->buffer, - &iter, - tmp, - -1, - tag, - NULL); - g_free (tmp); - - body = gossip_message_get_body (msg); - chat_view_append_text (view, body, tag); -} - -static void -chat_view_append_irc_message (GossipChatView *view, - GossipMessage *msg) -{ - GossipChatViewPriv *priv; - GossipContact *sender; - const gchar *name; - const gchar *body; - const gchar *nick_tag; - const gchar *body_tag; - GtkTextIter iter; - gchar *tmp; - - priv = GET_PRIV (view); - - gossip_debug (DEBUG_DOMAIN, "Add IRC message"); - - body = gossip_message_get_body (msg); - sender = gossip_message_get_sender (msg); - name = gossip_contact_get_name (sender); - - if (gossip_contact_is_user (sender)) { - nick_tag = "irc-nick-self"; - body_tag = "irc-body-self"; - } else { - if (gossip_chat_should_highlight_nick (msg)) { - nick_tag = "irc-nick-highlight"; - } else { - nick_tag = "irc-nick-other"; - } - - body_tag = "irc-body-other"; - } - - if (priv->last_block_type != BLOCK_TYPE_SELF && - priv->last_block_type != BLOCK_TYPE_OTHER) { - chat_view_append_spacing (view); - } - - gtk_text_buffer_get_end_iter (priv->buffer, &iter); - - /* The nickname. */ - tmp = g_strdup_printf ("%s: ", name); - gtk_text_buffer_insert_with_tags_by_name (priv->buffer, - &iter, - tmp, - -1, - "cut", - nick_tag, - NULL); - g_free (tmp); - - /* The text body. */ - chat_view_append_text (view, body, body_tag); -} - -static void -chat_view_append_fancy_message (GossipChatView *view, - GossipMessage *msg) -{ - GossipChatViewPriv *priv; - GossipContact *sender; - const gchar *body; - const gchar *tag; - - priv = GET_PRIV (view); - - sender = gossip_message_get_sender (msg); - - if (gossip_contact_is_user (sender)) { - tag = "fancy-body-self"; - } else { - tag = "fancy-body-other"; - - /* FIXME: Might want to support nick highlighting here... */ - } - - body = gossip_message_get_body (msg); - chat_view_append_text (view, body, tag); -} - -static void -chat_view_theme_changed_cb (GossipThemeManager *manager, - GossipChatView *view) -{ - GossipChatViewPriv *priv; - gboolean show_avatars = FALSE; - gboolean theme_rooms = FALSE; - - priv = GET_PRIV (view); - - priv->last_block_type = BLOCK_TYPE_NONE; - - gossip_conf_get_bool (gossip_conf_get (), - GOSSIP_PREFS_CHAT_THEME_CHAT_ROOM, - &theme_rooms); - if (!theme_rooms && priv->is_group_chat) { - gossip_theme_manager_apply (manager, view, NULL); - } else { - gossip_theme_manager_apply_saved (manager, view); - } - - /* Needed for now to update the "rise" property of the names to get it - * vertically centered. - */ - gossip_conf_get_bool (gossip_conf_get (), - GOSSIP_PREFS_UI_SHOW_AVATARS, - &show_avatars); - gossip_theme_manager_update_show_avatars (manager, view, show_avatars); -} - -/* Pads a pixbuf to the specified size, by centering it in a larger transparent - * pixbuf. Returns a new ref. - */ -static GdkPixbuf * -chat_view_pad_to_size (GdkPixbuf *pixbuf, - gint width, - gint height, - gint extra_padding_right) -{ - gint src_width, src_height; - GdkPixbuf *padded; - gint x_offset, y_offset; - - src_width = gdk_pixbuf_get_width (pixbuf); - src_height = gdk_pixbuf_get_height (pixbuf); - - x_offset = (width - src_width) / 2; - y_offset = (height - src_height) / 2; - - padded = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (pixbuf), - TRUE, /* alpha */ - gdk_pixbuf_get_bits_per_sample (pixbuf), - width + extra_padding_right, - height); - - gdk_pixbuf_fill (padded, 0); - - gdk_pixbuf_copy_area (pixbuf, - 0, /* source coords */ - 0, - src_width, - src_height, - padded, - x_offset, /* dest coords */ - y_offset); - - return padded; -} - -GossipChatView * -gossip_chat_view_new (void) -{ - return g_object_new (GOSSIP_TYPE_CHAT_VIEW, NULL); -} - -/* The name is optional, if NULL, the sender for msg is used. */ -void -gossip_chat_view_append_message (GossipChatView *view, - GossipMessage *msg) -{ - GossipChatViewPriv *priv; - GossipContact *sender; - const gchar *body; - gboolean scroll_down; - - g_return_if_fail (GOSSIP_IS_CHAT_VIEW (view)); - g_return_if_fail (GOSSIP_IS_MESSAGE (msg)); - - priv = GET_PRIV (view); - - body = gossip_message_get_body (msg); - if (!body) { - return; - } - - scroll_down = chat_view_is_scrolled_down (view); - - chat_view_maybe_trim_buffer (view); - chat_view_maybe_append_date_and_time (view, msg); - - sender = gossip_message_get_sender (msg); - - if (!priv->irc_style) { - chat_view_maybe_append_fancy_header (view, msg); - } - - if (gossip_message_get_type (msg) == GOSSIP_MESSAGE_TYPE_ACTION) { - if (priv->irc_style) { - chat_view_append_irc_action (view, msg); - } else { - chat_view_append_fancy_action (view, msg); - } - } else { - if (priv->irc_style) { - chat_view_append_irc_message (view, msg); - } else { - chat_view_append_fancy_message (view, msg); - } - } - - /* Reset the last inserted contact. */ - if (priv->last_contact) { - g_object_unref (priv->last_contact); - } - - if (gossip_contact_is_user (sender)) { - priv->last_block_type = BLOCK_TYPE_SELF; - priv->last_contact = NULL; - } else { - priv->last_block_type = BLOCK_TYPE_OTHER; - priv->last_contact = g_object_ref (sender); - } - - if (scroll_down) { - gossip_chat_view_scroll_down (view); - } -} - -void -gossip_chat_view_append_event (GossipChatView *view, - const gchar *str) -{ - GossipChatViewPriv *priv; - gboolean bottom; - GtkTextIter iter; - gchar *msg; - const gchar *tag; - - g_return_if_fail (GOSSIP_IS_CHAT_VIEW (view)); - g_return_if_fail (!G_STR_EMPTY (str)); - - priv = GET_PRIV (view); - - bottom = chat_view_is_scrolled_down (view); - - chat_view_maybe_trim_buffer (view); - - if (priv->irc_style) { - tag = "irc-event"; - msg = g_strdup_printf (" - %s\n", str); - } else { - tag = "fancy-event"; - msg = g_strdup_printf (" - %s\n", str); - } - - if (priv->last_block_type != BLOCK_TYPE_EVENT) { - /* Comment out for now. */ - /*chat_view_append_spacing (view);*/ - } - - chat_view_maybe_append_date_and_time (view, NULL); - - gtk_text_buffer_get_end_iter (priv->buffer, &iter); - - gtk_text_buffer_insert_with_tags_by_name (priv->buffer, &iter, - msg, -1, - tag, - NULL); - g_free (msg); - - if (bottom) { - gossip_chat_view_scroll_down (view); - } - - priv->last_block_type = BLOCK_TYPE_EVENT; -} - -void -gossip_chat_view_append_button (GossipChatView *view, - const gchar *message, - GtkWidget *button1, - GtkWidget *button2) -{ - GossipChatViewPriv *priv; - GtkTextChildAnchor *anchor; - GtkTextIter iter; - gboolean bottom; - const gchar *tag; - - g_return_if_fail (GOSSIP_IS_CHAT_VIEW (view)); - g_return_if_fail (button1 != NULL); - - priv = GET_PRIV (view); - - if (priv->irc_style) { - tag = "irc-invite"; - } else { - tag = "fancy-invite"; - } - - bottom = chat_view_is_scrolled_down (view); - - chat_view_maybe_append_date_and_time (view, NULL); - - if (message) { - chat_view_append_text (view, message, tag); - } - - gtk_text_buffer_get_end_iter (priv->buffer, &iter); - - anchor = gtk_text_buffer_create_child_anchor (priv->buffer, &iter); - gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view), button1, anchor); - gtk_widget_show (button1); - - gtk_text_buffer_insert_with_tags_by_name (priv->buffer, - &iter, - " ", - 1, - tag, - NULL); - - if (button2) { - gtk_text_buffer_get_end_iter (priv->buffer, &iter); - - anchor = gtk_text_buffer_create_child_anchor (priv->buffer, &iter); - gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view), button2, anchor); - gtk_widget_show (button2); - - gtk_text_buffer_insert_with_tags_by_name (priv->buffer, - &iter, - " ", - 1, - tag, - NULL); - } - - gtk_text_buffer_get_end_iter (priv->buffer, &iter); - gtk_text_buffer_insert_with_tags_by_name (priv->buffer, - &iter, - "\n\n", - 2, - tag, - NULL); - - if (bottom) { - gossip_chat_view_scroll_down (view); - } - - priv->last_block_type = BLOCK_TYPE_INVITE; -} - -void -gossip_chat_view_scroll (GossipChatView *view, - gboolean allow_scrolling) -{ - GossipChatViewPriv *priv; - - g_return_if_fail (GOSSIP_IS_CHAT_VIEW (view)); - - priv = GET_PRIV (view); - - priv->allow_scrolling = allow_scrolling; - - gossip_debug (DEBUG_DOMAIN, "Scrolling %s", - allow_scrolling ? "enabled" : "disabled"); -} - -/* Code stolen from pidgin/gtkimhtml.c */ -static gboolean -chat_view_scroll_cb (GossipChatView *view) -{ - GossipChatViewPriv *priv; - GtkAdjustment *adj; - gdouble max_val; - - priv = GET_PRIV (view); - adj = GTK_TEXT_VIEW (view)->vadjustment; - max_val = adj->upper - adj->page_size; - - g_return_val_if_fail (priv->scroll_time != NULL, FALSE); - - if (g_timer_elapsed (priv->scroll_time, NULL) > MAX_SCROLL_TIME) { - /* time's up. jump to the end and kill the timer */ - gtk_adjustment_set_value (adj, max_val); - g_timer_destroy (priv->scroll_time); - priv->scroll_time = NULL; - priv->scroll_timeout = 0; - return FALSE; - } - - /* scroll by 1/3rd the remaining distance */ - gtk_adjustment_set_value (adj, gtk_adjustment_get_value (adj) + ((max_val - gtk_adjustment_get_value (adj)) / 3)); - return TRUE; -} - -void -gossip_chat_view_scroll_down (GossipChatView *view) -{ - GossipChatViewPriv *priv; - - g_return_if_fail (GOSSIP_IS_CHAT_VIEW (view)); - - priv = GET_PRIV (view); - - if (!priv->allow_scrolling) { - return; - } - - gossip_debug (DEBUG_DOMAIN, "Scrolling down"); - - if (priv->scroll_time) { - g_timer_reset (priv->scroll_time); - } else { - priv->scroll_time = g_timer_new(); - } - if (!priv->scroll_timeout) { - priv->scroll_timeout = g_timeout_add (SCROLL_DELAY, - (GSourceFunc) chat_view_scroll_cb, - view); - } -} - -gboolean -gossip_chat_view_get_selection_bounds (GossipChatView *view, - GtkTextIter *start, - GtkTextIter *end) -{ - GtkTextBuffer *buffer; - - g_return_val_if_fail (GOSSIP_IS_CHAT_VIEW (view), FALSE); - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); - - return gtk_text_buffer_get_selection_bounds (buffer, start, end); -} - -void -gossip_chat_view_clear (GossipChatView *view) -{ - GtkTextBuffer *buffer; - GossipChatViewPriv *priv; - - g_return_if_fail (GOSSIP_IS_CHAT_VIEW (view)); - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); - gtk_text_buffer_set_text (buffer, "", -1); - - /* We set these back to the initial values so we get - * timestamps when clearing the window to know when - * conversations start. - */ - priv = GET_PRIV (view); - - priv->last_block_type = BLOCK_TYPE_NONE; - priv->last_timestamp = 0; -} - -gboolean -gossip_chat_view_find_previous (GossipChatView *view, - const gchar *search_criteria, - gboolean new_search) -{ - GossipChatViewPriv *priv; - GtkTextBuffer *buffer; - GtkTextIter iter_at_mark; - GtkTextIter iter_match_start; - GtkTextIter iter_match_end; - gboolean found; - gboolean from_start = FALSE; - - g_return_val_if_fail (GOSSIP_IS_CHAT_VIEW (view), FALSE); - g_return_val_if_fail (search_criteria != NULL, FALSE); - - priv = GET_PRIV (view); - - buffer = priv->buffer; - - if (G_STR_EMPTY (search_criteria)) { - if (priv->find_mark_previous) { - gtk_text_buffer_get_start_iter (buffer, &iter_at_mark); - - gtk_text_buffer_move_mark (buffer, - priv->find_mark_previous, - &iter_at_mark); - gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view), - priv->find_mark_previous, - 0.0, - TRUE, - 0.0, - 0.0); - gtk_text_buffer_select_range (buffer, - &iter_at_mark, - &iter_at_mark); - } - - return FALSE; - } - - if (new_search) { - from_start = TRUE; - } - - if (priv->find_mark_previous) { - gtk_text_buffer_get_iter_at_mark (buffer, - &iter_at_mark, - priv->find_mark_previous); - } else { - gtk_text_buffer_get_end_iter (buffer, &iter_at_mark); - from_start = TRUE; - } - - priv->find_last_direction = FALSE; - - found = gossip_text_iter_backward_search (&iter_at_mark, - search_criteria, - &iter_match_start, - &iter_match_end, - NULL); - - if (!found) { - gboolean result = FALSE; - - if (from_start) { - return result; - } - - /* Here we wrap around. */ - if (!new_search && !priv->find_wrapped) { - priv->find_wrapped = TRUE; - result = gossip_chat_view_find_previous (view, - search_criteria, - FALSE); - priv->find_wrapped = FALSE; - } - - return result; - } - - /* Set new mark and show on screen */ - if (!priv->find_mark_previous) { - priv->find_mark_previous = gtk_text_buffer_create_mark (buffer, NULL, - &iter_match_start, - TRUE); - } else { - gtk_text_buffer_move_mark (buffer, - priv->find_mark_previous, - &iter_match_start); - } - - if (!priv->find_mark_next) { - priv->find_mark_next = gtk_text_buffer_create_mark (buffer, NULL, - &iter_match_end, - TRUE); - } else { - gtk_text_buffer_move_mark (buffer, - priv->find_mark_next, - &iter_match_end); - } - - gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view), - priv->find_mark_previous, - 0.0, - TRUE, - 0.5, - 0.5); - - gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &iter_match_start); - gtk_text_buffer_move_mark_by_name (buffer, "insert", &iter_match_end); - - return TRUE; -} - -gboolean -gossip_chat_view_find_next (GossipChatView *view, - const gchar *search_criteria, - gboolean new_search) -{ - GossipChatViewPriv *priv; - GtkTextBuffer *buffer; - GtkTextIter iter_at_mark; - GtkTextIter iter_match_start; - GtkTextIter iter_match_end; - gboolean found; - gboolean from_start = FALSE; - - g_return_val_if_fail (GOSSIP_IS_CHAT_VIEW (view), FALSE); - g_return_val_if_fail (search_criteria != NULL, FALSE); - - priv = GET_PRIV (view); - - buffer = priv->buffer; - - if (G_STR_EMPTY (search_criteria)) { - if (priv->find_mark_next) { - gtk_text_buffer_get_start_iter (buffer, &iter_at_mark); - - gtk_text_buffer_move_mark (buffer, - priv->find_mark_next, - &iter_at_mark); - gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view), - priv->find_mark_next, - 0.0, - TRUE, - 0.0, - 0.0); - gtk_text_buffer_select_range (buffer, - &iter_at_mark, - &iter_at_mark); - } - - return FALSE; - } - - if (new_search) { - from_start = TRUE; - } - - if (priv->find_mark_next) { - gtk_text_buffer_get_iter_at_mark (buffer, - &iter_at_mark, - priv->find_mark_next); - } else { - gtk_text_buffer_get_start_iter (buffer, &iter_at_mark); - from_start = TRUE; - } - - priv->find_last_direction = TRUE; - - found = gossip_text_iter_forward_search (&iter_at_mark, - search_criteria, - &iter_match_start, - &iter_match_end, - NULL); - - if (!found) { - gboolean result = FALSE; - - if (from_start) { - return result; - } - - /* Here we wrap around. */ - if (!new_search && !priv->find_wrapped) { - priv->find_wrapped = TRUE; - result = gossip_chat_view_find_next (view, - search_criteria, - FALSE); - priv->find_wrapped = FALSE; - } - - return result; - } - - /* Set new mark and show on screen */ - if (!priv->find_mark_next) { - priv->find_mark_next = gtk_text_buffer_create_mark (buffer, NULL, - &iter_match_end, - TRUE); - } else { - gtk_text_buffer_move_mark (buffer, - priv->find_mark_next, - &iter_match_end); - } - - if (!priv->find_mark_previous) { - priv->find_mark_previous = gtk_text_buffer_create_mark (buffer, NULL, - &iter_match_start, - TRUE); - } else { - gtk_text_buffer_move_mark (buffer, - priv->find_mark_previous, - &iter_match_start); - } - - gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view), - priv->find_mark_next, - 0.0, - TRUE, - 0.5, - 0.5); - - gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &iter_match_start); - gtk_text_buffer_move_mark_by_name (buffer, "insert", &iter_match_end); - - return TRUE; -} - - -void -gossip_chat_view_find_abilities (GossipChatView *view, - const gchar *search_criteria, - gboolean *can_do_previous, - gboolean *can_do_next) -{ - GossipChatViewPriv *priv; - GtkTextBuffer *buffer; - GtkTextIter iter_at_mark; - GtkTextIter iter_match_start; - GtkTextIter iter_match_end; - - g_return_if_fail (GOSSIP_IS_CHAT_VIEW (view)); - g_return_if_fail (search_criteria != NULL); - g_return_if_fail (can_do_previous != NULL && can_do_next != NULL); - - priv = GET_PRIV (view); - - buffer = priv->buffer; - - if (can_do_previous) { - if (priv->find_mark_previous) { - gtk_text_buffer_get_iter_at_mark (buffer, - &iter_at_mark, - priv->find_mark_previous); - } else { - gtk_text_buffer_get_start_iter (buffer, &iter_at_mark); - } - - *can_do_previous = gossip_text_iter_backward_search (&iter_at_mark, - search_criteria, - &iter_match_start, - &iter_match_end, - NULL); - } - - if (can_do_next) { - if (priv->find_mark_next) { - gtk_text_buffer_get_iter_at_mark (buffer, - &iter_at_mark, - priv->find_mark_next); - } else { - gtk_text_buffer_get_start_iter (buffer, &iter_at_mark); - } - - *can_do_next = gossip_text_iter_forward_search (&iter_at_mark, - search_criteria, - &iter_match_start, - &iter_match_end, - NULL); - } -} - -void -gossip_chat_view_highlight (GossipChatView *view, - const gchar *text) -{ - GtkTextBuffer *buffer; - GtkTextIter iter; - GtkTextIter iter_start; - GtkTextIter iter_end; - GtkTextIter iter_match_start; - GtkTextIter iter_match_end; - gboolean found; - - g_return_if_fail (GOSSIP_IS_CHAT_VIEW (view)); - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); - - gtk_text_buffer_get_start_iter (buffer, &iter); - - gtk_text_buffer_get_bounds (buffer, &iter_start, &iter_end); - gtk_text_buffer_remove_tag_by_name (buffer, "highlight", - &iter_start, - &iter_end); - - if (G_STR_EMPTY (text)) { - return; - } - - while (1) { - found = gossip_text_iter_forward_search (&iter, - text, - &iter_match_start, - &iter_match_end, - NULL); - - if (!found) { - break; - } - - gtk_text_buffer_apply_tag_by_name (buffer, "highlight", - &iter_match_start, - &iter_match_end); - - iter = iter_match_end; - gtk_text_iter_forward_char (&iter); - } -} - -void -gossip_chat_view_copy_clipboard (GossipChatView *view) -{ - GtkTextBuffer *buffer; - GtkClipboard *clipboard; - - g_return_if_fail (GOSSIP_IS_CHAT_VIEW (view)); - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); - clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); - - gtk_text_buffer_copy_clipboard (buffer, clipboard); -} - -gboolean -gossip_chat_view_get_irc_style (GossipChatView *view) -{ - GossipChatViewPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CHAT_VIEW (view), FALSE); - - priv = GET_PRIV (view); - - return priv->irc_style; -} - -void -gossip_chat_view_set_irc_style (GossipChatView *view, - gboolean irc_style) -{ - GossipChatViewPriv *priv; - - g_return_if_fail (GOSSIP_IS_CHAT_VIEW (view)); - - priv = GET_PRIV (view); - - priv->irc_style = irc_style; -} - -void -gossip_chat_view_set_margin (GossipChatView *view, - gint margin) -{ - GossipChatViewPriv *priv; - - g_return_if_fail (GOSSIP_IS_CHAT_VIEW (view)); - - priv = GET_PRIV (view); - - g_object_set (view, - "left-margin", margin, - "right-margin", margin, - NULL); -} - -GdkPixbuf * -gossip_chat_view_get_smiley_image (GossipSmiley smiley) -{ - static GdkPixbuf *pixbufs[GOSSIP_SMILEY_COUNT]; - static gboolean inited = FALSE; - - if (!inited) { - gint i; - - for (i = 0; i < GOSSIP_SMILEY_COUNT; i++) { - pixbufs[i] = gossip_pixbuf_from_smiley (i, GTK_ICON_SIZE_MENU); - } - - inited = TRUE; - } - - return pixbufs[smiley]; -} - -const gchar * -gossip_chat_view_get_smiley_text (GossipSmiley smiley) -{ - gint i; - - for (i = 0; i < G_N_ELEMENTS (smileys); i++) { - if (smileys[i].smiley != smiley) { - continue; - } - - return smileys[i].pattern; - } - - return NULL; -} - -GtkWidget * -gossip_chat_view_get_smiley_menu (GCallback callback, - gpointer user_data, - GtkTooltips *tooltips) -{ - GtkWidget *menu; - gint x; - gint y; - gint i; - - g_return_val_if_fail (callback != NULL, NULL); - - menu = gtk_menu_new (); - - for (i = 0, x = 0, y = 0; i < GOSSIP_SMILEY_COUNT; i++) { - GtkWidget *item; - GtkWidget *image; - GdkPixbuf *pixbuf; - const gchar *smiley_text; - - pixbuf = gossip_chat_view_get_smiley_image (i); - if (!pixbuf) { - continue; - } - - image = gtk_image_new_from_pixbuf (pixbuf); - - item = gtk_image_menu_item_new_with_label (""); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); - - gtk_menu_attach (GTK_MENU (menu), item, - x, x + 1, y, y + 1); - - smiley_text = gossip_chat_view_get_smiley_text (i); - - gtk_tooltips_set_tip (tooltips, - item, - smiley_text, - NULL); - - g_object_set_data (G_OBJECT (item), "smiley_text", (gpointer) smiley_text); - g_signal_connect (item, "activate", callback, user_data); - - if (x > 3) { - y++; - x = 0; - } else { - x++; - } - } - - gtk_widget_show_all (menu); - - return menu; -} - -/* FIXME: Do we really need this? Better to do it internally only at setup time, - * we will never change it on the fly. - */ -void -gossip_chat_view_set_is_group_chat (GossipChatView *view, - gboolean is_group_chat) -{ - GossipChatViewPriv *priv; - gboolean theme_rooms = FALSE; - - g_return_if_fail (GOSSIP_IS_CHAT_VIEW (view)); - - priv = GET_PRIV (view); - - priv->is_group_chat = is_group_chat; - - gossip_conf_get_bool (gossip_conf_get (), - GOSSIP_PREFS_CHAT_THEME_CHAT_ROOM, - &theme_rooms); - - if (!theme_rooms && is_group_chat) { - gossip_theme_manager_apply (gossip_theme_manager_get (), - view, - NULL); - } else { - gossip_theme_manager_apply_saved (gossip_theme_manager_get (), - view); - } -} diff --git a/libempathy-gtk/gossip-chat-view.h b/libempathy-gtk/gossip-chat-view.h deleted file mode 100644 index 2a7b1147..00000000 --- a/libempathy-gtk/gossip-chat-view.h +++ /dev/null @@ -1,134 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2002-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Richard Hult - * Martyn Russell - */ - -#ifndef __GOSSIP_CHAT_VIEW_H__ -#define __GOSSIP_CHAT_VIEW_H__ - -#include -#include - -#include -#include - -G_BEGIN_DECLS - -#define GOSSIP_TYPE_CHAT_VIEW (gossip_chat_view_get_type ()) -#define GOSSIP_CHAT_VIEW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOSSIP_TYPE_CHAT_VIEW, GossipChatView)) -#define GOSSIP_CHAT_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GOSSIP_TYPE_CHAT_VIEW, GossipChatViewClass)) -#define GOSSIP_IS_CHAT_VIEW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOSSIP_TYPE_CHAT_VIEW)) -#define GOSSIP_IS_CHAT_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOSSIP_TYPE_CHAT_VIEW)) -#define GOSSIP_CHAT_VIEW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOSSIP_TYPE_CHAT_VIEW, GossipChatViewClass)) - -typedef struct _GossipChatView GossipChatView; -typedef struct _GossipChatViewClass GossipChatViewClass; -typedef struct _GossipChatViewPriv GossipChatViewPriv; - -struct _GossipChatView { - GtkTextView parent; -}; - -struct _GossipChatViewClass { - GtkTextViewClass parent_class; -}; - -typedef enum { - GOSSIP_SMILEY_NORMAL, /* :) */ - GOSSIP_SMILEY_WINK, /* ;) */ - GOSSIP_SMILEY_BIGEYE, /* =) */ - GOSSIP_SMILEY_NOSE, /* :-) */ - GOSSIP_SMILEY_CRY, /* :'( */ - GOSSIP_SMILEY_SAD, /* :( */ - GOSSIP_SMILEY_SCEPTICAL, /* :/ */ - GOSSIP_SMILEY_BIGSMILE, /* :D */ - GOSSIP_SMILEY_INDIFFERENT, /* :| */ - GOSSIP_SMILEY_TOUNGE, /* :p */ - GOSSIP_SMILEY_SHOCKED, /* :o */ - GOSSIP_SMILEY_COOL, /* 8) */ - GOSSIP_SMILEY_SORRY, /* *| */ - GOSSIP_SMILEY_KISS, /* :* */ - GOSSIP_SMILEY_SHUTUP, /* :# */ - GOSSIP_SMILEY_YAWN, /* |O */ - GOSSIP_SMILEY_CONFUSED, /* :$ */ - GOSSIP_SMILEY_ANGEL, /* <) */ - GOSSIP_SMILEY_OOOH, /* :x */ - GOSSIP_SMILEY_LOOKAWAY, /* *) */ - GOSSIP_SMILEY_BLUSH, /* *S */ - GOSSIP_SMILEY_COOLBIGSMILE, /* 8D */ - GOSSIP_SMILEY_ANGRY, /* :@ */ - GOSSIP_SMILEY_BOSS, /* @) */ - GOSSIP_SMILEY_MONKEY, /* #) */ - GOSSIP_SMILEY_SILLY, /* O) */ - GOSSIP_SMILEY_SICK, /* +o( */ - - GOSSIP_SMILEY_COUNT -} GossipSmiley; - -GType gossip_chat_view_get_type (void) G_GNUC_CONST; -GossipChatView *gossip_chat_view_new (void); -void gossip_chat_view_append_message (GossipChatView *view, - GossipMessage *msg); -void gossip_chat_view_append_event (GossipChatView *view, - const gchar *str); -void gossip_chat_view_append_button (GossipChatView *view, - const gchar *message, - GtkWidget *button1, - GtkWidget *button2); -void gossip_chat_view_set_margin (GossipChatView *view, - gint margin); -void gossip_chat_view_scroll (GossipChatView *view, - gboolean allow_scrolling); -void gossip_chat_view_scroll_down (GossipChatView *view); -gboolean gossip_chat_view_get_selection_bounds (GossipChatView *view, - GtkTextIter *start, - GtkTextIter *end); -void gossip_chat_view_clear (GossipChatView *view); -gboolean gossip_chat_view_find_previous (GossipChatView *view, - const gchar *search_criteria, - gboolean new_search); -gboolean gossip_chat_view_find_next (GossipChatView *view, - const gchar *search_criteria, - gboolean new_search); -void gossip_chat_view_find_abilities (GossipChatView *view, - const gchar *search_criteria, - gboolean *can_do_previous, - gboolean *can_do_next); -void gossip_chat_view_highlight (GossipChatView *view, - const gchar *text); -void gossip_chat_view_copy_clipboard (GossipChatView *view); -gboolean gossip_chat_view_get_irc_style (GossipChatView *view); -void gossip_chat_view_set_irc_style (GossipChatView *view, - gboolean irc_style); -void gossip_chat_view_set_margin (GossipChatView *view, - gint margin); -GdkPixbuf * gossip_chat_view_get_smiley_image (GossipSmiley smiley); -const gchar * gossip_chat_view_get_smiley_text (GossipSmiley smiley); -GtkWidget * gossip_chat_view_get_smiley_menu (GCallback callback, - gpointer user_data, - GtkTooltips *tooltips); -void gossip_chat_view_set_is_group_chat (GossipChatView *view, - gboolean is_group_chat); - -G_END_DECLS - -#endif /* __GOSSIP_CHAT_VIEW_H__ */ diff --git a/libempathy-gtk/gossip-chat-window.c b/libempathy-gtk/gossip-chat-window.c deleted file mode 100644 index 854c3142..00000000 --- a/libempathy-gtk/gossip-chat-window.c +++ /dev/null @@ -1,1901 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2003-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Richard Hult - * Martyn Russell - * Geert-Jan Van den Bogaerde - * Xavier Claessens - */ - -#include "config.h" - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gossip-chat-window.h" -#include "empathy-images.h" -//#include "gossip-chat-invite.h" -#include "empathy-contact-dialogs.h" -#include "gossip-log-window.h" -#include "gossip-new-chatroom-dialog.h" -#include "gossip-preferences.h" -#include "gossip-private-chat.h" -#include "gossip-group-chat.h" -//#include "gossip-sound.h" -#include "gossip-ui-utils.h" - -#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CHAT_WINDOW, GossipChatWindowPriv)) - -#define DEBUG_DOMAIN "ChatWindow" - -#define URGENCY_TIMEOUT 60*1000 - -struct _GossipChatWindowPriv { - GossipChatroomManager *chatroom_manager; - GList *chats; - GList *chats_new_msg; - GList *chats_composing; - - GossipChat *current_chat; - - gboolean page_added; - gboolean dnd_same_window; - - guint urgency_timeout_id; - - GtkWidget *dialog; - GtkWidget *notebook; - - GtkTooltips *tooltips; - - /* Menu items. */ - GtkWidget *menu_conv_clear; - GtkWidget *menu_conv_insert_smiley; - GtkWidget *menu_conv_log; - GtkWidget *menu_conv_separator; - GtkWidget *menu_conv_add_contact; - GtkWidget *menu_conv_info; - GtkWidget *menu_conv_close; - - GtkWidget *menu_room; - GtkWidget *menu_room_set_topic; - GtkWidget *menu_room_join_new; - GtkWidget *menu_room_invite; - GtkWidget *menu_room_add; - GtkWidget *menu_room_show_contacts; - - GtkWidget *menu_edit_cut; - GtkWidget *menu_edit_copy; - GtkWidget *menu_edit_paste; - - GtkWidget *menu_tabs_next; - GtkWidget *menu_tabs_prev; - GtkWidget *menu_tabs_left; - GtkWidget *menu_tabs_right; - GtkWidget *menu_tabs_detach; - - guint save_geometry_id; -}; - -static void gossip_chat_window_class_init (GossipChatWindowClass *klass); -static void gossip_chat_window_init (GossipChatWindow *window); -static void gossip_chat_window_finalize (GObject *object); -static void chat_window_accel_cb (GtkAccelGroup *accelgroup, - GObject *object, - guint key, - GdkModifierType mod, - GossipChatWindow *window); -static void chat_window_close_clicked_cb (GtkWidget *button, - GossipChat *chat); -static GtkWidget *chat_window_create_label (GossipChatWindow *window, - GossipChat *chat); -static void chat_window_update_status (GossipChatWindow *window, - GossipChat *chat); -static void chat_window_update_title (GossipChatWindow *window, - GossipChat *chat); -static void chat_window_update_menu (GossipChatWindow *window); -static gboolean chat_window_save_geometry_timeout_cb (GossipChatWindow *window); -static gboolean chat_window_configure_event_cb (GtkWidget *widget, - GdkEventConfigure *event, - GossipChatWindow *window); -static void chat_window_conv_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window); -static void chat_window_clear_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window); -static void chat_window_info_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window); -static void chat_window_add_contact_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window); -static void chat_window_log_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window); -static void chat_window_show_contacts_toggled_cb (GtkWidget *menuitem, - GossipChatWindow *window); -static void chat_window_edit_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window); -static void chat_window_insert_smiley_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window); -static void chat_window_close_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window); -static void chat_window_room_set_topic_activate_cb(GtkWidget *menuitem, - GossipChatWindow *window); -static void chat_window_room_join_new_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window); -static void chat_window_room_invite_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window); -static void chat_window_room_add_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window); -static void chat_window_cut_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window); -static void chat_window_copy_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window); -static void chat_window_paste_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window); -static void chat_window_tabs_left_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window); -static void chat_window_tabs_right_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window); -static void chat_window_detach_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window); -static gboolean chat_window_delete_event_cb (GtkWidget *dialog, - GdkEvent *event, - GossipChatWindow *window); -static void chat_window_status_changed_cb (GossipChat *chat, - GossipChatWindow *window); -static void chat_window_update_tooltip (GossipChatWindow *window, - GossipChat *chat); -static void chat_window_name_changed_cb (GossipChat *chat, - const gchar *name, - GossipChatWindow *window); -static void chat_window_composing_cb (GossipChat *chat, - gboolean is_composing, - GossipChatWindow *window); -static void chat_window_new_message_cb (GossipChat *chat, - GossipMessage *message, - gboolean is_backlog, - GossipChatWindow *window); -static GtkNotebook* chat_window_detach_hook (GtkNotebook *source, - GtkWidget *page, - gint x, - gint y, - gpointer user_data); -static void chat_window_page_switched_cb (GtkNotebook *notebook, - GtkNotebookPage *page, - gint page_num, - GossipChatWindow *window); -static void chat_window_page_reordered_cb (GtkNotebook *notebook, - GtkWidget *widget, - guint page_num, - GossipChatWindow *window); -static void chat_window_page_added_cb (GtkNotebook *notebook, - GtkWidget *child, - guint page_num, - GossipChatWindow *window); -static void chat_window_page_removed_cb (GtkNotebook *notebook, - GtkWidget *child, - guint page_num, - GossipChatWindow *window); -static gboolean chat_window_focus_in_event_cb (GtkWidget *widget, - GdkEvent *event, - GossipChatWindow *window); -static void chat_window_drag_data_received (GtkWidget *widget, - GdkDragContext *context, - int x, - int y, - GtkSelectionData *selection, - guint info, - guint time, - GossipChatWindow *window); -static void chat_window_set_urgency_hint (GossipChatWindow *window, - gboolean urgent); - - -static GList *chat_windows = NULL; - -static const guint tab_accel_keys[] = { - GDK_1, GDK_2, GDK_3, GDK_4, GDK_5, - GDK_6, GDK_7, GDK_8, GDK_9, GDK_0 -}; - -typedef enum { - DND_DRAG_TYPE_CONTACT_ID, - DND_DRAG_TYPE_TAB -} DndDragType; - -static const GtkTargetEntry drag_types_dest[] = { - { "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID }, - { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, DND_DRAG_TYPE_TAB }, -}; - -G_DEFINE_TYPE (GossipChatWindow, gossip_chat_window, G_TYPE_OBJECT); - -static void -gossip_chat_window_class_init (GossipChatWindowClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = gossip_chat_window_finalize; - - g_type_class_add_private (object_class, sizeof (GossipChatWindowPriv)); - - /* Set up a style for the close button with no focus padding. */ - gtk_rc_parse_string ( - "style \"gossip-close-button-style\"\n" - "{\n" - " GtkWidget::focus-padding = 0\n" - " xthickness = 0\n" - " ythickness = 0\n" - "}\n" - "widget \"*.gossip-close-button\" style \"gossip-close-button-style\""); - - gtk_notebook_set_window_creation_hook (chat_window_detach_hook, NULL, NULL); -} - -static void -gossip_chat_window_init (GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - GladeXML *glade; - GtkAccelGroup *accel_group; - GtkWidget *image; - GClosure *closure; - GtkWidget *menu_conv; - GtkWidget *menu; - gint i; - GtkWidget *chat_vbox; - - priv = GET_PRIV (window); - - priv->tooltips = g_object_ref_sink (gtk_tooltips_new ()); - - glade = gossip_glade_get_file ("gossip-chat.glade", - "chat_window", - NULL, - "chat_window", &priv->dialog, - "chat_vbox", &chat_vbox, - "menu_conv", &menu_conv, - "menu_conv_clear", &priv->menu_conv_clear, - "menu_conv_insert_smiley", &priv->menu_conv_insert_smiley, - "menu_conv_log", &priv->menu_conv_log, - "menu_conv_separator", &priv->menu_conv_separator, - "menu_conv_add_contact", &priv->menu_conv_add_contact, - "menu_conv_info", &priv->menu_conv_info, - "menu_conv_close", &priv->menu_conv_close, - "menu_room", &priv->menu_room, - "menu_room_set_topic", &priv->menu_room_set_topic, - "menu_room_join_new", &priv->menu_room_join_new, - "menu_room_invite", &priv->menu_room_invite, - "menu_room_add", &priv->menu_room_add, - "menu_room_show_contacts", &priv->menu_room_show_contacts, - "menu_edit_cut", &priv->menu_edit_cut, - "menu_edit_copy", &priv->menu_edit_copy, - "menu_edit_paste", &priv->menu_edit_paste, - "menu_tabs_next", &priv->menu_tabs_next, - "menu_tabs_prev", &priv->menu_tabs_prev, - "menu_tabs_left", &priv->menu_tabs_left, - "menu_tabs_right", &priv->menu_tabs_right, - "menu_tabs_detach", &priv->menu_tabs_detach, - NULL); - - gossip_glade_connect (glade, - window, - "chat_window", "configure-event", chat_window_configure_event_cb, - "menu_conv", "activate", chat_window_conv_activate_cb, - "menu_conv_clear", "activate", chat_window_clear_activate_cb, - "menu_conv_log", "activate", chat_window_log_activate_cb, - "menu_conv_add_contact", "activate", chat_window_add_contact_activate_cb, - "menu_conv_info", "activate", chat_window_info_activate_cb, - "menu_conv_close", "activate", chat_window_close_activate_cb, - "menu_room_set_topic", "activate", chat_window_room_set_topic_activate_cb, - "menu_room_join_new", "activate", chat_window_room_join_new_activate_cb, - "menu_room_invite", "activate", chat_window_room_invite_activate_cb, - "menu_room_add", "activate", chat_window_room_add_activate_cb, - "menu_edit", "activate", chat_window_edit_activate_cb, - "menu_edit_cut", "activate", chat_window_cut_activate_cb, - "menu_edit_copy", "activate", chat_window_copy_activate_cb, - "menu_edit_paste", "activate", chat_window_paste_activate_cb, - "menu_tabs_left", "activate", chat_window_tabs_left_activate_cb, - "menu_tabs_right", "activate", chat_window_tabs_right_activate_cb, - "menu_tabs_detach", "activate", chat_window_detach_activate_cb, - NULL); - - g_object_unref (glade); - - /* Set up chatroom manager */ - priv->chatroom_manager = gossip_chatroom_manager_new (); - g_signal_connect_swapped (priv->chatroom_manager, "chatroom-added", - G_CALLBACK (chat_window_update_menu), - window); - g_signal_connect_swapped (priv->chatroom_manager, "chatroom-removed", - G_CALLBACK (chat_window_update_menu), - window); - - priv->notebook = gtk_notebook_new (); - gtk_notebook_set_group_id (GTK_NOTEBOOK (priv->notebook), 1); - gtk_box_pack_start (GTK_BOX (chat_vbox), priv->notebook, TRUE, TRUE, 0); - gtk_widget_show (priv->notebook); - - /* Set up accels */ - accel_group = gtk_accel_group_new (); - gtk_window_add_accel_group (GTK_WINDOW (priv->dialog), accel_group); - - for (i = 0; i < G_N_ELEMENTS (tab_accel_keys); i++) { - closure = g_cclosure_new (G_CALLBACK (chat_window_accel_cb), - window, - NULL); - gtk_accel_group_connect (accel_group, - tab_accel_keys[i], - GDK_MOD1_MASK, - 0, - closure); - } - - g_object_unref (accel_group); - - /* Set the contact information menu item image to the Gossip - * stock image - */ - image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (priv->menu_conv_info)); - gtk_image_set_from_icon_name (GTK_IMAGE (image), - EMPATHY_IMAGE_CONTACT_INFORMATION, - GTK_ICON_SIZE_MENU); - - /* Set up smiley menu */ - menu = gossip_chat_view_get_smiley_menu ( - G_CALLBACK (chat_window_insert_smiley_activate_cb), - window, - priv->tooltips); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (priv->menu_conv_insert_smiley), menu); - - /* Set up signals we can't do with glade since we may need to - * block/unblock them at some later stage. - */ - - g_signal_connect (priv->dialog, - "delete_event", - G_CALLBACK (chat_window_delete_event_cb), - window); - - g_signal_connect (priv->menu_room_show_contacts, - "toggled", - G_CALLBACK (chat_window_show_contacts_toggled_cb), - window); - - g_signal_connect_swapped (priv->menu_tabs_prev, - "activate", - G_CALLBACK (gtk_notebook_prev_page), - priv->notebook); - g_signal_connect_swapped (priv->menu_tabs_next, - "activate", - G_CALLBACK (gtk_notebook_next_page), - priv->notebook); - - g_signal_connect (priv->dialog, - "focus_in_event", - G_CALLBACK (chat_window_focus_in_event_cb), - window); - g_signal_connect_after (priv->notebook, - "switch_page", - G_CALLBACK (chat_window_page_switched_cb), - window); - g_signal_connect (priv->notebook, - "page_reordered", - G_CALLBACK (chat_window_page_reordered_cb), - window); - g_signal_connect (priv->notebook, - "page_added", - G_CALLBACK (chat_window_page_added_cb), - window); - g_signal_connect (priv->notebook, - "page_removed", - G_CALLBACK (chat_window_page_removed_cb), - window); - - /* Set up drag and drop */ - gtk_drag_dest_set (GTK_WIDGET (priv->notebook), - GTK_DEST_DEFAULT_ALL, - drag_types_dest, - G_N_ELEMENTS (drag_types_dest), - GDK_ACTION_MOVE); - - g_signal_connect (priv->notebook, - "drag-data-received", - G_CALLBACK (chat_window_drag_data_received), - window); - - chat_windows = g_list_prepend (chat_windows, window); - - /* Set up private details */ - priv->chats = NULL; - priv->chats_new_msg = NULL; - priv->chats_composing = NULL; - priv->current_chat = NULL; -} - -/* Returns the window to open a new tab in if there is only one window - * visble, otherwise, returns NULL indicating that a new window should - * be added. - */ -GossipChatWindow * -gossip_chat_window_get_default (void) -{ - GList *l; - gboolean separate_windows = TRUE; - - gossip_conf_get_bool (gossip_conf_get (), - GOSSIP_PREFS_UI_SEPARATE_CHAT_WINDOWS, - &separate_windows); - - if (separate_windows) { - /* Always create a new window */ - return NULL; - } - - for (l = chat_windows; l; l = l->next) { - GossipChatWindow *chat_window; - GtkWidget *dialog; - GdkWindow *window; - gboolean visible; - - chat_window = l->data; - - dialog = gossip_chat_window_get_dialog (chat_window); - window = dialog->window; - - g_object_get (dialog, - "visible", &visible, - NULL); - - visible = visible && !(gdk_window_get_state (window) & GDK_WINDOW_STATE_ICONIFIED); - - if (visible) { - /* Found a visible window on this desktop */ - return chat_window; - } - } - - return NULL; -} - -static void -gossip_chat_window_finalize (GObject *object) -{ - GossipChatWindow *window; - GossipChatWindowPriv *priv; - - window = GOSSIP_CHAT_WINDOW (object); - priv = GET_PRIV (window); - - gossip_debug (DEBUG_DOMAIN, "Finalized: %p", object); - - if (priv->save_geometry_id != 0) { - g_source_remove (priv->save_geometry_id); - } - - if (priv->urgency_timeout_id != 0) { - g_source_remove (priv->urgency_timeout_id); - } - - chat_windows = g_list_remove (chat_windows, window); - gtk_widget_destroy (priv->dialog); - g_object_unref (priv->tooltips); - - g_signal_handlers_disconnect_by_func (priv->chatroom_manager, - chat_window_update_menu, - window); - g_object_unref (priv->chatroom_manager); - - G_OBJECT_CLASS (gossip_chat_window_parent_class)->finalize (object); -} - -static void -chat_window_accel_cb (GtkAccelGroup *accelgroup, - GObject *object, - guint key, - GdkModifierType mod, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - gint num = -1; - gint i; - - priv = GET_PRIV (window); - - for (i = 0; i < G_N_ELEMENTS (tab_accel_keys); i++) { - if (tab_accel_keys[i] == key) { - num = i; - break; - } - } - - if (num != -1) { - gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), num); - } -} - -static void -chat_window_close_clicked_cb (GtkWidget *button, - GossipChat *chat) -{ - GossipChatWindow *window; - - window = gossip_chat_get_window (chat); - gossip_chat_window_remove_chat (window, chat); -} - -static void -chat_window_close_button_style_set_cb (GtkWidget *button, - GtkStyle *previous_style, - gpointer user_data) -{ - gint h, w; - - gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (button), - GTK_ICON_SIZE_MENU, &w, &h); - - gtk_widget_set_size_request (button, w, h); -} - -static GtkWidget * -chat_window_create_label (GossipChatWindow *window, - GossipChat *chat) -{ - GossipChatWindowPriv *priv; - GtkWidget *hbox; - GtkWidget *name_label; - GtkWidget *status_image; - GtkWidget *close_button; - GtkWidget *close_image; - GtkWidget *event_box; - GtkWidget *event_box_hbox; - PangoAttrList *attr_list; - PangoAttribute *attr; - - priv = GET_PRIV (window); - - /* The spacing between the button and the label. */ - hbox = gtk_hbox_new (FALSE, 0); - - event_box = gtk_event_box_new (); - gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE); - - name_label = gtk_label_new (gossip_chat_get_name (chat)); - gtk_label_set_ellipsize (GTK_LABEL (name_label), PANGO_ELLIPSIZE_END); - - attr_list = pango_attr_list_new (); - attr = pango_attr_scale_new (1/1.2); - attr->start_index = 0; - attr->end_index = -1; - pango_attr_list_insert (attr_list, attr); - gtk_label_set_attributes (GTK_LABEL (name_label), attr_list); - pango_attr_list_unref (attr_list); - - gtk_misc_set_padding (GTK_MISC (name_label), 2, 0); - gtk_misc_set_alignment (GTK_MISC (name_label), 0.0, 0.5); - g_object_set_data (G_OBJECT (chat), "chat-window-tab-label", name_label); - - status_image = gtk_image_new (); - - /* Spacing between the icon and label. */ - event_box_hbox = gtk_hbox_new (FALSE, 0); - - gtk_box_pack_start (GTK_BOX (event_box_hbox), status_image, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (event_box_hbox), name_label, TRUE, TRUE, 0); - - g_object_set_data (G_OBJECT (chat), "chat-window-tab-image", status_image); - g_object_set_data (G_OBJECT (chat), "chat-window-tab-tooltip-widget", event_box); - - close_button = gtk_button_new (); - gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE); - - /* We don't want focus/keynav for the button to avoid clutter, and - * Ctrl-W works anyway. - */ - GTK_WIDGET_UNSET_FLAGS (close_button, GTK_CAN_FOCUS); - GTK_WIDGET_UNSET_FLAGS (close_button, GTK_CAN_DEFAULT); - - /* Set the name to make the special rc style match. */ - gtk_widget_set_name (close_button, "gossip-close-button"); - - close_image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU); - - gtk_container_add (GTK_CONTAINER (close_button), close_image); - - gtk_container_add (GTK_CONTAINER (event_box), event_box_hbox); - gtk_box_pack_start (GTK_BOX (hbox), event_box, TRUE, TRUE, 0); - gtk_box_pack_end (GTK_BOX (hbox), close_button, FALSE, FALSE, 0); - - /* React to theme changes and also used to setup the initial size - * correctly. - */ - g_signal_connect (close_button, - "style-set", - G_CALLBACK (chat_window_close_button_style_set_cb), - chat); - - g_signal_connect (close_button, - "clicked", - G_CALLBACK (chat_window_close_clicked_cb), - chat); - - /* Set up tooltip */ - chat_window_update_tooltip (window, chat); - - gtk_widget_show_all (hbox); - - return hbox; -} - -static void -chat_window_update_status (GossipChatWindow *window, - GossipChat *chat) -{ - GossipChatWindowPriv *priv; - GtkImage *image; - const gchar *icon_name = NULL; - - priv = GET_PRIV (window); - - if (g_list_find (priv->chats_new_msg, chat)) { - icon_name = EMPATHY_IMAGE_MESSAGE; - } - else if (g_list_find (priv->chats_composing, chat)) { - icon_name = EMPATHY_IMAGE_TYPING; - } - else { - icon_name = gossip_chat_get_status_icon_name (chat); - } - image = g_object_get_data (G_OBJECT (chat), "chat-window-tab-image"); - gtk_image_set_from_icon_name (image, icon_name, GTK_ICON_SIZE_MENU); - - chat_window_update_title (window, chat); - chat_window_update_tooltip (window, chat); -} - -static void -chat_window_update_title (GossipChatWindow *window, - GossipChat *chat) -{ - GossipChatWindowPriv *priv; - const gchar *str; - gchar *title; - gint n_chats; - - priv = GET_PRIV (window); - - n_chats = g_list_length (priv->chats); - if (n_chats == 1) { - if (priv->chats_new_msg) { - title = g_strdup_printf ( - "%s - %s", - gossip_chat_get_name (priv->current_chat), - _("New Message")); - } - else if (gossip_chat_is_group_chat (priv->current_chat)) { - title = g_strdup_printf ( - "%s - %s", - gossip_chat_get_name (priv->current_chat), - _("Chat Room")); - } else { - title = g_strdup_printf ( - "%s - %s", - gossip_chat_get_name (priv->current_chat), - _("Conversation")); - } - } else { - if (priv->chats_new_msg) { - GString *names; - GList *l; - gint n_messages = 0; - - names = g_string_new (NULL); - - for (l = priv->chats_new_msg; l; l = l->next) { - n_messages++; - g_string_append (names, - gossip_chat_get_name (l->data)); - if (l->next) { - g_string_append (names, ", "); - } - } - - str = ngettext ("New Message", "New Messages", n_messages); - title = g_strdup_printf ("%s - %s", names->str, str); - g_string_free (names, TRUE); - } else { - str = ngettext ("Conversation", "Conversations (%d)", n_chats); - title = g_strdup_printf (str, n_chats); - } - } - - gtk_window_set_title (GTK_WINDOW (priv->dialog), title); - g_free (title); - - if (priv->chats_new_msg) { - gtk_window_set_icon_name (GTK_WINDOW (priv->dialog), - EMPATHY_IMAGE_MESSAGE); - } else { - gtk_window_set_icon_name (GTK_WINDOW (priv->dialog), NULL); - } -} - -static void -chat_window_update_menu (GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - gboolean first_page; - gboolean last_page; - gboolean is_connected; - gint num_pages; - gint page_num; - - priv = GET_PRIV (window); - - /* Notebook pages */ - page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)); - num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook)); - first_page = (page_num == 0); - last_page = (page_num == (num_pages - 1)); - - gtk_widget_set_sensitive (priv->menu_tabs_next, !last_page); - gtk_widget_set_sensitive (priv->menu_tabs_prev, !first_page); - gtk_widget_set_sensitive (priv->menu_tabs_detach, num_pages > 1); - gtk_widget_set_sensitive (priv->menu_tabs_left, !first_page); - gtk_widget_set_sensitive (priv->menu_tabs_right, !last_page); - - is_connected = gossip_chat_is_connected (priv->current_chat); - - if (gossip_chat_is_group_chat (priv->current_chat)) { - GossipGroupChat *group_chat; - GossipChatroom *chatroom; - gboolean show_contacts; - - group_chat = GOSSIP_GROUP_CHAT (priv->current_chat); - - /* Show / Hide widgets */ - gtk_widget_show (priv->menu_room); - - gtk_widget_hide (priv->menu_conv_add_contact); - gtk_widget_hide (priv->menu_conv_info); - gtk_widget_hide (priv->menu_conv_separator); - - /* Can we add this room to our favourites and are we - * connected to the room? - */ - chatroom = gossip_chatroom_manager_find (priv->chatroom_manager, - priv->current_chat->account, - gossip_chat_get_id (priv->current_chat)); - - gtk_widget_set_sensitive (priv->menu_room_add, chatroom == NULL); - gtk_widget_set_sensitive (priv->menu_conv_insert_smiley, is_connected); - gtk_widget_set_sensitive (priv->menu_room_join_new, is_connected); - gtk_widget_set_sensitive (priv->menu_room_invite, is_connected); - - /* We need to block the signal here because all we are - * really trying to do is check or uncheck the menu - * item. If we don't do this we get funny behaviour - * with 2 or more group chat windows where showing - * contacts doesn't do anything. - */ - show_contacts = gossip_group_chat_get_show_contacts (group_chat); - - g_signal_handlers_block_by_func (priv->menu_room_show_contacts, - chat_window_show_contacts_toggled_cb, - window); - - g_object_set (priv->menu_room_show_contacts, - "active", show_contacts, - NULL); - - g_signal_handlers_unblock_by_func (priv->menu_room_show_contacts, - chat_window_show_contacts_toggled_cb, - window); - } else { - GossipPrivateChat *chat; - GossipSubscription subscription; - GossipContact *contact; - - chat = GOSSIP_PRIVATE_CHAT (priv->current_chat); - - /* Show / Hide widgets */ - gtk_widget_hide (priv->menu_room); - - contact = gossip_private_chat_get_contact (chat); - subscription = gossip_contact_get_subscription (contact); - if (!(subscription & GOSSIP_SUBSCRIPTION_FROM)) { - gtk_widget_show (priv->menu_conv_add_contact); - } else { - gtk_widget_hide (priv->menu_conv_add_contact); - } - - gtk_widget_show (priv->menu_conv_separator); - gtk_widget_show (priv->menu_conv_info); - - /* Are we connected? */ - gtk_widget_set_sensitive (priv->menu_conv_insert_smiley, is_connected); - gtk_widget_set_sensitive (priv->menu_conv_add_contact, is_connected); - gtk_widget_set_sensitive (priv->menu_conv_info, is_connected); - } -} - -static void -chat_window_insert_smiley_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - GossipChat *chat; - GtkTextBuffer *buffer; - GtkTextIter iter; - const gchar *smiley; - - priv = GET_PRIV (window); - - chat = priv->current_chat; - - smiley = g_object_get_data (G_OBJECT (menuitem), "smiley_text"); - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); - gtk_text_buffer_get_end_iter (buffer, &iter); - gtk_text_buffer_insert (buffer, &iter, - smiley, -1); -} - -static void -chat_window_clear_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - - priv = GET_PRIV (window); - - gossip_chat_clear (priv->current_chat); -} - -static void -chat_window_add_contact_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - //GossipContact *contact; - - priv = GET_PRIV (window); - - //contact = gossip_chat_get_contact (priv->current_chat); - - // FIXME: gossip_add_contact_dialog_show (NULL, contact); -} - -static void -chat_window_log_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - - priv = GET_PRIV (window); - - gossip_log_window_show (priv->current_chat->account, - gossip_chat_get_id (priv->current_chat), - gossip_chat_is_group_chat (priv->current_chat), - GTK_WINDOW (priv->dialog)); -} - -static void -chat_window_info_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - GossipContact *contact; - - priv = GET_PRIV (window); - - contact = gossip_private_chat_get_contact (GOSSIP_PRIVATE_CHAT (priv->current_chat)); - - empathy_contact_information_dialog_show (contact, - GTK_WINDOW (priv->dialog), - FALSE); -} - -static gboolean -chat_window_save_geometry_timeout_cb (GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - gint x, y, w, h; - - priv = GET_PRIV (window); - - gtk_window_get_size (GTK_WINDOW (priv->dialog), &w, &h); - gtk_window_get_position (GTK_WINDOW (priv->dialog), &x, &y); - - gossip_chat_save_geometry (priv->current_chat, x, y, w, h); - - priv->save_geometry_id = 0; - - return FALSE; -} - -static gboolean -chat_window_configure_event_cb (GtkWidget *widget, - GdkEventConfigure *event, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - - priv = GET_PRIV (window); - - /* Only save geometry information if there is ONE chat visible. */ - if (g_list_length (priv->chats) > 1) { - return FALSE; - } - - if (priv->save_geometry_id != 0) { - g_source_remove (priv->save_geometry_id); - } - - priv->save_geometry_id = - g_timeout_add (500, - (GSourceFunc) chat_window_save_geometry_timeout_cb, - window); - - return FALSE; -} - -static void -chat_window_conv_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - EmpathyLogManager *manager; - gboolean log_exists = FALSE; - - priv = GET_PRIV (window); - - manager = empathy_log_manager_new (); - log_exists = empathy_log_manager_exists (manager, - priv->current_chat->account, - gossip_chat_get_id (priv->current_chat), - gossip_chat_is_group_chat (priv->current_chat)); - g_object_unref (manager); - - gtk_widget_set_sensitive (priv->menu_conv_log, log_exists); -} - -static void -chat_window_show_contacts_toggled_cb (GtkWidget *menuitem, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - gboolean show; - - priv = GET_PRIV (window); - - g_return_if_fail (priv->current_chat != NULL); - - show = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (priv->menu_room_show_contacts)); - gossip_group_chat_set_show_contacts (GOSSIP_GROUP_CHAT (priv->current_chat), show); -} - -static void -chat_window_close_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - - priv = GET_PRIV (window); - - g_return_if_fail (priv->current_chat != NULL); - - gossip_chat_window_remove_chat (window, priv->current_chat); -} - -static void -chat_window_room_set_topic_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - - priv = GET_PRIV (window); - - if (gossip_chat_is_group_chat (priv->current_chat)) { - GossipGroupChat *group_chat; - - group_chat = GOSSIP_GROUP_CHAT (priv->current_chat); - gossip_group_chat_set_topic (group_chat); - } -} - -static void -chat_window_room_join_new_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - - priv = GET_PRIV (window); - - gossip_new_chatroom_dialog_show (GTK_WINDOW (priv->dialog)); -} - -static void -chat_window_room_invite_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window) -{ -/* FIXME: - GossipChatWindowPriv *priv; - GossipContact *own_contact; - GossipChatroomId id = 0; - - priv = GET_PRIV (window); - own_contact = gossip_chat_get_own_contact (priv->current_chat); - - if (gossip_chat_is_group_chat (priv->current_chat)) { - GossipGroupChat *group_chat; - - group_chat = GOSSIP_GROUP_CHAT (priv->current_chat); - id = gossip_group_chat_get_chatroom_id (group_chat); - } - - gossip_chat_invite_dialog_show (own_contact, id); -*/ -} - -static void -chat_window_room_add_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - GossipChatroomManager *manager; - GossipChatroom *chatroom; - - priv = GET_PRIV (window); - - g_return_if_fail (priv->current_chat != NULL); - - if (!gossip_chat_is_group_chat (priv->current_chat)) { - return; - } - - chatroom = gossip_chatroom_new_full (priv->current_chat->account, - gossip_chat_get_id (priv->current_chat), - gossip_chat_get_name (priv->current_chat), - FALSE); - - manager = gossip_chatroom_manager_new (); - gossip_chatroom_manager_add (manager, chatroom); - chat_window_update_menu (window); - - g_object_unref (chatroom); - g_object_unref (manager); -} - -static void -chat_window_edit_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - GtkClipboard *clipboard; - GtkTextBuffer *buffer; - gboolean text_available; - - priv = GET_PRIV (window); - - g_return_if_fail (priv->current_chat != NULL); - - if (!gossip_chat_is_connected (priv->current_chat)) { - gtk_widget_set_sensitive (priv->menu_edit_copy, FALSE); - gtk_widget_set_sensitive (priv->menu_edit_cut, FALSE); - gtk_widget_set_sensitive (priv->menu_edit_paste, FALSE); - return; - } - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->current_chat->input_text_view)); - if (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL)) { - gtk_widget_set_sensitive (priv->menu_edit_copy, TRUE); - gtk_widget_set_sensitive (priv->menu_edit_cut, TRUE); - } else { - gboolean selection; - - selection = gossip_chat_view_get_selection_bounds (priv->current_chat->view, - NULL, NULL); - - gtk_widget_set_sensitive (priv->menu_edit_cut, FALSE); - gtk_widget_set_sensitive (priv->menu_edit_copy, selection); - } - - clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); - text_available = gtk_clipboard_wait_is_text_available (clipboard); - gtk_widget_set_sensitive (priv->menu_edit_paste, text_available); -} - -static void -chat_window_cut_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - - g_return_if_fail (GOSSIP_IS_CHAT_WINDOW (window)); - - priv = GET_PRIV (window); - - gossip_chat_cut (priv->current_chat); -} - -static void -chat_window_copy_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - - g_return_if_fail (GOSSIP_IS_CHAT_WINDOW (window)); - - priv = GET_PRIV (window); - - gossip_chat_copy (priv->current_chat); -} - -static void -chat_window_paste_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - - g_return_if_fail (GOSSIP_IS_CHAT_WINDOW (window)); - - priv = GET_PRIV (window); - - gossip_chat_paste (priv->current_chat); -} - -static void -chat_window_tabs_left_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - GossipChat *chat; - gint index; - - priv = GET_PRIV (window); - - chat = priv->current_chat; - index = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)); - if (index <= 0) { - return; - } - - gtk_notebook_reorder_child (GTK_NOTEBOOK (priv->notebook), - gossip_chat_get_widget (chat), - index - 1); - - chat_window_update_menu (window); - chat_window_update_status (window, chat); -} - -static void -chat_window_tabs_right_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - GossipChat *chat; - gint index; - - priv = GET_PRIV (window); - - chat = priv->current_chat; - index = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)); - - gtk_notebook_reorder_child (GTK_NOTEBOOK (priv->notebook), - gossip_chat_get_widget (chat), - index + 1); - - chat_window_update_menu (window); - chat_window_update_status (window, chat); -} - -static void -chat_window_detach_activate_cb (GtkWidget *menuitem, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - GossipChatWindow *new_window; - GossipChat *chat; - - priv = GET_PRIV (window); - - chat = priv->current_chat; - new_window = gossip_chat_window_new (); - - gossip_chat_window_move_chat (window, new_window, chat); - - priv = GET_PRIV (new_window); - gtk_widget_show (priv->dialog); -} - -static gboolean -chat_window_delete_event_cb (GtkWidget *dialog, - GdkEvent *event, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - GList *list; - GList *l; - - priv = GET_PRIV (window); - - gossip_debug (DEBUG_DOMAIN, "Delete event received"); - - list = g_list_copy (priv->chats); - - for (l = list; l; l = l->next) { - gossip_chat_window_remove_chat (window, l->data); - } - - g_list_free (list); - - return TRUE; -} - -static void -chat_window_status_changed_cb (GossipChat *chat, - GossipChatWindow *window) -{ - chat_window_update_menu (window); - chat_window_update_status (window, chat); -} - -static void -chat_window_update_tooltip (GossipChatWindow *window, - GossipChat *chat) -{ - GossipChatWindowPriv *priv; - GtkWidget *widget; - gchar *current_tooltip; - gchar *str; - - priv = GET_PRIV (window); - - current_tooltip = gossip_chat_get_tooltip (chat); - - if (g_list_find (priv->chats_composing, chat)) { - str = g_strconcat (current_tooltip, "\n", _("Typing a message."), NULL); - g_free (current_tooltip); - } else { - str = current_tooltip; - } - - widget = g_object_get_data (G_OBJECT (chat), "chat-window-tab-tooltip-widget"); - gtk_tooltips_set_tip (priv->tooltips, - widget, - str, - NULL); - - g_free (str); -} - -static void -chat_window_name_changed_cb (GossipChat *chat, - const gchar *name, - GossipChatWindow *window) -{ - GtkLabel *label; - - label = g_object_get_data (G_OBJECT (chat), "chat-window-tab-label"); - - gtk_label_set_text (label, name); -} - -static void -chat_window_composing_cb (GossipChat *chat, - gboolean is_composing, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - - priv = GET_PRIV (window); - - if (is_composing && !g_list_find (priv->chats_composing, chat)) { - priv->chats_composing = g_list_prepend (priv->chats_composing, chat); - } else { - priv->chats_composing = g_list_remove (priv->chats_composing, chat); - } - - chat_window_update_status (window, chat); -} - -static void -chat_window_new_message_cb (GossipChat *chat, - GossipMessage *message, - gboolean is_backlog, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - gboolean has_focus; - gboolean needs_urgency; - - priv = GET_PRIV (window); - - has_focus = gossip_chat_window_has_focus (window); - - if (has_focus && priv->current_chat == chat) { - gossip_debug (DEBUG_DOMAIN, "New message, we have focus"); - return; - } - - gossip_debug (DEBUG_DOMAIN, "New message, no focus"); - - needs_urgency = FALSE; - if (gossip_chat_is_group_chat (chat)) { - if (!is_backlog && - gossip_chat_should_highlight_nick (message)) { - gossip_debug (DEBUG_DOMAIN, "Highlight this nick"); - needs_urgency = TRUE; - } - } else { - needs_urgency = TRUE; - } - - if (needs_urgency && !has_focus) { - chat_window_set_urgency_hint (window, TRUE); - } - - if (!is_backlog && - !g_list_find (priv->chats_new_msg, chat)) { - priv->chats_new_msg = g_list_prepend (priv->chats_new_msg, chat); - chat_window_update_status (window, chat); - } -} - -static GtkNotebook * -chat_window_detach_hook (GtkNotebook *source, - GtkWidget *page, - gint x, - gint y, - gpointer user_data) -{ - GossipChatWindowPriv *priv; - GossipChatWindow *window, *new_window; - GossipChat *chat; - - chat = g_object_get_data (G_OBJECT (page), "chat"); - window = gossip_chat_get_window (chat); - - new_window = gossip_chat_window_new (); - priv = GET_PRIV (new_window); - - gossip_debug (DEBUG_DOMAIN, "Detach hook called"); - - gossip_chat_window_move_chat (window, new_window, chat); - - gtk_window_move (GTK_WINDOW (priv->dialog), x, y); - gtk_widget_show (priv->dialog); - - return NULL; -} - -static void -chat_window_page_switched_cb (GtkNotebook *notebook, - GtkNotebookPage *page, - gint page_num, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - GossipChat *chat; - GtkWidget *child; - - gossip_debug (DEBUG_DOMAIN, "Page switched"); - - priv = GET_PRIV (window); - - child = gtk_notebook_get_nth_page (notebook, page_num); - chat = g_object_get_data (G_OBJECT (child), "chat"); - - if (priv->page_added) { - priv->page_added = FALSE; - gossip_chat_scroll_down (chat); - } - else if (priv->current_chat == chat) { - return; - } - - priv->current_chat = chat; - priv->chats_new_msg = g_list_remove (priv->chats_new_msg, chat); - - chat_window_update_menu (window); - chat_window_update_status (window, chat); -} - -static void -chat_window_page_reordered_cb (GtkNotebook *notebook, - GtkWidget *widget, - guint page_num, - GossipChatWindow *window) -{ - gossip_debug (DEBUG_DOMAIN, "Page reordered"); - - chat_window_update_menu (window); -} - -static void -chat_window_page_added_cb (GtkNotebook *notebook, - GtkWidget *child, - guint page_num, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - GossipChat *chat; - - priv = GET_PRIV (window); - - /* If we just received DND to the same window, we don't want - * to do anything here like removing the tab and then readding - * it, so we return here and in "page-added". - */ - if (priv->dnd_same_window) { - gossip_debug (DEBUG_DOMAIN, "Page added (back to the same window)"); - priv->dnd_same_window = FALSE; - return; - } - - gossip_debug (DEBUG_DOMAIN, "Page added"); - - /* Get chat object */ - chat = g_object_get_data (G_OBJECT (child), "chat"); - - /* Set the chat window */ - gossip_chat_set_window (chat, window); - - /* Connect chat signals for this window */ - g_signal_connect (chat, "status-changed", - G_CALLBACK (chat_window_status_changed_cb), - window); - g_signal_connect (chat, "name-changed", - G_CALLBACK (chat_window_name_changed_cb), - window); - g_signal_connect (chat, "composing", - G_CALLBACK (chat_window_composing_cb), - window); - g_signal_connect (chat, "new-message", - G_CALLBACK (chat_window_new_message_cb), - window); - - /* Set flag so we know to perform some special operations on - * switch page due to the new page being added. - */ - priv->page_added = TRUE; - - /* Get list of chats up to date */ - priv->chats = g_list_append (priv->chats, chat); -} - -static void -chat_window_page_removed_cb (GtkNotebook *notebook, - GtkWidget *child, - guint page_num, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - GossipChat *chat; - - priv = GET_PRIV (window); - - /* If we just received DND to the same window, we don't want - * to do anything here like removing the tab and then readding - * it, so we return here and in "page-added". - */ - if (priv->dnd_same_window) { - gossip_debug (DEBUG_DOMAIN, "Page removed (and will be readded to same window)"); - return; - } - - gossip_debug (DEBUG_DOMAIN, "Page removed"); - - /* Get chat object */ - chat = g_object_get_data (G_OBJECT (child), "chat"); - - /* Unset the window associated with a chat */ - gossip_chat_set_window (chat, NULL); - - /* Disconnect all signal handlers for this chat and this window */ - g_signal_handlers_disconnect_by_func (chat, - G_CALLBACK (chat_window_status_changed_cb), - window); - g_signal_handlers_disconnect_by_func (chat, - G_CALLBACK (chat_window_name_changed_cb), - window); - g_signal_handlers_disconnect_by_func (chat, - G_CALLBACK (chat_window_composing_cb), - window); - g_signal_handlers_disconnect_by_func (chat, - G_CALLBACK (chat_window_new_message_cb), - window); - - /* Keep list of chats up to date */ - priv->chats = g_list_remove (priv->chats, chat); - priv->chats_new_msg = g_list_remove (priv->chats_new_msg, chat); - priv->chats_composing = g_list_remove (priv->chats_composing, chat); - - if (priv->chats == NULL) { - g_object_unref (window); - } else { - chat_window_update_menu (window); - chat_window_update_title (window, NULL); - } -} - -static gboolean -chat_window_focus_in_event_cb (GtkWidget *widget, - GdkEvent *event, - GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - - gossip_debug (DEBUG_DOMAIN, "Focus in event, updating title"); - - priv = GET_PRIV (window); - - priv->chats_new_msg = g_list_remove (priv->chats_new_msg, priv->current_chat); - - chat_window_set_urgency_hint (window, FALSE); - - /* Update the title, since we now mark all unread messages as read. */ - chat_window_update_status (window, priv->current_chat); - - return FALSE; -} - -static void -chat_window_drag_data_received (GtkWidget *widget, - GdkDragContext *context, - int x, - int y, - GtkSelectionData *selection, - guint info, - guint time, - GossipChatWindow *window) -{ - /* FIXME: DnD of contact do not seems to work... */ - if (info == DND_DRAG_TYPE_CONTACT_ID) { - EmpathyContactManager *manager; - GossipContact *contact; - GossipChat *chat; - GossipChatWindow *old_window; - McAccount *account; - const gchar *id = NULL; - - if (selection) { - id = (const gchar*) selection->data; - } - - gossip_debug (DEBUG_DOMAIN, "DND contact from roster with id:'%s'", id); - - manager = empathy_contact_manager_new (); - contact = empathy_contact_list_find (EMPATHY_CONTACT_LIST (manager), id); - g_object_unref (manager); - - if (!contact) { - gossip_debug (DEBUG_DOMAIN, "DND contact from roster not found"); - return; - } - - account = gossip_contact_get_account (contact); - chat = gossip_chat_window_find_chat (account, id); - old_window = gossip_chat_get_window (chat); - - if (old_window) { - if (old_window == window) { - gtk_drag_finish (context, TRUE, FALSE, time); - return; - } - - gossip_chat_window_move_chat (old_window, window, chat); - } else { - gossip_chat_window_add_chat (window, chat); - } - - /* Added to take care of any outstanding chat events */ - gossip_chat_present (chat); - - /* We should return TRUE to remove the data when doing - * GDK_ACTION_MOVE, but we don't here otherwise it has - * weird consequences, and we handle that internally - * anyway with add_chat() and remove_chat(). - */ - gtk_drag_finish (context, TRUE, FALSE, time); - } - else if (info == DND_DRAG_TYPE_TAB) { - GossipChat *chat = NULL; - GossipChatWindow *old_window; - GtkWidget **child = NULL; - - gossip_debug (DEBUG_DOMAIN, "DND tab"); - - if (selection) { - child = (void*) selection->data; - } - - if (child) { - chat = g_object_get_data (G_OBJECT (*child), "chat"); - } - - old_window = gossip_chat_get_window (chat); - if (old_window) { - GossipChatWindowPriv *priv; - - priv = GET_PRIV (window); - - if (old_window == window) { - gossip_debug (DEBUG_DOMAIN, "DND tab (within same window)"); - priv->dnd_same_window = TRUE; - gtk_drag_finish (context, TRUE, FALSE, time); - return; - } - - priv->dnd_same_window = FALSE; - } - - /* We should return TRUE to remove the data when doing - * GDK_ACTION_MOVE, but we don't here otherwise it has - * weird consequences, and we handle that internally - * anyway with add_chat() and remove_chat(). - */ - gtk_drag_finish (context, TRUE, FALSE, time); - } else { - gossip_debug (DEBUG_DOMAIN, "DND from unknown source"); - gtk_drag_finish (context, FALSE, FALSE, time); - } -} - -static gboolean -chat_window_urgency_timeout_func (GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - - priv = GET_PRIV (window); - - gossip_debug (DEBUG_DOMAIN, "Turning off urgency hint"); - gtk_window_set_urgency_hint (GTK_WINDOW (priv->dialog), FALSE); - - priv->urgency_timeout_id = 0; - - return FALSE; -} - -static void -chat_window_set_urgency_hint (GossipChatWindow *window, - gboolean urgent) -{ - GossipChatWindowPriv *priv; - - priv = GET_PRIV (window); - - if (!urgent) { - /* Remove any existing hint and timeout. */ - if (priv->urgency_timeout_id) { - gossip_debug (DEBUG_DOMAIN, "Turning off urgency hint"); - gtk_window_set_urgency_hint (GTK_WINDOW (priv->dialog), FALSE); - g_source_remove (priv->urgency_timeout_id); - priv->urgency_timeout_id = 0; - } - return; - } - - /* Add a new hint and renew any exising timeout or add a new one. */ - if (priv->urgency_timeout_id) { - g_source_remove (priv->urgency_timeout_id); - } else { - gossip_debug (DEBUG_DOMAIN, "Turning on urgency hint"); - gtk_window_set_urgency_hint (GTK_WINDOW (priv->dialog), TRUE); - } - - priv->urgency_timeout_id = g_timeout_add ( - URGENCY_TIMEOUT, - (GSourceFunc) chat_window_urgency_timeout_func, - window); -} - -GossipChatWindow * -gossip_chat_window_new (void) -{ - return GOSSIP_CHAT_WINDOW (g_object_new (GOSSIP_TYPE_CHAT_WINDOW, NULL)); -} - -GtkWidget * -gossip_chat_window_get_dialog (GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - - g_return_val_if_fail (window != NULL, NULL); - - priv = GET_PRIV (window); - - return priv->dialog; -} - -void -gossip_chat_window_add_chat (GossipChatWindow *window, - GossipChat *chat) -{ - GossipChatWindowPriv *priv; - GtkWidget *label; - GtkWidget *child; - - priv = GET_PRIV (window); - - /* Reference the chat object */ - g_object_ref (chat); - - /* Set the chat window */ - gossip_chat_set_window (chat, window); - - if (g_list_length (priv->chats) == 0) { - gint x, y, w, h; - - gossip_chat_load_geometry (chat, &x, &y, &w, &h); - - if (x >= 0 && y >= 0) { - /* Let the window manager position it if we don't have - * good x, y coordinates. - */ - gtk_window_move (GTK_WINDOW (priv->dialog), x, y); - } - - if (w > 0 && h > 0) { - /* Use the defaults from the glade file if we don't have - * good w, h geometry. - */ - gtk_window_resize (GTK_WINDOW (priv->dialog), w, h); - } - } - - child = gossip_chat_get_widget (chat); - label = chat_window_create_label (window, chat); - - gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), child, label); - gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (priv->notebook), child, TRUE); - gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (priv->notebook), child, TRUE); - gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (priv->notebook), child, - TRUE, TRUE, GTK_PACK_START); - - gossip_debug (DEBUG_DOMAIN, - "Chat added (%d references)", - G_OBJECT (chat)->ref_count); -} - -void -gossip_chat_window_remove_chat (GossipChatWindow *window, - GossipChat *chat) -{ - GossipChatWindowPriv *priv; - gint position; - - priv = GET_PRIV (window); - - position = gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook), - gossip_chat_get_widget (chat)); - gtk_notebook_remove_page (GTK_NOTEBOOK (priv->notebook), position); - - gossip_debug (DEBUG_DOMAIN, - "Chat removed (%d references)", - G_OBJECT (chat)->ref_count - 1); - - g_object_unref (chat); -} - -void -gossip_chat_window_move_chat (GossipChatWindow *old_window, - GossipChatWindow *new_window, - GossipChat *chat) -{ - GtkWidget *widget; - - g_return_if_fail (GOSSIP_IS_CHAT_WINDOW (old_window)); - g_return_if_fail (GOSSIP_IS_CHAT_WINDOW (new_window)); - g_return_if_fail (GOSSIP_IS_CHAT (chat)); - - widget = gossip_chat_get_widget (chat); - - gossip_debug (DEBUG_DOMAIN, - "Chat moving with widget:%p (%d references)", - widget, - G_OBJECT (widget)->ref_count); - - /* We reference here to make sure we don't loose the widget - * and the GossipChat object during the move. - */ - g_object_ref (chat); - g_object_ref (widget); - - gossip_chat_window_remove_chat (old_window, chat); - gossip_chat_window_add_chat (new_window, chat); - - g_object_unref (widget); - g_object_unref (chat); -} - -void -gossip_chat_window_switch_to_chat (GossipChatWindow *window, - GossipChat *chat) -{ - GossipChatWindowPriv *priv; - gint page_num; - - priv = GET_PRIV (window); - - page_num = gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook), - gossip_chat_get_widget (chat)); - gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), - page_num); -} - -gboolean -gossip_chat_window_has_focus (GossipChatWindow *window) -{ - GossipChatWindowPriv *priv; - gboolean has_focus; - - g_return_val_if_fail (GOSSIP_IS_CHAT_WINDOW (window), FALSE); - - priv = GET_PRIV (window); - - g_object_get (priv->dialog, "has-toplevel-focus", &has_focus, NULL); - - return has_focus; -} - -GossipChat * -gossip_chat_window_find_chat (McAccount *account, - const gchar *id) -{ - GList *l; - - for (l = chat_windows; l; l = l->next) { - GossipChatWindowPriv *priv; - GossipChatWindow *window; - GList *ll; - - window = l->data; - priv = GET_PRIV (window); - - for (ll = priv->chats; ll; ll = ll->next) { - GossipChat *chat; - - chat = ll->data; - - if (gossip_account_equal (account, chat->account) && - strcmp (id, gossip_chat_get_id (chat)) == 0) { - return chat; - } - } - } - - return NULL; -} - diff --git a/libempathy-gtk/gossip-chat-window.h b/libempathy-gtk/gossip-chat-window.h deleted file mode 100644 index b58e5dac..00000000 --- a/libempathy-gtk/gossip-chat-window.h +++ /dev/null @@ -1,80 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2003-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Richard Hult - * Martyn Russell - * Geert-Jan Van den Bogaerde - * Xavier Claessens - */ - -#ifndef __GOSSIP_CHAT_WINDOW_H__ -#define __GOSSIP_CHAT_WINDOW_H__ - -#include - -#include - -G_BEGIN_DECLS - -#define GOSSIP_TYPE_CHAT_WINDOW (gossip_chat_window_get_type ()) -#define GOSSIP_CHAT_WINDOW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOSSIP_TYPE_CHAT_WINDOW, GossipChatWindow)) -#define GOSSIP_CHAT_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GOSSIP_TYPE_CHAT_WINDOW, GossipChatWindowClass)) -#define GOSSIP_IS_CHAT_WINDOW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOSSIP_TYPE_CHAT_WINDOW)) -#define GOSSIP_IS_CHAT_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOSSIP_TYPE_CHAT_WINDOW)) -#define GOSSIP_CHAT_WINDOW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOSSIP_TYPE_CHAT_WINDOW, GossipChatWindowClass)) - -typedef struct _GossipChatWindow GossipChatWindow; -typedef struct _GossipChatWindowClass GossipChatWindowClass; -typedef struct _GossipChatWindowPriv GossipChatWindowPriv; - -#include "gossip-chat.h" - -struct _GossipChatWindow { - GObject parent; -}; - -struct _GossipChatWindowClass { - GObjectClass parent_class; -}; - -GType gossip_chat_window_get_type (void); -GossipChatWindow *gossip_chat_window_get_default (void); - -GossipChatWindow *gossip_chat_window_new (void); - -GtkWidget * gossip_chat_window_get_dialog (GossipChatWindow *window); - -void gossip_chat_window_add_chat (GossipChatWindow *window, - GossipChat *chat); -void gossip_chat_window_remove_chat (GossipChatWindow *window, - GossipChat *chat); -void gossip_chat_window_move_chat (GossipChatWindow *old_window, - GossipChatWindow *new_window, - GossipChat *chat); -void gossip_chat_window_switch_to_chat (GossipChatWindow *window, - GossipChat *chat); -gboolean gossip_chat_window_has_focus (GossipChatWindow *window); -GossipChat * gossip_chat_window_find_chat (McAccount *account, - const gchar *id); - -G_END_DECLS - -#endif /* __GOSSIP_CHAT_WINDOW_H__ */ diff --git a/libempathy-gtk/gossip-chat.c b/libempathy-gtk/gossip-chat.c deleted file mode 100644 index 1ad76b7f..00000000 --- a/libempathy-gtk/gossip-chat.c +++ /dev/null @@ -1,1561 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2002-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Richard Hult - * Martyn Russell - * Geert-Jan Van den Bogaerde - * Xavier Claessens - */ - -#include "config.h" - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "gossip-chat.h" -#include "gossip-chat-window.h" -#include "gossip-geometry.h" -#include "gossip-preferences.h" -#include "gossip-spell.h" -#include "gossip-spell-dialog.h" -#include "gossip-ui-utils.h" - -#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CHAT, GossipChatPriv)) - -#define DEBUG_DOMAIN "Chat" - -#define CHAT_DIR_CREATE_MODE (S_IRUSR | S_IWUSR | S_IXUSR) -#define CHAT_FILE_CREATE_MODE (S_IRUSR | S_IWUSR) - -#define IS_ENTER(v) (v == GDK_Return || v == GDK_ISO_Enter || v == GDK_KP_Enter) - -#define MAX_INPUT_HEIGHT 150 - -#define COMPOSING_STOP_TIMEOUT 5 - -struct _GossipChatPriv { - EmpathyContactManager *manager; - EmpathyLogManager *log_manager; - EmpathyTpChat *tp_chat; - GossipChatWindow *window; - GtkTooltips *tooltips; - guint composing_stop_timeout_id; - gboolean sensitive; - gchar *id; - GSList *sent_messages; - gint sent_messages_index; - GList *compositors; - guint scroll_idle_id; - gboolean first_tp_chat; - GossipTime time_joined; - /* Used to automatically shrink a window that has temporarily - * grown due to long input. - */ - gint padding_height; - gint default_window_height; - gint last_input_height; - gboolean vscroll_visible; -}; - -typedef struct { - GossipChat *chat; - gchar *word; - - GtkTextIter start; - GtkTextIter end; -} GossipChatSpell; - -static void gossip_chat_class_init (GossipChatClass *klass); -static void gossip_chat_init (GossipChat *chat); -static void chat_finalize (GObject *object); -static void chat_destroy_cb (EmpathyTpChat *tp_chat, - GossipChat *chat); -static void chat_send (GossipChat *chat, - const gchar *msg); -static void chat_input_text_view_send (GossipChat *chat); -static void chat_message_received_cb (EmpathyTpChat *tp_chat, - GossipMessage *message, - GossipChat *chat); -void chat_sent_message_add (GossipChat *chat, - const gchar *str); -const gchar * chat_sent_message_get_next (GossipChat *chat); -const gchar * chat_sent_message_get_last (GossipChat *chat); -static gboolean chat_input_key_press_event_cb (GtkWidget *widget, - GdkEventKey *event, - GossipChat *chat); -static void chat_input_text_buffer_changed_cb (GtkTextBuffer *buffer, - GossipChat *chat); -static gboolean chat_text_view_focus_in_event_cb (GtkWidget *widget, - GdkEvent *event, - GossipChat *chat); -static void chat_text_view_scroll_hide_cb (GtkWidget *widget, - GossipChat *chat); -static void chat_text_view_size_allocate_cb (GtkWidget *widget, - GtkAllocation *allocation, - GossipChat *chat); -static void chat_text_view_realize_cb (GtkWidget *widget, - GossipChat *chat); -static void chat_text_populate_popup_cb (GtkTextView *view, - GtkMenu *menu, - GossipChat *chat); -static void chat_text_check_word_spelling_cb (GtkMenuItem *menuitem, - GossipChatSpell *chat_spell); -static GossipChatSpell *chat_spell_new (GossipChat *chat, - const gchar *word, - GtkTextIter start, - GtkTextIter end); -static void chat_spell_free (GossipChatSpell *chat_spell); -static void chat_composing_start (GossipChat *chat); -static void chat_composing_stop (GossipChat *chat); -static void chat_composing_remove_timeout (GossipChat *chat); -static gboolean chat_composing_stop_timeout_cb (GossipChat *chat); -static void chat_state_changed_cb (EmpathyTpChat *tp_chat, - GossipContact *contact, - TelepathyChannelChatState state, - GossipChat *chat); -static void chat_add_logs (GossipChat *chat); -static gboolean chat_scroll_down_idle_func (GossipChat *chat); - -enum { - COMPOSING, - NEW_MESSAGE, - NAME_CHANGED, - STATUS_CHANGED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -G_DEFINE_TYPE (GossipChat, gossip_chat, G_TYPE_OBJECT); - -static void -gossip_chat_class_init (GossipChatClass *klass) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = chat_finalize; - - signals[COMPOSING] = - g_signal_new ("composing", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__BOOLEAN, - G_TYPE_NONE, - 1, G_TYPE_BOOLEAN); - - signals[NEW_MESSAGE] = - g_signal_new ("new-message", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - empathy_marshal_VOID__OBJECT_BOOLEAN, - G_TYPE_NONE, - 2, GOSSIP_TYPE_MESSAGE, G_TYPE_BOOLEAN); - - signals[NAME_CHANGED] = - g_signal_new ("name-changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, - 1, G_TYPE_POINTER); - - signals[STATUS_CHANGED] = - g_signal_new ("status-changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - g_type_class_add_private (object_class, sizeof (GossipChatPriv)); -} - -static void -gossip_chat_init (GossipChat *chat) -{ - GossipChatPriv *priv; - GtkTextBuffer *buffer; - - chat->view = gossip_chat_view_new (); - chat->input_text_view = gtk_text_view_new (); - - chat->is_first_char = TRUE; - - g_object_set (chat->input_text_view, - "pixels-above-lines", 2, - "pixels-below-lines", 2, - "pixels-inside-wrap", 1, - "right-margin", 2, - "left-margin", 2, - "wrap-mode", GTK_WRAP_WORD_CHAR, - NULL); - - priv = GET_PRIV (chat); - - priv->manager = empathy_contact_manager_new (); - priv->log_manager = empathy_log_manager_new (); - priv->tooltips = g_object_ref_sink (gtk_tooltips_new ()); - priv->default_window_height = -1; - priv->vscroll_visible = FALSE; - priv->sensitive = TRUE; - priv->sent_messages = NULL; - priv->sent_messages_index = -1; - priv->first_tp_chat = TRUE; - - g_signal_connect (chat->input_text_view, - "key_press_event", - G_CALLBACK (chat_input_key_press_event_cb), - chat); - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); - g_signal_connect (buffer, - "changed", - G_CALLBACK (chat_input_text_buffer_changed_cb), - chat); - g_signal_connect (chat->view, - "focus_in_event", - G_CALLBACK (chat_text_view_focus_in_event_cb), - chat); - - g_signal_connect (chat->input_text_view, - "size_allocate", - G_CALLBACK (chat_text_view_size_allocate_cb), - chat); - - g_signal_connect (chat->input_text_view, - "realize", - G_CALLBACK (chat_text_view_realize_cb), - chat); - - g_signal_connect (GTK_TEXT_VIEW (chat->input_text_view), - "populate_popup", - G_CALLBACK (chat_text_populate_popup_cb), - chat); - - /* create misspelt words identification tag */ - gtk_text_buffer_create_tag (buffer, - "misspelled", - "underline", PANGO_UNDERLINE_ERROR, - NULL); -} - -static void -chat_finalize (GObject *object) -{ - GossipChat *chat; - GossipChatPriv *priv; - - chat = GOSSIP_CHAT (object); - priv = GET_PRIV (chat); - - gossip_debug (DEBUG_DOMAIN, "Finalized: %p", object); - - g_slist_foreach (priv->sent_messages, (GFunc) g_free, NULL); - g_slist_free (priv->sent_messages); - - g_list_foreach (priv->compositors, (GFunc) g_object_unref, NULL); - g_list_free (priv->compositors); - - chat_composing_remove_timeout (chat); - g_object_unref (chat->account); - g_object_unref (priv->manager); - g_object_unref (priv->log_manager); - g_object_unref (priv->tooltips); - - if (priv->tp_chat) { - g_object_unref (priv->tp_chat); - } - - if (priv->scroll_idle_id) { - g_source_remove (priv->scroll_idle_id); - } - - g_free (priv->id); - - G_OBJECT_CLASS (gossip_chat_parent_class)->finalize (object); -} - -static void -chat_destroy_cb (EmpathyTpChat *tp_chat, - GossipChat *chat) -{ - GossipChatPriv *priv; - - priv = GET_PRIV (chat); - - if (priv->tp_chat) { - g_object_unref (priv->tp_chat); - priv->tp_chat = NULL; - } - priv->sensitive = FALSE; - - gossip_chat_view_append_event (chat->view, _("Disconnected")); - gtk_widget_set_sensitive (chat->input_text_view, FALSE); - - if (GOSSIP_CHAT_GET_CLASS (chat)->set_tp_chat) { - GOSSIP_CHAT_GET_CLASS (chat)->set_tp_chat (chat, NULL); - } -} - -static void -chat_send (GossipChat *chat, - const gchar *msg) -{ - GossipChatPriv *priv; - GossipMessage *message; - - priv = GET_PRIV (chat); - - if (G_STR_EMPTY (msg)) { - return; - } - - chat_sent_message_add (chat, msg); - - if (g_str_has_prefix (msg, "/clear")) { - gossip_chat_view_clear (chat->view); - return; - } - - /* FIXME: add here something to let group/privrate chat handle - * some special messages */ - - message = gossip_message_new (msg); - - empathy_tp_chat_send (priv->tp_chat, message); - - g_object_unref (message); -} - -static void -chat_input_text_view_send (GossipChat *chat) -{ - GossipChatPriv *priv; - GtkTextBuffer *buffer; - GtkTextIter start, end; - gchar *msg; - - priv = GET_PRIV (chat); - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); - - gtk_text_buffer_get_bounds (buffer, &start, &end); - msg = gtk_text_buffer_get_text (buffer, &start, &end, FALSE); - - /* clear the input field */ - gtk_text_buffer_set_text (buffer, "", -1); - - chat_send (chat, msg); - - g_free (msg); - - chat->is_first_char = TRUE; -} - -static void -chat_message_received_cb (EmpathyTpChat *tp_chat, - GossipMessage *message, - GossipChat *chat) -{ - GossipChatPriv *priv; - GossipContact *sender; - GossipTime timestamp; - - priv = GET_PRIV (chat); - - sender = gossip_message_get_sender (message); - gossip_debug (DEBUG_DOMAIN, "Appending message ('%s')", - gossip_contact_get_name (sender)); - - /* Log the message only if it's not backlog */ - timestamp = gossip_message_get_timestamp (message); - if (timestamp >= priv->time_joined) { - empathy_log_manager_add_message (priv->log_manager, - gossip_chat_get_id (chat), - gossip_chat_is_group_chat (chat), - message); - } - - gossip_chat_view_append_message (chat->view, message); - - if (gossip_chat_should_play_sound (chat)) { - // FIXME: gossip_sound_play (GOSSIP_SOUND_CHAT); - } - - g_signal_emit (chat, signals[NEW_MESSAGE], 0, message, FALSE); -} - -void -chat_sent_message_add (GossipChat *chat, - const gchar *str) -{ - GossipChatPriv *priv; - GSList *list; - GSList *item; - - priv = GET_PRIV (chat); - - /* Save the sent message in our repeat buffer */ - list = priv->sent_messages; - - /* Remove any other occurances of this msg */ - while ((item = g_slist_find_custom (list, str, (GCompareFunc) strcmp)) != NULL) { - list = g_slist_remove_link (list, item); - g_free (item->data); - g_slist_free1 (item); - } - - /* Trim the list to the last 10 items */ - while (g_slist_length (list) > 10) { - item = g_slist_last (list); - if (item) { - list = g_slist_remove_link (list, item); - g_free (item->data); - g_slist_free1 (item); - } - } - - /* Add new message */ - list = g_slist_prepend (list, g_strdup (str)); - - /* Set list and reset the index */ - priv->sent_messages = list; - priv->sent_messages_index = -1; -} - -const gchar * -chat_sent_message_get_next (GossipChat *chat) -{ - GossipChatPriv *priv; - gint max; - - priv = GET_PRIV (chat); - - if (!priv->sent_messages) { - gossip_debug (DEBUG_DOMAIN, - "No sent messages, next message is NULL"); - return NULL; - } - - max = g_slist_length (priv->sent_messages) - 1; - - if (priv->sent_messages_index < max) { - priv->sent_messages_index++; - } - - gossip_debug (DEBUG_DOMAIN, - "Returning next message index:%d", - priv->sent_messages_index); - - return g_slist_nth_data (priv->sent_messages, priv->sent_messages_index); -} - -const gchar * -chat_sent_message_get_last (GossipChat *chat) -{ - GossipChatPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CHAT (chat), NULL); - - priv = GET_PRIV (chat); - - if (!priv->sent_messages) { - gossip_debug (DEBUG_DOMAIN, - "No sent messages, last message is NULL"); - return NULL; - } - - if (priv->sent_messages_index >= 0) { - priv->sent_messages_index--; - } - - gossip_debug (DEBUG_DOMAIN, - "Returning last message index:%d", - priv->sent_messages_index); - - return g_slist_nth_data (priv->sent_messages, priv->sent_messages_index); -} - -static gboolean -chat_input_key_press_event_cb (GtkWidget *widget, - GdkEventKey *event, - GossipChat *chat) -{ - GossipChatPriv *priv; - GtkAdjustment *adj; - gdouble val; - GtkWidget *text_view_sw; - - priv = GET_PRIV (chat); - - if (event->keyval == GDK_Tab && !(event->state & GDK_CONTROL_MASK)) { - return TRUE; - } - - /* Catch ctrl+up/down so we can traverse messages we sent */ - if ((event->state & GDK_CONTROL_MASK) && - (event->keyval == GDK_Up || - event->keyval == GDK_Down)) { - GtkTextBuffer *buffer; - const gchar *str; - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); - - if (event->keyval == GDK_Up) { - str = chat_sent_message_get_next (chat); - } else { - str = chat_sent_message_get_last (chat); - } - - g_signal_handlers_block_by_func (buffer, - chat_input_text_buffer_changed_cb, - chat); - gtk_text_buffer_set_text (buffer, str ? str : "", -1); - g_signal_handlers_unblock_by_func (buffer, - chat_input_text_buffer_changed_cb, - chat); - - return TRUE; - } - - /* Catch enter but not ctrl/shift-enter */ - if (IS_ENTER (event->keyval) && !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))) { - GtkTextView *view; - - /* This is to make sure that kinput2 gets the enter. And if - * it's handled there we shouldn't send on it. This is because - * kinput2 uses Enter to commit letters. See: - * http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=104299 - */ - - view = GTK_TEXT_VIEW (chat->input_text_view); - if (gtk_im_context_filter_keypress (view->im_context, event)) { - GTK_TEXT_VIEW (chat->input_text_view)->need_im_reset = TRUE; - return TRUE; - } - - chat_input_text_view_send (chat); - return TRUE; - } - - text_view_sw = gtk_widget_get_parent (GTK_WIDGET (chat->view)); - - if (IS_ENTER (event->keyval) && (event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))) { - /* Newline for shift-enter. */ - return FALSE; - } - else if ((event->state & GDK_CONTROL_MASK) != GDK_CONTROL_MASK && - event->keyval == GDK_Page_Up) { - adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (text_view_sw)); - gtk_adjustment_set_value (adj, adj->value - adj->page_size); - - return TRUE; - } - else if ((event->state & GDK_CONTROL_MASK) != GDK_CONTROL_MASK && - event->keyval == GDK_Page_Down) { - adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (text_view_sw)); - val = MIN (adj->value + adj->page_size, adj->upper - adj->page_size); - gtk_adjustment_set_value (adj, val); - - return TRUE; - } - - return FALSE; -} - -static gboolean -chat_text_view_focus_in_event_cb (GtkWidget *widget, - GdkEvent *event, - GossipChat *chat) -{ - gtk_widget_grab_focus (chat->input_text_view); - - return TRUE; -} - -static void -chat_input_text_buffer_changed_cb (GtkTextBuffer *buffer, - GossipChat *chat) -{ - GossipChatPriv *priv; - GtkTextIter start, end; - gchar *str; - gboolean spell_checker = FALSE; - - priv = GET_PRIV (chat); - - if (gtk_text_buffer_get_char_count (buffer) == 0) { - chat_composing_stop (chat); - } else { - chat_composing_start (chat); - } - - gossip_conf_get_bool (gossip_conf_get (), - GOSSIP_PREFS_CHAT_SPELL_CHECKER_ENABLED, - &spell_checker); - - if (chat->is_first_char) { - GtkRequisition req; - gint window_height; - GtkWidget *dialog; - GtkAllocation *allocation; - - /* Save the window's size */ - dialog = gossip_chat_window_get_dialog (priv->window); - gtk_window_get_size (GTK_WINDOW (dialog), - NULL, &window_height); - - gtk_widget_size_request (chat->input_text_view, &req); - - allocation = >K_WIDGET (chat->view)->allocation; - - priv->default_window_height = window_height; - priv->last_input_height = req.height; - priv->padding_height = window_height - req.height - allocation->height; - - chat->is_first_char = FALSE; - } - - gtk_text_buffer_get_start_iter (buffer, &start); - - if (!spell_checker) { - gtk_text_buffer_get_end_iter (buffer, &end); - gtk_text_buffer_remove_tag_by_name (buffer, "misspelled", &start, &end); - return; - } - - if (!gossip_spell_supported ()) { - return; - } - - /* NOTE: this is really inefficient, we shouldn't have to - reiterate the whole buffer each time and check each work - every time. */ - while (TRUE) { - gboolean correct = FALSE; - - /* if at start */ - if (gtk_text_iter_is_start (&start)) { - end = start; - - if (!gtk_text_iter_forward_word_end (&end)) { - /* no whole word yet */ - break; - } - } else { - if (!gtk_text_iter_forward_word_end (&end)) { - /* must be the end of the buffer */ - break; - } - - start = end; - gtk_text_iter_backward_word_start (&start); - } - - str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE); - - /* spell check string */ - if (!gossip_chat_get_is_command (str)) { - correct = gossip_spell_check (str); - } else { - correct = TRUE; - } - - if (!correct) { - gtk_text_buffer_apply_tag_by_name (buffer, "misspelled", &start, &end); - } else { - gtk_text_buffer_remove_tag_by_name (buffer, "misspelled", &start, &end); - } - - g_free (str); - - /* set start iter to the end iters position */ - start = end; - } -} - -typedef struct { - GtkWidget *window; - gint width; - gint height; -} ChangeSizeData; - -static gboolean -chat_change_size_in_idle_cb (ChangeSizeData *data) -{ - gtk_window_resize (GTK_WINDOW (data->window), - data->width, data->height); - - return FALSE; -} - -static void -chat_text_view_scroll_hide_cb (GtkWidget *widget, - GossipChat *chat) -{ - GossipChatPriv *priv; - GtkWidget *sw; - - priv = GET_PRIV (chat); - - priv->vscroll_visible = FALSE; - g_signal_handlers_disconnect_by_func (widget, chat_text_view_scroll_hide_cb, chat); - - sw = gtk_widget_get_parent (chat->input_text_view); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), - GTK_POLICY_NEVER, - GTK_POLICY_NEVER); - g_object_set (sw, "height-request", -1, NULL); -} - -static void -chat_text_view_size_allocate_cb (GtkWidget *widget, - GtkAllocation *allocation, - GossipChat *chat) -{ - GossipChatPriv *priv; - gint width; - GtkWidget *dialog; - ChangeSizeData *data; - gint window_height; - gint new_height; - GtkAllocation *view_allocation; - gint current_height; - gint diff; - GtkWidget *sw; - - priv = GET_PRIV (chat); - - if (priv->default_window_height <= 0) { - return; - } - - sw = gtk_widget_get_parent (widget); - if (sw->allocation.height >= MAX_INPUT_HEIGHT && !priv->vscroll_visible) { - GtkWidget *vscroll; - - priv->vscroll_visible = TRUE; - gtk_widget_set_size_request (sw, sw->allocation.width, MAX_INPUT_HEIGHT); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), - GTK_POLICY_NEVER, - GTK_POLICY_AUTOMATIC); - vscroll = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (sw)); - g_signal_connect (vscroll, "hide", - G_CALLBACK (chat_text_view_scroll_hide_cb), - chat); - } - - if (priv->last_input_height <= allocation->height) { - priv->last_input_height = allocation->height; - return; - } - - diff = priv->last_input_height - allocation->height; - priv->last_input_height = allocation->height; - - view_allocation = >K_WIDGET (chat->view)->allocation; - - dialog = gossip_chat_window_get_dialog (priv->window); - gtk_window_get_size (GTK_WINDOW (dialog), NULL, ¤t_height); - - new_height = view_allocation->height + priv->padding_height + allocation->height - diff; - - if (new_height <= priv->default_window_height) { - window_height = priv->default_window_height; - } else { - window_height = new_height; - } - - if (current_height <= window_height) { - return; - } - - /* Restore the window's size */ - gtk_window_get_size (GTK_WINDOW (dialog), &width, NULL); - - data = g_new0 (ChangeSizeData, 1); - data->window = dialog; - data->width = width; - data->height = window_height; - - g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, - (GSourceFunc) chat_change_size_in_idle_cb, - data, g_free); -} - -static void -chat_text_view_realize_cb (GtkWidget *widget, - GossipChat *chat) -{ - gossip_debug (DEBUG_DOMAIN, "Setting focus to the input text view"); - gtk_widget_grab_focus (widget); -} - -static void -chat_insert_smiley_activate_cb (GtkWidget *menuitem, - GossipChat *chat) -{ - GtkTextBuffer *buffer; - GtkTextIter iter; - const gchar *smiley; - - smiley = g_object_get_data (G_OBJECT (menuitem), "smiley_text"); - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); - - gtk_text_buffer_get_end_iter (buffer, &iter); - gtk_text_buffer_insert (buffer, &iter, smiley, -1); - - gtk_text_buffer_get_end_iter (buffer, &iter); - gtk_text_buffer_insert (buffer, &iter, " ", -1); -} - -static void -chat_text_populate_popup_cb (GtkTextView *view, - GtkMenu *menu, - GossipChat *chat) -{ - GossipChatPriv *priv; - GtkTextBuffer *buffer; - GtkTextTagTable *table; - GtkTextTag *tag; - gint x, y; - GtkTextIter iter, start, end; - GtkWidget *item; - gchar *str = NULL; - GossipChatSpell *chat_spell; - GtkWidget *smiley_menu; - - priv = GET_PRIV (chat); - - /* Add the emoticon menu. */ - item = gtk_separator_menu_item_new (); - gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - item = gtk_menu_item_new_with_mnemonic (_("Insert Smiley")); - gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - smiley_menu = gossip_chat_view_get_smiley_menu ( - G_CALLBACK (chat_insert_smiley_activate_cb), - chat, - priv->tooltips); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), smiley_menu); - - /* Add the spell check menu item. */ - buffer = gtk_text_view_get_buffer (view); - table = gtk_text_buffer_get_tag_table (buffer); - - tag = gtk_text_tag_table_lookup (table, "misspelled"); - - gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y); - - gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view), - GTK_TEXT_WINDOW_WIDGET, - x, y, - &x, &y); - - gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view), &iter, x, y); - - start = end = iter; - - if (gtk_text_iter_backward_to_tag_toggle (&start, tag) && - gtk_text_iter_forward_to_tag_toggle (&end, tag)) { - - str = gtk_text_buffer_get_text (buffer, - &start, &end, FALSE); - } - - if (G_STR_EMPTY (str)) { - return; - } - - chat_spell = chat_spell_new (chat, str, start, end); - - g_object_set_data_full (G_OBJECT (menu), - "chat_spell", chat_spell, - (GDestroyNotify) chat_spell_free); - - item = gtk_separator_menu_item_new (); - gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - item = gtk_menu_item_new_with_mnemonic (_("_Check Word Spelling...")); - g_signal_connect (item, - "activate", - G_CALLBACK (chat_text_check_word_spelling_cb), - chat_spell); - gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); -} - -static void -chat_text_check_word_spelling_cb (GtkMenuItem *menuitem, - GossipChatSpell *chat_spell) -{ - gossip_spell_dialog_show (chat_spell->chat, - chat_spell->start, - chat_spell->end, - chat_spell->word); -} - -static GossipChatSpell * -chat_spell_new (GossipChat *chat, - const gchar *word, - GtkTextIter start, - GtkTextIter end) -{ - GossipChatSpell *chat_spell; - - chat_spell = g_new0 (GossipChatSpell, 1); - - chat_spell->chat = g_object_ref (chat); - chat_spell->word = g_strdup (word); - chat_spell->start = start; - chat_spell->end = end; - - return chat_spell; -} - -static void -chat_spell_free (GossipChatSpell *chat_spell) -{ - g_object_unref (chat_spell->chat); - g_free (chat_spell->word); - g_free (chat_spell); -} - -static void -chat_composing_start (GossipChat *chat) -{ - GossipChatPriv *priv; - - priv = GET_PRIV (chat); - - if (priv->composing_stop_timeout_id) { - /* Just restart the timeout */ - chat_composing_remove_timeout (chat); - } else { - empathy_tp_chat_set_state (priv->tp_chat, - TP_CHANNEL_CHAT_STATE_COMPOSING); - } - - priv->composing_stop_timeout_id = g_timeout_add ( - 1000 * COMPOSING_STOP_TIMEOUT, - (GSourceFunc) chat_composing_stop_timeout_cb, - chat); -} - -static void -chat_composing_stop (GossipChat *chat) -{ - GossipChatPriv *priv; - - priv = GET_PRIV (chat); - - chat_composing_remove_timeout (chat); - empathy_tp_chat_set_state (priv->tp_chat, - TP_CHANNEL_CHAT_STATE_ACTIVE); -} - -static void -chat_composing_remove_timeout (GossipChat *chat) -{ - GossipChatPriv *priv; - - priv = GET_PRIV (chat); - - if (priv->composing_stop_timeout_id) { - g_source_remove (priv->composing_stop_timeout_id); - priv->composing_stop_timeout_id = 0; - } -} - -static gboolean -chat_composing_stop_timeout_cb (GossipChat *chat) -{ - GossipChatPriv *priv; - - priv = GET_PRIV (chat); - - priv->composing_stop_timeout_id = 0; - empathy_tp_chat_set_state (priv->tp_chat, - TP_CHANNEL_CHAT_STATE_PAUSED); - - return FALSE; -} - -static void -chat_state_changed_cb (EmpathyTpChat *tp_chat, - GossipContact *contact, - TelepathyChannelChatState state, - GossipChat *chat) -{ - GossipChatPriv *priv; - GList *l; - gboolean was_composing; - - priv = GET_PRIV (chat); - - if (gossip_contact_is_user (contact)) { - /* We don't care about our own chat state */ - return; - } - - was_composing = (priv->compositors != NULL); - - /* Find the contact in the list. After that l is the list elem or NULL */ - for (l = priv->compositors; l; l = l->next) { - if (gossip_contact_equal (contact, l->data)) { - break; - } - } - - switch (state) { - case TP_CHANNEL_CHAT_STATE_GONE: - case TP_CHANNEL_CHAT_STATE_INACTIVE: - case TP_CHANNEL_CHAT_STATE_ACTIVE: - /* Contact is not composing */ - if (l) { - priv->compositors = g_list_remove_link (priv->compositors, l); - g_object_unref (l->data); - g_list_free1 (l); - } - break; - case TP_CHANNEL_CHAT_STATE_PAUSED: - case TP_CHANNEL_CHAT_STATE_COMPOSING: - /* Contact is composing */ - if (!l) { - priv->compositors = g_list_prepend (priv->compositors, - g_object_ref (contact)); - } - break; - default: - g_assert_not_reached (); - } - - gossip_debug (DEBUG_DOMAIN, "Was composing: %s now composing: %s", - was_composing ? "yes" : "no", - priv->compositors ? "yes" : "no"); - - if ((was_composing && !priv->compositors) || - (!was_composing && priv->compositors)) { - /* Composing state changed */ - g_signal_emit (chat, signals[COMPOSING], 0, - priv->compositors != NULL); - } -} - -static void -chat_add_logs (GossipChat *chat) -{ - GossipChatPriv *priv; - GList *messages, *l; - guint num_messages; - guint i; - - priv = GET_PRIV (chat); - - /* Do not display backlog for chatrooms */ - if (gossip_chat_is_group_chat (chat)) { - return; - } - - /* Turn off scrolling temporarily */ - gossip_chat_view_scroll (chat->view, FALSE); - - /* Add messages from last conversation */ - messages = empathy_log_manager_get_last_messages (priv->log_manager, - chat->account, - gossip_chat_get_id (chat), - gossip_chat_is_group_chat (chat)); - num_messages = g_list_length (messages); - - for (l = messages, i = 0; l; l = l->next, i++) { - GossipMessage *message; - - message = l->data; - - /* Only add 10 last messages */ - if (num_messages - i > 10) { - g_object_unref (message); - continue; - } - - - gossip_chat_view_append_message (chat->view, message); - g_object_unref (message); - } - g_list_free (messages); - - /* Turn back on scrolling */ - gossip_chat_view_scroll (chat->view, TRUE); - - /* Scroll to the most recent messages, we reference the chat - * for the duration of the scroll func. - */ - priv->scroll_idle_id = g_idle_add ((GSourceFunc) chat_scroll_down_idle_func, - g_object_ref (chat)); -} - -/* Scroll down after the back-log has been received. */ -static gboolean -chat_scroll_down_idle_func (GossipChat *chat) -{ - GossipChatPriv *priv; - - priv = GET_PRIV (chat); - - gossip_chat_scroll_down (chat); - g_object_unref (chat); - - priv->scroll_idle_id = 0; - - return FALSE; -} - -gboolean -gossip_chat_get_is_command (const gchar *str) -{ - g_return_val_if_fail (str != NULL, FALSE); - - if (str[0] != '/') { - return FALSE; - } - - if (g_str_has_prefix (str, "/me")) { - return TRUE; - } - else if (g_str_has_prefix (str, "/nick")) { - return TRUE; - } - else if (g_str_has_prefix (str, "/topic")) { - return TRUE; - } - - return FALSE; -} - -void -gossip_chat_correct_word (GossipChat *chat, - GtkTextIter start, - GtkTextIter end, - const gchar *new_word) -{ - GtkTextBuffer *buffer; - - g_return_if_fail (chat != NULL); - g_return_if_fail (new_word != NULL); - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); - - gtk_text_buffer_delete (buffer, &start, &end); - gtk_text_buffer_insert (buffer, &start, - new_word, - -1); -} - -const gchar * -gossip_chat_get_name (GossipChat *chat) -{ - g_return_val_if_fail (GOSSIP_IS_CHAT (chat), NULL); - - if (GOSSIP_CHAT_GET_CLASS (chat)->get_name) { - return GOSSIP_CHAT_GET_CLASS (chat)->get_name (chat); - } - - return NULL; -} - -gchar * -gossip_chat_get_tooltip (GossipChat *chat) -{ - g_return_val_if_fail (GOSSIP_IS_CHAT (chat), NULL); - - if (GOSSIP_CHAT_GET_CLASS (chat)->get_tooltip) { - return GOSSIP_CHAT_GET_CLASS (chat)->get_tooltip (chat); - } - - return NULL; -} - -const gchar * -gossip_chat_get_status_icon_name (GossipChat *chat) -{ - g_return_val_if_fail (GOSSIP_IS_CHAT (chat), NULL); - - if (GOSSIP_CHAT_GET_CLASS (chat)->get_status_icon_name) { - return GOSSIP_CHAT_GET_CLASS (chat)->get_status_icon_name (chat); - } - - return NULL; -} - -GtkWidget * -gossip_chat_get_widget (GossipChat *chat) -{ - g_return_val_if_fail (GOSSIP_IS_CHAT (chat), NULL); - - if (GOSSIP_CHAT_GET_CLASS (chat)->get_widget) { - return GOSSIP_CHAT_GET_CLASS (chat)->get_widget (chat); - } - - return NULL; -} - -gboolean -gossip_chat_is_group_chat (GossipChat *chat) -{ - g_return_val_if_fail (GOSSIP_IS_CHAT (chat), FALSE); - - if (GOSSIP_CHAT_GET_CLASS (chat)->is_group_chat) { - return GOSSIP_CHAT_GET_CLASS (chat)->is_group_chat (chat); - } - - return FALSE; -} - -gboolean -gossip_chat_is_connected (GossipChat *chat) -{ - GossipChatPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CHAT (chat), FALSE); - - priv = GET_PRIV (chat); - - return (priv->tp_chat != NULL); -} - -void -gossip_chat_save_geometry (GossipChat *chat, - gint x, - gint y, - gint w, - gint h) -{ - gossip_geometry_save (gossip_chat_get_id (chat), x, y, w, h); -} - -void -gossip_chat_load_geometry (GossipChat *chat, - gint *x, - gint *y, - gint *w, - gint *h) -{ - gossip_geometry_load (gossip_chat_get_id (chat), x, y, w, h); -} - -void -gossip_chat_set_tp_chat (GossipChat *chat, - EmpathyTpChat *tp_chat) -{ - GossipChatPriv *priv; - - g_return_if_fail (GOSSIP_IS_CHAT (chat)); - g_return_if_fail (EMPATHY_IS_TP_CHAT (tp_chat)); - - priv = GET_PRIV (chat); - - if (tp_chat == priv->tp_chat) { - return; - } - - if (priv->tp_chat) { - g_signal_handlers_disconnect_by_func (priv->tp_chat, - chat_message_received_cb, - chat); - g_signal_handlers_disconnect_by_func (priv->tp_chat, - chat_destroy_cb, - chat); - g_object_unref (priv->tp_chat); - } - - g_free (priv->id); - priv->tp_chat = g_object_ref (tp_chat); - priv->id = g_strdup (empathy_tp_chat_get_id (tp_chat)); - priv->time_joined = gossip_time_get_current (); - - if (priv->first_tp_chat) { - chat_add_logs (chat); - priv->first_tp_chat = FALSE; - } - - g_signal_connect (tp_chat, "message-received", - G_CALLBACK (chat_message_received_cb), - chat); - g_signal_connect (tp_chat, "chat-state-changed", - G_CALLBACK (chat_state_changed_cb), - chat); - g_signal_connect (tp_chat, "destroy", - G_CALLBACK (chat_destroy_cb), - chat); - - empathy_tp_chat_request_pending (tp_chat); - - if (!priv->sensitive) { - gtk_widget_set_sensitive (chat->input_text_view, TRUE); - gossip_chat_view_append_event (chat->view, _("Connected")); - priv->sensitive = TRUE; - } - - if (GOSSIP_CHAT_GET_CLASS (chat)->set_tp_chat) { - GOSSIP_CHAT_GET_CLASS (chat)->set_tp_chat (chat, tp_chat); - } - -} - -const gchar * -gossip_chat_get_id (GossipChat *chat) -{ - GossipChatPriv *priv; - - priv = GET_PRIV (chat); - - return priv->id; -} - -void -gossip_chat_clear (GossipChat *chat) -{ - g_return_if_fail (GOSSIP_IS_CHAT (chat)); - - gossip_chat_view_clear (chat->view); -} - -void -gossip_chat_set_window (GossipChat *chat, - GossipChatWindow *window) -{ - GossipChatPriv *priv; - - priv = GET_PRIV (chat); - priv->window = window; -} - -GossipChatWindow * -gossip_chat_get_window (GossipChat *chat) -{ - GossipChatPriv *priv; - - priv = GET_PRIV (chat); - - return priv->window; -} - -void -gossip_chat_scroll_down (GossipChat *chat) -{ - g_return_if_fail (GOSSIP_IS_CHAT (chat)); - - gossip_chat_view_scroll_down (chat->view); -} - -void -gossip_chat_cut (GossipChat *chat) -{ - GtkTextBuffer *buffer; - - g_return_if_fail (GOSSIP_IS_CHAT (chat)); - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); - if (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL)) { - GtkClipboard *clipboard; - - clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); - - gtk_text_buffer_cut_clipboard (buffer, clipboard, TRUE); - } -} - -void -gossip_chat_copy (GossipChat *chat) -{ - GtkTextBuffer *buffer; - - g_return_if_fail (GOSSIP_IS_CHAT (chat)); - - if (gossip_chat_view_get_selection_bounds (chat->view, NULL, NULL)) { - gossip_chat_view_copy_clipboard (chat->view); - return; - } - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); - if (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL)) { - GtkClipboard *clipboard; - - clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); - - gtk_text_buffer_copy_clipboard (buffer, clipboard); - } -} - -void -gossip_chat_paste (GossipChat *chat) -{ - GtkTextBuffer *buffer; - GtkClipboard *clipboard; - - g_return_if_fail (GOSSIP_IS_CHAT (chat)); - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); - clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); - - gtk_text_buffer_paste_clipboard (buffer, clipboard, NULL, TRUE); -} - -void -gossip_chat_present (GossipChat *chat) -{ - GossipChatPriv *priv; - - g_return_if_fail (GOSSIP_IS_CHAT (chat)); - - priv = GET_PRIV (chat); - - if (priv->window == NULL) { - GossipChatWindow *window; - - window = gossip_chat_window_get_default (); - if (!window) { - window = gossip_chat_window_new (); - } - - gossip_chat_window_add_chat (window, chat); - } - - gossip_chat_window_switch_to_chat (priv->window, chat); - gossip_window_present ( - GTK_WINDOW (gossip_chat_window_get_dialog (priv->window)), - TRUE); - - gtk_widget_grab_focus (chat->input_text_view); -} - -gboolean -gossip_chat_should_play_sound (GossipChat *chat) -{ - GossipChatWindow *window; - gboolean play = TRUE; - - g_return_val_if_fail (GOSSIP_IS_CHAT (chat), FALSE); - - window = gossip_chat_get_window (chat); - if (!window) { - return TRUE; - } - - play = !gossip_chat_window_has_focus (window); - - return play; -} - -gboolean -gossip_chat_should_highlight_nick (GossipMessage *message) -{ - GossipContact *contact; - const gchar *msg, *to; - gchar *cf_msg, *cf_to; - gchar *ch; - gboolean ret_val; - - g_return_val_if_fail (GOSSIP_IS_MESSAGE (message), FALSE); - - gossip_debug (DEBUG_DOMAIN, "Highlighting nickname"); - - ret_val = FALSE; - - msg = gossip_message_get_body (message); - if (!msg) { - return FALSE; - } - - contact = gossip_message_get_receiver (message); - if (!contact || !gossip_contact_is_user (contact)) { - return FALSE; - } - - to = gossip_contact_get_name (contact); - if (!to) { - return FALSE; - } - - cf_msg = g_utf8_casefold (msg, -1); - cf_to = g_utf8_casefold (to, -1); - - ch = strstr (cf_msg, cf_to); - if (ch == NULL) { - goto finished; - } - - if (ch != cf_msg) { - /* Not first in the message */ - if ((*(ch - 1) != ' ') && - (*(ch - 1) != ',') && - (*(ch - 1) != '.')) { - goto finished; - } - } - - ch = ch + strlen (cf_to); - if (ch >= cf_msg + strlen (cf_msg)) { - ret_val = TRUE; - goto finished; - } - - if ((*ch == ' ') || - (*ch == ',') || - (*ch == '.') || - (*ch == ':')) { - ret_val = TRUE; - goto finished; - } - -finished: - g_free (cf_msg); - g_free (cf_to); - - return ret_val; -} - diff --git a/libempathy-gtk/gossip-chat.glade b/libempathy-gtk/gossip-chat.glade deleted file mode 100644 index d07bf77e..00000000 --- a/libempathy-gtk/gossip-chat.glade +++ /dev/null @@ -1,699 +0,0 @@ - - - - - - - Chat - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - 350 - 250 - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - 4 - True - False - 3 - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_ALWAYS - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - - - - 0 - True - True - - - - - - True - True - GTK_POLICY_NEVER - GTK_POLICY_NEVER - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - - - - 0 - False - False - - - - - - - - Chat - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - 350 - 250 - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 0 - - - - True - GTK_PACK_DIRECTION_LTR - GTK_PACK_DIRECTION_LTR - - - - True - _Conversation - True - - - - - - - True - C_lear - True - - - - True - gtk-clear - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - Insert _Smiley - True - - - - - - True - - - - - - True - _View Previous Conversations - True - - - - - True - gtk-justify-left - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - - - - - - _Add Contact... - True - - - - True - gtk-add - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - Contact Infor_mation - True - - - - True - gtk-info - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - - - - - - True - _Close - True - - - - - True - gtk-close - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - - - - - _Room - True - - - - - - - True - Change _Topic... - True - - - - - - True - - - - - - True - Join _New... - True - - - - True - gtk-new - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - In_vite... - True - - - - - - True - - - - - - True - _Add To Favorites - True - - - - True - gtk-add - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - - - - - - True - _Show Contacts - True - True - - - - - - - - - - - True - _Edit - True - - - - - - - True - Cu_t - True - - - - - True - gtk-cut - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - _Copy - True - - - - - True - gtk-copy - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - _Paste - True - - - - - True - gtk-paste - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - - - - - True - _Tabs - True - - - - - - - True - _Previous Tab - True - - - - - - - True - _Next Tab - True - - - - - - - True - - - - - - True - Move Tab _Left - True - - - - - - True - Move Tab _Right - True - - - - - - True - _Detach Tab - True - - - - - - - - - 0 - False - False - - - - - - - - - - - - 5 - Invite - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - True - 275 - 225 - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - False - False - - - - True - False - 0 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - -6 - - - - - - True - False - True - True - True - In_vite - True - GTK_RELIEF_NORMAL - True - -5 - - - - - 0 - False - True - GTK_PACK_END - - - - - - 5 - True - False - 18 - - - - True - False - 6 - - - - True - Select who would you like to invite: - False - True - GTK_JUSTIFY_LEFT - True - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - True - True - False - False - False - True - False - False - False - - - - - 0 - True - True - - - - - 0 - True - True - - - - - - True - False - 6 - - - - True - Invitation _message: - True - True - GTK_JUSTIFY_LEFT - True - False - 0 - 0.5 - 0 - 0 - entry - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - True - True - True - 0 - You have been invited to join a chat conference. - True - * - True - 40 - - - 0 - False - False - - - - - 0 - False - False - - - - - 0 - True - True - - - - - - - diff --git a/libempathy-gtk/gossip-chat.h b/libempathy-gtk/gossip-chat.h deleted file mode 100644 index 85bfc66b..00000000 --- a/libempathy-gtk/gossip-chat.h +++ /dev/null @@ -1,123 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2002-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Richard Hult - * Martyn Russell - * Geert-Jan Van den Bogaerde - * Xavier Claessens - */ - -#ifndef __GOSSIP_CHAT_H__ -#define __GOSSIP_CHAT_H__ - -#include - -#include -#include -#include - -#include "gossip-chat-view.h" -#include "gossip-spell.h" - -G_BEGIN_DECLS - -#define GOSSIP_TYPE_CHAT (gossip_chat_get_type ()) -#define GOSSIP_CHAT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOSSIP_TYPE_CHAT, GossipChat)) -#define GOSSIP_CHAT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GOSSIP_TYPE_CHAT, GossipChatClass)) -#define GOSSIP_IS_CHAT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOSSIP_TYPE_CHAT)) -#define GOSSIP_IS_CHAT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOSSIP_TYPE_CHAT)) -#define GOSSIP_CHAT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOSSIP_TYPE_CHAT, GossipChatClass)) - -typedef struct _GossipChat GossipChat; -typedef struct _GossipChatClass GossipChatClass; -typedef struct _GossipChatPriv GossipChatPriv; - -#include "gossip-chat-window.h" - -struct _GossipChat { - GObject parent; - - /* Protected */ - GossipChatView *view; - EmpathyTpChat *tp_chat; - GtkWidget *input_text_view; - gboolean is_first_char; - McAccount *account; -}; - -struct _GossipChatClass { - GObjectClass parent; - - /* VTable */ - const gchar * (*get_name) (GossipChat *chat); - gchar * (*get_tooltip) (GossipChat *chat); - const gchar * (*get_status_icon_name)(GossipChat *chat); - GtkWidget * (*get_widget) (GossipChat *chat); - gboolean (*is_group_chat) (GossipChat *chat); - void (*set_tp_chat) (GossipChat *chat, - EmpathyTpChat *tp_chat); -}; - -GType gossip_chat_get_type (void); - -GossipChatView * gossip_chat_get_view (GossipChat *chat); -GossipChatWindow *gossip_chat_get_window (GossipChat *chat); -void gossip_chat_set_window (GossipChat *chat, - GossipChatWindow *window); -void gossip_chat_present (GossipChat *chat); -void gossip_chat_clear (GossipChat *chat); -void gossip_chat_scroll_down (GossipChat *chat); -void gossip_chat_cut (GossipChat *chat); -void gossip_chat_copy (GossipChat *chat); -void gossip_chat_paste (GossipChat *chat); -const gchar * gossip_chat_get_name (GossipChat *chat); -gchar * gossip_chat_get_tooltip (GossipChat *chat); -const gchar * gossip_chat_get_status_icon_name (GossipChat *chat); -GtkWidget * gossip_chat_get_widget (GossipChat *chat); -gboolean gossip_chat_is_group_chat (GossipChat *chat); -gboolean gossip_chat_is_connected (GossipChat *chat); - -void gossip_chat_save_geometry (GossipChat *chat, - gint x, - gint y, - gint w, - gint h); -void gossip_chat_load_geometry (GossipChat *chat, - gint *x, - gint *y, - gint *w, - gint *h); -void gossip_chat_set_tp_chat (GossipChat *chat, - EmpathyTpChat *tp_chat); -const gchar * gossip_chat_get_id (GossipChat *chat); - -/* For spell checker dialog to correct the misspelled word. */ -gboolean gossip_chat_get_is_command (const gchar *str); -void gossip_chat_correct_word (GossipChat *chat, - GtkTextIter start, - GtkTextIter end, - const gchar *new_word); -gboolean gossip_chat_should_play_sound (GossipChat *chat); -gboolean gossip_chat_should_highlight_nick (GossipMessage *message); - -G_END_DECLS - -#endif /* __GOSSIP_CHAT_H__ */ diff --git a/libempathy-gtk/gossip-chatrooms-window.c b/libempathy-gtk/gossip-chatrooms-window.c deleted file mode 100644 index 4d4333e8..00000000 --- a/libempathy-gtk/gossip-chatrooms-window.c +++ /dev/null @@ -1,575 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2004-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Xavier Claessens - * Martyn Russell - * Mikael Hallendal - */ - -#include "config.h" - -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "gossip-account-chooser.h" -#include "gossip-chatrooms-window.h" -//#include "gossip-edit-chatroom-dialog.h" -#include "gossip-new-chatroom-dialog.h" -#include "gossip-ui-utils.h" - -typedef struct { - GossipChatroomManager *manager; - - GtkWidget *window; - GtkWidget *hbox_account; - GtkWidget *label_account; - GtkWidget *account_chooser; - GtkWidget *treeview; - GtkWidget *button_remove; - GtkWidget *button_edit; - GtkWidget *button_close; - - gint room_column; -} GossipChatroomsWindow; - -static void chatrooms_window_destroy_cb (GtkWidget *widget, - GossipChatroomsWindow *window); -static void chatrooms_window_model_setup (GossipChatroomsWindow *window); -static void chatrooms_window_model_add_columns (GossipChatroomsWindow *window); -static void chatrooms_window_model_refresh_data (GossipChatroomsWindow *window, - gboolean first_time); -static void chatrooms_window_model_add (GossipChatroomsWindow *window, - GossipChatroom *chatroom, - gboolean set_active); -static void chatrooms_window_model_cell_auto_connect_toggled (GtkCellRendererToggle *cell, - gchar *path_string, - GossipChatroomsWindow *window); -static GossipChatroom * chatrooms_window_model_get_selected (GossipChatroomsWindow *window); -static void chatrooms_window_model_action_selected (GossipChatroomsWindow *window); -static void chatrooms_window_row_activated_cb (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - GossipChatroomsWindow *window); -static void chatrooms_window_button_remove_clicked_cb (GtkWidget *widget, - GossipChatroomsWindow *window); -static void chatrooms_window_button_edit_clicked_cb (GtkWidget *widget, - GossipChatroomsWindow *window); -static void chatrooms_window_button_close_clicked_cb (GtkWidget *widget, - GossipChatroomsWindow *window); -static void chatrooms_window_chatroom_added_cb (GossipChatroomManager *manager, - GossipChatroom *chatroom, - GossipChatroomsWindow *window); -static void chatrooms_window_chatroom_removed_cb (GossipChatroomManager *manager, - GossipChatroom *chatroom, - GossipChatroomsWindow *window); -static gboolean chatrooms_window_remove_chatroom_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - GossipChatroom *chatroom); -static void chatrooms_window_account_changed_cb (GtkWidget *combo_box, - GossipChatroomsWindow *window); - -enum { - COL_IMAGE, - COL_NAME, - COL_ROOM, - COL_AUTO_CONNECT, - COL_POINTER, - COL_COUNT -}; - -void -gossip_chatrooms_window_show (GtkWindow *parent) -{ - static GossipChatroomsWindow *window = NULL; - GladeXML *glade; - - if (window) { - gtk_window_present (GTK_WINDOW (window->window)); - return; - } - - window = g_new0 (GossipChatroomsWindow, 1); - - glade = gossip_glade_get_file ("gossip-chatrooms-window.glade", - "chatrooms_window", - NULL, - "chatrooms_window", &window->window, - "hbox_account", &window->hbox_account, - "label_account", &window->label_account, - "treeview", &window->treeview, - "button_edit", &window->button_edit, - "button_remove", &window->button_remove, - "button_close", &window->button_close, - NULL); - - gossip_glade_connect (glade, - window, - "chatrooms_window", "destroy", chatrooms_window_destroy_cb, - "button_remove", "clicked", chatrooms_window_button_remove_clicked_cb, - "button_edit", "clicked", chatrooms_window_button_edit_clicked_cb, - "button_close", "clicked", chatrooms_window_button_close_clicked_cb, - NULL); - - g_object_unref (glade); - - g_object_add_weak_pointer (G_OBJECT (window->window), (gpointer) &window); - - /* Get the session and chat room manager */ - window->manager = gossip_chatroom_manager_new (); - - g_signal_connect (window->manager, "chatroom-added", - G_CALLBACK (chatrooms_window_chatroom_added_cb), - window); - g_signal_connect (window->manager, "chatroom-removed", - G_CALLBACK (chatrooms_window_chatroom_removed_cb), - window); - - /* Account chooser for chat rooms */ - window->account_chooser = gossip_account_chooser_new (); - gossip_account_chooser_set_account (GOSSIP_ACCOUNT_CHOOSER (window->account_chooser), NULL); - g_object_set (window->account_chooser, - "can-select-all", TRUE, - "has-all-option", TRUE, - NULL); - - gtk_box_pack_start (GTK_BOX (window->hbox_account), - window->account_chooser, - TRUE, TRUE, 0); - - g_signal_connect (window->account_chooser, "changed", - G_CALLBACK (chatrooms_window_account_changed_cb), - window); - - gtk_widget_show (window->account_chooser); - - /* Set up chatrooms */ - chatrooms_window_model_setup (window); - - /* Set focus */ - gtk_widget_grab_focus (window->treeview); - - /* Last touches */ - if (parent) { - gtk_window_set_transient_for (GTK_WINDOW (window->window), - GTK_WINDOW (parent)); - } - - gtk_widget_show (window->window); -} - -static void -chatrooms_window_destroy_cb (GtkWidget *widget, - GossipChatroomsWindow *window) -{ - g_object_unref (window->manager); - g_free (window); -} - -static void -chatrooms_window_model_setup (GossipChatroomsWindow *window) -{ - GtkTreeView *view; - GtkListStore *store; - GtkTreeSelection *selection; - - /* View */ - view = GTK_TREE_VIEW (window->treeview); - - g_signal_connect (view, "row-activated", - G_CALLBACK (chatrooms_window_row_activated_cb), - window); - - /* Store */ - store = gtk_list_store_new (COL_COUNT, - G_TYPE_STRING, /* Image */ - G_TYPE_STRING, /* Name */ - G_TYPE_STRING, /* Room */ - G_TYPE_BOOLEAN, /* Auto start */ - GOSSIP_TYPE_CHATROOM); /* Chatroom */ - - gtk_tree_view_set_model (view, GTK_TREE_MODEL (store)); - - /* Selection */ - selection = gtk_tree_view_get_selection (view); - gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); - - /* Columns */ - chatrooms_window_model_add_columns (window); - - /* Add data */ - chatrooms_window_model_refresh_data (window, TRUE); - - /* Clean up */ - g_object_unref (store); -} - -static void -chatrooms_window_model_add_columns (GossipChatroomsWindow *window) -{ - GtkTreeView *view; - GtkTreeModel *model; - GtkTreeViewColumn *column; - GtkCellRenderer *cell; - gint count; - - view = GTK_TREE_VIEW (window->treeview); - model = gtk_tree_view_get_model (view); - - gtk_tree_view_set_headers_visible (view, TRUE); - gtk_tree_view_set_headers_clickable (view, TRUE); - - /* Name & Status */ - column = gtk_tree_view_column_new (); - count = gtk_tree_view_append_column (view, column); - - gtk_tree_view_column_set_title (column, _("Name")); - gtk_tree_view_column_set_expand (column, TRUE); - gtk_tree_view_column_set_sort_column_id (column, count - 1); - - cell = gtk_cell_renderer_pixbuf_new (); - gtk_tree_view_column_pack_start (column, cell, FALSE); - gtk_tree_view_column_add_attribute (column, cell, "icon-name", COL_IMAGE); - - cell = gtk_cell_renderer_text_new (); - g_object_set (cell, - "xpad", 4, - "ypad", 1, - NULL); - gtk_tree_view_column_pack_start (column, cell, TRUE); - gtk_tree_view_column_add_attribute (column, cell, "text", COL_NAME); - - /* Room */ - cell = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes (_("Room"), cell, - "text", COL_ROOM, - NULL); - count = gtk_tree_view_append_column (view, column); - gtk_tree_view_column_set_sort_column_id (column, count - 1); - window->room_column = count - 1; - - /* Chatroom auto connect */ - cell = gtk_cell_renderer_toggle_new (); - column = gtk_tree_view_column_new_with_attributes (_("Auto Connect"), cell, - "active", COL_AUTO_CONNECT, - NULL); - count = gtk_tree_view_append_column (view, column); - gtk_tree_view_column_set_sort_column_id (column, count - 1); - - g_signal_connect (cell, "toggled", - G_CALLBACK (chatrooms_window_model_cell_auto_connect_toggled), - window); - - /* Sort model */ - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), 0, - GTK_SORT_ASCENDING); -} - -static void -chatrooms_window_model_refresh_data (GossipChatroomsWindow *window, - gboolean first_time) -{ - GtkTreeView *view; - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkListStore *store; - GtkTreeIter iter; - GtkTreeViewColumn *column; - GossipAccountChooser *account_chooser; - McAccount *account; - GList *chatrooms, *l; - - view = GTK_TREE_VIEW (window->treeview); - selection = gtk_tree_view_get_selection (view); - model = gtk_tree_view_get_model (view); - store = GTK_LIST_STORE (model); - - /* Look up chatrooms */ - account_chooser = GOSSIP_ACCOUNT_CHOOSER (window->account_chooser); - account = gossip_account_chooser_get_account (account_chooser); - - chatrooms = gossip_chatroom_manager_get_chatrooms (window->manager, account); - - /* Sort out columns, we only show the server column for - * selected protocol types, such as Jabber. - */ - if (account) { - column = gtk_tree_view_get_column (view, window->room_column); - gtk_tree_view_column_set_visible (column, TRUE); - } else { - column = gtk_tree_view_get_column (view, window->room_column); - gtk_tree_view_column_set_visible (column, FALSE); - } - - /* Clean out the store */ - gtk_list_store_clear (store); - - /* Populate with chatroom list. */ - for (l = chatrooms; l; l = l->next) { - chatrooms_window_model_add (window, l->data, FALSE); - } - - if (gtk_tree_model_get_iter_first (model, &iter)) { - gtk_tree_selection_select_iter (selection, &iter); - } - - if (account) { - g_object_unref (account); - } - - g_list_free (chatrooms); -} - -static void -chatrooms_window_model_add (GossipChatroomsWindow *window, - GossipChatroom *chatroom, - gboolean set_active) -{ - GtkTreeView *view; - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkListStore *store; - GtkTreeIter iter; - - view = GTK_TREE_VIEW (window->treeview); - selection = gtk_tree_view_get_selection (view); - model = gtk_tree_view_get_model (view); - store = GTK_LIST_STORE (model); - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - COL_NAME, gossip_chatroom_get_name (chatroom), - COL_ROOM, gossip_chatroom_get_room (chatroom), - COL_AUTO_CONNECT, gossip_chatroom_get_auto_connect (chatroom), - COL_POINTER, chatroom, - -1); - - if (set_active) { - gtk_tree_selection_select_iter (selection, &iter); - } -} - -static void -chatrooms_window_model_cell_auto_connect_toggled (GtkCellRendererToggle *cell, - gchar *path_string, - GossipChatroomsWindow *window) -{ - GossipChatroom *chatroom; - gboolean enabled; - GtkTreeView *view; - GtkTreeModel *model; - GtkListStore *store; - GtkTreePath *path; - GtkTreeIter iter; - - view = GTK_TREE_VIEW (window->treeview); - model = gtk_tree_view_get_model (view); - store = GTK_LIST_STORE (model); - - path = gtk_tree_path_new_from_string (path_string); - - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_model_get (model, &iter, - COL_AUTO_CONNECT, &enabled, - COL_POINTER, &chatroom, - -1); - - enabled = !enabled; - - gossip_chatroom_set_auto_connect (chatroom, enabled); - gossip_chatroom_manager_store (window->manager); - - gtk_list_store_set (store, &iter, COL_AUTO_CONNECT, enabled, -1); - gtk_tree_path_free (path); - g_object_unref (chatroom); -} - -static GossipChatroom * -chatrooms_window_model_get_selected (GossipChatroomsWindow *window) -{ - GtkTreeView *view; - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - GossipChatroom *chatroom = NULL; - - view = GTK_TREE_VIEW (window->treeview); - selection = gtk_tree_view_get_selection (view); - - if (gtk_tree_selection_get_selected (selection, &model, &iter)) { - gtk_tree_model_get (model, &iter, COL_POINTER, &chatroom, -1); - } - - return chatroom; -} - -static void -chatrooms_window_model_action_selected (GossipChatroomsWindow *window) -{ - GossipChatroom *chatroom; - GtkTreeView *view; - GtkTreeModel *model; - - view = GTK_TREE_VIEW (window->treeview); - model = gtk_tree_view_get_model (view); - - chatroom = chatrooms_window_model_get_selected (window); - if (!chatroom) { - return; - } - - //gossip_edit_chatroom_dialog_show (GTK_WINDOW (window->window), chatroom); - - g_object_unref (chatroom); -} - -static void -chatrooms_window_row_activated_cb (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - GossipChatroomsWindow *window) -{ - if (GTK_WIDGET_IS_SENSITIVE (window->button_edit)) { - chatrooms_window_model_action_selected (window); - } -} - -static void -chatrooms_window_button_remove_clicked_cb (GtkWidget *widget, - GossipChatroomsWindow *window) -{ - GossipChatroom *chatroom; - GtkTreeView *view; - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - - /* Remove from treeview */ - view = GTK_TREE_VIEW (window->treeview); - selection = gtk_tree_view_get_selection (view); - - if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { - return; - } - - gtk_tree_model_get (model, &iter, COL_POINTER, &chatroom, -1); - gtk_list_store_remove (GTK_LIST_STORE (model), &iter); - - /* Remove from config */ - gossip_chatroom_manager_remove (window->manager, chatroom); - - g_object_unref (chatroom); -} - -static void -chatrooms_window_button_edit_clicked_cb (GtkWidget *widget, - GossipChatroomsWindow *window) -{ - GossipChatroom *chatroom; - - chatroom = chatrooms_window_model_get_selected (window); - if (!chatroom) { - return; - } - - //gossip_edit_chatroom_dialog_show (GTK_WINDOW (window->window), chatroom); - - g_object_unref (chatroom); -} - -static void -chatrooms_window_button_close_clicked_cb (GtkWidget *widget, - GossipChatroomsWindow *window) -{ - gtk_widget_destroy (window->window); -} - -static void -chatrooms_window_chatroom_added_cb (GossipChatroomManager *manager, - GossipChatroom *chatroom, - GossipChatroomsWindow *window) -{ - GossipAccountChooser *account_chooser; - McAccount *account; - - account_chooser = GOSSIP_ACCOUNT_CHOOSER (window->account_chooser); - account = gossip_account_chooser_get_account (account_chooser); - - if (!account) { - chatrooms_window_model_add (window, chatroom, FALSE); - } else { - if (gossip_account_equal (account, gossip_chatroom_get_account (chatroom))) { - chatrooms_window_model_add (window, chatroom, FALSE); - } - - g_object_unref (account); - } -} - -static void -chatrooms_window_chatroom_removed_cb (GossipChatroomManager *manager, - GossipChatroom *chatroom, - GossipChatroomsWindow *window) -{ - GtkTreeModel *model; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (window->treeview)); - - gtk_tree_model_foreach (model, - (GtkTreeModelForeachFunc) chatrooms_window_remove_chatroom_foreach, - chatroom); -} - -static gboolean -chatrooms_window_remove_chatroom_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - GossipChatroom *chatroom) -{ - GossipChatroom *this_chatroom; - - gtk_tree_model_get (model, iter, COL_POINTER, &this_chatroom, -1); - - if (gossip_chatroom_equal (chatroom, this_chatroom)) { - gtk_list_store_remove (GTK_LIST_STORE (model), iter); - g_object_unref (this_chatroom); - return TRUE; - } - - g_object_unref (this_chatroom); - - return FALSE; -} - -static void -chatrooms_window_account_changed_cb (GtkWidget *combo_box, - GossipChatroomsWindow *window) -{ - chatrooms_window_model_refresh_data (window, FALSE); -} - diff --git a/libempathy-gtk/gossip-chatrooms-window.glade b/libempathy-gtk/gossip-chatrooms-window.glade deleted file mode 100644 index ad2971e0..00000000 --- a/libempathy-gtk/gossip-chatrooms-window.glade +++ /dev/null @@ -1,477 +0,0 @@ - - - - - - - 5 - True - Edit Favorite Room - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - False - False - gtk-edit - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - False - False - - - - True - False - 2 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - -6 - - - - - - True - True - True - gtk-save - True - GTK_RELIEF_NORMAL - True - -5 - - - - - 0 - False - True - GTK_PACK_END - - - - - - 5 - True - 5 - 2 - False - 6 - 12 - - - - True - True - True - True - 0 - - True - * - False - - - 1 - 2 - 3 - 4 - - - - - - - True - True - True - True - 0 - - True - * - False - - - 1 - 2 - 2 - 3 - - - - - - - True - True - True - True - 0 - - True - * - False - - - 1 - 2 - 1 - 2 - - - - - - - True - _Room: - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - entry_room - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 3 - 4 - fill - - - - - - - True - S_erver: - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - entry_server - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 2 - 3 - fill - - - - - - - True - _Nickname: - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - entry_nickname - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 1 - 2 - fill - - - - - - - True - N_ame: - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - entry_name - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 0 - 1 - fill - - - - - - - True - True - True - True - 0 - - True - * - False - 25 - - - 1 - 2 - 0 - 1 - - - - - - - True - Join this chat room when Gossip starts and you are connected - True - Join room on start_up - True - GTK_RELIEF_NORMAL - True - False - False - True - - - 1 - 2 - 4 - 5 - fill - - - - - - 0 - True - True - - - - - - - - 12 - True - Manage Favorite Rooms - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - False - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 12 - - - - True - False - 18 - - - - True - False - 12 - - - - True - Account: - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - True - - - - - - - - - 0 - False - True - - - - - - 150 - True - True - GTK_POLICY_NEVER - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - True - True - True - True - False - False - True - False - False - False - - - - - 0 - True - True - - - - - 0 - True - True - - - - - - True - GTK_BUTTONBOX_END - 6 - - - - True - True - True - gtk-close - True - GTK_RELIEF_NORMAL - True - - - - - - True - True - True - gtk-remove - True - GTK_RELIEF_NORMAL - True - - - - - - True - False - True - True - gtk-edit - True - GTK_RELIEF_NORMAL - True - - - - - 0 - False - False - - - - - - - diff --git a/libempathy-gtk/gossip-chatrooms-window.h b/libempathy-gtk/gossip-chatrooms-window.h deleted file mode 100644 index d1314ec2..00000000 --- a/libempathy-gtk/gossip-chatrooms-window.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2004-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Xavier Claessens - * Martyn Russell - * Mikael Hallendal - */ - -#ifndef __GOSSIP_CHATROOMS_WINDOW_H__ -#define __GOSSIP_CHATROOMS_WINDOW_H__ - -G_BEGIN_DECLS - -void gossip_chatrooms_window_show (GtkWindow *parent); - -G_END_DECLS - -#endif /* __GOSSIP_CHATROOMS_WINDOW_H__ */ diff --git a/libempathy-gtk/gossip-contact-groups.c b/libempathy-gtk/gossip-contact-groups.c deleted file mode 100644 index 8a6afda1..00000000 --- a/libempathy-gtk/gossip-contact-groups.c +++ /dev/null @@ -1,286 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2005-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Martyn Russell - */ - -#include "config.h" - -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include - -#include "gossip-contact-groups.h" - -#define DEBUG_DOMAIN "ContactGroups" - -#define CONTACT_GROUPS_XML_FILENAME "contact-groups.xml" -#define CONTACT_GROUPS_DTD_FILENAME "gossip-contact-groups.dtd" - -typedef struct { - gchar *name; - gboolean expanded; -} ContactGroup; - -static void contact_groups_file_parse (const gchar *filename); -static gboolean contact_groups_file_save (void); -static ContactGroup *contact_group_new (const gchar *name, - gboolean expanded); -static void contact_group_free (ContactGroup *group); - -static GList *groups = NULL; - -void -gossip_contact_groups_get_all (void) -{ - gchar *dir; - gchar *file_with_path; - - /* If already set up clean up first */ - if (groups) { - g_list_foreach (groups, (GFunc)contact_group_free, NULL); - g_list_free (groups); - groups = NULL; - } - - dir = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, NULL); - file_with_path = g_build_filename (dir, CONTACT_GROUPS_XML_FILENAME, NULL); - g_free (dir); - - if (g_file_test (file_with_path, G_FILE_TEST_EXISTS)) { - contact_groups_file_parse (file_with_path); - } - - g_free (file_with_path); -} - -static void -contact_groups_file_parse (const gchar *filename) -{ - xmlParserCtxtPtr ctxt; - xmlDocPtr doc; - xmlNodePtr contacts; - xmlNodePtr account; - xmlNodePtr node; - - gossip_debug (DEBUG_DOMAIN, "Attempting to parse file:'%s'...", filename); - - ctxt = xmlNewParserCtxt (); - - /* Parse and validate the file. */ - doc = xmlCtxtReadFile (ctxt, filename, NULL, 0); - if (!doc) { - g_warning ("Failed to parse file:'%s'", filename); - xmlFreeParserCtxt (ctxt); - return; - } - - if (!gossip_xml_validate (doc, CONTACT_GROUPS_DTD_FILENAME)) { - g_warning ("Failed to validate file:'%s'", filename); - xmlFreeDoc(doc); - xmlFreeParserCtxt (ctxt); - return; - } - - /* The root node, contacts. */ - contacts = xmlDocGetRootElement (doc); - - account = NULL; - node = contacts->children; - while (node) { - if (strcmp ((gchar *) node->name, "account") == 0) { - account = node; - break; - } - node = node->next; - } - - node = NULL; - if (account) { - node = account->children; - } - - while (node) { - if (strcmp ((gchar *) node->name, "group") == 0) { - gchar *name; - gchar *expanded_str; - gboolean expanded; - ContactGroup *contact_group; - - name = (gchar *) xmlGetProp (node, "name"); - expanded_str = (gchar *) xmlGetProp (node, "expanded"); - - if (expanded_str && strcmp (expanded_str, "yes") == 0) { - expanded = TRUE; - } else { - expanded = FALSE; - } - - contact_group = contact_group_new (name, expanded); - groups = g_list_append (groups, contact_group); - - xmlFree (name); - xmlFree (expanded_str); - } - - node = node->next; - } - - gossip_debug (DEBUG_DOMAIN, "Parsed %d contact groups", g_list_length (groups)); - - xmlFreeDoc(doc); - xmlFreeParserCtxt (ctxt); -} - -static ContactGroup * -contact_group_new (const gchar *name, - gboolean expanded) -{ - ContactGroup *group; - - group = g_new0 (ContactGroup, 1); - - group->name = g_strdup (name); - group->expanded = expanded; - - return group; -} - -static void -contact_group_free (ContactGroup *group) -{ - g_return_if_fail (group != NULL); - - g_free (group->name); - - g_free (group); -} - -static gboolean -contact_groups_file_save (void) -{ - xmlDocPtr doc; - xmlNodePtr root; - xmlNodePtr node; - GList *l; - gchar *dir; - gchar *file; - - dir = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, NULL); - g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR); - file = g_build_filename (dir, CONTACT_GROUPS_XML_FILENAME, NULL); - g_free (dir); - - doc = xmlNewDoc ("1.0"); - root = xmlNewNode (NULL, "contacts"); - xmlDocSetRootElement (doc, root); - - node = xmlNewChild (root, NULL, "account", NULL); - xmlNewProp (node, "name", "Default"); - - for (l = groups; l; l = l->next) { - ContactGroup *cg; - xmlNodePtr subnode; - - cg = l->data; - - subnode = xmlNewChild (node, NULL, "group", NULL); - xmlNewProp (subnode, "expanded", cg->expanded ? "yes" : "no"); - xmlNewProp (subnode, "name", cg->name); - } - - /* Make sure the XML is indented properly */ - xmlIndentTreeOutput = 1; - - gossip_debug (DEBUG_DOMAIN, "Saving file:'%s'", file); - xmlSaveFormatFileEnc (file, doc, "utf-8", 1); - xmlFreeDoc (doc); - - xmlCleanupParser (); - xmlMemoryDump (); - - g_free (file); - - return TRUE; -} - -gboolean -gossip_contact_group_get_expanded (const gchar *group) -{ - GList *l; - gboolean default_val = TRUE; - - g_return_val_if_fail (group != NULL, default_val); - - for (l = groups; l; l = l->next) { - ContactGroup *cg = l->data; - - if (!cg || !cg->name) { - continue; - } - - if (strcmp (cg->name, group) == 0) { - return cg->expanded; - } - } - - return default_val; -} - -void -gossip_contact_group_set_expanded (const gchar *group, - gboolean expanded) -{ - GList *l; - ContactGroup *cg; - gboolean changed = FALSE; - - g_return_if_fail (group != NULL); - - for (l = groups; l; l = l->next) { - ContactGroup *cg = l->data; - - if (!cg || !cg->name) { - continue; - } - - if (strcmp (cg->name, group) == 0) { - cg->expanded = expanded; - changed = TRUE; - break; - } - } - - /* if here... we don't have a ContactGroup for the group. */ - if (!changed) { - cg = contact_group_new (group, expanded); - groups = g_list_append (groups, cg); - } - - contact_groups_file_save (); -} diff --git a/libempathy-gtk/gossip-contact-groups.dtd b/libempathy-gtk/gossip-contact-groups.dtd deleted file mode 100644 index 689220f0..00000000 --- a/libempathy-gtk/gossip-contact-groups.dtd +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - diff --git a/libempathy-gtk/gossip-contact-groups.h b/libempathy-gtk/gossip-contact-groups.h deleted file mode 100644 index 88bbdc0c..00000000 --- a/libempathy-gtk/gossip-contact-groups.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2005 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Martyn Russell - */ - -#ifndef __GOSSIP_CONTACT_GROUPS_H__ -#define __GOSSIP_CONTACT_GROUPS_H__ - -G_BEGIN_DECLS - -#include - -void gossip_contact_groups_get_all (void); - -gboolean gossip_contact_group_get_expanded (const gchar *group); -void gossip_contact_group_set_expanded (const gchar *group, - gboolean expanded); - -G_END_DECLS - -#endif /* __GOSSIP_CONTACT_GROUPS_H__ */ diff --git a/libempathy-gtk/gossip-contact-list-store.c b/libempathy-gtk/gossip-contact-list-store.c deleted file mode 100644 index 3db336a7..00000000 --- a/libempathy-gtk/gossip-contact-list-store.c +++ /dev/null @@ -1,1484 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2005-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Martyn Russell - * Xavier Claessens - */ - -#include "config.h" - -#include - -#include -#include - -#include - -#include "gossip-contact-list-store.h" -#include "gossip-contact-groups.h" -#include "gossip-ui-utils.h" - -#define DEBUG_DOMAIN "ContactListStore" - -/* Active users are those which have recently changed state - * (e.g. online, offline or from normal to a busy state). - */ - -/* Time user is shown as active */ -#define ACTIVE_USER_SHOW_TIME 7000 - -/* Time after connecting which we wait before active users are enabled */ -#define ACTIVE_USER_WAIT_TO_ENABLE_TIME 5000 - -#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CONTACT_LIST_STORE, GossipContactListStorePriv)) - -struct _GossipContactListStorePriv { - EmpathyContactList *list; - gboolean show_offline; - gboolean show_avatars; - gboolean is_compact; - gboolean show_active; - GossipContactListStoreSort sort_criterium; - guint inhibit_active; - - GossipContactGroupsFunc get_contact_groups; - gpointer get_contact_groups_data; -}; - -typedef struct { - GtkTreeIter iter; - const gchar *name; - gboolean found; -} FindGroup; - -typedef struct { - GossipContact *contact; - gboolean found; - GList *iters; -} FindContact; - -typedef struct { - GossipContactListStore *store; - GossipContact *contact; - gboolean remove; -} ShowActiveData; - -static void gossip_contact_list_store_class_init (GossipContactListStoreClass *klass); -static void gossip_contact_list_store_init (GossipContactListStore *list); -static void contact_list_store_finalize (GObject *object); -static void contact_list_store_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec); -static void contact_list_store_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec); -static void contact_list_store_setup (GossipContactListStore *store); -static gboolean contact_list_store_inibit_active_cb (GossipContactListStore *store); -static void contact_list_store_contact_added_cb (EmpathyContactList *list_iface, - GossipContact *contact, - GossipContactListStore *store); -static void contact_list_store_add_contact (GossipContactListStore *store, - GossipContact *contact); -static void contact_list_store_contact_removed_cb (EmpathyContactList *list_iface, - GossipContact *contact, - GossipContactListStore *store); -static void contact_list_store_remove_contact (GossipContactListStore *store, - GossipContact *contact); -static void contact_list_store_contact_update (GossipContactListStore *store, - GossipContact *contact); -static void contact_list_store_contact_groups_updated_cb (GossipContact *contact, - GParamSpec *param, - GossipContactListStore *store); -static void contact_list_store_contact_updated_cb (GossipContact *contact, - GParamSpec *param, - GossipContactListStore *store); -static void contact_list_store_contact_set_active (GossipContactListStore *store, - GossipContact *contact, - gboolean active, - gboolean set_changed); -static ShowActiveData * contact_list_store_contact_active_new (GossipContactListStore *store, - GossipContact *contact, - gboolean remove); -static void contact_list_store_contact_active_free (ShowActiveData *data); -static gboolean contact_list_store_contact_active_cb (ShowActiveData *data); -static gboolean contact_list_store_get_group_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - FindGroup *fg); -static void contact_list_store_get_group (GossipContactListStore *store, - const gchar *name, - GtkTreeIter *iter_group_to_set, - GtkTreeIter *iter_separator_to_set, - gboolean *created); -static gint contact_list_store_state_sort_func (GtkTreeModel *model, - GtkTreeIter *iter_a, - GtkTreeIter *iter_b, - gpointer user_data); -static gint contact_list_store_name_sort_func (GtkTreeModel *model, - GtkTreeIter *iter_a, - GtkTreeIter *iter_b, - gpointer user_data); -static gboolean contact_list_store_find_contact_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - FindContact *fc); -static GList * contact_list_store_find_contact (GossipContactListStore *store, - GossipContact *contact); -static gboolean contact_list_store_update_list_mode_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - GossipContactListStore *store); - -enum { - PROP_0, - PROP_SHOW_OFFLINE, - PROP_SHOW_AVATARS, - PROP_IS_COMPACT, - PROP_SORT_CRITERIUM -}; - -GType -gossip_contact_list_store_sort_get_type (void) -{ - static GType etype = 0; - - if (etype == 0) { - static const GEnumValue values[] = { - { GOSSIP_CONTACT_LIST_STORE_SORT_NAME, - "GOSSIP_CONTACT_LIST_STORE_SORT_NAME", - "name" }, - { GOSSIP_CONTACT_LIST_STORE_SORT_STATE, - "GOSSIP_CONTACT_LIST_STORE_SORT_STATE", - "state" }, - { 0, NULL, NULL } - }; - - etype = g_enum_register_static ("GossipContactListStoreSort", values); - } - - return etype; -} - -G_DEFINE_TYPE (GossipContactListStore, gossip_contact_list_store, GTK_TYPE_TREE_STORE); - -static void -gossip_contact_list_store_class_init (GossipContactListStoreClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = contact_list_store_finalize; - object_class->get_property = contact_list_store_get_property; - object_class->set_property = contact_list_store_set_property; - - g_object_class_install_property (object_class, - PROP_SHOW_OFFLINE, - g_param_spec_boolean ("show-offline", - "Show Offline", - "Whether contact list should display " - "offline contacts", - FALSE, - G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_SHOW_AVATARS, - g_param_spec_boolean ("show-avatars", - "Show Avatars", - "Whether contact list should display " - "avatars for contacts", - TRUE, - G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_IS_COMPACT, - g_param_spec_boolean ("is-compact", - "Is Compact", - "Whether the contact list is in compact mode or not", - FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_SORT_CRITERIUM, - g_param_spec_enum ("sort-criterium", - "Sort citerium", - "The sort criterium to use for sorting the contact list", - GOSSIP_TYPE_CONTACT_LIST_STORE_SORT, - GOSSIP_CONTACT_LIST_STORE_SORT_NAME, - G_PARAM_READWRITE)); - - g_type_class_add_private (object_class, sizeof (GossipContactListStorePriv)); -} - -static void -gossip_contact_list_store_init (GossipContactListStore *store) -{ - GossipContactListStorePriv *priv; - - priv = GET_PRIV (store); - - priv->inhibit_active = g_timeout_add (ACTIVE_USER_WAIT_TO_ENABLE_TIME, - (GSourceFunc) contact_list_store_inibit_active_cb, - store); -} - -static void -contact_list_store_finalize (GObject *object) -{ - GossipContactListStorePriv *priv; - - priv = GET_PRIV (object); - - /* FIXME: disconnect all signals on the list and contacts */ - - if (priv->list) { - g_object_unref (priv->list); - } - - if (priv->inhibit_active) { - g_source_remove (priv->inhibit_active); - } - - G_OBJECT_CLASS (gossip_contact_list_store_parent_class)->finalize (object); -} - -static void -contact_list_store_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec) -{ - GossipContactListStorePriv *priv; - - priv = GET_PRIV (object); - - switch (param_id) { - case PROP_SHOW_OFFLINE: - g_value_set_boolean (value, priv->show_offline); - break; - case PROP_SHOW_AVATARS: - g_value_set_boolean (value, priv->show_avatars); - break; - case PROP_IS_COMPACT: - g_value_set_boolean (value, priv->is_compact); - break; - case PROP_SORT_CRITERIUM: - g_value_set_enum (value, priv->sort_criterium); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -static void -contact_list_store_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec) -{ - GossipContactListStorePriv *priv; - - priv = GET_PRIV (object); - - switch (param_id) { - case PROP_SHOW_OFFLINE: - gossip_contact_list_store_set_show_offline (GOSSIP_CONTACT_LIST_STORE (object), - g_value_get_boolean (value)); - break; - case PROP_SHOW_AVATARS: - gossip_contact_list_store_set_show_avatars (GOSSIP_CONTACT_LIST_STORE (object), - g_value_get_boolean (value)); - break; - case PROP_IS_COMPACT: - gossip_contact_list_store_set_is_compact (GOSSIP_CONTACT_LIST_STORE (object), - g_value_get_boolean (value)); - break; - case PROP_SORT_CRITERIUM: - gossip_contact_list_store_set_sort_criterium (GOSSIP_CONTACT_LIST_STORE (object), - g_value_get_enum (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -GossipContactListStore * -gossip_contact_list_store_new (EmpathyContactList *list_iface) -{ - GossipContactListStore *store; - GossipContactListStorePriv *priv; - GList *contacts, *l; - - g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST (list_iface), NULL); - - store = g_object_new (GOSSIP_TYPE_CONTACT_LIST_STORE, NULL); - priv = GET_PRIV (store); - - contact_list_store_setup (store); - priv->list = g_object_ref (list_iface); - - /* Signal connection. */ - g_signal_connect (priv->list, - "contact-added", - G_CALLBACK (contact_list_store_contact_added_cb), - store); - g_signal_connect (priv->list, - "contact-removed", - G_CALLBACK (contact_list_store_contact_removed_cb), - store); - - /* Add contacts already created. */ - contacts = empathy_contact_list_get_members (priv->list); - for (l = contacts; l; l = l->next) { - GossipContact *contact; - - contact = l->data; - - contact_list_store_contact_added_cb (priv->list, contact, store); - - g_object_unref (contact); - } - g_list_free (contacts); - - return store; -} - -EmpathyContactList * -gossip_contact_list_store_get_list_iface (GossipContactListStore *store) -{ - GossipContactListStorePriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONTACT_LIST_STORE (store), FALSE); - - priv = GET_PRIV (store); - - return priv->list; -} - -gboolean -gossip_contact_list_store_get_show_offline (GossipContactListStore *store) -{ - GossipContactListStorePriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONTACT_LIST_STORE (store), FALSE); - - priv = GET_PRIV (store); - - return priv->show_offline; -} - -void -gossip_contact_list_store_set_show_offline (GossipContactListStore *store, - gboolean show_offline) -{ - GossipContactListStorePriv *priv; - GList *contacts, *l; - gboolean show_active; - - g_return_if_fail (GOSSIP_IS_CONTACT_LIST_STORE (store)); - - priv = GET_PRIV (store); - - priv->show_offline = show_offline; - show_active = priv->show_active; - - /* Disable temporarily. */ - priv->show_active = FALSE; - - contacts = empathy_contact_list_get_members (priv->list); - for (l = contacts; l; l = l->next) { - GossipContact *contact; - - contact = GOSSIP_CONTACT (l->data); - - contact_list_store_contact_update (store, contact); - - g_object_unref (contact); - } - g_list_free (contacts); - - /* Restore to original setting. */ - priv->show_active = show_active; -} - -gboolean -gossip_contact_list_store_get_show_avatars (GossipContactListStore *store) -{ - GossipContactListStorePriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONTACT_LIST_STORE (store), TRUE); - - priv = GET_PRIV (store); - - return priv->show_avatars; -} - -void -gossip_contact_list_store_set_show_avatars (GossipContactListStore *store, - gboolean show_avatars) -{ - GossipContactListStorePriv *priv; - GtkTreeModel *model; - - g_return_if_fail (GOSSIP_IS_CONTACT_LIST_STORE (store)); - - priv = GET_PRIV (store); - - priv->show_avatars = show_avatars; - - model = GTK_TREE_MODEL (store); - - gtk_tree_model_foreach (model, - (GtkTreeModelForeachFunc) - contact_list_store_update_list_mode_foreach, - store); -} - -gboolean -gossip_contact_list_store_get_is_compact (GossipContactListStore *store) -{ - GossipContactListStorePriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONTACT_LIST_STORE (store), TRUE); - - priv = GET_PRIV (store); - - return priv->is_compact; -} - -void -gossip_contact_list_store_set_is_compact (GossipContactListStore *store, - gboolean is_compact) -{ - GossipContactListStorePriv *priv; - GtkTreeModel *model; - - g_return_if_fail (GOSSIP_IS_CONTACT_LIST_STORE (store)); - - priv = GET_PRIV (store); - - priv->is_compact = is_compact; - - model = GTK_TREE_MODEL (store); - - gtk_tree_model_foreach (model, - (GtkTreeModelForeachFunc) - contact_list_store_update_list_mode_foreach, - store); -} - -GossipContactListStoreSort -gossip_contact_list_store_get_sort_criterium (GossipContactListStore *store) -{ - GossipContactListStorePriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONTACT_LIST_STORE (store), 0); - - priv = GET_PRIV (store); - - return priv->sort_criterium; -} - -void -gossip_contact_list_store_set_sort_criterium (GossipContactListStore *store, - GossipContactListStoreSort sort_criterium) -{ - GossipContactListStorePriv *priv; - - g_return_if_fail (GOSSIP_IS_CONTACT_LIST_STORE (store)); - - priv = GET_PRIV (store); - - priv->sort_criterium = sort_criterium; - - switch (sort_criterium) { - case GOSSIP_CONTACT_LIST_STORE_SORT_STATE: - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), - COL_STATUS, - GTK_SORT_ASCENDING); - break; - - case GOSSIP_CONTACT_LIST_STORE_SORT_NAME: - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), - COL_NAME, - GTK_SORT_ASCENDING); - break; - } -} - -gboolean -gossip_contact_list_store_row_separator_func (GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) -{ - gboolean is_separator = FALSE; - - g_return_val_if_fail (GTK_IS_TREE_MODEL (model), FALSE); - - gtk_tree_model_get (model, iter, - COL_IS_SEPARATOR, &is_separator, - -1); - - return is_separator; -} - -gchar * -gossip_contact_list_store_get_parent_group (GtkTreeModel *model, - GtkTreePath *path, - gboolean *path_is_group) -{ - GtkTreeIter parent_iter, iter; - gchar *name = NULL; - gboolean is_group; - - g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL); - - if (path_is_group) { - *path_is_group = FALSE; - } - - if (!gtk_tree_model_get_iter (model, &iter, path)) { - return NULL; - } - - gtk_tree_model_get (model, &iter, - COL_IS_GROUP, &is_group, - COL_NAME, &name, - -1); - - if (!is_group) { - g_free (name); - name = NULL; - - if (!gtk_tree_model_iter_parent (model, &parent_iter, &iter)) { - return NULL; - } - - iter = parent_iter; - - gtk_tree_model_get (model, &iter, - COL_IS_GROUP, &is_group, - COL_NAME, &name, - -1); - if (!is_group) { - g_free (name); - return NULL; - } - } - - if (path_is_group) { - *path_is_group = TRUE; - } - - return name; -} - -gboolean -gossip_contact_list_store_search_equal_func (GtkTreeModel *model, - gint column, - const gchar *key, - GtkTreeIter *iter, - gpointer search_data) -{ - gchar *name, *name_folded; - gchar *key_folded; - gboolean ret; - - g_return_val_if_fail (GTK_IS_TREE_MODEL (model), FALSE); - - if (!key) { - return FALSE; - } - - gtk_tree_model_get (model, iter, COL_NAME, &name, -1); - - if (!name) { - return FALSE; - } - - name_folded = g_utf8_casefold (name, -1); - key_folded = g_utf8_casefold (key, -1); - - if (name_folded && key_folded && - strstr (name_folded, key_folded)) { - ret = FALSE; - } else { - ret = TRUE; - } - - g_free (name); - g_free (name_folded); - g_free (key_folded); - - return ret; -} - -void -gossip_contact_list_store_set_contact_groups_func (GossipContactListStore *store, - GossipContactGroupsFunc func, - gpointer user_data) -{ - GossipContactListStorePriv *priv; - GList *contacts, *l; - - g_return_if_fail (GOSSIP_IS_CONTACT_LIST_STORE (store)); - - priv = GET_PRIV (store); - - if (func) { - priv->get_contact_groups = func; - priv->get_contact_groups_data = user_data; - } else { - priv->get_contact_groups = NULL; - priv->get_contact_groups_data = NULL; - } - - /* If we set a custom function to get contacts groups we have to - * disconnect our default notify::groups signal and wait for the user - * to call himself gossip_contact_list_store_update_contact_groups () - * when needed. If func is NULL we come back to default. - */ - contacts = empathy_contact_list_get_members (priv->list); - for (l = contacts; l; l = l->next) { - GossipContact *contact; - - contact = l->data; - - if (func) { - g_signal_handlers_disconnect_by_func (contact, - G_CALLBACK (contact_list_store_contact_groups_updated_cb), - store); - } else { - g_signal_connect (contact, "notify::groups", - G_CALLBACK (contact_list_store_contact_groups_updated_cb), - store); - } - - gossip_contact_list_store_update_contact_groups (store, contact); - - g_object_unref (contact); - } - g_list_free (contacts); -} - -void -gossip_contact_list_store_update_contact_groups (GossipContactListStore *store, - GossipContact *contact) -{ - GossipContactListStorePriv *priv; - gboolean show_active; - - g_return_if_fail (GOSSIP_IS_CONTACT_LIST_STORE (store)); - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); - - priv = GET_PRIV (store); - - gossip_debug (DEBUG_DOMAIN, "Contact:'%s' updating groups", - gossip_contact_get_name (contact)); - - /* We do this to make sure the groups are correct, if not, we - * would have to check the groups already set up for each - * contact and then see what has been updated. - */ - show_active = priv->show_active; - priv->show_active = FALSE; - contact_list_store_remove_contact (store, contact); - contact_list_store_add_contact (store, contact); - priv->show_active = show_active; -} - -static void -contact_list_store_setup (GossipContactListStore *store) -{ - GossipContactListStorePriv *priv; - GType types[] = {G_TYPE_STRING, /* Status icon-name */ - GDK_TYPE_PIXBUF, /* Avatar pixbuf */ - G_TYPE_BOOLEAN, /* Avatar pixbuf visible */ - G_TYPE_STRING, /* Name */ - G_TYPE_STRING, /* Status string */ - G_TYPE_BOOLEAN, /* Show status */ - GOSSIP_TYPE_CONTACT, /* Contact type */ - G_TYPE_BOOLEAN, /* Is group */ - G_TYPE_BOOLEAN, /* Is active */ - G_TYPE_BOOLEAN, /* Is online */ - G_TYPE_BOOLEAN}; /* Is separator */ - - priv = GET_PRIV (store); - - gtk_tree_store_set_column_types (GTK_TREE_STORE (store), COL_COUNT, types); - - /* Set up sorting */ - gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store), - COL_NAME, - contact_list_store_name_sort_func, - store, NULL); - gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store), - COL_STATUS, - contact_list_store_state_sort_func, - store, NULL); - - priv->sort_criterium = GOSSIP_CONTACT_LIST_STORE_SORT_NAME; - gossip_contact_list_store_set_sort_criterium (store, priv->sort_criterium); -} - -static gboolean -contact_list_store_inibit_active_cb (GossipContactListStore *store) -{ - GossipContactListStorePriv *priv; - - priv = GET_PRIV (store); - - priv->show_active = TRUE; - priv->inhibit_active = 0; - - return FALSE; -} - -static void -contact_list_store_contact_added_cb (EmpathyContactList *list_iface, - GossipContact *contact, - GossipContactListStore *store) -{ - GossipContactListStorePriv *priv; - - priv = GET_PRIV (store); - - gossip_debug (DEBUG_DOMAIN, - "Contact:'%s' added", - gossip_contact_get_name (contact)); - - if (!priv->get_contact_groups) { - g_signal_connect (contact, "notify::groups", - G_CALLBACK (contact_list_store_contact_groups_updated_cb), - store); - } - g_signal_connect (contact, "notify::presence", - G_CALLBACK (contact_list_store_contact_updated_cb), - store); - g_signal_connect (contact, "notify::name", - G_CALLBACK (contact_list_store_contact_updated_cb), - store); - g_signal_connect (contact, "notify::avatar", - G_CALLBACK (contact_list_store_contact_updated_cb), - store); - g_signal_connect (contact, "notify::type", - G_CALLBACK (contact_list_store_contact_updated_cb), - store); - - contact_list_store_add_contact (store, contact); -} - -static void -contact_list_store_add_contact (GossipContactListStore *store, - GossipContact *contact) -{ - GossipContactListStorePriv *priv; - GtkTreeIter iter; - GList *groups, *l; - - priv = GET_PRIV (store); - - if (!priv->show_offline && !gossip_contact_is_online (contact)) { - return; - } - - /* If no groups just add it at the top level. */ - if (priv->get_contact_groups) { - groups = priv->get_contact_groups (contact, - priv->get_contact_groups_data); - } else { - groups = gossip_contact_get_groups (contact); - } - - if (!groups) { - gtk_tree_store_append (GTK_TREE_STORE (store), &iter, NULL); - gtk_tree_store_set (GTK_TREE_STORE (store), &iter, - COL_NAME, gossip_contact_get_name (contact), - COL_CONTACT, contact, - COL_IS_GROUP, FALSE, - COL_IS_SEPARATOR, FALSE, - -1); - } - - /* Else add to each group. */ - for (l = groups; l; l = l->next) { - GtkTreeIter iter_group; - const gchar *name; - - name = l->data; - if (!name) { - continue; - } - - contact_list_store_get_group (store, name, &iter_group, NULL, NULL); - - gtk_tree_store_insert_after (GTK_TREE_STORE (store), &iter, - &iter_group, NULL); - gtk_tree_store_set (GTK_TREE_STORE (store), &iter, - COL_NAME, gossip_contact_get_name (contact), - COL_CONTACT, contact, - COL_IS_GROUP, FALSE, - COL_IS_SEPARATOR, FALSE, - -1); - } - - contact_list_store_contact_update (store, contact); -} - -static void -contact_list_store_contact_removed_cb (EmpathyContactList *list_iface, - GossipContact *contact, - GossipContactListStore *store) -{ - gossip_debug (DEBUG_DOMAIN, "Contact:'%s' removed", - gossip_contact_get_name (contact)); - - /* Disconnect signals */ - g_signal_handlers_disconnect_by_func (contact, - G_CALLBACK (contact_list_store_contact_groups_updated_cb), - store); - g_signal_handlers_disconnect_by_func (contact, - G_CALLBACK (contact_list_store_contact_updated_cb), - store); - - contact_list_store_remove_contact (store, contact); -} - -static void -contact_list_store_remove_contact (GossipContactListStore *store, - GossipContact *contact) -{ - GossipContactListStorePriv *priv; - GtkTreeModel *model; - GList *iters, *l; - - priv = GET_PRIV (store); - - iters = contact_list_store_find_contact (store, contact); - if (!iters) { - return; - } - - /* Clean up model */ - model = GTK_TREE_MODEL (store); - - for (l = iters; l; l = l->next) { - GtkTreeIter parent; - - /* NOTE: it is only <= 2 here because we have - * separators after the group name, otherwise it - * should be 1. - */ - if (gtk_tree_model_iter_parent (model, &parent, l->data) && - gtk_tree_model_iter_n_children (model, &parent) <= 2) { - gtk_tree_store_remove (GTK_TREE_STORE (store), &parent); - } else { - gtk_tree_store_remove (GTK_TREE_STORE (store), l->data); - } - } - - g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL); - g_list_free (iters); -} - -static void -contact_list_store_contact_update (GossipContactListStore *store, - GossipContact *contact) -{ - GossipContactListStorePriv *priv; - ShowActiveData *data; - GtkTreeModel *model; - GList *iters, *l; - gboolean in_list; - gboolean should_be_in_list; - gboolean was_online = TRUE; - gboolean now_online = FALSE; - gboolean set_model = FALSE; - gboolean do_remove = FALSE; - gboolean do_set_active = FALSE; - gboolean do_set_refresh = FALSE; - GdkPixbuf *pixbuf_avatar; - - priv = GET_PRIV (store); - - model = GTK_TREE_MODEL (store); - - iters = contact_list_store_find_contact (store, contact); - if (!iters) { - in_list = FALSE; - } else { - in_list = TRUE; - } - - /* Get online state now. */ - now_online = gossip_contact_is_online (contact); - - if (priv->show_offline || now_online) { - should_be_in_list = TRUE; - } else { - should_be_in_list = FALSE; - } - - if (!in_list && !should_be_in_list) { - /* Nothing to do. */ - gossip_debug (DEBUG_DOMAIN, - "Contact:'%s' in list:NO, should be:NO", - gossip_contact_get_name (contact)); - - g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL); - g_list_free (iters); - return; - } - else if (in_list && !should_be_in_list) { - gossip_debug (DEBUG_DOMAIN, - "Contact:'%s' in list:YES, should be:NO", - gossip_contact_get_name (contact)); - - if (priv->show_active) { - do_remove = TRUE; - do_set_active = TRUE; - do_set_refresh = TRUE; - - set_model = TRUE; - gossip_debug (DEBUG_DOMAIN, "Remove item (after timeout)"); - } else { - gossip_debug (DEBUG_DOMAIN, "Remove item (now)!"); - contact_list_store_remove_contact (store, contact); - } - } - else if (!in_list && should_be_in_list) { - gossip_debug (DEBUG_DOMAIN, - "Contact:'%s' in list:NO, should be:YES", - gossip_contact_get_name (contact)); - - contact_list_store_add_contact (store, contact); - - if (priv->show_active) { - do_set_active = TRUE; - - gossip_debug (DEBUG_DOMAIN, "Set active (contact added)"); - } - } else { - gossip_debug (DEBUG_DOMAIN, - "Contact:'%s' in list:YES, should be:YES", - gossip_contact_get_name (contact)); - - /* Get online state before. */ - if (iters && g_list_length (iters) > 0) { - gtk_tree_model_get (model, iters->data, - COL_IS_ONLINE, &was_online, - -1); - } - - /* Is this really an update or an online/offline. */ - if (priv->show_active) { - if (was_online != now_online) { - do_set_active = TRUE; - do_set_refresh = TRUE; - - gossip_debug (DEBUG_DOMAIN, "Set active (contact updated %s)", - was_online ? "online -> offline" : - "offline -> online"); - } else { - /* Was TRUE for presence updates. */ - /* do_set_active = FALSE; */ - do_set_refresh = TRUE; - - gossip_debug (DEBUG_DOMAIN, "Set active (contact updated)"); - } - } - - set_model = TRUE; - } - - pixbuf_avatar = gossip_pixbuf_avatar_from_contact_scaled (contact, 32, 32); - for (l = iters; l && set_model; l = l->next) { - gtk_tree_store_set (GTK_TREE_STORE (store), l->data, - COL_ICON_STATUS, gossip_icon_name_for_contact (contact), - COL_PIXBUF_AVATAR, pixbuf_avatar, - COL_PIXBUF_AVATAR_VISIBLE, priv->show_avatars, - COL_NAME, gossip_contact_get_name (contact), - COL_STATUS, gossip_contact_get_status (contact), - COL_STATUS_VISIBLE, !priv->is_compact, - COL_IS_GROUP, FALSE, - COL_IS_ONLINE, now_online, - COL_IS_SEPARATOR, FALSE, - -1); - } - - if (pixbuf_avatar) { - g_object_unref (pixbuf_avatar); - } - - if (priv->show_active && do_set_active) { - contact_list_store_contact_set_active (store, contact, do_set_active, do_set_refresh); - - if (do_set_active) { - data = contact_list_store_contact_active_new (store, contact, do_remove); - g_timeout_add (ACTIVE_USER_SHOW_TIME, - (GSourceFunc) contact_list_store_contact_active_cb, - data); - } - } - - /* FIXME: when someone goes online then offline quickly, the - * first timeout sets the user to be inactive and the second - * timeout removes the user from the contact list, really we - * should remove the first timeout. - */ - g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL); - g_list_free (iters); -} - -static void -contact_list_store_contact_groups_updated_cb (GossipContact *contact, - GParamSpec *param, - GossipContactListStore *store) -{ - gossip_contact_list_store_update_contact_groups (store, contact); -} - -static void -contact_list_store_contact_updated_cb (GossipContact *contact, - GParamSpec *param, - GossipContactListStore *store) -{ - gossip_debug (DEBUG_DOMAIN, - "Contact:'%s' updated, checking roster is in sync...", - gossip_contact_get_name (contact)); - - contact_list_store_contact_update (store, contact); -} - -static void -contact_list_store_contact_set_active (GossipContactListStore *store, - GossipContact *contact, - gboolean active, - gboolean set_changed) -{ - GossipContactListStorePriv *priv; - GtkTreeModel *model; - GList *iters, *l; - - priv = GET_PRIV (store); - model = GTK_TREE_MODEL (store); - - iters = contact_list_store_find_contact (store, contact); - for (l = iters; l; l = l->next) { - GtkTreePath *path; - - gtk_tree_store_set (GTK_TREE_STORE (store), l->data, - COL_IS_ACTIVE, active, - -1); - - gossip_debug (DEBUG_DOMAIN, "Set item %s", active ? "active" : "inactive"); - - if (set_changed) { - path = gtk_tree_model_get_path (model, l->data); - gtk_tree_model_row_changed (model, path, l->data); - gtk_tree_path_free (path); - } - } - - g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL); - g_list_free (iters); - -} - -static ShowActiveData * -contact_list_store_contact_active_new (GossipContactListStore *store, - GossipContact *contact, - gboolean remove) -{ - ShowActiveData *data; - - gossip_debug (DEBUG_DOMAIN, - "Contact:'%s' now active, and %s be removed", - gossip_contact_get_name (contact), - remove ? "WILL" : "WILL NOT"); - - data = g_slice_new0 (ShowActiveData); - - data->store = g_object_ref (store); - data->contact = g_object_ref (contact); - data->remove = remove; - - return data; -} - -static void -contact_list_store_contact_active_free (ShowActiveData *data) -{ - g_object_unref (data->contact); - g_object_unref (data->store); - - g_slice_free (ShowActiveData, data); -} - -static gboolean -contact_list_store_contact_active_cb (ShowActiveData *data) -{ - GossipContactListStorePriv *priv; - - priv = GET_PRIV (data->store); - - if (data->remove && - !priv->show_offline && - !gossip_contact_is_online (data->contact)) { - gossip_debug (DEBUG_DOMAIN, - "Contact:'%s' active timeout, removing item", - gossip_contact_get_name (data->contact)); - contact_list_store_remove_contact (data->store, data->contact); - } - - gossip_debug (DEBUG_DOMAIN, - "Contact:'%s' no longer active", - gossip_contact_get_name (data->contact)); - - contact_list_store_contact_set_active (data->store, - data->contact, - FALSE, - TRUE); - - contact_list_store_contact_active_free (data); - - return FALSE; -} - -static gboolean -contact_list_store_get_group_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - FindGroup *fg) -{ - gchar *str; - gboolean is_group; - - /* Groups are only at the top level. */ - if (gtk_tree_path_get_depth (path) != 1) { - return FALSE; - } - - gtk_tree_model_get (model, iter, - COL_NAME, &str, - COL_IS_GROUP, &is_group, - -1); - - if (is_group && strcmp (str, fg->name) == 0) { - fg->found = TRUE; - fg->iter = *iter; - } - - g_free (str); - - return fg->found; -} - -static void -contact_list_store_get_group (GossipContactListStore *store, - const gchar *name, - GtkTreeIter *iter_group_to_set, - GtkTreeIter *iter_separator_to_set, - gboolean *created) -{ - GossipContactListStorePriv *priv; - GtkTreeModel *model; - GtkTreeIter iter_group; - GtkTreeIter iter_separator; - FindGroup fg; - - priv = GET_PRIV (store); - - memset (&fg, 0, sizeof (fg)); - - fg.name = name; - - model = GTK_TREE_MODEL (store); - gtk_tree_model_foreach (model, - (GtkTreeModelForeachFunc) contact_list_store_get_group_foreach, - &fg); - - if (!fg.found) { - if (created) { - *created = TRUE; - } - - gtk_tree_store_append (GTK_TREE_STORE (store), &iter_group, NULL); - gtk_tree_store_set (GTK_TREE_STORE (store), &iter_group, - COL_ICON_STATUS, NULL, - COL_NAME, name, - COL_IS_GROUP, TRUE, - COL_IS_ACTIVE, FALSE, - COL_IS_SEPARATOR, FALSE, - -1); - - if (iter_group_to_set) { - *iter_group_to_set = iter_group; - } - - gtk_tree_store_append (GTK_TREE_STORE (store), - &iter_separator, - &iter_group); - gtk_tree_store_set (GTK_TREE_STORE (store), &iter_separator, - COL_IS_SEPARATOR, TRUE, - -1); - - if (iter_separator_to_set) { - *iter_separator_to_set = iter_separator; - } - } else { - if (created) { - *created = FALSE; - } - - if (iter_group_to_set) { - *iter_group_to_set = fg.iter; - } - - iter_separator = fg.iter; - - if (gtk_tree_model_iter_next (model, &iter_separator)) { - gboolean is_separator; - - gtk_tree_model_get (model, &iter_separator, - COL_IS_SEPARATOR, &is_separator, - -1); - - if (is_separator && iter_separator_to_set) { - *iter_separator_to_set = iter_separator; - } - } - } -} - -static gint -contact_list_store_state_sort_func (GtkTreeModel *model, - GtkTreeIter *iter_a, - GtkTreeIter *iter_b, - gpointer user_data) -{ - gint ret_val = 0; - gchar *name_a, *name_b; - gboolean is_separator_a, is_separator_b; - GossipContact *contact_a, *contact_b; - GossipPresence *presence_a, *presence_b; - McPresence state_a, state_b; - - gtk_tree_model_get (model, iter_a, - COL_NAME, &name_a, - COL_CONTACT, &contact_a, - COL_IS_SEPARATOR, &is_separator_a, - -1); - gtk_tree_model_get (model, iter_b, - COL_NAME, &name_b, - COL_CONTACT, &contact_b, - COL_IS_SEPARATOR, &is_separator_b, - -1); - - /* Separator or group? */ - if (is_separator_a || is_separator_b) { - if (is_separator_a) { - ret_val = -1; - } else if (is_separator_b) { - ret_val = 1; - } - } else if (!contact_a && contact_b) { - ret_val = 1; - } else if (contact_a && !contact_b) { - ret_val = -1; - } else if (!contact_a && !contact_b) { - /* Handle groups */ - ret_val = g_utf8_collate (name_a, name_b); - } - - if (ret_val) { - goto free_and_out; - } - - /* If we managed to get this far, we can start looking at - * the presences. - */ - presence_a = gossip_contact_get_presence (GOSSIP_CONTACT (contact_a)); - presence_b = gossip_contact_get_presence (GOSSIP_CONTACT (contact_b)); - - if (!presence_a && presence_b) { - ret_val = 1; - } else if (presence_a && !presence_b) { - ret_val = -1; - } else if (!presence_a && !presence_b) { - /* Both offline, sort by name */ - ret_val = g_utf8_collate (name_a, name_b); - } else { - state_a = gossip_presence_get_state (presence_a); - state_b = gossip_presence_get_state (presence_b); - - if (state_a < state_b) { - ret_val = -1; - } else if (state_a > state_b) { - ret_val = 1; - } else { - /* Fallback: compare by name */ - ret_val = g_utf8_collate (name_a, name_b); - } - } - -free_and_out: - g_free (name_a); - g_free (name_b); - - if (contact_a) { - g_object_unref (contact_a); - } - - if (contact_b) { - g_object_unref (contact_b); - } - - return ret_val; -} - -static gint -contact_list_store_name_sort_func (GtkTreeModel *model, - GtkTreeIter *iter_a, - GtkTreeIter *iter_b, - gpointer user_data) -{ - gchar *name_a, *name_b; - GossipContact *contact_a, *contact_b; - gboolean is_separator_a, is_separator_b; - gint ret_val; - - gtk_tree_model_get (model, iter_a, - COL_NAME, &name_a, - COL_CONTACT, &contact_a, - COL_IS_SEPARATOR, &is_separator_a, - -1); - gtk_tree_model_get (model, iter_b, - COL_NAME, &name_b, - COL_CONTACT, &contact_b, - COL_IS_SEPARATOR, &is_separator_b, - -1); - - /* If contact is NULL it means it's a group. */ - - if (is_separator_a || is_separator_b) { - if (is_separator_a) { - ret_val = -1; - } else if (is_separator_b) { - ret_val = 1; - } - } else if (!contact_a && contact_b) { - ret_val = 1; - } else if (contact_a && !contact_b) { - ret_val = -1; - } else { - ret_val = g_utf8_collate (name_a, name_b); - } - - g_free (name_a); - g_free (name_b); - - if (contact_a) { - g_object_unref (contact_a); - } - - if (contact_b) { - g_object_unref (contact_b); - } - - return ret_val; -} - -static gboolean -contact_list_store_find_contact_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - FindContact *fc) -{ - GossipContact *contact; - - gtk_tree_model_get (model, iter, - COL_CONTACT, &contact, - -1); - - if (!contact) { - return FALSE; - } - - if (gossip_contact_equal (contact, fc->contact)) { - fc->found = TRUE; - fc->iters = g_list_append (fc->iters, gtk_tree_iter_copy (iter)); - } - g_object_unref (contact); - - return FALSE; -} - -static GList * -contact_list_store_find_contact (GossipContactListStore *store, - GossipContact *contact) -{ - GossipContactListStorePriv *priv; - GtkTreeModel *model; - GList *l = NULL; - FindContact fc; - - priv = GET_PRIV (store); - - memset (&fc, 0, sizeof (fc)); - - fc.contact = contact; - - model = GTK_TREE_MODEL (store); - gtk_tree_model_foreach (model, - (GtkTreeModelForeachFunc) contact_list_store_find_contact_foreach, - &fc); - - if (fc.found) { - l = fc.iters; - } - - return l; -} - -static gboolean -contact_list_store_update_list_mode_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - GossipContactListStore *store) -{ - GossipContactListStorePriv *priv; - gboolean show_avatar = FALSE; - - priv = GET_PRIV (store); - - if (priv->show_avatars && !priv->is_compact) { - show_avatar = TRUE; - } - - gtk_tree_store_set (GTK_TREE_STORE (store), iter, - COL_PIXBUF_AVATAR_VISIBLE, show_avatar, - COL_STATUS_VISIBLE, !priv->is_compact, - -1); - - return FALSE; -} - diff --git a/libempathy-gtk/gossip-contact-list-store.h b/libempathy-gtk/gossip-contact-list-store.h deleted file mode 100644 index b2131bca..00000000 --- a/libempathy-gtk/gossip-contact-list-store.h +++ /dev/null @@ -1,122 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2005-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Martyn Russell - * Xavier Claessens - */ - -#ifndef __GOSSIP_CONTACT_LIST_STORE_H__ -#define __GOSSIP_CONTACT_LIST_STORE_H__ - -#include - -#include -#include - -G_BEGIN_DECLS - -/* - * GossipContactListStoreSort - */ -#define GOSSIP_TYPE_CONTACT_LIST_STORE_SORT (gossip_contact_list_store_sort_get_type ()) - -typedef enum { - GOSSIP_CONTACT_LIST_STORE_SORT_STATE, - GOSSIP_CONTACT_LIST_STORE_SORT_NAME -} GossipContactListStoreSort; - -GType gossip_contact_list_store_sort_get_type (void) G_GNUC_CONST; - -/* - * GossipContactListStore - */ -#define GOSSIP_TYPE_CONTACT_LIST_STORE (gossip_contact_list_store_get_type ()) -#define GOSSIP_CONTACT_LIST_STORE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOSSIP_TYPE_CONTACT_LIST_STORE, GossipContactListStore)) -#define GOSSIP_CONTACT_LIST_STORE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GOSSIP_TYPE_CONTACT_LIST_STORE, GossipContactListStoreClass)) -#define GOSSIP_IS_CONTACT_LIST_STORE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOSSIP_TYPE_CONTACT_LIST_STORE)) -#define GOSSIP_IS_CONTACT_LIST_STORE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOSSIP_TYPE_CONTACT_LIST_STORE)) -#define GOSSIP_CONTACT_LIST_STORE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOSSIP_TYPE_CONTACT_LIST_STORE, GossipContactListStoreClass)) - -typedef struct _GossipContactListStore GossipContactListStore; -typedef struct _GossipContactListStoreClass GossipContactListStoreClass; -typedef struct _GossipContactListStorePriv GossipContactListStorePriv; - -enum { - COL_ICON_STATUS, - COL_PIXBUF_AVATAR, - COL_PIXBUF_AVATAR_VISIBLE, - COL_NAME, - COL_STATUS, - COL_STATUS_VISIBLE, - COL_CONTACT, - COL_IS_GROUP, - COL_IS_ACTIVE, - COL_IS_ONLINE, - COL_IS_SEPARATOR, - COL_COUNT -} GossipContactListStoreCol; - -struct _GossipContactListStore { - GtkTreeStore parent; -}; - -struct _GossipContactListStoreClass { - GtkTreeStoreClass parent_class; -}; -typedef GList * (*GossipContactGroupsFunc) (GossipContact *contact, - gpointer user_data); - -GType gossip_contact_list_store_get_type (void) G_GNUC_CONST; -GossipContactListStore * gossip_contact_list_store_new (EmpathyContactList *list_iface); -EmpathyContactList * gossip_contact_list_store_get_list_iface (GossipContactListStore *store); -gboolean gossip_contact_list_store_get_show_offline (GossipContactListStore *store); -void gossip_contact_list_store_set_show_offline (GossipContactListStore *store, - gboolean show_offline); -gboolean gossip_contact_list_store_get_show_avatars (GossipContactListStore *store); -void gossip_contact_list_store_set_show_avatars (GossipContactListStore *store, - gboolean show_avatars); -gboolean gossip_contact_list_store_get_is_compact (GossipContactListStore *store); -void gossip_contact_list_store_set_is_compact (GossipContactListStore *store, - gboolean is_compact); -GossipContactListStoreSort gossip_contact_list_store_get_sort_criterium (GossipContactListStore *store); -void gossip_contact_list_store_set_sort_criterium (GossipContactListStore *store, - GossipContactListStoreSort sort_criterium); -gboolean gossip_contact_list_store_row_separator_func (GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data); -gchar * gossip_contact_list_store_get_parent_group (GtkTreeModel *model, - GtkTreePath *path, - gboolean *path_is_group); -gboolean gossip_contact_list_store_search_equal_func (GtkTreeModel *model, - gint column, - const gchar *key, - GtkTreeIter *iter, - gpointer search_data); -void gossip_contact_list_store_set_contact_groups_func (GossipContactListStore*store, - GossipContactGroupsFunc func, - gpointer user_data); -void gossip_contact_list_store_update_contact_groups (GossipContactListStore *store, - GossipContact *contact); - -G_END_DECLS - -#endif /* __GOSSIP_CONTACT_LIST_STORE_H__ */ - diff --git a/libempathy-gtk/gossip-contact-list-view.c b/libempathy-gtk/gossip-contact-list-view.c deleted file mode 100644 index 5c3fd274..00000000 --- a/libempathy-gtk/gossip-contact-list-view.c +++ /dev/null @@ -1,1524 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2005-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Martyn Russell - * Xavier Claessens - */ - -#include "config.h" - -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "gossip-contact-list-view.h" -#include "gossip-contact-list-store.h" -#include "empathy-images.h" -#include "gossip-contact-groups.h" -#include "gossip-cell-renderer-expander.h" -#include "gossip-cell-renderer-text.h" -#include "gossip-ui-utils.h" -#include "empathy-contact-dialogs.h" -//#include "gossip-chat-invite.h" -//#include "gossip-ft-window.h" -#include "gossip-log-window.h" - -#define DEBUG_DOMAIN "ContactListView" - -/* Flashing delay for icons (milliseconds). */ -#define FLASH_TIMEOUT 500 - -/* Active users are those which have recently changed state - * (e.g. online, offline or from normal to a busy state). - */ - -#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CONTACT_LIST_VIEW, GossipContactListViewPriv)) - -struct _GossipContactListViewPriv { - GossipContactListStore *store; - GtkUIManager *ui; - GtkTreeRowReference *drag_row; - GtkTreeModel *filter; - gchar *filter_text; - - GossipContactListViewDragReceivedFunc drag_received; - gpointer drag_received_data; -}; - -typedef struct { - GossipContactListView *view; - GtkTreePath *path; - guint timeout_id; -} DragMotionData; - -typedef struct { - GossipContactListView *view; - GossipContact *contact; - gboolean remove; -} ShowActiveData; - -static void gossip_contact_list_view_class_init (GossipContactListViewClass *klass); -static void gossip_contact_list_view_init (GossipContactListView *list); -static void contact_list_view_finalize (GObject *object); -static void contact_list_view_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec); -static void contact_list_view_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec); -static void contact_list_view_setup (GossipContactListView *view); -static void contact_list_view_row_has_child_toggled_cb (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - GossipContactListView *view); -static void contact_list_view_contact_received (GossipContactListView *view, - GossipContact *contact, - GdkDragAction action, - const gchar *old_group, - const gchar *new_group); -static void contact_list_view_drag_data_received (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection, - guint info, - guint time); -static gboolean contact_list_view_drag_motion (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint time); -static gboolean contact_list_view_drag_motion_cb (DragMotionData *data); -static void contact_list_view_drag_begin (GtkWidget *widget, - GdkDragContext *context); -static void contact_list_view_drag_data_get (GtkWidget *widget, - GdkDragContext *context, - GtkSelectionData *selection, - guint info, - guint time); -static void contact_list_view_drag_end (GtkWidget *widget, - GdkDragContext *context); -static gboolean contact_list_view_drag_drop (GtkWidget *widget, - GdkDragContext *drag_context, - gint x, - gint y, - guint time); -static void contact_list_view_cell_set_background (GossipContactListView *view, - GtkCellRenderer *cell, - gboolean is_group, - gboolean is_active); -static void contact_list_view_pixbuf_cell_data_func (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - GossipContactListView *view); -static void contact_list_view_avatar_cell_data_func (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - GossipContactListView *view); -static void contact_list_view_text_cell_data_func (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - GossipContactListView *view); -static void contact_list_view_expander_cell_data_func (GtkTreeViewColumn *column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - GossipContactListView *view); -static GtkWidget * contact_list_view_get_contact_menu (GossipContactListView *view, - gboolean can_send_file, - gboolean can_show_log); -static gboolean contact_list_view_button_press_event_cb (GossipContactListView *view, - GdkEventButton *event, - gpointer user_data); -static void contact_list_view_row_activated_cb (GossipContactListView *view, - GtkTreePath *path, - GtkTreeViewColumn *col, - gpointer user_data); -static void contact_list_view_row_expand_or_collapse_cb (GossipContactListView *view, - GtkTreeIter *iter, - GtkTreePath *path, - gpointer user_data); -static gboolean contact_list_view_filter_show_contact (GossipContact *contact, - const gchar *filter); -static gboolean contact_list_view_filter_show_group (GossipContactListView *view, - const gchar *group, - const gchar *filter); -static gboolean contact_list_view_filter_func (GtkTreeModel *model, - GtkTreeIter *iter, - GossipContactListView *view); -static void contact_list_view_action_cb (GtkAction *action, - GossipContactListView *view); -static void contact_list_view_action_activated (GossipContactListView *view, - GossipContact *contact); - -enum { - PROP_0, - PROP_FILTER, -}; - -static const GtkActionEntry entries[] = { - { "ContactMenu", NULL, - N_("_Contact"), NULL, NULL, - NULL - }, - { "GroupMenu", NULL, - N_("_Group"),NULL, NULL, - NULL - }, - { "Chat", EMPATHY_IMAGE_MESSAGE, - N_("_Chat"), NULL, N_("Chat with contact"), - G_CALLBACK (contact_list_view_action_cb) - }, - { "Information", EMPATHY_IMAGE_CONTACT_INFORMATION, - N_("Infor_mation"), "I", N_("View contact information"), - G_CALLBACK (contact_list_view_action_cb) - }, - { "Rename", NULL, - N_("Re_name"), NULL, N_("Rename"), - G_CALLBACK (contact_list_view_action_cb) - }, - { "Edit", GTK_STOCK_EDIT, - N_("_Edit"), NULL, N_("Edit the groups and name for this contact"), - G_CALLBACK (contact_list_view_action_cb) - }, - { "Remove", GTK_STOCK_REMOVE, - N_("_Remove"), NULL, N_("Remove contact"), - G_CALLBACK (contact_list_view_action_cb) - }, - { "Invite", EMPATHY_IMAGE_GROUP_MESSAGE, - N_("_Invite to Chat Room"), NULL, N_("Invite to a currently open chat room"), - G_CALLBACK (contact_list_view_action_cb) - }, - { "SendFile", NULL, - N_("_Send File..."), NULL, N_("Send a file"), - G_CALLBACK (contact_list_view_action_cb) - }, - { "Log", GTK_STOCK_JUSTIFY_LEFT, - N_("_View Previous Conversations"), NULL, N_("View previous conversations with this contact"), - G_CALLBACK (contact_list_view_action_cb) - }, -}; - -static guint n_entries = G_N_ELEMENTS (entries); - -static const gchar *ui_info = - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""; - -enum DndDragType { - DND_DRAG_TYPE_CONTACT_ID, - DND_DRAG_TYPE_URL, - DND_DRAG_TYPE_STRING, -}; - -static const GtkTargetEntry drag_types_dest[] = { - { "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID }, - { "text/uri-list", 0, DND_DRAG_TYPE_URL }, - { "text/plain", 0, DND_DRAG_TYPE_STRING }, - { "STRING", 0, DND_DRAG_TYPE_STRING }, -}; - -static const GtkTargetEntry drag_types_source[] = { - { "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID }, -}; - -static GdkAtom drag_atoms_dest[G_N_ELEMENTS (drag_types_dest)]; -static GdkAtom drag_atoms_source[G_N_ELEMENTS (drag_types_source)]; - -enum { - DRAG_CONTACT_RECEIVED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL]; - -G_DEFINE_TYPE (GossipContactListView, gossip_contact_list_view, GTK_TYPE_TREE_VIEW); - -static void -gossip_contact_list_view_class_init (GossipContactListViewClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - - object_class->finalize = contact_list_view_finalize; - object_class->get_property = contact_list_view_get_property; - object_class->set_property = contact_list_view_set_property; - - widget_class->drag_data_received = contact_list_view_drag_data_received; - widget_class->drag_drop = contact_list_view_drag_drop; - widget_class->drag_begin = contact_list_view_drag_begin; - widget_class->drag_data_get = contact_list_view_drag_data_get; - widget_class->drag_end = contact_list_view_drag_end; - /* FIXME: noticed but when you drag the row over the treeview - * fast, it seems to stop redrawing itself, if we don't - * connect this signal, all is fine. - */ - widget_class->drag_motion = contact_list_view_drag_motion; - - signals[DRAG_CONTACT_RECEIVED] = - g_signal_new ("drag-contact-received", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - empathy_marshal_VOID__OBJECT_STRING_STRING, - G_TYPE_NONE, - 3, GOSSIP_TYPE_CONTACT, G_TYPE_STRING, G_TYPE_STRING); - - g_object_class_install_property (object_class, - PROP_FILTER, - g_param_spec_string ("filter", - "Filter", - "The text to use to filter the contact list", - NULL, - G_PARAM_READWRITE)); - - g_type_class_add_private (object_class, sizeof (GossipContactListViewPriv)); -} - -static void -gossip_contact_list_view_init (GossipContactListView *view) -{ - GossipContactListViewPriv *priv; - GtkActionGroup *action_group; - GError *error = NULL; - - priv = GET_PRIV (view); - - /* Get saved group states. */ - gossip_contact_groups_get_all (); - - /* Set up UI Manager */ - priv->ui = gtk_ui_manager_new (); - - action_group = gtk_action_group_new ("Actions"); - gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE); - gtk_action_group_add_actions (action_group, entries, n_entries, view); - gtk_ui_manager_insert_action_group (priv->ui, action_group, 0); - - if (!gtk_ui_manager_add_ui_from_string (priv->ui, ui_info, -1, &error)) { - g_warning ("Could not build contact menus from string:'%s'", error->message); - g_error_free (error); - } - - g_object_unref (action_group); - - gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (view), - gossip_contact_list_store_row_separator_func, - NULL, NULL); - - /* Connect to tree view signals rather than override. */ - g_signal_connect (view, - "button-press-event", - G_CALLBACK (contact_list_view_button_press_event_cb), - NULL); - g_signal_connect (view, - "row-activated", - G_CALLBACK (contact_list_view_row_activated_cb), - NULL); - g_signal_connect (view, - "row-expanded", - G_CALLBACK (contact_list_view_row_expand_or_collapse_cb), - GINT_TO_POINTER (TRUE)); - g_signal_connect (view, - "row-collapsed", - G_CALLBACK (contact_list_view_row_expand_or_collapse_cb), - GINT_TO_POINTER (FALSE)); -} - -static void -contact_list_view_finalize (GObject *object) -{ - GossipContactListViewPriv *priv; - - priv = GET_PRIV (object); - - if (priv->ui) { - g_object_unref (priv->ui); - } - if (priv->store) { - g_object_unref (priv->store); - } - if (priv->filter) { - g_object_unref (priv->filter); - } - g_free (priv->filter_text); - - G_OBJECT_CLASS (gossip_contact_list_view_parent_class)->finalize (object); -} - -static void -contact_list_view_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec) -{ - GossipContactListViewPriv *priv; - - priv = GET_PRIV (object); - - switch (param_id) { - case PROP_FILTER: - g_value_set_string (value, priv->filter_text); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -static void -contact_list_view_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec) -{ - GossipContactListViewPriv *priv; - - priv = GET_PRIV (object); - - switch (param_id) { - case PROP_FILTER: - gossip_contact_list_view_set_filter (GOSSIP_CONTACT_LIST_VIEW (object), - g_value_get_string (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -GossipContactListView * -gossip_contact_list_view_new (GossipContactListStore *store) -{ - GossipContactListViewPriv *priv; - GossipContactListView *view; - - view = g_object_new (GOSSIP_TYPE_CONTACT_LIST_VIEW, NULL); - priv = GET_PRIV (view); - - priv->store = g_object_ref (store); - contact_list_view_setup (view); - - return view; -} - -GossipContact * -gossip_contact_list_view_get_selected (GossipContactListView *view) -{ - GossipContactListViewPriv *priv; - GtkTreeSelection *selection; - GtkTreeIter iter; - GtkTreeModel *model; - GossipContact *contact; - - g_return_val_if_fail (GOSSIP_IS_CONTACT_LIST_VIEW (view), NULL); - - priv = GET_PRIV (view); - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); - if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { - return NULL; - } - - gtk_tree_model_get (model, &iter, COL_CONTACT, &contact, -1); - - return contact; -} - -gchar * -gossip_contact_list_view_get_selected_group (GossipContactListView *view) -{ - GossipContactListViewPriv *priv; - GtkTreeSelection *selection; - GtkTreeIter iter; - GtkTreeModel *model; - gboolean is_group; - gchar *name; - - g_return_val_if_fail (GOSSIP_IS_CONTACT_LIST_VIEW (view), NULL); - - priv = GET_PRIV (view); - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); - if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { - return NULL; - } - - gtk_tree_model_get (model, &iter, - COL_IS_GROUP, &is_group, - COL_NAME, &name, - -1); - - if (!is_group) { - g_free (name); - return NULL; - } - - return name; -} - -GtkWidget * -gossip_contact_list_view_get_group_menu (GossipContactListView *view) -{ - GossipContactListViewPriv *priv; - GtkWidget *widget; - - g_return_val_if_fail (GOSSIP_IS_CONTACT_LIST_VIEW (view), NULL); - - priv = GET_PRIV (view); - - widget = gtk_ui_manager_get_widget (priv->ui, "/Group"); - - return widget; -} - -GtkWidget * -gossip_contact_list_view_get_contact_menu (GossipContactListView *view, - GossipContact *contact) -{ - EmpathyLogManager *log_manager; - gboolean can_show_log; - gboolean can_send_file; - - g_return_val_if_fail (GOSSIP_IS_CONTACT_LIST_VIEW (view), NULL); - g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL); - - log_manager = empathy_log_manager_new (); - can_show_log = empathy_log_manager_exists (log_manager, - gossip_contact_get_account (contact), - gossip_contact_get_id (contact), - FALSE); - can_send_file = FALSE; - g_object_unref (log_manager); - - return contact_list_view_get_contact_menu (view, - can_send_file, - can_show_log); -} - -void -gossip_contact_list_view_set_filter (GossipContactListView *view, - const gchar *filter) -{ - GossipContactListViewPriv *priv; - - g_return_if_fail (GOSSIP_IS_CONTACT_LIST_VIEW (view)); - - priv = GET_PRIV (view); - - g_free (priv->filter_text); - if (filter) { - priv->filter_text = g_utf8_casefold (filter, -1); - } else { - priv->filter_text = NULL; - } - - gossip_debug (DEBUG_DOMAIN, "Refiltering with filter:'%s' (case folded)", filter); - gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter)); -} - -void -gossip_contact_list_view_set_drag_received_func (GossipContactListView *view, - GossipContactListViewDragReceivedFunc func, - gpointer user_data) -{ - GossipContactListViewPriv *priv; - - g_return_if_fail (GOSSIP_IS_CONTACT_LIST_VIEW (view)); - - priv = GET_PRIV (view); - - if (func) { - priv->drag_received = func; - priv->drag_received_data = user_data; - } else { - priv->drag_received = NULL; - priv->drag_received_data = NULL; - } -} - -static void -contact_list_view_setup (GossipContactListView *view) -{ - GossipContactListViewPriv *priv; - GtkCellRenderer *cell; - GtkTreeViewColumn *col; - gint i; - - priv = GET_PRIV (view); - - /* Create filter */ - priv->filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (priv->store), NULL); - - gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (priv->filter), - (GtkTreeModelFilterVisibleFunc) - contact_list_view_filter_func, - view, NULL); - gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (view), - gossip_contact_list_store_search_equal_func, - view, NULL); - g_signal_connect (priv->filter, "row-has-child-toggled", - G_CALLBACK (contact_list_view_row_has_child_toggled_cb), - view); - gtk_tree_view_set_model (GTK_TREE_VIEW (view), priv->filter); - - - /* Setup view */ - g_object_set (view, - "headers-visible", FALSE, - "reorderable", TRUE, - "show-expanders", FALSE, - NULL); - - col = gtk_tree_view_column_new (); - - /* State */ - cell = gtk_cell_renderer_pixbuf_new (); - gtk_tree_view_column_pack_start (col, cell, FALSE); - gtk_tree_view_column_set_cell_data_func ( - col, cell, - (GtkTreeCellDataFunc) contact_list_view_pixbuf_cell_data_func, - view, NULL); - - g_object_set (cell, - "xpad", 5, - "ypad", 1, - "visible", FALSE, - NULL); - - /* Name */ - cell = gossip_cell_renderer_text_new (); - gtk_tree_view_column_pack_start (col, cell, TRUE); - gtk_tree_view_column_set_cell_data_func ( - col, cell, - (GtkTreeCellDataFunc) contact_list_view_text_cell_data_func, - view, NULL); - - gtk_tree_view_column_add_attribute (col, cell, - "name", COL_NAME); - gtk_tree_view_column_add_attribute (col, cell, - "status", COL_STATUS); - gtk_tree_view_column_add_attribute (col, cell, - "is_group", COL_IS_GROUP); - - /* Avatar */ - cell = gtk_cell_renderer_pixbuf_new (); - gtk_tree_view_column_pack_start (col, cell, FALSE); - gtk_tree_view_column_set_cell_data_func ( - col, cell, - (GtkTreeCellDataFunc) contact_list_view_avatar_cell_data_func, - view, NULL); - - g_object_set (cell, - "xpad", 0, - "ypad", 0, - "visible", FALSE, - "width", 32, - "height", 32, - NULL); - - /* Expander */ - cell = gossip_cell_renderer_expander_new (); - gtk_tree_view_column_pack_end (col, cell, FALSE); - gtk_tree_view_column_set_cell_data_func ( - col, cell, - (GtkTreeCellDataFunc) contact_list_view_expander_cell_data_func, - view, NULL); - - /* Actually add the column now we have added all cell renderers */ - gtk_tree_view_append_column (GTK_TREE_VIEW (view), col); - - /* Drag & Drop. */ - for (i = 0; i < G_N_ELEMENTS (drag_types_dest); ++i) { - drag_atoms_dest[i] = gdk_atom_intern (drag_types_dest[i].target, - FALSE); - } - - for (i = 0; i < G_N_ELEMENTS (drag_types_source); ++i) { - drag_atoms_source[i] = gdk_atom_intern (drag_types_source[i].target, - FALSE); - } - - /* Note: We support the COPY action too, but need to make the - * MOVE action the default. - */ - gtk_drag_source_set (GTK_WIDGET (view), - GDK_BUTTON1_MASK, - drag_types_source, - G_N_ELEMENTS (drag_types_source), - GDK_ACTION_MOVE); - - gtk_drag_dest_set (GTK_WIDGET (view), - GTK_DEST_DEFAULT_ALL, - drag_types_dest, - G_N_ELEMENTS (drag_types_dest), - GDK_ACTION_MOVE | GDK_ACTION_LINK); -} - -static void -contact_list_view_row_has_child_toggled_cb (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - GossipContactListView *view) -{ - gboolean is_group = FALSE; - gchar *name = NULL; - - gtk_tree_model_get (model, iter, - COL_IS_GROUP, &is_group, - COL_NAME, &name, - -1); - - if (!is_group || G_STR_EMPTY (name)) { - g_free (name); - return; - } - - if (gossip_contact_group_get_expanded (name)) { - g_signal_handlers_block_by_func (view, - contact_list_view_row_expand_or_collapse_cb, - GINT_TO_POINTER (TRUE)); - gtk_tree_view_expand_row (GTK_TREE_VIEW (view), path, TRUE); - g_signal_handlers_unblock_by_func (view, - contact_list_view_row_expand_or_collapse_cb, - GINT_TO_POINTER (TRUE)); - } else { - g_signal_handlers_block_by_func (view, - contact_list_view_row_expand_or_collapse_cb, - GINT_TO_POINTER (FALSE)); - gtk_tree_view_collapse_row (GTK_TREE_VIEW (view), path); - g_signal_handlers_unblock_by_func (view, - contact_list_view_row_expand_or_collapse_cb, - GINT_TO_POINTER (FALSE)); - } - - g_free (name); -} - -static void -contact_list_view_contact_received (GossipContactListView *view, - GossipContact *contact, - GdkDragAction action, - const gchar *old_group, - const gchar *new_group) -{ - GossipContactListViewPriv *priv; - GList *groups, *l; - GList *new_groups_list = NULL; - - priv = GET_PRIV (view); - - groups = gossip_contact_get_groups (contact); - for (l = groups; l; l = l->next) { - gchar *str; - - str = l->data; - - if (action == GDK_ACTION_MOVE && - old_group != NULL && - strcmp (str, old_group) == 0) { - continue; - } - - if (new_group && strcmp (str, new_group) == 0) { - /* Otherwise we set it twice */ - continue; - } - - new_groups_list = g_list_prepend (new_groups_list, g_strdup (str)); - } - - if (new_group) { - new_groups_list = g_list_prepend (new_groups_list, g_strdup (new_group)); - } - - gossip_contact_set_groups (contact, new_groups_list); -} - -static void -contact_list_view_drag_data_received (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection, - guint info, - guint time) -{ - GossipContactListViewPriv *priv; - EmpathyContactList *list; - GtkTreeModel *model; - GtkTreePath *path; - GtkTreeViewDropPosition position; - GossipContact *contact; - const gchar *id; - gchar *new_group = NULL; - gchar *old_group = NULL; - gboolean is_row; - - priv = GET_PRIV (widget); - - id = (const gchar*) selection->data; - gossip_debug (DEBUG_DOMAIN, "Received %s%s drag & drop contact from roster with id:'%s'", - context->action == GDK_ACTION_MOVE ? "move" : "", - context->action == GDK_ACTION_COPY ? "copy" : "", - id); - - /* FIXME: This is ambigous, an id can come from multiple accounts */ - list = gossip_contact_list_store_get_list_iface (priv->store); - contact = empathy_contact_list_find (list, id); - - if (!contact) { - gossip_debug (DEBUG_DOMAIN, "No contact found associated with drag & drop"); - return; - } - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); - - /* Get source group information. */ - if (priv->drag_row) { - path = gtk_tree_row_reference_get_path (priv->drag_row); - if (path) { - old_group = gossip_contact_list_store_get_parent_group (model, path, NULL); - gtk_tree_path_free (path); - } - } - - /* Get destination group information. */ - is_row = gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget), - x, - y, - &path, - &position); - - if (is_row) { - new_group = gossip_contact_list_store_get_parent_group (model, path, NULL); - gtk_tree_path_free (path); - } - - gossip_debug (DEBUG_DOMAIN, - "contact '%s' dragged from '%s' to '%s'", - gossip_contact_get_name (contact), - old_group, new_group); - - if (priv->drag_received) { - priv->drag_received (contact, - context->action, - old_group, - new_group, - priv->drag_received_data); - } else { - contact_list_view_contact_received (GOSSIP_CONTACT_LIST_VIEW (widget), - contact, - context->action, - old_group, - new_group); - } - - g_free (old_group); - g_free (new_group); - - gtk_drag_finish (context, TRUE, FALSE, GDK_CURRENT_TIME); -} - -static gboolean -contact_list_view_drag_motion (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint time) -{ - static DragMotionData *dm = NULL; - GtkTreePath *path; - gboolean is_row; - gboolean is_different = FALSE; - gboolean cleanup = TRUE; - - is_row = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), - x, - y, - &path, - NULL, - NULL, - NULL); - - cleanup &= (!dm); - - if (is_row) { - cleanup &= (dm && gtk_tree_path_compare (dm->path, path) != 0); - is_different = (!dm || (dm && gtk_tree_path_compare (dm->path, path) != 0)); - } else { - cleanup &= FALSE; - } - - if (!is_different && !cleanup) { - return TRUE; - } - - if (dm) { - gtk_tree_path_free (dm->path); - if (dm->timeout_id) { - g_source_remove (dm->timeout_id); - } - - g_free (dm); - - dm = NULL; - } - - if (!gtk_tree_view_row_expanded (GTK_TREE_VIEW (widget), path)) { - dm = g_new0 (DragMotionData, 1); - - dm->view = GOSSIP_CONTACT_LIST_VIEW (widget); - dm->path = gtk_tree_path_copy (path); - - dm->timeout_id = g_timeout_add ( - 1500, - (GSourceFunc) contact_list_view_drag_motion_cb, - dm); - } - - return TRUE; -} - -static gboolean -contact_list_view_drag_motion_cb (DragMotionData *data) -{ - gtk_tree_view_expand_row (GTK_TREE_VIEW (data->view), - data->path, - FALSE); - - data->timeout_id = 0; - - return FALSE; -} - -static void -contact_list_view_drag_begin (GtkWidget *widget, - GdkDragContext *context) -{ - GossipContactListViewPriv *priv; - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreePath *path; - GtkTreeIter iter; - - priv = GET_PRIV (widget); - - GTK_WIDGET_CLASS (gossip_contact_list_view_parent_class)->drag_begin (widget, - context); - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); - if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { - return; - } - - path = gtk_tree_model_get_path (model, &iter); - priv->drag_row = gtk_tree_row_reference_new (model, path); - gtk_tree_path_free (path); -} - -static void -contact_list_view_drag_data_get (GtkWidget *widget, - GdkDragContext *context, - GtkSelectionData *selection, - guint info, - guint time) -{ - GossipContactListViewPriv *priv; - GtkTreePath *src_path; - GtkTreeIter iter; - GtkTreeModel *model; - GossipContact *contact; - const gchar *id; - - priv = GET_PRIV (widget); - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); - if (!priv->drag_row) { - return; - } - - src_path = gtk_tree_row_reference_get_path (priv->drag_row); - if (!src_path) { - return; - } - - if (!gtk_tree_model_get_iter (model, &iter, src_path)) { - gtk_tree_path_free (src_path); - return; - } - - gtk_tree_path_free (src_path); - - contact = gossip_contact_list_view_get_selected (GOSSIP_CONTACT_LIST_VIEW (widget)); - if (!contact) { - return; - } - - id = gossip_contact_get_id (contact); - g_object_unref (contact); - - switch (info) { - case DND_DRAG_TYPE_CONTACT_ID: - gtk_selection_data_set (selection, drag_atoms_source[info], 8, - (guchar*)id, strlen (id) + 1); - break; - - default: - return; - } -} - -static void -contact_list_view_drag_end (GtkWidget *widget, - GdkDragContext *context) -{ - GossipContactListViewPriv *priv; - - priv = GET_PRIV (widget); - - GTK_WIDGET_CLASS (gossip_contact_list_view_parent_class)->drag_end (widget, - context); - - if (priv->drag_row) { - gtk_tree_row_reference_free (priv->drag_row); - priv->drag_row = NULL; - } -} - -static gboolean -contact_list_view_drag_drop (GtkWidget *widget, - GdkDragContext *drag_context, - gint x, - gint y, - guint time) -{ - return FALSE; -} - -static void -contact_list_view_cell_set_background (GossipContactListView *view, - GtkCellRenderer *cell, - gboolean is_group, - gboolean is_active) -{ - GdkColor color; - GtkStyle *style; - - style = gtk_widget_get_style (GTK_WIDGET (view)); - - if (!is_group) { - if (is_active) { - color = style->bg[GTK_STATE_SELECTED]; - - /* Here we take the current theme colour and add it to - * the colour for white and average the two. This - * gives a colour which is inline with the theme but - * slightly whiter. - */ - color.red = (color.red + (style->white).red) / 2; - color.green = (color.green + (style->white).green) / 2; - color.blue = (color.blue + (style->white).blue) / 2; - - g_object_set (cell, - "cell-background-gdk", &color, - NULL); - } else { - g_object_set (cell, - "cell-background-gdk", NULL, - NULL); - } - } else { - g_object_set (cell, - "cell-background-gdk", NULL, - NULL); - } -} - -static void -contact_list_view_pixbuf_cell_data_func (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - GossipContactListView *view) -{ - gchar *icon_name; - gboolean is_group; - gboolean is_active; - - gtk_tree_model_get (model, iter, - COL_IS_GROUP, &is_group, - COL_IS_ACTIVE, &is_active, - COL_ICON_STATUS, &icon_name, - -1); - - g_object_set (cell, - "visible", !is_group, - "icon-name", icon_name, - NULL); - - g_free (icon_name); - - contact_list_view_cell_set_background (view, cell, is_group, is_active); -} - -static void -contact_list_view_avatar_cell_data_func (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - GossipContactListView *view) -{ - GdkPixbuf *pixbuf; - gboolean show_avatar; - gboolean is_group; - gboolean is_active; - - gtk_tree_model_get (model, iter, - COL_PIXBUF_AVATAR, &pixbuf, - COL_PIXBUF_AVATAR_VISIBLE, &show_avatar, - COL_IS_GROUP, &is_group, - COL_IS_ACTIVE, &is_active, - -1); - - g_object_set (cell, - "visible", !is_group && show_avatar, - "pixbuf", pixbuf, - NULL); - - if (pixbuf) { - g_object_unref (pixbuf); - } - - contact_list_view_cell_set_background (view, cell, is_group, is_active); -} - -static void -contact_list_view_text_cell_data_func (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - GossipContactListView *view) -{ - gboolean is_group; - gboolean is_active; - gboolean show_status; - - gtk_tree_model_get (model, iter, - COL_IS_GROUP, &is_group, - COL_IS_ACTIVE, &is_active, - COL_STATUS_VISIBLE, &show_status, - -1); - - g_object_set (cell, - "show-status", show_status, - NULL); - - contact_list_view_cell_set_background (view, cell, is_group, is_active); -} - -static void -contact_list_view_expander_cell_data_func (GtkTreeViewColumn *column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - GossipContactListView *view) -{ - gboolean is_group; - gboolean is_active; - - gtk_tree_model_get (model, iter, - COL_IS_GROUP, &is_group, - COL_IS_ACTIVE, &is_active, - -1); - - if (gtk_tree_model_iter_has_child (model, iter)) { - GtkTreePath *path; - gboolean row_expanded; - - path = gtk_tree_model_get_path (model, iter); - row_expanded = gtk_tree_view_row_expanded (GTK_TREE_VIEW (column->tree_view), path); - gtk_tree_path_free (path); - - g_object_set (cell, - "visible", TRUE, - "expander-style", row_expanded ? GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED, - NULL); - } else { - g_object_set (cell, "visible", FALSE, NULL); - } - - contact_list_view_cell_set_background (view, cell, is_group, is_active); -} - -static GtkWidget * -contact_list_view_get_contact_menu (GossipContactListView *view, - gboolean can_send_file, - gboolean can_show_log) -{ - GossipContactListViewPriv *priv; - GtkAction *action; - GtkWidget *widget; - - priv = GET_PRIV (view); - - /* Sort out sensitive items */ - action = gtk_ui_manager_get_action (priv->ui, "/Contact/Log"); - gtk_action_set_sensitive (action, can_show_log); - - action = gtk_ui_manager_get_action (priv->ui, "/Contact/SendFile"); - gtk_action_set_visible (action, can_send_file); - - widget = gtk_ui_manager_get_widget (priv->ui, "/Contact"); - - return widget; -} - -static gboolean -contact_list_view_button_press_event_cb (GossipContactListView *view, - GdkEventButton *event, - gpointer user_data) -{ - GossipContactListViewPriv *priv; - GossipContact *contact; - GtkTreePath *path; - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeIter iter; - gboolean row_exists; - GtkWidget *menu; - - if (event->button != 3) { - return FALSE; - } - - priv = GET_PRIV (view); - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); - model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); - - gtk_widget_grab_focus (GTK_WIDGET (view)); - - row_exists = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (view), - event->x, event->y, - &path, - NULL, NULL, NULL); - if (!row_exists) { - return FALSE; - } - - gtk_tree_selection_unselect_all (selection); - gtk_tree_selection_select_path (selection, path); - - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_path_free (path); - - gtk_tree_model_get (model, &iter, COL_CONTACT, &contact, -1); - - if (contact) { - menu = gossip_contact_list_view_get_contact_menu (view, contact); - g_object_unref (contact); - } else { - menu = gossip_contact_list_view_get_group_menu (view); - } - - if (!menu) { - return FALSE; - } - - gtk_widget_show (menu); - - gtk_menu_popup (GTK_MENU (menu), - NULL, NULL, NULL, NULL, - event->button, event->time); - - return TRUE; -} - -static void -contact_list_view_row_activated_cb (GossipContactListView *view, - GtkTreePath *path, - GtkTreeViewColumn *col, - gpointer user_data) -{ - GossipContact *contact; - GtkTreeModel *model; - GtkTreeIter iter; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); - - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_model_get (model, &iter, COL_CONTACT, &contact, -1); - - if (contact) { - contact_list_view_action_activated (view, contact); - g_object_unref (contact); - } -} - -static void -contact_list_view_row_expand_or_collapse_cb (GossipContactListView *view, - GtkTreeIter *iter, - GtkTreePath *path, - gpointer user_data) -{ - GtkTreeModel *model; - gchar *name; - gboolean expanded; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); - - gtk_tree_model_get (model, iter, - COL_NAME, &name, - -1); - - expanded = GPOINTER_TO_INT (user_data); - gossip_contact_group_set_expanded (name, expanded); - - g_free (name); -} - -static gboolean -contact_list_view_filter_show_contact (GossipContact *contact, - const gchar *filter) -{ - gchar *str; - gboolean visible; - - /* Check contact id */ - str = g_utf8_casefold (gossip_contact_get_id (contact), -1); - visible = G_STR_EMPTY (str) || strstr (str, filter); - g_free (str); - - if (visible) { - return TRUE; - } - - /* Check contact name */ - str = g_utf8_casefold (gossip_contact_get_name (contact), -1); - visible = G_STR_EMPTY (str) || strstr (str, filter); - g_free (str); - - return visible; -} - -static gboolean -contact_list_view_filter_show_group (GossipContactListView *view, - const gchar *group, - const gchar *filter) -{ - GossipContactListViewPriv *priv; - EmpathyContactList *list; - GList *contacts, *l; - gchar *str; - gboolean show_group = FALSE; - - priv = GET_PRIV (view); - - str = g_utf8_casefold (group, -1); - if (!str) { - return FALSE; - } - - /* If the filter is the partially the group name, we show the - * whole group. - */ - if (strstr (str, filter)) { - g_free (str); - return TRUE; - } - - /* At this point, we need to check in advance if this - * group should be shown because a contact we want to - * show exists in it. - */ - list = gossip_contact_list_store_get_list_iface (priv->store); - contacts = empathy_contact_list_get_members (list); - for (l = contacts; l && !show_group; l = l->next) { - if (!gossip_contact_is_in_group (l->data, group)) { - g_object_unref (l->data); - continue; - } - - if (contact_list_view_filter_show_contact (l->data, filter)) { - show_group = TRUE; - } - g_object_unref (l->data); - } - g_list_free (contacts); - g_free (str); - - return show_group; -} - -static gboolean -contact_list_view_filter_func (GtkTreeModel *model, - GtkTreeIter *iter, - GossipContactListView *view) -{ - GossipContactListViewPriv *priv; - gboolean is_group; - gboolean is_separator; - gboolean visible = TRUE; - - priv = GET_PRIV (view); - - if (G_STR_EMPTY (priv->filter_text)) { - return TRUE; - } - - /* Check to see if iter matches any group names */ - gtk_tree_model_get (model, iter, - COL_IS_GROUP, &is_group, - COL_IS_SEPARATOR, &is_separator, - -1); - - if (is_group) { - gchar *name; - - gtk_tree_model_get (model, iter, COL_NAME, &name, -1); - visible &= contact_list_view_filter_show_group (view, - name, - priv->filter_text); - g_free (name); - } else if (is_separator) { - /* Do nothing here */ - } else { - GossipContact *contact; - - /* Check contact id */ - gtk_tree_model_get (model, iter, COL_CONTACT, &contact, -1); - visible &= contact_list_view_filter_show_contact (contact, - priv->filter_text); - g_object_unref (contact); - } - - return visible; -} - -static void -contact_list_view_action_cb (GtkAction *action, - GossipContactListView *view) -{ - GossipContactListViewPriv *priv; - GossipContact *contact; - const gchar *name; - gchar *group; - GtkWindow *parent; - - priv = GET_PRIV (view); - - name = gtk_action_get_name (action); - if (!name) { - return; - } - - gossip_debug (DEBUG_DOMAIN, "Action:'%s' activated", name); - - contact = gossip_contact_list_view_get_selected (view); - group = gossip_contact_list_view_get_selected_group (view); - parent = gossip_get_toplevel_window (GTK_WIDGET (view)); - - if (contact && strcmp (name, "Chat") == 0) { - contact_list_view_action_activated (view, contact); - } - else if (contact && strcmp (name, "Information") == 0) { - empathy_contact_information_dialog_show (contact, parent, FALSE); - } - else if (contact && strcmp (name, "Edit") == 0) { - empathy_contact_information_dialog_show (contact, parent, TRUE); - } - else if (contact && strcmp (name, "Remove") == 0) { - /* FIXME: Ask for confirmation */ - EmpathyContactList *list; - - list = gossip_contact_list_store_get_list_iface (priv->store); - empathy_contact_list_remove (list, contact, - _("Sorry, I don't want you in my contact list anymore.")); - } - else if (contact && strcmp (name, "Invite") == 0) { - } - else if (contact && strcmp (name, "SendFile") == 0) { - } - else if (contact && strcmp (name, "Log") == 0) { - gossip_log_window_show (gossip_contact_get_account (contact), - gossip_contact_get_id (contact), - FALSE, - parent); - } - else if (group && strcmp (name, "Rename") == 0) { - } - - g_free (group); - if (contact) { - g_object_unref (contact); - } -} - -static void -contact_list_view_action_activated (GossipContactListView *view, - GossipContact *contact) -{ - MissionControl *mc; - - mc = gossip_mission_control_new (); - mission_control_request_channel (mc, - gossip_contact_get_account (contact), - TP_IFACE_CHANNEL_TYPE_TEXT, - gossip_contact_get_handle (contact), - TP_HANDLE_TYPE_CONTACT, - NULL, NULL); - g_object_unref (mc); -} - diff --git a/libempathy-gtk/gossip-contact-list-view.h b/libempathy-gtk/gossip-contact-list-view.h deleted file mode 100644 index 20262f8a..00000000 --- a/libempathy-gtk/gossip-contact-list-view.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2005-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Martyn Russell - * Xavier Claessens - */ - -#ifndef __GOSSIP_CONTACT_LIST_VIEW_H__ -#define __GOSSIP_CONTACT_LIST_VIEW_H__ - -#include - -#include - -#include "gossip-contact-list-store.h" - -G_BEGIN_DECLS - -#define GOSSIP_TYPE_CONTACT_LIST_VIEW (gossip_contact_list_view_get_type ()) -#define GOSSIP_CONTACT_LIST_VIEW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOSSIP_TYPE_CONTACT_LIST_VIEW, GossipContactListView)) -#define GOSSIP_CONTACT_LIST_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GOSSIP_TYPE_CONTACT_LIST_VIEW, GossipContactListViewClass)) -#define GOSSIP_IS_CONTACT_LIST_VIEW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOSSIP_TYPE_CONTACT_LIST_VIEW)) -#define GOSSIP_IS_CONTACT_LIST_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOSSIP_TYPE_CONTACT_LIST_VIEW)) -#define GOSSIP_CONTACT_LIST_VIEW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOSSIP_TYPE_CONTACT_LIST_VIEW, GossipContactListViewClass)) - -typedef struct _GossipContactListView GossipContactListView; -typedef struct _GossipContactListViewClass GossipContactListViewClass; -typedef struct _GossipContactListViewPriv GossipContactListViewPriv; - -struct _GossipContactListView { - GtkTreeView parent; -}; - -struct _GossipContactListViewClass { - GtkTreeViewClass parent_class; -}; - -typedef void (*GossipContactListViewDragReceivedFunc) (GossipContact *contact, - GdkDragAction action, - const gchar *old_group, - const gchar *new_group, - gpointer user_data); - -GType gossip_contact_list_view_get_type (void) G_GNUC_CONST; -GossipContactListView *gossip_contact_list_view_new (GossipContactListStore *store); -GossipContact * gossip_contact_list_view_get_selected (GossipContactListView *view); -gchar * gossip_contact_list_view_get_selected_group (GossipContactListView *view); -GtkWidget * gossip_contact_list_view_get_contact_menu (GossipContactListView *view, - GossipContact *contact); -GtkWidget * gossip_contact_list_view_get_group_menu (GossipContactListView *view); -void gossip_contact_list_view_set_filter (GossipContactListView *view, - const gchar *filter); -void gossip_contact_list_view_set_drag_received_func (GossipContactListView *view, - GossipContactListViewDragReceivedFunc func, - gpointer user_data); - -G_END_DECLS - -#endif /* __GOSSIP_CONTACT_LIST_VIEW_H__ */ - diff --git a/libempathy-gtk/gossip-geometry.c b/libempathy-gtk/gossip-geometry.c deleted file mode 100644 index ad0bd8dd..00000000 --- a/libempathy-gtk/gossip-geometry.c +++ /dev/null @@ -1,186 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Martyn Russell - * Xavier Claessens - */ - -#include "config.h" - -#include - -#include -#include - -#include - -#include "gossip-geometry.h" - -#define DEBUG_DOMAIN "Geometry" - -#define GEOMETRY_DIR_CREATE_MODE (S_IRUSR | S_IWUSR | S_IXUSR) -#define GEOMETRY_FILE_CREATE_MODE (S_IRUSR | S_IWUSR) - -#define GEOMETRY_KEY_FILENAME "geometry.ini" -#define GEOMETRY_FORMAT "%d,%d,%d,%d" -#define GEOMETRY_GROUP_NAME "geometry" - -static gchar *geometry_get_filename (void); - -static gchar * -geometry_get_filename (void) -{ - gchar *dir; - gchar *filename; - - dir = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, NULL); - if (!g_file_test (dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { - gossip_debug (DEBUG_DOMAIN, "Creating directory:'%s'", dir); - g_mkdir_with_parents (dir, GEOMETRY_DIR_CREATE_MODE); - } - - filename = g_build_filename (dir, GEOMETRY_KEY_FILENAME, NULL); - g_free (dir); - - return filename; -} - -void -gossip_geometry_save (const gchar *name, - gint x, - gint y, - gint w, - gint h) -{ - GError *error = NULL; - GKeyFile *key_file; - gchar *filename; - GdkScreen *screen; - gint max_width; - gint max_height; - gchar *content; - gsize length; - gchar *str; - - gossip_debug (DEBUG_DOMAIN, "Saving window geometry: x:%d, y:%d, w:%d, h:%d\n", - x, y, w, h); - - screen = gdk_screen_get_default (); - max_width = gdk_screen_get_width (screen); - max_height = gdk_screen_get_height (screen); - - w = CLAMP (w, 100, max_width); - h = CLAMP (h, 100, max_height); - - x = CLAMP (x, 0, max_width - w); - y = CLAMP (y, 0, max_height - h); - - str = g_strdup_printf (GEOMETRY_FORMAT, x, y, w, h); - - key_file = g_key_file_new (); - - filename = geometry_get_filename (); - - g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL); - g_key_file_set_string (key_file, GEOMETRY_GROUP_NAME, name, str); - - g_free (str); - - content = g_key_file_to_data (key_file, &length, NULL); - if (!g_file_set_contents (filename, content, length, &error)) { - g_warning ("Couldn't save window geometry, error:%d->'%s'", - error->code, error->message); - g_error_free (error); - } - - g_free (content); - g_free (filename); - g_key_file_free (key_file); -} - -void -gossip_geometry_load (const gchar *name, - gint *x, - gint *y, - gint *w, - gint *h) -{ - GKeyFile *key_file; - gchar *filename; - gchar *str = NULL; - - if (x) { - *x = -1; - } - - if (y) { - *y = -1; - } - - if (w) { - *w = -1; - } - - if (h) { - *h = -1; - } - - key_file = g_key_file_new (); - - filename = geometry_get_filename (); - - if (g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL)) { - str = g_key_file_get_string (key_file, GEOMETRY_GROUP_NAME, name, NULL); - } - - if (str) { - gint tmp_x, tmp_y, tmp_w, tmp_h; - - sscanf (str, GEOMETRY_FORMAT, &tmp_x, &tmp_y, &tmp_w, &tmp_h); - - if (x) { - *x = tmp_x; - } - - if (y) { - *y = tmp_y; - } - - if (w) { - *w = tmp_w; - } - - if (h) { - *h = tmp_h; - } - - g_free (str); - } - - gossip_debug (DEBUG_DOMAIN, "Loading window geometry: x:%d, y:%d, w:%d, h:%d\n", - x ? *x : -1, - y ? *y : -1, - w ? *w : -1, - h ? *h : -1); - - g_free (filename); - g_key_file_free (key_file); -} - diff --git a/libempathy-gtk/gossip-geometry.h b/libempathy-gtk/gossip-geometry.h deleted file mode 100644 index 24534fb3..00000000 --- a/libempathy-gtk/gossip-geometry.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Martyn Russell - * Xavier Claessens - */ - -#ifndef __GOSSIP_GEOMETRY_H__ -#define __GOSSIP_GEOMETRY_H__ - -#include - -G_BEGIN_DECLS - -void gossip_geometry_save (const gchar *name, - gint x, - gint y, - gint w, - gint h); -void gossip_geometry_load (const gchar *name, - gint *x, - gint *y, - gint *w, - gint *h); - -G_END_DECLS - -#endif /* __GOSSIP_GEOMETRY_H__ */ diff --git a/libempathy-gtk/gossip-group-chat.c b/libempathy-gtk/gossip-group-chat.c deleted file mode 100644 index 9f3a0f79..00000000 --- a/libempathy-gtk/gossip-group-chat.c +++ /dev/null @@ -1,707 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2002-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Richard Hult - * Martyn Russell - * Xavier Claessens - */ - -#include "config.h" - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "gossip-group-chat.h" -#include "gossip-chat.h" -#include "gossip-chat-view.h" -#include "gossip-contact-list-store.h" -#include "gossip-contact-list-view.h" -//#include "gossip-chat-invite.h" -//#include "gossip-sound.h" -#include "empathy-images.h" -#include "gossip-ui-utils.h" - -#define DEBUG_DOMAIN "GroupChat" - -#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_GROUP_CHAT, GossipGroupChatPriv)) - -struct _GossipGroupChatPriv { - GossipContactListStore *store; - GossipContactListView *view; - EmpathyTpChatroom *tp_chat; - - GtkWidget *widget; - GtkWidget *hpaned; - GtkWidget *vbox_left; - GtkWidget *scrolled_window_chat; - GtkWidget *scrolled_window_input; - GtkWidget *scrolled_window_contacts; - GtkWidget *hbox_topic; - GtkWidget *label_topic; - - gchar *topic; - gchar *name; - GCompletion *completion; - - gint contacts_width; - gboolean contacts_visible; -}; - -static void group_chat_finalize (GObject *object); -static void group_chat_create_ui (GossipGroupChat *chat); -static void group_chat_widget_destroy_cb (GtkWidget *widget, - GossipGroupChat *chat); -static void group_chat_contact_added_cb (EmpathyTpChatroom *tp_chat, - GossipContact *contact, - GossipGroupChat *chat); -static void group_chat_contact_removed_cb (EmpathyTpChatroom *tp_chat, - GossipContact *contact, - GossipGroupChat *chat); -/*static void group_chat_topic_changed_cb (EmpathyTpChatroom *tp_chat, - const gchar *new_topic, - GossipGroupChat *chat);*/ -static void group_chat_topic_entry_activate_cb (GtkWidget *entry, - GtkDialog *dialog); -static void group_chat_topic_response_cb (GtkWidget *dialog, - gint response, - GossipGroupChat *chat); -static const gchar * group_chat_get_name (GossipChat *chat); -static gchar * group_chat_get_tooltip (GossipChat *chat); -static const gchar * group_chat_get_status_icon_name (GossipChat *chat); -static GtkWidget * group_chat_get_widget (GossipChat *chat); -static gboolean group_chat_is_group_chat (GossipChat *chat); -static void group_chat_set_tp_chat (GossipChat *chat, - EmpathyTpChat *tp_chat); -static void group_chat_subject_notify_cb (EmpathyTpChat *tp_chat, - GParamSpec *param, - GossipGroupChat *chat); -static void group_chat_name_notify_cb (EmpathyTpChat *tp_chat, - GParamSpec *param, - GossipGroupChat *chat); -/*static gboolean group_chat_key_press_event (GtkWidget *widget, - GdkEventKey *event, - GossipGroupChat *chat);*/ -static gint group_chat_contacts_completion_func (const gchar *s1, - const gchar *s2, - gsize n); - -G_DEFINE_TYPE (GossipGroupChat, gossip_group_chat, GOSSIP_TYPE_CHAT) - -static void -gossip_group_chat_class_init (GossipGroupChatClass *klass) -{ - GObjectClass *object_class; - GossipChatClass *chat_class; - - object_class = G_OBJECT_CLASS (klass); - chat_class = GOSSIP_CHAT_CLASS (klass); - - object_class->finalize = group_chat_finalize; - - chat_class->get_name = group_chat_get_name; - chat_class->get_tooltip = group_chat_get_tooltip; - chat_class->get_status_icon_name = group_chat_get_status_icon_name; - chat_class->get_widget = group_chat_get_widget; - chat_class->is_group_chat = group_chat_is_group_chat; - chat_class->set_tp_chat = group_chat_set_tp_chat; - - g_type_class_add_private (object_class, sizeof (GossipGroupChatPriv)); -} - -static void -gossip_group_chat_init (GossipGroupChat *chat) -{ - GossipGroupChatPriv *priv; - GossipChatView *chatview; - - priv = GET_PRIV (chat); - - priv->contacts_visible = TRUE; - - chatview = GOSSIP_CHAT_VIEW (GOSSIP_CHAT (chat)->view); - gossip_chat_view_set_is_group_chat (chatview, TRUE); - - group_chat_create_ui (chat); -} - -static void -group_chat_finalize (GObject *object) -{ - GossipGroupChat *chat; - GossipGroupChatPriv *priv; - - gossip_debug (DEBUG_DOMAIN, "Finalized:%p", object); - - chat = GOSSIP_GROUP_CHAT (object); - priv = GET_PRIV (chat); - - g_free (priv->name); - g_free (priv->topic); - g_object_unref (priv->store); - g_object_unref (priv->tp_chat); - g_completion_free (priv->completion); - - G_OBJECT_CLASS (gossip_group_chat_parent_class)->finalize (object); -} - -GossipGroupChat * -gossip_group_chat_new (McAccount *account, - TpChan *tp_chan) -{ - GossipGroupChat *chat; - GossipGroupChatPriv *priv; - - g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); - g_return_val_if_fail (TELEPATHY_IS_CHAN (tp_chan), NULL); - - chat = g_object_new (GOSSIP_TYPE_GROUP_CHAT, NULL); - - priv = GET_PRIV (chat); - - GOSSIP_CHAT (chat)->account = g_object_ref (account); - priv->tp_chat = empathy_tp_chatroom_new (account, tp_chan); - gossip_chat_set_tp_chat (GOSSIP_CHAT (chat), EMPATHY_TP_CHAT (priv->tp_chat)); - - return chat; -} - -gboolean -gossip_group_chat_get_show_contacts (GossipGroupChat *chat) -{ - GossipGroupChat *group_chat; - GossipGroupChatPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_GROUP_CHAT (chat), FALSE); - - group_chat = GOSSIP_GROUP_CHAT (chat); - priv = GET_PRIV (group_chat); - - return priv->contacts_visible; -} - -void -gossip_group_chat_set_show_contacts (GossipGroupChat *chat, - gboolean show) -{ - GossipGroupChat *group_chat; - GossipGroupChatPriv *priv; - - g_return_if_fail (GOSSIP_IS_GROUP_CHAT (chat)); - - group_chat = GOSSIP_GROUP_CHAT (chat); - priv = GET_PRIV (group_chat); - - priv->contacts_visible = show; - - if (show) { - gtk_widget_show (priv->scrolled_window_contacts); - gtk_paned_set_position (GTK_PANED (priv->hpaned), - priv->contacts_width); - } else { - priv->contacts_width = gtk_paned_get_position (GTK_PANED (priv->hpaned)); - gtk_widget_hide (priv->scrolled_window_contacts); - } -} - -void -gossip_group_chat_set_topic (GossipGroupChat *chat) -{ - GossipGroupChatPriv *priv; - GossipChatWindow *chat_window; - GtkWidget *chat_dialog; - GtkWidget *dialog; - GtkWidget *entry; - GtkWidget *hbox; - const gchar *topic; - - g_return_if_fail (GOSSIP_IS_GROUP_CHAT (chat)); - - priv = GET_PRIV (chat); - - chat_window = gossip_chat_get_window (GOSSIP_CHAT (chat)); - chat_dialog = gossip_chat_window_get_dialog (chat_window); - - dialog = gtk_message_dialog_new (GTK_WINDOW (chat_dialog), - 0, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_OK_CANCEL, - _("Enter the new topic you want to set for this room:")); - - topic = gtk_label_get_text (GTK_LABEL (priv->label_topic)); - - hbox = gtk_hbox_new (FALSE, 0); - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), - hbox, FALSE, TRUE, 4); - - entry = gtk_entry_new (); - gtk_entry_set_text (GTK_ENTRY (entry), topic); - gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1); - - gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 4); - - g_object_set (GTK_MESSAGE_DIALOG (dialog)->label, "use-markup", TRUE, NULL); - g_object_set_data (G_OBJECT (dialog), "entry", entry); - - g_signal_connect (entry, "activate", - G_CALLBACK (group_chat_topic_entry_activate_cb), - dialog); - g_signal_connect (dialog, "response", - G_CALLBACK (group_chat_topic_response_cb), - chat); - - gtk_widget_show_all (dialog); -} - -static void -group_chat_create_ui (GossipGroupChat *chat) -{ - GossipGroupChatPriv *priv; - GladeXML *glade; - GList *list = NULL; - - priv = GET_PRIV (chat); - - glade = gossip_glade_get_file ("gossip-group-chat.glade", - "group_chat_widget", - NULL, - "group_chat_widget", &priv->widget, - "hpaned", &priv->hpaned, - "vbox_left", &priv->vbox_left, - "scrolled_window_chat", &priv->scrolled_window_chat, - "scrolled_window_input", &priv->scrolled_window_input, - "hbox_topic", &priv->hbox_topic, - "label_topic", &priv->label_topic, - "scrolled_window_contacts", &priv->scrolled_window_contacts, - NULL); - - gossip_glade_connect (glade, - chat, - "group_chat_widget", "destroy", group_chat_widget_destroy_cb, - NULL); - - g_object_unref (glade); - - g_object_set_data (G_OBJECT (priv->widget), "chat", g_object_ref (chat)); - - /* Add room GtkTextView. */ - gtk_container_add (GTK_CONTAINER (priv->scrolled_window_chat), - GTK_WIDGET (GOSSIP_CHAT (chat)->view)); - gtk_widget_show (GTK_WIDGET (GOSSIP_CHAT (chat)->view)); - - /* Add input GtkTextView */ - gtk_container_add (GTK_CONTAINER (priv->scrolled_window_input), - GOSSIP_CHAT (chat)->input_text_view); - gtk_widget_show (GOSSIP_CHAT (chat)->input_text_view); - - /* Add nick name completion */ - priv->completion = g_completion_new (NULL); - g_completion_set_compare (priv->completion, - group_chat_contacts_completion_func); - - /* Set widget focus order */ - list = g_list_append (NULL, priv->scrolled_window_input); - gtk_container_set_focus_chain (GTK_CONTAINER (priv->vbox_left), list); - g_list_free (list); - - list = g_list_append (NULL, priv->vbox_left); - list = g_list_append (list, priv->scrolled_window_contacts); - gtk_container_set_focus_chain (GTK_CONTAINER (priv->hpaned), list); - g_list_free (list); - - list = g_list_append (NULL, priv->hpaned); - list = g_list_append (list, priv->hbox_topic); - gtk_container_set_focus_chain (GTK_CONTAINER (priv->widget), list); - g_list_free (list); -} - -static void -group_chat_widget_destroy_cb (GtkWidget *widget, - GossipGroupChat *chat) -{ - gossip_debug (DEBUG_DOMAIN, "Destroyed"); - - g_object_unref (chat); -} - -static void -group_chat_contact_added_cb (EmpathyTpChatroom *tp_chat, - GossipContact *contact, - GossipGroupChat *chat) -{ - GossipGroupChatPriv *priv; - gchar *str; - - priv = GET_PRIV (chat); - - str = g_strdup_printf (_("%s has joined the room"), - gossip_contact_get_name (contact)); - gossip_chat_view_append_event (GOSSIP_CHAT (chat)->view, str); - g_free (str); -} - -static void -group_chat_contact_removed_cb (EmpathyTpChatroom *tp_chat, - GossipContact *contact, - GossipGroupChat *chat) -{ - GossipGroupChatPriv *priv; - gchar *str; - - priv = GET_PRIV (chat); - - str = g_strdup_printf (_("%s has left the room"), - gossip_contact_get_name (contact)); - gossip_chat_view_append_event (GOSSIP_CHAT (chat)->view, str); - g_free (str); -} - -static void -group_chat_topic_entry_activate_cb (GtkWidget *entry, - GtkDialog *dialog) -{ - gtk_dialog_response (dialog, GTK_RESPONSE_OK); -} - -static void -group_chat_topic_response_cb (GtkWidget *dialog, - gint response, - GossipGroupChat *chat) -{ - if (response == GTK_RESPONSE_OK) { - GtkWidget *entry; - const gchar *topic; - - entry = g_object_get_data (G_OBJECT (dialog), "entry"); - topic = gtk_entry_get_text (GTK_ENTRY (entry)); - - if (!G_STR_EMPTY (topic)) { - GossipGroupChatPriv *priv; - - priv = GET_PRIV (chat); - - empathy_tp_chatroom_set_topic (priv->tp_chat, topic); - } - } - - gtk_widget_destroy (dialog); -} - -static const gchar * -group_chat_get_name (GossipChat *chat) -{ - GossipGroupChat *group_chat; - GossipGroupChatPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_GROUP_CHAT (chat), NULL); - - group_chat = GOSSIP_GROUP_CHAT (chat); - priv = GET_PRIV (group_chat); - - if (!priv->name) { - const gchar *id; - const gchar *server; - - id = gossip_chat_get_id (chat); - server = strstr (id, "@"); - - if (server) { - priv->name = g_strndup (id, server - id); - } else { - priv->name = g_strdup (id); - } - } - - return priv->name; -} - -static gchar * -group_chat_get_tooltip (GossipChat *chat) -{ - GossipGroupChat *group_chat; - GossipGroupChatPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_GROUP_CHAT (chat), NULL); - - group_chat = GOSSIP_GROUP_CHAT (chat); - priv = GET_PRIV (group_chat); - - if (priv->topic) { - gchar *topic, *tmp; - - topic = g_strdup_printf (_("Topic: %s"), priv->topic); - tmp = g_strdup_printf ("%s\n%s", priv->name, topic); - g_free (topic); - - return tmp; - } - - return g_strdup (priv->name); -} - -static const gchar * -group_chat_get_status_icon_name (GossipChat *chat) -{ - return EMPATHY_IMAGE_GROUP_MESSAGE; -} - -static GtkWidget * -group_chat_get_widget (GossipChat *chat) -{ - GossipGroupChat *group_chat; - GossipGroupChatPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_GROUP_CHAT (chat), NULL); - - group_chat = GOSSIP_GROUP_CHAT (chat); - priv = GET_PRIV (group_chat); - - return priv->widget; -} - -static gboolean -group_chat_is_group_chat (GossipChat *chat) -{ - g_return_val_if_fail (GOSSIP_IS_GROUP_CHAT (chat), FALSE); - - return TRUE; -} - -static void -group_chat_set_tp_chat (GossipChat *chat, - EmpathyTpChat *tp_chat) -{ - GossipGroupChat *group_chat; - GossipGroupChatPriv *priv; - - g_return_if_fail (GOSSIP_IS_GROUP_CHAT (chat)); - - group_chat = GOSSIP_GROUP_CHAT (chat); - priv = GET_PRIV (group_chat); - - /* Free all resources related to tp_chat */ - if (priv->tp_chat) { - g_object_unref (priv->tp_chat); - priv->tp_chat = NULL; - } - if (priv->view) { - gtk_widget_destroy (GTK_WIDGET (priv->view)); - g_object_unref (priv->store); - } - g_free (priv->name); - g_free (priv->topic); - priv->name = NULL; - priv->topic = NULL; - - if (!tp_chat) { - /* We are no more connected */ - gtk_widget_set_sensitive (priv->hbox_topic, FALSE); - gtk_widget_set_sensitive (priv->scrolled_window_contacts, FALSE); - return; - } - - /* We are connected */ - gtk_widget_set_sensitive (priv->hbox_topic, TRUE); - gtk_widget_set_sensitive (priv->scrolled_window_contacts, TRUE); - - priv->tp_chat = g_object_ref (tp_chat); - - /* FIXME: Ask the user before accepting */ - empathy_tp_chatroom_accept_invitation (priv->tp_chat); - - /* Create contact list */ - priv->store = gossip_contact_list_store_new (EMPATHY_CONTACT_LIST (priv->tp_chat)); - priv->view = gossip_contact_list_view_new (priv->store); - gtk_container_add (GTK_CONTAINER (priv->scrolled_window_contacts), - GTK_WIDGET (priv->view)); - gtk_widget_show (GTK_WIDGET (priv->view)); - - /* Connect signals */ - g_signal_connect (priv->tp_chat, "contact-added", - G_CALLBACK (group_chat_contact_added_cb), - chat); - g_signal_connect (priv->tp_chat, "contact-removed", - G_CALLBACK (group_chat_contact_removed_cb), - chat); - g_signal_connect (priv->tp_chat, "notify::subject", - G_CALLBACK (group_chat_subject_notify_cb), - chat); - g_signal_connect (priv->tp_chat, "notify::name", - G_CALLBACK (group_chat_name_notify_cb), - chat); -} - -static void -group_chat_subject_notify_cb (EmpathyTpChat *tp_chat, - GParamSpec *param, - GossipGroupChat *chat) -{ - GossipGroupChatPriv *priv; - gchar *str; - - priv = GET_PRIV (chat); - - g_free (priv->topic); - - g_object_get (priv->tp_chat, "subject", &priv->topic, NULL); - gtk_label_set_text (GTK_LABEL (priv->label_topic), priv->topic); - - str = g_strdup_printf (_("Topic set to: %s"), priv->topic); - gossip_chat_view_append_event (GOSSIP_CHAT (chat)->view, str); - g_free (str); -} - -static void -group_chat_name_notify_cb (EmpathyTpChat *tp_chat, - GParamSpec *param, - GossipGroupChat *chat) -{ - GossipGroupChatPriv *priv; - - priv = GET_PRIV (chat); - - g_free (priv->name); - g_object_get (priv->tp_chat, "name", &priv->name, NULL); -} - -#if 0 -static gboolean -group_chat_key_press_event (GtkWidget *widget, - GdkEventKey *event, - GossipGroupChat *chat) -{ - GossipGroupChatPriv *priv; - GtkAdjustment *adj; - gdouble val; - GtkTextBuffer *buffer; - GtkTextIter start, current; - gchar *nick, *completed; - gint len; - GList *list, *l, *completed_list; - gboolean is_start_of_buffer; - - priv = GET_PRIV (chat); - - if ((event->state & GDK_CONTROL_MASK) != GDK_CONTROL_MASK && - (event->state & GDK_SHIFT_MASK) != GDK_SHIFT_MASK && - event->keyval == GDK_Tab) { - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (GOSSIP_CHAT (chat)->input_text_view)); - gtk_text_buffer_get_iter_at_mark (buffer, ¤t, gtk_text_buffer_get_insert (buffer)); - - /* Get the start of the nick to complete. */ - gtk_text_buffer_get_iter_at_mark (buffer, &start, gtk_text_buffer_get_insert (buffer)); - gtk_text_iter_backward_word_start (&start); - is_start_of_buffer = gtk_text_iter_is_start (&start); - - nick = gtk_text_buffer_get_text (buffer, &start, ¤t, FALSE); - - g_completion_clear_items (priv->completion); - - len = strlen (nick); - - list = group_chat_get_nick_list (chat); - - g_completion_add_items (priv->completion, list); - - completed_list = g_completion_complete (priv->completion, - nick, - &completed); - - g_free (nick); - - if (completed) { - int len; - gchar *text; - - gtk_text_buffer_delete (buffer, &start, ¤t); - - len = g_list_length (completed_list); - - if (len == 1) { - /* If we only have one hit, use that text - * instead of the text in completed since the - * completed text will use the typed string - * which might be cased all wrong. - * Fixes #120876 - * */ - text = (gchar *) completed_list->data; - } else { - text = completed; - } - - gtk_text_buffer_insert_at_cursor (buffer, text, strlen (text)); - - if (len == 1) { - if (is_start_of_buffer) { - gtk_text_buffer_insert_at_cursor (buffer, ", ", 2); - } - } - - g_free (completed); - } - - g_completion_clear_items (priv->completion); - - for (l = list; l; l = l->next) { - g_free (l->data); - } - - g_list_free (list); - - return TRUE; - } - - return FALSE; -} -#endif - -static gint -group_chat_contacts_completion_func (const gchar *s1, - const gchar *s2, - gsize n) -{ - gchar *tmp, *nick1, *nick2; - gint ret; - - tmp = g_utf8_normalize (s1, -1, G_NORMALIZE_DEFAULT); - nick1 = g_utf8_casefold (tmp, -1); - g_free (tmp); - - tmp = g_utf8_normalize (s2, -1, G_NORMALIZE_DEFAULT); - nick2 = g_utf8_casefold (tmp, -1); - g_free (tmp); - - ret = strncmp (nick1, nick2, n); - - g_free (nick1); - g_free (nick2); - - return ret; -} - diff --git a/libempathy-gtk/gossip-group-chat.glade b/libempathy-gtk/gossip-group-chat.glade deleted file mode 100644 index 7b6f2c00..00000000 --- a/libempathy-gtk/gossip-group-chat.glade +++ /dev/null @@ -1,183 +0,0 @@ - - - - - - - 6 - Group Chat - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - 600 - 400 - True - False - gossip-group-message.png - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - 4 - True - False - 6 - - - - True - False - 6 - - - - True - <b>Topic:</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0 - 0 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - True - - False - True - GTK_JUSTIFY_LEFT - True - True - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_END - -1 - True - 0 - - - 0 - True - True - - - - - 2 - False - False - - - - - - True - True - - - - True - False - 6 - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_ALWAYS - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - - - - 0 - True - True - - - - - - True - True - GTK_POLICY_NEVER - GTK_POLICY_NEVER - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - - - - 0 - False - True - - - - - True - True - - - - - - 0 - True - True - GTK_POLICY_NEVER - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - - - - False - False - - - - - 0 - True - True - - - - - - - diff --git a/libempathy-gtk/gossip-group-chat.h b/libempathy-gtk/gossip-group-chat.h deleted file mode 100644 index 37a7772b..00000000 --- a/libempathy-gtk/gossip-group-chat.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2002-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Richard Hult - * Martyn Russell - * Xavier Claessens - */ - -#ifndef __GOSSIP_GROUP_CHAT_H__ -#define __GOSSIP_GROUP_CHAT_H__ - -G_BEGIN_DECLS - -#include - -#include - -#define GOSSIP_TYPE_GROUP_CHAT (gossip_group_chat_get_type ()) -#define GOSSIP_GROUP_CHAT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOSSIP_TYPE_GROUP_CHAT, GossipGroupChat)) -#define GOSSIP_GROUP_CHAT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GOSSIP_TYPE_GROUP_CHAT, GossipGroupChatClass)) -#define GOSSIP_IS_GROUP_CHAT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOSSIP_TYPE_GROUP_CHAT)) -#define GOSSIP_IS_GROUP_CHAT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOSSIP_TYPE_GROUP_CHAT)) -#define GOSSIP_GROUP_CHAT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOSSIP_TYPE_GROUP_CHAT, GossipGroupChatClass)) - -typedef struct _GossipGroupChat GossipGroupChat; -typedef struct _GossipGroupChatClass GossipGroupChatClass; -typedef struct _GossipGroupChatPriv GossipGroupChatPriv; - -#include "gossip-chat.h" - -struct _GossipGroupChat { - GossipChat parent; - - GossipGroupChatPriv *priv; -}; - -struct _GossipGroupChatClass { - GossipChatClass parent_class; -}; - -GType gossip_group_chat_get_type (void) G_GNUC_CONST; -GossipGroupChat *gossip_group_chat_new (McAccount *account, - TpChan *tp_chan); -gboolean gossip_group_chat_get_show_contacts (GossipGroupChat *chat); -void gossip_group_chat_set_show_contacts (GossipGroupChat *chat, - gboolean show); -void gossip_group_chat_set_topic (GossipGroupChat *chat); - -G_END_DECLS - -#endif /* __GOSSIP_GROUP_CHAT_H__ */ diff --git a/libempathy-gtk/gossip-log-window.c b/libempathy-gtk/gossip-log-window.c deleted file mode 100644 index dae8b79a..00000000 --- a/libempathy-gtk/gossip-log-window.c +++ /dev/null @@ -1,1118 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Martyn Russell - * Xavier Claessens - */ - -#include "config.h" - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "gossip-log-window.h" -#include "gossip-account-chooser.h" -#include "gossip-chat-view.h" -#include "gossip-ui-utils.h" - -#define DEBUG_DOMAIN "LogWindow" - -typedef struct { - GtkWidget *window; - - GtkWidget *notebook; - - GtkWidget *entry_find; - GtkWidget *button_find; - GtkWidget *treeview_find; - GtkWidget *scrolledwindow_find; - GossipChatView *chatview_find; - GtkWidget *button_previous; - GtkWidget *button_next; - - GtkWidget *vbox_chats; - GtkWidget *account_chooser_chats; - GtkWidget *entry_chats; - GtkWidget *calendar_chats; - GtkWidget *treeview_chats; - GtkWidget *scrolledwindow_chats; - GossipChatView *chatview_chats; - - gchar *last_find; - - EmpathyLogManager *log_manager; -} GossipLogWindow; - -static void -log_window_destroy_cb (GtkWidget *widget, - GossipLogWindow *window); -static void -log_window_entry_find_changed_cb (GtkWidget *entry, - GossipLogWindow *window); -static void -log_window_find_changed_cb (GtkTreeSelection *selection, - GossipLogWindow *window); -static void -log_window_find_populate (GossipLogWindow *window, - const gchar *search_criteria); -static void -log_window_find_setup (GossipLogWindow *window); -static void -log_window_button_find_clicked_cb (GtkWidget *widget, - GossipLogWindow *window); -static void -log_window_button_next_clicked_cb (GtkWidget *widget, - GossipLogWindow *window); -static void -log_window_button_previous_clicked_cb (GtkWidget *widget, - GossipLogWindow *window); -static void -log_window_chats_changed_cb (GtkTreeSelection *selection, - GossipLogWindow *window); -static void -log_window_chats_populate (GossipLogWindow *window); -static void -log_window_chats_setup (GossipLogWindow *window); -static void -log_window_chats_accounts_changed_cb (GtkWidget *combobox, - GossipLogWindow *window); -static void -log_window_chats_new_message_cb (GossipContact *own_contact, - GossipMessage *message, - GossipLogWindow *window); -static void -log_window_chats_set_selected (GossipLogWindow *window, - McAccount *account, - const gchar *chat_id, - gboolean is_chatroom); -static gboolean -log_window_chats_get_selected (GossipLogWindow *window, - McAccount **account, - gchar **chat_id, - gboolean *is_chatroom); -static void -log_window_chats_get_messages (GossipLogWindow *window, - const gchar *date_to_show); -static void -log_window_calendar_chats_day_selected_cb (GtkWidget *calendar, - GossipLogWindow *window); -static void -log_window_calendar_chats_month_changed_cb (GtkWidget *calendar, - GossipLogWindow *window); -static void -log_window_entry_chats_changed_cb (GtkWidget *entry, - GossipLogWindow *window); -static void -log_window_entry_chats_activate_cb (GtkWidget *entry, - GossipLogWindow *window); - -enum { - COL_FIND_ACCOUNT_ICON, - COL_FIND_ACCOUNT_NAME, - COL_FIND_ACCOUNT, - COL_FIND_CHAT_NAME, - COL_FIND_CHAT_ID, - COL_FIND_IS_CHATROOM, - COL_FIND_DATE, - COL_FIND_DATE_READABLE, - COL_FIND_COUNT -}; - -enum { - COL_CHAT_ICON, - COL_CHAT_NAME, - COL_CHAT_ACCOUNT, - COL_CHAT_ID, - COL_CHAT_IS_CHATROOM, - COL_CHAT_COUNT -}; - -void -gossip_log_window_show (McAccount *account, - const gchar *chat_id, - gboolean is_chatroom, - GtkWindow *parent) -{ - static GossipLogWindow *window = NULL; - GossipAccountChooser *account_chooser; - GList *accounts; - gint account_num; - GladeXML *glade; - - if (window) { - gtk_window_present (GTK_WINDOW (window->window)); - - if (account && chat_id) { - gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), 1); - log_window_chats_set_selected (window, account, - chat_id, is_chatroom); - } - - return; - } - - window = g_new0 (GossipLogWindow, 1); - window->log_manager = empathy_log_manager_new (); - - glade = gossip_glade_get_file ("gossip-log-window.glade", - "log_window", - NULL, - "log_window", &window->window, - "notebook", &window->notebook, - "entry_find", &window->entry_find, - "button_find", &window->button_find, - "treeview_find", &window->treeview_find, - "scrolledwindow_find", &window->scrolledwindow_find, - "button_previous", &window->button_previous, - "button_next", &window->button_next, - "entry_chats", &window->entry_chats, - "calendar_chats", &window->calendar_chats, - "vbox_chats", &window->vbox_chats, - "treeview_chats", &window->treeview_chats, - "scrolledwindow_chats", &window->scrolledwindow_chats, - NULL); - gossip_glade_connect (glade, - window, - "log_window", "destroy", log_window_destroy_cb, - "entry_find", "changed", log_window_entry_find_changed_cb, - "button_previous", "clicked", log_window_button_previous_clicked_cb, - "button_next", "clicked", log_window_button_next_clicked_cb, - "button_find", "clicked", log_window_button_find_clicked_cb, - "entry_chats", "changed", log_window_entry_chats_changed_cb, - "entry_chats", "activate", log_window_entry_chats_activate_cb, - NULL); - - g_object_unref (glade); - - g_object_add_weak_pointer (G_OBJECT (window->window), - (gpointer) &window); - - /* We set this up here so we can block it when needed. */ - g_signal_connect (window->calendar_chats, "day-selected", - G_CALLBACK (log_window_calendar_chats_day_selected_cb), - window); - g_signal_connect (window->calendar_chats, "month-changed", - G_CALLBACK (log_window_calendar_chats_month_changed_cb), - window); - - /* Configure Search GossipChatView */ - window->chatview_find = gossip_chat_view_new (); - gtk_container_add (GTK_CONTAINER (window->scrolledwindow_find), - GTK_WIDGET (window->chatview_find)); - gtk_widget_show (GTK_WIDGET (window->chatview_find)); - - /* Configure Contacts GossipChatView */ - window->chatview_chats = gossip_chat_view_new (); - gtk_container_add (GTK_CONTAINER (window->scrolledwindow_chats), - GTK_WIDGET (window->chatview_chats)); - gtk_widget_show (GTK_WIDGET (window->chatview_chats)); - - /* Account chooser for chats */ - window->account_chooser_chats = gossip_account_chooser_new (); - account_chooser = GOSSIP_ACCOUNT_CHOOSER (window->account_chooser_chats); - gossip_account_chooser_set_can_select_all (account_chooser, TRUE); - - gtk_box_pack_start (GTK_BOX (window->vbox_chats), - window->account_chooser_chats, - FALSE, TRUE, 0); - - g_signal_connect (window->account_chooser_chats, "changed", - G_CALLBACK (log_window_chats_accounts_changed_cb), - window); - - /* Populate */ - accounts = mc_accounts_list (); - account_num = g_list_length (accounts); - mc_accounts_list_free (accounts); - - if (account_num > 1) { - gtk_widget_show (window->vbox_chats); - gtk_widget_show (window->account_chooser_chats); - } else { - gtk_widget_hide (window->vbox_chats); - gtk_widget_hide (window->account_chooser_chats); - } - - /* Search List */ - log_window_find_setup (window); - - /* Contacts */ - log_window_chats_setup (window); - log_window_chats_populate (window); - - /* Select chat */ - if (account && chat_id) { - gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), 1); - log_window_chats_set_selected (window, account, - chat_id, is_chatroom); - } - - if (parent) { - gtk_window_set_transient_for (GTK_WINDOW (window->window), - GTK_WINDOW (parent)); - } - - gtk_widget_show (window->window); -} - -static void -log_window_destroy_cb (GtkWidget *widget, - GossipLogWindow *window) -{ - g_signal_handlers_disconnect_by_func (window->log_manager, - log_window_chats_new_message_cb, - window); - - g_free (window->last_find); - g_object_unref (window->log_manager); - - g_free (window); -} - -/* - * Search code. - */ -static void -log_window_entry_find_changed_cb (GtkWidget *entry, - GossipLogWindow *window) -{ - const gchar *str; - gboolean is_sensitive = TRUE; - - str = gtk_entry_get_text (GTK_ENTRY (window->entry_find)); - - is_sensitive &= !G_STR_EMPTY (str); - is_sensitive &= - !window->last_find || - (window->last_find && strcmp (window->last_find, str) != 0); - - gtk_widget_set_sensitive (window->button_find, is_sensitive); -} - -static void -log_window_find_changed_cb (GtkTreeSelection *selection, - GossipLogWindow *window) -{ - GtkTreeView *view; - GtkTreeModel *model; - GtkTreeIter iter; - McAccount *account; - gchar *chat_id; - gboolean is_chatroom; - gchar *date; - GossipMessage *message; - GList *messages; - GList *l; - gboolean can_do_previous; - gboolean can_do_next; - - /* Get selected information */ - view = GTK_TREE_VIEW (window->treeview_find); - model = gtk_tree_view_get_model (view); - - if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) { - gtk_widget_set_sensitive (window->button_previous, FALSE); - gtk_widget_set_sensitive (window->button_next, FALSE); - - gossip_chat_view_clear (window->chatview_find); - - return; - } - - gtk_widget_set_sensitive (window->button_previous, TRUE); - gtk_widget_set_sensitive (window->button_next, TRUE); - - gtk_tree_model_get (model, &iter, - COL_FIND_ACCOUNT, &account, - COL_FIND_CHAT_ID, &chat_id, - COL_FIND_IS_CHATROOM, &is_chatroom, - COL_FIND_DATE, &date, - -1); - - /* Clear all current messages shown in the textview */ - gossip_chat_view_clear (window->chatview_find); - - /* Turn off scrolling temporarily */ - gossip_chat_view_scroll (window->chatview_find, FALSE); - - /* Get messages */ - messages = empathy_log_manager_get_messages_for_date (window->log_manager, - account, - chat_id, - is_chatroom, - date); - g_object_unref (account); - g_free (date); - g_free (chat_id); - - for (l = messages; l; l = l->next) { - message = l->data; - gossip_chat_view_append_message (window->chatview_find, message); - g_object_unref (message); - } - g_list_free (messages); - - /* Scroll to the most recent messages */ - gossip_chat_view_scroll (window->chatview_find, TRUE); - - /* Highlight and find messages */ - gossip_chat_view_highlight (window->chatview_find, - window->last_find); - gossip_chat_view_find_next (window->chatview_find, - window->last_find, - TRUE); - gossip_chat_view_find_abilities (window->chatview_find, - window->last_find, - &can_do_previous, - &can_do_next); - gtk_widget_set_sensitive (window->button_previous, can_do_previous); - gtk_widget_set_sensitive (window->button_next, can_do_next); - gtk_widget_set_sensitive (window->button_find, FALSE); -} - -static void -log_window_find_populate (GossipLogWindow *window, - const gchar *search_criteria) -{ - GList *hits, *l; - - GtkTreeView *view; - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkListStore *store; - GtkTreeIter iter; - - view = GTK_TREE_VIEW (window->treeview_find); - model = gtk_tree_view_get_model (view); - selection = gtk_tree_view_get_selection (view); - store = GTK_LIST_STORE (model); - - gossip_chat_view_clear (window->chatview_find); - - gtk_list_store_clear (store); - - if (G_STR_EMPTY (search_criteria)) { - /* Just clear the search. */ - return; - } - - hits = empathy_log_manager_search_new (window->log_manager, search_criteria); - - for (l = hits; l; l = l->next) { - EmpathyLogSearchHit *hit; - const gchar *account_name; - const gchar *account_icon; - gchar *date_readable; - - hit = l->data; - - /* Protect against invalid data (corrupt or old log files. */ - if (!hit->account || !hit->chat_id) { - continue; - } - - date_readable = empathy_log_manager_get_date_readable (hit->date); - account_name = mc_account_get_display_name (hit->account); - account_icon = gossip_icon_name_from_account (hit->account); - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - COL_FIND_ACCOUNT_ICON, account_icon, - COL_FIND_ACCOUNT_NAME, account_name, - COL_FIND_ACCOUNT, hit->account, - COL_FIND_CHAT_NAME, hit->chat_id, /* FIXME */ - COL_FIND_CHAT_ID, hit->chat_id, - COL_FIND_IS_CHATROOM, hit->is_chatroom, - COL_FIND_DATE, hit->date, - COL_FIND_DATE_READABLE, date_readable, - -1); - - g_free (date_readable); - - /* FIXME: Update COL_FIND_CHAT_NAME */ - if (hit->is_chatroom) { - } else { - } - } - - if (hits) { - empathy_log_manager_search_free (hits); - } -} - -static void -log_window_find_setup (GossipLogWindow *window) -{ - GtkTreeView *view; - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeSortable *sortable; - GtkTreeViewColumn *column; - GtkListStore *store; - GtkCellRenderer *cell; - gint offset; - - view = GTK_TREE_VIEW (window->treeview_find); - selection = gtk_tree_view_get_selection (view); - - /* New store */ - store = gtk_list_store_new (COL_FIND_COUNT, - G_TYPE_STRING, /* account icon name */ - G_TYPE_STRING, /* account name */ - MC_TYPE_ACCOUNT, /* account */ - G_TYPE_STRING, /* chat name */ - G_TYPE_STRING, /* chat id */ - G_TYPE_BOOLEAN, /* is chatroom */ - G_TYPE_STRING, /* date */ - G_TYPE_STRING); /* date_readable */ - - model = GTK_TREE_MODEL (store); - sortable = GTK_TREE_SORTABLE (store); - - gtk_tree_view_set_model (view, model); - - /* New column */ - column = gtk_tree_view_column_new (); - - cell = gtk_cell_renderer_pixbuf_new (); - gtk_tree_view_column_pack_start (column, cell, FALSE); - gtk_tree_view_column_add_attribute (column, cell, - "icon-name", - COL_FIND_ACCOUNT_ICON); - - cell = gtk_cell_renderer_text_new (); - gtk_tree_view_column_pack_start (column, cell, TRUE); - gtk_tree_view_column_add_attribute (column, cell, - "text", - COL_FIND_ACCOUNT_NAME); - - gtk_tree_view_column_set_title (column, _("Account")); - gtk_tree_view_append_column (view, column); - - gtk_tree_view_column_set_resizable (column, TRUE); - gtk_tree_view_column_set_clickable (column, TRUE); - - cell = gtk_cell_renderer_text_new (); - offset = gtk_tree_view_insert_column_with_attributes (view, -1, _("Conversation"), - cell, "text", COL_FIND_CHAT_NAME, - NULL); - - column = gtk_tree_view_get_column (view, offset - 1); - gtk_tree_view_column_set_sort_column_id (column, COL_FIND_CHAT_NAME); - gtk_tree_view_column_set_resizable (column, TRUE); - gtk_tree_view_column_set_clickable (column, TRUE); - - cell = gtk_cell_renderer_text_new (); - offset = gtk_tree_view_insert_column_with_attributes (view, -1, _("Date"), - cell, "text", COL_FIND_DATE_READABLE, - NULL); - - column = gtk_tree_view_get_column (view, offset - 1); - gtk_tree_view_column_set_sort_column_id (column, COL_FIND_DATE); - gtk_tree_view_column_set_resizable (column, TRUE); - gtk_tree_view_column_set_clickable (column, TRUE); - - /* Set up treeview properties */ - gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); - gtk_tree_sortable_set_sort_column_id (sortable, - COL_FIND_DATE, - GTK_SORT_ASCENDING); - - /* Set up signals */ - g_signal_connect (selection, "changed", - G_CALLBACK (log_window_find_changed_cb), - window); - - g_object_unref (store); -} - -static void -log_window_button_find_clicked_cb (GtkWidget *widget, - GossipLogWindow *window) -{ - const gchar *str; - - str = gtk_entry_get_text (GTK_ENTRY (window->entry_find)); - - /* Don't find the same crap again */ - if (window->last_find && strcmp (window->last_find, str) == 0) { - return; - } - - g_free (window->last_find); - window->last_find = g_strdup (str); - - log_window_find_populate (window, str); -} - -static void -log_window_button_next_clicked_cb (GtkWidget *widget, - GossipLogWindow *window) -{ - if (window->last_find) { - gboolean can_do_previous; - gboolean can_do_next; - - gossip_chat_view_find_next (window->chatview_find, - window->last_find, - FALSE); - gossip_chat_view_find_abilities (window->chatview_find, - window->last_find, - &can_do_previous, - &can_do_next); - gtk_widget_set_sensitive (window->button_previous, can_do_previous); - gtk_widget_set_sensitive (window->button_next, can_do_next); - } -} - -static void -log_window_button_previous_clicked_cb (GtkWidget *widget, - GossipLogWindow *window) -{ - if (window->last_find) { - gboolean can_do_previous; - gboolean can_do_next; - - gossip_chat_view_find_previous (window->chatview_find, - window->last_find, - FALSE); - gossip_chat_view_find_abilities (window->chatview_find, - window->last_find, - &can_do_previous, - &can_do_next); - gtk_widget_set_sensitive (window->button_previous, can_do_previous); - gtk_widget_set_sensitive (window->button_next, can_do_next); - } -} - -/* - * Chats Code - */ - -static void -log_window_chats_changed_cb (GtkTreeSelection *selection, - GossipLogWindow *window) -{ - /* Use last date by default */ - gtk_calendar_clear_marks (GTK_CALENDAR (window->calendar_chats)); - - log_window_chats_get_messages (window, NULL); -} - -static void -log_window_chats_populate (GossipLogWindow *window) -{ - GossipAccountChooser *account_chooser; - McAccount *account; - GList *chats, *l; - - GtkTreeView *view; - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkListStore *store; - GtkTreeIter iter; - - account_chooser = GOSSIP_ACCOUNT_CHOOSER (window->account_chooser_chats); - account = gossip_account_chooser_get_account (account_chooser); - - view = GTK_TREE_VIEW (window->treeview_chats); - model = gtk_tree_view_get_model (view); - selection = gtk_tree_view_get_selection (view); - store = GTK_LIST_STORE (model); - - /* Block signals to stop the logs being retrieved prematurely */ - g_signal_handlers_block_by_func (selection, - log_window_chats_changed_cb, - window); - - gtk_list_store_clear (store); - - chats = empathy_log_manager_get_chats (window->log_manager, account); - for (l = chats; l; l = l->next) { - EmpathyLogSearchHit *hit; - - hit = l->data; - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - COL_CHAT_ICON, "empathy-available", /* FIXME */ - COL_CHAT_NAME, hit->chat_id, - COL_CHAT_ACCOUNT, account, - COL_CHAT_ID, hit->chat_id, - COL_CHAT_IS_CHATROOM, hit->is_chatroom, - -1); - - /* FIXME: Update COL_CHAT_ICON/NAME */ - if (hit->is_chatroom) { - } else { - } - } - empathy_log_manager_search_free (chats); - - /* Unblock signals */ - g_signal_handlers_unblock_by_func (selection, - log_window_chats_changed_cb, - window); - - - g_object_unref (account); -} - -static void -log_window_chats_setup (GossipLogWindow *window) -{ - GtkTreeView *view; - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeSortable *sortable; - GtkTreeViewColumn *column; - GtkListStore *store; - GtkCellRenderer *cell; - - view = GTK_TREE_VIEW (window->treeview_chats); - selection = gtk_tree_view_get_selection (view); - - /* new store */ - store = gtk_list_store_new (COL_CHAT_COUNT, - G_TYPE_STRING, /* icon */ - G_TYPE_STRING, /* name */ - MC_TYPE_ACCOUNT, /* account */ - G_TYPE_STRING, /* id */ - G_TYPE_BOOLEAN); /* is chatroom */ - - model = GTK_TREE_MODEL (store); - sortable = GTK_TREE_SORTABLE (store); - - gtk_tree_view_set_model (view, model); - - /* new column */ - column = gtk_tree_view_column_new (); - - cell = gtk_cell_renderer_pixbuf_new (); - gtk_tree_view_column_pack_start (column, cell, FALSE); - gtk_tree_view_column_add_attribute (column, cell, - "icon-name", - COL_CHAT_ICON); - - cell = gtk_cell_renderer_text_new (); - g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL); - gtk_tree_view_column_pack_start (column, cell, TRUE); - gtk_tree_view_column_add_attribute (column, cell, - "text", - COL_CHAT_NAME); - - gtk_tree_view_append_column (view, column); - - /* set up treeview properties */ - gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); - gtk_tree_sortable_set_sort_column_id (sortable, - COL_CHAT_NAME, - GTK_SORT_ASCENDING); - - /* set up signals */ - g_signal_connect (selection, "changed", - G_CALLBACK (log_window_chats_changed_cb), - window); - - g_object_unref (store); -} - -static void -log_window_chats_accounts_changed_cb (GtkWidget *combobox, - GossipLogWindow *window) -{ - /* Clear all current messages shown in the textview */ - gossip_chat_view_clear (window->chatview_chats); - - log_window_chats_populate (window); -} - -static void -log_window_chats_new_message_cb (GossipContact *own_contact, - GossipMessage *message, - GossipLogWindow *window) -{ - gossip_chat_view_append_message (window->chatview_chats, message); - - /* Scroll to the most recent messages */ - gossip_chat_view_scroll_down (window->chatview_chats); -} - -static void -log_window_chats_set_selected (GossipLogWindow *window, - McAccount *account, - const gchar *chat_id, - gboolean is_chatroom) -{ - GossipAccountChooser *account_chooser; - GtkTreeView *view; - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - GtkTreePath *path; - gboolean ok; - - account_chooser = GOSSIP_ACCOUNT_CHOOSER (window->account_chooser_chats); - gossip_account_chooser_set_account (account_chooser, account); - - view = GTK_TREE_VIEW (window->treeview_chats); - model = gtk_tree_view_get_model (view); - selection = gtk_tree_view_get_selection (view); - - if (!gtk_tree_model_get_iter_first (model, &iter)) { - return; - } - - for (ok = TRUE; ok; ok = gtk_tree_model_iter_next (model, &iter)) { - McAccount *this_account; - gchar *this_chat_id; - gboolean this_is_chatroom; - - gtk_tree_model_get (model, &iter, - COL_CHAT_ACCOUNT, &this_account, - COL_CHAT_ID, &this_chat_id, - COL_CHAT_IS_CHATROOM, &this_is_chatroom, - -1); - - if (gossip_account_equal (this_account, account) && - strcmp (this_chat_id, chat_id) == 0 && - this_is_chatroom == is_chatroom) { - gtk_tree_selection_select_iter (selection, &iter); - path = gtk_tree_model_get_path (model, &iter); - gtk_tree_view_scroll_to_cell (view, path, NULL, TRUE, 0.5, 0.0); - gtk_tree_path_free (path); - g_object_unref (this_account); - g_free (this_chat_id); - break; - } - - g_object_unref (this_account); - g_free (this_chat_id); - } -} - -static gboolean -log_window_chats_get_selected (GossipLogWindow *window, - McAccount **account, - gchar **chat_id, - gboolean *is_chatroom) -{ - GtkTreeView *view; - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - gchar *id = NULL; - McAccount *acc = NULL; - gboolean room = FALSE; - - view = GTK_TREE_VIEW (window->treeview_chats); - model = gtk_tree_view_get_model (view); - selection = gtk_tree_view_get_selection (view); - - if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) { - return FALSE; - } - - gtk_tree_model_get (model, &iter, - COL_CHAT_ACCOUNT, &acc, - COL_CHAT_ID, &id, - COL_CHAT_IS_CHATROOM, &room, - -1); - - if (chat_id) { - *chat_id = id; - } else { - g_free (id); - } - if (account) { - *account = acc; - } else { - g_object_unref (acc); - } - if (is_chatroom) { - *is_chatroom = room; - } - - return TRUE; -} - -static void -log_window_chats_get_messages (GossipLogWindow *window, - const gchar *date_to_show) -{ - McAccount *account; - gchar *chat_id; - gboolean is_chatroom; - GossipMessage *message; - GList *messages; - GList *dates = NULL; - GList *l; - const gchar *date; - guint year_selected; - guint year; - guint month; - guint month_selected; - guint day; - - if (!log_window_chats_get_selected (window, &account, - &chat_id, &is_chatroom)) { - return; - } - - g_signal_handlers_block_by_func (window->calendar_chats, - log_window_calendar_chats_day_selected_cb, - window); - - /* Either use the supplied date or get the last */ - date = date_to_show; - if (!date) { - gboolean day_selected = FALSE; - - /* Get a list of dates and show them on the calendar */ - dates = empathy_log_manager_get_dates (window->log_manager, - account, chat_id, - is_chatroom); - - for (l = dates; l; l = l->next) { - const gchar *str; - - str = l->data; - if (!str) { - continue; - } - - sscanf (str, "%4d%2d%2d", &year, &month, &day); - gtk_calendar_get_date (GTK_CALENDAR (window->calendar_chats), - &year_selected, - &month_selected, - NULL); - - month_selected++; - - if (!l->next) { - date = str; - } - - if (year != year_selected || month != month_selected) { - continue; - } - - - gossip_debug (DEBUG_DOMAIN, "Marking date:'%s'", str); - gtk_calendar_mark_day (GTK_CALENDAR (window->calendar_chats), day); - - if (l->next) { - continue; - } - - day_selected = TRUE; - - gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats), day); - } - - if (!day_selected) { - /* Unselect the day in the calendar */ - gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats), 0); - } - } else { - sscanf (date, "%4d%2d%2d", &year, &month, &day); - gtk_calendar_get_date (GTK_CALENDAR (window->calendar_chats), - &year_selected, - &month_selected, - NULL); - - month_selected++; - - if (year != year_selected && month != month_selected) { - day = 0; - } - - gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats), day); - } - g_signal_handlers_unblock_by_func (window->calendar_chats, - log_window_calendar_chats_day_selected_cb, - window); - - /* Clear all current messages shown in the textview */ - gossip_chat_view_clear (window->chatview_chats); - - /* Turn off scrolling temporarily */ - gossip_chat_view_scroll (window->chatview_find, FALSE); - - /* Get messages */ - messages = empathy_log_manager_get_messages_for_date (window->log_manager, - account, chat_id, - is_chatroom, - date); - - for (l = messages; l; l = l->next) { - message = l->data; - - gossip_chat_view_append_message (window->chatview_chats, - message); - g_object_unref (message); - } - g_list_free (messages); - - g_list_foreach (dates, (GFunc) g_free, NULL); - g_list_free (dates); - - g_object_unref (account); - g_free (chat_id); - - /* Turn back on scrolling */ - gossip_chat_view_scroll (window->chatview_find, TRUE); - - /* Scroll to the most recent messages */ - gossip_chat_view_scroll_down (window->chatview_chats); - - /* Give the search entry main focus */ - gtk_widget_grab_focus (window->entry_chats); -} - -static void -log_window_calendar_chats_day_selected_cb (GtkWidget *calendar, - GossipLogWindow *window) -{ - guint year; - guint month; - guint day; - - gchar *date; - - gtk_calendar_get_date (GTK_CALENDAR (calendar), &year, &month, &day); - - /* We need this hear because it appears that the months start from 0 */ - month++; - - date = g_strdup_printf ("%4.4d%2.2d%2.2d", year, month, day); - - gossip_debug (DEBUG_DOMAIN, "Currently selected date is:'%s'", date); - - log_window_chats_get_messages (window, date); - - g_free (date); -} - -static void -log_window_calendar_chats_month_changed_cb (GtkWidget *calendar, - GossipLogWindow *window) -{ - McAccount *account; - gchar *chat_id; - gboolean is_chatroom; - guint year_selected; - guint month_selected; - - GList *dates; - GList *l; - - gtk_calendar_clear_marks (GTK_CALENDAR (calendar)); - - if (!log_window_chats_get_selected (window, &account, - &chat_id, &is_chatroom)) { - gossip_debug (DEBUG_DOMAIN, "No chat selected to get dates for..."); - return; - } - - g_object_get (calendar, - "month", &month_selected, - "year", &year_selected, - NULL); - - /* We need this hear because it appears that the months start from 0 */ - month_selected++; - - /* Get the log object for this contact */ - dates = empathy_log_manager_get_dates (window->log_manager, account, - chat_id, is_chatroom); - g_object_unref (account); - g_free (chat_id); - - for (l = dates; l; l = l->next) { - const gchar *str; - guint year; - guint month; - guint day; - - str = l->data; - if (!str) { - continue; - } - - sscanf (str, "%4d%2d%2d", &year, &month, &day); - - if (year == year_selected && month == month_selected) { - gossip_debug (DEBUG_DOMAIN, "Marking date:'%s'", str); - gtk_calendar_mark_day (GTK_CALENDAR (window->calendar_chats), day); - } - } - - g_list_foreach (dates, (GFunc) g_free, NULL); - g_list_free (dates); - - gossip_debug (DEBUG_DOMAIN, - "Currently showing month %d and year %d", - month_selected, year_selected); -} - -static void -log_window_entry_chats_changed_cb (GtkWidget *entry, - GossipLogWindow *window) -{ - const gchar *str; - - str = gtk_entry_get_text (GTK_ENTRY (window->entry_chats)); - gossip_chat_view_highlight (window->chatview_chats, str); - - if (str) { - gossip_chat_view_find_next (window->chatview_chats, - str, - TRUE); - } -} - -static void -log_window_entry_chats_activate_cb (GtkWidget *entry, - GossipLogWindow *window) -{ - const gchar *str; - - str = gtk_entry_get_text (GTK_ENTRY (window->entry_chats)); - - if (str) { - gossip_chat_view_find_next (window->chatview_chats, - str, - FALSE); - } -} - diff --git a/libempathy-gtk/gossip-log-window.glade b/libempathy-gtk/gossip-log-window.glade deleted file mode 100644 index 4309a354..00000000 --- a/libempathy-gtk/gossip-log-window.glade +++ /dev/null @@ -1,470 +0,0 @@ - - - - - - - View Previous Conversations - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - 640 - 450 - True - False - gtk-justify-left - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - 2 - True - True - True - True - GTK_POS_TOP - False - False - - - - 12 - True - False - 6 - - - - True - False - 12 - - - - True - _For: - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - entry_find - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - True - True - True - True - 0 - - True - * - True - - - 0 - True - True - - - - - - True - False - True - True - True - gtk-find - True - GTK_RELIEF_NORMAL - False - - - 0 - False - False - - - - - 0 - False - False - - - - - - True - True - 120 - - - - True - True - GTK_POLICY_NEVER - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - True - True - True - False - False - False - False - False - False - - - - - True - False - - - - - - True - False - 6 - - - - True - True - GTK_POLICY_NEVER - GTK_POLICY_ALWAYS - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - - - - 0 - True - True - - - - - - True - False - 12 - - - - - - - - True - False - True - gtk-media-next - True - GTK_RELIEF_NORMAL - False - - - 0 - False - False - GTK_PACK_END - - - - - - True - False - True - gtk-media-previous - True - GTK_RELIEF_NORMAL - False - - - 0 - False - False - GTK_PACK_END - - - - - 0 - False - False - - - - - True - True - - - - - 0 - True - True - - - - - False - True - - - - - - True - Search - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - tab - - - - - - 12 - True - 2 - 2 - False - 6 - 6 - - - - True - False - 6 - - - - True - gtk-find - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - True - True - True - 0 - - True - * - True - - - 0 - True - True - - - - - 1 - 2 - 0 - 1 - fill - fill - - - - - - True - False - 6 - - - - 150 - True - True - GTK_POLICY_NEVER - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - True - True - False - False - False - True - False - False - False - - - - - 0 - True - True - - - - - - True - True - GTK_CALENDAR_SHOW_HEADING|GTK_CALENDAR_SHOW_DAY_NAMES - - - 0 - False - False - - - - - 0 - 1 - 1 - 2 - fill - - - - - - True - True - GTK_POLICY_NEVER - GTK_POLICY_ALWAYS - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - - - - 1 - 2 - 1 - 2 - - - - - - True - False - 6 - - - - - - - 0 - 1 - 0 - 1 - fill - fill - - - - - False - True - - - - - - True - Conversations - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - tab - - - - - - - diff --git a/libempathy-gtk/gossip-log-window.h b/libempathy-gtk/gossip-log-window.h deleted file mode 100644 index 7801072f..00000000 --- a/libempathy-gtk/gossip-log-window.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Martyn Russell - * Xavier Claessens - */ - -#ifndef __GOSSIP_LOG_WINDOW_H__ -#define __GOSSIP_LOG_WINDOW_H__ - -#include - -G_BEGIN_DECLS - -void gossip_log_window_show (McAccount *account, - const gchar *chat_id, - gboolean chatroom, - GtkWindow *parent); - -G_END_DECLS - -#endif /* __GOSSIP_LOG_WINDOW_H__ */ diff --git a/libempathy-gtk/gossip-new-chatroom-dialog.c b/libempathy-gtk/gossip-new-chatroom-dialog.c deleted file mode 100644 index 81594f1d..00000000 --- a/libempathy-gtk/gossip-new-chatroom-dialog.c +++ /dev/null @@ -1,690 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Martyn Russell - * Xavier Claessens - */ - -#include "config.h" - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include "gossip-new-chatroom-dialog.h" -#include "gossip-account-chooser.h" -//#include "gossip-chatrooms-window.h" -#include "gossip-ui-utils.h" -#include "ephy-spinner.h" - -#define DEBUG_DOMAIN "NewChatroomDialog" - -typedef struct { - GtkWidget *window; - - GtkWidget *vbox_widgets; - - GtkWidget *hbox_account; - GtkWidget *label_account; - GtkWidget *account_chooser; - - GtkWidget *hbox_server; - GtkWidget *label_server; - GtkWidget *entry_server; - GtkWidget *togglebutton_refresh; - - GtkWidget *hbox_room; - GtkWidget *label_room; - GtkWidget *entry_room; - - GtkWidget *hbox_nick; - GtkWidget *label_nick; - GtkWidget *entry_nick; - - GtkWidget *vbox_browse; - GtkWidget *image_status; - GtkWidget *label_status; - GtkWidget *hbox_status; - GtkWidget *throbber; - GtkWidget *treeview; - GtkTreeModel *model; - GtkTreeModel *filter; - - GtkWidget *button_join; - GtkWidget *button_close; -} GossipNewChatroomDialog; - -typedef struct { - guint handle; - gchar *channel_type; - gchar *name; - gchar *id; -} EmpathyRoomListItem; - -enum { - COL_IMAGE, - COL_NAME, - COL_POINTER, - COL_COUNT -}; - -static void new_chatroom_dialog_response_cb (GtkWidget *widget, - gint response, - GossipNewChatroomDialog *dialog); -static void new_chatroom_dialog_destroy_cb (GtkWidget *widget, - GossipNewChatroomDialog *dialog); -static void new_chatroom_dialog_model_setup (GossipNewChatroomDialog *dialog); -static void new_chatroom_dialog_model_add_columns (GossipNewChatroomDialog *dialog); -static void new_chatroom_dialog_update_buttons (GossipNewChatroomDialog *dialog); -static void new_chatroom_dialog_update_widgets (GossipNewChatroomDialog *dialog); -static void new_chatroom_dialog_account_changed_cb (GtkComboBox *combobox, - GossipNewChatroomDialog *dialog); -static void new_chatroom_dialog_model_add (GossipNewChatroomDialog *dialog, - EmpathyRoomListItem *item); -static void new_chatroom_dialog_model_clear (GossipNewChatroomDialog *dialog); -static GList * new_chatroom_dialog_model_get_selected (GossipNewChatroomDialog *dialog); -static gboolean new_chatroom_dialog_model_filter_func (GtkTreeModel *model, - GtkTreeIter *iter, - GossipNewChatroomDialog *dialog); -static void new_chatroom_dialog_model_row_activated_cb (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - GossipNewChatroomDialog *dialog); -static void new_chatroom_dialog_model_row_inserted_cb (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - GossipNewChatroomDialog *dialog); -static void new_chatroom_dialog_model_row_deleted_cb (GtkTreeModel *model, - GtkTreePath *path, - GossipNewChatroomDialog *dialog); -static void new_chatroom_dialog_model_selection_changed (GtkTreeSelection *selection, - GossipNewChatroomDialog *dialog); -static void new_chatroom_dialog_join (GossipNewChatroomDialog *dialog); -static void new_chatroom_dialog_entry_changed_cb (GtkWidget *entry, - GossipNewChatroomDialog *dialog); -static void new_chatroom_dialog_browse_start (GossipNewChatroomDialog *dialog); -static void new_chatroom_dialog_browse_stop (GossipNewChatroomDialog *dialog); -static void new_chatroom_dialog_entry_server_activate_cb (GtkWidget *widget, - GossipNewChatroomDialog *dialog); -static void new_chatroom_dialog_togglebutton_refresh_toggled_cb (GtkWidget *widget, - GossipNewChatroomDialog *dialog); - -static GossipNewChatroomDialog *dialog_p = NULL; - -void -gossip_new_chatroom_dialog_show (GtkWindow *parent) -{ - GossipNewChatroomDialog *dialog; - GladeXML *glade; - GList *accounts; - gint account_num; - GtkSizeGroup *size_group; - - if (dialog_p) { - gtk_window_present (GTK_WINDOW (dialog_p->window)); - return; - } - - dialog_p = dialog = g_new0 (GossipNewChatroomDialog, 1); - - glade = gossip_glade_get_file ("gossip-new-chatroom-dialog.glade", - "new_chatroom_dialog", - NULL, - "new_chatroom_dialog", &dialog->window, - "hbox_account", &dialog->hbox_account, - "label_account", &dialog->label_account, - "vbox_widgets", &dialog->vbox_widgets, - "label_server", &dialog->label_server, - "label_room", &dialog->label_room, - "label_nick", &dialog->label_nick, - "hbox_server", &dialog->hbox_server, - "hbox_room", &dialog->hbox_room, - "hbox_nick", &dialog->hbox_nick, - "entry_server", &dialog->entry_server, - "entry_room", &dialog->entry_room, - "entry_nick", &dialog->entry_nick, - "togglebutton_refresh", &dialog->togglebutton_refresh, - "vbox_browse", &dialog->vbox_browse, - "image_status", &dialog->image_status, - "label_status", &dialog->label_status, - "hbox_status", &dialog->hbox_status, - "treeview", &dialog->treeview, - "button_join", &dialog->button_join, - NULL); - - gossip_glade_connect (glade, - dialog, - "new_chatroom_dialog", "response", new_chatroom_dialog_response_cb, - "new_chatroom_dialog", "destroy", new_chatroom_dialog_destroy_cb, - "entry_nick", "changed", new_chatroom_dialog_entry_changed_cb, - "entry_server", "changed", new_chatroom_dialog_entry_changed_cb, - "entry_server", "activate", new_chatroom_dialog_entry_server_activate_cb, - "entry_room", "changed", new_chatroom_dialog_entry_changed_cb, - "togglebutton_refresh", "toggled", new_chatroom_dialog_togglebutton_refresh_toggled_cb, - NULL); - - g_object_unref (glade); - - g_object_add_weak_pointer (G_OBJECT (dialog->window), (gpointer) &dialog_p); - - /* Label alignment */ - size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); - - gtk_size_group_add_widget (size_group, dialog->label_account); - gtk_size_group_add_widget (size_group, dialog->label_server); - gtk_size_group_add_widget (size_group, dialog->label_room); - gtk_size_group_add_widget (size_group, dialog->label_nick); - - g_object_unref (size_group); - - /* Account chooser for custom */ - dialog->account_chooser = gossip_account_chooser_new (); - gtk_box_pack_start (GTK_BOX (dialog->hbox_account), - dialog->account_chooser, - TRUE, TRUE, 0); - gtk_widget_show (dialog->account_chooser); - - g_signal_connect (GTK_COMBO_BOX (dialog->account_chooser), "changed", - G_CALLBACK (new_chatroom_dialog_account_changed_cb), - dialog); - - /* Populate */ - accounts = mc_accounts_list (); - account_num = g_list_length (accounts); - - g_list_foreach (accounts, (GFunc) g_object_unref, NULL); - g_list_free (accounts); - - if (account_num > 1) { - gtk_widget_show (dialog->hbox_account); - } else { - /* Show no accounts combo box */ - gtk_widget_hide (dialog->hbox_account); - } - - /* Add throbber */ - dialog->throbber = ephy_spinner_new (); - ephy_spinner_set_size (EPHY_SPINNER (dialog->throbber), GTK_ICON_SIZE_LARGE_TOOLBAR); - gtk_widget_show (dialog->throbber); - - gtk_box_pack_start (GTK_BOX (dialog->hbox_status), dialog->throbber, - FALSE, FALSE, 0); - - /* Set up chatrooms treeview */ - new_chatroom_dialog_model_setup (dialog); - - /* Set things up according to the account type */ - new_chatroom_dialog_update_widgets (dialog); - - if (parent) { - gtk_window_set_transient_for (GTK_WINDOW (dialog->window), - GTK_WINDOW (parent)); - } - - gtk_widget_show (dialog->window); -} - -static void -new_chatroom_dialog_response_cb (GtkWidget *widget, - gint response, - GossipNewChatroomDialog *dialog) -{ - if (response == GTK_RESPONSE_OK) { - new_chatroom_dialog_join (dialog); - } - - gtk_widget_destroy (widget); -} - -static void -new_chatroom_dialog_destroy_cb (GtkWidget *widget, - GossipNewChatroomDialog *dialog) -{ - g_object_unref (dialog->model); - g_object_unref (dialog->filter); - - g_free (dialog); -} - -static void -new_chatroom_dialog_model_setup (GossipNewChatroomDialog *dialog) -{ - GtkTreeView *view; - GtkListStore *store; - GtkTreeSelection *selection; - - /* View */ - view = GTK_TREE_VIEW (dialog->treeview); - - g_signal_connect (view, "row-activated", - G_CALLBACK (new_chatroom_dialog_model_row_activated_cb), - dialog); - - /* Store/Model */ - store = gtk_list_store_new (COL_COUNT, - G_TYPE_STRING, /* Image */ - G_TYPE_STRING, /* Text */ - G_TYPE_POINTER); /* infos */ - - dialog->model = GTK_TREE_MODEL (store); - - /* Filter */ - dialog->filter = gtk_tree_model_filter_new (dialog->model, NULL); - - gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (dialog->filter), - (GtkTreeModelFilterVisibleFunc) - new_chatroom_dialog_model_filter_func, - dialog, - NULL); - - gtk_tree_view_set_model (view, dialog->filter); - - g_signal_connect (dialog->filter, "row-inserted", - G_CALLBACK (new_chatroom_dialog_model_row_inserted_cb), - dialog); - g_signal_connect (dialog->filter, "row-deleted", - G_CALLBACK (new_chatroom_dialog_model_row_deleted_cb), - dialog); - - /* Selection */ - selection = gtk_tree_view_get_selection (view); - gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE); - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), - COL_NAME, GTK_SORT_ASCENDING); - - g_signal_connect (selection, "changed", - G_CALLBACK (new_chatroom_dialog_model_selection_changed), dialog); - - /* Columns */ - new_chatroom_dialog_model_add_columns (dialog); -} - -static void -new_chatroom_dialog_model_add_columns (GossipNewChatroomDialog *dialog) -{ - GtkTreeView *view; - GtkTreeViewColumn *column; - GtkCellRenderer *cell; - - view = GTK_TREE_VIEW (dialog->treeview); - gtk_tree_view_set_headers_visible (view, FALSE); - - /* Chatroom pointer */ - column = gtk_tree_view_column_new (); - gtk_tree_view_column_set_title (column, _("Chat Rooms")); - - cell = gtk_cell_renderer_pixbuf_new (); - gtk_tree_view_column_pack_start (column, cell, FALSE); - - cell = gtk_cell_renderer_text_new (); - g_object_set (cell, - "xpad", (guint) 4, - "ypad", (guint) 1, - "ellipsize", PANGO_ELLIPSIZE_END, - NULL); - - gtk_tree_view_column_pack_start (column, cell, TRUE); - - gtk_tree_view_column_set_expand (column, TRUE); - gtk_tree_view_append_column (view, column); -} - -static void -new_chatroom_dialog_update_buttons (GossipNewChatroomDialog *dialog) -{ - GtkButton *button; - GtkWidget *image; - GtkTreeView *view; - GtkTreeModel *model; - guint items; - const gchar *room; - - /* Sort out Join button. */ - button = GTK_BUTTON (dialog->button_join); - - image = gtk_button_get_image (button); - if (!image) { - image = gtk_image_new (); - gtk_button_set_image (button, image); - } - //gtk_button_set_use_stock (button, FALSE); - - room = gtk_entry_get_text (GTK_ENTRY (dialog->entry_room)); - - /* Collect necessary information first. */ - view = GTK_TREE_VIEW (dialog->treeview); - model = gtk_tree_view_get_model (view); - items = gtk_tree_model_iter_n_children (model, NULL); - - if (items < 1 && !G_STR_EMPTY (room)) { - gtk_button_set_label (button, _("Create")); - gtk_image_set_from_stock (GTK_IMAGE (image), - GTK_STOCK_NEW, - GTK_ICON_SIZE_BUTTON); - } else { - gtk_button_set_label (button, _("Join")); - gtk_image_set_from_stock (GTK_IMAGE (image), - GTK_STOCK_EXECUTE, - GTK_ICON_SIZE_BUTTON); - } - - gtk_widget_set_sensitive (dialog->button_join, !G_STR_EMPTY (room)); -} - -static void -new_chatroom_dialog_update_widgets (GossipNewChatroomDialog *dialog) -{ - GossipAccountChooser *account_chooser; - McAccount *account; - McProfile *profile; - const gchar *protocol; - - account_chooser = GOSSIP_ACCOUNT_CHOOSER (dialog->account_chooser); - account = gossip_account_chooser_get_account (account_chooser); - profile = mc_account_get_profile (account); - protocol = mc_profile_get_protocol_name (profile); - - /* hardcode here known protocols */ - if (strcmp (protocol, "jabber") == 0) { - const gchar *server; - - server = mc_profile_get_default_account_domain (profile); - if (server) { - gchar *conference_server; - - conference_server = g_strconcat ("conference.", - server, NULL); - gtk_entry_set_text (GTK_ENTRY (dialog->entry_server), - conference_server); - g_free (conference_server); - } - - gtk_widget_show (dialog->hbox_server); - gtk_widget_show (dialog->hbox_nick); - gtk_widget_show (dialog->vbox_browse); - - } - else if (strcmp (protocol, "salut") == 0) { - gtk_widget_hide (dialog->hbox_server); - gtk_widget_show (dialog->hbox_nick); - gtk_widget_show (dialog->vbox_browse); - } - else if (strcmp (protocol, "irc") == 0) { - gtk_widget_hide (dialog->hbox_server); - gtk_widget_hide (dialog->hbox_nick); - gtk_widget_show (dialog->vbox_browse); - } else { - gtk_widget_hide (dialog->hbox_server); - gtk_widget_hide (dialog->hbox_nick); - gtk_widget_hide (dialog->vbox_browse); - } - - new_chatroom_dialog_update_buttons (dialog); - - /* Final set up of the dialog */ - gtk_widget_grab_focus (dialog->entry_room); - - g_object_unref (account); - g_object_unref (profile); -} - -static void -new_chatroom_dialog_account_changed_cb (GtkComboBox *combobox, - GossipNewChatroomDialog *dialog) -{ - new_chatroom_dialog_update_widgets (dialog); -} - -static void -new_chatroom_dialog_model_add (GossipNewChatroomDialog *dialog, - EmpathyRoomListItem *item) -{ - GtkTreeView *view; - GtkTreeSelection *selection; - GtkListStore *store; - GtkTreeIter iter; - - /* Add to model */ - view = GTK_TREE_VIEW (dialog->treeview); - selection = gtk_tree_view_get_selection (view); - store = GTK_LIST_STORE (dialog->model); - - gtk_list_store_append (store, &iter); - - gtk_list_store_set (store, &iter, - COL_NAME, item->name, - COL_POINTER, item, - -1); -} - -static void -new_chatroom_dialog_model_clear (GossipNewChatroomDialog *dialog) -{ - GtkListStore *store; - - store = GTK_LIST_STORE (dialog->model); - gtk_list_store_clear (store); -} - -static GList * -new_chatroom_dialog_model_get_selected (GossipNewChatroomDialog *dialog) -{ - GtkTreeView *view; - GtkTreeModel *model; - GtkTreeSelection *selection; - GList *rows, *l; - GList *chatrooms = NULL; - - view = GTK_TREE_VIEW (dialog->treeview); - selection = gtk_tree_view_get_selection (view); - model = gtk_tree_view_get_model (view); - - rows = gtk_tree_selection_get_selected_rows (selection, NULL); - for (l = rows; l; l = l->next) { - GtkTreeIter iter; - EmpathyRoomListItem *chatroom; - - if (!gtk_tree_model_get_iter (model, &iter, l->data)) { - continue; - } - - gtk_tree_model_get (model, &iter, COL_POINTER, &chatroom, -1); - chatrooms = g_list_append (chatrooms, chatroom); - } - - g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL); - g_list_free (rows); - - return chatrooms; -} - -static gboolean -new_chatroom_dialog_model_filter_func (GtkTreeModel *model, - GtkTreeIter *iter, - GossipNewChatroomDialog *dialog) -{ - EmpathyRoomListItem *chatroom; - const gchar *text; - gchar *room_nocase; - gchar *text_nocase; - gboolean found = FALSE; - - gtk_tree_model_get (model, iter, COL_POINTER, &chatroom, -1); - - if (!chatroom) { - return TRUE; - } - - text = gtk_entry_get_text (GTK_ENTRY (dialog->entry_room)); - - /* Casefold */ - room_nocase = g_utf8_casefold (chatroom->id, -1); - text_nocase = g_utf8_casefold (text, -1); - - /* Compare */ - if (g_utf8_strlen (text_nocase, -1) < 1 || - strstr (room_nocase, text_nocase)) { - found = TRUE; - } - - g_free (room_nocase); - g_free (text_nocase); - - return found; -} - -static void -new_chatroom_dialog_model_row_activated_cb (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - GossipNewChatroomDialog *dialog) -{ - gtk_widget_activate (dialog->button_join); -} - -static void -new_chatroom_dialog_model_row_inserted_cb (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - GossipNewChatroomDialog *dialog) -{ - new_chatroom_dialog_update_buttons (dialog); -} - -static void -new_chatroom_dialog_model_row_deleted_cb (GtkTreeModel *model, - GtkTreePath *path, - GossipNewChatroomDialog *dialog) -{ - new_chatroom_dialog_update_buttons (dialog); -} - -static void -new_chatroom_dialog_model_selection_changed (GtkTreeSelection *selection, - GossipNewChatroomDialog *dialog) -{ - new_chatroom_dialog_update_buttons (dialog); -} - -static void -new_chatroom_dialog_join (GossipNewChatroomDialog *dialog) -{ - McAccount *account; - GossipAccountChooser *account_chooser; - MissionControl *mc; - GList *chatrooms, *l; - const gchar *room; - const gchar *server = NULL; - gchar *room_name = NULL; - - chatrooms = new_chatroom_dialog_model_get_selected (dialog); - if (chatrooms) { - for (l = chatrooms; l; l = l->next) { - /* Join it */ - } - g_list_free (chatrooms); - return; - } - - room = gtk_entry_get_text (GTK_ENTRY (dialog->entry_room)); - if (GTK_WIDGET_VISIBLE (dialog->hbox_server)) { - server = gtk_entry_get_text (GTK_ENTRY (dialog->entry_server)); - } - account_chooser = GOSSIP_ACCOUNT_CHOOSER (dialog->account_chooser); - account = gossip_account_chooser_get_account (account_chooser); - - if (!G_STR_EMPTY (server)) { - room_name = g_strconcat (room, "@", server, NULL); - } else { - room_name = g_strdup (room); - } - - gossip_debug (DEBUG_DOMAIN, "Requesting channel for '%s'", room_name); - - mc = gossip_mission_control_new (); - mission_control_request_channel_with_string_handle (mc, - account, - TP_IFACE_CHANNEL_TYPE_TEXT, - room_name, - TP_HANDLE_TYPE_ROOM, - NULL, NULL); - g_free (room_name); - g_object_unref (mc); -} - -static void -new_chatroom_dialog_entry_changed_cb (GtkWidget *entry, - GossipNewChatroomDialog *dialog) -{ - if (entry == dialog->entry_room) { - gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (dialog->filter)); - } - - new_chatroom_dialog_update_buttons (dialog); -} - -static void -new_chatroom_dialog_browse_start (GossipNewChatroomDialog *dialog) -{ - if (0) { - new_chatroom_dialog_model_clear (dialog); - new_chatroom_dialog_model_add (dialog, NULL); - } -} - -static void -new_chatroom_dialog_browse_stop (GossipNewChatroomDialog *dialog) -{ -} - -static void -new_chatroom_dialog_entry_server_activate_cb (GtkWidget *widget, - GossipNewChatroomDialog *dialog) -{ - new_chatroom_dialog_togglebutton_refresh_toggled_cb (dialog->togglebutton_refresh, - dialog); -} - -static void -new_chatroom_dialog_togglebutton_refresh_toggled_cb (GtkWidget *widget, - GossipNewChatroomDialog *dialog) -{ - gboolean toggled; - - toggled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); - - if (toggled) { - new_chatroom_dialog_browse_start (dialog); - } else { - new_chatroom_dialog_browse_stop (dialog); - } -} - diff --git a/libempathy-gtk/gossip-new-chatroom-dialog.glade b/libempathy-gtk/gossip-new-chatroom-dialog.glade deleted file mode 100644 index 49bdadb6..00000000 --- a/libempathy-gtk/gossip-new-chatroom-dialog.glade +++ /dev/null @@ -1,519 +0,0 @@ - - - - - - - 5 - True - Join New - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - 350 - False - False - gtk-new - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - False - False - - - - True - False - 6 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-close - True - GTK_RELIEF_NORMAL - True - -7 - - - - - - True - False - True - True - True - GTK_RELIEF_NORMAL - True - -5 - - - - True - 0.5 - 0.5 - 0 - 0 - 0 - 0 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-execute - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - Join - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - - - - - - 0 - False - True - GTK_PACK_END - - - - - - 5 - True - False - 18 - - - - True - False - 12 - - - - True - Account: - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - True - - - - - - - - - 0 - True - True - - - - - - True - False - 6 - - - - True - False - 12 - - - - True - _Server: - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - entry_server - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - True - True - True - 0 - - True - * - False - 25 - - - 0 - True - True - - - - - - True - True - Re_fresh - True - GTK_RELIEF_NORMAL - True - False - False - - - 0 - False - False - - - - - 0 - True - True - - - - - - True - False - 12 - - - - True - _Room: - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - entry_room - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - Enter the room name to join here or click on one or more rooms in the list. - True - True - True - 0 - - True - * - True - 32 - - - 0 - True - True - - - - - 0 - True - True - - - - - - True - False - 12 - - - - True - _Nickname: - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - entry_nick - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - True - True - True - 0 - - True - * - False - - - 0 - True - True - - - - - 0 - True - True - - - - - 0 - False - False - - - - - - True - False - 6 - - - - True - False - 6 - - - - True - False - 3 - - - - True - 2 - gtk-find - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - Browse: - False - False - GTK_JUSTIFY_LEFT - True - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - True - True - - - - - 0 - True - True - - - - - - - - - 0 - True - True - - - - - - 150 - True - True - GTK_POLICY_NEVER - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - True - This list represents all chat rooms hosted on the server you have entered. - True - False - False - False - True - False - False - False - - - - - 0 - True - True - - - - - 0 - True - True - - - - - 0 - False - False - - - - - - - diff --git a/libempathy-gtk/gossip-new-chatroom-dialog.h b/libempathy-gtk/gossip-new-chatroom-dialog.h deleted file mode 100644 index 44b7ce67..00000000 --- a/libempathy-gtk/gossip-new-chatroom-dialog.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Martyn Russell - * Xavier Claessens - */ - -#ifndef __GOSSIP_NEW_CHATROOMS_WINDOW_H__ -#define __GOSSIP_NEW_CHATROOMS_WINDOW_H__ - -G_BEGIN_DECLS - -void gossip_new_chatroom_dialog_show (GtkWindow *parent); - -G_END_DECLS - -#endif /* __GOSSIP_NEW_CHATROOMS_WINDOW_H__ */ diff --git a/libempathy-gtk/gossip-preferences.c b/libempathy-gtk/gossip-preferences.c deleted file mode 100644 index fd93353d..00000000 --- a/libempathy-gtk/gossip-preferences.c +++ /dev/null @@ -1,985 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2003-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Richard Hult - * Martyn Russell - */ - -#include "config.h" - -#include - -#include -#include -#include - -#include - -#include "gossip-preferences.h" -#include "gossip-ui-utils.h" -#include "gossip-theme-manager.h" -#include "gossip-spell.h" -#include "gossip-contact-list-store.h" - -typedef struct { - GtkWidget *dialog; - - GtkWidget *notebook; - - GtkWidget *checkbutton_show_avatars; - GtkWidget *checkbutton_compact_contact_list; - GtkWidget *checkbutton_show_smileys; - GtkWidget *combobox_chat_theme; - GtkWidget *checkbutton_theme_chat_room; - GtkWidget *checkbutton_separate_chat_windows; - GtkWidget *radiobutton_contact_list_sort_by_name; - GtkWidget *radiobutton_contact_list_sort_by_state; - - GtkWidget *checkbutton_sounds_for_messages; - GtkWidget *checkbutton_sounds_when_busy; - GtkWidget *checkbutton_sounds_when_away; - GtkWidget *checkbutton_popups_when_available; - - GtkWidget *treeview_spell_checker; - GtkWidget *checkbutton_spell_checker; - - GList *notify_ids; -} GossipPreferences; - -static void preferences_setup_widgets (GossipPreferences *preferences); -static void preferences_languages_setup (GossipPreferences *preferences); -static void preferences_languages_add (GossipPreferences *preferences); -static void preferences_languages_save (GossipPreferences *preferences); -static gboolean preferences_languages_save_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gchar **languages); -static void preferences_languages_load (GossipPreferences *preferences); -static gboolean preferences_languages_load_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gchar **languages); -static void preferences_languages_cell_toggled_cb (GtkCellRendererToggle *cell, - gchar *path_string, - GossipPreferences *preferences); -static void preferences_themes_setup (GossipPreferences *preferences); -static void preferences_widget_sync_bool (const gchar *key, - GtkWidget *widget); -static void preferences_widget_sync_int (const gchar *key, - GtkWidget *widget); -static void preferences_widget_sync_string (const gchar *key, - GtkWidget *widget); -static void preferences_widget_sync_string_combo (const gchar *key, - GtkWidget *widget); -static void preferences_notify_int_cb (GossipConf *conf, - const gchar *key, - gpointer user_data); -static void preferences_notify_string_cb (GossipConf *conf, - const gchar *key, - gpointer user_data); -static void preferences_notify_string_combo_cb (GossipConf *conf, - const gchar *key, - gpointer user_data); -static void preferences_notify_bool_cb (GossipConf *conf, - const gchar *key, - gpointer user_data); -static void preferences_notify_sensitivity_cb (GossipConf *conf, - const gchar *key, - gpointer user_data); -static void preferences_hookup_spin_button (GossipPreferences *preferences, - const gchar *key, - GtkWidget *widget); -static void preferences_hookup_entry (GossipPreferences *preferences, - const gchar *key, - GtkWidget *widget); -static void preferences_hookup_toggle_button (GossipPreferences *preferences, - const gchar *key, - GtkWidget *widget); -static void preferences_hookup_radio_button (GossipPreferences *preferences, - const gchar *key, - GtkWidget *widget); -static void preferences_hookup_string_combo (GossipPreferences *preferences, - const gchar *key, - GtkWidget *widget); -static void preferences_hookup_sensitivity (GossipPreferences *preferences, - const gchar *key, - GtkWidget *widget); -static void preferences_spin_button_value_changed_cb (GtkWidget *button, - gpointer user_data); -static void preferences_entry_value_changed_cb (GtkWidget *entry, - gpointer user_data); -static void preferences_toggle_button_toggled_cb (GtkWidget *button, - gpointer user_data); -static void preferences_radio_button_toggled_cb (GtkWidget *button, - gpointer user_data); -static void preferences_string_combo_changed_cb (GtkWidget *button, - gpointer user_data); -static void preferences_destroy_cb (GtkWidget *widget, - GossipPreferences *preferences); -static void preferences_response_cb (GtkWidget *widget, - gint response, - GossipPreferences *preferences); - -enum { - COL_LANG_ENABLED, - COL_LANG_CODE, - COL_LANG_NAME, - COL_LANG_COUNT -}; - -enum { - COL_COMBO_VISIBLE_NAME, - COL_COMBO_NAME, - COL_COMBO_COUNT -}; - -static void -preferences_setup_widgets (GossipPreferences *preferences) -{ - preferences_hookup_toggle_button (preferences, - GOSSIP_PREFS_SOUNDS_FOR_MESSAGES, - preferences->checkbutton_sounds_for_messages); - preferences_hookup_toggle_button (preferences, - GOSSIP_PREFS_SOUNDS_WHEN_AWAY, - preferences->checkbutton_sounds_when_away); - preferences_hookup_toggle_button (preferences, - GOSSIP_PREFS_SOUNDS_WHEN_BUSY, - preferences->checkbutton_sounds_when_busy); - preferences_hookup_toggle_button (preferences, - GOSSIP_PREFS_POPUPS_WHEN_AVAILABLE, - preferences->checkbutton_popups_when_available); - - preferences_hookup_sensitivity (preferences, - GOSSIP_PREFS_SOUNDS_FOR_MESSAGES, - preferences->checkbutton_sounds_when_away); - preferences_hookup_sensitivity (preferences, - GOSSIP_PREFS_SOUNDS_FOR_MESSAGES, - preferences->checkbutton_sounds_when_busy); - - preferences_hookup_toggle_button (preferences, - GOSSIP_PREFS_UI_SEPARATE_CHAT_WINDOWS, - preferences->checkbutton_separate_chat_windows); - - preferences_hookup_toggle_button (preferences, - GOSSIP_PREFS_UI_SHOW_AVATARS, - preferences->checkbutton_show_avatars); - - preferences_hookup_toggle_button (preferences, - GOSSIP_PREFS_UI_COMPACT_CONTACT_LIST, - preferences->checkbutton_compact_contact_list); - - preferences_hookup_toggle_button (preferences, - GOSSIP_PREFS_CHAT_SHOW_SMILEYS, - preferences->checkbutton_show_smileys); - - preferences_hookup_string_combo (preferences, - GOSSIP_PREFS_CHAT_THEME, - preferences->combobox_chat_theme); - - preferences_hookup_toggle_button (preferences, - GOSSIP_PREFS_CHAT_THEME_CHAT_ROOM, - preferences->checkbutton_theme_chat_room); - - preferences_hookup_toggle_button (preferences, - GOSSIP_PREFS_CHAT_SPELL_CHECKER_ENABLED, - preferences->checkbutton_spell_checker); - preferences_hookup_sensitivity (preferences, - GOSSIP_PREFS_CHAT_SPELL_CHECKER_ENABLED, - preferences->treeview_spell_checker); - - preferences_hookup_radio_button (preferences, - GOSSIP_PREFS_CONTACTS_SORT_CRITERIUM, - preferences->radiobutton_contact_list_sort_by_name); -} - -static void -preferences_languages_setup (GossipPreferences *preferences) -{ - GtkTreeView *view; - GtkListStore *store; - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeViewColumn *column; - GtkCellRenderer *renderer; - guint col_offset; - - view = GTK_TREE_VIEW (preferences->treeview_spell_checker); - - store = gtk_list_store_new (COL_LANG_COUNT, - G_TYPE_BOOLEAN, /* enabled */ - G_TYPE_STRING, /* code */ - G_TYPE_STRING); /* name */ - - gtk_tree_view_set_model (view, GTK_TREE_MODEL (store)); - - selection = gtk_tree_view_get_selection (view); - gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); - - model = GTK_TREE_MODEL (store); - - renderer = gtk_cell_renderer_toggle_new (); - g_signal_connect (renderer, "toggled", - G_CALLBACK (preferences_languages_cell_toggled_cb), - preferences); - - column = gtk_tree_view_column_new_with_attributes (NULL, renderer, - "active", COL_LANG_ENABLED, - NULL); - - gtk_tree_view_append_column (view, column); - - renderer = gtk_cell_renderer_text_new (); - col_offset = gtk_tree_view_insert_column_with_attributes (view, - -1, _("Language"), - renderer, - "text", COL_LANG_NAME, - NULL); - - g_object_set_data (G_OBJECT (renderer), - "column", GINT_TO_POINTER (COL_LANG_NAME)); - - column = gtk_tree_view_get_column (view, col_offset - 1); - gtk_tree_view_column_set_sort_column_id (column, COL_LANG_NAME); - gtk_tree_view_column_set_resizable (column, FALSE); - gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); - - g_object_unref (store); -} - -static void -preferences_languages_add (GossipPreferences *preferences) -{ - GtkTreeView *view; - GtkListStore *store; - GList *codes, *l; - - view = GTK_TREE_VIEW (preferences->treeview_spell_checker); - store = GTK_LIST_STORE (gtk_tree_view_get_model (view)); - - codes = gossip_spell_get_language_codes (); - for (l = codes; l; l = l->next) { - GtkTreeIter iter; - const gchar *code; - const gchar *name; - - code = l->data; - name = gossip_spell_get_language_name (code); - if (!name) { - continue; - } - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - COL_LANG_CODE, code, - COL_LANG_NAME, name, - -1); - } - - gossip_spell_free_language_codes (codes); -} - -static void -preferences_languages_save (GossipPreferences *preferences) -{ - GtkTreeView *view; - GtkTreeModel *model; - - gchar *languages = NULL; - - view = GTK_TREE_VIEW (preferences->treeview_spell_checker); - model = gtk_tree_view_get_model (view); - - gtk_tree_model_foreach (model, - (GtkTreeModelForeachFunc) preferences_languages_save_foreach, - &languages); - - if (!languages) { - /* Default to english */ - languages = g_strdup ("en"); - } - - gossip_conf_set_string (gossip_conf_get (), - GOSSIP_PREFS_CHAT_SPELL_CHECKER_LANGUAGES, - languages); - - g_free (languages); -} - -static gboolean -preferences_languages_save_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gchar **languages) -{ - gboolean enabled; - gchar *code; - - if (!languages) { - return TRUE; - } - - gtk_tree_model_get (model, iter, COL_LANG_ENABLED, &enabled, -1); - if (!enabled) { - return FALSE; - } - - gtk_tree_model_get (model, iter, COL_LANG_CODE, &code, -1); - if (!code) { - return FALSE; - } - - if (!(*languages)) { - *languages = g_strdup (code); - } else { - gchar *str = *languages; - *languages = g_strdup_printf ("%s,%s", str, code); - g_free (str); - } - - g_free (code); - - return FALSE; -} - -static void -preferences_languages_load (GossipPreferences *preferences) -{ - GtkTreeView *view; - GtkTreeModel *model; - gchar *value; - gchar **vlanguages; - - if (!gossip_conf_get_string (gossip_conf_get (), - GOSSIP_PREFS_CHAT_SPELL_CHECKER_LANGUAGES, - &value) || !value) { - return; - } - - vlanguages = g_strsplit (value, ",", -1); - g_free (value); - - view = GTK_TREE_VIEW (preferences->treeview_spell_checker); - model = gtk_tree_view_get_model (view); - - gtk_tree_model_foreach (model, - (GtkTreeModelForeachFunc) preferences_languages_load_foreach, - vlanguages); - - g_strfreev (vlanguages); -} - -static gboolean -preferences_languages_load_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gchar **languages) -{ - gchar *code; - gchar *lang; - gint i; - gboolean found = FALSE; - - if (!languages) { - return TRUE; - } - - gtk_tree_model_get (model, iter, COL_LANG_CODE, &code, -1); - if (!code) { - return FALSE; - } - - for (i = 0, lang = languages[i]; lang; lang = languages[++i]) { - if (strcmp (lang, code) == 0) { - found = TRUE; - } - } - - gtk_list_store_set (GTK_LIST_STORE (model), iter, COL_LANG_ENABLED, found, -1); - return FALSE; -} - -static void -preferences_languages_cell_toggled_cb (GtkCellRendererToggle *cell, - gchar *path_string, - GossipPreferences *preferences) -{ - GtkTreeView *view; - GtkTreeModel *model; - GtkListStore *store; - GtkTreePath *path; - GtkTreeIter iter; - gboolean enabled; - - view = GTK_TREE_VIEW (preferences->treeview_spell_checker); - model = gtk_tree_view_get_model (view); - store = GTK_LIST_STORE (model); - - path = gtk_tree_path_new_from_string (path_string); - - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_model_get (model, &iter, COL_LANG_ENABLED, &enabled, -1); - - enabled ^= 1; - - gtk_list_store_set (store, &iter, COL_LANG_ENABLED, enabled, -1); - gtk_tree_path_free (path); - - preferences_languages_save (preferences); -} - -static void -preferences_themes_setup (GossipPreferences *preferences) -{ - GtkComboBox *combo; - GtkListStore *model; - GtkTreeIter iter; - const gchar **themes; - gint i; - - combo = GTK_COMBO_BOX (preferences->combobox_chat_theme); - - model = gtk_list_store_new (COL_COMBO_COUNT, - G_TYPE_STRING, - G_TYPE_STRING); - - themes = gossip_theme_manager_get_themes (); - for (i = 0; themes[i]; i += 2) { - gtk_list_store_append (model, &iter); - gtk_list_store_set (model, &iter, - COL_COMBO_VISIBLE_NAME, _(themes[i + 1]), - COL_COMBO_NAME, themes[i], - -1); - } - - gtk_combo_box_set_model (combo, GTK_TREE_MODEL (model)); - g_object_unref (model); -} - -static void -preferences_widget_sync_bool (const gchar *key, GtkWidget *widget) -{ - gboolean value; - - if (gossip_conf_get_bool (gossip_conf_get (), key, &value)) { - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), value); - } -} - -static void -preferences_widget_sync_int (const gchar *key, GtkWidget *widget) -{ - gint value; - - if (gossip_conf_get_int (gossip_conf_get (), key, &value)) { - if (GTK_IS_SPIN_BUTTON (widget)) { - gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value); - } - } -} - -static void -preferences_widget_sync_string (const gchar *key, GtkWidget *widget) -{ - gchar *value; - - if (gossip_conf_get_string (gossip_conf_get (), key, &value) && value) { - if (GTK_IS_ENTRY (widget)) { - gtk_entry_set_text (GTK_ENTRY (widget), value); - } else if (GTK_IS_RADIO_BUTTON (widget)) { - if (strcmp (key, GOSSIP_PREFS_CONTACTS_SORT_CRITERIUM) == 0) { - GType type; - GEnumClass *enum_class; - GEnumValue *enum_value; - GSList *list; - GtkWidget *toggle_widget; - - /* Get index from new string */ - type = gossip_contact_list_store_sort_get_type (); - enum_class = G_ENUM_CLASS (g_type_class_peek (type)); - enum_value = g_enum_get_value_by_nick (enum_class, value); - - if (enum_value) { - list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget)); - toggle_widget = g_slist_nth_data (list, enum_value->value); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle_widget), TRUE); - } - } else { - g_warning ("Unhandled key:'%s' just had string change", key); - } - } - - g_free (value); - } -} - -static void -preferences_widget_sync_string_combo (const gchar *key, GtkWidget *widget) -{ - gchar *value; - GtkTreeModel *model; - GtkTreeIter iter; - gboolean found; - - if (!gossip_conf_get_string (gossip_conf_get (), key, &value)) { - return; - } - - model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget)); - - found = FALSE; - if (value && gtk_tree_model_get_iter_first (model, &iter)) { - gchar *name; - - do { - gtk_tree_model_get (model, &iter, - COL_COMBO_NAME, &name, - -1); - - if (strcmp (name, value) == 0) { - found = TRUE; - gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter); - break; - } else { - found = FALSE; - } - - g_free (name); - } while (gtk_tree_model_iter_next (model, &iter)); - } - - /* Fallback to the first one. */ - if (!found) { - if (gtk_tree_model_get_iter_first (model, &iter)) { - gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter); - } - } - - g_free (value); -} - -static void -preferences_notify_int_cb (GossipConf *conf, - const gchar *key, - gpointer user_data) -{ - preferences_widget_sync_int (key, user_data); -} - -static void -preferences_notify_string_cb (GossipConf *conf, - const gchar *key, - gpointer user_data) -{ - preferences_widget_sync_string (key, user_data); -} - -static void -preferences_notify_string_combo_cb (GossipConf *conf, - const gchar *key, - gpointer user_data) -{ - preferences_widget_sync_string_combo (key, user_data); -} - -static void -preferences_notify_bool_cb (GossipConf *conf, - const gchar *key, - gpointer user_data) -{ - preferences_widget_sync_bool (key, user_data); -} - -static void -preferences_notify_sensitivity_cb (GossipConf *conf, - const gchar *key, - gpointer user_data) -{ - gboolean value; - - if (gossip_conf_get_bool (conf, key, &value)) { - gtk_widget_set_sensitive (GTK_WIDGET (user_data), value); - } -} - -static void -preferences_add_id (GossipPreferences *preferences, guint id) -{ - preferences->notify_ids = g_list_prepend (preferences->notify_ids, - GUINT_TO_POINTER (id)); -} - -static void -preferences_hookup_spin_button (GossipPreferences *preferences, - const gchar *key, - GtkWidget *widget) -{ - guint id; - - /* Silence warning. */ - if (0) { - preferences_hookup_spin_button (preferences, key, widget); - } - - preferences_widget_sync_int (key, widget); - - g_object_set_data_full (G_OBJECT (widget), "key", - g_strdup (key), g_free); - - g_signal_connect (widget, - "value_changed", - G_CALLBACK (preferences_spin_button_value_changed_cb), - NULL); - - id = gossip_conf_notify_add (gossip_conf_get (), - key, - preferences_notify_int_cb, - widget); - if (id) { - preferences_add_id (preferences, id); - } -} - -static void -preferences_hookup_entry (GossipPreferences *preferences, - const gchar *key, - GtkWidget *widget) -{ - guint id; - - if (0) { /* Silent warning before we use this function. */ - preferences_hookup_entry (preferences, key, widget); - } - - preferences_widget_sync_string (key, widget); - - g_object_set_data_full (G_OBJECT (widget), "key", - g_strdup (key), g_free); - - g_signal_connect (widget, - "changed", - G_CALLBACK (preferences_entry_value_changed_cb), - NULL); - - id = gossip_conf_notify_add (gossip_conf_get (), - key, - preferences_notify_string_cb, - widget); - if (id) { - preferences_add_id (preferences, id); - } -} - -static void -preferences_hookup_toggle_button (GossipPreferences *preferences, - const gchar *key, - GtkWidget *widget) -{ - guint id; - - preferences_widget_sync_bool (key, widget); - - g_object_set_data_full (G_OBJECT (widget), "key", - g_strdup (key), g_free); - - g_signal_connect (widget, - "toggled", - G_CALLBACK (preferences_toggle_button_toggled_cb), - NULL); - - id = gossip_conf_notify_add (gossip_conf_get (), - key, - preferences_notify_bool_cb, - widget); - if (id) { - preferences_add_id (preferences, id); - } -} - -static void -preferences_hookup_radio_button (GossipPreferences *preferences, - const gchar *key, - GtkWidget *widget) -{ - GSList *group, *l; - guint id; - - preferences_widget_sync_string (key, widget); - - group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget)); - for (l = group; l; l = l->next) { - g_signal_connect (l->data, - "toggled", - G_CALLBACK (preferences_radio_button_toggled_cb), - NULL); - - g_object_set_data_full (G_OBJECT (l->data), "key", - g_strdup (key), g_free); - } - - id = gossip_conf_notify_add (gossip_conf_get (), - key, - preferences_notify_string_cb, - widget); - if (id) { - preferences_add_id (preferences, id); - } -} - -static void -preferences_hookup_string_combo (GossipPreferences *preferences, - const gchar *key, - GtkWidget *widget) -{ - guint id; - - preferences_widget_sync_string_combo (key, widget); - - g_object_set_data_full (G_OBJECT (widget), "key", - g_strdup (key), g_free); - - g_signal_connect (widget, - "changed", - G_CALLBACK (preferences_string_combo_changed_cb), - NULL); - - id = gossip_conf_notify_add (gossip_conf_get (), - key, - preferences_notify_string_combo_cb, - widget); - if (id) { - preferences_add_id (preferences, id); - } -} - -static void -preferences_hookup_sensitivity (GossipPreferences *preferences, - const gchar *key, - GtkWidget *widget) -{ - gboolean value; - guint id; - - if (gossip_conf_get_bool (gossip_conf_get (), key, &value)) { - gtk_widget_set_sensitive (widget, value); - } - - id = gossip_conf_notify_add (gossip_conf_get (), - key, - preferences_notify_sensitivity_cb, - widget); - if (id) { - preferences_add_id (preferences, id); - } -} - -static void -preferences_spin_button_value_changed_cb (GtkWidget *button, - gpointer user_data) -{ - const gchar *key; - - key = g_object_get_data (G_OBJECT (button), "key"); - - gossip_conf_set_int (gossip_conf_get (), - key, - gtk_spin_button_get_value (GTK_SPIN_BUTTON (button))); -} - -static void -preferences_entry_value_changed_cb (GtkWidget *entry, - gpointer user_data) -{ - const gchar *key; - - key = g_object_get_data (G_OBJECT (entry), "key"); - - gossip_conf_set_string (gossip_conf_get (), - key, - gtk_entry_get_text (GTK_ENTRY (entry))); -} - -static void -preferences_toggle_button_toggled_cb (GtkWidget *button, - gpointer user_data) -{ - const gchar *key; - - key = g_object_get_data (G_OBJECT (button), "key"); - - gossip_conf_set_bool (gossip_conf_get (), - key, - gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))); -} - -static void -preferences_radio_button_toggled_cb (GtkWidget *button, - gpointer user_data) -{ - const gchar *key; - const gchar *value = NULL; - - if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) { - return; - } - - key = g_object_get_data (G_OBJECT (button), "key"); - - if (key && strcmp (key, GOSSIP_PREFS_CONTACTS_SORT_CRITERIUM) == 0) { - GSList *group; - GType type; - GEnumClass *enum_class; - GEnumValue *enum_value; - - group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button)); - - /* Get string from index */ - type = gossip_contact_list_store_sort_get_type (); - enum_class = G_ENUM_CLASS (g_type_class_peek (type)); - enum_value = g_enum_get_value (enum_class, g_slist_index (group, button)); - - if (!enum_value) { - g_warning ("No GEnumValue for GossipContactListSort with GtkRadioButton index:%d", - g_slist_index (group, button)); - return; - } - - value = enum_value->value_nick; - } - - gossip_conf_set_string (gossip_conf_get (), key, value); -} - -static void -preferences_string_combo_changed_cb (GtkWidget *combo, - gpointer user_data) -{ - const gchar *key; - GtkTreeModel *model; - GtkTreeIter iter; - gchar *name; - - key = g_object_get_data (G_OBJECT (combo), "key"); - - if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) { - model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo)); - - gtk_tree_model_get (model, &iter, - COL_COMBO_NAME, &name, - -1); - gossip_conf_set_string (gossip_conf_get (), key, name); - g_free (name); - } -} - -static void -preferences_response_cb (GtkWidget *widget, - gint response, - GossipPreferences *preferences) -{ - gtk_widget_destroy (widget); -} - -static void -preferences_destroy_cb (GtkWidget *widget, - GossipPreferences *preferences) -{ - GList *l; - - for (l = preferences->notify_ids; l; l = l->next) { - guint id; - - id = GPOINTER_TO_UINT (l->data); - gossip_conf_notify_remove (gossip_conf_get (), id); - } - - g_list_free (preferences->notify_ids); - g_free (preferences); -} - -GtkWidget * -gossip_preferences_show (GtkWindow *parent) -{ - static GossipPreferences *preferences; - GladeXML *glade; - - if (preferences) { - gtk_window_present (GTK_WINDOW (preferences->dialog)); - return preferences->dialog; - } - - preferences = g_new0 (GossipPreferences, 1); - - glade = gossip_glade_get_file ( - "gossip-preferences.glade", - "preferences_dialog", - NULL, - "preferences_dialog", &preferences->dialog, - "notebook", &preferences->notebook, - "checkbutton_show_avatars", &preferences->checkbutton_show_avatars, - "checkbutton_compact_contact_list", &preferences->checkbutton_compact_contact_list, - "checkbutton_show_smileys", &preferences->checkbutton_show_smileys, - "combobox_chat_theme", &preferences->combobox_chat_theme, - "checkbutton_theme_chat_room", &preferences->checkbutton_theme_chat_room, - "checkbutton_separate_chat_windows", &preferences->checkbutton_separate_chat_windows, - "radiobutton_contact_list_sort_by_name", &preferences->radiobutton_contact_list_sort_by_name, - "radiobutton_contact_list_sort_by_state", &preferences->radiobutton_contact_list_sort_by_state, - "checkbutton_sounds_for_messages", &preferences->checkbutton_sounds_for_messages, - "checkbutton_sounds_when_busy", &preferences->checkbutton_sounds_when_busy, - "checkbutton_sounds_when_away", &preferences->checkbutton_sounds_when_away, - "checkbutton_popups_when_available", &preferences->checkbutton_popups_when_available, - "treeview_spell_checker", &preferences->treeview_spell_checker, - "checkbutton_spell_checker", &preferences->checkbutton_spell_checker, - NULL); - - gossip_glade_connect (glade, - preferences, - "preferences_dialog", "destroy", preferences_destroy_cb, - "preferences_dialog", "response", preferences_response_cb, - NULL); - - g_object_unref (glade); - - g_object_add_weak_pointer (G_OBJECT (preferences->dialog), (gpointer) &preferences); - - preferences_themes_setup (preferences); - - preferences_setup_widgets (preferences); - - preferences_languages_setup (preferences); - preferences_languages_add (preferences); - preferences_languages_load (preferences); - - if (gossip_spell_supported ()) { - GtkWidget *page; - - page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (preferences->notebook), 2); - gtk_widget_show (page); - } - - if (parent) { - gtk_window_set_transient_for (GTK_WINDOW (preferences->dialog), - GTK_WINDOW (parent)); - } - - gtk_widget_show (preferences->dialog); - - return preferences->dialog; -} - diff --git a/libempathy-gtk/gossip-preferences.glade b/libempathy-gtk/gossip-preferences.glade deleted file mode 100644 index c5cd5147..00000000 --- a/libempathy-gtk/gossip-preferences.glade +++ /dev/null @@ -1,1092 +0,0 @@ - - - - - - - - 5 - Preferences - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - False - True - False - gtk-preferences - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - False - False - - - - True - False - 2 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-close - True - GTK_RELIEF_NORMAL - True - -6 - - - - - 0 - False - True - GTK_PACK_END - - - - - - 5 - True - True - True - True - GTK_POS_TOP - False - False - - - - 12 - True - False - 18 - - - - True - 0 - 0.5 - GTK_SHADOW_NONE - - - - True - 0.5 - 0.5 - 1 - 1 - 6 - 0 - 12 - 0 - - - - True - False - 6 - - - - True - Avatars are user chosen images shown in the contact list - True - Show _avatars - True - GTK_RELIEF_NORMAL - True - True - False - True - - - 0 - False - False - - - - - - True - True - Show co_mpact contact list - True - GTK_RELIEF_NORMAL - True - False - False - True - - - 0 - False - False - - - - - - True - True - Show _smileys as images - True - GTK_RELIEF_NORMAL - True - True - False - True - - - 0 - False - False - - - - - - - - - - True - <b>Appearance</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - label_item - - - - - 0 - False - False - - - - - - True - 0 - 0.5 - GTK_SHADOW_NONE - - - - True - 0.5 - 0.5 - 1 - 1 - 6 - 0 - 12 - 0 - - - - True - True - _Open new chats in separate windows - True - GTK_RELIEF_NORMAL - True - False - False - True - - - - - - - - True - <b>Behaviour</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - label_item - - - - - 0 - False - False - - - - - True - 0 - 0.5 - GTK_SHADOW_NONE - - - - True - 0.5 - 0.5 - 1 - 1 - 6 - 0 - 12 - 0 - - - - True - False - 0 - - - - True - True - Sort by _name - True - GTK_RELIEF_NORMAL - True - False - False - True - - - 0 - False - False - - - - - - True - True - Sort by s_tate - True - GTK_RELIEF_NORMAL - True - False - False - True - radiobutton_contact_list_sort_by_name - - - 0 - False - False - - - - - - - - - - True - <b>Contact List</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - label_item - - - - - 0 - True - True - - - - - False - True - - - - - - True - General - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - tab - - - - - - 12 - True - False - 18 - - - - True - 0 - 0.5 - GTK_SHADOW_NONE - - - - True - 0.5 - 0.5 - 1 - 1 - 6 - 0 - 12 - 0 - - - - True - False - 6 - - - - True - True - _Play sound when messages arrive - True - GTK_RELIEF_NORMAL - True - False - False - True - - - 0 - False - False - - - - - - True - True - Enable sounds when _busy - True - GTK_RELIEF_NORMAL - True - False - False - True - - - 0 - False - False - - - - - - True - True - Enable sounds when _away - True - GTK_RELIEF_NORMAL - True - False - False - True - - - 0 - False - False - - - - - - - - - - True - <b>Audio</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - label_item - - - - - 0 - False - False - - - - - - True - 0 - 0.5 - GTK_SHADOW_NONE - - - - True - 0.5 - 0.5 - 1 - 1 - 6 - 0 - 12 - 0 - - - - True - True - Display notifications when contacts come _online - True - GTK_RELIEF_NORMAL - True - False - False - True - - - - - - - - True - <b>Visual</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - label_item - - - - - 0 - False - False - - - - - False - True - - - - - - True - Notifications - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - tab - - - - - - 12 - False - 18 - - - - True - 0 - 0.5 - GTK_SHADOW_NONE - - - - True - 0.5 - 0.5 - 1 - 1 - 6 - 0 - 12 - 0 - - - - True - False - 6 - - - - True - False - 0 - - - - True - False - 6 - - - - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - True - True - False - False - False - True - False - False - False - - - - - 0 - True - True - - - - - 0 - True - True - - - - - 0 - True - True - - - - - - True - False - 6 - - - - True - gtk-dialog-info - 4 - 0.5 - 0 - 0 - 0 - - - 0 - False - True - - - - - - True - <small>The list of languages reflects only the languages for which you have a dictionary installed.</small> - False - True - GTK_JUSTIFY_LEFT - True - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - True - True - - - - - 0 - False - True - - - - - - - - - - True - <b>Languages</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - label_item - - - - - 0 - True - True - - - - - - True - 0 - 0.5 - GTK_SHADOW_NONE - - - - True - 0.5 - 0.5 - 1 - 1 - 6 - 0 - 12 - 0 - - - - True - True - _Enable spell checking - True - GTK_RELIEF_NORMAL - True - False - False - True - - - - - - - - True - <b>Options</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - label_item - - - - - 0 - False - True - - - - - False - True - - - - - - True - Spell Checking - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - tab - - - - - - 12 - True - False - 18 - - - - True - 0 - 0.5 - GTK_SHADOW_NONE - - - - True - 0.5 - 0.5 - 1 - 1 - 6 - 0 - 12 - 0 - - - - True - False - 6 - - - - True - False - 12 - - - - True - Chat Th_eme: - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - combobox_chat_theme - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - - False - True - - - 0 - False - False - - - - - 0 - True - True - - - - - - - - - - True - <b>Appearance</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - label_item - - - - - 0 - False - False - - - - - - True - 0 - 0.5 - GTK_SHADOW_NONE - - - - True - 0.5 - 0.5 - 1 - 1 - 6 - 0 - 12 - 0 - - - - True - True - _Use for chat rooms - True - GTK_RELIEF_NORMAL - True - False - False - True - - - - - - - - True - <b>Options</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - label_item - - - - - 0 - False - False - - - - - False - True - - - - - - True - Themes - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - tab - - - - - 0 - True - True - - - - - - - diff --git a/libempathy-gtk/gossip-preferences.h b/libempathy-gtk/gossip-preferences.h deleted file mode 100644 index 35b26621..00000000 --- a/libempathy-gtk/gossip-preferences.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2003-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Richard Hult - * Martyn Russell - */ - -#ifndef __GOSSIP_PREFERENCES_H__ -#define __GOSSIP_PREFERENCES_H__ - -#include - -G_BEGIN_DECLS - -#define GOSSIP_PREFS_PATH "/apps/empathy" - -#define GOSSIP_PREFS_SOUNDS_FOR_MESSAGES GOSSIP_PREFS_PATH "/notifications/sounds_for_messages" -#define GOSSIP_PREFS_SOUNDS_WHEN_AWAY GOSSIP_PREFS_PATH "/notifications/sounds_when_away" -#define GOSSIP_PREFS_SOUNDS_WHEN_BUSY GOSSIP_PREFS_PATH "/notifications/sounds_when_busy" -#define GOSSIP_PREFS_POPUPS_WHEN_AVAILABLE GOSSIP_PREFS_PATH "/notifications/popups_when_available" -#define GOSSIP_PREFS_CHAT_SHOW_SMILEYS GOSSIP_PREFS_PATH "/conversation/graphical_smileys" -#define GOSSIP_PREFS_CHAT_THEME GOSSIP_PREFS_PATH "/conversation/theme" -#define GOSSIP_PREFS_CHAT_THEME_CHAT_ROOM GOSSIP_PREFS_PATH "/conversation/theme_chat_room" -#define GOSSIP_PREFS_CHAT_SPELL_CHECKER_LANGUAGES GOSSIP_PREFS_PATH "/conversation/spell_checker_languages" -#define GOSSIP_PREFS_CHAT_SPELL_CHECKER_ENABLED GOSSIP_PREFS_PATH "/conversation/spell_checker_enabled" -#define GOSSIP_PREFS_UI_SEPARATE_CHAT_WINDOWS GOSSIP_PREFS_PATH "/ui/separate_chat_windows" -#define GOSSIP_PREFS_UI_MAIN_WINDOW_HIDDEN GOSSIP_PREFS_PATH "/ui/main_window_hidden" -#define GOSSIP_PREFS_UI_AVATAR_DIRECTORY GOSSIP_PREFS_PATH "/ui/avatar_directory" -#define GOSSIP_PREFS_UI_SHOW_AVATARS GOSSIP_PREFS_PATH "/ui/show_avatars" -#define GOSSIP_PREFS_UI_COMPACT_CONTACT_LIST GOSSIP_PREFS_PATH "/ui/compact_contact_list" -#define GOSSIP_PREFS_CONTACTS_SHOW_OFFLINE GOSSIP_PREFS_PATH "/contacts/show_offline" -#define GOSSIP_PREFS_CONTACTS_SORT_CRITERIUM GOSSIP_PREFS_PATH "/contacts/sort_criterium" -#define GOSSIP_PREFS_HINTS_CLOSE_MAIN_WINDOW GOSSIP_PREFS_PATH "/hints/close_main_window" - -GtkWidget * gossip_preferences_show (GtkWindow *parent); - -G_END_DECLS - -#endif /* __GOSSIP_PREFERENCES_H__ */ - - diff --git a/libempathy-gtk/gossip-presence-chooser.c b/libempathy-gtk/gossip-presence-chooser.c deleted file mode 100644 index 74c56e7a..00000000 --- a/libempathy-gtk/gossip-presence-chooser.c +++ /dev/null @@ -1,979 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2005-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Richard Hult - * Martyn Russell - */ - -#include "config.h" - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include "gossip-ui-utils.h" -#include "empathy-images.h" -#include "gossip-presence-chooser.h" -#include "gossip-status-presets.h" - -#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_PRESENCE_CHOOSER, GossipPresenceChooserPriv)) - -#define DEBUG_DOMAIN "PresenceChooser" - -/* Flashing delay for icons (milliseconds). */ -#define FLASH_TIMEOUT 500 - -typedef struct { - EmpathyIdle *idle; - - GtkWidget *hbox; - GtkWidget *image; - GtkWidget *label; - GtkWidget *menu; - - McPresence last_state; - - McPresence flash_state_1; - McPresence flash_state_2; - guint flash_timeout_id; - - /* The handle the kind of unnessecary scroll support. */ - guint scroll_timeout_id; - McPresence scroll_state; - gchar *scroll_status; -} GossipPresenceChooserPriv; - -typedef struct { - McPresence state; - const gchar *status; -} StateAndStatus; - -/* States to be listed in the menu */ -static McPresence states[] = {MC_PRESENCE_AVAILABLE, - MC_PRESENCE_DO_NOT_DISTURB, - MC_PRESENCE_AWAY}; - -static void gossip_presence_chooser_class_init (GossipPresenceChooserClass *klass); -static void gossip_presence_chooser_init (GossipPresenceChooser *chooser); -static void presence_chooser_finalize (GObject *object); -static void presence_chooser_presence_changed_cb (GossipPresenceChooser *chooser); -static void presence_chooser_reset_scroll_timeout (GossipPresenceChooser *chooser); -static gboolean presence_chooser_scroll_timeout_cb (GossipPresenceChooser *chooser); -static gboolean presence_chooser_scroll_event_cb (GossipPresenceChooser *chooser, - GdkEventScroll *event, - gpointer user_data); -static GList * presence_chooser_get_presets (GossipPresenceChooser *chooser); -static StateAndStatus *presence_chooser_state_and_status_new (McPresence state, - const gchar *status); -static gboolean presence_chooser_flash_timeout_cb (GossipPresenceChooser *chooser); -static void presence_chooser_flash_start (GossipPresenceChooser *chooser, - McPresence state_1, - McPresence state_2); -static void presence_chooser_flash_stop (GossipPresenceChooser *chooser, - McPresence state); -static gboolean presence_chooser_button_press_event_cb (GtkWidget *chooser, - GdkEventButton *event, - gpointer user_data); -static void presence_chooser_toggled_cb (GtkWidget *chooser, - gpointer user_data); -static void presence_chooser_menu_popup (GossipPresenceChooser *chooser); -static void presence_chooser_menu_popdown (GossipPresenceChooser *chooser); -static void presence_chooser_menu_selection_done_cb (GtkMenuShell *menushell, - GossipPresenceChooser *chooser); -static void presence_chooser_menu_destroy_cb (GtkWidget *menu, - GossipPresenceChooser *chooser); -static void presence_chooser_menu_detach (GtkWidget *attach_widget, - GtkMenu *menu); -static void presence_chooser_menu_align_func (GtkMenu *menu, - gint *x, - gint *y, - gboolean *push_in, - GtkWidget *widget); -static void presence_chooser_menu_add_item (GtkWidget *menu, - const gchar *str, - McPresence state, - gboolean custom); -static void presence_chooser_clear_activate_cb (GtkWidget *item, - gpointer user_data); -static void presence_chooser_clear_response_cb (GtkWidget *widget, - gint response, - gpointer user_data); -static void presence_chooser_noncustom_activate_cb (GtkWidget *item, - gpointer user_data); -static void presence_chooser_set_state (McPresence state, - const gchar *status, - gboolean save); -static void presence_chooser_custom_activate_cb (GtkWidget *item, - gpointer user_data); -static void presence_chooser_show_dialog (McPresence state); -static void presence_chooser_dialog_response_cb (GtkWidget *dialog, - gint response, - gpointer user_data); - -G_DEFINE_TYPE (GossipPresenceChooser, gossip_presence_chooser, GTK_TYPE_TOGGLE_BUTTON); - -static void -gossip_presence_chooser_class_init (GossipPresenceChooserClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = presence_chooser_finalize; - - g_type_class_add_private (object_class, sizeof (GossipPresenceChooserPriv)); -} - -static void -gossip_presence_chooser_init (GossipPresenceChooser *chooser) -{ - GossipPresenceChooserPriv *priv; - GtkWidget *arrow; - GtkWidget *alignment; - - priv = GET_PRIV (chooser); - - gtk_button_set_relief (GTK_BUTTON (chooser), GTK_RELIEF_NONE); - gtk_button_set_focus_on_click (GTK_BUTTON (chooser), FALSE); - - alignment = gtk_alignment_new (0.5, 0.5, 1, 1); - gtk_widget_show (alignment); - gtk_container_add (GTK_CONTAINER (chooser), alignment); - gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 1, 0); - - priv->hbox = gtk_hbox_new (FALSE, 1); - gtk_widget_show (priv->hbox); - gtk_container_add (GTK_CONTAINER (alignment), priv->hbox); - - priv->image = gtk_image_new (); - gtk_widget_show (priv->image); - gtk_box_pack_start (GTK_BOX (priv->hbox), priv->image, FALSE, TRUE, 0); - - priv->label = gtk_label_new (NULL); - gtk_widget_show (priv->label); - gtk_box_pack_start (GTK_BOX (priv->hbox), priv->label, TRUE, TRUE, 0); - gtk_label_set_ellipsize (GTK_LABEL (priv->label), PANGO_ELLIPSIZE_END); - gtk_misc_set_alignment (GTK_MISC (priv->label), 0, 0.5); - gtk_misc_set_padding (GTK_MISC (priv->label), 4, 1); - - alignment = gtk_alignment_new (0.5, 0.5, 1, 1); - gtk_widget_show (alignment); - gtk_box_pack_start (GTK_BOX (priv->hbox), alignment, FALSE, FALSE, 0); - - arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT); - gtk_widget_show (arrow); - gtk_container_add (GTK_CONTAINER (alignment), arrow); - - g_signal_connect (chooser, "toggled", - G_CALLBACK (presence_chooser_toggled_cb), - NULL); - g_signal_connect (chooser, "button-press-event", - G_CALLBACK (presence_chooser_button_press_event_cb), - NULL); - g_signal_connect (chooser, "scroll-event", - G_CALLBACK (presence_chooser_scroll_event_cb), - NULL); - - priv->idle = empathy_idle_new (); - presence_chooser_presence_changed_cb (chooser); - g_signal_connect_swapped (priv->idle, "notify", - G_CALLBACK (presence_chooser_presence_changed_cb), - chooser); -} - -static void -presence_chooser_finalize (GObject *object) -{ - GossipPresenceChooserPriv *priv; - - priv = GET_PRIV (object); - - if (priv->flash_timeout_id) { - g_source_remove (priv->flash_timeout_id); - } - - if (priv->scroll_timeout_id) { - g_source_remove (priv->scroll_timeout_id); - } - - g_signal_handlers_disconnect_by_func (priv->idle, - presence_chooser_presence_changed_cb, - object); - g_object_unref (priv->idle); - - G_OBJECT_CLASS (gossip_presence_chooser_parent_class)->finalize (object); -} - -GtkWidget * -gossip_presence_chooser_new (void) -{ - GtkWidget *chooser; - - chooser = g_object_new (GOSSIP_TYPE_PRESENCE_CHOOSER, NULL); - - return chooser; -} - -static void -presence_chooser_presence_changed_cb (GossipPresenceChooser *chooser) -{ - GossipPresenceChooserPriv *priv; - McPresence state; - McPresence flash_state; - const gchar *status; - - priv = GET_PRIV (chooser); - - state = empathy_idle_get_state (priv->idle); - status = empathy_idle_get_status (priv->idle); - flash_state = empathy_idle_get_flash_state (priv->idle); - - presence_chooser_reset_scroll_timeout (chooser); - gtk_label_set_text (GTK_LABEL (priv->label), status); - - if (flash_state != MC_PRESENCE_UNSET) { - presence_chooser_flash_start (chooser, state, flash_state); - } else { - presence_chooser_flash_stop (chooser, state); - } -} - -static void -presence_chooser_reset_scroll_timeout (GossipPresenceChooser *chooser) -{ - GossipPresenceChooserPriv *priv; - - priv = GET_PRIV (chooser); - - if (priv->scroll_timeout_id) { - g_source_remove (priv->scroll_timeout_id); - priv->scroll_timeout_id = 0; - } - - g_free (priv->scroll_status); - priv->scroll_status = NULL; -} - -static gboolean -presence_chooser_scroll_timeout_cb (GossipPresenceChooser *chooser) -{ - GossipPresenceChooserPriv *priv; - - priv = GET_PRIV (chooser); - - priv->scroll_timeout_id = 0; - - empathy_idle_set_presence (priv->idle, - priv->scroll_state, - priv->scroll_status); - - g_free (priv->scroll_status); - priv->scroll_status = NULL; - - return FALSE; -} - -static gboolean -presence_chooser_scroll_event_cb (GossipPresenceChooser *chooser, - GdkEventScroll *event, - gpointer user_data) -{ - GossipPresenceChooserPriv *priv; - GList *list, *l; - const gchar *current_status; - StateAndStatus *sas; - gboolean match; - - priv = GET_PRIV (chooser); - - switch (event->direction) { - case GDK_SCROLL_UP: - break; - case GDK_SCROLL_DOWN: - break; - default: - return FALSE; - } - - current_status = gtk_label_get_text (GTK_LABEL (priv->label)); - - /* Get the list of presets, which in this context means all the items - * without a trailing "...". - */ - list = presence_chooser_get_presets (chooser); - sas = NULL; - match = FALSE; - for (l = list; l; l = l->next) { - sas = l->data; - - if (sas->state == priv->last_state && - strcmp (sas->status, current_status) == 0) { - sas = NULL; - match = TRUE; - if (event->direction == GDK_SCROLL_UP) { - if (l->prev) { - sas = l->prev->data; - } - } - else if (event->direction == GDK_SCROLL_DOWN) { - if (l->next) { - sas = l->next->data; - } - } - break; - } - - sas = NULL; - } - - if (sas) { - presence_chooser_reset_scroll_timeout (chooser); - - priv->scroll_status = g_strdup (sas->status); - priv->scroll_state = sas->state; - - priv->scroll_timeout_id = - g_timeout_add (500, - (GSourceFunc) presence_chooser_scroll_timeout_cb, - chooser); - - presence_chooser_flash_stop (chooser, sas->state); - gtk_label_set_text (GTK_LABEL (priv->label), sas->status); - } - else if (!match) { - const gchar *status; - /* If we didn't get any match at all, it means the last state - * was a custom one. Just switch to the first one. - */ - status = gossip_presence_state_get_default_status (states[0]); - - presence_chooser_reset_scroll_timeout (chooser); - empathy_idle_set_presence (priv->idle, states[0], status); - } - - g_list_foreach (list, (GFunc) g_free, NULL); - g_list_free (list); - - return TRUE; -} - -static GList * -presence_chooser_get_presets (GossipPresenceChooser *chooser) -{ - GList *list = NULL; - guint i; - - for (i = 0; i < G_N_ELEMENTS (states); i++) { - GList *presets, *p; - StateAndStatus *sas; - const gchar *status; - - status = gossip_presence_state_get_default_status (states[i]); - sas = presence_chooser_state_and_status_new (states[i], status); - list = g_list_append (list, sas); - - presets = gossip_status_presets_get (states[i], 5); - for (p = presets; p; p = p->next) { - sas = presence_chooser_state_and_status_new (states[i], p->data); - list = g_list_append (list, sas); - } - g_list_free (presets); - } - - return list; -} - -static StateAndStatus * -presence_chooser_state_and_status_new (McPresence state, - const gchar *status) -{ - StateAndStatus *sas; - - sas = g_new0 (StateAndStatus, 1); - - sas->state = state; - sas->status = status; - - return sas; -} - -static gboolean -presence_chooser_flash_timeout_cb (GossipPresenceChooser *chooser) -{ - GossipPresenceChooserPriv *priv; - McPresence state; - static gboolean on = FALSE; - - priv = GET_PRIV (chooser); - - if (on) { - state = priv->flash_state_1; - } else { - state = priv->flash_state_2; - } - - gtk_image_set_from_icon_name (GTK_IMAGE (priv->image), - gossip_icon_name_for_presence_state (state), - GTK_ICON_SIZE_MENU); - - on = !on; - - return TRUE; -} - -static void -presence_chooser_flash_start (GossipPresenceChooser *chooser, - McPresence state_1, - McPresence state_2) -{ - GossipPresenceChooserPriv *priv; - - g_return_if_fail (GOSSIP_IS_PRESENCE_CHOOSER (chooser)); - - priv = GET_PRIV (chooser); - - priv->flash_state_1 = state_1; - priv->flash_state_2 = state_2; - - if (!priv->flash_timeout_id) { - priv->flash_timeout_id = g_timeout_add (FLASH_TIMEOUT, - (GSourceFunc) presence_chooser_flash_timeout_cb, - chooser); - } -} - -static void -presence_chooser_flash_stop (GossipPresenceChooser *chooser, - McPresence state) -{ - GossipPresenceChooserPriv *priv; - - g_return_if_fail (GOSSIP_IS_PRESENCE_CHOOSER (chooser)); - - priv = GET_PRIV (chooser); - - if (priv->flash_timeout_id) { - g_source_remove (priv->flash_timeout_id); - priv->flash_timeout_id = 0; - } - - gtk_image_set_from_icon_name (GTK_IMAGE (priv->image), - gossip_icon_name_for_presence_state (state), - GTK_ICON_SIZE_MENU); - - priv->last_state = state; -} - -static gboolean -presence_chooser_button_press_event_cb (GtkWidget *chooser, - GdkEventButton *event, - gpointer user_data) -{ - if (event->button != 1 || event->type != GDK_BUTTON_PRESS) { - return FALSE; - } - - if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (chooser))) { - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (chooser), TRUE); - return TRUE; - } - - return FALSE; -} - -static void -presence_chooser_toggled_cb (GtkWidget *chooser, - gpointer user_data) -{ - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (chooser))) { - presence_chooser_menu_popup (GOSSIP_PRESENCE_CHOOSER (chooser)); - } else { - presence_chooser_menu_popdown (GOSSIP_PRESENCE_CHOOSER (chooser)); - } -} - -static void -presence_chooser_menu_popup (GossipPresenceChooser *chooser) -{ - GossipPresenceChooserPriv *priv; - GtkWidget *menu; - - priv = GET_PRIV (chooser); - - if (priv->menu) { - return; - } - - menu = gossip_presence_chooser_create_menu (); - - g_signal_connect_after (menu, "selection-done", - G_CALLBACK (presence_chooser_menu_selection_done_cb), - chooser); - - g_signal_connect (menu, "destroy", - G_CALLBACK (presence_chooser_menu_destroy_cb), - chooser); - - gtk_menu_attach_to_widget (GTK_MENU (menu), - GTK_WIDGET (chooser), - presence_chooser_menu_detach); - - gtk_menu_popup (GTK_MENU (menu), - NULL, NULL, - (GtkMenuPositionFunc) presence_chooser_menu_align_func, - chooser, - 1, - gtk_get_current_event_time ()); - - priv->menu = menu; -} - -static void -presence_chooser_menu_popdown (GossipPresenceChooser *chooser) -{ - GossipPresenceChooserPriv *priv; - - priv = GET_PRIV (chooser); - - if (priv->menu) { - gtk_widget_destroy (priv->menu); - } -} - -static void -presence_chooser_menu_selection_done_cb (GtkMenuShell *menushell, - GossipPresenceChooser *chooser) -{ - gtk_widget_destroy (GTK_WIDGET (menushell)); - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (chooser), FALSE); -} - -static void -presence_chooser_menu_destroy_cb (GtkWidget *menu, - GossipPresenceChooser *chooser) -{ - GossipPresenceChooserPriv *priv; - - priv = GET_PRIV (chooser); - - priv->menu = NULL; -} - -static void -presence_chooser_menu_detach (GtkWidget *attach_widget, - GtkMenu *menu) -{ - /* We don't need to do anything, but attaching the menu means - * we don't own the ref count and it is cleaned up properly. - */ -} - -static void -presence_chooser_menu_align_func (GtkMenu *menu, - gint *x, - gint *y, - gboolean *push_in, - GtkWidget *widget) -{ - GtkRequisition req; - GdkScreen *screen; - gint screen_height; - - gtk_widget_size_request (GTK_WIDGET (menu), &req); - - gdk_window_get_origin (widget->window, x, y); - - *x += widget->allocation.x + 1; - *y += widget->allocation.y; - - screen = gtk_widget_get_screen (GTK_WIDGET (menu)); - screen_height = gdk_screen_get_height (screen); - - if (req.height > screen_height) { - /* Too big for screen height anyway. */ - *y = 0; - return; - } - - if ((*y + req.height + widget->allocation.height) > screen_height) { - /* Can't put it below the button. */ - *y -= req.height; - *y += 1; - } else { - /* Put menu below button. */ - *y += widget->allocation.height; - *y -= 1; - } - - *push_in = FALSE; -} - -GtkWidget * -gossip_presence_chooser_create_menu (void) -{ - const gchar *status; - GtkWidget *menu; - GtkWidget *item; - GtkWidget *image; - guint i; - - menu = gtk_menu_new (); - - for (i = 0; i < G_N_ELEMENTS (states); i++) { - GList *list, *l; - - status = gossip_presence_state_get_default_status (states[i]); - presence_chooser_menu_add_item (menu, - status, - states[i], - FALSE); - - list = gossip_status_presets_get (states[i], 5); - for (l = list; l; l = l->next) { - presence_chooser_menu_add_item (menu, - l->data, - states[i], - FALSE); - } - g_list_free (list); - - presence_chooser_menu_add_item (menu, - _("Custom message..."), - states[i], - TRUE); - - /* Separator. */ - item = gtk_menu_item_new (); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - } - - /* Offline to disconnect */ - status = gossip_presence_state_get_default_status (MC_PRESENCE_OFFLINE); - presence_chooser_menu_add_item (menu, - status, - MC_PRESENCE_OFFLINE, - FALSE); - /* Separator. */ - item = gtk_menu_item_new (); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - /* Clear list */ - item = gtk_image_menu_item_new_with_label (_("Clear List...")); - image = gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (image); - gtk_widget_show (item); - - g_signal_connect (item, - "activate", - G_CALLBACK (presence_chooser_clear_activate_cb), - NULL); - - return menu; -} - -static void -presence_chooser_menu_add_item (GtkWidget *menu, - const gchar *str, - McPresence state, - gboolean custom) -{ - GtkWidget *item; - GtkWidget *image; - const gchar *icon_name; - - item = gtk_image_menu_item_new_with_label (str); - icon_name = gossip_icon_name_for_presence_state (state); - - if (custom) { - g_signal_connect (item, "activate", - G_CALLBACK (presence_chooser_custom_activate_cb), - NULL); - } else { - g_signal_connect (item, "activate", - G_CALLBACK (presence_chooser_noncustom_activate_cb), - NULL); - } - - image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); - gtk_widget_show (image); - - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); - gtk_widget_show (item); - - g_object_set_data_full (G_OBJECT (item), - "status", g_strdup (str), - (GDestroyNotify) g_free); - - g_object_set_data (G_OBJECT (item), "state", GINT_TO_POINTER (state)); - - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); -} - -static void -presence_chooser_clear_activate_cb (GtkWidget *item, - gpointer user_data) -{ - GtkWidget *dialog; - GtkWidget *toplevel; - GtkWindow *parent = NULL; - - toplevel = gtk_widget_get_toplevel (item); - if (GTK_WIDGET_TOPLEVEL (toplevel) && - GTK_IS_WINDOW (toplevel)) { - GtkWindow *window; - gboolean visible; - - window = GTK_WINDOW (toplevel); - visible = gossip_window_get_is_visible (window); - - if (visible) { - parent = window; - } - } - - dialog = gtk_message_dialog_new (GTK_WINDOW (parent), - 0, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_NONE, - _("Are you sure you want to clear the list?")); - - gtk_message_dialog_format_secondary_text ( - GTK_MESSAGE_DIALOG (dialog), - _("This will remove any custom messages you have " - "added to the list of preset status messages.")); - - gtk_dialog_add_buttons (GTK_DIALOG (dialog), - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - _("Clear List"), GTK_RESPONSE_OK, - NULL); - - gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), FALSE); - - g_signal_connect (dialog, "response", - G_CALLBACK (presence_chooser_clear_response_cb), - NULL); - - gtk_widget_show (dialog); -} - -static void -presence_chooser_clear_response_cb (GtkWidget *widget, - gint response, - gpointer user_data) -{ - if (response == GTK_RESPONSE_OK) { - gossip_status_presets_reset (); - } - - gtk_widget_destroy (widget); -} - -static void -presence_chooser_noncustom_activate_cb (GtkWidget *item, - gpointer user_data) -{ - McPresence state; - const gchar *status; - - status = g_object_get_data (G_OBJECT (item), "status"); - state = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "state")); - - presence_chooser_set_state (state, status, FALSE); -} - -static void -presence_chooser_set_state (McPresence state, - const gchar *status, - gboolean save) -{ - EmpathyIdle *idle; - - if (!G_STR_EMPTY (status)) { - const gchar *default_status; - - /* Only store the value if it differs from the default ones. */ - default_status = gossip_presence_state_get_default_status (state); - if (save && strcmp (status, default_status) != 0) { - gossip_status_presets_set_last (state, status); - } - } - - idle = empathy_idle_new (); - empathy_idle_set_presence (idle, state, status); - g_object_unref (idle); -} - -static void -presence_chooser_custom_activate_cb (GtkWidget *item, - gpointer user_data) -{ - McPresence state; - - state = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "state")); - - presence_chooser_show_dialog (state); -} - -static void -presence_chooser_show_dialog (McPresence state) -{ - static GtkWidget *dialog = NULL; - static GtkListStore *store[LAST_MC_PRESENCE]; - GladeXML *glade; - GtkWidget *image; - GtkWidget *combo; - GtkWidget *entry; - GtkWidget *checkbutton; - const gchar *default_status; - - if (dialog) { - gtk_widget_destroy (dialog); - dialog = NULL; - } else { - guint i; - - for (i = 0; i < LAST_MC_PRESENCE; i++) { - store[i] = NULL; - } - } - - glade = gossip_glade_get_file ("gossip-presence-chooser.glade", - "status_message_dialog", - NULL, - "status_message_dialog", &dialog, - "comboentry_status", &combo, - "image_status", &image, - "checkbutton_add", &checkbutton, - NULL); - - g_object_unref (glade); - - g_signal_connect (dialog, "destroy", - G_CALLBACK (gtk_widget_destroyed), - &dialog); - g_signal_connect (dialog, "response", - G_CALLBACK (presence_chooser_dialog_response_cb), - NULL); - - gtk_image_set_from_icon_name (GTK_IMAGE (image), - gossip_icon_name_for_presence_state (state), - GTK_ICON_SIZE_MENU); - - if (!store[state]) { - GList *presets, *l; - GtkTreeIter iter; - - store[state] = gtk_list_store_new (1, G_TYPE_STRING); - - presets = gossip_status_presets_get (state, -1); - for (l = presets; l; l = l->next) { - gtk_list_store_append (store[state], &iter); - gtk_list_store_set (store[state], &iter, 0, l->data, -1); - } - - g_list_free (presets); - } - - default_status = gossip_presence_state_get_default_status (state); - - entry = GTK_BIN (combo)->child; - gtk_entry_set_text (GTK_ENTRY (entry), default_status); - gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); - gtk_entry_set_width_chars (GTK_ENTRY (entry), 25); - - gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (store[state])); - gtk_combo_box_entry_set_text_column (GTK_COMBO_BOX_ENTRY (combo), 0); - - /* FIXME: Set transian for a window ? */ - - g_object_set_data (G_OBJECT (dialog), "store", store[state]); - g_object_set_data (G_OBJECT (dialog), "entry", entry); - g_object_set_data (G_OBJECT (dialog), "checkbutton", checkbutton); - g_object_set_data (G_OBJECT (dialog), "state", GINT_TO_POINTER (state)); - - gtk_widget_show_all (dialog); -} - -static void -presence_chooser_dialog_response_cb (GtkWidget *dialog, - gint response, - gpointer user_data) -{ - if (response == GTK_RESPONSE_OK) { - GtkWidget *entry; - GtkWidget *checkbutton; - GtkListStore *store; - GtkTreeModel *model; - GtkTreeIter iter; - McPresence state; - const gchar *status; - gboolean save; - gboolean duplicate = FALSE; - gboolean has_next; - - entry = g_object_get_data (G_OBJECT (dialog), "entry"); - status = gtk_entry_get_text (GTK_ENTRY (entry)); - store = g_object_get_data (G_OBJECT (dialog), "store"); - model = GTK_TREE_MODEL (store); - - has_next = gtk_tree_model_get_iter_first (model, &iter); - while (has_next) { - gchar *str; - - gtk_tree_model_get (model, &iter, - 0, &str, - -1); - - if (strcmp (status, str) == 0) { - g_free (str); - duplicate = TRUE; - break; - } - - g_free (str); - - has_next = gtk_tree_model_iter_next (model, &iter); - } - - if (!duplicate) { - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, 0, status, -1); - } - - checkbutton = g_object_get_data (G_OBJECT (dialog), "checkbutton"); - save = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton)); - state = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), "state")); - - presence_chooser_set_state (state, status, save); - } - - gtk_widget_destroy (dialog); -} - diff --git a/libempathy-gtk/gossip-presence-chooser.glade b/libempathy-gtk/gossip-presence-chooser.glade deleted file mode 100644 index f9f1d4eb..00000000 --- a/libempathy-gtk/gossip-presence-chooser.glade +++ /dev/null @@ -1,173 +0,0 @@ - - - - - - - - 5 - Status Message Presets - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - False - False - False - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - False - False - - - - True - False - 2 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - -6 - - - - - - True - True - True - True - gtk-ok - True - GTK_RELIEF_NORMAL - True - -5 - - - - - 0 - False - True - GTK_PACK_END - - - - - - 5 - True - False - 6 - - - - True - False - 6 - - - - True - 0.5 - 0.5 - 0 - 0 - - - 0 - False - True - - - - - - True - Enter status message: - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - True - True - - - - - 0 - False - False - - - - - - True - False - True - True - - - 0 - False - False - - - - - - True - True - _Add to status message list - True - GTK_RELIEF_NORMAL - True - False - False - True - - - 0 - False - False - - - - - 0 - True - True - - - - - - - diff --git a/libempathy-gtk/gossip-presence-chooser.h b/libempathy-gtk/gossip-presence-chooser.h deleted file mode 100644 index 7175126e..00000000 --- a/libempathy-gtk/gossip-presence-chooser.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2005-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Richard Hult - * Martyn Russell - */ - -#ifndef __GOSSIP_PRESENCE_CHOOSER_H__ -#define __GOSSIP_PRESENCE_CHOOSER_H__ - -#include - -#include - -G_BEGIN_DECLS - -#define GOSSIP_TYPE_PRESENCE_CHOOSER (gossip_presence_chooser_get_type ()) -#define GOSSIP_PRESENCE_CHOOSER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOSSIP_TYPE_PRESENCE_CHOOSER, GossipPresenceChooser)) -#define GOSSIP_PRESENCE_CHOOSER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GOSSIP_TYPE_PRESENCE_CHOOSER, GossipPresenceChooserClass)) -#define GOSSIP_IS_PRESENCE_CHOOSER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOSSIP_TYPE_PRESENCE_CHOOSER)) -#define GOSSIP_IS_PRESENCE_CHOOSER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOSSIP_TYPE_PRESENCE_CHOOSER)) -#define GOSSIP_PRESENCE_CHOOSER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOSSIP_TYPE_PRESENCE_CHOOSER, GossipPresenceChooserClass)) - -typedef struct _GossipPresenceChooser GossipPresenceChooser; -typedef struct _GossipPresenceChooserClass GossipPresenceChooserClass; - -struct _GossipPresenceChooser { - GtkToggleButton parent; -}; - -struct _GossipPresenceChooserClass { - GtkToggleButtonClass parent_class; -}; - -GType gossip_presence_chooser_get_type (void) G_GNUC_CONST; -GtkWidget *gossip_presence_chooser_new (void); -GtkWidget *gossip_presence_chooser_create_menu (void); - -G_END_DECLS - -#endif /* __GOSSIP_PRESENCE_CHOOSER_H__ */ - diff --git a/libempathy-gtk/gossip-private-chat.c b/libempathy-gtk/gossip-private-chat.c deleted file mode 100644 index a7ef8fb0..00000000 --- a/libempathy-gtk/gossip-private-chat.c +++ /dev/null @@ -1,374 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2002-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Richard Hult - * Martyn Russell - * Geert-Jan Van den Bogaerde - * Xavier Claessens - */ - -#include "config.h" - -#include - -#include -#include -#include - -#include -#include -#include -#include -//#include - -#include "gossip-private-chat.h" -#include "gossip-chat-view.h" -#include "gossip-chat.h" -#include "gossip-preferences.h" -//#include "gossip-sound.h" -#include "empathy-images.h" -#include "gossip-ui-utils.h" - -#define DEBUG_DOMAIN "PrivateChat" - -#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_PRIVATE_CHAT, GossipPrivateChatPriv)) - -struct _GossipPrivateChatPriv { - GossipContact *contact; - gchar *name; - - gboolean is_online; - - GtkWidget *widget; - GtkWidget *text_view_sw; -}; - -static void gossip_private_chat_class_init (GossipPrivateChatClass *klass); -static void gossip_private_chat_init (GossipPrivateChat *chat); -static void private_chat_finalize (GObject *object); -static void private_chat_create_ui (GossipPrivateChat *chat); -static void private_chat_contact_presence_updated_cb (GossipContact *contact, - GParamSpec *param, - GossipPrivateChat *chat); -static void private_chat_contact_updated_cb (GossipContact *contact, - GParamSpec *param, - GossipPrivateChat *chat); -static void private_chat_widget_destroy_cb (GtkWidget *widget, - GossipPrivateChat *chat); -static const gchar * private_chat_get_name (GossipChat *chat); -static gchar * private_chat_get_tooltip (GossipChat *chat); -static const gchar * private_chat_get_status_icon_name (GossipChat *chat); -static GtkWidget * private_chat_get_widget (GossipChat *chat); - -G_DEFINE_TYPE (GossipPrivateChat, gossip_private_chat, GOSSIP_TYPE_CHAT); - -static void -gossip_private_chat_class_init (GossipPrivateChatClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GossipChatClass *chat_class = GOSSIP_CHAT_CLASS (klass); - - object_class->finalize = private_chat_finalize; - - chat_class->get_name = private_chat_get_name; - chat_class->get_tooltip = private_chat_get_tooltip; - chat_class->get_status_icon_name = private_chat_get_status_icon_name; - chat_class->get_widget = private_chat_get_widget; - chat_class->set_tp_chat = NULL; - - g_type_class_add_private (object_class, sizeof (GossipPrivateChatPriv)); -} - -static void -gossip_private_chat_init (GossipPrivateChat *chat) -{ - GossipPrivateChatPriv *priv; - - priv = GET_PRIV (chat); - - priv->is_online = FALSE; - - private_chat_create_ui (chat); -} - -static void -private_chat_finalize (GObject *object) -{ - GossipPrivateChat *chat; - GossipPrivateChatPriv *priv; - - chat = GOSSIP_PRIVATE_CHAT (object); - priv = GET_PRIV (chat); - - g_signal_handlers_disconnect_by_func (priv->contact, - private_chat_contact_updated_cb, - chat); - g_signal_handlers_disconnect_by_func (priv->contact, - private_chat_contact_presence_updated_cb, - chat); - - if (priv->contact) { - g_object_unref (priv->contact); - } - - g_free (priv->name); - - G_OBJECT_CLASS (gossip_private_chat_parent_class)->finalize (object); -} - -static void -private_chat_create_ui (GossipPrivateChat *chat) -{ - GladeXML *glade; - GossipPrivateChatPriv *priv; - GtkWidget *input_text_view_sw; - - priv = GET_PRIV (chat); - - glade = gossip_glade_get_file ("gossip-chat.glade", - "chat_widget", - NULL, - "chat_widget", &priv->widget, - "chat_view_sw", &priv->text_view_sw, - "input_text_view_sw", &input_text_view_sw, - NULL); - - gossip_glade_connect (glade, - chat, - "chat_widget", "destroy", private_chat_widget_destroy_cb, - NULL); - - g_object_unref (glade); - - g_object_set_data (G_OBJECT (priv->widget), "chat", g_object_ref (chat)); - - gtk_container_add (GTK_CONTAINER (priv->text_view_sw), - GTK_WIDGET (GOSSIP_CHAT (chat)->view)); - gtk_widget_show (GTK_WIDGET (GOSSIP_CHAT (chat)->view)); - - gtk_container_add (GTK_CONTAINER (input_text_view_sw), - GOSSIP_CHAT (chat)->input_text_view); - gtk_widget_show (GOSSIP_CHAT (chat)->input_text_view); -} - -static void -private_chat_contact_presence_updated_cb (GossipContact *contact, - GParamSpec *param, - GossipPrivateChat *chat) -{ - GossipPrivateChatPriv *priv; - - priv = GET_PRIV (chat); - - gossip_debug (DEBUG_DOMAIN, "Presence update for contact: %s", - gossip_contact_get_id (contact)); - - if (!gossip_contact_is_online (contact)) { - if (priv->is_online) { - gchar *msg; - - msg = g_strdup_printf (_("%s went offline"), - gossip_contact_get_name (priv->contact)); - gossip_chat_view_append_event (GOSSIP_CHAT (chat)->view, msg); - g_free (msg); - } - - priv->is_online = FALSE; - - g_signal_emit_by_name (chat, "composing", FALSE); - - } else { - if (!priv->is_online) { - gchar *msg; - - msg = g_strdup_printf (_("%s has come online"), - gossip_contact_get_name (priv->contact)); - gossip_chat_view_append_event (GOSSIP_CHAT (chat)->view, msg); - g_free (msg); - } - - priv->is_online = TRUE; - } - - g_signal_emit_by_name (chat, "status-changed"); -} - -static void -private_chat_contact_updated_cb (GossipContact *contact, - GParamSpec *param, - GossipPrivateChat *chat) -{ - GossipPrivateChatPriv *priv; - - priv = GET_PRIV (chat); - - if (strcmp (priv->name, gossip_contact_get_name (contact)) != 0) { - g_free (priv->name); - priv->name = g_strdup (gossip_contact_get_name (contact)); - g_signal_emit_by_name (chat, "name-changed", priv->name); - } -} - -static void -private_chat_widget_destroy_cb (GtkWidget *widget, - GossipPrivateChat *chat) -{ - gossip_debug (DEBUG_DOMAIN, "Destroyed"); - - g_object_unref (chat); -} - -static const gchar * -private_chat_get_name (GossipChat *chat) -{ - GossipPrivateChatPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_PRIVATE_CHAT (chat), NULL); - - priv = GET_PRIV (chat); - - return priv->name; -} - -static gchar * -private_chat_get_tooltip (GossipChat *chat) -{ - GossipPrivateChatPriv *priv; - const gchar *status; - - g_return_val_if_fail (GOSSIP_IS_PRIVATE_CHAT (chat), NULL); - - priv = GET_PRIV (chat); - - status = gossip_contact_get_status (priv->contact); - - return g_strdup_printf ("%s\n%s", - gossip_contact_get_id (priv->contact), - status); -} - -static const gchar * -private_chat_get_status_icon_name (GossipChat *chat) -{ - GossipPrivateChatPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_PRIVATE_CHAT (chat), NULL); - - priv = GET_PRIV (chat); - - return gossip_icon_name_for_contact (priv->contact); -} - -GossipContact * -gossip_private_chat_get_contact (GossipPrivateChat *chat) -{ - GossipPrivateChatPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_PRIVATE_CHAT (chat), NULL); - - priv = GET_PRIV (chat); - - return priv->contact; -} - -static GtkWidget * -private_chat_get_widget (GossipChat *chat) -{ - GossipPrivateChatPriv *priv; - - priv = GET_PRIV (chat); - - return priv->widget; -} - -static void -private_chat_setup (GossipPrivateChat *chat, - GossipContact *contact, - EmpathyTpChat *tp_chat) -{ - GossipPrivateChatPriv *priv; - - priv = GET_PRIV (chat); - - GOSSIP_CHAT (chat)->account = g_object_ref (gossip_contact_get_account (contact)); - priv->contact = g_object_ref (contact); - priv->name = g_strdup (gossip_contact_get_name (contact)); - - gossip_chat_set_tp_chat (GOSSIP_CHAT (chat), tp_chat); - - g_signal_connect (priv->contact, - "notify::name", - G_CALLBACK (private_chat_contact_updated_cb), - chat); - g_signal_connect (priv->contact, - "notify::presence", - G_CALLBACK (private_chat_contact_presence_updated_cb), - chat); - - priv->is_online = gossip_contact_is_online (priv->contact); -} - -GossipPrivateChat * -gossip_private_chat_new (McAccount *account, - TpChan *tp_chan) -{ - GossipPrivateChat *chat; - EmpathyTpChat *tp_chat; - EmpathyContactManager *manager; - EmpathyTpContactList *list; - GossipContact *contact; - - g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); - g_return_val_if_fail (TELEPATHY_IS_CHAN (tp_chan), NULL); - - manager = empathy_contact_manager_new (); - list = empathy_contact_manager_get_list (manager, account); - contact = empathy_tp_contact_list_get_from_handle (list, tp_chan->handle); - - chat = g_object_new (GOSSIP_TYPE_PRIVATE_CHAT, NULL); - tp_chat = empathy_tp_chat_new (account, tp_chan); - - private_chat_setup (chat, contact, tp_chat); - - g_object_unref (tp_chat); - g_object_unref (contact); - g_object_unref (manager); - - return chat; -} - -GossipPrivateChat * -gossip_private_chat_new_with_contact (GossipContact *contact) -{ - GossipPrivateChat *chat; - EmpathyTpChat *tp_chat; - - g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL); - - chat = g_object_new (GOSSIP_TYPE_PRIVATE_CHAT, NULL); - tp_chat = empathy_tp_chat_new_with_contact (contact); - - private_chat_setup (chat, contact, tp_chat); - g_object_unref (tp_chat); - - return chat; -} - diff --git a/libempathy-gtk/gossip-private-chat.h b/libempathy-gtk/gossip-private-chat.h deleted file mode 100644 index 326d0f60..00000000 --- a/libempathy-gtk/gossip-private-chat.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2002-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Richard Hult - * Martyn Russell - * Geert-Jan Van den Bogaerde - * Xavier Claessens - */ - -#ifndef __GOSSIP_PRIVATE_CHAT_H__ -#define __GOSSIP_PRIVATE_CHAT_H__ - -#include - -#include - -#include - -G_BEGIN_DECLS - -#define GOSSIP_TYPE_PRIVATE_CHAT (gossip_private_chat_get_type ()) -#define GOSSIP_PRIVATE_CHAT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOSSIP_TYPE_PRIVATE_CHAT, GossipPrivateChat)) -#define GOSSIP_PRIVATE_CHAT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GOSSIP_TYPE_PRIVATE_CHAT, GossipPrivateChatClass)) -#define GOSSIP_IS_PRIVATE_CHAT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOSSIP_TYPE_PRIVATE_CHAT)) -#define GOSSIP_IS_PRIVATE_CHAT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOSSIP_TYPE_PRIVATE_CHAT)) -#define GOSSIP_PRIVATE_CHAT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOSSIP_TYPE_PRIVATE_CHAT, GossipPrivateChatClass)) - -typedef struct _GossipPrivateChat GossipPrivateChat; -typedef struct _GossipPrivateChatClass GossipPrivateChatClass; -typedef struct _GossipPrivateChatPriv GossipPrivateChatPriv; - -#include "gossip-chat.h" - -struct _GossipPrivateChat { - GossipChat parent; -}; - -struct _GossipPrivateChatClass { - GossipChatClass parent; -}; - -GType gossip_private_chat_get_type (void); -GossipPrivateChat * gossip_private_chat_new (McAccount *account, - TpChan *tp_chan); -GossipPrivateChat * gossip_private_chat_new_with_contact (GossipContact *contact); -GossipContact * gossip_private_chat_get_contact (GossipPrivateChat *chat); - -G_END_DECLS - -#endif /* __GOSSIP_PRIVATE_CHAT_H__ */ diff --git a/libempathy-gtk/gossip-profile-chooser.c b/libempathy-gtk/gossip-profile-chooser.c deleted file mode 100644 index b5500289..00000000 --- a/libempathy-gtk/gossip-profile-chooser.c +++ /dev/null @@ -1,106 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Xavier Claessens - */ - -#include - -#include -#include - -#include - -#include "gossip-profile-chooser.h" - -enum { - COL_ICON, - COL_LABEL, - COL_PROFILE, - COL_COUNT -}; - -McProfile* -gossip_profile_chooser_get_selected (GtkWidget *widget) -{ - GtkTreeModel *model; - GtkTreeIter iter; - McProfile *profile = NULL; - - model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget)); - if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter)) { - gtk_tree_model_get (model, &iter, - COL_PROFILE, &profile, - -1); - } - - return profile; -} - -GtkWidget * -gossip_profile_chooser_new (void) -{ - GList *profiles, *l; - GtkListStore *store; - GtkCellRenderer *renderer; - GtkWidget *combo_box; - GtkTreeIter iter; - - /* set up combo box with new store */ - store = gtk_list_store_new (COL_COUNT, - G_TYPE_STRING, /* Icon name */ - G_TYPE_STRING, /* Label */ - MC_TYPE_PROFILE); /* Profile */ - combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store)); - - - renderer = gtk_cell_renderer_pixbuf_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, FALSE); - gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer, - "icon-name", COL_ICON, - NULL); - g_object_set (renderer, "stock-size", GTK_ICON_SIZE_BUTTON, NULL); - - renderer = gtk_cell_renderer_text_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE); - gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer, - "text", COL_LABEL, - NULL); - - profiles = mc_profiles_list (); - for (l = profiles; l; l = l->next) { - McProfile *profile; - - profile = l->data; - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - COL_ICON, mc_profile_get_icon_name (profile), - COL_LABEL, mc_profile_get_display_name (profile), - COL_PROFILE, profile, - -1); - gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter); - } - - mc_profiles_free_list (profiles); - g_object_unref (store); - - return combo_box; -} - diff --git a/libempathy-gtk/gossip-profile-chooser.h b/libempathy-gtk/gossip-profile-chooser.h deleted file mode 100644 index a563109a..00000000 --- a/libempathy-gtk/gossip-profile-chooser.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Xavier Claessens - */ - -#ifndef __GOSSIP_PROTOCOL_CHOOSER_H__ -#define __GOSSIP_PROTOCOL_CHOOSER_H__ - -#include - -G_BEGIN_DECLS - -GtkWidget * gossip_profile_chooser_new (void); -McProfile * gossip_profile_chooser_get_selected (GtkWidget *widget); - -G_END_DECLS -#endif /* __GOSSIP_PROTOCOL_CHOOSER_H__ */ diff --git a/libempathy-gtk/gossip-spell-dialog.c b/libempathy-gtk/gossip-spell-dialog.c deleted file mode 100644 index b34a8860..00000000 --- a/libempathy-gtk/gossip-spell-dialog.c +++ /dev/null @@ -1,267 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2004-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "config.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gossip-chat.h" -#include "gossip-spell-dialog.h" -#include "gossip-ui-utils.h" - -typedef struct { - GtkWidget *window; - GtkWidget *button_replace; - GtkWidget *label_word; - GtkWidget *treeview_words; - - GossipChat *chat; - - gchar *word; - GtkTextIter start; - GtkTextIter end; -} GossipSpellDialog; - -enum { - COL_SPELL_WORD, - COL_SPELL_COUNT -}; - -static void spell_dialog_model_populate_columns (GossipSpellDialog *dialog); -static void spell_dialog_model_populate_suggestions (GossipSpellDialog *dialog); -static void spell_dialog_model_row_activated_cb (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - GossipSpellDialog *dialog); -static void spell_dialog_model_selection_changed_cb (GtkTreeSelection *treeselection, - GossipSpellDialog *dialog); -static void spell_dialog_model_setup (GossipSpellDialog *dialog); -static void spell_dialog_response_cb (GtkWidget *widget, - gint response, - GossipSpellDialog *dialog); -static void spell_dialog_destroy_cb (GtkWidget *widget, - GossipSpellDialog *dialog); - -static void -spell_dialog_model_populate_columns (GossipSpellDialog *dialog) -{ - GtkTreeModel *model; - GtkTreeViewColumn *column; - GtkCellRenderer *renderer; - guint col_offset; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview_words)); - - renderer = gtk_cell_renderer_text_new (); - col_offset = gtk_tree_view_insert_column_with_attributes ( - GTK_TREE_VIEW (dialog->treeview_words), - -1, _("Word"), - renderer, - "text", COL_SPELL_WORD, - NULL); - - g_object_set_data (G_OBJECT (renderer), - "column", GINT_TO_POINTER (COL_SPELL_WORD)); - - column = gtk_tree_view_get_column (GTK_TREE_VIEW (dialog->treeview_words), col_offset - 1); - gtk_tree_view_column_set_sort_column_id (column, COL_SPELL_WORD); - gtk_tree_view_column_set_resizable (column, FALSE); - gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); -} - -static void -spell_dialog_model_populate_suggestions (GossipSpellDialog *dialog) -{ - GtkTreeModel *model; - GtkListStore *store; - GList *suggestions, *l; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview_words)); - store = GTK_LIST_STORE (model); - - suggestions = gossip_spell_get_suggestions (dialog->word); - for (l = suggestions; l; l=l->next) { - GtkTreeIter iter; - gchar *word; - - word = l->data; - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - COL_SPELL_WORD, word, - -1); - } - - gossip_spell_free_suggestions (suggestions); -} - -static void -spell_dialog_model_row_activated_cb (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - GossipSpellDialog *dialog) -{ - spell_dialog_response_cb (dialog->window, GTK_RESPONSE_OK, dialog); -} - -static void -spell_dialog_model_selection_changed_cb (GtkTreeSelection *treeselection, - GossipSpellDialog *dialog) -{ - gint count; - - count = gtk_tree_selection_count_selected_rows (treeselection); - gtk_widget_set_sensitive (dialog->button_replace, (count == 1)); -} - -static void -spell_dialog_model_setup (GossipSpellDialog *dialog) -{ - GtkTreeView *view; - GtkListStore *store; - GtkTreeSelection *selection; - - view = GTK_TREE_VIEW (dialog->treeview_words); - - g_signal_connect (view, "row-activated", - G_CALLBACK (spell_dialog_model_row_activated_cb), - dialog); - - store = gtk_list_store_new (COL_SPELL_COUNT, - G_TYPE_STRING); /* word */ - - gtk_tree_view_set_model (view, GTK_TREE_MODEL (store)); - - selection = gtk_tree_view_get_selection (view); - gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); - - g_signal_connect (selection, "changed", - G_CALLBACK (spell_dialog_model_selection_changed_cb), - dialog); - - spell_dialog_model_populate_columns (dialog); - spell_dialog_model_populate_suggestions (dialog); - - g_object_unref (store); -} - -static void -spell_dialog_destroy_cb (GtkWidget *widget, - GossipSpellDialog *dialog) -{ - g_object_unref (dialog->chat); - g_free (dialog->word); - - g_free (dialog); -} - -static void -spell_dialog_response_cb (GtkWidget *widget, - gint response, - GossipSpellDialog *dialog) -{ - if (response == GTK_RESPONSE_OK) { - GtkTreeView *view; - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - - gchar *new_word; - - view = GTK_TREE_VIEW (dialog->treeview_words); - selection = gtk_tree_view_get_selection (view); - - if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { - return; - } - - gtk_tree_model_get (model, &iter, COL_SPELL_WORD, &new_word, -1); - - gossip_chat_correct_word (dialog->chat, - dialog->start, - dialog->end, - new_word); - - g_free (new_word); - } - - gtk_widget_destroy (dialog->window); -} - -void -gossip_spell_dialog_show (GossipChat *chat, - GtkTextIter start, - GtkTextIter end, - const gchar *word) -{ - GossipSpellDialog *dialog; - GladeXML *gui; - gchar *str; - - g_return_if_fail (chat != NULL); - g_return_if_fail (word != NULL); - - dialog = g_new0 (GossipSpellDialog, 1); - - dialog->chat = g_object_ref (chat); - - dialog->word = g_strdup (word); - - dialog->start = start; - dialog->end = end; - - gui = gossip_glade_get_file ("gossip-spell-dialog.glade", - "spell_dialog", - NULL, - "spell_dialog", &dialog->window, - "button_replace", &dialog->button_replace, - "label_word", &dialog->label_word, - "treeview_words", &dialog->treeview_words, - NULL); - - gossip_glade_connect (gui, - dialog, - "spell_dialog", "response", spell_dialog_response_cb, - "spell_dialog", "destroy", spell_dialog_destroy_cb, - NULL); - - g_object_unref (gui); - - str = g_strdup_printf ("%s:\n%s", - _("Suggestions for the word"), - word); - - gtk_label_set_markup (GTK_LABEL (dialog->label_word), str); - g_free (str); - - spell_dialog_model_setup (dialog); - - gtk_widget_show (dialog->window); -} diff --git a/libempathy-gtk/gossip-spell-dialog.glade b/libempathy-gtk/gossip-spell-dialog.glade deleted file mode 100644 index 502fb0d1..00000000 --- a/libempathy-gtk/gossip-spell-dialog.glade +++ /dev/null @@ -1,205 +0,0 @@ - - - - - - - 5 - Spell Checker - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - True - 275 - 225 - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - False - False - - - - True - False - 2 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - -6 - - - - - - True - False - True - True - GTK_RELIEF_NORMAL - True - -5 - - - - True - 0.5 - 0.5 - 0 - 0 - 0 - 0 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-convert - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - _Replace - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - - - - - - 0 - False - True - GTK_PACK_END - - - - - - 5 - True - False - 6 - - - - True - Suggestions for the word: - False - True - GTK_JUSTIFY_LEFT - True - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - True - True - False - False - False - True - False - False - False - - - - - 0 - True - True - - - - - 0 - True - True - - - - - - - diff --git a/libempathy-gtk/gossip-spell-dialog.h b/libempathy-gtk/gossip-spell-dialog.h deleted file mode 100644 index 2f71033f..00000000 --- a/libempathy-gtk/gossip-spell-dialog.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2004-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Martyn Russell - * Richard Hult - */ - -#ifndef __GOSSIP_SPELL_DIALOG_H__ -#define __GOSSIP_SPELL_DIALOG_H__ - -#include -#include "gossip-chat.h" - -G_BEGIN_DECLS - -void gossip_spell_dialog_show (GossipChat *chat, - GtkTextIter start, - GtkTextIter end, - const gchar *word); - -G_END_DECLS - -#endif /* __GOSSIP_SPELL_DIALOG_H__ */ diff --git a/libempathy-gtk/gossip-spell.c b/libempathy-gtk/gossip-spell.c deleted file mode 100644 index 8d595f4c..00000000 --- a/libempathy-gtk/gossip-spell.c +++ /dev/null @@ -1,452 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2004-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Martyn Russell - * Richard Hult - */ - -#include "config.h" - -#include -#include - -#include - -#ifdef HAVE_ASPELL -#include -#endif - -#include -#include - -#include "gossip-spell.h" -#include "gossip-preferences.h" - -#define DEBUG_DOMAIN "Spell" - -#ifdef HAVE_ASPELL - -/* Note: We could use aspell_reset_cache (NULL); periodically if we wanted - * to... - */ - -typedef struct { - AspellConfig *spell_config; - AspellCanHaveError *spell_possible_err; - AspellSpeller *spell_checker; -} SpellLanguage; - -#define ISO_CODES_DATADIR ISO_CODES_PREFIX "/share/xml/iso-codes" -#define ISO_CODES_LOCALESDIR ISO_CODES_PREFIX "/share/locale" - -static GHashTable *iso_code_names = NULL; -static GList *languages = NULL; -static gboolean gossip_conf_notify_inited = FALSE; - -static void -spell_iso_codes_parse_start_tag (GMarkupParseContext *ctx, - const gchar *element_name, - const gchar **attr_names, - const gchar **attr_values, - gpointer data, - GError **error) -{ - const gchar *ccode_longB, *ccode_longT, *ccode; - const gchar *lang_name; - - if (!g_str_equal (element_name, "iso_639_entry") || - attr_names == NULL || attr_values == NULL) { - return; - } - - ccode = NULL; - ccode_longB = NULL; - ccode_longT = NULL; - lang_name = NULL; - - while (*attr_names && *attr_values) { - if (g_str_equal (*attr_names, "iso_639_1_code")) { - if (**attr_values) { - ccode = *attr_values; - } - } - else if (g_str_equal (*attr_names, "iso_639_2B_code")) { - if (**attr_values) { - ccode_longB = *attr_values; - } - } - else if (g_str_equal (*attr_names, "iso_639_2T_code")) { - if (**attr_values) { - ccode_longT = *attr_values; - } - } - else if (g_str_equal (*attr_names, "name")) { - lang_name = *attr_values; - } - - attr_names++; - attr_values++; - } - - if (!lang_name) { - return; - } - - if (ccode) { - g_hash_table_insert (iso_code_names, - g_strdup (ccode), - g_strdup (lang_name)); - } - - if (ccode_longB) { - g_hash_table_insert (iso_code_names, - g_strdup (ccode_longB), - g_strdup (lang_name)); - } - - if (ccode_longT) { - g_hash_table_insert (iso_code_names, - g_strdup (ccode_longT), - g_strdup (lang_name)); - } -} - -static void -spell_iso_code_names_init (void) -{ - GError *err = NULL; - gchar *buf; - gsize buf_len; - - iso_code_names = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_free); - - bindtextdomain ("iso_639", ISO_CODES_LOCALESDIR); - bind_textdomain_codeset ("iso_639", "UTF-8"); - - /* FIXME: We should read this in chunks and pass to the parser. */ - if (g_file_get_contents (ISO_CODES_DATADIR "/iso_639.xml", &buf, &buf_len, &err)) { - GMarkupParseContext *ctx; - GMarkupParser parser = { - spell_iso_codes_parse_start_tag, - NULL, NULL, NULL, NULL - }; - - ctx = g_markup_parse_context_new (&parser, 0, NULL, NULL); - if (!g_markup_parse_context_parse (ctx, buf, buf_len, &err)) { - g_warning ("Failed to parse '%s': %s", - ISO_CODES_DATADIR"/iso_639.xml", - err->message); - g_error_free (err); - } - - g_markup_parse_context_free (ctx); - g_free (buf); - } else { - g_warning ("Failed to load '%s': %s", - ISO_CODES_DATADIR"/iso_639.xml", err->message); - g_error_free (err); - } -} - -static void -spell_notify_languages_cb (GossipConf *conf, - const gchar *key, - gpointer user_data) -{ - GList *l; - - gossip_debug (DEBUG_DOMAIN, "Resetting languages due to config change"); - - /* We just reset the languages list. */ - for (l = languages; l; l = l->next) { - SpellLanguage *lang; - - lang = l->data; - - delete_aspell_config (lang->spell_config); - delete_aspell_speller (lang->spell_checker); - - g_slice_free (SpellLanguage, lang); - } - - g_list_free (languages); - languages = NULL; -} - -static void -spell_setup_languages (void) -{ - gchar *str; - - if (!gossip_conf_notify_inited) { - gossip_conf_notify_add (gossip_conf_get (), - GOSSIP_PREFS_CHAT_SPELL_CHECKER_LANGUAGES, - spell_notify_languages_cb, NULL); - - gossip_conf_notify_inited = TRUE; - } - - if (languages) { - return; - } - - if (gossip_conf_get_string (gossip_conf_get (), - GOSSIP_PREFS_CHAT_SPELL_CHECKER_LANGUAGES, - &str) && str) { - gchar **strv; - gint i; - - strv = g_strsplit (str, ",", -1); - - i = 0; - while (strv && strv[i]) { - SpellLanguage *lang; - - gossip_debug (DEBUG_DOMAIN, "Setting up language:'%s'", strv[i]); - - lang = g_slice_new0 (SpellLanguage); - - lang->spell_config = new_aspell_config(); - - aspell_config_replace (lang->spell_config, "encoding", "utf-8"); - aspell_config_replace (lang->spell_config, "lang", strv[i++]); - - lang->spell_possible_err = new_aspell_speller (lang->spell_config); - - if (aspell_error_number (lang->spell_possible_err) == 0) { - lang->spell_checker = to_aspell_speller (lang->spell_possible_err); - languages = g_list_append (languages, lang); - } else { - delete_aspell_config (lang->spell_config); - g_slice_free (SpellLanguage, lang); - } - } - - if (strv) { - g_strfreev (strv); - } - - g_free (str); - } -} - -const char * -gossip_spell_get_language_name (const char *code) -{ - const gchar *name; - - g_return_val_if_fail (code != NULL, NULL); - - if (!iso_code_names) { - spell_iso_code_names_init (); - } - - name = g_hash_table_lookup (iso_code_names, code); - if (!name) { - return NULL; - } - - return dgettext ("iso_639", name); -} - -GList * -gossip_spell_get_language_codes (void) -{ - AspellConfig *config; - AspellDictInfoList *dlist; - AspellDictInfoEnumeration *dels; - const AspellDictInfo *entry; - GList *codes = NULL; - - config = new_aspell_config (); - dlist = get_aspell_dict_info_list (config); - dels = aspell_dict_info_list_elements (dlist); - - while ((entry = aspell_dict_info_enumeration_next (dels)) != 0) { - if (g_list_find_custom (codes, entry->code, (GCompareFunc) strcmp)) { - continue; - } - - codes = g_list_append (codes, g_strdup (entry->code)); - } - - delete_aspell_dict_info_enumeration (dels); - delete_aspell_config (config); - - return codes; -} - -void -gossip_spell_free_language_codes (GList *codes) -{ - g_list_foreach (codes, (GFunc) g_free, NULL); - g_list_free (codes); -} - -gboolean -gossip_spell_check (const gchar *word) -{ - GList *l; - gint n_langs; - gboolean correct = FALSE; - gint len; - const gchar *p; - gunichar c; - gboolean digit; - - g_return_val_if_fail (word != NULL, FALSE); - - spell_setup_languages (); - - if (!languages) { - gossip_debug (DEBUG_DOMAIN, "No languages to check against"); - return TRUE; - } - - /* Ignore certain cases like numbers, etc. */ - for (p = word, digit = TRUE; *p && digit; p = g_utf8_next_char (p)) { - c = g_utf8_get_char (p); - digit = g_unichar_isdigit (c); - } - - if (digit) { - /* We don't spell check digits. */ - gossip_debug (DEBUG_DOMAIN, "Not spell checking word:'%s', it is all digits", word); - return TRUE; - } - - len = strlen (word); - n_langs = g_list_length (languages); - for (l = languages; l; l = l->next) { - SpellLanguage *lang; - - lang = l->data; - - correct = aspell_speller_check (lang->spell_checker, word, len); - if (n_langs > 1 && correct) { - break; - } - } - - return correct; -} - -GList * -gossip_spell_get_suggestions (const gchar *word) -{ - GList *l1; - GList *l2 = NULL; - const AspellWordList *suggestions; - AspellStringEnumeration *elements; - const char *next; - gint len; - - g_return_val_if_fail (word != NULL, NULL); - - spell_setup_languages (); - - len = strlen (word); - - for (l1 = languages; l1; l1 = l1->next) { - SpellLanguage *lang; - - lang = l1->data; - - suggestions = aspell_speller_suggest (lang->spell_checker, - word, len); - - elements = aspell_word_list_elements (suggestions); - - while ((next = aspell_string_enumeration_next (elements))) { - l2 = g_list_append (l2, g_strdup (next)); - } - - delete_aspell_string_enumeration (elements); - } - - return l2; -} - -gboolean -gossip_spell_supported (void) -{ - if (g_getenv ("GOSSIP_SPELL_DISABLED")) { - gossip_debug (DEBUG_DOMAIN, "GOSSIP_SPELL_DISABLE env variable defined"); - return FALSE; - } - - return TRUE; -} - -#else /* not HAVE_ASPELL */ - -gboolean -gossip_spell_supported (void) -{ - return FALSE; -} - -GList * -gossip_spell_get_suggestions (const gchar *word) -{ - gossip_debug (DEBUG_DOMAIN, "Support disabled, could not get suggestions"); - - return NULL; -} - -gboolean -gossip_spell_check (const gchar *word) -{ - gossip_debug (DEBUG_DOMAIN, "Support disabled, could not check spelling"); - - return TRUE; -} - -const char * -gossip_spell_get_language_name (const char *lang) -{ - gossip_debug (DEBUG_DOMAIN, "Support disabled, could not get language name"); - - return NULL; -} - -GList * -gossip_spell_get_language_codes (void) -{ - gossip_debug (DEBUG_DOMAIN, "Support disabled, could not get language codes"); - - return NULL; -} - -void -gossip_spell_free_language_codes (GList *codes) -{ -} - -#endif /* HAVE_ASPELL */ - - -void -gossip_spell_free_suggestions (GList *suggestions) -{ - g_list_foreach (suggestions, (GFunc) g_free, NULL); - g_list_free (suggestions); -} - diff --git a/libempathy-gtk/gossip-spell.h b/libempathy-gtk/gossip-spell.h deleted file mode 100644 index f2d841b3..00000000 --- a/libempathy-gtk/gossip-spell.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2004-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Martyn Russell - * Richard Hult - */ - -#ifndef __GOSSIP_SPELL_H__ -#define __GOSSIP_SPELL_H__ - -G_BEGIN_DECLS - -gboolean gossip_spell_supported (void); -const gchar *gossip_spell_get_language_name (const gchar *code); -GList *gossip_spell_get_language_codes (void); -void gossip_spell_free_language_codes (GList *codes); -gboolean gossip_spell_check (const gchar *word); -GList * gossip_spell_get_suggestions (const gchar *word); -void gossip_spell_free_suggestions (GList *suggestions); - -G_END_DECLS - -#endif /* __GOSSIP_SPELL_H__ */ diff --git a/libempathy-gtk/gossip-status-presets.c b/libempathy-gtk/gossip-status-presets.c deleted file mode 100644 index b27238d4..00000000 --- a/libempathy-gtk/gossip-status-presets.c +++ /dev/null @@ -1,389 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2005-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Author: Martyn Russell - */ - -#include "config.h" - -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include - -#include "gossip-status-presets.h" - -#define DEBUG_DOMAIN "StatusPresets" - -#define STATUS_PRESETS_XML_FILENAME "status-presets.xml" -#define STATUS_PRESETS_DTD_FILENAME "gossip-status-presets.dtd" -#define STATUS_PRESETS_MAX_EACH 15 - -typedef struct { - gchar *status; - McPresence state; -} StatusPreset; - -static StatusPreset *status_preset_new (McPresence state, - const gchar *status); -static void status_preset_free (StatusPreset *status); -static void status_presets_file_parse (const gchar *filename); -const gchar * status_presets_get_state_as_str (McPresence state); -static gboolean status_presets_file_save (void); -static void status_presets_set_default (McPresence state, - const gchar *status); - -static GList *presets = NULL; -static StatusPreset *default_preset = NULL; - -static StatusPreset * -status_preset_new (McPresence state, - const gchar *status) -{ - StatusPreset *preset; - - preset = g_new0 (StatusPreset, 1); - - preset->status = g_strdup (status); - preset->state = state; - - return preset; -} - -static void -status_preset_free (StatusPreset *preset) -{ - g_free (preset->status); - g_free (preset); -} - -static void -status_presets_file_parse (const gchar *filename) -{ - xmlParserCtxtPtr ctxt; - xmlDocPtr doc; - xmlNodePtr presets_node; - xmlNodePtr node; - - gossip_debug (DEBUG_DOMAIN, "Attempting to parse file:'%s'...", filename); - - ctxt = xmlNewParserCtxt (); - - /* Parse and validate the file. */ - doc = xmlCtxtReadFile (ctxt, filename, NULL, 0); - if (!doc) { - g_warning ("Failed to parse file:'%s'", filename); - xmlFreeParserCtxt (ctxt); - return; - } - - if (!gossip_xml_validate (doc, STATUS_PRESETS_DTD_FILENAME)) { - g_warning ("Failed to validate file:'%s'", filename); - xmlFreeDoc(doc); - xmlFreeParserCtxt (ctxt); - return; - } - - /* The root node, presets. */ - presets_node = xmlDocGetRootElement (doc); - - node = presets_node->children; - while (node) { - if (strcmp ((gchar *) node->name, "status") == 0 || - strcmp ((gchar *) node->name, "default") == 0) { - McPresence state; - gchar *status; - gchar *state_str; - StatusPreset *preset; - gboolean is_default = FALSE; - - if (strcmp ((gchar *) node->name, "default") == 0) { - is_default = TRUE; - } - - status = (gchar *) xmlNodeGetContent (node); - state_str = (gchar *) xmlGetProp (node, "presence"); - - if (state_str) { - state = gossip_presence_state_from_str (state_str); - - if (is_default) { - gossip_debug (DEBUG_DOMAIN, - "Default status preset state is:'%s', status:'%s'", - state_str, status); - - status_presets_set_default (state, status); - } else { - preset = status_preset_new (state, status); - presets = g_list_append (presets, preset); - } - } - - xmlFree (status); - xmlFree (state_str); - } - - node = node->next; - } - - /* Use the default if not set */ - if (!default_preset) { - status_presets_set_default (MC_PRESENCE_OFFLINE, NULL); - } - - gossip_debug (DEBUG_DOMAIN, "Parsed %d status presets", g_list_length (presets)); - - xmlFreeDoc (doc); - xmlFreeParserCtxt (ctxt); -} - -void -gossip_status_presets_get_all (void) -{ - gchar *dir; - gchar *file_with_path; - - /* If already set up clean up first. */ - if (presets) { - g_list_foreach (presets, (GFunc) status_preset_free, NULL); - g_list_free (presets); - presets = NULL; - } - - dir = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, NULL); - g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR); - file_with_path = g_build_filename (dir, STATUS_PRESETS_XML_FILENAME, NULL); - g_free (dir); - - if (g_file_test (file_with_path, G_FILE_TEST_EXISTS)) { - status_presets_file_parse (file_with_path); - } - - g_free (file_with_path); -} - -static gboolean -status_presets_file_save (void) -{ - xmlDocPtr doc; - xmlNodePtr root; - GList *l; - gchar *dir; - gchar *file; - gint count[LAST_MC_PRESENCE]; - gint i; - - for (i = 0; i < LAST_MC_PRESENCE; i++) { - count[i] = 0; - } - - dir = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, NULL); - g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR); - file = g_build_filename (dir, STATUS_PRESETS_XML_FILENAME, NULL); - g_free (dir); - - doc = xmlNewDoc ("1.0"); - root = xmlNewNode (NULL, "presets"); - xmlDocSetRootElement (doc, root); - - if (default_preset) { - xmlNodePtr subnode; - xmlChar *state; - - state = (gchar*) gossip_presence_state_to_str (default_preset->state); - - subnode = xmlNewTextChild (root, NULL, "default", - default_preset->status); - xmlNewProp (subnode, "presence", state); - } - - for (l = presets; l; l = l->next) { - StatusPreset *sp; - xmlNodePtr subnode; - xmlChar *state; - - sp = l->data; - state = (gchar*) gossip_presence_state_to_str (sp->state); - - count[sp->state]++; - if (count[sp->state] > STATUS_PRESETS_MAX_EACH) { - continue; - } - - subnode = xmlNewTextChild (root, NULL, - "status", sp->status); - xmlNewProp (subnode, "presence", state); - } - - /* Make sure the XML is indented properly */ - xmlIndentTreeOutput = 1; - - gossip_debug (DEBUG_DOMAIN, "Saving file:'%s'", file); - xmlSaveFormatFileEnc (file, doc, "utf-8", 1); - xmlFreeDoc (doc); - - g_free (file); - - return TRUE; -} - -GList * -gossip_status_presets_get (McPresence state, - gint max_number) -{ - GList *list = NULL; - GList *l; - gint i; - - i = 0; - for (l = presets; l; l = l->next) { - StatusPreset *sp; - - sp = l->data; - - if (sp->state != state) { - continue; - } - - list = g_list_append (list, sp->status); - i++; - - if (max_number != -1 && i >= max_number) { - break; - } - } - - return list; -} - -void -gossip_status_presets_set_last (McPresence state, - const gchar *status) -{ - GList *l; - StatusPreset *preset; - gint num; - - /* Remove any duplicate. */ - for (l = presets; l; l = l->next) { - preset = l->data; - - if (state == preset->state) { - if (strcmp (status, preset->status) == 0) { - status_preset_free (preset); - presets = g_list_delete_link (presets, l); - break; - } - } - } - - preset = status_preset_new (state, status); - presets = g_list_prepend (presets, preset); - - num = 0; - for (l = presets; l; l = l->next) { - preset = l->data; - - if (state != preset->state) { - continue; - } - - num++; - - if (num > STATUS_PRESETS_MAX_EACH) { - status_preset_free (preset); - presets = g_list_delete_link (presets, l); - break; - } - } - - status_presets_file_save (); -} - -void -gossip_status_presets_reset (void) -{ - g_list_foreach (presets, (GFunc) status_preset_free, NULL); - g_list_free (presets); - - presets = NULL; - - status_presets_set_default (MC_PRESENCE_AVAILABLE, NULL); - - status_presets_file_save (); -} - -McPresence -gossip_status_presets_get_default_state (void) -{ - if (!default_preset) { - return MC_PRESENCE_OFFLINE; - } - - return default_preset->state; -} - -const gchar * -gossip_status_presets_get_default_status (void) -{ - if (!default_preset || - !default_preset->status) { - return NULL; - } - - return default_preset->status; -} - -static void -status_presets_set_default (McPresence state, - const gchar *status) -{ - if (default_preset) { - status_preset_free (default_preset); - } - - default_preset = status_preset_new (state, status); -} - -void -gossip_status_presets_set_default (McPresence state, - const gchar *status) -{ - status_presets_set_default (state, status); - status_presets_file_save (); -} - -void -gossip_status_presets_clear_default (void) -{ - if (default_preset) { - status_preset_free (default_preset); - default_preset = NULL; - } - - status_presets_file_save (); -} diff --git a/libempathy-gtk/gossip-status-presets.dtd b/libempathy-gtk/gossip-status-presets.dtd deleted file mode 100644 index b7acc962..00000000 --- a/libempathy-gtk/gossip-status-presets.dtd +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - diff --git a/libempathy-gtk/gossip-status-presets.h b/libempathy-gtk/gossip-status-presets.h deleted file mode 100644 index 4b2d9255..00000000 --- a/libempathy-gtk/gossip-status-presets.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2005-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Author: Martyn Russell - */ - -#ifndef __GOSSIP_STATUS_PRESETS_H__ -#define __GOSSIP_STATUS_PRESETS_H__ - -#include - -G_BEGIN_DECLS - -void gossip_status_presets_get_all (void); -GList * gossip_status_presets_get (McPresence state, - gint max_number); -void gossip_status_presets_set_last (McPresence state, - const gchar *status); -void gossip_status_presets_reset (void); -McPresence gossip_status_presets_get_default_state (void); -const gchar * gossip_status_presets_get_default_status (void); -void gossip_status_presets_set_default (McPresence state, - const gchar *status); -void gossip_status_presets_clear_default (void); - -G_END_DECLS - -#endif /* __GOSSIP_STATUS_PRESETS_H__ */ diff --git a/libempathy-gtk/gossip-theme-manager.c b/libempathy-gtk/gossip-theme-manager.c deleted file mode 100644 index 6d5905e5..00000000 --- a/libempathy-gtk/gossip-theme-manager.c +++ /dev/null @@ -1,1045 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2005-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Richard Hult - */ - -#include "config.h" - -#include - -#include -#include - -#include -#include - -#include "gossip-chat-view.h" -#include "gossip-preferences.h" -#include "gossip-theme-manager.h" - -#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_THEME_MANAGER, GossipThemeManagerPriv)) - -typedef struct { - gchar *name; - guint name_notify_id; - guint room_notify_id; - - gboolean show_avatars; - guint show_avatars_notify_id; - - gboolean irc_style; -} GossipThemeManagerPriv; - -static void theme_manager_finalize (GObject *object); -static void theme_manager_notify_name_cb (GossipConf *conf, - const gchar *key, - gpointer user_data); -static void theme_manager_notify_room_cb (GossipConf *conf, - const gchar *key, - gpointer user_data); -static void theme_manager_notify_show_avatars_cb (GossipConf *conf, - const gchar *key, - gpointer user_data); -static void theme_manager_ensure_tag_by_name (GtkTextBuffer *buffer, - const gchar *name); -static gboolean theme_manager_ensure_theme_exists (const gchar *name); -static GtkTextTag *theme_manager_init_tag_by_name (GtkTextTagTable *table, - const gchar *name); -static void theme_manager_add_tag (GtkTextTagTable *table, - GtkTextTag *tag); -static void theme_manager_fixup_tag_table (GossipThemeManager *theme_manager, - GossipChatView *view); -static void theme_manager_apply_theme_classic (GossipThemeManager *manager, - GossipChatView *view); -static void theme_manager_apply_theme_clean (GossipThemeManager *manager, - GossipChatView *view); -static void theme_manager_apply_theme_blue (GossipThemeManager *manager, - GossipChatView *view); -static void theme_manager_apply_theme (GossipThemeManager *manager, - GossipChatView *view, - const gchar *name); - -enum { - THEME_CHANGED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -static const gchar *themes[] = { - "classic", N_("Classic"), - "simple", N_("Simple"), - "clean", N_("Clean"), - "blue", N_("Blue"), - NULL -}; - -G_DEFINE_TYPE (GossipThemeManager, gossip_theme_manager, G_TYPE_OBJECT); - -static void -gossip_theme_manager_class_init (GossipThemeManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - signals[THEME_CHANGED] = - g_signal_new ("theme-changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - g_type_class_add_private (object_class, sizeof (GossipThemeManagerPriv)); - - object_class->finalize = theme_manager_finalize; -} - -static void -gossip_theme_manager_init (GossipThemeManager *manager) -{ - GossipThemeManagerPriv *priv; - - priv = GET_PRIV (manager); - - priv->name_notify_id = - gossip_conf_notify_add (gossip_conf_get (), - GOSSIP_PREFS_CHAT_THEME, - theme_manager_notify_name_cb, - manager); - - priv->room_notify_id = - gossip_conf_notify_add (gossip_conf_get (), - GOSSIP_PREFS_CHAT_THEME_CHAT_ROOM, - theme_manager_notify_room_cb, - manager); - - gossip_conf_get_string (gossip_conf_get (), - GOSSIP_PREFS_CHAT_THEME, - &priv->name); - - /* Unused right now, but will be used soon. */ - priv->show_avatars_notify_id = - gossip_conf_notify_add (gossip_conf_get (), - GOSSIP_PREFS_UI_SHOW_AVATARS, - theme_manager_notify_show_avatars_cb, - manager); - - gossip_conf_get_bool (gossip_conf_get (), - GOSSIP_PREFS_UI_SHOW_AVATARS, - &priv->show_avatars); -} - -static void -theme_manager_finalize (GObject *object) -{ - GossipThemeManagerPriv *priv; - - priv = GET_PRIV (object); - - gossip_conf_notify_remove (gossip_conf_get (), priv->name_notify_id); - gossip_conf_notify_remove (gossip_conf_get (), priv->room_notify_id); - gossip_conf_notify_remove (gossip_conf_get (), priv->show_avatars_notify_id); - - g_free (priv->name); - - G_OBJECT_CLASS (gossip_theme_manager_parent_class)->finalize (object); -} - -static void -theme_manager_notify_name_cb (GossipConf *conf, - const gchar *key, - gpointer user_data) -{ - GossipThemeManager *manager; - GossipThemeManagerPriv *priv; - gchar *name; - - manager = user_data; - priv = GET_PRIV (manager); - - g_free (priv->name); - - name = NULL; - if (!gossip_conf_get_string (conf, key, &name) || - name == NULL || name[0] == 0) { - priv->name = g_strdup ("classic"); - g_free (name); - } else { - priv->name = name; - } - - g_signal_emit (manager, signals[THEME_CHANGED], 0, NULL); -} - -static void -theme_manager_notify_room_cb (GossipConf *conf, - const gchar *key, - gpointer user_data) -{ - g_signal_emit (user_data, signals[THEME_CHANGED], 0, NULL); -} - -static void -theme_manager_notify_show_avatars_cb (GossipConf *conf, - const gchar *key, - gpointer user_data) -{ - GossipThemeManager *manager; - GossipThemeManagerPriv *priv; - gboolean value; - - manager = user_data; - priv = GET_PRIV (manager); - - if (!gossip_conf_get_bool (conf, key, &value)) { - priv->show_avatars = FALSE; - } else { - priv->show_avatars = value; - } -} - -static void -theme_manager_ensure_tag_by_name (GtkTextBuffer *buffer, - const gchar *name) -{ - GtkTextTagTable *table; - GtkTextTag *tag; - - table = gtk_text_buffer_get_tag_table (buffer); - tag = gtk_text_tag_table_lookup (table, name); - - if (!tag) { - gtk_text_buffer_create_tag (buffer, - name, - NULL); - } -} - -static gboolean -theme_manager_ensure_theme_exists (const gchar *name) -{ - gint i; - - if (G_STR_EMPTY (name)) { - return FALSE; - } - - for (i = 0; themes[i]; i += 2) { - if (strcmp (themes[i], name) == 0) { - return TRUE; - } - } - - return FALSE; -} - -static GtkTextTag * -theme_manager_init_tag_by_name (GtkTextTagTable *table, - const gchar *name) -{ - GtkTextTag *tag; - - tag = gtk_text_tag_table_lookup (table, name); - - if (!tag) { - return gtk_text_tag_new (name); - } - - /* Clear the old values so that we don't affect the new theme. */ - g_object_set (tag, - "background-set", FALSE, - "foreground-set", FALSE, - "invisible-set", FALSE, - "justification-set", FALSE, - "paragraph-background-set", FALSE, - "pixels-above-lines-set", FALSE, - "pixels-below-lines-set", FALSE, - "rise-set", FALSE, - "scale-set", FALSE, - "size-set", FALSE, - "style-set", FALSE, - "weight-set", FALSE, - NULL); - - return tag; -} - -static void -theme_manager_add_tag (GtkTextTagTable *table, - GtkTextTag *tag) -{ - gchar *name; - GtkTextTag *check_tag; - - g_object_get (tag, "name", &name, NULL); - check_tag = gtk_text_tag_table_lookup (table, name); - g_free (name); - if (check_tag) { - return; - } - - gtk_text_tag_table_add (table, tag); - - g_object_unref (tag); -} - -static void -theme_manager_fixup_tag_table (GossipThemeManager *theme_manager, - GossipChatView *view) -{ - GtkTextBuffer *buffer; - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); - - /* "Fancy" style tags. */ - theme_manager_ensure_tag_by_name (buffer, "fancy-header-self"); - theme_manager_ensure_tag_by_name (buffer, "fancy-header-self-avatar"); - theme_manager_ensure_tag_by_name (buffer, "fancy-avatar-self"); - theme_manager_ensure_tag_by_name (buffer, "fancy-line-top-self"); - theme_manager_ensure_tag_by_name (buffer, "fancy-line-bottom-self"); - theme_manager_ensure_tag_by_name (buffer, "fancy-body-self"); - theme_manager_ensure_tag_by_name (buffer, "fancy-action-self"); - theme_manager_ensure_tag_by_name (buffer, "fancy-highlight-self"); - - theme_manager_ensure_tag_by_name (buffer, "fancy-header-other"); - theme_manager_ensure_tag_by_name (buffer, "fancy-header-other-avatar"); - theme_manager_ensure_tag_by_name (buffer, "fancy-avatar-other"); - theme_manager_ensure_tag_by_name (buffer, "fancy-line-top-other"); - theme_manager_ensure_tag_by_name (buffer, "fancy-line-bottom-other"); - theme_manager_ensure_tag_by_name (buffer, "fancy-body-other"); - theme_manager_ensure_tag_by_name (buffer, "fancy-action-other"); - theme_manager_ensure_tag_by_name (buffer, "fancy-highlight-other"); - - theme_manager_ensure_tag_by_name (buffer, "fancy-spacing"); - theme_manager_ensure_tag_by_name (buffer, "fancy-time"); - theme_manager_ensure_tag_by_name (buffer, "fancy-event"); - theme_manager_ensure_tag_by_name (buffer, "fancy-invite"); - theme_manager_ensure_tag_by_name (buffer, "fancy-link"); - - /* IRC style tags. */ - theme_manager_ensure_tag_by_name (buffer, "irc-nick-self"); - theme_manager_ensure_tag_by_name (buffer, "irc-body-self"); - theme_manager_ensure_tag_by_name (buffer, "irc-action-self"); - - theme_manager_ensure_tag_by_name (buffer, "irc-nick-other"); - theme_manager_ensure_tag_by_name (buffer, "irc-body-other"); - theme_manager_ensure_tag_by_name (buffer, "irc-action-other"); - - theme_manager_ensure_tag_by_name (buffer, "irc-nick-highlight"); - theme_manager_ensure_tag_by_name (buffer, "irc-spacing"); - theme_manager_ensure_tag_by_name (buffer, "irc-time"); - theme_manager_ensure_tag_by_name (buffer, "irc-event"); - theme_manager_ensure_tag_by_name (buffer, "irc-invite"); - theme_manager_ensure_tag_by_name (buffer, "irc-link"); -} - -static void -theme_manager_apply_theme_classic (GossipThemeManager *manager, - GossipChatView *view) -{ - GossipThemeManagerPriv *priv; - GtkTextBuffer *buffer; - GtkTextTagTable *table; - GtkTextTag *tag; - - priv = GET_PRIV (manager); - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); - table = gtk_text_buffer_get_tag_table (buffer); - - priv->irc_style = TRUE; - - tag = theme_manager_init_tag_by_name (table, "irc-spacing"); - g_object_set (tag, - "size", 2000, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "irc-nick-self"); - g_object_set (tag, - "foreground", "sea green", - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "irc-body-self"); - g_object_set (tag, - /* To get the default theme color: */ - "foreground-set", FALSE, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "irc-action-self"); - g_object_set (tag, - "foreground", "brown4", - "style", PANGO_STYLE_ITALIC, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "irc-nick-highlight"); - g_object_set (tag, - "foreground", "indian red", - "weight", PANGO_WEIGHT_BOLD, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "irc-nick-other"); - g_object_set (tag, - "foreground", "skyblue4", - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "irc-body-other"); - g_object_set (tag, - /* To get the default theme color: */ - "foreground-set", FALSE, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "irc-action-other"); - g_object_set (tag, - "foreground", "brown4", - "style", PANGO_STYLE_ITALIC, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "irc-time"); - g_object_set (tag, - "foreground", "darkgrey", - "justification", GTK_JUSTIFY_CENTER, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "irc-event"); - g_object_set (tag, - "foreground", "PeachPuff4", - "justification", GTK_JUSTIFY_LEFT, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "irc-invite"); - g_object_set (tag, - "foreground", "sienna", - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "irc-link"); - g_object_set (tag, - "foreground", "steelblue", - "underline", PANGO_UNDERLINE_SINGLE, - NULL); - theme_manager_add_tag (table, tag); -} - -static void -theme_manager_apply_theme_simple (GossipThemeManager *manager, - GossipChatView *view) -{ - GossipThemeManagerPriv *priv; - GtkTextBuffer *buffer; - GtkTextTagTable *table; - GtkTextTag *tag; - GtkWidget *widget; - GtkStyle *style; - - priv = GET_PRIV (manager); - - widget = gtk_entry_new (); - style = gtk_widget_get_style (widget); - gtk_widget_destroy (widget); - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); - table = gtk_text_buffer_get_tag_table (buffer); - - priv->irc_style = FALSE; - - tag = theme_manager_init_tag_by_name (table, "fancy-spacing"); - g_object_set (tag, - "size", 3000, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-header-self"); - g_object_set (tag, - "weight", PANGO_WEIGHT_BOLD, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-header-self-avatar"); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-avatar-self"); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-line-top-self"); - g_object_set (tag, - "size", 6 * PANGO_SCALE, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-line-bottom-self"); - g_object_set (tag, - "size", 1, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-body-self"); - g_object_set (tag, - "pixels-above-lines", 2, - "pixels-below-lines", 2, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-action-self"); - g_object_set (tag, - "foreground-gdk", &style->base[GTK_STATE_SELECTED], - "style", PANGO_STYLE_ITALIC, - "pixels-above-lines", 2, - "pixels-below-lines", 2, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-highlight-self"); - g_object_set (tag, - "weight", PANGO_WEIGHT_BOLD, - "pixels-above-lines", 2, - "pixels-below-lines", 2, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-header-other"); - g_object_set (tag, - "weight", PANGO_WEIGHT_BOLD, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-header-other-avatar"); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-avatar-other"); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-line-top-other"); - g_object_set (tag, - "size", 6 * PANGO_SCALE, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-line-bottom-other"); - g_object_set (tag, - "size", 1, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-body-other"); - g_object_set (tag, - "pixels-above-lines", 2, - "pixels-below-lines", 2, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-action-other"); - g_object_set (tag, - "foreground-gdk", &style->base[GTK_STATE_SELECTED], - "style", PANGO_STYLE_ITALIC, - "pixels-above-lines", 2, - "pixels-below-lines", 2, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-highlight-other"); - g_object_set (tag, - "weight", PANGO_WEIGHT_BOLD, - "pixels-above-lines", 2, - "pixels-below-lines", 2, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-time"); - g_object_set (tag, - "foreground", "darkgrey", - "justification", GTK_JUSTIFY_CENTER, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-event"); - g_object_set (tag, - "foreground", "darkgrey", - "justification", GTK_JUSTIFY_LEFT, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-invite"); - g_object_set (tag, - "foreground", "darkgrey", - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-link"); - g_object_set (tag, - "foreground-gdk", &style->base[GTK_STATE_SELECTED], - "underline", PANGO_UNDERLINE_SINGLE, - NULL); - theme_manager_add_tag (table, tag); -} - -static void -theme_manager_apply_theme_clean (GossipThemeManager *manager, - GossipChatView *view) -{ - GossipThemeManagerPriv *priv; - GtkTextBuffer *buffer; - GtkTextTagTable *table; - GtkTextTag *tag; - - priv = GET_PRIV (manager); - - /* Inherit the simple theme. */ - theme_manager_apply_theme_simple (manager, view); - -#define ELEGANT_HEAD "#efefdf" -#define ELEGANT_LINE "#e3e3d3" - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); - table = gtk_text_buffer_get_tag_table (buffer); - - tag = theme_manager_init_tag_by_name (table, "fancy-spacing"); - g_object_set (tag, - "size", PANGO_SCALE * 10, - NULL); - - tag = theme_manager_init_tag_by_name (table, "fancy-header-self"); - g_object_set (tag, - "foreground", "black", - "weight", PANGO_WEIGHT_BOLD, - "paragraph-background", ELEGANT_HEAD, - "pixels-above-lines", 2, - "pixels-below-lines", 2, - NULL); - - tag = theme_manager_init_tag_by_name (table, "fancy-avatar-self"); - g_object_set (tag, - "paragraph-background", ELEGANT_HEAD, - "pixels-above-lines", 2, - "pixels-below-lines", 2, - NULL); - - tag = theme_manager_init_tag_by_name (table, "fancy-line-top-self"); - g_object_set (tag, - "size", 1 * PANGO_SCALE, - "paragraph-background", ELEGANT_LINE, - NULL); - - tag = theme_manager_init_tag_by_name (table, "fancy-line-bottom-self"); - g_object_set (tag, - "size", 1 * PANGO_SCALE, - NULL); - - tag = theme_manager_init_tag_by_name (table, "fancy-action-self"); - g_object_set (tag, - "foreground", "brown4", - "style", PANGO_STYLE_ITALIC, - NULL); - - tag = theme_manager_init_tag_by_name (table, "fancy-highlight-self"); - g_object_set (tag, - "foreground", "black", - "weight", PANGO_WEIGHT_BOLD, - NULL); - - tag = theme_manager_init_tag_by_name (table, "fancy-header-other"); - g_object_set (tag, - "foreground", "black", - "weight", PANGO_WEIGHT_BOLD, - "paragraph-background", ELEGANT_HEAD, - "pixels-above-lines", 2, - "pixels-below-lines", 2, - NULL); - - tag = theme_manager_init_tag_by_name (table, "fancy-avatar-other"); - g_object_set (tag, - "paragraph-background", ELEGANT_HEAD, - "pixels-above-lines", 2, - "pixels-below-lines", 2, - NULL); - - tag = theme_manager_init_tag_by_name (table, "fancy-line-top-other"); - g_object_set (tag, - "size", 1 * PANGO_SCALE, - "paragraph-background", ELEGANT_LINE, - NULL); - - tag = theme_manager_init_tag_by_name (table, "fancy-line-bottom-other"); - g_object_set (tag, - "size", 1 * PANGO_SCALE, - NULL); - - tag = theme_manager_init_tag_by_name (table, "fancy-action-other"); - g_object_set (tag, - "foreground", "brown4", - "style", PANGO_STYLE_ITALIC, - NULL); - - tag = theme_manager_init_tag_by_name (table, "fancy-time"); - g_object_set (tag, - "foreground", "darkgrey", - "justification", GTK_JUSTIFY_CENTER, - NULL); - - tag = theme_manager_init_tag_by_name (table, "fancy-event"); - g_object_set (tag, - "foreground", "darkgrey", - "justification", GTK_JUSTIFY_LEFT, - NULL); - - tag = theme_manager_init_tag_by_name (table, "fancy-invite"); - g_object_set (tag, - "foreground", "sienna", - NULL); - - tag = theme_manager_init_tag_by_name (table, "fancy-link"); - g_object_set (tag, - "foreground", "#49789e", - "underline", PANGO_UNDERLINE_SINGLE, - NULL); -} - -static void -theme_manager_apply_theme_blue (GossipThemeManager *manager, - GossipChatView *view) -{ - GossipThemeManagerPriv *priv; - GtkTextBuffer *buffer; - GtkTextTagTable *table; - GtkTextTag *tag; - - priv = GET_PRIV (manager); - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); - table = gtk_text_buffer_get_tag_table (buffer); - - priv->irc_style = FALSE; - -#define BLUE_BODY_SELF "#dcdcdc" -#define BLUE_HEAD_SELF "#b9b9b9" -#define BLUE_LINE_SELF "#aeaeae" - -#define BLUE_BODY_OTHER "#adbdc8" -#define BLUE_HEAD_OTHER "#88a2b4" -#define BLUE_LINE_OTHER "#7f96a4" - - tag = theme_manager_init_tag_by_name (table, "fancy-spacing"); - g_object_set (tag, - "size", 3000, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-header-self"); - g_object_set (tag, - "foreground", "black", - "paragraph-background", BLUE_HEAD_SELF, - "weight", PANGO_WEIGHT_BOLD, - "pixels-above-lines", 2, - "pixels-below-lines", 2, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-header-self-avatar"); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-avatar-self"); - g_object_set (tag, - "paragraph-background", BLUE_HEAD_SELF, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-line-top-self"); - g_object_set (tag, - "size", 1, - "paragraph-background", BLUE_LINE_SELF, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-line-bottom-self"); - g_object_set (tag, - "size", 1, - "paragraph-background", BLUE_LINE_SELF, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-body-self"); - g_object_set (tag, - "foreground", "black", - "paragraph-background", BLUE_BODY_SELF, - "pixels-above-lines", 4, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-action-self"); - g_object_set (tag, - "foreground", "brown4", - "style", PANGO_STYLE_ITALIC, - "paragraph-background", BLUE_BODY_SELF, - "pixels-above-lines", 4, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-highlight-self"); - g_object_set (tag, - "foreground", "black", - "weight", PANGO_WEIGHT_BOLD, - "paragraph-background", BLUE_BODY_SELF, - "pixels-above-lines", 4, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-header-other"); - g_object_set (tag, - "foreground", "black", - "paragraph-background", BLUE_HEAD_OTHER, - "weight", PANGO_WEIGHT_BOLD, - "pixels-above-lines", 2, - "pixels-below-lines", 2, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-header-other-avatar"); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-avatar-other"); - g_object_set (tag, - "paragraph-background", BLUE_HEAD_OTHER, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-line-top-other"); - g_object_set (tag, - "size", 1, - "paragraph-background", BLUE_LINE_OTHER, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-line-bottom-other"); - g_object_set (tag, - "size", 1, - "paragraph-background", BLUE_LINE_OTHER, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-body-other"); - g_object_set (tag, - "foreground", "black", - "paragraph-background", BLUE_BODY_OTHER, - "pixels-above-lines", 4, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-action-other"); - g_object_set (tag, - "foreground", "brown4", - "style", PANGO_STYLE_ITALIC, - "paragraph-background", BLUE_BODY_OTHER, - "pixels-above-lines", 4, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-highlight-other"); - g_object_set (tag, - "foreground", "black", - "weight", PANGO_WEIGHT_BOLD, - "paragraph-background", BLUE_BODY_OTHER, - "pixels-above-lines", 4, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-time"); - g_object_set (tag, - "foreground", "darkgrey", - "justification", GTK_JUSTIFY_CENTER, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-event"); - g_object_set (tag, - "foreground", BLUE_LINE_OTHER, - "justification", GTK_JUSTIFY_LEFT, - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-invite"); - g_object_set (tag, - "foreground", "sienna", - NULL); - theme_manager_add_tag (table, tag); - - tag = theme_manager_init_tag_by_name (table, "fancy-link"); - g_object_set (tag, - "foreground", "#49789e", - "underline", PANGO_UNDERLINE_SINGLE, - NULL); - theme_manager_add_tag (table, tag); -} - -static void -theme_manager_apply_theme (GossipThemeManager *manager, - GossipChatView *view, - const gchar *name) -{ - GossipThemeManagerPriv *priv; - gint margin; - - priv = GET_PRIV (manager); - - /* Make sure all tags are present. Note: not useful now but when we have - * user defined theme it will be. - */ - theme_manager_fixup_tag_table (manager, view); - - if (theme_manager_ensure_theme_exists (name)) { - if (strcmp (name, "clean") == 0) { - theme_manager_apply_theme_clean (manager, view); - margin = 3; - } - else if (strcmp (name, "simple") == 0) { - theme_manager_apply_theme_simple (manager, view); - margin = 3; - } - else if (strcmp (name, "blue") == 0) { - theme_manager_apply_theme_blue (manager, view); - margin = 0; - } else { - theme_manager_apply_theme_classic (manager, view); - margin = 3; - } - } else { - theme_manager_apply_theme_classic (manager, view); - margin = 3; - } - - gossip_chat_view_set_margin (view, margin); - gossip_chat_view_set_irc_style (view, priv->irc_style); -} - -GossipThemeManager * -gossip_theme_manager_get (void) -{ - static GossipThemeManager *manager = NULL; - - if (!manager) { - manager = g_object_new (GOSSIP_TYPE_THEME_MANAGER, NULL); - } - - return manager; -} - -const gchar ** -gossip_theme_manager_get_themes (void) -{ - return themes; -} - -void -gossip_theme_manager_apply (GossipThemeManager *manager, - GossipChatView *view, - const gchar *name) -{ - GossipThemeManagerPriv *priv; - - priv = GET_PRIV (manager); - - theme_manager_apply_theme (manager, view, name); -} - -void -gossip_theme_manager_apply_saved (GossipThemeManager *manager, - GossipChatView *view) -{ - GossipThemeManagerPriv *priv; - - priv = GET_PRIV (manager); - - theme_manager_apply_theme (manager, view, priv->name); -} - -/* FIXME: A bit ugly. We should probably change the scheme so that instead of - * the manager signalling, views are registered and applied to automatically. - */ -void -gossip_theme_manager_update_show_avatars (GossipThemeManager *manager, - GossipChatView *view, - gboolean show) -{ - GossipThemeManagerPriv *priv; - GtkTextBuffer *buffer; - GtkTextTagTable *table; - GtkTextTag *tag_text_self, *tag_text_other; - GtkTextTag *tag_image_self, *tag_image_other; - - priv = GET_PRIV (manager); - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); - table = gtk_text_buffer_get_tag_table (buffer); - - tag_text_self = gtk_text_tag_table_lookup (table, "fancy-header-self-avatar"); - tag_text_other = gtk_text_tag_table_lookup (table, "fancy-header-other-avatar"); - - tag_image_self = gtk_text_tag_table_lookup (table, "fancy-avatar-self"); - tag_image_other = gtk_text_tag_table_lookup (table, "fancy-avatar-other"); - - if (!show) { - g_object_set (tag_text_self, - "rise", 0, - NULL); - g_object_set (tag_text_other, - "rise", 0, - NULL); - g_object_set (tag_image_self, - "invisible", TRUE, - NULL); - g_object_set (tag_image_other, - "invisible", TRUE, - NULL); - } else { - GtkTextAttributes *attrs; - gint size; - gint rise; - - attrs = gtk_text_view_get_default_attributes (GTK_TEXT_VIEW (view)); - size = pango_font_description_get_size (attrs->font); - rise = MAX (0, (32 * PANGO_SCALE - size) / 2.0); - - g_object_set (tag_text_self, - "rise", rise, - NULL); - g_object_set (tag_text_other, - "rise", rise, - NULL); - g_object_set (tag_image_self, - "invisible", FALSE, - NULL); - g_object_set (tag_image_other, - "invisible", FALSE, - NULL); - - gtk_text_attributes_unref (attrs); - } -} - diff --git a/libempathy-gtk/gossip-theme-manager.h b/libempathy-gtk/gossip-theme-manager.h deleted file mode 100644 index bb7e3cf7..00000000 --- a/libempathy-gtk/gossip-theme-manager.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2005-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Richard Hult - */ - -#ifndef __GOSSIP_THEME_MANAGER_H__ -#define __GOSSIP_THEME_MANAGER_H__ - -#include - -#include "gossip-chat-view.h" - -G_BEGIN_DECLS - -#define GOSSIP_TYPE_THEME_MANAGER (gossip_theme_manager_get_type ()) -#define GOSSIP_THEME_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOSSIP_TYPE_THEME_MANAGER, GossipThemeManager)) -#define GOSSIP_THEME_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GOSSIP_TYPE_THEME_MANAGER, GossipThemeManagerClass)) -#define GOSSIP_IS_THEME_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOSSIP_TYPE_THEME_MANAGER)) -#define GOSSIP_IS_THEME_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOSSIP_TYPE_THEME_MANAGER)) -#define GOSSIP_THEME_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOSSIP_TYPE_THEME_MANAGER, GossipThemeManagerClass)) - -typedef struct _GossipThemeManager GossipThemeManager; -typedef struct _GossipThemeManagerClass GossipThemeManagerClass; - -struct _GossipThemeManager { - GObject parent; -}; - -struct _GossipThemeManagerClass { - GObjectClass parent_class; -}; - -GType gossip_theme_manager_get_type (void) G_GNUC_CONST; -GossipThemeManager *gossip_theme_manager_get (void); -const gchar ** gossip_theme_manager_get_themes (void); -void gossip_theme_manager_apply (GossipThemeManager *manager, - GossipChatView *view, - const gchar *theme); -void gossip_theme_manager_apply_saved (GossipThemeManager *manager, - GossipChatView *view); -void gossip_theme_manager_update_show_avatars (GossipThemeManager *manager, - GossipChatView *view, - gboolean show); - -G_END_DECLS - -#endif /* __GOSSIP_THEME_MANAGER_H__ */ diff --git a/libempathy-gtk/gossip-ui-utils.c b/libempathy-gtk/gossip-ui-utils.c deleted file mode 100644 index b17e5776..00000000 --- a/libempathy-gtk/gossip-ui-utils.c +++ /dev/null @@ -1,1341 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2002-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Richard Hult - * Martyn Russell - * Xavier Claessens - * - * Part of this file is copied from GtkSourceView (gtksourceiter.c): - * Paolo Maggi - * Jeroen Zwartepoorte - */ - -#include - -#include -#include -#include -#include - -#include - -#include - -#include "gossip-ui-utils.h" -#include "empathy-images.h" - -#define DEBUG_DOMAIN "UiUtils" - -struct SizeData { - gint width; - gint height; - gboolean preserve_aspect_ratio; -}; - -static GladeXML * -get_glade_file (const gchar *filename, - const gchar *root, - const gchar *domain, - const gchar *first_required_widget, - va_list args) -{ - gchar *path; - GladeXML *gui; - const char *name; - GtkWidget **widget_ptr; - - path = g_build_filename (DATADIR, "empathy", filename, NULL); - gui = glade_xml_new (path, root, domain); - g_free (path); - - if (!gui) { - g_warning ("Couldn't find necessary glade file '%s'", filename); - return NULL; - } - - for (name = first_required_widget; name; name = va_arg (args, char *)) { - widget_ptr = va_arg (args, void *); - - *widget_ptr = glade_xml_get_widget (gui, name); - - if (!*widget_ptr) { - g_warning ("Glade file '%s' is missing widget '%s'.", - filename, name); - continue; - } - } - - return gui; -} - -void -gossip_glade_get_file_simple (const gchar *filename, - const gchar *root, - const gchar *domain, - const gchar *first_required_widget, ...) -{ - va_list args; - GladeXML *gui; - - va_start (args, first_required_widget); - - gui = get_glade_file (filename, - root, - domain, - first_required_widget, - args); - - va_end (args); - - if (!gui) { - return; - } - - g_object_unref (gui); -} - -GladeXML * -gossip_glade_get_file (const gchar *filename, - const gchar *root, - const gchar *domain, - const gchar *first_required_widget, ...) -{ - va_list args; - GladeXML *gui; - - va_start (args, first_required_widget); - - gui = get_glade_file (filename, - root, - domain, - first_required_widget, - args); - - va_end (args); - - if (!gui) { - return NULL; - } - - return gui; -} - -void -gossip_glade_connect (GladeXML *gui, - gpointer user_data, - gchar *first_widget, ...) -{ - va_list args; - const gchar *name; - const gchar *signal; - GtkWidget *widget; - gpointer *callback; - - va_start (args, first_widget); - - for (name = first_widget; name; name = va_arg (args, char *)) { - signal = va_arg (args, void *); - callback = va_arg (args, void *); - - widget = glade_xml_get_widget (gui, name); - if (!widget) { - g_warning ("Glade file is missing widget '%s', aborting", - name); - continue; - } - - g_signal_connect (widget, - signal, - G_CALLBACK (callback), - user_data); - } - - va_end (args); -} - -void -gossip_glade_setup_size_group (GladeXML *gui, - GtkSizeGroupMode mode, - gchar *first_widget, ...) -{ - va_list args; - GtkWidget *widget; - GtkSizeGroup *size_group; - const gchar *name; - - va_start (args, first_widget); - - size_group = gtk_size_group_new (mode); - - for (name = first_widget; name; name = va_arg (args, char *)) { - widget = glade_xml_get_widget (gui, name); - if (!widget) { - g_warning ("Glade file is missing widget '%s'", name); - continue; - } - - gtk_size_group_add_widget (size_group, widget); - } - - g_object_unref (size_group); - - va_end (args); -} - -GdkPixbuf * -gossip_pixbuf_from_icon_name (const gchar *icon_name, - GtkIconSize icon_size) -{ - GtkIconTheme *theme; - GdkPixbuf *pixbuf = NULL; - GError *error = NULL; - gint w, h; - gint size = 48; - - theme = gtk_icon_theme_get_default (); - - if (gtk_icon_size_lookup (icon_size, &w, &h)) { - size = (w + h) / 2; - } - - pixbuf = gtk_icon_theme_load_icon (theme, - icon_name, - size, - 0, - &error); - if (error) { - gossip_debug (DEBUG_DOMAIN, "Error loading icon: %s", error->message); - g_clear_error (&error); - } - - return pixbuf; -} - -GdkPixbuf * -gossip_pixbuf_from_smiley (GossipSmiley type, - GtkIconSize icon_size) -{ - const gchar *icon_id; - - switch (type) { - case GOSSIP_SMILEY_NORMAL: /* :) */ - icon_id = "stock_smiley-1"; - break; - case GOSSIP_SMILEY_WINK: /* ;) */ - icon_id = "stock_smiley-3"; - break; - case GOSSIP_SMILEY_BIGEYE: /* =) */ - icon_id = "stock_smiley-2"; - break; - case GOSSIP_SMILEY_NOSE: /* :-) */ - icon_id = "stock_smiley-7"; - break; - case GOSSIP_SMILEY_CRY: /* :'( */ - icon_id = "stock_smiley-11"; - break; - case GOSSIP_SMILEY_SAD: /* :( */ - icon_id = "stock_smiley-4"; - break; - case GOSSIP_SMILEY_SCEPTICAL: /* :/ */ - icon_id = "stock_smiley-9"; - break; - case GOSSIP_SMILEY_BIGSMILE: /* :D */ - icon_id = "stock_smiley-6"; - break; - case GOSSIP_SMILEY_INDIFFERENT: /* :| */ - icon_id = "stock_smiley-8"; - break; - case GOSSIP_SMILEY_TOUNGE: /* :p */ - icon_id = "stock_smiley-10"; - break; - case GOSSIP_SMILEY_SHOCKED: /* :o */ - icon_id = "stock_smiley-5"; - break; - case GOSSIP_SMILEY_COOL: /* 8) */ - icon_id = "stock_smiley-15"; - break; - case GOSSIP_SMILEY_SORRY: /* *| */ - icon_id = "stock_smiley-12"; - break; - case GOSSIP_SMILEY_KISS: /* :* */ - icon_id = "stock_smiley-13"; - break; - case GOSSIP_SMILEY_SHUTUP: /* :# */ - icon_id = "stock_smiley-14"; - break; - case GOSSIP_SMILEY_YAWN: /* |O */ - icon_id = ""; - break; - case GOSSIP_SMILEY_CONFUSED: /* :$ */ - icon_id = "stock_smiley-17"; - break; - case GOSSIP_SMILEY_ANGEL: /* O) */ - icon_id = "stock_smiley-18"; - break; - case GOSSIP_SMILEY_OOOH: /* :x */ - icon_id = "stock_smiley-19"; - break; - case GOSSIP_SMILEY_LOOKAWAY: /* *) */ - icon_id = "stock_smiley-20"; - break; - case GOSSIP_SMILEY_BLUSH: /* *S */ - icon_id = "stock_smiley-23"; - break; - case GOSSIP_SMILEY_COOLBIGSMILE: /* 8D */ - icon_id = "stock_smiley-25"; - break; - case GOSSIP_SMILEY_ANGRY: /* :@ */ - icon_id = "stock_smiley-16"; - break; - case GOSSIP_SMILEY_BOSS: /* @) */ - icon_id = "stock_smiley-21"; - break; - case GOSSIP_SMILEY_MONKEY: /* #) */ - icon_id = "stock_smiley-22"; - break; - case GOSSIP_SMILEY_SILLY: /* O) */ - icon_id = "stock_smiley-24"; - break; - case GOSSIP_SMILEY_SICK: /* +o( */ - icon_id = "stock_smiley-26"; - break; - - default: - g_assert_not_reached (); - icon_id = NULL; - } - - - return gossip_pixbuf_from_icon_name (icon_id, icon_size); -} - -const gchar * -gossip_icon_name_from_account (McAccount *account) -{ - McProfile *profile; - - profile = mc_account_get_profile (account); - - return mc_profile_get_icon_name (profile); -} - -const gchar * -gossip_icon_name_for_presence_state (McPresence state) -{ - switch (state) { - case MC_PRESENCE_AVAILABLE: - return EMPATHY_IMAGE_AVAILABLE; - case MC_PRESENCE_DO_NOT_DISTURB: - return EMPATHY_IMAGE_BUSY; - case MC_PRESENCE_AWAY: - return EMPATHY_IMAGE_AWAY; - case MC_PRESENCE_EXTENDED_AWAY: - return EMPATHY_IMAGE_EXT_AWAY; - case MC_PRESENCE_HIDDEN: - case MC_PRESENCE_OFFLINE: - case MC_PRESENCE_UNSET: - return EMPATHY_IMAGE_OFFLINE; - default: - g_assert_not_reached (); - } - - return NULL; -} - -const gchar * -gossip_icon_name_for_presence (GossipPresence *presence) -{ - McPresence state; - - g_return_val_if_fail (GOSSIP_IS_PRESENCE (presence), - EMPATHY_IMAGE_OFFLINE); - - state = gossip_presence_get_state (presence); - - return gossip_icon_name_for_presence_state (state); -} - -const gchar * -gossip_icon_name_for_contact (GossipContact *contact) -{ - GossipPresence *presence; - GossipSubscription subscription; - - g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), - EMPATHY_IMAGE_OFFLINE); - - presence = gossip_contact_get_presence (contact); - if (presence) { - return gossip_icon_name_for_presence (presence); - } - - subscription = gossip_contact_get_subscription (contact); - if (!(subscription & GOSSIP_SUBSCRIPTION_FROM)) { - return EMPATHY_IMAGE_PENDING; - } - - return EMPATHY_IMAGE_OFFLINE; -} - -GdkPixbuf * -gossip_pixbuf_avatar_from_contact (GossipContact *contact) -{ - GdkPixbuf *pixbuf; - GdkPixbufLoader *loader; - GossipAvatar *avatar; - GError *error = NULL; - - g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL); - - avatar = gossip_contact_get_avatar (contact); - if (!avatar) { - return NULL; - } - - loader = gdk_pixbuf_loader_new (); - - if (!gdk_pixbuf_loader_write (loader, avatar->data, avatar->len, &error)) { - g_warning ("Couldn't write avatar image:%p with " - "length:%" G_GSIZE_FORMAT " to pixbuf loader: %s", - avatar->data, avatar->len, error->message); - g_error_free (error); - return NULL; - } - - gdk_pixbuf_loader_close (loader, NULL); - - pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); - - g_object_ref (pixbuf); - g_object_unref (loader); - - return pixbuf; -} - -static void -pixbuf_from_avatar_size_prepared_cb (GdkPixbufLoader *loader, - int width, - int height, - struct SizeData *data) -{ - g_return_if_fail (width > 0 && height > 0); - - if (data->preserve_aspect_ratio && (data->width > 0 || data->height > 0)) { - if (width < data->width && height < data->height) { - width = width; - height = height; - } - - if (data->width < 0) { - width = width * (double) data->height / (gdouble) height; - height = data->height; - } else if (data->height < 0) { - height = height * (double) data->width / (double) width; - width = data->width; - } else if ((double) height * (double) data->width > - (double) width * (double) data->height) { - width = 0.5 + (double) width * (double) data->height / (double) height; - height = data->height; - } else { - height = 0.5 + (double) height * (double) data->width / (double) width; - width = data->width; - } - } else { - if (data->width > 0) { - width = data->width; - } - - if (data->height > 0) { - height = data->height; - } - } - - gdk_pixbuf_loader_set_size (loader, width, height); -} - -GdkPixbuf * -gossip_pixbuf_from_avatar_scaled (GossipAvatar *avatar, - gint width, - gint height) -{ - GdkPixbuf *pixbuf; - GdkPixbufLoader *loader; - struct SizeData data; - GError *error = NULL; - - if (!avatar) { - return NULL; - } - - data.width = width; - data.height = height; - data.preserve_aspect_ratio = TRUE; - - loader = gdk_pixbuf_loader_new (); - - g_signal_connect (loader, "size-prepared", - G_CALLBACK (pixbuf_from_avatar_size_prepared_cb), - &data); - - if (!gdk_pixbuf_loader_write (loader, avatar->data, avatar->len, &error)) { - g_warning ("Couldn't write avatar image:%p with " - "length:%" G_GSIZE_FORMAT " to pixbuf loader: %s", - avatar->data, avatar->len, error->message); - g_error_free (error); - return NULL; - } - - gdk_pixbuf_loader_close (loader, NULL); - - pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); - - g_object_ref (pixbuf); - g_object_unref (loader); - - return pixbuf; -} - -GdkPixbuf * -gossip_pixbuf_avatar_from_contact_scaled (GossipContact *contact, - gint width, - gint height) -{ - GossipAvatar *avatar; - - g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL); - - avatar = gossip_contact_get_avatar (contact); - - return gossip_pixbuf_from_avatar_scaled (avatar, width, height); -} -/* Stolen from GtkSourceView, hence the weird intendation. Please keep it like - * that to make it easier to apply changes from the original code. - */ -#define GTK_TEXT_UNKNOWN_CHAR 0xFFFC - -/* this function acts like g_utf8_offset_to_pointer() except that if it finds a - * decomposable character it consumes the decomposition length from the given - * offset. So it's useful when the offset was calculated for the normalized - * version of str, but we need a pointer to str itself. */ -static const gchar * -pointer_from_offset_skipping_decomp (const gchar *str, gint offset) -{ - gchar *casefold, *normal; - const gchar *p, *q; - - p = str; - while (offset > 0) - { - q = g_utf8_next_char (p); - casefold = g_utf8_casefold (p, q - p); - normal = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); - offset -= g_utf8_strlen (normal, -1); - g_free (casefold); - g_free (normal); - p = q; - } - return p; -} - -static const gchar * -g_utf8_strcasestr (const gchar *haystack, const gchar *needle) -{ - gsize needle_len; - gsize haystack_len; - const gchar *ret = NULL; - gchar *p; - gchar *casefold; - gchar *caseless_haystack; - gint i; - - g_return_val_if_fail (haystack != NULL, NULL); - g_return_val_if_fail (needle != NULL, NULL); - - casefold = g_utf8_casefold (haystack, -1); - caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); - g_free (casefold); - - needle_len = g_utf8_strlen (needle, -1); - haystack_len = g_utf8_strlen (caseless_haystack, -1); - - if (needle_len == 0) - { - ret = (gchar *)haystack; - goto finally_1; - } - - if (haystack_len < needle_len) - { - ret = NULL; - goto finally_1; - } - - p = (gchar*)caseless_haystack; - needle_len = strlen (needle); - i = 0; - - while (*p) - { - if ((strncmp (p, needle, needle_len) == 0)) - { - ret = pointer_from_offset_skipping_decomp (haystack, i); - goto finally_1; - } - - p = g_utf8_next_char (p); - i++; - } - -finally_1: - g_free (caseless_haystack); - - return ret; -} - -static gboolean -g_utf8_caselessnmatch (const char *s1, const char *s2, - gssize n1, gssize n2) -{ - gchar *casefold; - gchar *normalized_s1; - gchar *normalized_s2; - gint len_s1; - gint len_s2; - gboolean ret = FALSE; - - g_return_val_if_fail (s1 != NULL, FALSE); - g_return_val_if_fail (s2 != NULL, FALSE); - g_return_val_if_fail (n1 > 0, FALSE); - g_return_val_if_fail (n2 > 0, FALSE); - - casefold = g_utf8_casefold (s1, n1); - normalized_s1 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); - g_free (casefold); - - casefold = g_utf8_casefold (s2, n2); - normalized_s2 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); - g_free (casefold); - - len_s1 = strlen (normalized_s1); - len_s2 = strlen (normalized_s2); - - if (len_s1 < len_s2) - goto finally_2; - - ret = (strncmp (normalized_s1, normalized_s2, len_s2) == 0); - -finally_2: - g_free (normalized_s1); - g_free (normalized_s2); - - return ret; -} - -static void -forward_chars_with_skipping (GtkTextIter *iter, - gint count, - gboolean skip_invisible, - gboolean skip_nontext, - gboolean skip_decomp) -{ - gint i; - - g_return_if_fail (count >= 0); - - i = count; - - while (i > 0) - { - gboolean ignored = FALSE; - - /* minimal workaround to avoid the infinite loop of bug #168247. - * It doesn't fix the problemjust the symptom... - */ - if (gtk_text_iter_is_end (iter)) - return; - - if (skip_nontext && gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR) - ignored = TRUE; - - if (!ignored && skip_invisible && - /* _gtk_text_btree_char_is_invisible (iter)*/ FALSE) - ignored = TRUE; - - if (!ignored && skip_decomp) - { - /* being UTF8 correct sucks; this accounts for extra - offsets coming from canonical decompositions of - UTF8 characters (e.g. accented characters) which - g_utf8_normalize() performs */ - gchar *normal; - gchar buffer[6]; - gint buffer_len; - - buffer_len = g_unichar_to_utf8 (gtk_text_iter_get_char (iter), buffer); - normal = g_utf8_normalize (buffer, buffer_len, G_NORMALIZE_NFD); - i -= (g_utf8_strlen (normal, -1) - 1); - g_free (normal); - } - - gtk_text_iter_forward_char (iter); - - if (!ignored) - --i; - } -} - -static gboolean -lines_match (const GtkTextIter *start, - const gchar **lines, - gboolean visible_only, - gboolean slice, - GtkTextIter *match_start, - GtkTextIter *match_end) -{ - GtkTextIter next; - gchar *line_text; - const gchar *found; - gint offset; - - if (*lines == NULL || **lines == '\0') - { - if (match_start) - *match_start = *start; - if (match_end) - *match_end = *start; - return TRUE; - } - - next = *start; - gtk_text_iter_forward_line (&next); - - /* No more text in buffer, but *lines is nonempty */ - if (gtk_text_iter_equal (start, &next)) - return FALSE; - - if (slice) - { - if (visible_only) - line_text = gtk_text_iter_get_visible_slice (start, &next); - else - line_text = gtk_text_iter_get_slice (start, &next); - } - else - { - if (visible_only) - line_text = gtk_text_iter_get_visible_text (start, &next); - else - line_text = gtk_text_iter_get_text (start, &next); - } - - if (match_start) /* if this is the first line we're matching */ - { - found = g_utf8_strcasestr (line_text, *lines); - } - else - { - /* If it's not the first line, we have to match from the - * start of the line. - */ - if (g_utf8_caselessnmatch (line_text, *lines, strlen (line_text), - strlen (*lines))) - found = line_text; - else - found = NULL; - } - - if (found == NULL) - { - g_free (line_text); - return FALSE; - } - - /* Get offset to start of search string */ - offset = g_utf8_strlen (line_text, found - line_text); - - next = *start; - - /* If match start needs to be returned, set it to the - * start of the search string. - */ - forward_chars_with_skipping (&next, offset, visible_only, !slice, FALSE); - if (match_start) - { - *match_start = next; - } - - /* Go to end of search string */ - forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1), visible_only, !slice, TRUE); - - g_free (line_text); - - ++lines; - - if (match_end) - *match_end = next; - - /* pass NULL for match_start, since we don't need to find the - * start again. - */ - return lines_match (&next, lines, visible_only, slice, NULL, match_end); -} - -/* strsplit () that retains the delimiter as part of the string. */ -static gchar ** -strbreakup (const char *string, - const char *delimiter, - gint max_tokens) -{ - GSList *string_list = NULL, *slist; - gchar **str_array, *s, *casefold, *new_string; - guint i, n = 1; - - g_return_val_if_fail (string != NULL, NULL); - g_return_val_if_fail (delimiter != NULL, NULL); - - if (max_tokens < 1) - max_tokens = G_MAXINT; - - s = strstr (string, delimiter); - if (s) - { - guint delimiter_len = strlen (delimiter); - - do - { - guint len; - - len = s - string + delimiter_len; - new_string = g_new (gchar, len + 1); - strncpy (new_string, string, len); - new_string[len] = 0; - casefold = g_utf8_casefold (new_string, -1); - g_free (new_string); - new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); - g_free (casefold); - string_list = g_slist_prepend (string_list, new_string); - n++; - string = s + delimiter_len; - s = strstr (string, delimiter); - } while (--max_tokens && s); - } - - if (*string) - { - n++; - casefold = g_utf8_casefold (string, -1); - new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); - g_free (casefold); - string_list = g_slist_prepend (string_list, new_string); - } - - str_array = g_new (gchar*, n); - - i = n - 1; - - str_array[i--] = NULL; - for (slist = string_list; slist; slist = slist->next) - str_array[i--] = slist->data; - - g_slist_free (string_list); - - return str_array; -} - -gboolean -gossip_text_iter_forward_search (const GtkTextIter *iter, - const gchar *str, - GtkTextIter *match_start, - GtkTextIter *match_end, - const GtkTextIter *limit) -{ - gchar **lines = NULL; - GtkTextIter match; - gboolean retval = FALSE; - GtkTextIter search; - gboolean visible_only; - gboolean slice; - - g_return_val_if_fail (iter != NULL, FALSE); - g_return_val_if_fail (str != NULL, FALSE); - - if (limit && gtk_text_iter_compare (iter, limit) >= 0) - return FALSE; - - if (*str == '\0') { - /* If we can move one char, return the empty string there */ - match = *iter; - - if (gtk_text_iter_forward_char (&match)) { - if (limit && gtk_text_iter_equal (&match, limit)) { - return FALSE; - } - - if (match_start) { - *match_start = match; - } - if (match_end) { - *match_end = match; - } - return TRUE; - } else { - return FALSE; - } - } - - visible_only = TRUE; - slice = FALSE; - - /* locate all lines */ - lines = strbreakup (str, "\n", -1); - - search = *iter; - - do { - /* This loop has an inefficient worst-case, where - * gtk_text_iter_get_text () is called repeatedly on - * a single line. - */ - GtkTextIter end; - - if (limit && gtk_text_iter_compare (&search, limit) >= 0) { - break; - } - - if (lines_match (&search, (const gchar**)lines, - visible_only, slice, &match, &end)) { - if (limit == NULL || - (limit && gtk_text_iter_compare (&end, limit) <= 0)) { - retval = TRUE; - - if (match_start) { - *match_start = match; - } - if (match_end) { - *match_end = end; - } - } - break; - } - } while (gtk_text_iter_forward_line (&search)); - - g_strfreev ((gchar**)lines); - - return retval; -} - -static const gchar * -g_utf8_strrcasestr (const gchar *haystack, const gchar *needle) -{ - gsize needle_len; - gsize haystack_len; - const gchar *ret = NULL; - gchar *p; - gchar *casefold; - gchar *caseless_haystack; - gint i; - - g_return_val_if_fail (haystack != NULL, NULL); - g_return_val_if_fail (needle != NULL, NULL); - - casefold = g_utf8_casefold (haystack, -1); - caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD); - g_free (casefold); - - needle_len = g_utf8_strlen (needle, -1); - haystack_len = g_utf8_strlen (caseless_haystack, -1); - - if (needle_len == 0) - { - ret = (gchar *)haystack; - goto finally_1; - } - - if (haystack_len < needle_len) - { - ret = NULL; - goto finally_1; - } - - i = haystack_len - needle_len; - p = g_utf8_offset_to_pointer (caseless_haystack, i); - needle_len = strlen (needle); - - while (p >= caseless_haystack) - { - if (strncmp (p, needle, needle_len) == 0) - { - ret = pointer_from_offset_skipping_decomp (haystack, i); - goto finally_1; - } - - p = g_utf8_prev_char (p); - i--; - } - -finally_1: - g_free (caseless_haystack); - - return ret; -} - -static gboolean -backward_lines_match (const GtkTextIter *start, - const gchar **lines, - gboolean visible_only, - gboolean slice, - GtkTextIter *match_start, - GtkTextIter *match_end) -{ - GtkTextIter line, next; - gchar *line_text; - const gchar *found; - gint offset; - - if (*lines == NULL || **lines == '\0') - { - if (match_start) - *match_start = *start; - if (match_end) - *match_end = *start; - return TRUE; - } - - line = next = *start; - if (gtk_text_iter_get_line_offset (&next) == 0) - { - if (!gtk_text_iter_backward_line (&next)) - return FALSE; - } - else - gtk_text_iter_set_line_offset (&next, 0); - - if (slice) - { - if (visible_only) - line_text = gtk_text_iter_get_visible_slice (&next, &line); - else - line_text = gtk_text_iter_get_slice (&next, &line); - } - else - { - if (visible_only) - line_text = gtk_text_iter_get_visible_text (&next, &line); - else - line_text = gtk_text_iter_get_text (&next, &line); - } - - if (match_start) /* if this is the first line we're matching */ - { - found = g_utf8_strrcasestr (line_text, *lines); - } - else - { - /* If it's not the first line, we have to match from the - * start of the line. - */ - if (g_utf8_caselessnmatch (line_text, *lines, strlen (line_text), - strlen (*lines))) - found = line_text; - else - found = NULL; - } - - if (found == NULL) - { - g_free (line_text); - return FALSE; - } - - /* Get offset to start of search string */ - offset = g_utf8_strlen (line_text, found - line_text); - - forward_chars_with_skipping (&next, offset, visible_only, !slice, FALSE); - - /* If match start needs to be returned, set it to the - * start of the search string. - */ - if (match_start) - { - *match_start = next; - } - - /* Go to end of search string */ - forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1), visible_only, !slice, TRUE); - - g_free (line_text); - - ++lines; - - if (match_end) - *match_end = next; - - /* try to match the rest of the lines forward, passing NULL - * for match_start so lines_match will try to match the entire - * line */ - return lines_match (&next, lines, visible_only, - slice, NULL, match_end); -} - -gboolean -gossip_text_iter_backward_search (const GtkTextIter *iter, - const gchar *str, - GtkTextIter *match_start, - GtkTextIter *match_end, - const GtkTextIter *limit) -{ - gchar **lines = NULL; - GtkTextIter match; - gboolean retval = FALSE; - GtkTextIter search; - gboolean visible_only; - gboolean slice; - - g_return_val_if_fail (iter != NULL, FALSE); - g_return_val_if_fail (str != NULL, FALSE); - - if (limit && gtk_text_iter_compare (iter, limit) <= 0) - return FALSE; - - if (*str == '\0') - { - /* If we can move one char, return the empty string there */ - match = *iter; - - if (gtk_text_iter_backward_char (&match)) - { - if (limit && gtk_text_iter_equal (&match, limit)) - return FALSE; - - if (match_start) - *match_start = match; - if (match_end) - *match_end = match; - return TRUE; - } - else - { - return FALSE; - } - } - - visible_only = TRUE; - slice = TRUE; - - /* locate all lines */ - lines = strbreakup (str, "\n", -1); - - search = *iter; - - while (TRUE) - { - /* This loop has an inefficient worst-case, where - * gtk_text_iter_get_text () is called repeatedly on - * a single line. - */ - GtkTextIter end; - - if (limit && gtk_text_iter_compare (&search, limit) <= 0) - break; - - if (backward_lines_match (&search, (const gchar**)lines, - visible_only, slice, &match, &end)) - { - if (limit == NULL || (limit && - gtk_text_iter_compare (&end, limit) > 0)) - { - retval = TRUE; - - if (match_start) - *match_start = match; - if (match_end) - *match_end = end; - } - break; - } - - if (gtk_text_iter_get_line_offset (&search) == 0) - { - if (!gtk_text_iter_backward_line (&search)) - break; - } - else - { - gtk_text_iter_set_line_offset (&search, 0); - } - } - - g_strfreev ((gchar**)lines); - - return retval; -} - -static gboolean -window_get_is_on_current_workspace (GtkWindow *window) -{ - GdkWindow *gdk_window; - - gdk_window = GTK_WIDGET (window)->window; - if (gdk_window) { - return !(gdk_window_get_state (gdk_window) & - GDK_WINDOW_STATE_ICONIFIED); - } else { - return FALSE; - } -} - -/* Checks if the window is visible as in visible on the current workspace. */ -gboolean -gossip_window_get_is_visible (GtkWindow *window) -{ - gboolean visible; - - g_return_val_if_fail (window != NULL, FALSE); - - g_object_get (window, - "visible", &visible, - NULL); - - return visible && window_get_is_on_current_workspace (window); -} - -/* Takes care of moving the window to the current workspace. */ -void -gossip_window_present (GtkWindow *window, - gboolean steal_focus) -{ - gboolean visible; - gboolean on_current; - guint32 timestamp; - - g_return_if_fail (window != NULL); - - /* There are three cases: hidden, visible, visible on another - * workspace. - */ - - g_object_get (window, - "visible", &visible, - NULL); - - on_current = window_get_is_on_current_workspace (window); - - if (visible && !on_current) { - /* Hide it so present brings it to the current workspace. */ - gtk_widget_hide (GTK_WIDGET (window)); - } - - timestamp = gtk_get_current_event_time (); - if (steal_focus && timestamp != GDK_CURRENT_TIME) { - gtk_window_present_with_time (window, timestamp); - } else { - gtk_window_present (window); - } -} - -GtkWindow * -gossip_get_toplevel_window (GtkWidget *widget) -{ - GtkWidget *toplevel; - - g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); - - toplevel = gtk_widget_get_toplevel (widget); - if (GTK_IS_WINDOW (toplevel)) { - return GTK_WINDOW (toplevel); - } - - return NULL; -} - -/* The URL opening code can't handle schemeless strings, so we try to be - * smart and add http if there is no scheme or doesn't look like a mail - * address. This should work in most cases, and let us click on strings - * like "www.gnome.org". - */ -static gchar * -fixup_url (const gchar *url) -{ - gchar *real_url; - - if (!g_str_has_prefix (url, "http://") && - !strstr (url, ":/") && - !strstr (url, "@")) { - real_url = g_strdup_printf ("http://%s", url); - } else { - real_url = g_strdup (url); - } - - return real_url; -} - -void -gossip_url_show (const char *url) -{ - gchar *real_url; - GnomeVFSResult res; - - real_url = fixup_url (url); - res = gnome_vfs_url_show (real_url); - if (res != GNOME_VFS_OK) { - gossip_debug (DEBUG_DOMAIN, "Couldn't show URL %s: %s", - real_url, - gnome_vfs_result_to_string (res)); - } - - g_free (real_url); -} - -static void -link_button_hook (GtkLinkButton *button, - const gchar *link, - gpointer user_data) -{ - gossip_url_show (link); -} - -GtkWidget * -gossip_link_button_new (const gchar *url, - const gchar *title) -{ - static gboolean hook = FALSE; - - if (!hook) { - hook = TRUE; - gtk_link_button_set_uri_hook (link_button_hook, NULL, NULL); - } - - return gtk_link_button_new_with_label (url, title); -} - -void -gossip_toggle_button_set_state_quietly (GtkWidget *widget, - GCallback callback, - gpointer user_data, - gboolean active) -{ - g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget)); - - g_signal_handlers_block_by_func (widget, callback, user_data); - g_object_set (widget, "active", active, NULL); - g_signal_handlers_unblock_by_func (widget, callback, user_data); -} - diff --git a/libempathy-gtk/gossip-ui-utils.h b/libempathy-gtk/gossip-ui-utils.h deleted file mode 100644 index 5a0804a9..00000000 --- a/libempathy-gtk/gossip-ui-utils.h +++ /dev/null @@ -1,113 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2002-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Richard Hult - * Martyn Russell - * Xavier Claessens - * - * Part of this file is copied from GtkSourceView (gtksourceiter.c): - * Paolo Maggi - * Jeroen Zwartepoorte - */ - -#ifndef __GOSSIP_UI_UTILS_H__ -#define __GOSSIP_UI_UTILS_H__ - -#include -#include - -#include -#include - -#include -#include -#include - -#include "gossip-chat-view.h" - -G_BEGIN_DECLS - -#define G_STR_EMPTY(x) ((x) == NULL || (x)[0] == '\0') - -/* Glade */ -void gossip_glade_get_file_simple (const gchar *filename, - const gchar *root, - const gchar *domain, - const gchar *first_required_widget, - ...); -GladeXML * gossip_glade_get_file (const gchar *filename, - const gchar *root, - const gchar *domain, - const gchar *first_required_widget, - ...); -void gossip_glade_connect (GladeXML *gui, - gpointer user_data, - gchar *first_widget, - ...); -void gossip_glade_setup_size_group (GladeXML *gui, - GtkSizeGroupMode mode, - gchar *first_widget, - ...); -/* Pixbufs */ -GdkPixbuf * gossip_pixbuf_from_icon_name (const gchar *icon_name, - GtkIconSize icon_size); -GdkPixbuf * gossip_pixbuf_from_smiley (GossipSmiley type, - GtkIconSize icon_size); -const gchar * gossip_icon_name_from_account (McAccount *account); -const gchar * gossip_icon_name_for_presence_state (McPresence state); -const gchar * gossip_icon_name_for_presence (GossipPresence *presence); -const gchar * gossip_icon_name_for_contact (GossipContact *contact); -GdkPixbuf * gossip_pixbuf_from_avatar_scaled (GossipAvatar *avatar, - gint width, - gint height); -GdkPixbuf * gossip_pixbuf_avatar_from_contact (GossipContact *contact); -GdkPixbuf * gossip_pixbuf_avatar_from_contact_scaled (GossipContact *contact, - gint width, - gint height); -/* Text view */ -gboolean gossip_text_iter_forward_search (const GtkTextIter *iter, - const gchar *str, - GtkTextIter *match_start, - GtkTextIter *match_end, - const GtkTextIter *limit); -gboolean gossip_text_iter_backward_search (const GtkTextIter *iter, - const gchar *str, - GtkTextIter *match_start, - GtkTextIter *match_end, - const GtkTextIter *limit); - -/* Windows */ -gboolean gossip_window_get_is_visible (GtkWindow *window); -void gossip_window_present (GtkWindow *window, - gboolean steal_focus); -GtkWindow *gossip_get_toplevel_window (GtkWidget *widget); -void gossip_url_show (const char *url); -void gossip_toggle_button_set_state_quietly (GtkWidget *widget, - GCallback callback, - gpointer user_data, - gboolean active); -GtkWidget *gossip_link_button_new (const gchar *url, - const gchar *title); - - -G_END_DECLS - -#endif /* __GOSSIP_UI_UTILS_H__ */ diff --git a/libempathy/Makefile.am b/libempathy/Makefile.am index 37bb98e0..00ce4233 100644 --- a/libempathy/Makefile.am +++ b/libempathy/Makefile.am @@ -13,19 +13,19 @@ BUILT_SOURCES = \ noinst_LTLIBRARIES = libempathy.la libempathy_la_SOURCES = \ - gossip-conf.c gossip-conf.h \ - gossip-contact.c gossip-contact.h \ - gossip-avatar.c gossip-avatar.h \ - gossip-time.c gossip-time.h \ - gossip-presence.c gossip-presence.h \ - gossip-telepathy-group.c gossip-telepathy-group.h \ - gossip-debug.c gossip-debug.h \ - gossip-utils.c gossip-utils.h \ - gossip-message.c gossip-message.h \ - gossip-chatroom-manager.c gossip-chatroom-manager.h \ - gossip-chatroom.c gossip-chatroom.h \ + empathy-conf.c empathy-conf.h \ + empathy-contact.c empathy-contact.h \ + empathy-avatar.c empathy-avatar.h \ + empathy-time.c empathy-time.h \ + empathy-presence.c empathy-presence.h \ + empathy-debug.c empathy-debug.h \ + empathy-utils.c empathy-utils.h \ + empathy-message.c empathy-message.h \ + empathy-chatroom-manager.c empathy-chatroom-manager.h \ + empathy-chatroom.c empathy-chatroom.h \ empathy-contact-list.c empathy-contact-list.h \ empathy-contact-manager.c empathy-contact-manager.h \ + empathy-tp-group.c empathy-tp-group.h \ empathy-tp-contact-list.c empathy-tp-contact-list.h \ empathy-tp-chat.c empathy-tp-chat.h \ empathy-tp-chatroom.c empathy-tp-chatroom.h \ @@ -52,7 +52,7 @@ empathy-chandler-glue.h: empathy-chandler.xml dtddir = $(datadir)/empathy dtd_DATA = \ - gossip-chatroom-manager.dtd + empathy-chatroom-manager.dtd stylesheetdir = $(datadir)/empathy stylesheet_DATA = \ diff --git a/libempathy/empathy-avatar.c b/libempathy/empathy-avatar.c new file mode 100644 index 00000000..e5a2a73a --- /dev/null +++ b/libempathy/empathy-avatar.c @@ -0,0 +1,86 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2002-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Martyn Russell + * Xavier Claessens + */ + +#include "config.h" + +#include "empathy-avatar.h" + +#define DEBUG_DOMAIN "Avatar" + +GType +empathy_avatar_get_gtype (void) +{ + static GType type_id = 0; + + if (!type_id) { + type_id = g_boxed_type_register_static ("EmpathyAvatar", + (GBoxedCopyFunc) empathy_avatar_ref, + (GBoxedFreeFunc) empathy_avatar_unref); + } + + return type_id; +} + +EmpathyAvatar * +empathy_avatar_new (guchar *data, + gsize len, + gchar *format) +{ + EmpathyAvatar *avatar; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (len > 0, NULL); + g_return_val_if_fail (format != NULL, NULL); + + avatar = g_slice_new0 (EmpathyAvatar); + avatar->data = g_memdup (data, len); + avatar->len = len; + avatar->format = g_strdup (format); + avatar->refcount = 1; + + return avatar; +} + +void +empathy_avatar_unref (EmpathyAvatar *avatar) +{ + g_return_if_fail (avatar != NULL); + + avatar->refcount--; + if (avatar->refcount == 0) { + g_free (avatar->data); + g_free (avatar->format); + g_slice_free (EmpathyAvatar, avatar); + } +} + +EmpathyAvatar * +empathy_avatar_ref (EmpathyAvatar *avatar) +{ + g_return_val_if_fail (avatar != NULL, NULL); + + avatar->refcount++; + + return avatar; +} + diff --git a/libempathy/empathy-avatar.h b/libempathy/empathy-avatar.h new file mode 100644 index 00000000..73d69cf7 --- /dev/null +++ b/libempathy/empathy-avatar.h @@ -0,0 +1,48 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006 Xavier Claessens + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EMPATHY_AVATAR_H__ +#define __EMPATHY_AVATAR_H__ + +#include + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_AVATAR (empathy_avatar_get_gtype ()) + +typedef struct _EmpathyAvatar EmpathyAvatar; + +struct _EmpathyAvatar { + guchar *data; + gsize len; + gchar *format; + guint refcount; +}; + +GType empathy_avatar_get_gtype (void) G_GNUC_CONST; +EmpathyAvatar * empathy_avatar_new (guchar *avatar, + gsize len, + gchar *format); +EmpathyAvatar * empathy_avatar_ref (EmpathyAvatar *avatar); +void empathy_avatar_unref (EmpathyAvatar *avatar); + +G_END_DECLS + +#endif /* __EMPATHY_AVATAR_H__ */ diff --git a/libempathy/empathy-chandler.c b/libempathy/empathy-chandler.c index 5e9ca82f..9bef4b1e 100644 --- a/libempathy/empathy-chandler.c +++ b/libempathy/empathy-chandler.c @@ -29,7 +29,7 @@ #include #include "empathy-chandler.h" -#include "gossip-debug.h" +#include "empathy-debug.h" #include "empathy-marshal.h" #define DEBUG_DOMAIN "EmpathyChandler" @@ -100,7 +100,7 @@ empathy_chandler_new (const gchar *bus_name, G_TYPE_INVALID, G_TYPE_UINT, &result, G_TYPE_INVALID)) { - gossip_debug (DEBUG_DOMAIN, + empathy_debug (DEBUG_DOMAIN, "Failed to request name: %s", error ? error->message : "No error given"); g_clear_error (&error); diff --git a/libempathy/empathy-chatroom-manager.c b/libempathy/empathy-chatroom-manager.c new file mode 100644 index 00000000..a0b6fbb2 --- /dev/null +++ b/libempathy/empathy-chatroom-manager.c @@ -0,0 +1,501 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Xavier Claessens + * Martyn Russell + */ + +#include "config.h" + +#include +#include +#include + +#include +#include + +#include "empathy-debug.h" +#include "empathy-chatroom-manager.h" +#include "empathy-utils.h" + +#define DEBUG_DOMAIN "ChatroomManager" + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CHATROOM_MANAGER, EmpathyChatroomManagerPriv)) + +#define CHATROOMS_XML_FILENAME "chatrooms.xml" +#define CHATROOMS_DTD_FILENAME "empathy-chatroom-manager.dtd" + +struct _EmpathyChatroomManagerPriv { + GList *chatrooms; +}; + +static void empathy_chatroom_manager_class_init (EmpathyChatroomManagerClass *klass); +static void empathy_chatroom_manager_init (EmpathyChatroomManager *manager); +static void chatroom_manager_finalize (GObject *object); +static gboolean chatroom_manager_get_all (EmpathyChatroomManager *manager); +static gboolean chatroom_manager_file_parse (EmpathyChatroomManager *manager, + const gchar *filename); +static void chatroom_manager_parse_chatroom (EmpathyChatroomManager *manager, + xmlNodePtr node); +static gboolean chatroom_manager_file_save (EmpathyChatroomManager *manager); + +enum { + CHATROOM_ADDED, + CHATROOM_REMOVED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +G_DEFINE_TYPE (EmpathyChatroomManager, empathy_chatroom_manager, G_TYPE_OBJECT); + +static void +empathy_chatroom_manager_class_init (EmpathyChatroomManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = chatroom_manager_finalize; + + signals[CHATROOM_ADDED] = + g_signal_new ("chatroom-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, EMPATHY_TYPE_CHATROOM); + signals[CHATROOM_REMOVED] = + g_signal_new ("chatroom-removed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, EMPATHY_TYPE_CHATROOM); + + g_type_class_add_private (object_class, + sizeof (EmpathyChatroomManagerPriv)); +} + +static void +empathy_chatroom_manager_init (EmpathyChatroomManager *manager) +{ + EmpathyChatroomManagerPriv *priv; + + priv = GET_PRIV (manager); +} + +static void +chatroom_manager_finalize (GObject *object) +{ + EmpathyChatroomManagerPriv *priv; + + priv = GET_PRIV (object); + + g_list_foreach (priv->chatrooms, (GFunc) g_object_unref, NULL); + g_list_free (priv->chatrooms); + + (G_OBJECT_CLASS (empathy_chatroom_manager_parent_class)->finalize) (object); +} + +EmpathyChatroomManager * +empathy_chatroom_manager_new (void) +{ + static EmpathyChatroomManager *manager = NULL; + + if (!manager) { + EmpathyChatroomManagerPriv *priv; + + manager = g_object_new (EMPATHY_TYPE_CHATROOM_MANAGER, NULL); + priv = GET_PRIV (manager); + chatroom_manager_get_all (manager); + + g_object_add_weak_pointer (G_OBJECT (manager), (gpointer) &manager); + } else { + g_object_ref (manager); + } + + return manager; +} + +gboolean +empathy_chatroom_manager_add (EmpathyChatroomManager *manager, + EmpathyChatroom *chatroom) +{ + EmpathyChatroomManagerPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager), FALSE); + g_return_val_if_fail (EMPATHY_IS_CHATROOM (chatroom), FALSE); + + priv = GET_PRIV (manager); + + /* don't add more than once */ + if (!empathy_chatroom_manager_find (manager, + empathy_chatroom_get_account (chatroom), + empathy_chatroom_get_room (chatroom))) { + priv->chatrooms = g_list_prepend (priv->chatrooms, g_object_ref (chatroom)); + chatroom_manager_file_save (manager); + + g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom); + + return TRUE; + } + + return FALSE; +} + +void +empathy_chatroom_manager_remove (EmpathyChatroomManager *manager, + EmpathyChatroom *chatroom) +{ + EmpathyChatroomManagerPriv *priv; + GList *l; + + g_return_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager)); + g_return_if_fail (EMPATHY_IS_CHATROOM (chatroom)); + + priv = GET_PRIV (manager); + + for (l = priv->chatrooms; l; l = l->next) { + EmpathyChatroom *this_chatroom; + + this_chatroom = l->data; + + if (empathy_chatroom_equal (chatroom, this_chatroom)) { + priv->chatrooms = g_list_delete_link (priv->chatrooms, l); + + chatroom_manager_file_save (manager); + + g_signal_emit (manager, signals[CHATROOM_REMOVED], 0, this_chatroom); + g_object_unref (this_chatroom); + break; + } + } +} + +EmpathyChatroom * +empathy_chatroom_manager_find (EmpathyChatroomManager *manager, + McAccount *account, + const gchar *room) +{ + EmpathyChatroomManagerPriv *priv; + GList *l; + + g_return_val_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager), NULL); + g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + g_return_val_if_fail (room != NULL, NULL); + + priv = GET_PRIV (manager); + + for (l = priv->chatrooms; l; l = l->next) { + EmpathyChatroom *chatroom; + McAccount *this_account; + const gchar *this_room; + + chatroom = l->data; + this_account = empathy_chatroom_get_account (chatroom); + this_room = empathy_chatroom_get_room (chatroom); + + if (this_account && this_room && + empathy_account_equal (account, this_account) && + strcmp (this_room, room) == 0) { + return chatroom; + } + } + + return NULL; +} + +GList * +empathy_chatroom_manager_get_chatrooms (EmpathyChatroomManager *manager, + McAccount *account) +{ + EmpathyChatroomManagerPriv *priv; + GList *chatrooms, *l; + + g_return_val_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager), NULL); + + priv = GET_PRIV (manager); + + if (!account) { + return g_list_copy (priv->chatrooms); + } + + chatrooms = NULL; + for (l = priv->chatrooms; l; l = l->next) { + EmpathyChatroom *chatroom; + + chatroom = l->data; + + if (empathy_account_equal (account, + empathy_chatroom_get_account (chatroom))) { + chatrooms = g_list_append (chatrooms, chatroom); + } + } + + return chatrooms; +} + +guint +empathy_chatroom_manager_get_count (EmpathyChatroomManager *manager, + McAccount *account) +{ + EmpathyChatroomManagerPriv *priv; + GList *l; + guint count = 0; + + g_return_val_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager), 0); + + priv = GET_PRIV (manager); + + if (!account) { + return g_list_length (priv->chatrooms); + } + + for (l = priv->chatrooms; l; l = l->next) { + EmpathyChatroom *chatroom; + + chatroom = l->data; + + if (empathy_account_equal (account, + empathy_chatroom_get_account (chatroom))) { + count++; + } + } + + return count; +} + +void +empathy_chatroom_manager_store (EmpathyChatroomManager *manager) +{ + g_return_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager)); + + chatroom_manager_file_save (manager); +} + +/* + * API to save/load and parse the chatrooms file. + */ + +static gboolean +chatroom_manager_get_all (EmpathyChatroomManager *manager) +{ + EmpathyChatroomManagerPriv *priv; + gchar *dir; + gchar *file_with_path = NULL; + + priv = GET_PRIV (manager); + + dir = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, NULL); + if (!g_file_test (dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { + g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR); + } + + file_with_path = g_build_filename (dir, CHATROOMS_XML_FILENAME, NULL); + g_free (dir); + + /* read file in */ + if (g_file_test (file_with_path, G_FILE_TEST_EXISTS) && + !chatroom_manager_file_parse (manager, file_with_path)) { + g_free (file_with_path); + return FALSE; + } + + g_free (file_with_path); + + return TRUE; +} + +static gboolean +chatroom_manager_file_parse (EmpathyChatroomManager *manager, + const gchar *filename) +{ + EmpathyChatroomManagerPriv *priv; + xmlParserCtxtPtr ctxt; + xmlDocPtr doc; + xmlNodePtr chatrooms; + xmlNodePtr node; + + priv = GET_PRIV (manager); + + empathy_debug (DEBUG_DOMAIN, "Attempting to parse file:'%s'...", filename); + + ctxt = xmlNewParserCtxt (); + + /* Parse and validate the file. */ + doc = xmlCtxtReadFile (ctxt, filename, NULL, 0); + if (!doc) { + g_warning ("Failed to parse file:'%s'", filename); + xmlFreeParserCtxt (ctxt); + return FALSE; + } + + if (!empathy_xml_validate (doc, CHATROOMS_DTD_FILENAME)) { + g_warning ("Failed to validate file:'%s'", filename); + xmlFreeDoc(doc); + xmlFreeParserCtxt (ctxt); + return FALSE; + } + + /* The root node, chatrooms. */ + chatrooms = xmlDocGetRootElement (doc); + + for (node = chatrooms->children; node; node = node->next) { + if (strcmp ((gchar *) node->name, "chatroom") == 0) { + chatroom_manager_parse_chatroom (manager, node); + } + } + + empathy_debug (DEBUG_DOMAIN, + "Parsed %d chatrooms", + g_list_length (priv->chatrooms)); + + xmlFreeDoc(doc); + xmlFreeParserCtxt (ctxt); + + return TRUE; +} + +static void +chatroom_manager_parse_chatroom (EmpathyChatroomManager *manager, + xmlNodePtr node) +{ + EmpathyChatroomManagerPriv *priv; + EmpathyChatroom *chatroom; + McAccount *account; + xmlNodePtr child; + gchar *str; + gchar *name; + gchar *room; + gchar *account_id; + gboolean auto_connect; + + priv = GET_PRIV (manager); + + /* default values. */ + name = NULL; + room = NULL; + auto_connect = TRUE; + account_id = NULL; + + for (child = node->children; child; child = child->next) { + gchar *tag; + + if (xmlNodeIsText (child)) { + continue; + } + + tag = (gchar *) child->name; + str = (gchar *) xmlNodeGetContent (child); + + if (strcmp (tag, "name") == 0) { + name = g_strdup (str); + } + else if (strcmp (tag, "room") == 0) { + room = g_strdup (str); + } + else if (strcmp (tag, "auto_connect") == 0) { + if (strcmp (str, "yes") == 0) { + auto_connect = TRUE; + } else { + auto_connect = FALSE; + } + } + else if (strcmp (tag, "account") == 0) { + account_id = g_strdup (str); + } + + xmlFree (str); + } + + account = mc_account_lookup (account_id); + if (!account) { + g_free (name); + g_free (room); + g_free (account_id); + return; + } + + chatroom = empathy_chatroom_new_full (account, room, name, auto_connect); + priv->chatrooms = g_list_prepend (priv->chatrooms, chatroom); + g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom); + + g_object_unref (account); + g_free (name); + g_free (room); + g_free (account_id); +} + +static gboolean +chatroom_manager_file_save (EmpathyChatroomManager *manager) +{ + EmpathyChatroomManagerPriv *priv; + xmlDocPtr doc; + xmlNodePtr root; + GList *l; + gchar *dir; + gchar *file; + + priv = GET_PRIV (manager); + + dir = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, NULL); + if (!g_file_test (dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { + g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR); + } + + file = g_build_filename (dir, CHATROOMS_XML_FILENAME, NULL); + g_free (dir); + + doc = xmlNewDoc ("1.0"); + root = xmlNewNode (NULL, "chatrooms"); + xmlDocSetRootElement (doc, root); + + for (l = priv->chatrooms; l; l = l->next) { + EmpathyChatroom *chatroom; + xmlNodePtr node; + const gchar *account_id; + + chatroom = l->data; + account_id = mc_account_get_unique_name (empathy_chatroom_get_account (chatroom)); + + node = xmlNewChild (root, NULL, "chatroom", NULL); + xmlNewTextChild (node, NULL, "name", empathy_chatroom_get_name (chatroom)); + xmlNewTextChild (node, NULL, "room", empathy_chatroom_get_room (chatroom)); + xmlNewTextChild (node, NULL, "account", account_id); + xmlNewTextChild (node, NULL, "auto_connect", empathy_chatroom_get_auto_connect (chatroom) ? "yes" : "no"); + } + + /* Make sure the XML is indented properly */ + xmlIndentTreeOutput = 1; + + empathy_debug (DEBUG_DOMAIN, "Saving file:'%s'", file); + xmlSaveFormatFileEnc (file, doc, "utf-8", 1); + xmlFreeDoc (doc); + + xmlCleanupParser (); + xmlMemoryDump (); + + g_free (file); + + return TRUE; +} diff --git a/libempathy/empathy-chatroom-manager.dtd b/libempathy/empathy-chatroom-manager.dtd new file mode 100644 index 00000000..df6b953f --- /dev/null +++ b/libempathy/empathy-chatroom-manager.dtd @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/libempathy/empathy-chatroom-manager.h b/libempathy/empathy-chatroom-manager.h new file mode 100644 index 00000000..758aa29c --- /dev/null +++ b/libempathy/empathy-chatroom-manager.h @@ -0,0 +1,72 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Xavier Claessens + * Martyn Russell + */ + +#ifndef __EMPATHY_CHATROOM_MANAGER_H__ +#define __EMPATHY_CHATROOM_MANAGER_H__ + +#include + +#include + +#include "empathy-chatroom.h" + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_CHATROOM_MANAGER (empathy_chatroom_manager_get_type ()) +#define EMPATHY_CHATROOM_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_CHATROOM_MANAGER, EmpathyChatroomManager)) +#define EMPATHY_CHATROOM_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_CHATROOM_MANAGER, EmpathyChatroomManagerClass)) +#define EMPATHY_IS_CHATROOM_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_CHATROOM_MANAGER)) +#define EMPATHY_IS_CHATROOM_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_CHATROOM_MANAGER)) +#define EMPATHY_CHATROOM_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_CHATROOM_MANAGER, EmpathyChatroomManagerClass)) + +typedef struct _EmpathyChatroomManager EmpathyChatroomManager; +typedef struct _EmpathyChatroomManagerClass EmpathyChatroomManagerClass; +typedef struct _EmpathyChatroomManagerPriv EmpathyChatroomManagerPriv; + +struct _EmpathyChatroomManager { + GObject parent; +}; + +struct _EmpathyChatroomManagerClass { + GObjectClass parent_class; +}; + +GType empathy_chatroom_manager_get_type (void) G_GNUC_CONST; +EmpathyChatroomManager *empathy_chatroom_manager_new (void); +gboolean empathy_chatroom_manager_add (EmpathyChatroomManager *manager, + EmpathyChatroom *chatroom); +void empathy_chatroom_manager_remove (EmpathyChatroomManager *manager, + EmpathyChatroom *chatroom); +EmpathyChatroom * empathy_chatroom_manager_find (EmpathyChatroomManager *manager, + McAccount *account, + const gchar *room); +GList * empathy_chatroom_manager_get_chatrooms (EmpathyChatroomManager *manager, + McAccount *account); +guint empathy_chatroom_manager_get_count (EmpathyChatroomManager *manager, + McAccount *account); +void empathy_chatroom_manager_store (EmpathyChatroomManager *manager); + +G_END_DECLS + +#endif /* __EMPATHY_CHATROOM_MANAGER_H__ */ diff --git a/libempathy/empathy-chatroom.c b/libempathy/empathy-chatroom.c new file mode 100644 index 00000000..a2d8ae61 --- /dev/null +++ b/libempathy/empathy-chatroom.c @@ -0,0 +1,362 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Xavier Claessens + */ + +#include "config.h" + +#include + +#include + +#include "empathy-chatroom.h" +#include "empathy-utils.h" + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CHATROOM, EmpathyChatroomPriv)) + +struct _EmpathyChatroomPriv { + McAccount *account; + gchar *room; + gchar *name; + gboolean auto_connect; +}; + +static void empathy_chatroom_class_init (EmpathyChatroomClass *klass); +static void empathy_chatroom_init (EmpathyChatroom *chatroom); +static void chatroom_finalize (GObject *object); +static void chatroom_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); +static void chatroom_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); + +enum { + PROP_0, + PROP_ACCOUNT, + PROP_ROOM, + PROP_NAME, + PROP_AUTO_CONNECT, +}; + +G_DEFINE_TYPE (EmpathyChatroom, empathy_chatroom, G_TYPE_OBJECT); + +static void +empathy_chatroom_class_init (EmpathyChatroomClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = chatroom_finalize; + object_class->get_property = chatroom_get_property; + object_class->set_property = chatroom_set_property; + + g_object_class_install_property (object_class, + PROP_ACCOUNT, + g_param_spec_object ("account", + "Chatroom Account", + "The account associated with an chatroom", + MC_TYPE_ACCOUNT, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_ROOM, + g_param_spec_string ("room", + "Chatroom Room", + "Chatroom represented as 'room@server'", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_NAME, + g_param_spec_string ("name", + "Chatroom Name", + "Chatroom name", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_AUTO_CONNECT, + g_param_spec_boolean ("auto_connect", + "Chatroom Auto Connect", + "Connect on startup", + FALSE, + G_PARAM_READWRITE)); + + + g_type_class_add_private (object_class, sizeof (EmpathyChatroomPriv)); +} + +static void +empathy_chatroom_init (EmpathyChatroom *chatroom) +{ +} + +static void +chatroom_finalize (GObject *object) +{ + EmpathyChatroomPriv *priv; + + priv = GET_PRIV (object); + + g_object_unref (priv->account); + g_free (priv->room); + g_free (priv->name); + + (G_OBJECT_CLASS (empathy_chatroom_parent_class)->finalize) (object); +} + +static void +chatroom_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + EmpathyChatroomPriv *priv; + + priv = GET_PRIV (object); + + switch (param_id) { + case PROP_ACCOUNT: + g_value_set_object (value, priv->account); + break; + case PROP_ROOM: + g_value_set_string (value, priv->room); + break; + case PROP_NAME: + g_value_set_string (value, priv->name); + break; + case PROP_AUTO_CONNECT: + g_value_set_boolean (value, priv->auto_connect); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + }; +} + +static void +chatroom_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + EmpathyChatroomPriv *priv; + + priv = GET_PRIV (object); + + switch (param_id) { + case PROP_ACCOUNT: + empathy_chatroom_set_account (EMPATHY_CHATROOM (object), + g_value_get_object (value)); + break; + case PROP_ROOM: + empathy_chatroom_set_room (EMPATHY_CHATROOM (object), + g_value_get_string (value)); + break; + case PROP_NAME: + empathy_chatroom_set_name (EMPATHY_CHATROOM (object), + g_value_get_string (value)); + break; + case PROP_AUTO_CONNECT: + empathy_chatroom_set_auto_connect (EMPATHY_CHATROOM (object), + g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + }; +} + +EmpathyChatroom * +empathy_chatroom_new (McAccount *account, + const gchar *room) +{ + g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + g_return_val_if_fail (room != NULL, NULL); + + return g_object_new (EMPATHY_TYPE_CHATROOM, + "account", account, + "room", room, + NULL); +} + +EmpathyChatroom * +empathy_chatroom_new_full (McAccount *account, + const gchar *room, + const gchar *name, + gboolean auto_connect) +{ + g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + g_return_val_if_fail (room != NULL, NULL); + + return g_object_new (EMPATHY_TYPE_CHATROOM, + "account", account, + "room", room, + "name", name, + "auto_connect", auto_connect, + NULL); +} + +McAccount * +empathy_chatroom_get_account (EmpathyChatroom *chatroom) +{ + EmpathyChatroomPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CHATROOM (chatroom), NULL); + + priv = GET_PRIV (chatroom); + return priv->account; +} + +void +empathy_chatroom_set_account (EmpathyChatroom *chatroom, + McAccount *account) +{ + EmpathyChatroomPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHATROOM (chatroom)); + g_return_if_fail (MC_IS_ACCOUNT (account)); + + priv = GET_PRIV (chatroom); + + if (account == priv->account) { + return; + } + if (priv->account) { + g_object_unref (priv->account); + } + priv->account = g_object_ref (account); + + g_object_notify (G_OBJECT (chatroom), "account"); +} + +const gchar * +empathy_chatroom_get_room (EmpathyChatroom *chatroom) +{ + EmpathyChatroomPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CHATROOM (chatroom), NULL); + + priv = GET_PRIV (chatroom); + return priv->room; +} + +void +empathy_chatroom_set_room (EmpathyChatroom *chatroom, + const gchar *room) +{ + EmpathyChatroomPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHATROOM (chatroom)); + g_return_if_fail (room != NULL); + + priv = GET_PRIV (chatroom); + + g_free (priv->room); + priv->room = g_strdup (room); + + g_object_notify (G_OBJECT (chatroom), "room"); +} + +const gchar * +empathy_chatroom_get_name (EmpathyChatroom *chatroom) +{ + EmpathyChatroomPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CHATROOM (chatroom), NULL); + + priv = GET_PRIV (chatroom); + + if (G_STR_EMPTY (priv->name)) { + return priv->room; + } + + return priv->name; +} + +void +empathy_chatroom_set_name (EmpathyChatroom *chatroom, + const gchar *name) +{ + EmpathyChatroomPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHATROOM (chatroom)); + + priv = GET_PRIV (chatroom); + + g_free (priv->name); + priv->name = NULL; + if (name) { + priv->name = g_strdup (name); + } + + g_object_notify (G_OBJECT (chatroom), "name"); +} + +gboolean +empathy_chatroom_get_auto_connect (EmpathyChatroom *chatroom) +{ + EmpathyChatroomPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CHATROOM (chatroom), FALSE); + + priv = GET_PRIV (chatroom); + return priv->auto_connect; +} + +void +empathy_chatroom_set_auto_connect (EmpathyChatroom *chatroom, + gboolean auto_connect) +{ + EmpathyChatroomPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHATROOM (chatroom)); + + priv = GET_PRIV (chatroom); + + priv->auto_connect = auto_connect; + + g_object_notify (G_OBJECT (chatroom), "auto-connect"); +} + +gboolean +empathy_chatroom_equal (gconstpointer v1, + gconstpointer v2) +{ + McAccount *account_a; + McAccount *account_b; + const gchar *room_a; + const gchar *room_b; + + g_return_val_if_fail (EMPATHY_IS_CHATROOM (v1), FALSE); + g_return_val_if_fail (EMPATHY_IS_CHATROOM (v2), FALSE); + + account_a = empathy_chatroom_get_account (EMPATHY_CHATROOM (v1)); + account_b = empathy_chatroom_get_account (EMPATHY_CHATROOM (v2)); + + room_a = empathy_chatroom_get_room (EMPATHY_CHATROOM (v1)); + room_b = empathy_chatroom_get_room (EMPATHY_CHATROOM (v2)); + + return empathy_account_equal (account_a, account_b) && g_str_equal (room_a, room_b); +} + + diff --git a/libempathy/empathy-chatroom.h b/libempathy/empathy-chatroom.h new file mode 100644 index 00000000..20f98ecc --- /dev/null +++ b/libempathy/empathy-chatroom.h @@ -0,0 +1,78 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Xavier Claessens + */ + +#ifndef __EMPATHY_CHATROOM_H__ +#define __EMPATHY_CHATROOM_H__ + +#include + +#include + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_CHATROOM (empathy_chatroom_get_type ()) +#define EMPATHY_CHATROOM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_CHATROOM, EmpathyChatroom)) +#define EMPATHY_CHATROOM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_CHATROOM, EmpathyChatroomClass)) +#define EMPATHY_IS_CHATROOM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_CHATROOM)) +#define EMPATHY_IS_CHATROOM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_CHATROOM)) +#define EMPATHY_CHATROOM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_CHATROOM, EmpathyChatroomClass)) + +#define EMPATHY_TYPE_CHATROOM_INVITE (empathy_chatroom_invite_get_gtype ()) + +typedef struct _EmpathyChatroom EmpathyChatroom; +typedef struct _EmpathyChatroomClass EmpathyChatroomClass; +typedef struct _EmpathyChatroomPriv EmpathyChatroomPriv; + +struct _EmpathyChatroom { + GObject parent; +}; + +struct _EmpathyChatroomClass { + GObjectClass parent_class; +}; + +GType empathy_chatroom_get_type (void) G_GNUC_CONST; +EmpathyChatroom *empathy_chatroom_new (McAccount *account, + const gchar *room); +EmpathyChatroom *empathy_chatroom_new_full (McAccount *account, + const gchar *room, + const gchar *name, + gboolean auto_connect); +McAccount * empathy_chatroom_get_account (EmpathyChatroom *chatroom); +void empathy_chatroom_set_account (EmpathyChatroom *chatroom, + McAccount *account); +const gchar * empathy_chatroom_get_room (EmpathyChatroom *chatroom); +void empathy_chatroom_set_room (EmpathyChatroom *chatroom, + const gchar *room); +const gchar * empathy_chatroom_get_name (EmpathyChatroom *chatroom); +void empathy_chatroom_set_name (EmpathyChatroom *chatroom, + const gchar *name); +gboolean empathy_chatroom_get_auto_connect (EmpathyChatroom *chatroom); +void empathy_chatroom_set_auto_connect (EmpathyChatroom *chatroom, + gboolean auto_connect); +gboolean empathy_chatroom_equal (gconstpointer v1, + gconstpointer v2); + + +G_BEGIN_DECLS + +#endif /* __EMPATHY_CHATROOM_H__ */ diff --git a/libempathy/empathy-conf.c b/libempathy/empathy-conf.c new file mode 100644 index 00000000..71e520f7 --- /dev/null +++ b/libempathy/empathy-conf.c @@ -0,0 +1,372 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Richard Hult + */ + +#include "config.h" + +#include + +#include + +#include "empathy-conf.h" +#include "empathy-debug.h" + +#define DEBUG_DOMAIN "Config" + +#define EMPATHY_CONF_ROOT "/apps/empathy" +#define DESKTOP_INTERFACE_ROOT "/desktop/gnome/interface" + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CONF, EmpathyConfPriv)) + +typedef struct { + GConfClient *gconf_client; +} EmpathyConfPriv; + +typedef struct { + EmpathyConf *conf; + EmpathyConfNotifyFunc func; + gpointer user_data; +} EmpathyConfNotifyData; + +static void conf_finalize (GObject *object); + +G_DEFINE_TYPE (EmpathyConf, empathy_conf, G_TYPE_OBJECT); + +static EmpathyConf *global_conf = NULL; + +static void +empathy_conf_class_init (EmpathyConfClass *class) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (class); + + object_class->finalize = conf_finalize; + + g_type_class_add_private (object_class, sizeof (EmpathyConfPriv)); +} + +static void +empathy_conf_init (EmpathyConf *conf) +{ + EmpathyConfPriv *priv; + + priv = GET_PRIV (conf); + + priv->gconf_client = gconf_client_get_default (); + + gconf_client_add_dir (priv->gconf_client, + EMPATHY_CONF_ROOT, + GCONF_CLIENT_PRELOAD_ONELEVEL, + NULL); + gconf_client_add_dir (priv->gconf_client, + DESKTOP_INTERFACE_ROOT, + GCONF_CLIENT_PRELOAD_NONE, + NULL); +} + +static void +conf_finalize (GObject *object) +{ + EmpathyConfPriv *priv; + + priv = GET_PRIV (object); + + gconf_client_remove_dir (priv->gconf_client, + EMPATHY_CONF_ROOT, + NULL); + gconf_client_remove_dir (priv->gconf_client, + DESKTOP_INTERFACE_ROOT, + NULL); + + g_object_unref (priv->gconf_client); + + G_OBJECT_CLASS (empathy_conf_parent_class)->finalize (object); +} + +EmpathyConf * +empathy_conf_get (void) +{ + if (!global_conf) { + global_conf = g_object_new (EMPATHY_TYPE_CONF, NULL); + } + + return global_conf; +} + +void +empathy_conf_shutdown (void) +{ + if (global_conf) { + g_object_unref (global_conf); + global_conf = NULL; + } +} + +gboolean +empathy_conf_set_int (EmpathyConf *conf, + const gchar *key, + gint value) +{ + EmpathyConfPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONF (conf), FALSE); + + empathy_debug (DEBUG_DOMAIN, "Setting int:'%s' to %d", key, value); + + priv = GET_PRIV (conf); + + return gconf_client_set_int (priv->gconf_client, + key, + value, + NULL); +} + +gboolean +empathy_conf_get_int (EmpathyConf *conf, + const gchar *key, + gint *value) +{ + EmpathyConfPriv *priv; + GError *error = NULL; + + *value = 0; + + g_return_val_if_fail (EMPATHY_IS_CONF (conf), FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + priv = GET_PRIV (conf); + + *value = gconf_client_get_int (priv->gconf_client, + key, + &error); + + if (error) { + g_error_free (error); + return FALSE; + } + + return TRUE; +} + +gboolean +empathy_conf_set_bool (EmpathyConf *conf, + const gchar *key, + gboolean value) +{ + EmpathyConfPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONF (conf), FALSE); + + empathy_debug (DEBUG_DOMAIN, "Setting bool:'%s' to %d ---> %s", + key, value, value ? "true" : "false"); + + priv = GET_PRIV (conf); + + return gconf_client_set_bool (priv->gconf_client, + key, + value, + NULL); +} + +gboolean +empathy_conf_get_bool (EmpathyConf *conf, + const gchar *key, + gboolean *value) +{ + EmpathyConfPriv *priv; + GError *error = NULL; + + *value = FALSE; + + g_return_val_if_fail (EMPATHY_IS_CONF (conf), FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + priv = GET_PRIV (conf); + + *value = gconf_client_get_bool (priv->gconf_client, + key, + &error); + + if (error) { + g_error_free (error); + return FALSE; + } + + return TRUE; +} + +gboolean +empathy_conf_set_string (EmpathyConf *conf, + const gchar *key, + const gchar *value) +{ + EmpathyConfPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONF (conf), FALSE); + + empathy_debug (DEBUG_DOMAIN, "Setting string:'%s' to '%s'", + key, value); + + priv = GET_PRIV (conf); + + return gconf_client_set_string (priv->gconf_client, + key, + value, + NULL); +} + +gboolean +empathy_conf_get_string (EmpathyConf *conf, + const gchar *key, + gchar **value) +{ + EmpathyConfPriv *priv; + GError *error = NULL; + + *value = NULL; + + g_return_val_if_fail (EMPATHY_IS_CONF (conf), FALSE); + + priv = GET_PRIV (conf); + + *value = gconf_client_get_string (priv->gconf_client, + key, + &error); + + if (error) { + g_error_free (error); + return FALSE; + } + + return TRUE; +} + +gboolean +empathy_conf_set_string_list (EmpathyConf *conf, + const gchar *key, + GSList *value) +{ + EmpathyConfPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONF (conf), FALSE); + + priv = GET_PRIV (conf); + + return gconf_client_set_list (priv->gconf_client, + key, + GCONF_VALUE_STRING, + value, + NULL); +} + +gboolean +empathy_conf_get_string_list (EmpathyConf *conf, + const gchar *key, + GSList **value) +{ + EmpathyConfPriv *priv; + GError *error = NULL; + + *value = NULL; + + g_return_val_if_fail (EMPATHY_IS_CONF (conf), FALSE); + + priv = GET_PRIV (conf); + + *value = gconf_client_get_list (priv->gconf_client, + key, + GCONF_VALUE_STRING, + &error); + if (error) { + g_error_free (error); + return FALSE; + } + + return TRUE; +} + +static void +conf_notify_data_free (EmpathyConfNotifyData *data) +{ + g_object_unref (data->conf); + g_slice_free (EmpathyConfNotifyData, data); +} + +static void +conf_notify_func (GConfClient *client, + guint id, + GConfEntry *entry, + gpointer user_data) +{ + EmpathyConfNotifyData *data; + + data = user_data; + + data->func (data->conf, + gconf_entry_get_key (entry), + data->user_data); +} + +guint +empathy_conf_notify_add (EmpathyConf *conf, + const gchar *key, + EmpathyConfNotifyFunc func, + gpointer user_data) +{ + EmpathyConfPriv *priv; + guint id; + EmpathyConfNotifyData *data; + + g_return_val_if_fail (EMPATHY_IS_CONF (conf), 0); + + priv = GET_PRIV (conf); + + data = g_slice_new (EmpathyConfNotifyData); + data->func = func; + data->user_data = user_data; + data->conf = g_object_ref (conf); + + id = gconf_client_notify_add (priv->gconf_client, + key, + conf_notify_func, + data, + (GFreeFunc) conf_notify_data_free, + NULL); + + return id; +} + +gboolean +empathy_conf_notify_remove (EmpathyConf *conf, + guint id) +{ + EmpathyConfPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONF (conf), FALSE); + + priv = GET_PRIV (conf); + + gconf_client_notify_remove (priv->gconf_client, id); + + return TRUE; +} + diff --git a/libempathy/empathy-conf.h b/libempathy/empathy-conf.h new file mode 100644 index 00000000..7e8e60e2 --- /dev/null +++ b/libempathy/empathy-conf.h @@ -0,0 +1,87 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EMPATHY_CONF_H__ +#define __EMPATHY_CONF_H__ + +#include + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_CONF (empathy_conf_get_type ()) +#define EMPATHY_CONF(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_CONF, EmpathyConf)) +#define EMPATHY_CONF_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_CONF, EmpathyConfClass)) +#define EMPATHY_IS_CONF(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_CONF)) +#define EMPATHY_IS_CONF_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_CONF)) +#define EMPATHY_CONF_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_CONF, EmpathyConfClass)) + +typedef struct _EmpathyConf EmpathyConf; +typedef struct _EmpathyConfClass EmpathyConfClass; + +struct _EmpathyConf { + GObject parent; +}; + +struct _EmpathyConfClass { + GObjectClass parent_class; +}; + +typedef void (*EmpathyConfNotifyFunc) (EmpathyConf *conf, + const gchar *key, + gpointer user_data); + +GType empathy_conf_get_type (void) G_GNUC_CONST; +EmpathyConf *empathy_conf_get (void); +void empathy_conf_shutdown (void); +guint empathy_conf_notify_add (EmpathyConf *conf, + const gchar *key, + EmpathyConfNotifyFunc func, + gpointer data); +gboolean empathy_conf_notify_remove (EmpathyConf *conf, + guint id); +gboolean empathy_conf_set_int (EmpathyConf *conf, + const gchar *key, + gint value); +gboolean empathy_conf_get_int (EmpathyConf *conf, + const gchar *key, + gint *value); +gboolean empathy_conf_set_bool (EmpathyConf *conf, + const gchar *key, + gboolean value); +gboolean empathy_conf_get_bool (EmpathyConf *conf, + const gchar *key, + gboolean *value); +gboolean empathy_conf_set_string (EmpathyConf *conf, + const gchar *key, + const gchar *value); +gboolean empathy_conf_get_string (EmpathyConf *conf, + const gchar *key, + gchar **value); +gboolean empathy_conf_set_string_list (EmpathyConf *conf, + const gchar *key, + GSList *value); +gboolean empathy_conf_get_string_list (EmpathyConf *conf, + const gchar *key, + GSList **value); + +G_END_DECLS + +#endif /* __EMPATHY_CONF_H__ */ + diff --git a/libempathy/empathy-contact-list.c b/libempathy/empathy-contact-list.c index 3dd398c0..cc388d7e 100644 --- a/libempathy/empathy-contact-list.c +++ b/libempathy/empathy-contact-list.c @@ -60,7 +60,7 @@ contact_list_base_init (gpointer klass) NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, - 1, GOSSIP_TYPE_CONTACT); + 1, EMPATHY_TYPE_CONTACT); g_signal_new ("contact-removed", G_TYPE_FROM_CLASS (klass), @@ -69,7 +69,7 @@ contact_list_base_init (gpointer klass) NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, - 1, GOSSIP_TYPE_CONTACT); + 1, EMPATHY_TYPE_CONTACT); g_signal_new ("local-pending", G_TYPE_FROM_CLASS (klass), @@ -78,19 +78,19 @@ contact_list_base_init (gpointer klass) NULL, NULL, empathy_marshal_VOID__OBJECT_STRING, G_TYPE_NONE, - 2, GOSSIP_TYPE_CONTACT, G_TYPE_STRING); + 2, EMPATHY_TYPE_CONTACT, G_TYPE_STRING); initialized = TRUE; } } EmpathyContactListInfo * -empathy_contact_list_info_new (GossipContact *contact, +empathy_contact_list_info_new (EmpathyContact *contact, const gchar *message) { EmpathyContactListInfo *info; - g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL); + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); info = g_slice_new0 (EmpathyContactListInfo); info->contact = g_object_ref (contact); @@ -124,7 +124,7 @@ empathy_contact_list_setup (EmpathyContactList *list) } } -GossipContact * +EmpathyContact * empathy_contact_list_find (EmpathyContactList *list, const gchar *id) { @@ -139,7 +139,7 @@ empathy_contact_list_find (EmpathyContactList *list, void empathy_contact_list_add (EmpathyContactList *list, - GossipContact *contact, + EmpathyContact *contact, const gchar *message) { g_return_if_fail (EMPATHY_IS_CONTACT_LIST (list)); @@ -151,7 +151,7 @@ empathy_contact_list_add (EmpathyContactList *list, void empathy_contact_list_remove (EmpathyContactList *list, - GossipContact *contact, + EmpathyContact *contact, const gchar *message) { g_return_if_fail (EMPATHY_IS_CONTACT_LIST (list)); @@ -187,7 +187,7 @@ empathy_contact_list_get_local_pending (EmpathyContactList *list) void empathy_contact_list_process_pending (EmpathyContactList *list, - GossipContact *contact, + EmpathyContact *contact, gboolean accept) { g_return_if_fail (EMPATHY_IS_CONTACT_LIST (list)); diff --git a/libempathy/empathy-contact-list.h b/libempathy/empathy-contact-list.h index c1f9b41e..959f5c51 100644 --- a/libempathy/empathy-contact-list.h +++ b/libempathy/empathy-contact-list.h @@ -25,7 +25,7 @@ #include -#include "gossip-contact.h" +#include "empathy-contact.h" G_BEGIN_DECLS @@ -38,7 +38,7 @@ typedef struct _EmpathyContactList EmpathyContactList; typedef struct _EmpathyContactListIface EmpathyContactListIface; typedef struct { - GossipContact *contact; + EmpathyContact *contact; gchar *message; } EmpathyContactListInfo; @@ -47,38 +47,38 @@ struct _EmpathyContactListIface { /* VTabled */ void (*setup) (EmpathyContactList *list); - GossipContact * (*find) (EmpathyContactList *list, + EmpathyContact * (*find) (EmpathyContactList *list, const gchar *id); void (*add) (EmpathyContactList *list, - GossipContact *contact, + EmpathyContact *contact, const gchar *message); void (*remove) (EmpathyContactList *list, - GossipContact *contact, + EmpathyContact *contact, const gchar *message); GList * (*get_members) (EmpathyContactList *list); GList * (*get_local_pending) (EmpathyContactList *list); void (*process_pending) (EmpathyContactList *list, - GossipContact *contact, + EmpathyContact *contact, gboolean accept); }; GType empathy_contact_list_get_type (void) G_GNUC_CONST; -EmpathyContactListInfo *empathy_contact_list_info_new (GossipContact *contact, +EmpathyContactListInfo *empathy_contact_list_info_new (EmpathyContact *contact, const gchar *message); void empathy_contact_list_info_free (EmpathyContactListInfo *info); void empathy_contact_list_setup (EmpathyContactList *list); -GossipContact * empathy_contact_list_find (EmpathyContactList *list, +EmpathyContact * empathy_contact_list_find (EmpathyContactList *list, const gchar *id); void empathy_contact_list_add (EmpathyContactList *list, - GossipContact *contact, + EmpathyContact *contact, const gchar *message); void empathy_contact_list_remove (EmpathyContactList *list, - GossipContact *contact, + EmpathyContact *contact, const gchar *message); GList * empathy_contact_list_get_members (EmpathyContactList *list); GList * empathy_contact_list_get_local_pending (EmpathyContactList *list); void empathy_contact_list_process_pending (EmpathyContactList *list, - GossipContact *contact, + EmpathyContact *contact, gboolean accept); G_END_DECLS diff --git a/libempathy/empathy-contact-manager.c b/libempathy/empathy-contact-manager.c index 7f8cdfed..cc00108c 100644 --- a/libempathy/empathy-contact-manager.c +++ b/libempathy/empathy-contact-manager.c @@ -28,8 +28,8 @@ #include "empathy-contact-manager.h" #include "empathy-contact-list.h" -#include "gossip-utils.h" -#include "gossip-debug.h" +#include "empathy-utils.h" +#include "empathy-debug.h" #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ EMPATHY_TYPE_CONTACT_MANAGER, EmpathyContactManagerPriv)) @@ -48,7 +48,7 @@ typedef struct { } ContactManagerRenameGroupData; typedef struct { - GossipContact *contact; + EmpathyContact *contact; const gchar *id; } ContactManagerFindData; @@ -57,18 +57,18 @@ static void contact_manager_iface_init (EmpathyContactListIf static void empathy_contact_manager_init (EmpathyContactManager *manager); static void contact_manager_finalize (GObject *object); static void contact_manager_setup (EmpathyContactList *manager); -static GossipContact *contact_manager_find (EmpathyContactList *manager, +static EmpathyContact *contact_manager_find (EmpathyContactList *manager, const gchar *id); static void contact_manager_add (EmpathyContactList *manager, - GossipContact *contact, + EmpathyContact *contact, const gchar *message); static void contact_manager_remove (EmpathyContactList *manager, - GossipContact *contact, + EmpathyContact *contact, const gchar *message); static GList * contact_manager_get_members (EmpathyContactList *manager); static GList * contact_manager_get_local_pending (EmpathyContactList *manager); static void contact_manager_process_pending (EmpathyContactList *manager, - GossipContact *contact, + EmpathyContact *contact, gboolean accept); static void contact_manager_setup_foreach (McAccount *account, EmpathyTpContactList *list, @@ -79,13 +79,13 @@ static gboolean contact_manager_find_foreach (McAccount static void contact_manager_add_account (EmpathyContactManager *manager, McAccount *account); static void contact_manager_added_cb (EmpathyTpContactList *list, - GossipContact *contact, + EmpathyContact *contact, EmpathyContactManager *manager); static void contact_manager_removed_cb (EmpathyTpContactList *list, - GossipContact *contact, + EmpathyContact *contact, EmpathyContactManager *manager); static void contact_manager_local_pending_cb (EmpathyTpContactList *list, - GossipContact *contact, + EmpathyContact *contact, const gchar *message, EmpathyContactManager *manager); static void contact_manager_destroy_cb (EmpathyTpContactList *list, @@ -143,12 +143,12 @@ empathy_contact_manager_init (EmpathyContactManager *manager) priv = GET_PRIV (manager); - priv->lists = g_hash_table_new_full (gossip_account_hash, - gossip_account_equal, + priv->lists = g_hash_table_new_full (empathy_account_hash, + empathy_account_equal, (GDestroyNotify) g_object_unref, (GDestroyNotify) g_object_unref); - priv->mc = gossip_mission_control_new (); + priv->mc = empathy_mission_control_new (); dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc), "AccountStatusChanged", @@ -215,7 +215,7 @@ contact_manager_setup (EmpathyContactList *manager) priv->setup = TRUE; } -static GossipContact * +static EmpathyContact * contact_manager_find (EmpathyContactList *manager, const gchar *id) { @@ -239,7 +239,7 @@ contact_manager_find (EmpathyContactList *manager, static void contact_manager_add (EmpathyContactList *manager, - GossipContact *contact, + EmpathyContact *contact, const gchar *message) { EmpathyContactManagerPriv *priv; @@ -247,11 +247,11 @@ contact_manager_add (EmpathyContactList *manager, McAccount *account; g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); priv = GET_PRIV (manager); - account = gossip_contact_get_account (contact); + account = empathy_contact_get_account (contact); list = g_hash_table_lookup (priv->lists, account); if (list) { @@ -261,7 +261,7 @@ contact_manager_add (EmpathyContactList *manager, static void contact_manager_remove (EmpathyContactList *manager, - GossipContact *contact, + EmpathyContact *contact, const gchar *message) { EmpathyContactManagerPriv *priv; @@ -269,11 +269,11 @@ contact_manager_remove (EmpathyContactList *manager, McAccount *account; g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); priv = GET_PRIV (manager); - account = gossip_contact_get_account (contact); + account = empathy_contact_get_account (contact); list = g_hash_table_lookup (priv->lists, account); if (list) { @@ -317,7 +317,7 @@ contact_manager_get_local_pending (EmpathyContactList *manager) static void contact_manager_process_pending (EmpathyContactList *manager, - GossipContact *contact, + EmpathyContact *contact, gboolean accept) { EmpathyContactManagerPriv *priv; @@ -325,11 +325,11 @@ contact_manager_process_pending (EmpathyContactList *manager, McAccount *account; g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); priv = GET_PRIV (manager); - account = gossip_contact_get_account (contact); + account = empathy_contact_get_account (contact); list = g_hash_table_lookup (priv->lists, account); if (list) { @@ -351,7 +351,7 @@ empathy_contact_manager_get_list (EmpathyContactManager *manager, return g_hash_table_lookup (priv->lists, account); } -GossipContact * +EmpathyContact * empathy_contact_manager_get_user (EmpathyContactManager *manager, McAccount *account) { @@ -372,7 +372,7 @@ empathy_contact_manager_get_user (EmpathyContactManager *manager, return empathy_tp_contact_list_get_user (list); } -GossipContact * +EmpathyContact * empathy_contact_manager_create (EmpathyContactManager *manager, McAccount *account, const gchar *id) @@ -470,7 +470,7 @@ contact_manager_add_account (EmpathyContactManager *manager, return; } - gossip_debug (DEBUG_DOMAIN, "Adding new account: %s", + empathy_debug (DEBUG_DOMAIN, "Adding new account: %s", mc_account_get_display_name (account)); list = empathy_tp_contact_list_new (account); @@ -501,7 +501,7 @@ contact_manager_add_account (EmpathyContactManager *manager, static void contact_manager_added_cb (EmpathyTpContactList *list, - GossipContact *contact, + EmpathyContact *contact, EmpathyContactManager *manager) { g_signal_emit_by_name (manager, "contact-added", contact); @@ -509,7 +509,7 @@ contact_manager_added_cb (EmpathyTpContactList *list, static void contact_manager_removed_cb (EmpathyTpContactList *list, - GossipContact *contact, + EmpathyContact *contact, EmpathyContactManager *manager) { g_signal_emit_by_name (manager, "contact-removed", contact); @@ -517,7 +517,7 @@ contact_manager_removed_cb (EmpathyTpContactList *list, static void contact_manager_local_pending_cb (EmpathyTpContactList *list, - GossipContact *contact, + EmpathyContact *contact, const gchar *message, EmpathyContactManager *manager) { @@ -535,7 +535,7 @@ contact_manager_destroy_cb (EmpathyTpContactList *list, account = empathy_tp_contact_list_get_account (list); - gossip_debug (DEBUG_DOMAIN, "Removing account: %s", + empathy_debug (DEBUG_DOMAIN, "Removing account: %s", mc_account_get_display_name (account)); /* Disconnect signals from the list */ diff --git a/libempathy/empathy-contact-manager.h b/libempathy/empathy-contact-manager.h index db893b48..768301ae 100644 --- a/libempathy/empathy-contact-manager.h +++ b/libempathy/empathy-contact-manager.h @@ -27,7 +27,7 @@ #include -#include "gossip-contact.h" +#include "empathy-contact.h" #include "empathy-tp-contact-list.h" G_BEGIN_DECLS @@ -55,9 +55,9 @@ GType empathy_contact_manager_get_type (void) G_GNUC_CONST; EmpathyContactManager *empathy_contact_manager_new (void); EmpathyTpContactList * empathy_contact_manager_get_list (EmpathyContactManager *manager, McAccount *account); -GossipContact * empathy_contact_manager_get_user (EmpathyContactManager *manager, +EmpathyContact * empathy_contact_manager_get_user (EmpathyContactManager *manager, McAccount *account); -GossipContact * empathy_contact_manager_create (EmpathyContactManager *manager, +EmpathyContact * empathy_contact_manager_create (EmpathyContactManager *manager, McAccount *account, const gchar *id); void empathy_contact_manager_rename_group (EmpathyContactManager *manager, diff --git a/libempathy/empathy-contact.c b/libempathy/empathy-contact.c new file mode 100644 index 00000000..774a18f7 --- /dev/null +++ b/libempathy/empathy-contact.c @@ -0,0 +1,800 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Martyn Russell + */ + +#include "config.h" + +#include + +#include + +#include "empathy-contact.h" +#include "empathy-utils.h" +#include "empathy-debug.h" + +#define DEBUG_DOMAIN "Contact" + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CONTACT, EmpathyContactPriv)) + +typedef struct _EmpathyContactPriv EmpathyContactPriv; + +struct _EmpathyContactPriv { + gchar *id; + gchar *name; + EmpathyAvatar *avatar; + McAccount *account; + EmpathyPresence *presence; + GList *groups; + EmpathySubscription subscription; + guint handle; + gboolean is_user; +}; + +static void contact_class_init (EmpathyContactClass *class); +static void contact_init (EmpathyContact *contact); +static void contact_finalize (GObject *object); +static void contact_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); +static void contact_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); + +enum { + PROP_0, + PROP_ID, + PROP_NAME, + PROP_AVATAR, + PROP_ACCOUNT, + PROP_PRESENCE, + PROP_GROUPS, + PROP_SUBSCRIPTION, + PROP_HANDLE, + PROP_IS_USER +}; + +static gpointer parent_class = NULL; + +GType +empathy_contact_get_gtype (void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof (EmpathyContactClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) contact_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EmpathyContact), + 0, /* n_preallocs */ + (GInstanceInitFunc) contact_init + }; + + type = g_type_register_static (G_TYPE_OBJECT, + "EmpathyContact", + &info, 0); + } + + return type; +} + +static void +contact_class_init (EmpathyContactClass *class) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (class); + parent_class = g_type_class_peek_parent (class); + + object_class->finalize = contact_finalize; + object_class->get_property = contact_get_property; + object_class->set_property = contact_set_property; + + g_object_class_install_property (object_class, + PROP_ID, + g_param_spec_string ("id", + "Contact id", + "String identifying contact", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_NAME, + g_param_spec_string ("name", + "Contact Name", + "The name of the contact", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_AVATAR, + g_param_spec_boxed ("avatar", + "Avatar image", + "The avatar image", + EMPATHY_TYPE_AVATAR, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_ACCOUNT, + g_param_spec_object ("account", + "Contact Account", + "The account associated with the contact", + MC_TYPE_ACCOUNT, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_PRESENCE, + g_param_spec_object ("presence", + "Contact presence", + "Presence of contact", + EMPATHY_TYPE_PRESENCE, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_GROUPS, + g_param_spec_pointer ("groups", + "Contact groups", + "Groups of contact", + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_SUBSCRIPTION, + g_param_spec_int ("subscription", + "Contact Subscription", + "The subscription status of the contact", + EMPATHY_SUBSCRIPTION_NONE, + EMPATHY_SUBSCRIPTION_BOTH, + EMPATHY_SUBSCRIPTION_NONE, + G_PARAM_READWRITE)); + + + g_object_class_install_property (object_class, + PROP_HANDLE, + g_param_spec_uint ("handle", + "Contact Handle", + "The handle of the contact", + 0, + G_MAXUINT, + 0, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_IS_USER, + g_param_spec_boolean ("is-user", + "Contact is-user", + "Is contact the user", + FALSE, + G_PARAM_READWRITE)); + + g_type_class_add_private (object_class, sizeof (EmpathyContactPriv)); +} + +static void +contact_init (EmpathyContact *contact) +{ +} + +static void +contact_finalize (GObject *object) +{ + EmpathyContactPriv *priv; + + priv = GET_PRIV (object); + + empathy_debug (DEBUG_DOMAIN, "finalize: %p", object); + + g_free (priv->name); + g_free (priv->id); + + if (priv->avatar) { + empathy_avatar_unref (priv->avatar); + } + + if (priv->presence) { + g_object_unref (priv->presence); + } + + if (priv->groups) { + g_list_foreach (priv->groups, (GFunc) g_free, NULL); + g_list_free (priv->groups); + } + + if (priv->account) { + g_object_unref (priv->account); + } + + (G_OBJECT_CLASS (parent_class)->finalize) (object); +} + +static void +contact_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + EmpathyContactPriv *priv; + + priv = GET_PRIV (object); + + switch (param_id) { + case PROP_ID: + g_value_set_string (value, + empathy_contact_get_id (EMPATHY_CONTACT (object))); + break; + case PROP_NAME: + g_value_set_string (value, + empathy_contact_get_name (EMPATHY_CONTACT (object))); + break; + case PROP_AVATAR: + g_value_set_boxed (value, priv->avatar); + break; + case PROP_ACCOUNT: + g_value_set_object (value, priv->account); + break; + case PROP_PRESENCE: + g_value_set_object (value, priv->presence); + break; + case PROP_GROUPS: + g_value_set_pointer (value, priv->groups); + break; + case PROP_SUBSCRIPTION: + g_value_set_int (value, priv->subscription); + break; + case PROP_HANDLE: + g_value_set_uint (value, priv->handle); + break; + case PROP_IS_USER: + g_value_set_boolean (value, priv->is_user); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + }; +} + +static void +contact_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + EmpathyContactPriv *priv; + + priv = GET_PRIV (object); + + switch (param_id) { + case PROP_ID: + empathy_contact_set_id (EMPATHY_CONTACT (object), + g_value_get_string (value)); + break; + case PROP_NAME: + empathy_contact_set_name (EMPATHY_CONTACT (object), + g_value_get_string (value)); + break; + case PROP_AVATAR: + empathy_contact_set_avatar (EMPATHY_CONTACT (object), + g_value_get_boxed (value)); + break; + case PROP_ACCOUNT: + empathy_contact_set_account (EMPATHY_CONTACT (object), + MC_ACCOUNT (g_value_get_object (value))); + break; + case PROP_PRESENCE: + empathy_contact_set_presence (EMPATHY_CONTACT (object), + EMPATHY_PRESENCE (g_value_get_object (value))); + break; + case PROP_GROUPS: + empathy_contact_set_groups (EMPATHY_CONTACT (object), + g_value_get_pointer (value)); + break; + case PROP_SUBSCRIPTION: + empathy_contact_set_subscription (EMPATHY_CONTACT (object), + g_value_get_int (value)); + break; + case PROP_HANDLE: + empathy_contact_set_handle (EMPATHY_CONTACT (object), + g_value_get_uint (value)); + break; + case PROP_IS_USER: + empathy_contact_set_is_user (EMPATHY_CONTACT (object), + g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + }; +} + +EmpathyContact * +empathy_contact_new (McAccount *account) +{ + return g_object_new (EMPATHY_TYPE_CONTACT, + "account", account, + NULL); +} + +EmpathyContact * +empathy_contact_new_full (McAccount *account, + const gchar *id, + const gchar *name) +{ + return g_object_new (EMPATHY_TYPE_CONTACT, + "account", account, + "name", name, + "id", id, + NULL); +} + +const gchar * +empathy_contact_get_id (EmpathyContact *contact) +{ + EmpathyContactPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), ""); + + priv = GET_PRIV (contact); + + if (priv->id) { + return priv->id; + } + + return ""; +} + +const gchar * +empathy_contact_get_name (EmpathyContact *contact) +{ + EmpathyContactPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), ""); + + priv = GET_PRIV (contact); + + if (G_STR_EMPTY (priv->name)) { + return empathy_contact_get_id (contact); + } + + return priv->name; +} + +EmpathyAvatar * +empathy_contact_get_avatar (EmpathyContact *contact) +{ + EmpathyContactPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + + priv = GET_PRIV (contact); + + return priv->avatar; +} + +McAccount * +empathy_contact_get_account (EmpathyContact *contact) +{ + EmpathyContactPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + + priv = GET_PRIV (contact); + + return priv->account; +} + +EmpathyPresence * +empathy_contact_get_presence (EmpathyContact *contact) +{ + EmpathyContactPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + + priv = GET_PRIV (contact); + + return priv->presence; +} + +GList * +empathy_contact_get_groups (EmpathyContact *contact) +{ + EmpathyContactPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + + priv = GET_PRIV (contact); + + return priv->groups; +} + +EmpathySubscription +empathy_contact_get_subscription (EmpathyContact *contact) +{ + EmpathyContactPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), + EMPATHY_SUBSCRIPTION_NONE); + + priv = GET_PRIV (contact); + + return priv->subscription; +} + +guint +empathy_contact_get_handle (EmpathyContact *contact) +{ + EmpathyContactPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), 0); + + priv = GET_PRIV (contact); + + return priv->handle; +} + +gboolean +empathy_contact_is_user (EmpathyContact *contact) +{ + EmpathyContactPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE); + + priv = GET_PRIV (contact); + + return priv->is_user; +} + +void +empathy_contact_set_id (EmpathyContact *contact, + const gchar *id) +{ + EmpathyContactPriv *priv; + + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + g_return_if_fail (id != NULL); + + priv = GET_PRIV (contact); + + if (priv->id && strcmp (id, priv->id) == 0) { + return; + } + + g_free (priv->id); + priv->id = g_strdup (id); + + g_object_notify (G_OBJECT (contact), "id"); +} + +void +empathy_contact_set_name (EmpathyContact *contact, + const gchar *name) +{ + EmpathyContactPriv *priv; + + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + g_return_if_fail (name != NULL); + + priv = GET_PRIV (contact); + + if (priv->name && strcmp (name, priv->name) == 0) { + return; + } + + g_free (priv->name); + priv->name = g_strdup (name); + + g_object_notify (G_OBJECT (contact), "name"); +} + +void +empathy_contact_set_avatar (EmpathyContact *contact, + EmpathyAvatar *avatar) +{ + EmpathyContactPriv *priv; + + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + + priv = GET_PRIV (contact); + + if (priv->avatar == avatar) { + return; + } + + if (priv->avatar) { + empathy_avatar_unref (priv->avatar); + priv->avatar = NULL; + } + + if (avatar) { + priv->avatar = empathy_avatar_ref (avatar); + } + + g_object_notify (G_OBJECT (contact), "avatar"); +} + +void +empathy_contact_set_account (EmpathyContact *contact, + McAccount *account) +{ + EmpathyContactPriv *priv; + + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + g_return_if_fail (MC_IS_ACCOUNT (account)); + + priv = GET_PRIV (contact); + + if (account == priv->account) { + return; + } + + if (priv->account) { + g_object_unref (priv->account); + } + priv->account = g_object_ref (account); + + g_object_notify (G_OBJECT (contact), "account"); +} + +void +empathy_contact_set_presence (EmpathyContact *contact, + EmpathyPresence *presence) +{ + EmpathyContactPriv *priv; + + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + + priv = GET_PRIV (contact); + + if (presence == priv->presence) { + return; + } + + if (priv->presence) { + g_object_unref (priv->presence); + priv->presence = NULL; + } + + if (presence) { + priv->presence = g_object_ref (presence); + } + + g_object_notify (G_OBJECT (contact), "presence"); +} + +void +empathy_contact_set_groups (EmpathyContact *contact, + GList *groups) +{ + EmpathyContactPriv *priv; + GList *old_groups, *l; + + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + + priv = GET_PRIV (contact); + + old_groups = priv->groups; + priv->groups = NULL; + + for (l = groups; l; l = l->next) { + priv->groups = g_list_append (priv->groups, + g_strdup (l->data)); + } + + g_list_foreach (old_groups, (GFunc) g_free, NULL); + g_list_free (old_groups); + + g_object_notify (G_OBJECT (contact), "groups"); +} + +void +empathy_contact_set_subscription (EmpathyContact *contact, + EmpathySubscription subscription) +{ + EmpathyContactPriv *priv; + + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + + priv = GET_PRIV (contact); + + if (priv->subscription == subscription) { + return; + } + + priv->subscription = subscription; + + g_object_notify (G_OBJECT (contact), "subscription"); +} + +void +empathy_contact_set_handle (EmpathyContact *contact, + guint handle) +{ + EmpathyContactPriv *priv; + + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + + priv = GET_PRIV (contact); + + if (priv->handle == handle) { + return; + } + + priv->handle = handle; + + g_object_notify (G_OBJECT (contact), "handle"); +} + +void +empathy_contact_set_is_user (EmpathyContact *contact, + gboolean is_user) +{ + EmpathyContactPriv *priv; + + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + + priv = GET_PRIV (contact); + + if (priv->is_user == is_user) { + return; + } + + priv->is_user = is_user; + + g_object_notify (G_OBJECT (contact), "is-user"); +} + +void +empathy_contact_add_group (EmpathyContact *contact, + const gchar *group) +{ + EmpathyContactPriv *priv; + + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + g_return_if_fail (group != NULL); + + priv = GET_PRIV (contact); + + if (!g_list_find_custom (priv->groups, group, (GCompareFunc) strcmp)) { + priv->groups = g_list_prepend (priv->groups, g_strdup (group)); + g_object_notify (G_OBJECT (contact), "groups"); + } +} + +void +empathy_contact_remove_group (EmpathyContact *contact, + const gchar *group) +{ + EmpathyContactPriv *priv; + GList *l; + + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + g_return_if_fail (group != NULL); + + priv = GET_PRIV (contact); + + l = g_list_find_custom (priv->groups, group, (GCompareFunc) strcmp); + if (l) { + g_free (l->data); + priv->groups = g_list_delete_link (priv->groups, l); + g_object_notify (G_OBJECT (contact), "groups"); + } +} + +gboolean +empathy_contact_is_online (EmpathyContact *contact) +{ + EmpathyContactPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE); + + priv = GET_PRIV (contact); + + if (!priv->presence) { + return FALSE; + } + + return (empathy_presence_get_state (priv->presence) > MC_PRESENCE_OFFLINE); +} + +gboolean +empathy_contact_is_in_group (EmpathyContact *contact, + const gchar *group) +{ + EmpathyContactPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE); + g_return_val_if_fail (!G_STR_EMPTY (group), FALSE); + + priv = GET_PRIV (contact); + + if (g_list_find_custom (priv->groups, group, (GCompareFunc) strcmp)) { + return TRUE; + } + + return FALSE; +} + +const gchar * +empathy_contact_get_status (EmpathyContact *contact) +{ + EmpathyContactPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), ""); + + priv = GET_PRIV (contact); + + if (priv->presence) { + const gchar *status; + + status = empathy_presence_get_status (priv->presence); + if (!status) { + McPresence state; + + state = empathy_presence_get_state (priv->presence); + status = empathy_presence_state_get_default_status (state); + } + + return status; + } + + return empathy_presence_state_get_default_status (MC_PRESENCE_OFFLINE); +} + +gboolean +empathy_contact_equal (gconstpointer v1, + gconstpointer v2) +{ + McAccount *account_a; + McAccount *account_b; + const gchar *id_a; + const gchar *id_b; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (v1), FALSE); + g_return_val_if_fail (EMPATHY_IS_CONTACT (v2), FALSE); + + account_a = empathy_contact_get_account (EMPATHY_CONTACT (v1)); + account_b = empathy_contact_get_account (EMPATHY_CONTACT (v2)); + + id_a = empathy_contact_get_id (EMPATHY_CONTACT (v1)); + id_b = empathy_contact_get_id (EMPATHY_CONTACT (v2)); + + return empathy_account_equal (account_a, account_b) && g_str_equal (id_a, id_b); +} + +guint +empathy_contact_hash (gconstpointer key) +{ + EmpathyContactPriv *priv; + guint hash; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (key), +1); + + priv = GET_PRIV (EMPATHY_CONTACT (key)); + + hash = empathy_account_hash (empathy_contact_get_account (EMPATHY_CONTACT (key))); + hash += g_str_hash (empathy_contact_get_id (EMPATHY_CONTACT (key))); + + return hash; +} + diff --git a/libempathy/empathy-contact.h b/libempathy/empathy-contact.h new file mode 100644 index 00000000..b32d451b --- /dev/null +++ b/libempathy/empathy-contact.h @@ -0,0 +1,106 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EMPATHY_CONTACT_H__ +#define __EMPATHY_CONTACT_H__ + +#include + +#include + +#include "empathy-avatar.h" +#include "empathy-presence.h" + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_CONTACT (empathy_contact_get_gtype ()) +#define EMPATHY_CONTACT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_CONTACT, EmpathyContact)) +#define EMPATHY_CONTACT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_CONTACT, EmpathyContactClass)) +#define EMPATHY_IS_CONTACT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_CONTACT)) +#define EMPATHY_IS_CONTACT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_CONTACT)) +#define EMPATHY_CONTACT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_CONTACT, EmpathyContactClass)) + +typedef struct _EmpathyContact EmpathyContact; +typedef struct _EmpathyContactClass EmpathyContactClass; + +struct _EmpathyContact { + GObject parent; +}; + +struct _EmpathyContactClass { + GObjectClass parent_class; +}; + +typedef enum { + EMPATHY_SUBSCRIPTION_NONE = 0, + EMPATHY_SUBSCRIPTION_TO = 1 << 0, /* We send our presence to that contact */ + EMPATHY_SUBSCRIPTION_FROM = 1 << 1, /* That contact sends his presence to us */ + EMPATHY_SUBSCRIPTION_BOTH = EMPATHY_SUBSCRIPTION_TO | EMPATHY_SUBSCRIPTION_FROM +} EmpathySubscription; + +GType empathy_contact_get_gtype (void) G_GNUC_CONST; + +EmpathyContact * empathy_contact_new (McAccount *account); +EmpathyContact * empathy_contact_new_full (McAccount *account, + const gchar *id, + const gchar *name); +const gchar * empathy_contact_get_id (EmpathyContact *contact); +const gchar * empathy_contact_get_name (EmpathyContact *contact); +EmpathyAvatar * empathy_contact_get_avatar (EmpathyContact *contact); +McAccount * empathy_contact_get_account (EmpathyContact *contact); +EmpathyPresence * empathy_contact_get_presence (EmpathyContact *contact); +GList * empathy_contact_get_groups (EmpathyContact *contact); +EmpathySubscription empathy_contact_get_subscription (EmpathyContact *contact); +guint empathy_contact_get_handle (EmpathyContact *contact); +gboolean empathy_contact_is_user (EmpathyContact *contact); +void empathy_contact_set_id (EmpathyContact *contact, + const gchar *id); +void empathy_contact_set_name (EmpathyContact *contact, + const gchar *name); +void empathy_contact_set_avatar (EmpathyContact *contact, + EmpathyAvatar *avatar); +void empathy_contact_set_account (EmpathyContact *contact, + McAccount *account); +void empathy_contact_set_presence (EmpathyContact *contact, + EmpathyPresence *presence); +void empathy_contact_set_groups (EmpathyContact *contact, + GList *categories); +void empathy_contact_set_subscription (EmpathyContact *contact, + EmpathySubscription subscription); +void empathy_contact_set_handle (EmpathyContact *contact, + guint handle); +void empathy_contact_set_is_user (EmpathyContact *contact, + gboolean is_user); +void empathy_contact_add_group (EmpathyContact *contact, + const gchar *group); +void empathy_contact_remove_group (EmpathyContact *contact, + const gchar *group); +gboolean empathy_contact_is_online (EmpathyContact *contact); +gboolean empathy_contact_is_in_group (EmpathyContact *contact, + const gchar *group); +const gchar * empathy_contact_get_status (EmpathyContact *contact); +gboolean empathy_contact_equal (gconstpointer v1, + gconstpointer v2); +guint empathy_contact_hash (gconstpointer key); + +G_END_DECLS + +#endif /* __EMPATHY_CONTACT_H__ */ + diff --git a/libempathy/empathy-debug.c b/libempathy/empathy-debug.c new file mode 100644 index 00000000..2f565849 --- /dev/null +++ b/libempathy/empathy-debug.c @@ -0,0 +1,92 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Richard Hult + */ + +#include "config.h" + +#include +#include + +#include +#include + +/* Set EMPATHY_DEBUG to a colon/comma/space separated list of domains, or "all" + * to get all debug output. + */ + +#include "empathy-debug.h" + +static gchar **debug_strv; +static gboolean all_domains = FALSE; + +static void +debug_init (void) +{ + static gboolean inited = FALSE; + + if (!inited) { + const gchar *env; + gint i; + + env = g_getenv ("EMPATHY_DEBUG"); + + if (env) { + debug_strv = g_strsplit_set (env, ":, ", 0); + } else { + debug_strv = NULL; + } + + for (i = 0; debug_strv && debug_strv[i]; i++) { + if (strcmp ("all", debug_strv[i]) == 0) { + all_domains = TRUE; + } + } + + inited = TRUE; + } +} + +void +empathy_debug_impl (const gchar *domain, const gchar *msg, ...) +{ + gint i; + + g_return_if_fail (domain != NULL); + g_return_if_fail (msg != NULL); + + debug_init (); + + for (i = 0; debug_strv && debug_strv[i]; i++) { + if (all_domains || strcmp (domain, debug_strv[i]) == 0) { + va_list args; + + g_print ("%s: ", domain); + + va_start (args, msg); + g_vprintf (msg, args); + va_end (args); + + g_print ("\n"); + break; + } + } +} + diff --git a/libempathy/empathy-debug.h b/libempathy/empathy-debug.h new file mode 100644 index 00000000..19d2aa38 --- /dev/null +++ b/libempathy/empathy-debug.h @@ -0,0 +1,53 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EMPATHY_DEBUG_H__ +#define __EMPATHY_DEBUG_H__ + +#include + +G_BEGIN_DECLS + +#ifdef G_HAVE_ISO_VARARGS +# ifdef EMPATHY_DISABLE_DEBUG +# define empathy_debug(...) +# else +# define empathy_debug(...) empathy_debug_impl (__VA_ARGS__) +# endif +#elif defined(G_HAVE_GNUC_VARARGS) +# if EMPATHY_DISABLE_DEBUG +# define empathy_debug(fmt...) +# else +# define empathy_debug(fmt...) empathy_debug_impl(fmt) +# endif +#else +# if EMPATHY_DISABLE_DEBUG +# define empathy_debug(x) +# else +# define empathy_debug empathy_debug_impl +# endif +#endif + +void empathy_debug_impl (const gchar *domain, const gchar *msg, ...); + +G_END_DECLS + +#endif /* __EMPATHY_DEBUG_H__ */ + diff --git a/libempathy/empathy-idle.c b/libempathy/empathy-idle.c index 8150effd..5b04d363 100644 --- a/libempathy/empathy-idle.c +++ b/libempathy/empathy-idle.c @@ -30,8 +30,8 @@ #include #include "empathy-idle.h" -#include "gossip-utils.h" -#include "gossip-debug.h" +#include "empathy-utils.h" +#include "empathy-debug.h" #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ EMPATHY_TYPE_IDLE, EmpathyIdlePriv)) @@ -144,7 +144,7 @@ empathy_idle_init (EmpathyIdle *idle) priv = GET_PRIV (idle); priv->is_idle = FALSE; - priv->mc = gossip_mission_control_new (); + priv->mc = empathy_mission_control_new (); priv->state = mission_control_get_presence_actual (priv->mc, NULL); idle_presence_changed_cb (priv->mc, priv->state, idle); @@ -165,13 +165,13 @@ empathy_idle_init (EmpathyIdle *idle) G_CALLBACK (idle_session_idle_changed_cb), idle, NULL); } else { - gossip_debug (DEBUG_DOMAIN, "Failed to get gs proxy"); + empathy_debug (DEBUG_DOMAIN, "Failed to get gs proxy"); } system_bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); if (!system_bus) { - gossip_debug (DEBUG_DOMAIN, "Failed to get system bus: %s", + empathy_debug (DEBUG_DOMAIN, "Failed to get system bus: %s", error ? error->message : "No error given"); } else { priv->nm_proxy = dbus_g_proxy_new_for_name (system_bus, @@ -186,7 +186,7 @@ empathy_idle_init (EmpathyIdle *idle) G_CALLBACK (idle_nm_state_change_cb), idle, NULL); } else { - gossip_debug (DEBUG_DOMAIN, "Failed to get nm proxy"); + empathy_debug (DEBUG_DOMAIN, "Failed to get nm proxy"); } /* FIXME: get value */ priv->nm_connected = TRUE; @@ -310,7 +310,7 @@ empathy_idle_get_status (EmpathyIdle *idle) priv = GET_PRIV (idle); if (!priv->status) { - return gossip_presence_state_get_default_status (priv->state); + return empathy_presence_state_get_default_status (priv->state); } return priv->status; @@ -371,7 +371,7 @@ empathy_idle_set_presence (EmpathyIdle *idle, } /* Do not set translated default messages */ - default_status = gossip_presence_state_get_default_status (state); + default_status = empathy_presence_state_get_default_status (state); if (status && strcmp (status, default_status) == 0) { status = NULL; } @@ -413,7 +413,7 @@ idle_session_idle_changed_cb (DBusGProxy *gs_proxy, priv = GET_PRIV (idle); - gossip_debug (DEBUG_DOMAIN, "Session idle state changed, %s -> %s", + empathy_debug (DEBUG_DOMAIN, "Session idle state changed, %s -> %s", priv->is_idle ? "yes" : "no", is_idle ? "yes" : "no"); @@ -441,7 +441,7 @@ idle_session_idle_changed_cb (DBusGProxy *gs_proxy, priv->saved_status = g_strdup (priv->status); } - gossip_debug (DEBUG_DOMAIN, "Going to autoaway"); + empathy_debug (DEBUG_DOMAIN, "Going to autoaway"); empathy_idle_set_state (idle, new_state); idle_ext_away_start (idle); @@ -449,7 +449,7 @@ idle_session_idle_changed_cb (DBusGProxy *gs_proxy, /* We are no more idle, restore state */ idle_ext_away_stop (idle); - gossip_debug (DEBUG_DOMAIN, "Restoring state to %d %s", + empathy_debug (DEBUG_DOMAIN, "Restoring state to %d %s", priv->saved_state, priv->saved_status); @@ -473,7 +473,7 @@ idle_nm_state_change_cb (DBusGProxy *proxy, priv = GET_PRIV (idle); - gossip_debug (DEBUG_DOMAIN, "New network state (%d)", state); + empathy_debug (DEBUG_DOMAIN, "New network state (%d)", state); if (state != NM_STATE_CONNECTED && priv->state > MC_PRESENCE_OFFLINE) { @@ -529,7 +529,7 @@ idle_ext_away_cb (EmpathyIdle *idle) priv = GET_PRIV (idle); - gossip_debug (DEBUG_DOMAIN, "Going to extended autoaway"); + empathy_debug (DEBUG_DOMAIN, "Going to extended autoaway"); empathy_idle_set_state (idle, MC_PRESENCE_EXTENDED_AWAY); priv->ext_away_timeout = 0; diff --git a/libempathy/empathy-log-manager.c b/libempathy/empathy-log-manager.c index afb40a53..f7e3540f 100644 --- a/libempathy/empathy-log-manager.c +++ b/libempathy/empathy-log-manager.c @@ -27,10 +27,10 @@ #include #include "empathy-log-manager.h" -#include "gossip-contact.h" -#include "gossip-time.h" -#include "gossip-debug.h" -#include "gossip-utils.h" +#include "empathy-contact.h" +#include "empathy-time.h" +#include "empathy-debug.h" +#include "empathy-utils.h" #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ EMPATHY_TYPE_LOG_MANAGER, EmpathyLogManagerPriv)) @@ -45,7 +45,7 @@ #define LOG_TIME_FORMAT "%Y%m%d" #define LOG_HEADER \ "\n" \ - "\n" \ + "\n" \ "\n" #define LOG_FOOTER \ @@ -78,7 +78,7 @@ static gchar * log_manager_get_filename_for_date (EmpathyLogMa gboolean chatroom, const gchar *date); static gchar * log_manager_get_timestamp_filename (void); -static gchar * log_manager_get_timestamp_from_message (GossipMessage *message); +static gchar * log_manager_get_timestamp_from_message (EmpathyMessage *message); static EmpathyLogSearchHit *log_manager_search_hit_new (EmpathyLogManager *manager, const gchar *filename); @@ -128,11 +128,11 @@ void empathy_log_manager_add_message (EmpathyLogManager *manager, const gchar *chat_id, gboolean chatroom, - GossipMessage *message) + EmpathyMessage *message) { FILE *file; McAccount *account; - GossipContact *sender; + EmpathyContact *sender; const gchar *body_str; const gchar *str; gchar *filename; @@ -144,11 +144,11 @@ empathy_log_manager_add_message (EmpathyLogManager *manager, g_return_if_fail (EMPATHY_IS_LOG_MANAGER (manager)); g_return_if_fail (chat_id != NULL); - g_return_if_fail (GOSSIP_IS_MESSAGE (message)); + g_return_if_fail (EMPATHY_IS_MESSAGE (message)); - sender = gossip_message_get_sender (message); - account = gossip_contact_get_account (sender); - body_str = gossip_message_get_body (message); + sender = empathy_message_get_sender (message); + account = empathy_contact_get_account (sender); + body_str = empathy_message_get_body (message); if (G_STR_EMPTY (body_str)) { return; @@ -157,13 +157,13 @@ empathy_log_manager_add_message (EmpathyLogManager *manager, filename = log_manager_get_filename (manager, account, chat_id, chatroom); basedir = g_path_get_dirname (filename); if (!g_file_test (basedir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { - gossip_debug (DEBUG_DOMAIN, "Creating directory:'%s'", basedir); + empathy_debug (DEBUG_DOMAIN, "Creating directory:'%s'", basedir); g_mkdir_with_parents (basedir, LOG_DIR_CREATE_MODE); } g_free (basedir); - gossip_debug (DEBUG_DOMAIN, "Adding message: '%s' to file: '%s'", + empathy_debug (DEBUG_DOMAIN, "Adding message: '%s' to file: '%s'", body_str, filename); if (!g_file_test (filename, G_FILE_TEST_EXISTS)) { @@ -182,10 +182,10 @@ empathy_log_manager_add_message (EmpathyLogManager *manager, body = g_markup_escape_text (body_str, -1); timestamp = log_manager_get_timestamp_from_message (message); - str = gossip_contact_get_name (sender); + str = empathy_contact_get_name (sender); contact_name = g_markup_escape_text (str, -1); - str = gossip_contact_get_id (sender); + str = empathy_contact_get_id (sender); contact_id = g_markup_escape_text (str, -1); g_fprintf (file, @@ -193,7 +193,7 @@ empathy_log_manager_add_message (EmpathyLogManager *manager, timestamp, contact_id, contact_name, - gossip_contact_is_user (sender) ? "true" : "false", + empathy_contact_is_user (sender) ? "true" : "false", body); fclose (file); @@ -240,12 +240,12 @@ empathy_log_manager_get_dates (EmpathyLogManager *manager, directory = log_manager_get_dir (manager, account, chat_id, chatroom); dir = g_dir_open (directory, 0, NULL); if (!dir) { - gossip_debug (DEBUG_DOMAIN, "Could not open directory:'%s'", directory); + empathy_debug (DEBUG_DOMAIN, "Could not open directory:'%s'", directory); g_free (directory); return NULL; } - gossip_debug (DEBUG_DOMAIN, "Collating a list of dates in:'%s'", directory); + empathy_debug (DEBUG_DOMAIN, "Collating a list of dates in:'%s'", directory); while ((filename = g_dir_read_name (dir)) != NULL) { if (!g_str_has_suffix (filename, LOG_FILENAME_SUFFIX)) { @@ -264,7 +264,7 @@ empathy_log_manager_get_dates (EmpathyLogManager *manager, g_free (directory); g_dir_close (dir); - gossip_debug (DEBUG_DOMAIN, "Parsed %d dates", g_list_length (dates)); + empathy_debug (DEBUG_DOMAIN, "Parsed %d dates", g_list_length (dates)); return dates; } @@ -289,10 +289,10 @@ empathy_log_manager_get_messages_for_date (EmpathyLogManager *manager, filename = log_manager_get_filename_for_date (manager, account, chat_id, chatroom, date); - gossip_debug (DEBUG_DOMAIN, "Attempting to parse filename:'%s'...", filename); + empathy_debug (DEBUG_DOMAIN, "Attempting to parse filename:'%s'...", filename); if (!g_file_test (filename, G_FILE_TEST_EXISTS)) { - gossip_debug (DEBUG_DOMAIN, "Filename:'%s' does not exist", filename); + empathy_debug (DEBUG_DOMAIN, "Filename:'%s' does not exist", filename); g_free (filename); return NULL; } @@ -320,10 +320,10 @@ empathy_log_manager_get_messages_for_date (EmpathyLogManager *manager, /* Now get the messages. */ for (node = log_node->children; node; node = node->next) { - GossipMessage *message; - GossipContact *sender; + EmpathyMessage *message; + EmpathyContact *sender; gchar *time; - GossipTime t; + EmpathyTime t; gchar *sender_id; gchar *sender_name; gchar *body; @@ -344,13 +344,13 @@ empathy_log_manager_get_messages_for_date (EmpathyLogManager *manager, is_user = strcmp (is_user_str, "true") == 0; } - t = gossip_time_parse (time); + t = empathy_time_parse (time); - sender = gossip_contact_new_full (account, sender_id, sender_name); - gossip_contact_set_is_user (sender, is_user); - message = gossip_message_new (body); - gossip_message_set_sender (message, sender); - gossip_message_set_timestamp (message, t); + sender = empathy_contact_new_full (account, sender_id, sender_name); + empathy_contact_set_is_user (sender, is_user); + message = empathy_message_new (body); + empathy_message_set_sender (message, sender); + empathy_message_set_timestamp (message, t); messages = g_list_append (messages, message); @@ -361,7 +361,7 @@ empathy_log_manager_get_messages_for_date (EmpathyLogManager *manager, xmlFree (body); } - gossip_debug (DEBUG_DOMAIN, "Parsed %d messages", g_list_length (messages)); + empathy_debug (DEBUG_DOMAIN, "Parsed %d messages", g_list_length (messages)); g_free (filename); xmlFreeDoc (doc); @@ -430,7 +430,7 @@ empathy_log_manager_search_new (EmpathyLogManager *manager, text_casefold = g_utf8_casefold (text, -1); files = log_manager_get_all_files (manager, NULL); - gossip_debug (DEBUG_DOMAIN, "Found %d log files in total", + empathy_debug (DEBUG_DOMAIN, "Found %d log files in total", g_list_length (files)); for (l = files; l; l = l->next) { @@ -460,7 +460,7 @@ empathy_log_manager_search_new (EmpathyLogManager *manager, if (hit) { hits = g_list_prepend (hits, hit); - gossip_debug (DEBUG_DOMAIN, + empathy_debug (DEBUG_DOMAIN, "Found text:'%s' in file:'%s' on date:'%s'...", text, hit->filename, hit->date); } @@ -503,11 +503,11 @@ empathy_log_manager_search_free (GList *hits) gchar * empathy_log_manager_get_date_readable (const gchar *date) { - GossipTime t; + EmpathyTime t; - t = gossip_time_parse (date); + t = empathy_time_parse (date); - return gossip_time_to_string_local (t, "%a %d %b %Y"); + return empathy_time_to_string_local (t, "%a %d %b %Y"); } static const gchar * @@ -681,12 +681,12 @@ log_manager_get_filename_for_date (EmpathyLogManager *manager, static gchar * log_manager_get_timestamp_filename (void) { - GossipTime t; + EmpathyTime t; gchar *time_str; gchar *filename; - t = gossip_time_get_current (); - time_str = gossip_time_to_string_local (t, LOG_TIME_FORMAT); + t = empathy_time_get_current (); + time_str = empathy_time_to_string_local (t, LOG_TIME_FORMAT); filename = g_strconcat (time_str, LOG_FILENAME_SUFFIX, NULL); g_free (time_str); @@ -695,14 +695,14 @@ log_manager_get_timestamp_filename (void) } static gchar * -log_manager_get_timestamp_from_message (GossipMessage *message) +log_manager_get_timestamp_from_message (EmpathyMessage *message) { - GossipTime t; + EmpathyTime t; - t = gossip_message_get_timestamp (message); + t = empathy_message_get_timestamp (message); /* We keep the timestamps in the messages as UTC. */ - return gossip_time_to_string_utc (t, LOG_TIME_FORMAT_FULL); + return empathy_time_to_string_utc (t, LOG_TIME_FORMAT_FULL); } static EmpathyLogSearchHit * diff --git a/libempathy/empathy-log-manager.h b/libempathy/empathy-log-manager.h index d1a5f431..67ec19d5 100644 --- a/libempathy/empathy-log-manager.h +++ b/libempathy/empathy-log-manager.h @@ -27,7 +27,7 @@ #include -#include "gossip-message.h" +#include "empathy-message.h" G_BEGIN_DECLS @@ -64,7 +64,7 @@ EmpathyLogManager *empathy_log_manager_new (void); void empathy_log_manager_add_message (EmpathyLogManager *manager, const gchar *chat_id, gboolean chatroom, - GossipMessage *message); + EmpathyMessage *message); gboolean empathy_log_manager_exists (EmpathyLogManager *manager, McAccount *account, const gchar *chat_id, diff --git a/libempathy/empathy-message.c b/libempathy/empathy-message.c new file mode 100644 index 00000000..8b4751ee --- /dev/null +++ b/libempathy/empathy-message.c @@ -0,0 +1,418 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Xavier Claessens + */ + +#include "config.h" + +#include "empathy-message.h" + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_MESSAGE, EmpathyMessagePriv)) + +typedef struct _EmpathyMessagePriv EmpathyMessagePriv; + +struct _EmpathyMessagePriv { + EmpathyMessageType type; + EmpathyContact *sender; + EmpathyContact *receiver; + gchar *body; + EmpathyTime timestamp; + +}; + +static void empathy_message_class_init (EmpathyMessageClass *class); +static void empathy_message_init (EmpathyMessage *message); +static void empathy_message_finalize (GObject *object); +static void message_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); +static void message_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); + +enum { + PROP_0, + PROP_TYPE, + PROP_SENDER, + PROP_RECEIVER, + PROP_BODY, + PROP_TIMESTAMP, +}; + +static gpointer parent_class = NULL; + +GType +empathy_message_get_gtype (void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof (EmpathyMessageClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) empathy_message_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EmpathyMessage), + 0, /* n_preallocs */ + (GInstanceInitFunc) empathy_message_init + }; + + type = g_type_register_static (G_TYPE_OBJECT, + "EmpathyMessage", + &info, 0); + } + + return type; +} + +static void +empathy_message_class_init (EmpathyMessageClass *class) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (class); + parent_class = g_type_class_peek_parent (class); + + object_class->finalize = empathy_message_finalize; + object_class->get_property = message_get_property; + object_class->set_property = message_set_property; + + g_object_class_install_property (object_class, + PROP_TYPE, + g_param_spec_int ("type", + "Message Type", + "The type of message", + EMPATHY_MESSAGE_TYPE_NORMAL, + EMPATHY_MESSAGE_TYPE_LAST, + EMPATHY_MESSAGE_TYPE_NORMAL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_SENDER, + g_param_spec_object ("sender", + "Message Sender", + "The sender of the message", + EMPATHY_TYPE_CONTACT, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_RECEIVER, + g_param_spec_object ("receiver", + "Message Receiver", + "The receiver of the message", + EMPATHY_TYPE_CONTACT, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_BODY, + g_param_spec_string ("body", + "Message Body", + "The content of the message", + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_TIMESTAMP, + g_param_spec_long ("timestamp", + "timestamp", + "timestamp", + -1, + G_MAXLONG, + -1, + G_PARAM_READWRITE)); + + + g_type_class_add_private (object_class, sizeof (EmpathyMessagePriv)); + +} + +static void +empathy_message_init (EmpathyMessage *message) +{ + EmpathyMessagePriv *priv; + + priv = GET_PRIV (message); + + priv->timestamp = empathy_time_get_current (); +} + +static void +empathy_message_finalize (GObject *object) +{ + EmpathyMessagePriv *priv; + + priv = GET_PRIV (object); + + if (priv->sender) { + g_object_unref (priv->sender); + } + if (priv->receiver) { + g_object_unref (priv->receiver); + } + + g_free (priv->body); + + (G_OBJECT_CLASS (parent_class)->finalize) (object); +} + +static void +message_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + EmpathyMessagePriv *priv; + + priv = GET_PRIV (object); + + switch (param_id) { + case PROP_TYPE: + g_value_set_int (value, priv->type); + break; + case PROP_SENDER: + g_value_set_object (value, priv->sender); + break; + case PROP_RECEIVER: + g_value_set_object (value, priv->receiver); + break; + case PROP_BODY: + g_value_set_string (value, priv->body); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + }; +} + +static void +message_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + EmpathyMessagePriv *priv; + + priv = GET_PRIV (object); + + switch (param_id) { + case PROP_TYPE: + empathy_message_set_type (EMPATHY_MESSAGE (object), + g_value_get_int (value)); + break; + case PROP_SENDER: + empathy_message_set_sender (EMPATHY_MESSAGE (object), + EMPATHY_CONTACT (g_value_get_object (value))); + break; + case PROP_RECEIVER: + empathy_message_set_receiver (EMPATHY_MESSAGE (object), + EMPATHY_CONTACT (g_value_get_object (value))); + break; + case PROP_BODY: + empathy_message_set_body (EMPATHY_MESSAGE (object), + g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + }; +} + +EmpathyMessage * +empathy_message_new (const gchar *body) +{ + return g_object_new (EMPATHY_TYPE_MESSAGE, + "body", body, + NULL); +} + +EmpathyMessageType +empathy_message_get_type (EmpathyMessage *message) +{ + EmpathyMessagePriv *priv; + + g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), + EMPATHY_MESSAGE_TYPE_NORMAL); + + priv = GET_PRIV (message); + + return priv->type; +} + +void +empathy_message_set_type (EmpathyMessage *message, + EmpathyMessageType type) +{ + EmpathyMessagePriv *priv; + + g_return_if_fail (EMPATHY_IS_MESSAGE (message)); + + priv = GET_PRIV (message); + + priv->type = type; + + g_object_notify (G_OBJECT (message), "type"); +} + +EmpathyContact * +empathy_message_get_sender (EmpathyMessage *message) +{ + EmpathyMessagePriv *priv; + + g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), NULL); + + priv = GET_PRIV (message); + + return priv->sender; +} + +void +empathy_message_set_sender (EmpathyMessage *message, EmpathyContact *contact) +{ + EmpathyMessagePriv *priv; + EmpathyContact *old_sender; + + g_return_if_fail (EMPATHY_IS_MESSAGE (message)); + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + + priv = GET_PRIV (message); + + old_sender = priv->sender; + priv->sender = g_object_ref (contact); + + if (old_sender) { + g_object_unref (old_sender); + } + + g_object_notify (G_OBJECT (message), "sender"); +} + +EmpathyContact * +empathy_message_get_receiver (EmpathyMessage *message) +{ + EmpathyMessagePriv *priv; + + g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), NULL); + + priv = GET_PRIV (message); + + return priv->receiver; +} + +void +empathy_message_set_receiver (EmpathyMessage *message, EmpathyContact *contact) +{ + EmpathyMessagePriv *priv; + EmpathyContact *old_receiver; + + g_return_if_fail (EMPATHY_IS_MESSAGE (message)); + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + + priv = GET_PRIV (message); + + old_receiver = priv->receiver; + priv->receiver = g_object_ref (contact); + + if (old_receiver) { + g_object_unref (old_receiver); + } + + g_object_notify (G_OBJECT (message), "receiver"); +} + +const gchar * +empathy_message_get_body (EmpathyMessage *message) +{ + EmpathyMessagePriv *priv; + + g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), NULL); + + priv = GET_PRIV (message); + + return priv->body; +} + +void +empathy_message_set_body (EmpathyMessage *message, + const gchar *body) +{ + EmpathyMessagePriv *priv; + EmpathyMessageType type; + + g_return_if_fail (EMPATHY_IS_MESSAGE (message)); + + priv = GET_PRIV (message); + + g_free (priv->body); + priv->body = NULL; + + type = EMPATHY_MESSAGE_TYPE_NORMAL; + if (g_str_has_prefix (body, "/me")) { + type = EMPATHY_MESSAGE_TYPE_ACTION; + body += 4; + } + else if (g_str_has_prefix (body, "/say")) { + body += 5; + } + + if (body) { + priv->body = g_strdup (body); + } + + if (type != priv->type) { + empathy_message_set_type (message, type); + } + + g_object_notify (G_OBJECT (message), "body"); +} + +EmpathyTime +empathy_message_get_timestamp (EmpathyMessage *message) +{ + EmpathyMessagePriv *priv; + + g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), -1); + + priv = GET_PRIV (message); + + return priv->timestamp; +} + +void +empathy_message_set_timestamp (EmpathyMessage *message, + EmpathyTime timestamp) +{ + EmpathyMessagePriv *priv; + + g_return_if_fail (EMPATHY_IS_MESSAGE (message)); + g_return_if_fail (timestamp >= -1); + + priv = GET_PRIV (message); + + if (timestamp <= 0) { + priv->timestamp = empathy_time_get_current (); + } else { + priv->timestamp = timestamp; + } + + g_object_notify (G_OBJECT (message), "timestamp"); +} + diff --git a/libempathy/empathy-message.h b/libempathy/empathy-message.h new file mode 100644 index 00000000..ba6f4c42 --- /dev/null +++ b/libempathy/empathy-message.h @@ -0,0 +1,82 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + * Xavier Claessens + */ + +#ifndef __EMPATHY_MESSAGE_H__ +#define __EMPATHY_MESSAGE_H__ + +#include + +#include "empathy-contact.h" +#include "empathy-time.h" + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_MESSAGE (empathy_message_get_gtype ()) +#define EMPATHY_MESSAGE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_MESSAGE, EmpathyMessage)) +#define EMPATHY_MESSAGE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_MESSAGE, EmpathyMessageClass)) +#define EMPATHY_IS_MESSAGE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_MESSAGE)) +#define EMPATHY_IS_MESSAGE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_MESSAGE)) +#define EMPATHY_MESSAGE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_MESSAGE, EmpathyMessageClass)) + +typedef struct _EmpathyMessage EmpathyMessage; +typedef struct _EmpathyMessageClass EmpathyMessageClass; + +struct _EmpathyMessage { + GObject parent; +}; + +struct _EmpathyMessageClass { + GObjectClass parent_class; +}; + +typedef enum { + EMPATHY_MESSAGE_TYPE_NORMAL, + EMPATHY_MESSAGE_TYPE_ACTION, + EMPATHY_MESSAGE_TYPE_NOTICE, + EMPATHY_MESSAGE_TYPE_AUTO_REPLY, + EMPATHY_MESSAGE_TYPE_LAST +} EmpathyMessageType; + +GType empathy_message_get_gtype (void) G_GNUC_CONST; +EmpathyMessage * empathy_message_new (const gchar *body); +EmpathyMessageType empathy_message_get_type (EmpathyMessage *message); +void empathy_message_set_type (EmpathyMessage *message, + EmpathyMessageType type); +EmpathyContact * empathy_message_get_sender (EmpathyMessage *message); +void empathy_message_set_sender (EmpathyMessage *message, + EmpathyContact *contact); +EmpathyContact * empathy_message_get_receiver (EmpathyMessage *message); +void empathy_message_set_receiver (EmpathyMessage *message, + EmpathyContact *contact); +const gchar * empathy_message_get_body (EmpathyMessage *message); +void empathy_message_set_body (EmpathyMessage *message, + const gchar *body); +/* What return value should we have here? */ +EmpathyTime empathy_message_get_timestamp (EmpathyMessage *message); +void empathy_message_set_timestamp (EmpathyMessage *message, + EmpathyTime timestamp); + +G_END_DECLS + +#endif /* __EMPATHY_MESSAGE_H__ */ diff --git a/libempathy/empathy-presence.c b/libempathy/empathy-presence.c new file mode 100644 index 00000000..158707a8 --- /dev/null +++ b/libempathy/empathy-presence.c @@ -0,0 +1,337 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Mikael Hallendal + */ + +#include "config.h" + +#include + +#include + +#include "empathy-presence.h" +#include "empathy-time.h" + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_PRESENCE, EmpathyPresencePriv)) + +typedef struct _EmpathyPresencePriv EmpathyPresencePriv; + +struct _EmpathyPresencePriv { + McPresence state; + gchar *status; + EmpathyTime timestamp; +}; + +static void presence_finalize (GObject *object); +static void presence_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); +static void presence_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); + +enum { + PROP_0, + PROP_STATE, + PROP_STATUS +}; + +G_DEFINE_TYPE (EmpathyPresence, empathy_presence, G_TYPE_OBJECT); + +static void +empathy_presence_class_init (EmpathyPresenceClass *class) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (class); + + object_class->finalize = presence_finalize; + object_class->get_property = presence_get_property; + object_class->set_property = presence_set_property; + + g_object_class_install_property (object_class, + PROP_STATE, + g_param_spec_int ("state", + "Presence State", + "The current state of the presence", + MC_PRESENCE_UNSET, + LAST_MC_PRESENCE, + MC_PRESENCE_AVAILABLE, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_STATUS, + g_param_spec_string ("status", + "Presence Status", + "Status string set on presence", + NULL, + G_PARAM_READWRITE)); + + g_type_class_add_private (object_class, sizeof (EmpathyPresencePriv)); +} + +static void +empathy_presence_init (EmpathyPresence *presence) +{ + EmpathyPresencePriv *priv; + + priv = GET_PRIV (presence); + + priv->state = MC_PRESENCE_AVAILABLE; + priv->status = NULL; + priv->timestamp = empathy_time_get_current (); +} + +static void +presence_finalize (GObject *object) +{ + EmpathyPresencePriv *priv; + + priv = GET_PRIV (object); + + g_free (priv->status); + + (G_OBJECT_CLASS (empathy_presence_parent_class)->finalize) (object); +} + +static void +presence_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + EmpathyPresencePriv *priv; + + priv = GET_PRIV (object); + + switch (param_id) { + case PROP_STATE: + g_value_set_int (value, priv->state); + break; + case PROP_STATUS: + g_value_set_string (value, + empathy_presence_get_status (EMPATHY_PRESENCE (object))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} +static void +presence_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + EmpathyPresencePriv *priv; + + priv = GET_PRIV (object); + + switch (param_id) { + case PROP_STATE: + priv->state = g_value_get_int (value); + break; + case PROP_STATUS: + empathy_presence_set_status (EMPATHY_PRESENCE (object), + g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +EmpathyPresence * +empathy_presence_new (void) +{ + return g_object_new (EMPATHY_TYPE_PRESENCE, NULL); +} + +EmpathyPresence * +empathy_presence_new_full (McPresence state, + const gchar *status) +{ + return g_object_new (EMPATHY_TYPE_PRESENCE, + "state", state, + "status", status, + NULL); +} + +const gchar * +empathy_presence_get_status (EmpathyPresence *presence) +{ + EmpathyPresencePriv *priv; + + g_return_val_if_fail (EMPATHY_IS_PRESENCE (presence), + _("Offline")); + + priv = GET_PRIV (presence); + + return priv->status; +} + +McPresence +empathy_presence_get_state (EmpathyPresence *presence) +{ + EmpathyPresencePriv *priv; + + g_return_val_if_fail (EMPATHY_IS_PRESENCE (presence), + MC_PRESENCE_AVAILABLE); + + priv = GET_PRIV (presence); + + return priv->state; +} + +void +empathy_presence_set_state (EmpathyPresence *presence, + McPresence state) +{ + EmpathyPresencePriv *priv; + + g_return_if_fail (EMPATHY_IS_PRESENCE (presence)); + + priv = GET_PRIV (presence); + + priv->state = state; + + g_object_notify (G_OBJECT (presence), "state"); +} + +void +empathy_presence_set_status (EmpathyPresence *presence, + const gchar *status) +{ + EmpathyPresencePriv *priv; + + priv = GET_PRIV (presence); + g_return_if_fail (EMPATHY_IS_PRESENCE (presence)); + + g_free (priv->status); + + if (status) { + priv->status = g_strdup (status); + } else { + priv->status = NULL; + } + + g_object_notify (G_OBJECT (presence), "status"); +} + +gint +empathy_presence_sort_func (gconstpointer a, + gconstpointer b) +{ + EmpathyPresencePriv *priv_a; + EmpathyPresencePriv *priv_b; + gint diff; + + g_return_val_if_fail (EMPATHY_IS_PRESENCE (a), 0); + g_return_val_if_fail (EMPATHY_IS_PRESENCE (b), 0); + + priv_a = GET_PRIV (a); + priv_b = GET_PRIV (b); + + /* 1. State */ + diff = priv_a->state - priv_b->state; + if (diff != 0) { + return diff < 1 ? -1 : +1; + } + + /* 3. Time (newest first) */ + diff = priv_b->timestamp - priv_a->timestamp; + if (diff != 0) { + return diff < 1 ? -1 : +1; + } + + /* No real difference */ + return 0; +} + +const gchar * +empathy_presence_state_get_default_status (McPresence state) +{ + switch (state) { + case MC_PRESENCE_AVAILABLE: + return _("Available"); + case MC_PRESENCE_DO_NOT_DISTURB: + return _("Busy"); + case MC_PRESENCE_AWAY: + case MC_PRESENCE_EXTENDED_AWAY: + return _("Away"); + case MC_PRESENCE_HIDDEN: + case MC_PRESENCE_OFFLINE: + case MC_PRESENCE_UNSET: + return _("Offline"); + default: + g_assert_not_reached (); + } + + return NULL; +} + +const gchar * +empathy_presence_state_to_str (McPresence state) +{ + switch (state) { + case MC_PRESENCE_AVAILABLE: + return "available"; + case MC_PRESENCE_DO_NOT_DISTURB: + return "busy"; + case MC_PRESENCE_AWAY: + return "away"; + case MC_PRESENCE_EXTENDED_AWAY: + return "ext_away"; + case MC_PRESENCE_HIDDEN: + return "hidden"; + case MC_PRESENCE_OFFLINE: + return "offline"; + case MC_PRESENCE_UNSET: + return "unset"; + default: + g_assert_not_reached (); + } + + return NULL; +} + +McPresence +empathy_presence_state_from_str (const gchar *str) +{ + if (strcmp (str, "available") == 0) { + return MC_PRESENCE_AVAILABLE; + } else if ((strcmp (str, "dnd") == 0) || (strcmp (str, "busy") == 0)) { + return MC_PRESENCE_DO_NOT_DISTURB; + } else if ((strcmp (str, "away") == 0) || (strcmp (str, "brb") == 0)) { + return MC_PRESENCE_AWAY; + } else if ((strcmp (str, "xa") == 0) || (strcmp (str, "ext_away") == 0)) { + return MC_PRESENCE_EXTENDED_AWAY; + } else if (strcmp (str, "hidden") == 0) { + return MC_PRESENCE_HIDDEN; + } else if (strcmp (str, "offline") == 0) { + return MC_PRESENCE_OFFLINE; + } else if (strcmp (str, "unset") == 0) { + return MC_PRESENCE_UNSET; + } + + return MC_PRESENCE_AVAILABLE; +} + diff --git a/libempathy/empathy-presence.h b/libempathy/empathy-presence.h new file mode 100644 index 00000000..940bf9ca --- /dev/null +++ b/libempathy/empathy-presence.h @@ -0,0 +1,67 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EMPATHY_PRESENCE_H__ +#define __EMPATHY_PRESENCE_H__ + +#include +#include + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_PRESENCE (empathy_presence_get_type ()) +#define EMPATHY_PRESENCE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_PRESENCE, EmpathyPresence)) +#define EMPATHY_PRESENCE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_PRESENCE, EmpathyPresenceClass)) +#define EMPATHY_IS_PRESENCE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_PRESENCE)) +#define EMPATHY_IS_PRESENCE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_PRESENCE)) +#define EMPATHY_PRESENCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_PRESENCE, EmpathyPresenceClass)) + +typedef struct _EmpathyPresence EmpathyPresence; +typedef struct _EmpathyPresenceClass EmpathyPresenceClass; + +struct _EmpathyPresence { + GObject parent; +}; + +struct _EmpathyPresenceClass { + GObjectClass parent_class; +}; + +GType empathy_presence_get_type (void) G_GNUC_CONST; + +EmpathyPresence * empathy_presence_new (void); +EmpathyPresence * empathy_presence_new_full (McPresence state, + const gchar *status); +McPresence empathy_presence_get_state (EmpathyPresence *presence); +const gchar * empathy_presence_get_status (EmpathyPresence *presence); +void empathy_presence_set_state (EmpathyPresence *presence, + McPresence state); +void empathy_presence_set_status (EmpathyPresence *presence, + const gchar *status); +gint empathy_presence_sort_func (gconstpointer a, + gconstpointer b); +const gchar * empathy_presence_state_get_default_status (McPresence state); +const gchar * empathy_presence_state_to_str (McPresence state); +McPresence empathy_presence_state_from_str (const gchar *str); + +G_END_DECLS + +#endif /* __EMPATHY_PRESENCE_H__ */ + diff --git a/libempathy/empathy-time.c b/libempathy/empathy-time.c new file mode 100644 index 00000000..0851add4 --- /dev/null +++ b/libempathy/empathy-time.c @@ -0,0 +1,124 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2003-2007 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Richard Hult + */ + +#include "config.h" + +#include +#include +#include + +#include "empathy-time.h" + +/* Note: EmpathyTime is always in UTC. */ + +EmpathyTime +empathy_time_get_current (void) +{ + return time (NULL); +} + +time_t +empathy_time_get_local_time (struct tm *tm) +{ + const gchar *timezone; + time_t t; + + timezone = g_getenv ("TZ"); + g_setenv ("TZ", "", TRUE); + + tzset (); + + t = mktime (tm); + + if (timezone) { + g_setenv ("TZ", timezone, TRUE); + } else { + g_unsetenv ("TZ"); + } + + tzset (); + + return t; +} + +/* The format is: "20021209T23:51:30" and is in UTC. 0 is returned on + * failure. The alternative format "20021209" is also accepted. + */ +EmpathyTime +empathy_time_parse (const gchar *str) +{ + struct tm tm; + gint year, month; + gint n_parsed; + + memset (&tm, 0, sizeof (struct tm)); + + n_parsed = sscanf (str, "%4d%2d%2dT%2d:%2d:%2d", + &year, &month, &tm.tm_mday, &tm.tm_hour, + &tm.tm_min, &tm.tm_sec); + if (n_parsed != 3 && n_parsed != 6) { + return 0; + } + + tm.tm_year = year - 1900; + tm.tm_mon = month - 1; + tm.tm_isdst = -1; + + return empathy_time_get_local_time (&tm); +} + +/* Converts the UTC timestamp to a string, also in UTC. Returns NULL on failure. */ +gchar * +empathy_time_to_string_utc (EmpathyTime t, + const gchar *format) +{ + gchar stamp[128]; + struct tm *tm; + + g_return_val_if_fail (format != NULL, NULL); + + tm = gmtime (&t); + if (strftime (stamp, sizeof (stamp), format, tm) == 0) { + return NULL; + } + + return g_strdup (stamp); +} + +/* Converts the UTC timestamp to a string, in local time. Returns NULL on failure. */ +gchar * +empathy_time_to_string_local (EmpathyTime t, + const gchar *format) +{ + gchar stamp[128]; + struct tm *tm; + + g_return_val_if_fail (format != NULL, NULL); + + tm = localtime (&t); + if (strftime (stamp, sizeof (stamp), format, tm) == 0) { + return NULL; + } + + return g_strdup (stamp); +} + diff --git a/libempathy/empathy-time.h b/libempathy/empathy-time.h new file mode 100644 index 00000000..0989391c --- /dev/null +++ b/libempathy/empathy-time.h @@ -0,0 +1,50 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004 Imendio AB + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EMPATHY_TIME_H__ +#define __EMPATHY_TIME_H__ + +#define __USE_XOPEN +#include + +#include + +G_BEGIN_DECLS + +#define EMPATHY_TIME_FORMAT_DISPLAY_SHORT "%H:%M" +#define EMPATHY_TIME_FORMAT_DISPLAY_LONG "%a %d %b %Y" + +/* Note: Always in UTC. */ +typedef long EmpathyTime; + +EmpathyTime empathy_time_get_current (void); +time_t empathy_time_get_local_time (struct tm *tm); +EmpathyTime empathy_time_parse (const gchar *str); +EmpathyTime empathy_time_parse_format (const gchar *str, + const gchar *format); +gchar *empathy_time_to_string_utc (EmpathyTime t, + const gchar *format); +gchar *empathy_time_to_string_local (EmpathyTime t, + const gchar *format); + +G_END_DECLS + +#endif /* __EMPATHY_TIME_H__ */ + diff --git a/libempathy/empathy-tp-chat.c b/libempathy/empathy-tp-chat.c index a2852e1d..e97b5d64 100644 --- a/libempathy/empathy-tp-chat.c +++ b/libempathy/empathy-tp-chat.c @@ -34,9 +34,9 @@ #include "empathy-contact-manager.h" #include "empathy-tp-contact-list.h" #include "empathy-marshal.h" -#include "gossip-debug.h" -#include "gossip-time.h" -#include "gossip-utils.h" +#include "empathy-debug.h" +#include "empathy-time.h" +#include "empathy-utils.h" #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ EMPATHY_TYPE_TP_CHAT, EmpathyTpChatPriv)) @@ -278,7 +278,7 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass) NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, - 1, GOSSIP_TYPE_MESSAGE); + 1, EMPATHY_TYPE_MESSAGE); signals[CHAT_STATE_CHANGED] = g_signal_new ("chat-state-changed", @@ -288,7 +288,7 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass) NULL, NULL, empathy_marshal_VOID__OBJECT_UINT, G_TYPE_NONE, - 2, GOSSIP_TYPE_CONTACT, G_TYPE_UINT); + 2, EMPATHY_TYPE_CONTACT, G_TYPE_UINT); signals[DESTROY] = g_signal_new ("destroy", @@ -320,14 +320,14 @@ tp_chat_finalize (GObject *object) priv = GET_PRIV (chat); if (priv->tp_chan) { - gossip_debug (DEBUG_DOMAIN, "Closing channel..."); + empathy_debug (DEBUG_DOMAIN, "Closing channel..."); g_signal_handlers_disconnect_by_func (priv->tp_chan, tp_chat_destroy_cb, object); if (!tp_chan_close (DBUS_G_PROXY (priv->tp_chan), &error)) { - gossip_debug (DEBUG_DOMAIN, + empathy_debug (DEBUG_DOMAIN, "Error closing text channel: %s", error ? error->message : "No error given"); g_clear_error (&error); @@ -366,7 +366,7 @@ tp_chat_constructor (GType type, priv->manager = empathy_contact_manager_new (); priv->list = empathy_contact_manager_get_list (priv->manager, priv->account); - priv->mc = gossip_mission_control_new (); + priv->mc = empathy_mission_control_new (); g_object_ref (priv->list); priv->text_iface = tp_chan_get_interface (priv->tp_chan, @@ -506,7 +506,7 @@ empathy_tp_chat_new (McAccount *account, } EmpathyTpChat * -empathy_tp_chat_new_with_contact (GossipContact *contact) +empathy_tp_chat_new_with_contact (EmpathyContact *contact) { EmpathyTpChat *chat; MissionControl *mc; @@ -516,10 +516,10 @@ empathy_tp_chat_new_with_contact (GossipContact *contact) const gchar *bus_name; guint handle; - g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL); + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); - mc = gossip_mission_control_new (); - account = gossip_contact_get_account (contact); + mc = empathy_mission_control_new (); + account = empathy_contact_get_account (contact); if (mission_control_get_connection_status (mc, account, NULL) != 0) { /* The account is not connected, nothing to do. */ @@ -529,7 +529,7 @@ empathy_tp_chat_new_with_contact (GossipContact *contact) tp_conn = mission_control_get_connection (mc, account, NULL); g_return_val_if_fail (tp_conn != NULL, NULL); bus_name = dbus_g_proxy_get_bus_name (DBUS_G_PROXY (tp_conn)); - handle = gossip_contact_get_handle (contact); + handle = empathy_contact_get_handle (contact); text_chan = tp_conn_new_channel (tp_get_bus (), tp_conn, @@ -566,7 +566,7 @@ empathy_tp_chat_request_pending (EmpathyTpChat *chat) TRUE, &messages_list, &error)) { - gossip_debug (DEBUG_DOMAIN, + empathy_debug (DEBUG_DOMAIN, "Error retrieving pending messages: %s", error ? error->message : "No error given"); g_clear_error (&error); @@ -591,7 +591,7 @@ empathy_tp_chat_request_pending (EmpathyTpChat *chat) message_flags = g_value_get_uint (g_value_array_get_nth (message_struct, 4)); message_body = g_value_get_string (g_value_array_get_nth (message_struct, 5)); - gossip_debug (DEBUG_DOMAIN, "Message pending: %s", message_body); + empathy_debug (DEBUG_DOMAIN, "Message pending: %s", message_body); tp_chat_emit_message (chat, message_type, @@ -607,27 +607,27 @@ empathy_tp_chat_request_pending (EmpathyTpChat *chat) void empathy_tp_chat_send (EmpathyTpChat *chat, - GossipMessage *message) + EmpathyMessage *message) { EmpathyTpChatPriv *priv; const gchar *message_body; - GossipMessageType message_type; + EmpathyMessageType message_type; GError *error = NULL; g_return_if_fail (EMPATHY_IS_TP_CHAT (chat)); - g_return_if_fail (GOSSIP_IS_MESSAGE (message)); + g_return_if_fail (EMPATHY_IS_MESSAGE (message)); priv = GET_PRIV (chat); - message_body = gossip_message_get_body (message); - message_type = gossip_message_get_type (message); + message_body = empathy_message_get_body (message); + message_type = empathy_message_get_type (message); - gossip_debug (DEBUG_DOMAIN, "Sending message: %s", message_body); + empathy_debug (DEBUG_DOMAIN, "Sending message: %s", message_body); if (!tp_chan_type_text_send (priv->text_iface, message_type, message_body, &error)) { - gossip_debug (DEBUG_DOMAIN, + empathy_debug (DEBUG_DOMAIN, "Send Error: %s", error ? error->message : "No error given"); g_clear_error (&error); @@ -646,11 +646,11 @@ empathy_tp_chat_set_state (EmpathyTpChat *chat, priv = GET_PRIV (chat); if (priv->chat_state_iface) { - gossip_debug (DEBUG_DOMAIN, "Set state: %d", state); + empathy_debug (DEBUG_DOMAIN, "Set state: %d", state); if (!tp_chan_iface_chat_state_set_chat_state (priv->chat_state_iface, state, &error)) { - gossip_debug (DEBUG_DOMAIN, + empathy_debug (DEBUG_DOMAIN, "Set Chat State Error: %s", error ? error->message : "No error given"); g_clear_error (&error); @@ -671,7 +671,7 @@ empathy_tp_chat_get_id (EmpathyTpChat *chat) return priv->id; } - priv->id = gossip_get_channel_id (priv->account, priv->tp_chan); + priv->id = empathy_get_channel_id (priv->account, priv->tp_chan); return priv->id; } @@ -684,7 +684,7 @@ tp_chat_destroy_cb (TpChan *text_chan, priv = GET_PRIV (chat); - gossip_debug (DEBUG_DOMAIN, "Channel Closed or CM crashed"); + empathy_debug (DEBUG_DOMAIN, "Channel Closed or CM crashed"); g_object_unref (priv->tp_chan); priv->tp_chan = NULL; @@ -726,7 +726,7 @@ tp_chat_received_cb (DBusGProxy *text_iface, priv = GET_PRIV (chat); - gossip_debug (DEBUG_DOMAIN, "Message received: %s", message_body); + empathy_debug (DEBUG_DOMAIN, "Message received: %s", message_body); tp_chat_emit_message (chat, message_type, @@ -748,7 +748,7 @@ tp_chat_sent_cb (DBusGProxy *text_iface, gchar *message_body, EmpathyTpChat *chat) { - gossip_debug (DEBUG_DOMAIN, "Message sent: %s", message_body); + empathy_debug (DEBUG_DOMAIN, "Message sent: %s", message_body); tp_chat_emit_message (chat, message_type, @@ -764,14 +764,14 @@ tp_chat_state_changed_cb (DBusGProxy *chat_state_iface, EmpathyTpChat *chat) { EmpathyTpChatPriv *priv; - GossipContact *contact; + EmpathyContact *contact; priv = GET_PRIV (chat); contact = empathy_tp_contact_list_get_from_handle (priv->list, handle); - gossip_debug (DEBUG_DOMAIN, "Chat state changed for %s (%d): %d", - gossip_contact_get_name (contact), + empathy_debug (DEBUG_DOMAIN, "Chat state changed for %s (%d): %d", + empathy_contact_get_name (contact), handle, state); @@ -788,9 +788,9 @@ tp_chat_emit_message (EmpathyTpChat *chat, const gchar *message_body) { EmpathyTpChatPriv *priv; - GossipMessage *message; - GossipContact *sender; - GossipContact *receiver; + EmpathyMessage *message; + EmpathyContact *sender; + EmpathyContact *receiver; priv = GET_PRIV (chat); @@ -802,11 +802,11 @@ tp_chat_emit_message (EmpathyTpChat *chat, from_handle); } - message = gossip_message_new (message_body); - gossip_message_set_type (message, type); - gossip_message_set_sender (message, sender); - gossip_message_set_receiver (message, receiver); - gossip_message_set_timestamp (message, (GossipTime) timestamp); + message = empathy_message_new (message_body); + empathy_message_set_type (message, type); + empathy_message_set_sender (message, sender); + empathy_message_set_receiver (message, receiver); + empathy_message_set_timestamp (message, (EmpathyTime) timestamp); g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message); diff --git a/libempathy/empathy-tp-chat.h b/libempathy/empathy-tp-chat.h index 55bbfcd3..ce4e2a83 100644 --- a/libempathy/empathy-tp-chat.h +++ b/libempathy/empathy-tp-chat.h @@ -30,8 +30,8 @@ #include -#include "gossip-message.h" -#include "gossip-contact.h" +#include "empathy-message.h" +#include "empathy-contact.h" G_BEGIN_DECLS @@ -58,10 +58,10 @@ struct _EmpathyTpChatClass { GType empathy_tp_chat_get_type (void) G_GNUC_CONST; EmpathyTpChat *empathy_tp_chat_new (McAccount *account, TpChan *tp_chan); -EmpathyTpChat *empathy_tp_chat_new_with_contact (GossipContact *contact); +EmpathyTpChat *empathy_tp_chat_new_with_contact (EmpathyContact *contact); void empathy_tp_chat_request_pending (EmpathyTpChat *chat); void empathy_tp_chat_send (EmpathyTpChat *chat, - GossipMessage *message); + EmpathyMessage *message); void empathy_tp_chat_set_state (EmpathyTpChat *chat, TelepathyChannelChatState state); const gchar * empathy_tp_chat_get_id (EmpathyTpChat *chat); diff --git a/libempathy/empathy-tp-chatroom.c b/libempathy/empathy-tp-chatroom.c index 232db30f..fe8e7f8e 100644 --- a/libempathy/empathy-tp-chatroom.c +++ b/libempathy/empathy-tp-chatroom.c @@ -28,9 +28,9 @@ #include "empathy-tp-contact-list.h" #include "empathy-contact-list.h" #include "empathy-contact-manager.h" -#include "gossip-telepathy-group.h" -#include "gossip-utils.h" -#include "gossip-debug.h" +#include "empathy-tp-group.h" +#include "empathy-utils.h" +#include "empathy-debug.h" #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ EMPATHY_TYPE_TP_CHATROOM, EmpathyTpChatroomPriv)) @@ -40,10 +40,10 @@ struct _EmpathyTpChatroomPriv { EmpathyContactManager *manager; EmpathyTpContactList *list; - GossipTelepathyGroup *group; + EmpathyTpGroup *group; gboolean is_invited; - GossipContact *invitor; + EmpathyContact *invitor; gchar *invit_message; }; @@ -51,26 +51,26 @@ static void empathy_tp_chatroom_class_init (EmpathyTpChatroomClass * static void tp_chatroom_iface_init (EmpathyContactListIface *iface); static void empathy_tp_chatroom_init (EmpathyTpChatroom *chatroom); static void tp_chatroom_finalize (GObject *object); -static void tp_chatroom_members_added_cb (GossipTelepathyGroup *group, +static void tp_chatroom_members_added_cb (EmpathyTpGroup *group, GArray *handles, guint actor_handle, guint reason, const gchar *message, EmpathyTpChatroom *list); -static void tp_chatroom_members_removed_cb (GossipTelepathyGroup *group, +static void tp_chatroom_members_removed_cb (EmpathyTpGroup *group, GArray *handles, guint actor_handle, guint reason, const gchar *message, EmpathyTpChatroom *list); static void tp_chatroom_setup (EmpathyContactList *list); -static GossipContact * tp_chatroom_find (EmpathyContactList *list, +static EmpathyContact * tp_chatroom_find (EmpathyContactList *list, const gchar *id); static void tp_chatroom_add (EmpathyContactList *list, - GossipContact *contact, + EmpathyContact *contact, const gchar *message); static void tp_chatroom_remove (EmpathyContactList *list, - GossipContact *contact, + EmpathyContact *contact, const gchar *message); static GList * tp_chatroom_get_members (EmpathyContactList *list); @@ -145,11 +145,11 @@ empathy_tp_chatroom_new (McAccount *account, priv = GET_PRIV (chatroom); - mc = gossip_mission_control_new (); + mc = empathy_mission_control_new (); tp_conn = mission_control_get_connection (mc, account, NULL); priv->manager = empathy_contact_manager_new (); priv->list = empathy_contact_manager_get_list (priv->manager, account); - priv->group = gossip_telepathy_group_new (tp_chan, tp_conn); + priv->group = empathy_tp_group_new (tp_chan, tp_conn); g_signal_connect (priv->group, "members-added", G_CALLBACK (tp_chatroom_members_added_cb), @@ -159,10 +159,10 @@ empathy_tp_chatroom_new (McAccount *account, chatroom); /* Check if we are invited to join the chat */ - self_handle = gossip_telepathy_group_get_self_handle (priv->group); - members = gossip_telepathy_group_get_local_pending_members_with_info (priv->group); + self_handle = empathy_tp_group_get_self_handle (priv->group); + members = empathy_tp_group_get_local_pending_members_with_info (priv->group); for (l = members; l; l = l->next) { - GossipTpGroupInfo *info; + EmpathyTpGroupInfo *info; info = l->data; @@ -175,12 +175,12 @@ empathy_tp_chatroom_new (McAccount *account, priv->invit_message = g_strdup (info->message); priv->is_invited = TRUE; - gossip_debug (DEBUG_DOMAIN, "We are invited to join by %s: %s", - gossip_contact_get_name (priv->invitor), + empathy_debug (DEBUG_DOMAIN, "We are invited to join by %s: %s", + empathy_contact_get_name (priv->invitor), priv->invit_message); } - gossip_telepathy_group_info_list_free (members); + empathy_tp_group_info_list_free (members); g_object_unref (mc); g_object_unref (tp_conn); @@ -189,7 +189,7 @@ empathy_tp_chatroom_new (McAccount *account, gboolean empathy_tp_chatroom_get_invitation (EmpathyTpChatroom *chatroom, - GossipContact **contact, + EmpathyContact **contact, const gchar **message) { EmpathyTpChatroomPriv *priv; @@ -228,8 +228,8 @@ empathy_tp_chatroom_accept_invitation (EmpathyTpChatroom *chatroom) priv->invit_message = NULL; /* Add ourself in the members of the room */ - self_handle = gossip_telepathy_group_get_self_handle (priv->group); - gossip_telepathy_group_add_member (priv->group, self_handle, + self_handle = empathy_tp_group_get_self_handle (priv->group); + empathy_tp_group_add_member (priv->group, self_handle, "Just for fun"); } @@ -240,12 +240,12 @@ empathy_tp_chatroom_set_topic (EmpathyTpChatroom *chatroom, } static void -tp_chatroom_members_added_cb (GossipTelepathyGroup *group, - GArray *handles, - guint actor_handle, - guint reason, - const gchar *message, - EmpathyTpChatroom *chatroom) +tp_chatroom_members_added_cb (EmpathyTpGroup *group, + GArray *handles, + guint actor_handle, + guint reason, + const gchar *message, + EmpathyTpChatroom *chatroom) { EmpathyTpChatroomPriv *priv; GList *contacts, *l; @@ -254,7 +254,7 @@ tp_chatroom_members_added_cb (GossipTelepathyGroup *group, contacts = empathy_tp_contact_list_get_from_handles (priv->list, handles); for (l = contacts; l; l = l->next) { - GossipContact *contact; + EmpathyContact *contact; contact = l->data; @@ -266,12 +266,12 @@ tp_chatroom_members_added_cb (GossipTelepathyGroup *group, } static void -tp_chatroom_members_removed_cb (GossipTelepathyGroup *group, - GArray *handles, - guint actor_handle, - guint reason, - const gchar *message, - EmpathyTpChatroom *chatroom) +tp_chatroom_members_removed_cb (EmpathyTpGroup *group, + GArray *handles, + guint actor_handle, + guint reason, + const gchar *message, + EmpathyTpChatroom *chatroom) { EmpathyTpChatroomPriv *priv; GList *contacts, *l; @@ -280,7 +280,7 @@ tp_chatroom_members_removed_cb (GossipTelepathyGroup *group, contacts = empathy_tp_contact_list_get_from_handles (priv->list, handles); for (l = contacts; l; l = l->next) { - GossipContact *contact; + EmpathyContact *contact; contact = l->data; @@ -297,7 +297,7 @@ tp_chatroom_setup (EmpathyContactList *list) /* Nothing to do */ } -static GossipContact * +static EmpathyContact * tp_chatroom_find (EmpathyContactList *list, const gchar *id) { @@ -306,36 +306,36 @@ tp_chatroom_find (EmpathyContactList *list, static void tp_chatroom_add (EmpathyContactList *list, - GossipContact *contact, + EmpathyContact *contact, const gchar *message) { EmpathyTpChatroomPriv *priv; g_return_if_fail (EMPATHY_IS_TP_CHATROOM (list)); - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); priv = GET_PRIV (list); - gossip_telepathy_group_add_member (priv->group, - gossip_contact_get_handle (contact), - message); + empathy_tp_group_add_member (priv->group, + empathy_contact_get_handle (contact), + message); } static void tp_chatroom_remove (EmpathyContactList *list, - GossipContact *contact, + EmpathyContact *contact, const gchar *message) { EmpathyTpChatroomPriv *priv; g_return_if_fail (EMPATHY_IS_TP_CHATROOM (list)); - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); priv = GET_PRIV (list); - gossip_telepathy_group_remove_member (priv->group, - gossip_contact_get_handle (contact), - message); + empathy_tp_group_remove_member (priv->group, + empathy_contact_get_handle (contact), + message); } static GList * @@ -349,7 +349,7 @@ tp_chatroom_get_members (EmpathyContactList *list) priv = GET_PRIV (list); - members = gossip_telepathy_group_get_members (priv->group); + members = empathy_tp_group_get_members (priv->group); contacts = empathy_tp_contact_list_get_from_handles (priv->list, members); g_array_free (members, TRUE); diff --git a/libempathy/empathy-tp-chatroom.h b/libempathy/empathy-tp-chatroom.h index 488ac74f..cbdd246c 100644 --- a/libempathy/empathy-tp-chatroom.h +++ b/libempathy/empathy-tp-chatroom.h @@ -56,7 +56,7 @@ GType empathy_tp_chatroom_get_type (void) G_GNUC_CONST; EmpathyTpChatroom *empathy_tp_chatroom_new (McAccount *account, TpChan *tp_chan); gboolean empathy_tp_chatroom_get_invitation (EmpathyTpChatroom *chatroom, - GossipContact **contact, + EmpathyContact **contact, const gchar **message); void empathy_tp_chatroom_accept_invitation (EmpathyTpChatroom *chatroom); void empathy_tp_chatroom_set_topic (EmpathyTpChatroom *chatroom, diff --git a/libempathy/empathy-tp-contact-list.c b/libempathy/empathy-tp-contact-list.c index c435218e..dd04fac5 100644 --- a/libempathy/empathy-tp-contact-list.c +++ b/libempathy/empathy-tp-contact-list.c @@ -35,9 +35,9 @@ #include "empathy-tp-contact-list.h" #include "empathy-contact-list.h" -#include "gossip-telepathy-group.h" -#include "gossip-debug.h" -#include "gossip-utils.h" +#include "empathy-tp-group.h" +#include "empathy-debug.h" +#include "empathy-utils.h" #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ EMPATHY_TYPE_TP_CONTACT_LIST, EmpathyTpContactListPriv)) @@ -46,25 +46,25 @@ #define MAX_AVATAR_REQUESTS 10 struct _EmpathyTpContactListPriv { - TpConn *tp_conn; - McAccount *account; - MissionControl *mc; - GossipContact *user_contact; - gboolean setup; + TpConn *tp_conn; + McAccount *account; + MissionControl *mc; + EmpathyContact *user_contact; + gboolean setup; - GossipTelepathyGroup *publish; - GossipTelepathyGroup *subscribe; + EmpathyTpGroup *publish; + EmpathyTpGroup *subscribe; - GHashTable *groups; - GHashTable *contacts; - GList *members; - GList *local_pending; + GHashTable *groups; + GHashTable *contacts; + GList *members; + GList *local_pending; - DBusGProxy *aliasing_iface; - DBusGProxy *avatars_iface; - DBusGProxy *presence_iface; + DBusGProxy *aliasing_iface; + DBusGProxy *avatars_iface; + DBusGProxy *presence_iface; - GList *avatar_requests_queue; + GList *avatar_requests_queue; }; typedef enum { @@ -89,129 +89,129 @@ typedef struct { guint *handles; } TpContactListAliasesRequestData; -static void empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass); -static void tp_contact_list_iface_init (EmpathyContactListIface *iface); -static void empathy_tp_contact_list_init (EmpathyTpContactList *list); -static void tp_contact_list_finalize (GObject *object); -static void tp_contact_list_finalize_proxies (EmpathyTpContactList *list); -static void tp_contact_list_setup (EmpathyContactList *list); -static GossipContact * tp_contact_list_find (EmpathyContactList *list, - const gchar *id); -static void tp_contact_list_add (EmpathyContactList *list, - GossipContact *contact, - const gchar *message); -static void tp_contact_list_remove (EmpathyContactList *list, - GossipContact *contact, - const gchar *message); -static GList * tp_contact_list_get_members (EmpathyContactList *list); -static GList * tp_contact_list_get_local_pending (EmpathyContactList *list); -static void tp_contact_list_process_pending (EmpathyContactList *list, - GossipContact *contact, - gboolean accept); -static void tp_contact_list_remove_local_pending (EmpathyTpContactList *list, - GossipContact *contact); -static void tp_contact_list_contact_removed_foreach (guint handle, - GossipContact *contact, - EmpathyTpContactList *list); -static void tp_contact_list_destroy_cb (DBusGProxy *proxy, - EmpathyTpContactList *list); -static gboolean tp_contact_list_find_foreach (guint handle, - GossipContact *contact, - gchar *id); -static void tp_contact_list_newchannel_cb (DBusGProxy *proxy, - const gchar *object_path, - const gchar *channel_type, - TelepathyHandleType handle_type, - guint channel_handle, - gboolean suppress_handle, - EmpathyTpContactList *list); -static TpContactListType tp_contact_list_get_type (EmpathyTpContactList *list, - GossipTelepathyGroup *group); -static void tp_contact_list_added_cb (GossipTelepathyGroup *group, - GArray *handles, - guint actor_handle, - guint reason, - const gchar *message, - EmpathyTpContactList *list); -static void tp_contact_list_removed_cb (GossipTelepathyGroup *group, - GArray *handles, - guint actor_handle, - guint reason, - const gchar *message, - EmpathyTpContactList *list); -static void tp_contact_list_pending_cb (GossipTelepathyGroup *group, - GArray *handles, - guint actor_handle, - guint reason, - const gchar *message, - EmpathyTpContactList *list); -static void tp_contact_list_groups_updated_cb (GossipContact *contact, - GParamSpec *param, - EmpathyTpContactList *list); -static void tp_contact_list_name_updated_cb (GossipContact *contact, - GParamSpec *param, - EmpathyTpContactList *list); -static void tp_contact_list_update_groups_foreach (gchar *object_path, - GossipTelepathyGroup *group, - TpContactListData *data); -static GossipTelepathyGroup * tp_contact_list_get_group (EmpathyTpContactList *list, - const gchar *name); -static gboolean tp_contact_list_find_group (gchar *key, - GossipTelepathyGroup *group, - gchar *group_name); -static void tp_contact_list_get_groups_foreach (gchar *key, - GossipTelepathyGroup *group, - GList **groups); -static void tp_contact_list_group_channel_closed_cb (TpChan *channel, - EmpathyTpContactList *list); -static void tp_contact_list_group_members_added_cb (GossipTelepathyGroup *group, - GArray *members, - guint actor_handle, - guint reason, - const gchar *message, - EmpathyTpContactList *list); -static void tp_contact_list_group_members_removed_cb (GossipTelepathyGroup *group, - GArray *members, - guint actor_handle, - guint reason, - const gchar *message, - EmpathyTpContactList *list); -static void tp_contact_list_get_info (EmpathyTpContactList *list, - GArray *handles); -static void tp_contact_list_request_avatar (EmpathyTpContactList *list, - guint handle); -static void tp_contact_list_start_avatar_requests (EmpathyTpContactList *list); -static void tp_contact_list_avatar_update_cb (DBusGProxy *proxy, - guint handle, - gchar *new_token, - EmpathyTpContactList *list); -static void tp_contact_list_request_avatar_cb (DBusGProxy *proxy, - GArray *avatar_data, - gchar *mime_type, - GError *error, - TpContactListAvatarRequestData *data); -static void tp_contact_list_aliases_update_cb (DBusGProxy *proxy, - GPtrArray *handlers, - EmpathyTpContactList *list); -static void tp_contact_list_request_aliases_cb (DBusGProxy *proxy, - gchar **contact_names, - GError *error, - TpContactListAliasesRequestData *data); -static void tp_contact_list_presence_update_cb (DBusGProxy *proxy, - GHashTable *handle_table, - EmpathyTpContactList *list); -static void tp_contact_list_parse_presence_foreach (guint handle, - GValueArray *presence_struct, - EmpathyTpContactList *list); -static void tp_contact_list_presences_table_foreach (const gchar *state_str, - GHashTable *presences_table, - GossipPresence **presence); -static void tp_contact_list_status_changed_cb (MissionControl *mc, - TelepathyConnectionStatus status, - McPresence presence, - TelepathyConnectionStatusReason reason, - const gchar *unique_name, - EmpathyTpContactList *list); +static void empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass); +static void tp_contact_list_iface_init (EmpathyContactListIface *iface); +static void empathy_tp_contact_list_init (EmpathyTpContactList *list); +static void tp_contact_list_finalize (GObject *object); +static void tp_contact_list_finalize_proxies (EmpathyTpContactList *list); +static void tp_contact_list_setup (EmpathyContactList *list); +static EmpathyContact * tp_contact_list_find (EmpathyContactList *list, + const gchar *id); +static void tp_contact_list_add (EmpathyContactList *list, + EmpathyContact *contact, + const gchar *message); +static void tp_contact_list_remove (EmpathyContactList *list, + EmpathyContact *contact, + const gchar *message); +static GList * tp_contact_list_get_members (EmpathyContactList *list); +static GList * tp_contact_list_get_local_pending (EmpathyContactList *list); +static void tp_contact_list_process_pending (EmpathyContactList *list, + EmpathyContact *contact, + gboolean accept); +static void tp_contact_list_remove_local_pending (EmpathyTpContactList *list, + EmpathyContact *contact); +static void tp_contact_list_contact_removed_foreach (guint handle, + EmpathyContact *contact, + EmpathyTpContactList *list); +static void tp_contact_list_destroy_cb (DBusGProxy *proxy, + EmpathyTpContactList *list); +static gboolean tp_contact_list_find_foreach (guint handle, + EmpathyContact *contact, + gchar *id); +static void tp_contact_list_newchannel_cb (DBusGProxy *proxy, + const gchar *object_path, + const gchar *channel_type, + TelepathyHandleType handle_type, + guint channel_handle, + gboolean suppress_handle, + EmpathyTpContactList *list); +static TpContactListType tp_contact_list_get_type (EmpathyTpContactList *list, + EmpathyTpGroup *group); +static void tp_contact_list_added_cb (EmpathyTpGroup *group, + GArray *handles, + guint actor_handle, + guint reason, + const gchar *message, + EmpathyTpContactList *list); +static void tp_contact_list_removed_cb (EmpathyTpGroup *group, + GArray *handles, + guint actor_handle, + guint reason, + const gchar *message, + EmpathyTpContactList *list); +static void tp_contact_list_pending_cb (EmpathyTpGroup *group, + GArray *handles, + guint actor_handle, + guint reason, + const gchar *message, + EmpathyTpContactList *list); +static void tp_contact_list_groups_updated_cb (EmpathyContact *contact, + GParamSpec *param, + EmpathyTpContactList *list); +static void tp_contact_list_name_updated_cb (EmpathyContact *contact, + GParamSpec *param, + EmpathyTpContactList *list); +static void tp_contact_list_update_groups_foreach (gchar *object_path, + EmpathyTpGroup *group, + TpContactListData *data); +static EmpathyTpGroup * tp_contact_list_get_group (EmpathyTpContactList *list, + const gchar *name); +static gboolean tp_contact_list_find_group (gchar *key, + EmpathyTpGroup *group, + gchar *group_name); +static void tp_contact_list_get_groups_foreach (gchar *key, + EmpathyTpGroup *group, + GList **groups); +static void tp_contact_list_group_channel_closed_cb (TpChan *channel, + EmpathyTpContactList *list); +static void tp_contact_list_group_members_added_cb (EmpathyTpGroup *group, + GArray *members, + guint actor_handle, + guint reason, + const gchar *message, + EmpathyTpContactList *list); +static void tp_contact_list_group_members_removed_cb (EmpathyTpGroup *group, + GArray *members, + guint actor_handle, + guint reason, + const gchar *message, + EmpathyTpContactList *list); +static void tp_contact_list_get_info (EmpathyTpContactList *list, + GArray *handles); +static void tp_contact_list_request_avatar (EmpathyTpContactList *list, + guint handle); +static void tp_contact_list_start_avatar_requests (EmpathyTpContactList *list); +static void tp_contact_list_avatar_update_cb (DBusGProxy *proxy, + guint handle, + gchar *new_token, + EmpathyTpContactList *list); +static void tp_contact_list_request_avatar_cb (DBusGProxy *proxy, + GArray *avatar_data, + gchar *mime_type, + GError *error, + TpContactListAvatarRequestData *data); +static void tp_contact_list_aliases_update_cb (DBusGProxy *proxy, + GPtrArray *handlers, + EmpathyTpContactList *list); +static void tp_contact_list_request_aliases_cb (DBusGProxy *proxy, + gchar **contact_names, + GError *error, + TpContactListAliasesRequestData *data); +static void tp_contact_list_presence_update_cb (DBusGProxy *proxy, + GHashTable *handle_table, + EmpathyTpContactList *list); +static void tp_contact_list_parse_presence_foreach (guint handle, + GValueArray *presence_struct, + EmpathyTpContactList *list); +static void tp_contact_list_presences_table_foreach (const gchar *state_str, + GHashTable *presences_table, + EmpathyPresence **presence); +static void tp_contact_list_status_changed_cb (MissionControl *mc, + TelepathyConnectionStatus status, + McPresence presence, + TelepathyConnectionStatusReason reason, + const gchar *unique_name, + EmpathyTpContactList *list); enum { DESTROY, @@ -283,7 +283,7 @@ tp_contact_list_finalize (GObject *object) list = EMPATHY_TP_CONTACT_LIST (object); priv = GET_PRIV (list); - gossip_debug (DEBUG_DOMAIN, "finalize: %p", object); + empathy_debug (DEBUG_DOMAIN, "finalize: %p", object); dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc), "AccountStatusChanged", @@ -328,7 +328,7 @@ empathy_tp_contact_list_new (McAccount *account) g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); - mc = gossip_mission_control_new (); + mc = empathy_mission_control_new (); if (mission_control_get_connection_status (mc, account, NULL) != 0) { /* The account is not connected, nothing to do. */ @@ -381,12 +381,12 @@ empathy_tp_contact_list_new (McAccount *account) /* Get our own handle and contact */ if (!tp_conn_get_self_handle (DBUS_G_PROXY (priv->tp_conn), &handle, &error)) { - gossip_debug (DEBUG_DOMAIN, "GetSelfHandle Error: %s", + empathy_debug (DEBUG_DOMAIN, "GetSelfHandle Error: %s", error ? error->message : "No error given"); g_clear_error (&error); } else { priv->user_contact = empathy_tp_contact_list_get_from_handle (list, handle); - gossip_contact_set_is_user (priv->user_contact, TRUE); + empathy_contact_set_is_user (priv->user_contact, TRUE); } return list; @@ -404,7 +404,7 @@ tp_contact_list_setup (EmpathyContactList *list) priv = GET_PRIV (list); - gossip_debug (DEBUG_DOMAIN, "setup contact list: %p", list); + empathy_debug (DEBUG_DOMAIN, "setup contact list: %p", list); priv->setup = TRUE; dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->tp_conn), "NewChannel", @@ -415,7 +415,7 @@ tp_contact_list_setup (EmpathyContactList *list) if (!tp_conn_list_channels (DBUS_G_PROXY (priv->tp_conn), &channels, &error)) { - gossip_debug (DEBUG_DOMAIN, + empathy_debug (DEBUG_DOMAIN, "Failed to get list of open channels: %s", error ? error->message : "No error given"); g_clear_error (&error); @@ -447,7 +447,7 @@ tp_contact_list_setup (EmpathyContactList *list) g_ptr_array_free (channels, TRUE); } -static GossipContact * +static EmpathyContact * tp_contact_list_find (EmpathyContactList *list, const gchar *id) { @@ -464,7 +464,7 @@ tp_contact_list_find (EmpathyContactList *list, static void tp_contact_list_add (EmpathyContactList *list, - GossipContact *contact, + EmpathyContact *contact, const gchar *message) { EmpathyTpContactListPriv *priv; @@ -474,13 +474,13 @@ tp_contact_list_add (EmpathyContactList *list, priv = GET_PRIV (list); - handle = gossip_contact_get_handle (contact); - gossip_telepathy_group_add_member (priv->subscribe, handle, message); + handle = empathy_contact_get_handle (contact); + empathy_tp_group_add_member (priv->subscribe, handle, message); } static void tp_contact_list_remove (EmpathyContactList *list, - GossipContact *contact, + EmpathyContact *contact, const gchar *message) { EmpathyTpContactListPriv *priv; @@ -490,8 +490,8 @@ tp_contact_list_remove (EmpathyContactList *list, priv = GET_PRIV (list); - handle = gossip_contact_get_handle (contact); - gossip_telepathy_group_remove_member (priv->subscribe, handle, message); + handle = empathy_contact_get_handle (contact); + empathy_tp_group_remove_member (priv->subscribe, handle, message); } static GList * @@ -521,22 +521,22 @@ tp_contact_list_get_local_pending (EmpathyContactList *list) static void tp_contact_list_process_pending (EmpathyContactList *list, - GossipContact *contact, + EmpathyContact *contact, gboolean accept) { EmpathyTpContactListPriv *priv; guint handle; g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); priv = GET_PRIV (list); - handle = gossip_contact_get_handle (contact); + handle = empathy_contact_get_handle (contact); if (accept) { - gossip_telepathy_group_add_member (priv->publish, handle, NULL); + empathy_tp_group_add_member (priv->publish, handle, NULL); } else { - gossip_telepathy_group_remove_member (priv->publish, handle, NULL); + empathy_tp_group_remove_member (priv->publish, handle, NULL); } } @@ -552,7 +552,7 @@ empathy_tp_contact_list_get_account (EmpathyTpContactList *list) return priv->account; } -GossipContact * +EmpathyContact * empathy_tp_contact_list_get_user (EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv; @@ -564,12 +564,12 @@ empathy_tp_contact_list_get_user (EmpathyTpContactList *list) return priv->user_contact; } -GossipContact * +EmpathyContact * empathy_tp_contact_list_get_from_id (EmpathyTpContactList *list, const gchar *id) { EmpathyTpContactListPriv *priv; - GossipContact *contact; + EmpathyContact *contact; const gchar *contact_ids[] = {id, NULL}; GArray *handles; guint handle; @@ -590,7 +590,7 @@ empathy_tp_contact_list_get_from_id (EmpathyTpContactList *list, TP_HANDLE_TYPE_CONTACT, contact_ids, &handles, &error)) { - gossip_debug (DEBUG_DOMAIN, + empathy_debug (DEBUG_DOMAIN, "RequestHandle for %s failed: %s", id, error ? error->message : "No error given"); g_clear_error (&error); @@ -603,11 +603,11 @@ empathy_tp_contact_list_get_from_id (EmpathyTpContactList *list, return empathy_tp_contact_list_get_from_handle (list, handle); } -GossipContact * +EmpathyContact * empathy_tp_contact_list_get_from_handle (EmpathyTpContactList *list, guint handle) { - GossipContact *contact; + EmpathyContact *contact; GArray *handles; GList *contacts; @@ -649,7 +649,7 @@ empathy_tp_contact_list_get_from_handles (EmpathyTpContactList *list, /* Search all handles we already have */ new_handles = g_array_new (FALSE, FALSE, sizeof (guint)); for (i = 0; i < handles->len; i++) { - GossipContact *contact; + EmpathyContact *contact; guint handle; handle = g_array_index (handles, guint, i); @@ -679,7 +679,7 @@ empathy_tp_contact_list_get_from_handles (EmpathyTpContactList *list, if (!tp_conn_hold_handles (DBUS_G_PROXY (priv->tp_conn), TP_HANDLE_TYPE_CONTACT, new_handles, &error)) { - gossip_debug (DEBUG_DOMAIN, + empathy_debug (DEBUG_DOMAIN, "HoldHandles Error: %s", error ? error->message : "No error given"); g_clear_error (&error); @@ -693,7 +693,7 @@ empathy_tp_contact_list_get_from_handles (EmpathyTpContactList *list, new_handles, &handles_names, &error)) { - gossip_debug (DEBUG_DOMAIN, + empathy_debug (DEBUG_DOMAIN, "InspectHandle Error: %s", error ? error->message : "No error given"); g_clear_error (&error); @@ -703,25 +703,25 @@ empathy_tp_contact_list_get_from_handles (EmpathyTpContactList *list, /* Create contact objects */ for (i = 0, id = handles_names; *id && i < new_handles->len; id++, i++) { - GossipContact *contact; + EmpathyContact *contact; guint handle; handle = g_array_index (new_handles, guint, i); - contact = g_object_new (GOSSIP_TYPE_CONTACT, + contact = g_object_new (EMPATHY_TYPE_CONTACT, "account", priv->account, "id", *id, "handle", handle, NULL); if (!priv->presence_iface) { - GossipPresence *presence; + EmpathyPresence *presence; /* We have no presence iface, set default presence * to available */ - presence = gossip_presence_new_full (MC_PRESENCE_AVAILABLE, + presence = empathy_presence_new_full (MC_PRESENCE_AVAILABLE, NULL); - gossip_contact_set_presence (contact, presence); + empathy_contact_set_presence (contact, presence); g_object_unref (presence); } @@ -732,7 +732,7 @@ empathy_tp_contact_list_get_from_handles (EmpathyTpContactList *list, G_CALLBACK (tp_contact_list_name_updated_cb), list); - gossip_debug (DEBUG_DOMAIN, "new contact created: %s (%d)", + empathy_debug (DEBUG_DOMAIN, "new contact created: %s (%d)", *id, handle); g_hash_table_insert (priv->contacts, @@ -756,7 +756,7 @@ empathy_tp_contact_list_rename_group (EmpathyTpContactList *list, const gchar *new_group) { EmpathyTpContactListPriv *priv; - GossipTelepathyGroup *group; + EmpathyTpGroup *group; GArray *members; g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); @@ -773,22 +773,22 @@ empathy_tp_contact_list_rename_group (EmpathyTpContactList *list, return; } - gossip_debug (DEBUG_DOMAIN, "rename group %s to %s", group, new_group); + empathy_debug (DEBUG_DOMAIN, "rename group %s to %s", group, new_group); /* Remove all members from the old group */ - members = gossip_telepathy_group_get_members (group); - gossip_telepathy_group_remove_members (group, members, ""); + members = empathy_tp_group_get_members (group); + empathy_tp_group_remove_members (group, members, ""); tp_contact_list_group_members_removed_cb (group, members, - 0, - TP_CHANNEL_GROUP_CHANGE_REASON_NONE, - NULL, list); + 0, + TP_CHANNEL_GROUP_CHANGE_REASON_NONE, + NULL, list); g_hash_table_remove (priv->groups, - gossip_telepathy_group_get_object_path (group)); + empathy_tp_group_get_object_path (group)); /* Add all members to the new group */ group = tp_contact_list_get_group (list, new_group); if (group) { - gossip_telepathy_group_add_members (group, members, ""); + empathy_tp_group_add_members (group, members, ""); } } @@ -857,7 +857,7 @@ tp_contact_list_destroy_cb (DBusGProxy *proxy, priv = GET_PRIV (list); - gossip_debug (DEBUG_DOMAIN, "Connection destroyed... " + empathy_debug (DEBUG_DOMAIN, "Connection destroyed... " "Account disconnected or CM crashed"); /* DBus proxies should NOT be used anymore */ @@ -879,7 +879,7 @@ tp_contact_list_destroy_cb (DBusGProxy *proxy, static void tp_contact_list_contact_removed_foreach (guint handle, - GossipContact *contact, + EmpathyContact *contact, EmpathyTpContactList *list) { g_signal_handlers_disconnect_by_func (contact, @@ -894,7 +894,7 @@ tp_contact_list_contact_removed_foreach (guint handle, static void tp_contact_list_block_contact (EmpathyTpContactList *list, - GossipContact *contact) + EmpathyContact *contact) { g_signal_handlers_block_by_func (contact, tp_contact_list_groups_updated_cb, @@ -906,7 +906,7 @@ tp_contact_list_block_contact (EmpathyTpContactList *list, static void tp_contact_list_unblock_contact (EmpathyTpContactList *list, - GossipContact *contact) + EmpathyContact *contact) { g_signal_handlers_unblock_by_func (contact, tp_contact_list_groups_updated_cb, @@ -918,10 +918,10 @@ tp_contact_list_unblock_contact (EmpathyTpContactList *list, static gboolean tp_contact_list_find_foreach (guint handle, - GossipContact *contact, + EmpathyContact *contact, gchar *id) { - if (strcmp (gossip_contact_get_id (contact), id) == 0) { + if (strcmp (empathy_contact_get_id (contact), id) == 0) { return TRUE; } @@ -938,7 +938,7 @@ tp_contact_list_newchannel_cb (DBusGProxy *proxy, EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv; - GossipTelepathyGroup *group; + EmpathyTpGroup *group; TpChan *new_chan; const gchar *bus_name; GArray *members; @@ -960,19 +960,19 @@ tp_contact_list_newchannel_cb (DBusGProxy *proxy, if (handle_type == TP_HANDLE_TYPE_LIST) { TpContactListType list_type; - group = gossip_telepathy_group_new (new_chan, priv->tp_conn); + group = empathy_tp_group_new (new_chan, priv->tp_conn); list_type = tp_contact_list_get_type (list, group); if (list_type == TP_CONTACT_LIST_TYPE_UNKNOWN) { - gossip_debug (DEBUG_DOMAIN, + empathy_debug (DEBUG_DOMAIN, "Type of contact list channel unknown: %s", - gossip_telepathy_group_get_name (group)); + empathy_tp_group_get_name (group)); g_object_unref (new_chan); g_object_unref (group); return; } else { - gossip_debug (DEBUG_DOMAIN, + empathy_debug (DEBUG_DOMAIN, "New contact list channel of type: %d", list_type); } @@ -997,13 +997,13 @@ tp_contact_list_newchannel_cb (DBusGProxy *proxy, G_CALLBACK (tp_contact_list_pending_cb), list); - pendings = gossip_telepathy_group_get_local_pending_members_with_info (group); + pendings = empathy_tp_group_get_local_pending_members_with_info (group); if (pendings) { GArray *pending; pending = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); for (l = pendings; l; l = l->next) { - GossipTpGroupInfo *info; + EmpathyTpGroupInfo *info; info = l->data; @@ -1015,7 +1015,7 @@ tp_contact_list_newchannel_cb (DBusGProxy *proxy, list); } g_array_free (pending, TRUE); - gossip_telepathy_group_info_list_free (pendings); + empathy_tp_group_info_list_free (pendings); } } if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE) { @@ -1030,10 +1030,10 @@ tp_contact_list_newchannel_cb (DBusGProxy *proxy, g_signal_connect (group, "remote-pending", G_CALLBACK (tp_contact_list_pending_cb), list); - gossip_telepathy_group_get_all_members (group, - &members, - NULL, - &remote_pendings); + empathy_tp_group_get_all_members (group, + &members, + NULL, + &remote_pendings); tp_contact_list_pending_cb (group, remote_pendings, 0, TP_CHANNEL_GROUP_CHANGE_REASON_NONE, @@ -1041,7 +1041,7 @@ tp_contact_list_newchannel_cb (DBusGProxy *proxy, list); g_array_free (remote_pendings, TRUE); } else { - members = gossip_telepathy_group_get_members (group); + members = empathy_tp_group_get_members (group); } tp_contact_list_added_cb (group, members, 0, @@ -1058,10 +1058,10 @@ tp_contact_list_newchannel_cb (DBusGProxy *proxy, return; } - group = gossip_telepathy_group_new (new_chan, priv->tp_conn); + group = empathy_tp_group_new (new_chan, priv->tp_conn); - gossip_debug (DEBUG_DOMAIN, "New server-side group channel: %s", - gossip_telepathy_group_get_name (group)); + empathy_debug (DEBUG_DOMAIN, "New server-side group channel: %s", + empathy_tp_group_get_name (group)); dbus_g_proxy_connect_signal (DBUS_G_PROXY (new_chan), "Closed", G_CALLBACK @@ -1076,10 +1076,10 @@ tp_contact_list_newchannel_cb (DBusGProxy *proxy, G_CALLBACK (tp_contact_list_group_members_removed_cb), list); - members = gossip_telepathy_group_get_members (group); + members = empathy_tp_group_get_members (group); tp_contact_list_group_members_added_cb (group, members, 0, - TP_CHANNEL_GROUP_CHANGE_REASON_NONE, - NULL, list); + TP_CHANNEL_GROUP_CHANGE_REASON_NONE, + NULL, list); g_array_free (members, TRUE); } @@ -1088,15 +1088,15 @@ tp_contact_list_newchannel_cb (DBusGProxy *proxy, static TpContactListType tp_contact_list_get_type (EmpathyTpContactList *list, - GossipTelepathyGroup *group) + EmpathyTpGroup *group) { - EmpathyTpContactListPriv *priv; - TpContactListType list_type; - const gchar *name; + EmpathyTpContactListPriv *priv; + TpContactListType list_type; + const gchar *name; priv = GET_PRIV (list); - name = gossip_telepathy_group_get_name (group); + name = empathy_tp_group_get_name (group); if (strcmp (name, "subscribe") == 0) { list_type = TP_CONTACT_LIST_TYPE_SUBSCRIBE; } else if (strcmp (name, "publish") == 0) { @@ -1109,7 +1109,7 @@ tp_contact_list_get_type (EmpathyTpContactList *list, } static void -tp_contact_list_added_cb (GossipTelepathyGroup *group, +tp_contact_list_added_cb (EmpathyTpGroup *group, GArray *handles, guint actor_handle, guint reason, @@ -1126,26 +1126,26 @@ tp_contact_list_added_cb (GossipTelepathyGroup *group, added_list = empathy_tp_contact_list_get_from_handles (list, handles); for (l = added_list; l; l = l->next) { - GossipContact *contact; - GossipSubscription subscription; + EmpathyContact *contact; + EmpathySubscription subscription; - contact = GOSSIP_CONTACT (l->data); + contact = EMPATHY_CONTACT (l->data); - gossip_debug (DEBUG_DOMAIN, "Contact '%s' added to list type %d", - gossip_contact_get_name (contact), + empathy_debug (DEBUG_DOMAIN, "Contact '%s' added to list type %d", + empathy_contact_get_name (contact), list_type); - subscription = gossip_contact_get_subscription (contact); + subscription = empathy_contact_get_subscription (contact); if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE) { - subscription |= GOSSIP_SUBSCRIPTION_FROM; + subscription |= EMPATHY_SUBSCRIPTION_FROM; } else if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH) { - subscription |= GOSSIP_SUBSCRIPTION_TO; + subscription |= EMPATHY_SUBSCRIPTION_TO; tp_contact_list_remove_local_pending (list, contact); } tp_contact_list_block_contact (list, contact); - gossip_contact_set_subscription (contact, subscription); + empathy_contact_set_subscription (contact, subscription); tp_contact_list_unblock_contact (list, contact); if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE) { @@ -1163,7 +1163,7 @@ tp_contact_list_added_cb (GossipTelepathyGroup *group, } static void -tp_contact_list_removed_cb (GossipTelepathyGroup *group, +tp_contact_list_removed_cb (EmpathyTpGroup *group, GArray *handles, guint actor_handle, guint reason, @@ -1180,26 +1180,26 @@ tp_contact_list_removed_cb (GossipTelepathyGroup *group, removed_list = empathy_tp_contact_list_get_from_handles (list, handles); for (l = removed_list; l; l = l->next) { - GossipContact *contact; - GossipSubscription subscription; + EmpathyContact *contact; + EmpathySubscription subscription; - contact = GOSSIP_CONTACT (l->data); + contact = EMPATHY_CONTACT (l->data); - gossip_debug (DEBUG_DOMAIN, "Contact '%s' removed from list type %d", - gossip_contact_get_name (contact), + empathy_debug (DEBUG_DOMAIN, "Contact '%s' removed from list type %d", + empathy_contact_get_name (contact), list_type); - subscription = gossip_contact_get_subscription (contact); + subscription = empathy_contact_get_subscription (contact); if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE) { - subscription &= !GOSSIP_SUBSCRIPTION_FROM; + subscription &= !EMPATHY_SUBSCRIPTION_FROM; } else if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH) { - subscription &= !GOSSIP_SUBSCRIPTION_TO; + subscription &= !EMPATHY_SUBSCRIPTION_TO; tp_contact_list_remove_local_pending (list, contact); } tp_contact_list_block_contact (list, contact); - gossip_contact_set_subscription (contact, subscription); + empathy_contact_set_subscription (contact, subscription); tp_contact_list_unblock_contact (list, contact); if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE) { @@ -1218,7 +1218,7 @@ tp_contact_list_removed_cb (GossipTelepathyGroup *group, } static void -tp_contact_list_pending_cb (GossipTelepathyGroup *group, +tp_contact_list_pending_cb (EmpathyTpGroup *group, GArray *handles, guint actor_handle, guint reason, @@ -1235,12 +1235,12 @@ tp_contact_list_pending_cb (GossipTelepathyGroup *group, pending_list = empathy_tp_contact_list_get_from_handles (list, handles); for (l = pending_list; l; l = l->next) { - GossipContact *contact; + EmpathyContact *contact; - contact = GOSSIP_CONTACT (l->data); + contact = EMPATHY_CONTACT (l->data); - gossip_debug (DEBUG_DOMAIN, "Contact '%s' pending in list type %d", - gossip_contact_get_name (contact), + empathy_debug (DEBUG_DOMAIN, "Contact '%s' pending in list type %d", + empathy_contact_get_name (contact), list_type); if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH) { @@ -1269,7 +1269,7 @@ tp_contact_list_pending_cb (GossipTelepathyGroup *group, static void tp_contact_list_remove_local_pending (EmpathyTpContactList *list, - GossipContact *contact) + EmpathyContact *contact) { EmpathyTpContactListPriv *priv; GList *l; @@ -1280,9 +1280,9 @@ tp_contact_list_remove_local_pending (EmpathyTpContactList *list, EmpathyContactListInfo *info; info = l->data; - if (gossip_contact_equal (contact, info->contact)) { - gossip_debug (DEBUG_DOMAIN, "Contact no more local-pending: %s", - gossip_contact_get_name (contact)); + if (empathy_contact_equal (contact, info->contact)) { + empathy_debug (DEBUG_DOMAIN, "Contact no more local-pending: %s", + empathy_contact_get_name (contact)); priv->local_pending = g_list_delete_link (priv->local_pending, l); empathy_contact_list_info_free (info); @@ -1292,7 +1292,7 @@ tp_contact_list_remove_local_pending (EmpathyTpContactList *list, } static void -tp_contact_list_groups_updated_cb (GossipContact *contact, +tp_contact_list_groups_updated_cb (EmpathyContact *contact, GParamSpec *param, EmpathyTpContactList *list) { @@ -1303,12 +1303,12 @@ tp_contact_list_groups_updated_cb (GossipContact *contact, priv = GET_PRIV (list); /* Make sure all groups are created */ - groups = gossip_contact_get_groups (contact); + groups = empathy_contact_get_groups (contact); for (l = groups; l; l = l->next) { tp_contact_list_get_group (list, l->data); } - data.handle = gossip_contact_get_handle (contact); + data.handle = empathy_contact_get_handle (contact); data.new_groups = groups; g_hash_table_foreach (priv->groups, @@ -1317,7 +1317,7 @@ tp_contact_list_groups_updated_cb (GossipContact *contact, } static void -tp_contact_list_name_updated_cb (GossipContact *contact, +tp_contact_list_name_updated_cb (EmpathyContact *contact, GParamSpec *param, EmpathyTpContactList *list) { @@ -1333,10 +1333,10 @@ tp_contact_list_name_updated_cb (GossipContact *contact, return; } - handle = gossip_contact_get_handle (contact); - new_name = gossip_contact_get_name (contact); + handle = empathy_contact_get_handle (contact); + new_name = empathy_contact_get_name (contact); - gossip_debug (DEBUG_DOMAIN, "renaming handle %d to %s", + empathy_debug (DEBUG_DOMAIN, "renaming handle %d to %s", handle, new_name); new_alias = g_hash_table_new_full (g_direct_hash, @@ -1351,7 +1351,7 @@ tp_contact_list_name_updated_cb (GossipContact *contact, if (!tp_conn_iface_aliasing_set_aliases (priv->aliasing_iface, new_alias, &error)) { - gossip_debug (DEBUG_DOMAIN, + empathy_debug (DEBUG_DOMAIN, "Couldn't rename contact: %s", error ? error->message : "No error given"); g_clear_error (&error); @@ -1361,17 +1361,17 @@ tp_contact_list_name_updated_cb (GossipContact *contact, } static void -tp_contact_list_update_groups_foreach (gchar *object_path, - GossipTelepathyGroup *group, - TpContactListData *data) +tp_contact_list_update_groups_foreach (gchar *object_path, + EmpathyTpGroup *group, + TpContactListData *data) { gboolean is_member; gboolean found = FALSE; const gchar *group_name; GList *l; - is_member = gossip_telepathy_group_is_member (group, data->handle); - group_name = gossip_telepathy_group_get_name (group); + is_member = empathy_tp_group_is_member (group, data->handle); + group_name = empathy_tp_group_get_name (group); for (l = data->new_groups; l; l = l->next) { if (strcmp (group_name, l->data) == 0) { @@ -1382,25 +1382,25 @@ tp_contact_list_update_groups_foreach (gchar *object_path, if (is_member && !found) { /* We are no longer member of this group */ - gossip_debug (DEBUG_DOMAIN, "Contact %d removed from group '%s'", + empathy_debug (DEBUG_DOMAIN, "Contact %d removed from group '%s'", data->handle, group_name); - gossip_telepathy_group_remove_member (group, data->handle, ""); + empathy_tp_group_remove_member (group, data->handle, ""); } if (!is_member && found) { /* We are now member of this group */ - gossip_debug (DEBUG_DOMAIN, "Contact %d added to group '%s'", + empathy_debug (DEBUG_DOMAIN, "Contact %d added to group '%s'", data->handle, group_name); - gossip_telepathy_group_add_member (group, data->handle, ""); + empathy_tp_group_add_member (group, data->handle, ""); } } -static GossipTelepathyGroup * +static EmpathyTpGroup * tp_contact_list_get_group (EmpathyTpContactList *list, const gchar *name) { EmpathyTpContactListPriv *priv; - GossipTelepathyGroup *group; + EmpathyTpGroup *group; TpChan *group_channel; GArray *handles; guint group_handle; @@ -1417,14 +1417,14 @@ tp_contact_list_get_group (EmpathyTpContactList *list, return group; } - gossip_debug (DEBUG_DOMAIN, "creating new group: %s", name); + empathy_debug (DEBUG_DOMAIN, "creating new group: %s", name); if (!tp_conn_request_handles (DBUS_G_PROXY (priv->tp_conn), TP_HANDLE_TYPE_GROUP, names, &handles, &error)) { - gossip_debug (DEBUG_DOMAIN, + empathy_debug (DEBUG_DOMAIN, "Couldn't request the creation of a new handle for group: %s", error ? error->message : "No error given"); g_clear_error (&error); @@ -1440,7 +1440,7 @@ tp_contact_list_get_group (EmpathyTpContactList *list, FALSE, &group_object_path, &error)) { - gossip_debug (DEBUG_DOMAIN, + empathy_debug (DEBUG_DOMAIN, "Couldn't request the creation of a new group channel: %s", error ? error->message : "No error given"); g_clear_error (&error); @@ -1461,7 +1461,7 @@ tp_contact_list_get_group (EmpathyTpContactList *list, list, NULL); - group = gossip_telepathy_group_new (group_channel, priv->tp_conn); + group = empathy_tp_group_new (group_channel, priv->tp_conn); g_hash_table_insert (priv->groups, group_object_path, group); g_signal_connect (group, "members-added", G_CALLBACK (tp_contact_list_group_members_added_cb), @@ -1474,11 +1474,11 @@ tp_contact_list_get_group (EmpathyTpContactList *list, } static gboolean -tp_contact_list_find_group (gchar *key, - GossipTelepathyGroup *group, - gchar *group_name) +tp_contact_list_find_group (gchar *key, + EmpathyTpGroup *group, + gchar *group_name) { - if (strcmp (group_name, gossip_telepathy_group_get_name (group)) == 0) { + if (strcmp (group_name, empathy_tp_group_get_name (group)) == 0) { return TRUE; } @@ -1486,13 +1486,13 @@ tp_contact_list_find_group (gchar *key, } static void -tp_contact_list_get_groups_foreach (gchar *key, - GossipTelepathyGroup *group, - GList **groups) +tp_contact_list_get_groups_foreach (gchar *key, + EmpathyTpGroup *group, + GList **groups) { const gchar *name; - name = gossip_telepathy_group_get_name (group); + name = empathy_tp_group_get_name (group); *groups = g_list_append (*groups, g_strdup (name)); } @@ -1509,7 +1509,7 @@ tp_contact_list_group_channel_closed_cb (TpChan *channel, } static void -tp_contact_list_group_members_added_cb (GossipTelepathyGroup *group, +tp_contact_list_group_members_added_cb (EmpathyTpGroup *group, GArray *members, guint actor_handle, guint reason, @@ -1522,16 +1522,16 @@ tp_contact_list_group_members_added_cb (GossipTelepathyGroup *group, priv = GET_PRIV (list); - group_name = gossip_telepathy_group_get_name (group); + group_name = empathy_tp_group_get_name (group); added_list = empathy_tp_contact_list_get_from_handles (list, members); for (l = added_list; l; l = l->next) { - GossipContact *contact; + EmpathyContact *contact; - contact = GOSSIP_CONTACT (l->data); + contact = EMPATHY_CONTACT (l->data); tp_contact_list_block_contact (list, contact); - gossip_contact_add_group (contact, group_name); + empathy_contact_add_group (contact, group_name); tp_contact_list_unblock_contact (list, contact); g_object_unref (contact); @@ -1541,7 +1541,7 @@ tp_contact_list_group_members_added_cb (GossipTelepathyGroup *group, } static void -tp_contact_list_group_members_removed_cb (GossipTelepathyGroup *group, +tp_contact_list_group_members_removed_cb (EmpathyTpGroup *group, GArray *members, guint actor_handle, guint reason, @@ -1554,16 +1554,16 @@ tp_contact_list_group_members_removed_cb (GossipTelepathyGroup *group, priv = GET_PRIV (list); - group_name = gossip_telepathy_group_get_name (group); + group_name = empathy_tp_group_get_name (group); removed_list = empathy_tp_contact_list_get_from_handles (list, members); for (l = removed_list; l; l = l->next) { - GossipContact *contact; + EmpathyContact *contact; contact = l->data; tp_contact_list_block_contact (list, contact); - gossip_contact_remove_group (contact, group_name); + empathy_contact_remove_group (contact, group_name); tp_contact_list_unblock_contact (list, contact); g_object_unref (contact); @@ -1585,7 +1585,7 @@ tp_contact_list_get_info (EmpathyTpContactList *list, /* FIXME: We should use GetPresence instead */ if (!tp_conn_iface_presence_request_presence (priv->presence_iface, handles, &error)) { - gossip_debug (DEBUG_DOMAIN, + empathy_debug (DEBUG_DOMAIN, "Could not request presences: %s", error ? error->message : "No error given"); g_clear_error (&error); @@ -1675,7 +1675,7 @@ tp_contact_list_avatar_update_cb (DBusGProxy *proxy, return; } - gossip_debug (DEBUG_DOMAIN, "Changing avatar for %d to %s", + empathy_debug (DEBUG_DOMAIN, "Changing avatar for %d to %s", handle, new_token); tp_contact_list_request_avatar (list, handle); @@ -1688,24 +1688,24 @@ tp_contact_list_request_avatar_cb (DBusGProxy *proxy, GError *error, TpContactListAvatarRequestData *data) { - GossipContact *contact; + EmpathyContact *contact; contact = empathy_tp_contact_list_get_from_handle (data->list, data->handle); if (error) { - gossip_debug (DEBUG_DOMAIN, "Error requesting avatar for %s: %s", - gossip_contact_get_name (contact), + empathy_debug (DEBUG_DOMAIN, "Error requesting avatar for %s: %s", + empathy_contact_get_name (contact), error ? error->message : "No error given"); } else { - GossipAvatar *avatar; + EmpathyAvatar *avatar; - avatar = gossip_avatar_new (avatar_data->data, + avatar = empathy_avatar_new (avatar_data->data, avatar_data->len, mime_type); tp_contact_list_block_contact (data->list, contact); - gossip_contact_set_avatar (contact, avatar); + empathy_contact_set_avatar (contact, avatar); tp_contact_list_unblock_contact (data->list, contact); - gossip_avatar_unref (avatar); + empathy_avatar_unref (avatar); } n_avatar_requests--; @@ -1729,7 +1729,7 @@ tp_contact_list_aliases_update_cb (DBusGProxy *proxy, guint handle; const gchar *alias; GValueArray *renamed_struct; - GossipContact *contact; + EmpathyContact *contact; renamed_struct = g_ptr_array_index (renamed_handlers, i); handle = g_value_get_uint(g_value_array_get_nth (renamed_struct, 0)); @@ -1746,11 +1746,11 @@ tp_contact_list_aliases_update_cb (DBusGProxy *proxy, contact = empathy_tp_contact_list_get_from_handle (list, handle); tp_contact_list_block_contact (list, contact); - gossip_contact_set_name (contact, alias); + empathy_contact_set_name (contact, alias); tp_contact_list_unblock_contact (list, contact); g_object_unref (contact); - gossip_debug (DEBUG_DOMAIN, "contact %d renamed to %s (update cb)", + empathy_debug (DEBUG_DOMAIN, "contact %d renamed to %s (update cb)", handle, alias); } } @@ -1765,21 +1765,21 @@ tp_contact_list_request_aliases_cb (DBusGProxy *proxy, gchar **name; if (error) { - gossip_debug (DEBUG_DOMAIN, "Error requesting aliases: %s", + empathy_debug (DEBUG_DOMAIN, "Error requesting aliases: %s", error->message); } for (name = contact_names; *name && !error; name++) { - GossipContact *contact; + EmpathyContact *contact; contact = empathy_tp_contact_list_get_from_handle (data->list, data->handles[i]); tp_contact_list_block_contact (data->list, contact); - gossip_contact_set_name (contact, *name); + empathy_contact_set_name (contact, *name); tp_contact_list_unblock_contact (data->list, contact); g_object_unref (contact); - gossip_debug (DEBUG_DOMAIN, "contact %d renamed to %s (request cb)", + empathy_debug (DEBUG_DOMAIN, "contact %d renamed to %s (request cb)", data->handles[i], *name); i++; @@ -1806,8 +1806,8 @@ tp_contact_list_parse_presence_foreach (guint handle, { EmpathyTpContactListPriv *priv; GHashTable *presences_table; - GossipContact *contact; - GossipPresence *presence = NULL; + EmpathyContact *contact; + EmpathyPresence *presence = NULL; priv = GET_PRIV (list); @@ -1823,14 +1823,14 @@ tp_contact_list_parse_presence_foreach (guint handle, (GHFunc) tp_contact_list_presences_table_foreach, &presence); - gossip_debug (DEBUG_DOMAIN, "Presence changed for %s (%d) to %s (%d)", - gossip_contact_get_name (contact), + empathy_debug (DEBUG_DOMAIN, "Presence changed for %s (%d) to %s (%d)", + empathy_contact_get_name (contact), handle, - presence ? gossip_presence_get_status (presence) : "unset", - presence ? gossip_presence_get_state (presence) : MC_PRESENCE_UNSET); + presence ? empathy_presence_get_status (presence) : "unset", + presence ? empathy_presence_get_state (presence) : MC_PRESENCE_UNSET); tp_contact_list_block_contact (list, contact); - gossip_contact_set_presence (contact, presence); + empathy_contact_set_presence (contact, presence); tp_contact_list_unblock_contact (list, contact); g_object_unref (contact); @@ -1839,12 +1839,12 @@ tp_contact_list_parse_presence_foreach (guint handle, static void tp_contact_list_presences_table_foreach (const gchar *state_str, GHashTable *presences_table, - GossipPresence **presence) + EmpathyPresence **presence) { McPresence state; const GValue *message; - state = gossip_presence_state_from_str (state_str); + state = empathy_presence_state_from_str (state_str); if ((state == MC_PRESENCE_UNSET) || (state == MC_PRESENCE_OFFLINE)) { return; } @@ -1854,12 +1854,12 @@ tp_contact_list_presences_table_foreach (const gchar *state_str, *presence = NULL; } - *presence = gossip_presence_new (); - gossip_presence_set_state (*presence, state); + *presence = empathy_presence_new (); + empathy_presence_set_state (*presence, state); message = g_hash_table_lookup (presences_table, "message"); if (message != NULL) { - gossip_presence_set_status (*presence, + empathy_presence_set_status (*presence, g_value_get_string (message)); } } @@ -1879,7 +1879,7 @@ tp_contact_list_status_changed_cb (MissionControl *mc, account = mc_account_lookup (unique_name); if (status != TP_CONN_STATUS_DISCONNECTED || - !gossip_account_equal (account, priv->account) || + !empathy_account_equal (account, priv->account) || !priv->tp_conn) { g_object_unref (account); return; diff --git a/libempathy/empathy-tp-contact-list.h b/libempathy/empathy-tp-contact-list.h index 58074132..f0eccb37 100644 --- a/libempathy/empathy-tp-contact-list.h +++ b/libempathy/empathy-tp-contact-list.h @@ -27,7 +27,7 @@ #include #include -#include "gossip-contact.h" +#include "empathy-contact.h" G_BEGIN_DECLS @@ -53,10 +53,10 @@ struct _EmpathyTpContactListClass { GType empathy_tp_contact_list_get_type (void) G_GNUC_CONST; EmpathyTpContactList * empathy_tp_contact_list_new (McAccount *account); McAccount * empathy_tp_contact_list_get_account (EmpathyTpContactList *list); -GossipContact * empathy_tp_contact_list_get_user (EmpathyTpContactList *list); -GossipContact * empathy_tp_contact_list_get_from_id (EmpathyTpContactList *list, +EmpathyContact * empathy_tp_contact_list_get_user (EmpathyTpContactList *list); +EmpathyContact * empathy_tp_contact_list_get_from_id (EmpathyTpContactList *list, const gchar *id); -GossipContact * empathy_tp_contact_list_get_from_handle (EmpathyTpContactList *list, +EmpathyContact * empathy_tp_contact_list_get_from_handle (EmpathyTpContactList *list, guint handle); GList * empathy_tp_contact_list_get_from_handles (EmpathyTpContactList *list, GArray *handles); diff --git a/libempathy/empathy-tp-group.c b/libempathy/empathy-tp-group.c new file mode 100644 index 00000000..45a5e784 --- /dev/null +++ b/libempathy/empathy-tp-group.c @@ -0,0 +1,542 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006 Xavier Claessens + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include +#include +#include +#include +#include + +#include "empathy-debug.h" +#include "empathy-tp-group.h" +#include "empathy-marshal.h" + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ + EMPATHY_TYPE_TP_GROUP, EmpathyTpGroupPriv)) + +#define DEBUG_DOMAIN "TpGroup" + +struct _EmpathyTpGroupPriv { + DBusGProxy *group_iface; + TpConn *tp_conn; + TpChan *tp_chan; + gchar *group_name; +}; + +static void empathy_tp_group_class_init (EmpathyTpGroupClass *klass); +static void empathy_tp_group_init (EmpathyTpGroup *group); +static void tp_group_finalize (GObject *object); +static void tp_group_destroy_cb (DBusGProxy *proxy, + EmpathyTpGroup *group); +static void tp_group_members_changed_cb (DBusGProxy *group_iface, + gchar *message, + GArray *added, + GArray *removed, + GArray *local_pending, + GArray *remote_pending, + guint actor, + guint reason, + EmpathyTpGroup *group); + +enum { + MEMBERS_ADDED, + MEMBERS_REMOVED, + LOCAL_PENDING, + REMOTE_PENDING, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +G_DEFINE_TYPE (EmpathyTpGroup, empathy_tp_group, G_TYPE_OBJECT); + +static void +empathy_tp_group_class_init (EmpathyTpGroupClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = tp_group_finalize; + + signals[MEMBERS_ADDED] = + g_signal_new ("members-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + empathy_marshal_VOID__POINTER_UINT_UINT_STRING, + G_TYPE_NONE, + 4, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING); + + signals[MEMBERS_REMOVED] = + g_signal_new ("members-removed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + empathy_marshal_VOID__POINTER_UINT_UINT_STRING, + G_TYPE_NONE, + 4, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING); + + signals[LOCAL_PENDING] = + g_signal_new ("local-pending", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + empathy_marshal_VOID__POINTER_UINT_UINT_STRING, + G_TYPE_NONE, + 4, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING); + + signals[REMOTE_PENDING] = + g_signal_new ("remote-pending", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + empathy_marshal_VOID__POINTER_UINT_UINT_STRING, + G_TYPE_NONE, + 4, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING); + + g_type_class_add_private (object_class, sizeof (EmpathyTpGroupPriv)); +} + +static void +empathy_tp_group_init (EmpathyTpGroup *group) +{ +} + +static void +tp_group_finalize (GObject *object) +{ + EmpathyTpGroupPriv *priv; + + priv = GET_PRIV (object); + + if (priv->group_iface) { + g_signal_handlers_disconnect_by_func (priv->group_iface, + tp_group_destroy_cb, + object); + dbus_g_proxy_disconnect_signal (priv->group_iface, "MembersChanged", + G_CALLBACK (tp_group_members_changed_cb), + object); + g_object_unref (priv->group_iface); + } + + if (priv->tp_conn) { + g_object_unref (priv->tp_conn); + } + + if (priv->tp_chan) { + g_object_unref (priv->tp_chan); + } + + g_free (priv->group_name); + + G_OBJECT_CLASS (empathy_tp_group_parent_class)->finalize (object); +} + +EmpathyTpGroup * +empathy_tp_group_new (TpChan *tp_chan, + TpConn *tp_conn) +{ + EmpathyTpGroup *group; + EmpathyTpGroupPriv *priv; + DBusGProxy *group_iface; + + g_return_val_if_fail (TELEPATHY_IS_CHAN (tp_chan), NULL); + + group_iface = tp_chan_get_interface (tp_chan, + TELEPATHY_CHAN_IFACE_GROUP_QUARK); + g_return_val_if_fail (group_iface != NULL, NULL); + + group = g_object_new (EMPATHY_TYPE_TP_GROUP, NULL); + priv = GET_PRIV (group); + + priv->tp_conn = g_object_ref (tp_conn); + priv->tp_chan = g_object_ref (tp_chan); + priv->group_iface = g_object_ref (group_iface); + + dbus_g_proxy_connect_signal (priv->group_iface, "MembersChanged", + G_CALLBACK (tp_group_members_changed_cb), + group, NULL); + g_signal_connect (group_iface, "destroy", + G_CALLBACK (tp_group_destroy_cb), + group); + + return group; +} + +void +empathy_tp_group_add_members (EmpathyTpGroup *group, + GArray *handles, + const gchar *message) +{ + EmpathyTpGroupPriv *priv; + GError *error = NULL; + + g_return_if_fail (EMPATHY_IS_TP_GROUP (group)); + g_return_if_fail (handles != NULL); + + priv = GET_PRIV (group); + + if (!tp_chan_iface_group_add_members (priv->group_iface, + handles, + message, + &error)) { + empathy_debug (DEBUG_DOMAIN, + "Failed to add members: %s", + error ? error->message : "No error given"); + g_clear_error (&error); + } +} + +void +empathy_tp_group_add_member (EmpathyTpGroup *group, + guint handle, + const gchar *message) +{ + GArray *handles; + + handles = g_array_new (FALSE, FALSE, sizeof (guint)); + g_array_append_val (handles, handle); + + empathy_tp_group_add_members (group, handles, message); + + g_array_free (handles, TRUE); +} + +void +empathy_tp_group_remove_members (EmpathyTpGroup *group, + GArray *handles, + const gchar *message) +{ + EmpathyTpGroupPriv *priv; + GError *error = NULL; + + g_return_if_fail (EMPATHY_IS_TP_GROUP (group)); + + priv = GET_PRIV (group); + + if (!tp_chan_iface_group_remove_members (priv->group_iface, + handles, + message, + &error)) { + empathy_debug (DEBUG_DOMAIN, + "Failed to remove members: %s", + error ? error->message : "No error given"); + g_clear_error (&error); + } +} + +void +empathy_tp_group_remove_member (EmpathyTpGroup *group, + guint handle, + const gchar *message) +{ + GArray *handles; + + g_return_if_fail (EMPATHY_IS_TP_GROUP (group)); + + handles = g_array_new (FALSE, FALSE, sizeof (guint)); + g_array_append_val (handles, handle); + + empathy_tp_group_remove_members (group, handles, message); + + g_array_free (handles, TRUE); +} + +GArray * +empathy_tp_group_get_members (EmpathyTpGroup *group) +{ + EmpathyTpGroupPriv *priv; + GArray *members; + GError *error = NULL; + + g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); + + priv = GET_PRIV (group); + + if (!tp_chan_iface_group_get_members (priv->group_iface, + &members, + &error)) { + empathy_debug (DEBUG_DOMAIN, + "Couldn't get members: %s", + error ? error->message : "No error given"); + g_clear_error (&error); + return NULL; + } + + return members; +} + +void +empathy_tp_group_get_all_members (EmpathyTpGroup *group, + GArray **members, + GArray **local_pending, + GArray **remote_pending) +{ + EmpathyTpGroupPriv *priv; + GError *error = NULL; + + g_return_if_fail (EMPATHY_IS_TP_GROUP (group)); + + priv = GET_PRIV (group); + + if (!tp_chan_iface_group_get_all_members (priv->group_iface, + members, + local_pending, + remote_pending, + &error)) { + empathy_debug (DEBUG_DOMAIN, + "Couldn't get all members: %s", + error ? error->message : "No error given"); + g_clear_error (&error); + } +} + +GList * +empathy_tp_group_get_local_pending_members_with_info (EmpathyTpGroup *group) +{ + EmpathyTpGroupPriv *priv; + GPtrArray *array; + guint i; + GList *infos = NULL; + GError *error = NULL; + + g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); + + priv = GET_PRIV (group); + + if (!tp_chan_iface_group_get_local_pending_members_with_info (priv->group_iface, + &array, + &error)) { + empathy_debug (DEBUG_DOMAIN, + "GetLocalPendingMembersWithInfo failed: %s", + error ? error->message : "No error given"); + g_clear_error (&error); + + return NULL; + } + + if (!array) { + /* This happens with butterfly because + * GetLocalPendingMembersWithInfo is not + * implemented */ + return NULL; + } + + for (i = 0; array->len > i; i++) { + GValueArray *pending_struct; + EmpathyTpGroupInfo *info; + const gchar *message; + + info = g_slice_new (EmpathyTpGroupInfo); + + pending_struct = g_ptr_array_index (array, i); + info->member = g_value_get_uint (g_value_array_get_nth (pending_struct, 0)); + info->actor = g_value_get_uint (g_value_array_get_nth (pending_struct, 1)); + info->reason = g_value_get_uint (g_value_array_get_nth (pending_struct, 2)); + message = g_value_get_string (g_value_array_get_nth (pending_struct, 3)); + info->message = g_strdup (message); + g_value_array_free (pending_struct); + + infos = g_list_prepend (infos, info); + } + g_ptr_array_free (array, TRUE); + + return infos; +} + +void +empathy_tp_group_info_list_free (GList *infos) +{ + GList *l; + + for (l = infos; l; l = l->next) { + EmpathyTpGroupInfo *info; + + info = l->data; + + g_free (info->message); + g_slice_free (EmpathyTpGroupInfo, info); + } + g_list_free (infos); +} + + +static void +tp_group_destroy_cb (DBusGProxy *proxy, + EmpathyTpGroup *group) +{ + EmpathyTpGroupPriv *priv; + + priv = GET_PRIV (group); + + g_object_unref (priv->group_iface); + g_object_unref (priv->tp_conn); + g_object_unref (priv->tp_chan); + priv->group_iface = NULL; + priv->tp_chan = NULL; + priv->tp_conn = NULL; +} + +static void +tp_group_members_changed_cb (DBusGProxy *group_iface, + gchar *message, + GArray *added, + GArray *removed, + GArray *local_pending, + GArray *remote_pending, + guint actor, + guint reason, + EmpathyTpGroup *group) +{ + EmpathyTpGroupPriv *priv; + + priv = GET_PRIV (group); + + /* emit signals */ + if (added->len > 0) { + g_signal_emit (group, signals[MEMBERS_ADDED], 0, + added, actor, reason, message); + } + if (removed->len > 0) { + g_signal_emit (group, signals[MEMBERS_REMOVED], 0, + removed, actor, reason, message); + } + if (local_pending->len > 0) { + g_signal_emit (group, signals[LOCAL_PENDING], 0, + local_pending, actor, reason, message); + } + if (remote_pending->len > 0) { + g_signal_emit (group, signals[REMOTE_PENDING], 0, + remote_pending, actor, reason, message); + } +} + +const gchar * +empathy_tp_group_get_name (EmpathyTpGroup *group) +{ + TelepathyHandleType handle_type; + guint channel_handle; + GArray *group_handles; + gchar **group_names; + GError *error = NULL; + + EmpathyTpGroupPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); + + priv = GET_PRIV (group); + + /* Lazy initialisation */ + if (priv->group_name) { + return priv->group_name; + } + + if (!tp_chan_get_handle (DBUS_G_PROXY (priv->tp_chan), + &handle_type, + &channel_handle, + &error)) { + empathy_debug (DEBUG_DOMAIN, + "Couldn't retreive channel handle for group: %s", + error ? error->message : "No error given"); + g_clear_error (&error); + return NULL; + } + + group_handles = g_array_new (FALSE, FALSE, sizeof (guint)); + g_array_append_val (group_handles, channel_handle); + if (!tp_conn_inspect_handles (DBUS_G_PROXY (priv->tp_conn), + handle_type, + group_handles, + &group_names, + &error)) { + empathy_debug (DEBUG_DOMAIN, + "Couldn't get group name: %s", + error ? error->message : "No error given"); + g_clear_error (&error); + g_array_free (group_handles, TRUE); + return NULL; + } + + priv->group_name = *group_names; + g_array_free (group_handles, TRUE); + g_free (group_names); + + return priv->group_name; +} + +guint +empathy_tp_group_get_self_handle (EmpathyTpGroup *group) +{ + EmpathyTpGroupPriv *priv; + guint handle; + GError *error = NULL; + + g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), 0 ); + + priv = GET_PRIV (group); + + if (!tp_chan_iface_group_get_self_handle (priv->group_iface, &handle, &error)) { + empathy_debug (DEBUG_DOMAIN, + "Failed to get self handle: %s", + error ? error->message : "No error given"); + g_clear_error (&error); + return 0; + } + + return handle; +} + +const gchar * +empathy_tp_group_get_object_path (EmpathyTpGroup *group) +{ + EmpathyTpGroupPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); + + priv = GET_PRIV (group); + + return dbus_g_proxy_get_path (DBUS_G_PROXY (priv->tp_chan)); +} + +gboolean +empathy_tp_group_is_member (EmpathyTpGroup *group, + guint handle) +{ + GArray *members; + guint i; + gboolean found = FALSE; + + members = empathy_tp_group_get_members (group); + for (i = 0; i < members->len; i++) { + if (g_array_index (members, guint, i) == handle) { + found = TRUE; + break; + } + } + g_array_free (members, TRUE); + + return found; +} + diff --git a/libempathy/empathy-tp-group.h b/libempathy/empathy-tp-group.h new file mode 100644 index 00000000..2381ea10 --- /dev/null +++ b/libempathy/empathy-tp-group.h @@ -0,0 +1,86 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006 Xavier Claessens + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EMPATHY_TP_GROUP_H__ +#define __EMPATHY_TP_GROUP_H__ + +#include + +#include + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_TP_GROUP (empathy_tp_group_get_type ()) +#define EMPATHY_TP_GROUP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_TP_GROUP, EmpathyTpGroup)) +#define EMPATHY_TP_GROUP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_TP_GROUP, EmpathyTpGroupClass)) +#define EMPATHY_IS_TP_GROUP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_TP_GROUP)) +#define EMPATHY_IS_TP_GROUP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_TP_GROUP)) +#define EMPATHY_TP_GROUP_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_TP_GROUP, EmpathyTpGroupClass)) + +typedef struct _EmpathyTpGroup EmpathyTpGroup; +typedef struct _EmpathyTpGroupClass EmpathyTpGroupClass; +typedef struct _EmpathyTpGroupPriv EmpathyTpGroupPriv; + +struct _EmpathyTpGroup { + GObject parent; +}; + +struct _EmpathyTpGroupClass { + GObjectClass parent_class; +}; + +typedef struct { + guint member; + guint actor; + guint reason; + gchar *message; +} EmpathyTpGroupInfo; + +GType empathy_tp_group_get_type (void) G_GNUC_CONST; +EmpathyTpGroup * empathy_tp_group_new (TpChan *tp_chan, + TpConn *tp_conn); +void empathy_tp_group_add_members (EmpathyTpGroup *group, + GArray *handles, + const gchar *message); +void empathy_tp_group_add_member (EmpathyTpGroup *group, + guint handle, + const gchar *message); +void empathy_tp_group_remove_members (EmpathyTpGroup *group, + GArray *handle, + const gchar *message); +void empathy_tp_group_remove_member (EmpathyTpGroup *group, + guint handle, + const gchar *message); +GArray * empathy_tp_group_get_members (EmpathyTpGroup *group); +void empathy_tp_group_get_all_members (EmpathyTpGroup *group, + GArray **members, + GArray **local_pending, + GArray **remote_pending); +GList * empathy_tp_group_get_local_pending_members_with_info (EmpathyTpGroup *group); +void empathy_tp_group_info_list_free (GList *infos); +const gchar * empathy_tp_group_get_name (EmpathyTpGroup *group); +guint empathy_tp_group_get_self_handle (EmpathyTpGroup *group); +const gchar * empathy_tp_group_get_object_path (EmpathyTpGroup *group); +gboolean empathy_tp_group_is_member (EmpathyTpGroup *group, + guint handle); + +G_END_DECLS + +#endif /* __EMPATHY_TP_GROUP_H__ */ diff --git a/libempathy/empathy-utils.c b/libempathy/empathy-utils.c new file mode 100644 index 00000000..74a6bc07 --- /dev/null +++ b/libempathy/empathy-utils.c @@ -0,0 +1,495 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2003-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Richard Hult + * Martyn Russell + * Xavier Claessens + */ + +#include "config.h" + +#include +#include +#include +#include + +#include + +#include +#include + +#include "empathy-debug.h" +#include "empathy-utils.h" +#include "empathy-contact-manager.h" + +#define DEBUG_DOMAIN "Utils" + +static void regex_init (void); + +gchar * +empathy_substring (const gchar *str, + gint start, + gint end) +{ + return g_strndup (str + start, end - start); +} + +/* + * Regular Expression code to match urls. + */ +#define USERCHARS "-A-Za-z0-9" +#define PASSCHARS "-A-Za-z0-9,?;.:/!%$^*&~\"#'" +#define HOSTCHARS "-A-Za-z0-9" +#define PATHCHARS "-A-Za-z0-9_$.+!*(),;:@&=?/~#%" +#define SCHEME "(news:|telnet:|nntp:|file:/|https?:|ftps?:|webcal:)" +#define USER "[" USERCHARS "]+(:["PASSCHARS "]+)?" +#define URLPATH "/[" PATHCHARS "]*[^]'.}>) \t\r\n,\\\"]" + +static regex_t dingus[EMPATHY_REGEX_ALL]; + +static void +regex_init (void) +{ + static gboolean inited = FALSE; + const gchar *expression; + gint i; + + if (inited) { + return; + } + + for (i = 0; i < EMPATHY_REGEX_ALL; i++) { + switch (i) { + case EMPATHY_REGEX_AS_IS: + expression = + SCHEME "//(" USER "@)?[" HOSTCHARS ".]+" + "(:[0-9]+)?(" URLPATH ")?"; + break; + case EMPATHY_REGEX_BROWSER: + expression = + "(www|ftp)[" HOSTCHARS "]*\\.[" HOSTCHARS ".]+" + "(:[0-9]+)?(" URLPATH ")?"; + break; + case EMPATHY_REGEX_EMAIL: + expression = + "(mailto:)?[a-z0-9][a-z0-9.-]*@[a-z0-9]" + "[a-z0-9-]*(\\.[a-z0-9][a-z0-9-]*)+"; + break; + case EMPATHY_REGEX_OTHER: + expression = + "news:[-A-Z\\^_a-z{|}~!\"#$%&'()*+,./0-9;:=?`]+" + "@[" HOSTCHARS ".]+(:[0-9]+)?"; + break; + default: + /* Silence the compiler. */ + expression = NULL; + continue; + } + + memset (&dingus[i], 0, sizeof (regex_t)); + regcomp (&dingus[i], expression, REG_EXTENDED | REG_ICASE); + } + + inited = TRUE; +} + +gint +empathy_regex_match (EmpathyRegExType type, + const gchar *msg, + GArray *start, + GArray *end) +{ + regmatch_t matches[1]; + gint ret = 0; + gint num_matches = 0; + gint offset = 0; + gint i; + + g_return_val_if_fail (type >= 0 || type <= EMPATHY_REGEX_ALL, 0); + + regex_init (); + + while (!ret && type != EMPATHY_REGEX_ALL) { + ret = regexec (&dingus[type], msg + offset, 1, matches, 0); + if (ret == 0) { + gint s; + + num_matches++; + + s = matches[0].rm_so + offset; + offset = matches[0].rm_eo + offset; + + g_array_append_val (start, s); + g_array_append_val (end, offset); + } + } + + if (type != EMPATHY_REGEX_ALL) { + empathy_debug (DEBUG_DOMAIN, + "Found %d matches for regex type:%d", + num_matches, type); + return num_matches; + } + + /* If EMPATHY_REGEX_ALL then we run ALL regex's on the string. */ + for (i = 0; i < EMPATHY_REGEX_ALL; i++, ret = 0) { + while (!ret) { + ret = regexec (&dingus[i], msg + offset, 1, matches, 0); + if (ret == 0) { + gint s; + + num_matches++; + + s = matches[0].rm_so + offset; + offset = matches[0].rm_eo + offset; + + g_array_append_val (start, s); + g_array_append_val (end, offset); + } + } + } + + empathy_debug (DEBUG_DOMAIN, + "Found %d matches for ALL regex types", + num_matches); + + return num_matches; +} + +gint +empathy_strcasecmp (const gchar *s1, + const gchar *s2) +{ + return empathy_strncasecmp (s1, s2, -1); +} + +gint +empathy_strncasecmp (const gchar *s1, + const gchar *s2, + gsize n) +{ + gchar *u1, *u2; + gint ret_val; + + u1 = g_utf8_casefold (s1, n); + u2 = g_utf8_casefold (s2, n); + + ret_val = g_utf8_collate (u1, u2); + g_free (u1); + g_free (u2); + + return ret_val; +} + +gboolean +empathy_xml_validate (xmlDoc *doc, + const gchar *dtd_filename) +{ + gchar *path, *escaped; + xmlValidCtxt cvp; + xmlDtd *dtd; + gboolean ret; + + path = g_build_filename (DATADIR, "empathy", dtd_filename, NULL); + + /* The list of valid chars is taken from libxml. */ + escaped = xmlURIEscapeStr (path, ":@&=+$,/?;"); + + g_free (path); + + memset (&cvp, 0, sizeof (cvp)); + dtd = xmlParseDTD (NULL, escaped); + ret = xmlValidateDtd (&cvp, doc, dtd); + + xmlFree (escaped); + xmlFreeDtd (dtd); + + return ret; +} + +xmlNodePtr +empathy_xml_node_get_child (xmlNodePtr node, + const gchar *child_name) +{ + xmlNodePtr l; + + g_return_val_if_fail (node != NULL, NULL); + g_return_val_if_fail (child_name != NULL, NULL); + + for (l = node->children; l; l = l->next) { + if (l->name && strcmp (l->name, child_name) == 0) { + return l; + } + } + + return NULL; +} + +xmlChar * +empathy_xml_node_get_child_content (xmlNodePtr node, + const gchar *child_name) +{ + xmlNodePtr l; + + g_return_val_if_fail (node != NULL, NULL); + g_return_val_if_fail (child_name != NULL, NULL); + + l = empathy_xml_node_get_child (node, child_name); + if (l) { + return xmlNodeGetContent (l); + } + + return NULL; +} + +xmlNodePtr +empathy_xml_node_find_child_prop_value (xmlNodePtr node, + const gchar *prop_name, + const gchar *prop_value) +{ + xmlNodePtr l; + xmlNodePtr found = NULL; + + g_return_val_if_fail (node != NULL, NULL); + g_return_val_if_fail (prop_name != NULL, NULL); + g_return_val_if_fail (prop_value != NULL, NULL); + + for (l = node->children; l && !found; l = l->next) { + xmlChar *prop; + + if (!xmlHasProp (l, prop_name)) { + continue; + } + + prop = xmlGetProp (l, prop_name); + if (prop && strcmp (prop, prop_value) == 0) { + found = l; + } + + xmlFree (prop); + } + + return found; +} + +GType +empathy_dbus_type_to_g_type (const gchar *dbus_type_string) +{ + if (dbus_type_string == NULL) + return G_TYPE_NONE; + + if (dbus_type_string[0] == 's') { + return G_TYPE_STRING; + } + else if (dbus_type_string[0] == 'b') { + return G_TYPE_BOOLEAN; + } + else if (dbus_type_string[0] == 'q') { + return G_TYPE_UINT; + } + else if (dbus_type_string[0] == 'n') { + return G_TYPE_INT; + } + + g_assert_not_reached (); + return G_TYPE_NONE; +} + +const gchar * +empathy_g_type_to_dbus_type (GType g_type) +{ + switch (g_type) { + case G_TYPE_STRING: + return "s"; + case G_TYPE_BOOLEAN: + return "b"; + case G_TYPE_UINT: + return "q"; + case G_TYPE_INT: + return "n"; + default: + g_assert_not_reached (); + } + + return NULL; +} + +gchar * +empathy_g_value_to_string (const GValue *value) +{ + gchar *return_string = NULL; + GValue string_g_value = {0, }; + + g_value_init (&string_g_value, G_TYPE_STRING); + g_value_transform (value, &string_g_value); + return_string = g_value_dup_string (&string_g_value); + g_value_unset (&string_g_value); + + return return_string; +} + +GValue * +empathy_string_to_g_value (const gchar *str, GType type) +{ + GValue *g_value; + + g_value = g_new0 (GValue, 1); + g_value_init (g_value, type); + + switch (type) { + case G_TYPE_STRING: + g_value_set_string (g_value, str); + break; + case G_TYPE_BOOLEAN: + g_value_set_boolean (g_value, (str[0] == 'y' || str[0] == 'T')); + break; + case G_TYPE_UINT: + g_value_set_uint (g_value, atoi (str)); + break; + case G_TYPE_INT: + g_value_set_int (g_value, atoi (str)); + break; + default: + g_assert_not_reached (); + } + + return g_value; +} + +gboolean +empathy_g_value_equal (const GValue *value1, + const GValue *value2) +{ + GType type; + + g_return_val_if_fail (value1 != NULL, FALSE); + g_return_val_if_fail (value2 != NULL, FALSE); + + type = G_VALUE_TYPE (value1); + if (type != G_VALUE_TYPE (value2)) { + return FALSE; + } + + switch (type) + { + case G_TYPE_STRING: { + const gchar *str1; + const gchar *str2; + + str1 = g_value_get_string (value1); + str2 = g_value_get_string (value2); + return (str1 && str2 && strcmp (str1, str2) == 0) || + (G_STR_EMPTY (str1) && G_STR_EMPTY (str2)); + } + case G_TYPE_BOOLEAN: + return g_value_get_boolean (value1) == g_value_get_boolean (value2); + case G_TYPE_UINT: + return g_value_get_uint (value1) == g_value_get_uint (value2); + case G_TYPE_INT: + return g_value_get_int (value1) == g_value_get_int (value2); + default: + g_warning ("Unsupported GType in value comparaison"); + } + + return FALSE; +} + +guint +empathy_account_hash (gconstpointer key) +{ + return g_str_hash (mc_account_get_unique_name (MC_ACCOUNT (key))); +} + +gboolean +empathy_account_equal (gconstpointer a, + gconstpointer b) +{ + const gchar *name_a; + const gchar *name_b; + + name_a = mc_account_get_unique_name (MC_ACCOUNT (a)); + name_b = mc_account_get_unique_name (MC_ACCOUNT (b)); + + return g_str_equal (name_a, name_b); +} + +MissionControl * +empathy_mission_control_new (void) +{ + static MissionControl *mc = NULL; + + if (!mc) { + mc = mission_control_new (tp_get_bus ()); + g_object_add_weak_pointer (G_OBJECT (mc), (gpointer) &mc); + } else { + g_object_ref (mc); + } + + return mc; +} + +gchar * +empathy_get_channel_id (McAccount *account, + TpChan *tp_chan) +{ + MissionControl *mc; + TpConn *tp_conn; + GArray *handles; + gchar **names; + gchar *name; + GError *error; + + g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + g_return_val_if_fail (TELEPATHY_IS_CHAN (tp_chan), NULL); + + mc = empathy_mission_control_new (); + tp_conn = mission_control_get_connection (mc, account, NULL); + g_object_unref (mc); + + if (!tp_conn) { + return NULL; + } + + /* Get the handle's name */ + handles = g_array_new (FALSE, FALSE, sizeof (guint)); + g_array_append_val (handles, tp_chan->handle); + if (!tp_conn_inspect_handles (DBUS_G_PROXY (tp_conn), + tp_chan->handle_type, + handles, + &names, + &error)) { + empathy_debug (DEBUG_DOMAIN, + "Couldn't get id: %s", + error ? error->message : "No error given"); + + g_clear_error (&error); + g_array_free (handles, TRUE); + g_object_unref (tp_conn); + + return NULL; + } + + name = *names; + g_free (names); + g_object_unref (tp_conn); + + return name; +} + diff --git a/libempathy/empathy-utils.h b/libempathy/empathy-utils.h new file mode 100644 index 00000000..17be9ed3 --- /dev/null +++ b/libempathy/empathy-utils.h @@ -0,0 +1,100 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2003-2007 Imendio AB + * Copyright (C) 2007 Collabora Ltd. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Richard Hult + * Martyn Russell + * Xavier Claessens + */ + +#ifndef __EMPATHY_UTILS_H__ +#define __EMPATHY_UTILS_H__ + +#include +#include + +#include +#include + +#include + +#include +#include + +#include "empathy-contact.h" + +G_BEGIN_DECLS + +#define G_STR_EMPTY(x) ((x) == NULL || (x)[0] == '\0') + +typedef enum { + EMPATHY_REGEX_AS_IS, + EMPATHY_REGEX_BROWSER, + EMPATHY_REGEX_EMAIL, + EMPATHY_REGEX_OTHER, + EMPATHY_REGEX_ALL, +} EmpathyRegExType; + +/* Regular expressions */ +gchar * empathy_substring (const gchar *str, + gint start, + gint end); +gint empathy_regex_match (EmpathyRegExType type, + const gchar *msg, + GArray *start, + GArray *end); + +/* Strings */ +gint empathy_strcasecmp (const gchar *s1, + const gchar *s2); +gint empathy_strncasecmp (const gchar *s1, + const gchar *s2, + gsize n); + +/* XML */ +gboolean empathy_xml_validate (xmlDoc *doc, + const gchar *dtd_filename); +xmlNodePtr empathy_xml_node_get_child (xmlNodePtr node, + const gchar *child_name); +xmlChar * empathy_xml_node_get_child_content (xmlNodePtr node, + const gchar *child_name); +xmlNodePtr empathy_xml_node_find_child_prop_value (xmlNodePtr node, + const gchar *prop_name, + const gchar *prop_value); + + +/* GValue/GType */ +GType empathy_dbus_type_to_g_type (const gchar *dbus_type_string); +const gchar *empathy_g_type_to_dbus_type (GType g_type); +gchar * empathy_g_value_to_string (const GValue *value); +GValue * empathy_string_to_g_value (const gchar *str, + GType type); +gboolean empathy_g_value_equal (const GValue *value1, + const GValue *value2); + +guint empathy_account_hash (gconstpointer key); +gboolean empathy_account_equal (gconstpointer a, + gconstpointer b); +MissionControl *empathy_mission_control_new (void); +gchar * empathy_get_channel_id (McAccount *account, + TpChan *tp_chan); + +G_END_DECLS + +#endif /* __EMPATHY_UTILS_H__ */ diff --git a/libempathy/gossip-avatar.c b/libempathy/gossip-avatar.c deleted file mode 100644 index 5c17a517..00000000 --- a/libempathy/gossip-avatar.c +++ /dev/null @@ -1,86 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2002-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Martyn Russell - * Xavier Claessens - */ - -#include "config.h" - -#include "gossip-avatar.h" - -#define DEBUG_DOMAIN "Avatar" - -GType -gossip_avatar_get_gtype (void) -{ - static GType type_id = 0; - - if (!type_id) { - type_id = g_boxed_type_register_static ("GossipAvatar", - (GBoxedCopyFunc) gossip_avatar_ref, - (GBoxedFreeFunc) gossip_avatar_unref); - } - - return type_id; -} - -GossipAvatar * -gossip_avatar_new (guchar *data, - gsize len, - gchar *format) -{ - GossipAvatar *avatar; - - g_return_val_if_fail (data != NULL, NULL); - g_return_val_if_fail (len > 0, NULL); - g_return_val_if_fail (format != NULL, NULL); - - avatar = g_slice_new0 (GossipAvatar); - avatar->data = g_memdup (data, len); - avatar->len = len; - avatar->format = g_strdup (format); - avatar->refcount = 1; - - return avatar; -} - -void -gossip_avatar_unref (GossipAvatar *avatar) -{ - g_return_if_fail (avatar != NULL); - - avatar->refcount--; - if (avatar->refcount == 0) { - g_free (avatar->data); - g_free (avatar->format); - g_slice_free (GossipAvatar, avatar); - } -} - -GossipAvatar * -gossip_avatar_ref (GossipAvatar *avatar) -{ - g_return_val_if_fail (avatar != NULL, NULL); - - avatar->refcount++; - - return avatar; -} - diff --git a/libempathy/gossip-avatar.h b/libempathy/gossip-avatar.h deleted file mode 100644 index 44fa9aba..00000000 --- a/libempathy/gossip-avatar.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006 Xavier Claessens - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GOSSIP_AVATAR_H__ -#define __GOSSIP_AVATAR_H__ - -#include - -G_BEGIN_DECLS - -#define GOSSIP_TYPE_AVATAR (gossip_avatar_get_gtype ()) - -typedef struct _GossipAvatar GossipAvatar; - -struct _GossipAvatar { - guchar *data; - gsize len; - gchar *format; - guint refcount; -}; - -GType gossip_avatar_get_gtype (void) G_GNUC_CONST; -GossipAvatar * gossip_avatar_new (guchar *avatar, - gsize len, - gchar *format); -GossipAvatar * gossip_avatar_ref (GossipAvatar *avatar); -void gossip_avatar_unref (GossipAvatar *avatar); - -G_END_DECLS - -#endif /* __GOSSIP_AVATAR_H__ */ diff --git a/libempathy/gossip-chatroom-manager.c b/libempathy/gossip-chatroom-manager.c deleted file mode 100644 index cc6aa81a..00000000 --- a/libempathy/gossip-chatroom-manager.c +++ /dev/null @@ -1,501 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2004-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Xavier Claessens - * Martyn Russell - */ - -#include "config.h" - -#include -#include -#include - -#include -#include - -#include "gossip-debug.h" -#include "gossip-chatroom-manager.h" -#include "gossip-utils.h" - -#define DEBUG_DOMAIN "ChatroomManager" - -#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CHATROOM_MANAGER, GossipChatroomManagerPriv)) - -#define CHATROOMS_XML_FILENAME "chatrooms.xml" -#define CHATROOMS_DTD_FILENAME "gossip-chatroom-manager.dtd" - -struct _GossipChatroomManagerPriv { - GList *chatrooms; -}; - -static void gossip_chatroom_manager_class_init (GossipChatroomManagerClass *klass); -static void gossip_chatroom_manager_init (GossipChatroomManager *manager); -static void chatroom_manager_finalize (GObject *object); -static gboolean chatroom_manager_get_all (GossipChatroomManager *manager); -static gboolean chatroom_manager_file_parse (GossipChatroomManager *manager, - const gchar *filename); -static void chatroom_manager_parse_chatroom (GossipChatroomManager *manager, - xmlNodePtr node); -static gboolean chatroom_manager_file_save (GossipChatroomManager *manager); - -enum { - CHATROOM_ADDED, - CHATROOM_REMOVED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL]; - -G_DEFINE_TYPE (GossipChatroomManager, gossip_chatroom_manager, G_TYPE_OBJECT); - -static void -gossip_chatroom_manager_class_init (GossipChatroomManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = chatroom_manager_finalize; - - signals[CHATROOM_ADDED] = - g_signal_new ("chatroom-added", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, - 1, GOSSIP_TYPE_CHATROOM); - signals[CHATROOM_REMOVED] = - g_signal_new ("chatroom-removed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, - 1, GOSSIP_TYPE_CHATROOM); - - g_type_class_add_private (object_class, - sizeof (GossipChatroomManagerPriv)); -} - -static void -gossip_chatroom_manager_init (GossipChatroomManager *manager) -{ - GossipChatroomManagerPriv *priv; - - priv = GET_PRIV (manager); -} - -static void -chatroom_manager_finalize (GObject *object) -{ - GossipChatroomManagerPriv *priv; - - priv = GET_PRIV (object); - - g_list_foreach (priv->chatrooms, (GFunc) g_object_unref, NULL); - g_list_free (priv->chatrooms); - - (G_OBJECT_CLASS (gossip_chatroom_manager_parent_class)->finalize) (object); -} - -GossipChatroomManager * -gossip_chatroom_manager_new (void) -{ - static GossipChatroomManager *manager = NULL; - - if (!manager) { - GossipChatroomManagerPriv *priv; - - manager = g_object_new (GOSSIP_TYPE_CHATROOM_MANAGER, NULL); - priv = GET_PRIV (manager); - chatroom_manager_get_all (manager); - - g_object_add_weak_pointer (G_OBJECT (manager), (gpointer) &manager); - } else { - g_object_ref (manager); - } - - return manager; -} - -gboolean -gossip_chatroom_manager_add (GossipChatroomManager *manager, - GossipChatroom *chatroom) -{ - GossipChatroomManagerPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CHATROOM_MANAGER (manager), FALSE); - g_return_val_if_fail (GOSSIP_IS_CHATROOM (chatroom), FALSE); - - priv = GET_PRIV (manager); - - /* don't add more than once */ - if (!gossip_chatroom_manager_find (manager, - gossip_chatroom_get_account (chatroom), - gossip_chatroom_get_room (chatroom))) { - priv->chatrooms = g_list_prepend (priv->chatrooms, g_object_ref (chatroom)); - chatroom_manager_file_save (manager); - - g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom); - - return TRUE; - } - - return FALSE; -} - -void -gossip_chatroom_manager_remove (GossipChatroomManager *manager, - GossipChatroom *chatroom) -{ - GossipChatroomManagerPriv *priv; - GList *l; - - g_return_if_fail (GOSSIP_IS_CHATROOM_MANAGER (manager)); - g_return_if_fail (GOSSIP_IS_CHATROOM (chatroom)); - - priv = GET_PRIV (manager); - - for (l = priv->chatrooms; l; l = l->next) { - GossipChatroom *this_chatroom; - - this_chatroom = l->data; - - if (gossip_chatroom_equal (chatroom, this_chatroom)) { - priv->chatrooms = g_list_delete_link (priv->chatrooms, l); - - chatroom_manager_file_save (manager); - - g_signal_emit (manager, signals[CHATROOM_REMOVED], 0, this_chatroom); - g_object_unref (this_chatroom); - break; - } - } -} - -GossipChatroom * -gossip_chatroom_manager_find (GossipChatroomManager *manager, - McAccount *account, - const gchar *room) -{ - GossipChatroomManagerPriv *priv; - GList *l; - - g_return_val_if_fail (GOSSIP_IS_CHATROOM_MANAGER (manager), NULL); - g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); - g_return_val_if_fail (room != NULL, NULL); - - priv = GET_PRIV (manager); - - for (l = priv->chatrooms; l; l = l->next) { - GossipChatroom *chatroom; - McAccount *this_account; - const gchar *this_room; - - chatroom = l->data; - this_account = gossip_chatroom_get_account (chatroom); - this_room = gossip_chatroom_get_room (chatroom); - - if (this_account && this_room && - gossip_account_equal (account, this_account) && - strcmp (this_room, room) == 0) { - return chatroom; - } - } - - return NULL; -} - -GList * -gossip_chatroom_manager_get_chatrooms (GossipChatroomManager *manager, - McAccount *account) -{ - GossipChatroomManagerPriv *priv; - GList *chatrooms, *l; - - g_return_val_if_fail (GOSSIP_IS_CHATROOM_MANAGER (manager), NULL); - - priv = GET_PRIV (manager); - - if (!account) { - return g_list_copy (priv->chatrooms); - } - - chatrooms = NULL; - for (l = priv->chatrooms; l; l = l->next) { - GossipChatroom *chatroom; - - chatroom = l->data; - - if (gossip_account_equal (account, - gossip_chatroom_get_account (chatroom))) { - chatrooms = g_list_append (chatrooms, chatroom); - } - } - - return chatrooms; -} - -guint -gossip_chatroom_manager_get_count (GossipChatroomManager *manager, - McAccount *account) -{ - GossipChatroomManagerPriv *priv; - GList *l; - guint count = 0; - - g_return_val_if_fail (GOSSIP_IS_CHATROOM_MANAGER (manager), 0); - - priv = GET_PRIV (manager); - - if (!account) { - return g_list_length (priv->chatrooms); - } - - for (l = priv->chatrooms; l; l = l->next) { - GossipChatroom *chatroom; - - chatroom = l->data; - - if (gossip_account_equal (account, - gossip_chatroom_get_account (chatroom))) { - count++; - } - } - - return count; -} - -void -gossip_chatroom_manager_store (GossipChatroomManager *manager) -{ - g_return_if_fail (GOSSIP_IS_CHATROOM_MANAGER (manager)); - - chatroom_manager_file_save (manager); -} - -/* - * API to save/load and parse the chatrooms file. - */ - -static gboolean -chatroom_manager_get_all (GossipChatroomManager *manager) -{ - GossipChatroomManagerPriv *priv; - gchar *dir; - gchar *file_with_path = NULL; - - priv = GET_PRIV (manager); - - dir = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, NULL); - if (!g_file_test (dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { - g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR); - } - - file_with_path = g_build_filename (dir, CHATROOMS_XML_FILENAME, NULL); - g_free (dir); - - /* read file in */ - if (g_file_test (file_with_path, G_FILE_TEST_EXISTS) && - !chatroom_manager_file_parse (manager, file_with_path)) { - g_free (file_with_path); - return FALSE; - } - - g_free (file_with_path); - - return TRUE; -} - -static gboolean -chatroom_manager_file_parse (GossipChatroomManager *manager, - const gchar *filename) -{ - GossipChatroomManagerPriv *priv; - xmlParserCtxtPtr ctxt; - xmlDocPtr doc; - xmlNodePtr chatrooms; - xmlNodePtr node; - - priv = GET_PRIV (manager); - - gossip_debug (DEBUG_DOMAIN, "Attempting to parse file:'%s'...", filename); - - ctxt = xmlNewParserCtxt (); - - /* Parse and validate the file. */ - doc = xmlCtxtReadFile (ctxt, filename, NULL, 0); - if (!doc) { - g_warning ("Failed to parse file:'%s'", filename); - xmlFreeParserCtxt (ctxt); - return FALSE; - } - - if (!gossip_xml_validate (doc, CHATROOMS_DTD_FILENAME)) { - g_warning ("Failed to validate file:'%s'", filename); - xmlFreeDoc(doc); - xmlFreeParserCtxt (ctxt); - return FALSE; - } - - /* The root node, chatrooms. */ - chatrooms = xmlDocGetRootElement (doc); - - for (node = chatrooms->children; node; node = node->next) { - if (strcmp ((gchar *) node->name, "chatroom") == 0) { - chatroom_manager_parse_chatroom (manager, node); - } - } - - gossip_debug (DEBUG_DOMAIN, - "Parsed %d chatrooms", - g_list_length (priv->chatrooms)); - - xmlFreeDoc(doc); - xmlFreeParserCtxt (ctxt); - - return TRUE; -} - -static void -chatroom_manager_parse_chatroom (GossipChatroomManager *manager, - xmlNodePtr node) -{ - GossipChatroomManagerPriv *priv; - GossipChatroom *chatroom; - McAccount *account; - xmlNodePtr child; - gchar *str; - gchar *name; - gchar *room; - gchar *account_id; - gboolean auto_connect; - - priv = GET_PRIV (manager); - - /* default values. */ - name = NULL; - room = NULL; - auto_connect = TRUE; - account_id = NULL; - - for (child = node->children; child; child = child->next) { - gchar *tag; - - if (xmlNodeIsText (child)) { - continue; - } - - tag = (gchar *) child->name; - str = (gchar *) xmlNodeGetContent (child); - - if (strcmp (tag, "name") == 0) { - name = g_strdup (str); - } - else if (strcmp (tag, "room") == 0) { - room = g_strdup (str); - } - else if (strcmp (tag, "auto_connect") == 0) { - if (strcmp (str, "yes") == 0) { - auto_connect = TRUE; - } else { - auto_connect = FALSE; - } - } - else if (strcmp (tag, "account") == 0) { - account_id = g_strdup (str); - } - - xmlFree (str); - } - - account = mc_account_lookup (account_id); - if (!account) { - g_free (name); - g_free (room); - g_free (account_id); - return; - } - - chatroom = gossip_chatroom_new_full (account, room, name, auto_connect); - priv->chatrooms = g_list_prepend (priv->chatrooms, chatroom); - g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom); - - g_object_unref (account); - g_free (name); - g_free (room); - g_free (account_id); -} - -static gboolean -chatroom_manager_file_save (GossipChatroomManager *manager) -{ - GossipChatroomManagerPriv *priv; - xmlDocPtr doc; - xmlNodePtr root; - GList *l; - gchar *dir; - gchar *file; - - priv = GET_PRIV (manager); - - dir = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, NULL); - if (!g_file_test (dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { - g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR); - } - - file = g_build_filename (dir, CHATROOMS_XML_FILENAME, NULL); - g_free (dir); - - doc = xmlNewDoc ("1.0"); - root = xmlNewNode (NULL, "chatrooms"); - xmlDocSetRootElement (doc, root); - - for (l = priv->chatrooms; l; l = l->next) { - GossipChatroom *chatroom; - xmlNodePtr node; - const gchar *account_id; - - chatroom = l->data; - account_id = mc_account_get_unique_name (gossip_chatroom_get_account (chatroom)); - - node = xmlNewChild (root, NULL, "chatroom", NULL); - xmlNewTextChild (node, NULL, "name", gossip_chatroom_get_name (chatroom)); - xmlNewTextChild (node, NULL, "room", gossip_chatroom_get_room (chatroom)); - xmlNewTextChild (node, NULL, "account", account_id); - xmlNewTextChild (node, NULL, "auto_connect", gossip_chatroom_get_auto_connect (chatroom) ? "yes" : "no"); - } - - /* Make sure the XML is indented properly */ - xmlIndentTreeOutput = 1; - - gossip_debug (DEBUG_DOMAIN, "Saving file:'%s'", file); - xmlSaveFormatFileEnc (file, doc, "utf-8", 1); - xmlFreeDoc (doc); - - xmlCleanupParser (); - xmlMemoryDump (); - - g_free (file); - - return TRUE; -} diff --git a/libempathy/gossip-chatroom-manager.dtd b/libempathy/gossip-chatroom-manager.dtd deleted file mode 100644 index 5d94a57c..00000000 --- a/libempathy/gossip-chatroom-manager.dtd +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - diff --git a/libempathy/gossip-chatroom-manager.h b/libempathy/gossip-chatroom-manager.h deleted file mode 100644 index 7d10a0fc..00000000 --- a/libempathy/gossip-chatroom-manager.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2004-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Xavier Claessens - * Martyn Russell - */ - -#ifndef __GOSSIP_CHATROOM_MANAGER_H__ -#define __GOSSIP_CHATROOM_MANAGER_H__ - -#include - -#include - -#include "gossip-chatroom.h" - -G_BEGIN_DECLS - -#define GOSSIP_TYPE_CHATROOM_MANAGER (gossip_chatroom_manager_get_type ()) -#define GOSSIP_CHATROOM_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOSSIP_TYPE_CHATROOM_MANAGER, GossipChatroomManager)) -#define GOSSIP_CHATROOM_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GOSSIP_TYPE_CHATROOM_MANAGER, GossipChatroomManagerClass)) -#define GOSSIP_IS_CHATROOM_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOSSIP_TYPE_CHATROOM_MANAGER)) -#define GOSSIP_IS_CHATROOM_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOSSIP_TYPE_CHATROOM_MANAGER)) -#define GOSSIP_CHATROOM_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOSSIP_TYPE_CHATROOM_MANAGER, GossipChatroomManagerClass)) - -typedef struct _GossipChatroomManager GossipChatroomManager; -typedef struct _GossipChatroomManagerClass GossipChatroomManagerClass; -typedef struct _GossipChatroomManagerPriv GossipChatroomManagerPriv; - -struct _GossipChatroomManager { - GObject parent; -}; - -struct _GossipChatroomManagerClass { - GObjectClass parent_class; -}; - -GType gossip_chatroom_manager_get_type (void) G_GNUC_CONST; -GossipChatroomManager *gossip_chatroom_manager_new (void); -gboolean gossip_chatroom_manager_add (GossipChatroomManager *manager, - GossipChatroom *chatroom); -void gossip_chatroom_manager_remove (GossipChatroomManager *manager, - GossipChatroom *chatroom); -GossipChatroom * gossip_chatroom_manager_find (GossipChatroomManager *manager, - McAccount *account, - const gchar *room); -GList * gossip_chatroom_manager_get_chatrooms (GossipChatroomManager *manager, - McAccount *account); -guint gossip_chatroom_manager_get_count (GossipChatroomManager *manager, - McAccount *account); -void gossip_chatroom_manager_store (GossipChatroomManager *manager); - -G_END_DECLS - -#endif /* __GOSSIP_CHATROOM_MANAGER_H__ */ diff --git a/libempathy/gossip-chatroom.c b/libempathy/gossip-chatroom.c deleted file mode 100644 index 5b1760fd..00000000 --- a/libempathy/gossip-chatroom.c +++ /dev/null @@ -1,362 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Xavier Claessens - */ - -#include "config.h" - -#include - -#include - -#include "gossip-chatroom.h" -#include "gossip-utils.h" - -#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CHATROOM, GossipChatroomPriv)) - -struct _GossipChatroomPriv { - McAccount *account; - gchar *room; - gchar *name; - gboolean auto_connect; -}; - -static void gossip_chatroom_class_init (GossipChatroomClass *klass); -static void gossip_chatroom_init (GossipChatroom *chatroom); -static void chatroom_finalize (GObject *object); -static void chatroom_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec); -static void chatroom_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec); - -enum { - PROP_0, - PROP_ACCOUNT, - PROP_ROOM, - PROP_NAME, - PROP_AUTO_CONNECT, -}; - -G_DEFINE_TYPE (GossipChatroom, gossip_chatroom, G_TYPE_OBJECT); - -static void -gossip_chatroom_class_init (GossipChatroomClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = chatroom_finalize; - object_class->get_property = chatroom_get_property; - object_class->set_property = chatroom_set_property; - - g_object_class_install_property (object_class, - PROP_ACCOUNT, - g_param_spec_object ("account", - "Chatroom Account", - "The account associated with an chatroom", - MC_TYPE_ACCOUNT, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_ROOM, - g_param_spec_string ("room", - "Chatroom Room", - "Chatroom represented as 'room@server'", - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_NAME, - g_param_spec_string ("name", - "Chatroom Name", - "Chatroom name", - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_AUTO_CONNECT, - g_param_spec_boolean ("auto_connect", - "Chatroom Auto Connect", - "Connect on startup", - FALSE, - G_PARAM_READWRITE)); - - - g_type_class_add_private (object_class, sizeof (GossipChatroomPriv)); -} - -static void -gossip_chatroom_init (GossipChatroom *chatroom) -{ -} - -static void -chatroom_finalize (GObject *object) -{ - GossipChatroomPriv *priv; - - priv = GET_PRIV (object); - - g_object_unref (priv->account); - g_free (priv->room); - g_free (priv->name); - - (G_OBJECT_CLASS (gossip_chatroom_parent_class)->finalize) (object); -} - -static void -chatroom_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec) -{ - GossipChatroomPriv *priv; - - priv = GET_PRIV (object); - - switch (param_id) { - case PROP_ACCOUNT: - g_value_set_object (value, priv->account); - break; - case PROP_ROOM: - g_value_set_string (value, priv->room); - break; - case PROP_NAME: - g_value_set_string (value, priv->name); - break; - case PROP_AUTO_CONNECT: - g_value_set_boolean (value, priv->auto_connect); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -static void -chatroom_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec) -{ - GossipChatroomPriv *priv; - - priv = GET_PRIV (object); - - switch (param_id) { - case PROP_ACCOUNT: - gossip_chatroom_set_account (GOSSIP_CHATROOM (object), - g_value_get_object (value)); - break; - case PROP_ROOM: - gossip_chatroom_set_room (GOSSIP_CHATROOM (object), - g_value_get_string (value)); - break; - case PROP_NAME: - gossip_chatroom_set_name (GOSSIP_CHATROOM (object), - g_value_get_string (value)); - break; - case PROP_AUTO_CONNECT: - gossip_chatroom_set_auto_connect (GOSSIP_CHATROOM (object), - g_value_get_boolean (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -GossipChatroom * -gossip_chatroom_new (McAccount *account, - const gchar *room) -{ - g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); - g_return_val_if_fail (room != NULL, NULL); - - return g_object_new (GOSSIP_TYPE_CHATROOM, - "account", account, - "room", room, - NULL); -} - -GossipChatroom * -gossip_chatroom_new_full (McAccount *account, - const gchar *room, - const gchar *name, - gboolean auto_connect) -{ - g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); - g_return_val_if_fail (room != NULL, NULL); - - return g_object_new (GOSSIP_TYPE_CHATROOM, - "account", account, - "room", room, - "name", name, - "auto_connect", auto_connect, - NULL); -} - -McAccount * -gossip_chatroom_get_account (GossipChatroom *chatroom) -{ - GossipChatroomPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CHATROOM (chatroom), NULL); - - priv = GET_PRIV (chatroom); - return priv->account; -} - -void -gossip_chatroom_set_account (GossipChatroom *chatroom, - McAccount *account) -{ - GossipChatroomPriv *priv; - - g_return_if_fail (GOSSIP_IS_CHATROOM (chatroom)); - g_return_if_fail (MC_IS_ACCOUNT (account)); - - priv = GET_PRIV (chatroom); - - if (account == priv->account) { - return; - } - if (priv->account) { - g_object_unref (priv->account); - } - priv->account = g_object_ref (account); - - g_object_notify (G_OBJECT (chatroom), "account"); -} - -const gchar * -gossip_chatroom_get_room (GossipChatroom *chatroom) -{ - GossipChatroomPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CHATROOM (chatroom), NULL); - - priv = GET_PRIV (chatroom); - return priv->room; -} - -void -gossip_chatroom_set_room (GossipChatroom *chatroom, - const gchar *room) -{ - GossipChatroomPriv *priv; - - g_return_if_fail (GOSSIP_IS_CHATROOM (chatroom)); - g_return_if_fail (room != NULL); - - priv = GET_PRIV (chatroom); - - g_free (priv->room); - priv->room = g_strdup (room); - - g_object_notify (G_OBJECT (chatroom), "room"); -} - -const gchar * -gossip_chatroom_get_name (GossipChatroom *chatroom) -{ - GossipChatroomPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CHATROOM (chatroom), NULL); - - priv = GET_PRIV (chatroom); - - if (G_STR_EMPTY (priv->name)) { - return priv->room; - } - - return priv->name; -} - -void -gossip_chatroom_set_name (GossipChatroom *chatroom, - const gchar *name) -{ - GossipChatroomPriv *priv; - - g_return_if_fail (GOSSIP_IS_CHATROOM (chatroom)); - - priv = GET_PRIV (chatroom); - - g_free (priv->name); - priv->name = NULL; - if (name) { - priv->name = g_strdup (name); - } - - g_object_notify (G_OBJECT (chatroom), "name"); -} - -gboolean -gossip_chatroom_get_auto_connect (GossipChatroom *chatroom) -{ - GossipChatroomPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CHATROOM (chatroom), FALSE); - - priv = GET_PRIV (chatroom); - return priv->auto_connect; -} - -void -gossip_chatroom_set_auto_connect (GossipChatroom *chatroom, - gboolean auto_connect) -{ - GossipChatroomPriv *priv; - - g_return_if_fail (GOSSIP_IS_CHATROOM (chatroom)); - - priv = GET_PRIV (chatroom); - - priv->auto_connect = auto_connect; - - g_object_notify (G_OBJECT (chatroom), "auto-connect"); -} - -gboolean -gossip_chatroom_equal (gconstpointer v1, - gconstpointer v2) -{ - McAccount *account_a; - McAccount *account_b; - const gchar *room_a; - const gchar *room_b; - - g_return_val_if_fail (GOSSIP_IS_CHATROOM (v1), FALSE); - g_return_val_if_fail (GOSSIP_IS_CHATROOM (v2), FALSE); - - account_a = gossip_chatroom_get_account (GOSSIP_CHATROOM (v1)); - account_b = gossip_chatroom_get_account (GOSSIP_CHATROOM (v2)); - - room_a = gossip_chatroom_get_room (GOSSIP_CHATROOM (v1)); - room_b = gossip_chatroom_get_room (GOSSIP_CHATROOM (v2)); - - return gossip_account_equal (account_a, account_b) && g_str_equal (room_a, room_b); -} - - diff --git a/libempathy/gossip-chatroom.h b/libempathy/gossip-chatroom.h deleted file mode 100644 index 70614a36..00000000 --- a/libempathy/gossip-chatroom.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Xavier Claessens - */ - -#ifndef __GOSSIP_CHATROOM_H__ -#define __GOSSIP_CHATROOM_H__ - -#include - -#include - -G_BEGIN_DECLS - -#define GOSSIP_TYPE_CHATROOM (gossip_chatroom_get_type ()) -#define GOSSIP_CHATROOM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOSSIP_TYPE_CHATROOM, GossipChatroom)) -#define GOSSIP_CHATROOM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GOSSIP_TYPE_CHATROOM, GossipChatroomClass)) -#define GOSSIP_IS_CHATROOM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOSSIP_TYPE_CHATROOM)) -#define GOSSIP_IS_CHATROOM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOSSIP_TYPE_CHATROOM)) -#define GOSSIP_CHATROOM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOSSIP_TYPE_CHATROOM, GossipChatroomClass)) - -#define GOSSIP_TYPE_CHATROOM_INVITE (gossip_chatroom_invite_get_gtype ()) - -typedef struct _GossipChatroom GossipChatroom; -typedef struct _GossipChatroomClass GossipChatroomClass; -typedef struct _GossipChatroomPriv GossipChatroomPriv; - -struct _GossipChatroom { - GObject parent; -}; - -struct _GossipChatroomClass { - GObjectClass parent_class; -}; - -GType gossip_chatroom_get_type (void) G_GNUC_CONST; -GossipChatroom *gossip_chatroom_new (McAccount *account, - const gchar *room); -GossipChatroom *gossip_chatroom_new_full (McAccount *account, - const gchar *room, - const gchar *name, - gboolean auto_connect); -McAccount * gossip_chatroom_get_account (GossipChatroom *chatroom); -void gossip_chatroom_set_account (GossipChatroom *chatroom, - McAccount *account); -const gchar * gossip_chatroom_get_room (GossipChatroom *chatroom); -void gossip_chatroom_set_room (GossipChatroom *chatroom, - const gchar *room); -const gchar * gossip_chatroom_get_name (GossipChatroom *chatroom); -void gossip_chatroom_set_name (GossipChatroom *chatroom, - const gchar *name); -gboolean gossip_chatroom_get_auto_connect (GossipChatroom *chatroom); -void gossip_chatroom_set_auto_connect (GossipChatroom *chatroom, - gboolean auto_connect); -gboolean gossip_chatroom_equal (gconstpointer v1, - gconstpointer v2); - - -G_BEGIN_DECLS - -#endif /* __GOSSIP_CHATROOM_H__ */ diff --git a/libempathy/gossip-conf.c b/libempathy/gossip-conf.c deleted file mode 100644 index e788da6b..00000000 --- a/libempathy/gossip-conf.c +++ /dev/null @@ -1,372 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Richard Hult - */ - -#include "config.h" - -#include - -#include - -#include "gossip-conf.h" -#include "gossip-debug.h" - -#define DEBUG_DOMAIN "Config" - -#define GOSSIP_CONF_ROOT "/apps/empathy" -#define DESKTOP_INTERFACE_ROOT "/desktop/gnome/interface" - -#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CONF, GossipConfPriv)) - -typedef struct { - GConfClient *gconf_client; -} GossipConfPriv; - -typedef struct { - GossipConf *conf; - GossipConfNotifyFunc func; - gpointer user_data; -} GossipConfNotifyData; - -static void conf_finalize (GObject *object); - -G_DEFINE_TYPE (GossipConf, gossip_conf, G_TYPE_OBJECT); - -static GossipConf *global_conf = NULL; - -static void -gossip_conf_class_init (GossipConfClass *class) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (class); - - object_class->finalize = conf_finalize; - - g_type_class_add_private (object_class, sizeof (GossipConfPriv)); -} - -static void -gossip_conf_init (GossipConf *conf) -{ - GossipConfPriv *priv; - - priv = GET_PRIV (conf); - - priv->gconf_client = gconf_client_get_default (); - - gconf_client_add_dir (priv->gconf_client, - GOSSIP_CONF_ROOT, - GCONF_CLIENT_PRELOAD_ONELEVEL, - NULL); - gconf_client_add_dir (priv->gconf_client, - DESKTOP_INTERFACE_ROOT, - GCONF_CLIENT_PRELOAD_NONE, - NULL); -} - -static void -conf_finalize (GObject *object) -{ - GossipConfPriv *priv; - - priv = GET_PRIV (object); - - gconf_client_remove_dir (priv->gconf_client, - GOSSIP_CONF_ROOT, - NULL); - gconf_client_remove_dir (priv->gconf_client, - DESKTOP_INTERFACE_ROOT, - NULL); - - g_object_unref (priv->gconf_client); - - G_OBJECT_CLASS (gossip_conf_parent_class)->finalize (object); -} - -GossipConf * -gossip_conf_get (void) -{ - if (!global_conf) { - global_conf = g_object_new (GOSSIP_TYPE_CONF, NULL); - } - - return global_conf; -} - -void -gossip_conf_shutdown (void) -{ - if (global_conf) { - g_object_unref (global_conf); - global_conf = NULL; - } -} - -gboolean -gossip_conf_set_int (GossipConf *conf, - const gchar *key, - gint value) -{ - GossipConfPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONF (conf), FALSE); - - gossip_debug (DEBUG_DOMAIN, "Setting int:'%s' to %d", key, value); - - priv = GET_PRIV (conf); - - return gconf_client_set_int (priv->gconf_client, - key, - value, - NULL); -} - -gboolean -gossip_conf_get_int (GossipConf *conf, - const gchar *key, - gint *value) -{ - GossipConfPriv *priv; - GError *error = NULL; - - *value = 0; - - g_return_val_if_fail (GOSSIP_IS_CONF (conf), FALSE); - g_return_val_if_fail (value != NULL, FALSE); - - priv = GET_PRIV (conf); - - *value = gconf_client_get_int (priv->gconf_client, - key, - &error); - - if (error) { - g_error_free (error); - return FALSE; - } - - return TRUE; -} - -gboolean -gossip_conf_set_bool (GossipConf *conf, - const gchar *key, - gboolean value) -{ - GossipConfPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONF (conf), FALSE); - - gossip_debug (DEBUG_DOMAIN, "Setting bool:'%s' to %d ---> %s", - key, value, value ? "true" : "false"); - - priv = GET_PRIV (conf); - - return gconf_client_set_bool (priv->gconf_client, - key, - value, - NULL); -} - -gboolean -gossip_conf_get_bool (GossipConf *conf, - const gchar *key, - gboolean *value) -{ - GossipConfPriv *priv; - GError *error = NULL; - - *value = FALSE; - - g_return_val_if_fail (GOSSIP_IS_CONF (conf), FALSE); - g_return_val_if_fail (value != NULL, FALSE); - - priv = GET_PRIV (conf); - - *value = gconf_client_get_bool (priv->gconf_client, - key, - &error); - - if (error) { - g_error_free (error); - return FALSE; - } - - return TRUE; -} - -gboolean -gossip_conf_set_string (GossipConf *conf, - const gchar *key, - const gchar *value) -{ - GossipConfPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONF (conf), FALSE); - - gossip_debug (DEBUG_DOMAIN, "Setting string:'%s' to '%s'", - key, value); - - priv = GET_PRIV (conf); - - return gconf_client_set_string (priv->gconf_client, - key, - value, - NULL); -} - -gboolean -gossip_conf_get_string (GossipConf *conf, - const gchar *key, - gchar **value) -{ - GossipConfPriv *priv; - GError *error = NULL; - - *value = NULL; - - g_return_val_if_fail (GOSSIP_IS_CONF (conf), FALSE); - - priv = GET_PRIV (conf); - - *value = gconf_client_get_string (priv->gconf_client, - key, - &error); - - if (error) { - g_error_free (error); - return FALSE; - } - - return TRUE; -} - -gboolean -gossip_conf_set_string_list (GossipConf *conf, - const gchar *key, - GSList *value) -{ - GossipConfPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONF (conf), FALSE); - - priv = GET_PRIV (conf); - - return gconf_client_set_list (priv->gconf_client, - key, - GCONF_VALUE_STRING, - value, - NULL); -} - -gboolean -gossip_conf_get_string_list (GossipConf *conf, - const gchar *key, - GSList **value) -{ - GossipConfPriv *priv; - GError *error = NULL; - - *value = NULL; - - g_return_val_if_fail (GOSSIP_IS_CONF (conf), FALSE); - - priv = GET_PRIV (conf); - - *value = gconf_client_get_list (priv->gconf_client, - key, - GCONF_VALUE_STRING, - &error); - if (error) { - g_error_free (error); - return FALSE; - } - - return TRUE; -} - -static void -conf_notify_data_free (GossipConfNotifyData *data) -{ - g_object_unref (data->conf); - g_slice_free (GossipConfNotifyData, data); -} - -static void -conf_notify_func (GConfClient *client, - guint id, - GConfEntry *entry, - gpointer user_data) -{ - GossipConfNotifyData *data; - - data = user_data; - - data->func (data->conf, - gconf_entry_get_key (entry), - data->user_data); -} - -guint -gossip_conf_notify_add (GossipConf *conf, - const gchar *key, - GossipConfNotifyFunc func, - gpointer user_data) -{ - GossipConfPriv *priv; - guint id; - GossipConfNotifyData *data; - - g_return_val_if_fail (GOSSIP_IS_CONF (conf), 0); - - priv = GET_PRIV (conf); - - data = g_slice_new (GossipConfNotifyData); - data->func = func; - data->user_data = user_data; - data->conf = g_object_ref (conf); - - id = gconf_client_notify_add (priv->gconf_client, - key, - conf_notify_func, - data, - (GFreeFunc) conf_notify_data_free, - NULL); - - return id; -} - -gboolean -gossip_conf_notify_remove (GossipConf *conf, - guint id) -{ - GossipConfPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONF (conf), FALSE); - - priv = GET_PRIV (conf); - - gconf_client_notify_remove (priv->gconf_client, id); - - return TRUE; -} - diff --git a/libempathy/gossip-conf.h b/libempathy/gossip-conf.h deleted file mode 100644 index 35fdfb90..00000000 --- a/libempathy/gossip-conf.h +++ /dev/null @@ -1,87 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GOSSIP_CONF_H__ -#define __GOSSIP_CONF_H__ - -#include - -G_BEGIN_DECLS - -#define GOSSIP_TYPE_CONF (gossip_conf_get_type ()) -#define GOSSIP_CONF(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOSSIP_TYPE_CONF, GossipConf)) -#define GOSSIP_CONF_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GOSSIP_TYPE_CONF, GossipConfClass)) -#define GOSSIP_IS_CONF(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOSSIP_TYPE_CONF)) -#define GOSSIP_IS_CONF_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOSSIP_TYPE_CONF)) -#define GOSSIP_CONF_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOSSIP_TYPE_CONF, GossipConfClass)) - -typedef struct _GossipConf GossipConf; -typedef struct _GossipConfClass GossipConfClass; - -struct _GossipConf { - GObject parent; -}; - -struct _GossipConfClass { - GObjectClass parent_class; -}; - -typedef void (*GossipConfNotifyFunc) (GossipConf *conf, - const gchar *key, - gpointer user_data); - -GType gossip_conf_get_type (void) G_GNUC_CONST; -GossipConf *gossip_conf_get (void); -void gossip_conf_shutdown (void); -guint gossip_conf_notify_add (GossipConf *conf, - const gchar *key, - GossipConfNotifyFunc func, - gpointer data); -gboolean gossip_conf_notify_remove (GossipConf *conf, - guint id); -gboolean gossip_conf_set_int (GossipConf *conf, - const gchar *key, - gint value); -gboolean gossip_conf_get_int (GossipConf *conf, - const gchar *key, - gint *value); -gboolean gossip_conf_set_bool (GossipConf *conf, - const gchar *key, - gboolean value); -gboolean gossip_conf_get_bool (GossipConf *conf, - const gchar *key, - gboolean *value); -gboolean gossip_conf_set_string (GossipConf *conf, - const gchar *key, - const gchar *value); -gboolean gossip_conf_get_string (GossipConf *conf, - const gchar *key, - gchar **value); -gboolean gossip_conf_set_string_list (GossipConf *conf, - const gchar *key, - GSList *value); -gboolean gossip_conf_get_string_list (GossipConf *conf, - const gchar *key, - GSList **value); - -G_END_DECLS - -#endif /* __GOSSIP_CONF_H__ */ - diff --git a/libempathy/gossip-contact.c b/libempathy/gossip-contact.c deleted file mode 100644 index ba97fa75..00000000 --- a/libempathy/gossip-contact.c +++ /dev/null @@ -1,800 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2004-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Martyn Russell - */ - -#include "config.h" - -#include - -#include - -#include "gossip-contact.h" -#include "gossip-utils.h" -#include "gossip-debug.h" - -#define DEBUG_DOMAIN "Contact" - -#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CONTACT, GossipContactPriv)) - -typedef struct _GossipContactPriv GossipContactPriv; - -struct _GossipContactPriv { - gchar *id; - gchar *name; - GossipAvatar *avatar; - McAccount *account; - GossipPresence *presence; - GList *groups; - GossipSubscription subscription; - guint handle; - gboolean is_user; -}; - -static void contact_class_init (GossipContactClass *class); -static void contact_init (GossipContact *contact); -static void contact_finalize (GObject *object); -static void contact_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec); -static void contact_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec); - -enum { - PROP_0, - PROP_ID, - PROP_NAME, - PROP_AVATAR, - PROP_ACCOUNT, - PROP_PRESENCE, - PROP_GROUPS, - PROP_SUBSCRIPTION, - PROP_HANDLE, - PROP_IS_USER -}; - -static gpointer parent_class = NULL; - -GType -gossip_contact_get_gtype (void) -{ - static GType type = 0; - - if (!type) { - static const GTypeInfo info = { - sizeof (GossipContactClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) contact_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (GossipContact), - 0, /* n_preallocs */ - (GInstanceInitFunc) contact_init - }; - - type = g_type_register_static (G_TYPE_OBJECT, - "GossipContact", - &info, 0); - } - - return type; -} - -static void -contact_class_init (GossipContactClass *class) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (class); - parent_class = g_type_class_peek_parent (class); - - object_class->finalize = contact_finalize; - object_class->get_property = contact_get_property; - object_class->set_property = contact_set_property; - - g_object_class_install_property (object_class, - PROP_ID, - g_param_spec_string ("id", - "Contact id", - "String identifying contact", - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_NAME, - g_param_spec_string ("name", - "Contact Name", - "The name of the contact", - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_AVATAR, - g_param_spec_boxed ("avatar", - "Avatar image", - "The avatar image", - GOSSIP_TYPE_AVATAR, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_ACCOUNT, - g_param_spec_object ("account", - "Contact Account", - "The account associated with the contact", - MC_TYPE_ACCOUNT, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_PRESENCE, - g_param_spec_object ("presence", - "Contact presence", - "Presence of contact", - GOSSIP_TYPE_PRESENCE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_GROUPS, - g_param_spec_pointer ("groups", - "Contact groups", - "Groups of contact", - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_SUBSCRIPTION, - g_param_spec_int ("subscription", - "Contact Subscription", - "The subscription status of the contact", - GOSSIP_SUBSCRIPTION_NONE, - GOSSIP_SUBSCRIPTION_BOTH, - GOSSIP_SUBSCRIPTION_NONE, - G_PARAM_READWRITE)); - - - g_object_class_install_property (object_class, - PROP_HANDLE, - g_param_spec_uint ("handle", - "Contact Handle", - "The handle of the contact", - 0, - G_MAXUINT, - 0, - G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_IS_USER, - g_param_spec_boolean ("is-user", - "Contact is-user", - "Is contact the user", - FALSE, - G_PARAM_READWRITE)); - - g_type_class_add_private (object_class, sizeof (GossipContactPriv)); -} - -static void -contact_init (GossipContact *contact) -{ -} - -static void -contact_finalize (GObject *object) -{ - GossipContactPriv *priv; - - priv = GET_PRIV (object); - - gossip_debug (DEBUG_DOMAIN, "finalize: %p", object); - - g_free (priv->name); - g_free (priv->id); - - if (priv->avatar) { - gossip_avatar_unref (priv->avatar); - } - - if (priv->presence) { - g_object_unref (priv->presence); - } - - if (priv->groups) { - g_list_foreach (priv->groups, (GFunc) g_free, NULL); - g_list_free (priv->groups); - } - - if (priv->account) { - g_object_unref (priv->account); - } - - (G_OBJECT_CLASS (parent_class)->finalize) (object); -} - -static void -contact_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec) -{ - GossipContactPriv *priv; - - priv = GET_PRIV (object); - - switch (param_id) { - case PROP_ID: - g_value_set_string (value, - gossip_contact_get_id (GOSSIP_CONTACT (object))); - break; - case PROP_NAME: - g_value_set_string (value, - gossip_contact_get_name (GOSSIP_CONTACT (object))); - break; - case PROP_AVATAR: - g_value_set_boxed (value, priv->avatar); - break; - case PROP_ACCOUNT: - g_value_set_object (value, priv->account); - break; - case PROP_PRESENCE: - g_value_set_object (value, priv->presence); - break; - case PROP_GROUPS: - g_value_set_pointer (value, priv->groups); - break; - case PROP_SUBSCRIPTION: - g_value_set_int (value, priv->subscription); - break; - case PROP_HANDLE: - g_value_set_uint (value, priv->handle); - break; - case PROP_IS_USER: - g_value_set_boolean (value, priv->is_user); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -static void -contact_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec) -{ - GossipContactPriv *priv; - - priv = GET_PRIV (object); - - switch (param_id) { - case PROP_ID: - gossip_contact_set_id (GOSSIP_CONTACT (object), - g_value_get_string (value)); - break; - case PROP_NAME: - gossip_contact_set_name (GOSSIP_CONTACT (object), - g_value_get_string (value)); - break; - case PROP_AVATAR: - gossip_contact_set_avatar (GOSSIP_CONTACT (object), - g_value_get_boxed (value)); - break; - case PROP_ACCOUNT: - gossip_contact_set_account (GOSSIP_CONTACT (object), - MC_ACCOUNT (g_value_get_object (value))); - break; - case PROP_PRESENCE: - gossip_contact_set_presence (GOSSIP_CONTACT (object), - GOSSIP_PRESENCE (g_value_get_object (value))); - break; - case PROP_GROUPS: - gossip_contact_set_groups (GOSSIP_CONTACT (object), - g_value_get_pointer (value)); - break; - case PROP_SUBSCRIPTION: - gossip_contact_set_subscription (GOSSIP_CONTACT (object), - g_value_get_int (value)); - break; - case PROP_HANDLE: - gossip_contact_set_handle (GOSSIP_CONTACT (object), - g_value_get_uint (value)); - break; - case PROP_IS_USER: - gossip_contact_set_is_user (GOSSIP_CONTACT (object), - g_value_get_boolean (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -GossipContact * -gossip_contact_new (McAccount *account) -{ - return g_object_new (GOSSIP_TYPE_CONTACT, - "account", account, - NULL); -} - -GossipContact * -gossip_contact_new_full (McAccount *account, - const gchar *id, - const gchar *name) -{ - return g_object_new (GOSSIP_TYPE_CONTACT, - "account", account, - "name", name, - "id", id, - NULL); -} - -const gchar * -gossip_contact_get_id (GossipContact *contact) -{ - GossipContactPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), ""); - - priv = GET_PRIV (contact); - - if (priv->id) { - return priv->id; - } - - return ""; -} - -const gchar * -gossip_contact_get_name (GossipContact *contact) -{ - GossipContactPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), ""); - - priv = GET_PRIV (contact); - - if (G_STR_EMPTY (priv->name)) { - return gossip_contact_get_id (contact); - } - - return priv->name; -} - -GossipAvatar * -gossip_contact_get_avatar (GossipContact *contact) -{ - GossipContactPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL); - - priv = GET_PRIV (contact); - - return priv->avatar; -} - -McAccount * -gossip_contact_get_account (GossipContact *contact) -{ - GossipContactPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL); - - priv = GET_PRIV (contact); - - return priv->account; -} - -GossipPresence * -gossip_contact_get_presence (GossipContact *contact) -{ - GossipContactPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL); - - priv = GET_PRIV (contact); - - return priv->presence; -} - -GList * -gossip_contact_get_groups (GossipContact *contact) -{ - GossipContactPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL); - - priv = GET_PRIV (contact); - - return priv->groups; -} - -GossipSubscription -gossip_contact_get_subscription (GossipContact *contact) -{ - GossipContactPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), - GOSSIP_SUBSCRIPTION_NONE); - - priv = GET_PRIV (contact); - - return priv->subscription; -} - -guint -gossip_contact_get_handle (GossipContact *contact) -{ - GossipContactPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), 0); - - priv = GET_PRIV (contact); - - return priv->handle; -} - -gboolean -gossip_contact_is_user (GossipContact *contact) -{ - GossipContactPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), FALSE); - - priv = GET_PRIV (contact); - - return priv->is_user; -} - -void -gossip_contact_set_id (GossipContact *contact, - const gchar *id) -{ - GossipContactPriv *priv; - - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); - g_return_if_fail (id != NULL); - - priv = GET_PRIV (contact); - - if (priv->id && strcmp (id, priv->id) == 0) { - return; - } - - g_free (priv->id); - priv->id = g_strdup (id); - - g_object_notify (G_OBJECT (contact), "id"); -} - -void -gossip_contact_set_name (GossipContact *contact, - const gchar *name) -{ - GossipContactPriv *priv; - - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); - g_return_if_fail (name != NULL); - - priv = GET_PRIV (contact); - - if (priv->name && strcmp (name, priv->name) == 0) { - return; - } - - g_free (priv->name); - priv->name = g_strdup (name); - - g_object_notify (G_OBJECT (contact), "name"); -} - -void -gossip_contact_set_avatar (GossipContact *contact, - GossipAvatar *avatar) -{ - GossipContactPriv *priv; - - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); - - priv = GET_PRIV (contact); - - if (priv->avatar == avatar) { - return; - } - - if (priv->avatar) { - gossip_avatar_unref (priv->avatar); - priv->avatar = NULL; - } - - if (avatar) { - priv->avatar = gossip_avatar_ref (avatar); - } - - g_object_notify (G_OBJECT (contact), "avatar"); -} - -void -gossip_contact_set_account (GossipContact *contact, - McAccount *account) -{ - GossipContactPriv *priv; - - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); - g_return_if_fail (MC_IS_ACCOUNT (account)); - - priv = GET_PRIV (contact); - - if (account == priv->account) { - return; - } - - if (priv->account) { - g_object_unref (priv->account); - } - priv->account = g_object_ref (account); - - g_object_notify (G_OBJECT (contact), "account"); -} - -void -gossip_contact_set_presence (GossipContact *contact, - GossipPresence *presence) -{ - GossipContactPriv *priv; - - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); - - priv = GET_PRIV (contact); - - if (presence == priv->presence) { - return; - } - - if (priv->presence) { - g_object_unref (priv->presence); - priv->presence = NULL; - } - - if (presence) { - priv->presence = g_object_ref (presence); - } - - g_object_notify (G_OBJECT (contact), "presence"); -} - -void -gossip_contact_set_groups (GossipContact *contact, - GList *groups) -{ - GossipContactPriv *priv; - GList *old_groups, *l; - - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); - - priv = GET_PRIV (contact); - - old_groups = priv->groups; - priv->groups = NULL; - - for (l = groups; l; l = l->next) { - priv->groups = g_list_append (priv->groups, - g_strdup (l->data)); - } - - g_list_foreach (old_groups, (GFunc) g_free, NULL); - g_list_free (old_groups); - - g_object_notify (G_OBJECT (contact), "groups"); -} - -void -gossip_contact_set_subscription (GossipContact *contact, - GossipSubscription subscription) -{ - GossipContactPriv *priv; - - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); - - priv = GET_PRIV (contact); - - if (priv->subscription == subscription) { - return; - } - - priv->subscription = subscription; - - g_object_notify (G_OBJECT (contact), "subscription"); -} - -void -gossip_contact_set_handle (GossipContact *contact, - guint handle) -{ - GossipContactPriv *priv; - - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); - - priv = GET_PRIV (contact); - - if (priv->handle == handle) { - return; - } - - priv->handle = handle; - - g_object_notify (G_OBJECT (contact), "handle"); -} - -void -gossip_contact_set_is_user (GossipContact *contact, - gboolean is_user) -{ - GossipContactPriv *priv; - - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); - - priv = GET_PRIV (contact); - - if (priv->is_user == is_user) { - return; - } - - priv->is_user = is_user; - - g_object_notify (G_OBJECT (contact), "is-user"); -} - -void -gossip_contact_add_group (GossipContact *contact, - const gchar *group) -{ - GossipContactPriv *priv; - - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); - g_return_if_fail (group != NULL); - - priv = GET_PRIV (contact); - - if (!g_list_find_custom (priv->groups, group, (GCompareFunc) strcmp)) { - priv->groups = g_list_prepend (priv->groups, g_strdup (group)); - g_object_notify (G_OBJECT (contact), "groups"); - } -} - -void -gossip_contact_remove_group (GossipContact *contact, - const gchar *group) -{ - GossipContactPriv *priv; - GList *l; - - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); - g_return_if_fail (group != NULL); - - priv = GET_PRIV (contact); - - l = g_list_find_custom (priv->groups, group, (GCompareFunc) strcmp); - if (l) { - g_free (l->data); - priv->groups = g_list_delete_link (priv->groups, l); - g_object_notify (G_OBJECT (contact), "groups"); - } -} - -gboolean -gossip_contact_is_online (GossipContact *contact) -{ - GossipContactPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), FALSE); - - priv = GET_PRIV (contact); - - if (!priv->presence) { - return FALSE; - } - - return (gossip_presence_get_state (priv->presence) > MC_PRESENCE_OFFLINE); -} - -gboolean -gossip_contact_is_in_group (GossipContact *contact, - const gchar *group) -{ - GossipContactPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), FALSE); - g_return_val_if_fail (!G_STR_EMPTY (group), FALSE); - - priv = GET_PRIV (contact); - - if (g_list_find_custom (priv->groups, group, (GCompareFunc) strcmp)) { - return TRUE; - } - - return FALSE; -} - -const gchar * -gossip_contact_get_status (GossipContact *contact) -{ - GossipContactPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), ""); - - priv = GET_PRIV (contact); - - if (priv->presence) { - const gchar *status; - - status = gossip_presence_get_status (priv->presence); - if (!status) { - McPresence state; - - state = gossip_presence_get_state (priv->presence); - status = gossip_presence_state_get_default_status (state); - } - - return status; - } - - return gossip_presence_state_get_default_status (MC_PRESENCE_OFFLINE); -} - -gboolean -gossip_contact_equal (gconstpointer v1, - gconstpointer v2) -{ - McAccount *account_a; - McAccount *account_b; - const gchar *id_a; - const gchar *id_b; - - g_return_val_if_fail (GOSSIP_IS_CONTACT (v1), FALSE); - g_return_val_if_fail (GOSSIP_IS_CONTACT (v2), FALSE); - - account_a = gossip_contact_get_account (GOSSIP_CONTACT (v1)); - account_b = gossip_contact_get_account (GOSSIP_CONTACT (v2)); - - id_a = gossip_contact_get_id (GOSSIP_CONTACT (v1)); - id_b = gossip_contact_get_id (GOSSIP_CONTACT (v2)); - - return gossip_account_equal (account_a, account_b) && g_str_equal (id_a, id_b); -} - -guint -gossip_contact_hash (gconstpointer key) -{ - GossipContactPriv *priv; - guint hash; - - g_return_val_if_fail (GOSSIP_IS_CONTACT (key), +1); - - priv = GET_PRIV (GOSSIP_CONTACT (key)); - - hash = gossip_account_hash (gossip_contact_get_account (GOSSIP_CONTACT (key))); - hash += g_str_hash (gossip_contact_get_id (GOSSIP_CONTACT (key))); - - return hash; -} - diff --git a/libempathy/gossip-contact.h b/libempathy/gossip-contact.h deleted file mode 100644 index 14b32fdc..00000000 --- a/libempathy/gossip-contact.h +++ /dev/null @@ -1,106 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2004 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GOSSIP_CONTACT_H__ -#define __GOSSIP_CONTACT_H__ - -#include - -#include - -#include "gossip-avatar.h" -#include "gossip-presence.h" - -G_BEGIN_DECLS - -#define GOSSIP_TYPE_CONTACT (gossip_contact_get_gtype ()) -#define GOSSIP_CONTACT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOSSIP_TYPE_CONTACT, GossipContact)) -#define GOSSIP_CONTACT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GOSSIP_TYPE_CONTACT, GossipContactClass)) -#define GOSSIP_IS_CONTACT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOSSIP_TYPE_CONTACT)) -#define GOSSIP_IS_CONTACT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOSSIP_TYPE_CONTACT)) -#define GOSSIP_CONTACT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOSSIP_TYPE_CONTACT, GossipContactClass)) - -typedef struct _GossipContact GossipContact; -typedef struct _GossipContactClass GossipContactClass; - -struct _GossipContact { - GObject parent; -}; - -struct _GossipContactClass { - GObjectClass parent_class; -}; - -typedef enum { - GOSSIP_SUBSCRIPTION_NONE = 0, - GOSSIP_SUBSCRIPTION_TO = 1 << 0, /* We send our presence to that contact */ - GOSSIP_SUBSCRIPTION_FROM = 1 << 1, /* That contact sends his presence to us */ - GOSSIP_SUBSCRIPTION_BOTH = GOSSIP_SUBSCRIPTION_TO | GOSSIP_SUBSCRIPTION_FROM -} GossipSubscription; - -GType gossip_contact_get_gtype (void) G_GNUC_CONST; - -GossipContact * gossip_contact_new (McAccount *account); -GossipContact * gossip_contact_new_full (McAccount *account, - const gchar *id, - const gchar *name); -const gchar * gossip_contact_get_id (GossipContact *contact); -const gchar * gossip_contact_get_name (GossipContact *contact); -GossipAvatar * gossip_contact_get_avatar (GossipContact *contact); -McAccount * gossip_contact_get_account (GossipContact *contact); -GossipPresence * gossip_contact_get_presence (GossipContact *contact); -GList * gossip_contact_get_groups (GossipContact *contact); -GossipSubscription gossip_contact_get_subscription (GossipContact *contact); -guint gossip_contact_get_handle (GossipContact *contact); -gboolean gossip_contact_is_user (GossipContact *contact); -void gossip_contact_set_id (GossipContact *contact, - const gchar *id); -void gossip_contact_set_name (GossipContact *contact, - const gchar *name); -void gossip_contact_set_avatar (GossipContact *contact, - GossipAvatar *avatar); -void gossip_contact_set_account (GossipContact *contact, - McAccount *account); -void gossip_contact_set_presence (GossipContact *contact, - GossipPresence *presence); -void gossip_contact_set_groups (GossipContact *contact, - GList *categories); -void gossip_contact_set_subscription (GossipContact *contact, - GossipSubscription subscription); -void gossip_contact_set_handle (GossipContact *contact, - guint handle); -void gossip_contact_set_is_user (GossipContact *contact, - gboolean is_user); -void gossip_contact_add_group (GossipContact *contact, - const gchar *group); -void gossip_contact_remove_group (GossipContact *contact, - const gchar *group); -gboolean gossip_contact_is_online (GossipContact *contact); -gboolean gossip_contact_is_in_group (GossipContact *contact, - const gchar *group); -const gchar * gossip_contact_get_status (GossipContact *contact); -gboolean gossip_contact_equal (gconstpointer v1, - gconstpointer v2); -guint gossip_contact_hash (gconstpointer key); - -G_END_DECLS - -#endif /* __GOSSIP_CONTACT_H__ */ - diff --git a/libempathy/gossip-debug.c b/libempathy/gossip-debug.c deleted file mode 100644 index a6bbeea2..00000000 --- a/libempathy/gossip-debug.c +++ /dev/null @@ -1,92 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Richard Hult - */ - -#include "config.h" - -#include -#include - -#include -#include - -/* Set EMPATHY_DEBUG to a colon/comma/space separated list of domains, or "all" - * to get all debug output. - */ - -#include "gossip-debug.h" - -static gchar **debug_strv; -static gboolean all_domains = FALSE; - -static void -debug_init (void) -{ - static gboolean inited = FALSE; - - if (!inited) { - const gchar *env; - gint i; - - env = g_getenv ("EMPATHY_DEBUG"); - - if (env) { - debug_strv = g_strsplit_set (env, ":, ", 0); - } else { - debug_strv = NULL; - } - - for (i = 0; debug_strv && debug_strv[i]; i++) { - if (strcmp ("all", debug_strv[i]) == 0) { - all_domains = TRUE; - } - } - - inited = TRUE; - } -} - -void -gossip_debug_impl (const gchar *domain, const gchar *msg, ...) -{ - gint i; - - g_return_if_fail (domain != NULL); - g_return_if_fail (msg != NULL); - - debug_init (); - - for (i = 0; debug_strv && debug_strv[i]; i++) { - if (all_domains || strcmp (domain, debug_strv[i]) == 0) { - va_list args; - - g_print ("%s: ", domain); - - va_start (args, msg); - g_vprintf (msg, args); - va_end (args); - - g_print ("\n"); - break; - } - } -} - diff --git a/libempathy/gossip-debug.h b/libempathy/gossip-debug.h deleted file mode 100644 index 39dae0f1..00000000 --- a/libempathy/gossip-debug.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GOSSIP_DEBUG_H__ -#define __GOSSIP_DEBUG_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_HAVE_ISO_VARARGS -# ifdef GOSSIP_DISABLE_DEBUG -# define gossip_debug(...) -# else -# define gossip_debug(...) gossip_debug_impl (__VA_ARGS__) -# endif -#elif defined(G_HAVE_GNUC_VARARGS) -# if GOSSIP_DISABLE_DEBUG -# define gossip_debug(fmt...) -# else -# define gossip_debug(fmt...) gossip_debug_impl(fmt) -# endif -#else -# if GOSSIP_DISABLE_DEBUG -# define gossip_debug(x) -# else -# define gossip_debug gossip_debug_impl -# endif -#endif - -void gossip_debug_impl (const gchar *domain, const gchar *msg, ...); - -G_END_DECLS - -#endif /* __GOSSIP_DEBUG_H__ */ - diff --git a/libempathy/gossip-message.c b/libempathy/gossip-message.c deleted file mode 100644 index a46a2a5d..00000000 --- a/libempathy/gossip-message.c +++ /dev/null @@ -1,418 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2004-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Xavier Claessens - */ - -#include "config.h" - -#include "gossip-message.h" - -#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_MESSAGE, GossipMessagePriv)) - -typedef struct _GossipMessagePriv GossipMessagePriv; - -struct _GossipMessagePriv { - GossipMessageType type; - GossipContact *sender; - GossipContact *receiver; - gchar *body; - GossipTime timestamp; - -}; - -static void gossip_message_class_init (GossipMessageClass *class); -static void gossip_message_init (GossipMessage *message); -static void gossip_message_finalize (GObject *object); -static void message_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec); -static void message_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec); - -enum { - PROP_0, - PROP_TYPE, - PROP_SENDER, - PROP_RECEIVER, - PROP_BODY, - PROP_TIMESTAMP, -}; - -static gpointer parent_class = NULL; - -GType -gossip_message_get_gtype (void) -{ - static GType type = 0; - - if (!type) { - static const GTypeInfo info = { - sizeof (GossipMessageClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) gossip_message_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (GossipMessage), - 0, /* n_preallocs */ - (GInstanceInitFunc) gossip_message_init - }; - - type = g_type_register_static (G_TYPE_OBJECT, - "GossipMessage", - &info, 0); - } - - return type; -} - -static void -gossip_message_class_init (GossipMessageClass *class) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (class); - parent_class = g_type_class_peek_parent (class); - - object_class->finalize = gossip_message_finalize; - object_class->get_property = message_get_property; - object_class->set_property = message_set_property; - - g_object_class_install_property (object_class, - PROP_TYPE, - g_param_spec_int ("type", - "Message Type", - "The type of message", - GOSSIP_MESSAGE_TYPE_NORMAL, - GOSSIP_MESSAGE_TYPE_LAST, - GOSSIP_MESSAGE_TYPE_NORMAL, - G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_SENDER, - g_param_spec_object ("sender", - "Message Sender", - "The sender of the message", - GOSSIP_TYPE_CONTACT, - G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_RECEIVER, - g_param_spec_object ("receiver", - "Message Receiver", - "The receiver of the message", - GOSSIP_TYPE_CONTACT, - G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_BODY, - g_param_spec_string ("body", - "Message Body", - "The content of the message", - NULL, - G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_TIMESTAMP, - g_param_spec_long ("timestamp", - "timestamp", - "timestamp", - -1, - G_MAXLONG, - -1, - G_PARAM_READWRITE)); - - - g_type_class_add_private (object_class, sizeof (GossipMessagePriv)); - -} - -static void -gossip_message_init (GossipMessage *message) -{ - GossipMessagePriv *priv; - - priv = GET_PRIV (message); - - priv->timestamp = gossip_time_get_current (); -} - -static void -gossip_message_finalize (GObject *object) -{ - GossipMessagePriv *priv; - - priv = GET_PRIV (object); - - if (priv->sender) { - g_object_unref (priv->sender); - } - if (priv->receiver) { - g_object_unref (priv->receiver); - } - - g_free (priv->body); - - (G_OBJECT_CLASS (parent_class)->finalize) (object); -} - -static void -message_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec) -{ - GossipMessagePriv *priv; - - priv = GET_PRIV (object); - - switch (param_id) { - case PROP_TYPE: - g_value_set_int (value, priv->type); - break; - case PROP_SENDER: - g_value_set_object (value, priv->sender); - break; - case PROP_RECEIVER: - g_value_set_object (value, priv->receiver); - break; - case PROP_BODY: - g_value_set_string (value, priv->body); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -static void -message_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec) -{ - GossipMessagePriv *priv; - - priv = GET_PRIV (object); - - switch (param_id) { - case PROP_TYPE: - gossip_message_set_type (GOSSIP_MESSAGE (object), - g_value_get_int (value)); - break; - case PROP_SENDER: - gossip_message_set_sender (GOSSIP_MESSAGE (object), - GOSSIP_CONTACT (g_value_get_object (value))); - break; - case PROP_RECEIVER: - gossip_message_set_receiver (GOSSIP_MESSAGE (object), - GOSSIP_CONTACT (g_value_get_object (value))); - break; - case PROP_BODY: - gossip_message_set_body (GOSSIP_MESSAGE (object), - g_value_get_string (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -GossipMessage * -gossip_message_new (const gchar *body) -{ - return g_object_new (GOSSIP_TYPE_MESSAGE, - "body", body, - NULL); -} - -GossipMessageType -gossip_message_get_type (GossipMessage *message) -{ - GossipMessagePriv *priv; - - g_return_val_if_fail (GOSSIP_IS_MESSAGE (message), - GOSSIP_MESSAGE_TYPE_NORMAL); - - priv = GET_PRIV (message); - - return priv->type; -} - -void -gossip_message_set_type (GossipMessage *message, - GossipMessageType type) -{ - GossipMessagePriv *priv; - - g_return_if_fail (GOSSIP_IS_MESSAGE (message)); - - priv = GET_PRIV (message); - - priv->type = type; - - g_object_notify (G_OBJECT (message), "type"); -} - -GossipContact * -gossip_message_get_sender (GossipMessage *message) -{ - GossipMessagePriv *priv; - - g_return_val_if_fail (GOSSIP_IS_MESSAGE (message), NULL); - - priv = GET_PRIV (message); - - return priv->sender; -} - -void -gossip_message_set_sender (GossipMessage *message, GossipContact *contact) -{ - GossipMessagePriv *priv; - GossipContact *old_sender; - - g_return_if_fail (GOSSIP_IS_MESSAGE (message)); - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); - - priv = GET_PRIV (message); - - old_sender = priv->sender; - priv->sender = g_object_ref (contact); - - if (old_sender) { - g_object_unref (old_sender); - } - - g_object_notify (G_OBJECT (message), "sender"); -} - -GossipContact * -gossip_message_get_receiver (GossipMessage *message) -{ - GossipMessagePriv *priv; - - g_return_val_if_fail (GOSSIP_IS_MESSAGE (message), NULL); - - priv = GET_PRIV (message); - - return priv->receiver; -} - -void -gossip_message_set_receiver (GossipMessage *message, GossipContact *contact) -{ - GossipMessagePriv *priv; - GossipContact *old_receiver; - - g_return_if_fail (GOSSIP_IS_MESSAGE (message)); - g_return_if_fail (GOSSIP_IS_CONTACT (contact)); - - priv = GET_PRIV (message); - - old_receiver = priv->receiver; - priv->receiver = g_object_ref (contact); - - if (old_receiver) { - g_object_unref (old_receiver); - } - - g_object_notify (G_OBJECT (message), "receiver"); -} - -const gchar * -gossip_message_get_body (GossipMessage *message) -{ - GossipMessagePriv *priv; - - g_return_val_if_fail (GOSSIP_IS_MESSAGE (message), NULL); - - priv = GET_PRIV (message); - - return priv->body; -} - -void -gossip_message_set_body (GossipMessage *message, - const gchar *body) -{ - GossipMessagePriv *priv; - GossipMessageType type; - - g_return_if_fail (GOSSIP_IS_MESSAGE (message)); - - priv = GET_PRIV (message); - - g_free (priv->body); - priv->body = NULL; - - type = GOSSIP_MESSAGE_TYPE_NORMAL; - if (g_str_has_prefix (body, "/me")) { - type = GOSSIP_MESSAGE_TYPE_ACTION; - body += 4; - } - else if (g_str_has_prefix (body, "/say")) { - body += 5; - } - - if (body) { - priv->body = g_strdup (body); - } - - if (type != priv->type) { - gossip_message_set_type (message, type); - } - - g_object_notify (G_OBJECT (message), "body"); -} - -GossipTime -gossip_message_get_timestamp (GossipMessage *message) -{ - GossipMessagePriv *priv; - - g_return_val_if_fail (GOSSIP_IS_MESSAGE (message), -1); - - priv = GET_PRIV (message); - - return priv->timestamp; -} - -void -gossip_message_set_timestamp (GossipMessage *message, - GossipTime timestamp) -{ - GossipMessagePriv *priv; - - g_return_if_fail (GOSSIP_IS_MESSAGE (message)); - g_return_if_fail (timestamp >= -1); - - priv = GET_PRIV (message); - - if (timestamp <= 0) { - priv->timestamp = gossip_time_get_current (); - } else { - priv->timestamp = timestamp; - } - - g_object_notify (G_OBJECT (message), "timestamp"); -} - diff --git a/libempathy/gossip-message.h b/libempathy/gossip-message.h deleted file mode 100644 index aa494802..00000000 --- a/libempathy/gossip-message.h +++ /dev/null @@ -1,82 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2004-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - * Xavier Claessens - */ - -#ifndef __GOSSIP_MESSAGE_H__ -#define __GOSSIP_MESSAGE_H__ - -#include - -#include "gossip-contact.h" -#include "gossip-time.h" - -G_BEGIN_DECLS - -#define GOSSIP_TYPE_MESSAGE (gossip_message_get_gtype ()) -#define GOSSIP_MESSAGE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOSSIP_TYPE_MESSAGE, GossipMessage)) -#define GOSSIP_MESSAGE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GOSSIP_TYPE_MESSAGE, GossipMessageClass)) -#define GOSSIP_IS_MESSAGE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOSSIP_TYPE_MESSAGE)) -#define GOSSIP_IS_MESSAGE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOSSIP_TYPE_MESSAGE)) -#define GOSSIP_MESSAGE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOSSIP_TYPE_MESSAGE, GossipMessageClass)) - -typedef struct _GossipMessage GossipMessage; -typedef struct _GossipMessageClass GossipMessageClass; - -struct _GossipMessage { - GObject parent; -}; - -struct _GossipMessageClass { - GObjectClass parent_class; -}; - -typedef enum { - GOSSIP_MESSAGE_TYPE_NORMAL, - GOSSIP_MESSAGE_TYPE_ACTION, - GOSSIP_MESSAGE_TYPE_NOTICE, - GOSSIP_MESSAGE_TYPE_AUTO_REPLY, - GOSSIP_MESSAGE_TYPE_LAST -} GossipMessageType; - -GType gossip_message_get_gtype (void) G_GNUC_CONST; -GossipMessage * gossip_message_new (const gchar *body); -GossipMessageType gossip_message_get_type (GossipMessage *message); -void gossip_message_set_type (GossipMessage *message, - GossipMessageType type); -GossipContact * gossip_message_get_sender (GossipMessage *message); -void gossip_message_set_sender (GossipMessage *message, - GossipContact *contact); -GossipContact * gossip_message_get_receiver (GossipMessage *message); -void gossip_message_set_receiver (GossipMessage *message, - GossipContact *contact); -const gchar * gossip_message_get_body (GossipMessage *message); -void gossip_message_set_body (GossipMessage *message, - const gchar *body); -/* What return value should we have here? */ -GossipTime gossip_message_get_timestamp (GossipMessage *message); -void gossip_message_set_timestamp (GossipMessage *message, - GossipTime timestamp); - -G_END_DECLS - -#endif /* __GOSSIP_MESSAGE_H__ */ diff --git a/libempathy/gossip-presence.c b/libempathy/gossip-presence.c deleted file mode 100644 index 7add3966..00000000 --- a/libempathy/gossip-presence.c +++ /dev/null @@ -1,337 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2004-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Mikael Hallendal - */ - -#include "config.h" - -#include - -#include - -#include "gossip-presence.h" -#include "gossip-time.h" - -#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_PRESENCE, GossipPresencePriv)) - -typedef struct _GossipPresencePriv GossipPresencePriv; - -struct _GossipPresencePriv { - McPresence state; - gchar *status; - GossipTime timestamp; -}; - -static void presence_finalize (GObject *object); -static void presence_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec); -static void presence_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec); - -enum { - PROP_0, - PROP_STATE, - PROP_STATUS -}; - -G_DEFINE_TYPE (GossipPresence, gossip_presence, G_TYPE_OBJECT); - -static void -gossip_presence_class_init (GossipPresenceClass *class) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (class); - - object_class->finalize = presence_finalize; - object_class->get_property = presence_get_property; - object_class->set_property = presence_set_property; - - g_object_class_install_property (object_class, - PROP_STATE, - g_param_spec_int ("state", - "Presence State", - "The current state of the presence", - MC_PRESENCE_UNSET, - LAST_MC_PRESENCE, - MC_PRESENCE_AVAILABLE, - G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_STATUS, - g_param_spec_string ("status", - "Presence Status", - "Status string set on presence", - NULL, - G_PARAM_READWRITE)); - - g_type_class_add_private (object_class, sizeof (GossipPresencePriv)); -} - -static void -gossip_presence_init (GossipPresence *presence) -{ - GossipPresencePriv *priv; - - priv = GET_PRIV (presence); - - priv->state = MC_PRESENCE_AVAILABLE; - priv->status = NULL; - priv->timestamp = gossip_time_get_current (); -} - -static void -presence_finalize (GObject *object) -{ - GossipPresencePriv *priv; - - priv = GET_PRIV (object); - - g_free (priv->status); - - (G_OBJECT_CLASS (gossip_presence_parent_class)->finalize) (object); -} - -static void -presence_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec) -{ - GossipPresencePriv *priv; - - priv = GET_PRIV (object); - - switch (param_id) { - case PROP_STATE: - g_value_set_int (value, priv->state); - break; - case PROP_STATUS: - g_value_set_string (value, - gossip_presence_get_status (GOSSIP_PRESENCE (object))); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - } -} -static void -presence_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec) -{ - GossipPresencePriv *priv; - - priv = GET_PRIV (object); - - switch (param_id) { - case PROP_STATE: - priv->state = g_value_get_int (value); - break; - case PROP_STATUS: - gossip_presence_set_status (GOSSIP_PRESENCE (object), - g_value_get_string (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - } -} - -GossipPresence * -gossip_presence_new (void) -{ - return g_object_new (GOSSIP_TYPE_PRESENCE, NULL); -} - -GossipPresence * -gossip_presence_new_full (McPresence state, - const gchar *status) -{ - return g_object_new (GOSSIP_TYPE_PRESENCE, - "state", state, - "status", status, - NULL); -} - -const gchar * -gossip_presence_get_status (GossipPresence *presence) -{ - GossipPresencePriv *priv; - - g_return_val_if_fail (GOSSIP_IS_PRESENCE (presence), - _("Offline")); - - priv = GET_PRIV (presence); - - return priv->status; -} - -McPresence -gossip_presence_get_state (GossipPresence *presence) -{ - GossipPresencePriv *priv; - - g_return_val_if_fail (GOSSIP_IS_PRESENCE (presence), - MC_PRESENCE_AVAILABLE); - - priv = GET_PRIV (presence); - - return priv->state; -} - -void -gossip_presence_set_state (GossipPresence *presence, - McPresence state) -{ - GossipPresencePriv *priv; - - g_return_if_fail (GOSSIP_IS_PRESENCE (presence)); - - priv = GET_PRIV (presence); - - priv->state = state; - - g_object_notify (G_OBJECT (presence), "state"); -} - -void -gossip_presence_set_status (GossipPresence *presence, - const gchar *status) -{ - GossipPresencePriv *priv; - - priv = GET_PRIV (presence); - g_return_if_fail (GOSSIP_IS_PRESENCE (presence)); - - g_free (priv->status); - - if (status) { - priv->status = g_strdup (status); - } else { - priv->status = NULL; - } - - g_object_notify (G_OBJECT (presence), "status"); -} - -gint -gossip_presence_sort_func (gconstpointer a, - gconstpointer b) -{ - GossipPresencePriv *priv_a; - GossipPresencePriv *priv_b; - gint diff; - - g_return_val_if_fail (GOSSIP_IS_PRESENCE (a), 0); - g_return_val_if_fail (GOSSIP_IS_PRESENCE (b), 0); - - priv_a = GET_PRIV (a); - priv_b = GET_PRIV (b); - - /* 1. State */ - diff = priv_a->state - priv_b->state; - if (diff != 0) { - return diff < 1 ? -1 : +1; - } - - /* 3. Time (newest first) */ - diff = priv_b->timestamp - priv_a->timestamp; - if (diff != 0) { - return diff < 1 ? -1 : +1; - } - - /* No real difference */ - return 0; -} - -const gchar * -gossip_presence_state_get_default_status (McPresence state) -{ - switch (state) { - case MC_PRESENCE_AVAILABLE: - return _("Available"); - case MC_PRESENCE_DO_NOT_DISTURB: - return _("Busy"); - case MC_PRESENCE_AWAY: - case MC_PRESENCE_EXTENDED_AWAY: - return _("Away"); - case MC_PRESENCE_HIDDEN: - case MC_PRESENCE_OFFLINE: - case MC_PRESENCE_UNSET: - return _("Offline"); - default: - g_assert_not_reached (); - } - - return NULL; -} - -const gchar * -gossip_presence_state_to_str (McPresence state) -{ - switch (state) { - case MC_PRESENCE_AVAILABLE: - return "available"; - case MC_PRESENCE_DO_NOT_DISTURB: - return "busy"; - case MC_PRESENCE_AWAY: - return "away"; - case MC_PRESENCE_EXTENDED_AWAY: - return "ext_away"; - case MC_PRESENCE_HIDDEN: - return "hidden"; - case MC_PRESENCE_OFFLINE: - return "offline"; - case MC_PRESENCE_UNSET: - return "unset"; - default: - g_assert_not_reached (); - } - - return NULL; -} - -McPresence -gossip_presence_state_from_str (const gchar *str) -{ - if (strcmp (str, "available") == 0) { - return MC_PRESENCE_AVAILABLE; - } else if ((strcmp (str, "dnd") == 0) || (strcmp (str, "busy") == 0)) { - return MC_PRESENCE_DO_NOT_DISTURB; - } else if ((strcmp (str, "away") == 0) || (strcmp (str, "brb") == 0)) { - return MC_PRESENCE_AWAY; - } else if ((strcmp (str, "xa") == 0) || (strcmp (str, "ext_away") == 0)) { - return MC_PRESENCE_EXTENDED_AWAY; - } else if (strcmp (str, "hidden") == 0) { - return MC_PRESENCE_HIDDEN; - } else if (strcmp (str, "offline") == 0) { - return MC_PRESENCE_OFFLINE; - } else if (strcmp (str, "unset") == 0) { - return MC_PRESENCE_UNSET; - } - - return MC_PRESENCE_AVAILABLE; -} - diff --git a/libempathy/gossip-presence.h b/libempathy/gossip-presence.h deleted file mode 100644 index 0029906f..00000000 --- a/libempathy/gossip-presence.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2004 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GOSSIP_PRESENCE_H__ -#define __GOSSIP_PRESENCE_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GOSSIP_TYPE_PRESENCE (gossip_presence_get_type ()) -#define GOSSIP_PRESENCE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOSSIP_TYPE_PRESENCE, GossipPresence)) -#define GOSSIP_PRESENCE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GOSSIP_TYPE_PRESENCE, GossipPresenceClass)) -#define GOSSIP_IS_PRESENCE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOSSIP_TYPE_PRESENCE)) -#define GOSSIP_IS_PRESENCE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOSSIP_TYPE_PRESENCE)) -#define GOSSIP_PRESENCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOSSIP_TYPE_PRESENCE, GossipPresenceClass)) - -typedef struct _GossipPresence GossipPresence; -typedef struct _GossipPresenceClass GossipPresenceClass; - -struct _GossipPresence { - GObject parent; -}; - -struct _GossipPresenceClass { - GObjectClass parent_class; -}; - -GType gossip_presence_get_type (void) G_GNUC_CONST; - -GossipPresence * gossip_presence_new (void); -GossipPresence * gossip_presence_new_full (McPresence state, - const gchar *status); -McPresence gossip_presence_get_state (GossipPresence *presence); -const gchar * gossip_presence_get_status (GossipPresence *presence); -void gossip_presence_set_state (GossipPresence *presence, - McPresence state); -void gossip_presence_set_status (GossipPresence *presence, - const gchar *status); -gint gossip_presence_sort_func (gconstpointer a, - gconstpointer b); -const gchar * gossip_presence_state_get_default_status (McPresence state); -const gchar * gossip_presence_state_to_str (McPresence state); -McPresence gossip_presence_state_from_str (const gchar *str); - -G_END_DECLS - -#endif /* __GOSSIP_PRESENCE_H__ */ - diff --git a/libempathy/gossip-telepathy-group.c b/libempathy/gossip-telepathy-group.c deleted file mode 100644 index 5d6bff67..00000000 --- a/libempathy/gossip-telepathy-group.c +++ /dev/null @@ -1,543 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006 Xavier Claessens - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include - -#include -#include -#include -#include -#include - -#include "gossip-debug.h" -#include "gossip-telepathy-group.h" -#include "empathy-marshal.h" - -#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ - GOSSIP_TYPE_TELEPATHY_GROUP, GossipTelepathyGroupPriv)) - -#define DEBUG_DOMAIN "TelepathyGroup" - -struct _GossipTelepathyGroupPriv { - DBusGProxy *group_iface; - TpConn *tp_conn; - TpChan *tp_chan; - gchar *group_name; -}; - -static void gossip_telepathy_group_class_init (GossipTelepathyGroupClass *klass); -static void gossip_telepathy_group_init (GossipTelepathyGroup *group); -static void telepathy_group_finalize (GObject *object); -static void telepathy_group_destroy_cb (DBusGProxy *proxy, - GossipTelepathyGroup *group); -static void telepathy_group_members_changed_cb (DBusGProxy *group_iface, - gchar *message, - GArray *added, - GArray *removed, - GArray *local_pending, - GArray *remote_pending, - guint actor, - guint reason, - GossipTelepathyGroup *group); - -enum { - MEMBERS_ADDED, - MEMBERS_REMOVED, - LOCAL_PENDING, - REMOTE_PENDING, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL]; - -G_DEFINE_TYPE (GossipTelepathyGroup, gossip_telepathy_group, G_TYPE_OBJECT); - -static void -gossip_telepathy_group_class_init (GossipTelepathyGroupClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = telepathy_group_finalize; - - signals[MEMBERS_ADDED] = - g_signal_new ("members-added", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - empathy_marshal_VOID__POINTER_UINT_UINT_STRING, - G_TYPE_NONE, - 4, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING); - - signals[MEMBERS_REMOVED] = - g_signal_new ("members-removed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - empathy_marshal_VOID__POINTER_UINT_UINT_STRING, - G_TYPE_NONE, - 4, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING); - - signals[LOCAL_PENDING] = - g_signal_new ("local-pending", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - empathy_marshal_VOID__POINTER_UINT_UINT_STRING, - G_TYPE_NONE, - 4, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING); - - signals[REMOTE_PENDING] = - g_signal_new ("remote-pending", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - empathy_marshal_VOID__POINTER_UINT_UINT_STRING, - G_TYPE_NONE, - 4, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING); - - g_type_class_add_private (object_class, sizeof (GossipTelepathyGroupPriv)); -} - -static void -gossip_telepathy_group_init (GossipTelepathyGroup *group) -{ -} - -static void -telepathy_group_finalize (GObject *object) -{ - GossipTelepathyGroupPriv *priv; - - priv = GET_PRIV (object); - - if (priv->group_iface) { - g_signal_handlers_disconnect_by_func (priv->group_iface, - telepathy_group_destroy_cb, - object); - dbus_g_proxy_disconnect_signal (priv->group_iface, "MembersChanged", - G_CALLBACK (telepathy_group_members_changed_cb), - object); - g_object_unref (priv->group_iface); - } - - if (priv->tp_conn) { - g_object_unref (priv->tp_conn); - } - - if (priv->tp_chan) { - g_object_unref (priv->tp_chan); - } - - g_free (priv->group_name); - - G_OBJECT_CLASS (gossip_telepathy_group_parent_class)->finalize (object); -} - -GossipTelepathyGroup * -gossip_telepathy_group_new (TpChan *tp_chan, - TpConn *tp_conn) -{ - GossipTelepathyGroup *group; - GossipTelepathyGroupPriv *priv; - DBusGProxy *group_iface; - - g_return_val_if_fail (TELEPATHY_IS_CHAN (tp_chan), NULL); - - group_iface = tp_chan_get_interface (tp_chan, - TELEPATHY_CHAN_IFACE_GROUP_QUARK); - g_return_val_if_fail (group_iface != NULL, NULL); - - group = g_object_new (GOSSIP_TYPE_TELEPATHY_GROUP, NULL); - priv = GET_PRIV (group); - - priv->tp_conn = g_object_ref (tp_conn); - priv->tp_chan = g_object_ref (tp_chan); - priv->group_iface = g_object_ref (group_iface); - - dbus_g_proxy_connect_signal (priv->group_iface, "MembersChanged", - G_CALLBACK (telepathy_group_members_changed_cb), - group, NULL); - g_signal_connect (group_iface, "destroy", - G_CALLBACK (telepathy_group_destroy_cb), - group); - - - return group; -} - -void -gossip_telepathy_group_add_members (GossipTelepathyGroup *group, - GArray *handles, - const gchar *message) -{ - GossipTelepathyGroupPriv *priv; - GError *error = NULL; - - g_return_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group)); - g_return_if_fail (handles != NULL); - - priv = GET_PRIV (group); - - if (!tp_chan_iface_group_add_members (priv->group_iface, - handles, - message, - &error)) { - gossip_debug (DEBUG_DOMAIN, - "Failed to add members: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - } -} - -void -gossip_telepathy_group_add_member (GossipTelepathyGroup *group, - guint handle, - const gchar *message) -{ - GArray *handles; - - handles = g_array_new (FALSE, FALSE, sizeof (guint)); - g_array_append_val (handles, handle); - - gossip_telepathy_group_add_members (group, handles, message); - - g_array_free (handles, TRUE); -} - -void -gossip_telepathy_group_remove_members (GossipTelepathyGroup *group, - GArray *handles, - const gchar *message) -{ - GossipTelepathyGroupPriv *priv; - GError *error = NULL; - - g_return_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group)); - - priv = GET_PRIV (group); - - if (!tp_chan_iface_group_remove_members (priv->group_iface, - handles, - message, - &error)) { - gossip_debug (DEBUG_DOMAIN, - "Failed to remove members: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - } -} - -void -gossip_telepathy_group_remove_member (GossipTelepathyGroup *group, - guint handle, - const gchar *message) -{ - GArray *handles; - - g_return_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group)); - - handles = g_array_new (FALSE, FALSE, sizeof (guint)); - g_array_append_val (handles, handle); - - gossip_telepathy_group_remove_members (group, handles, message); - - g_array_free (handles, TRUE); -} - -GArray * -gossip_telepathy_group_get_members (GossipTelepathyGroup *group) -{ - GossipTelepathyGroupPriv *priv; - GArray *members; - GError *error = NULL; - - g_return_val_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group), NULL); - - priv = GET_PRIV (group); - - if (!tp_chan_iface_group_get_members (priv->group_iface, - &members, - &error)) { - gossip_debug (DEBUG_DOMAIN, - "Couldn't get members: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - return NULL; - } - - return members; -} - -void -gossip_telepathy_group_get_all_members (GossipTelepathyGroup *group, - GArray **members, - GArray **local_pending, - GArray **remote_pending) -{ - GossipTelepathyGroupPriv *priv; - GError *error = NULL; - - g_return_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group)); - - priv = GET_PRIV (group); - - if (!tp_chan_iface_group_get_all_members (priv->group_iface, - members, - local_pending, - remote_pending, - &error)) { - gossip_debug (DEBUG_DOMAIN, - "Couldn't get all members: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - } -} - -GList * -gossip_telepathy_group_get_local_pending_members_with_info (GossipTelepathyGroup *group) -{ - GossipTelepathyGroupPriv *priv; - GPtrArray *array; - guint i; - GList *infos = NULL; - GError *error = NULL; - - g_return_val_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group), NULL); - - priv = GET_PRIV (group); - - if (!tp_chan_iface_group_get_local_pending_members_with_info (priv->group_iface, - &array, - &error)) { - gossip_debug (DEBUG_DOMAIN, - "GetLocalPendingMembersWithInfo failed: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - - return NULL; - } - - if (!array) { - /* This happens with butterfly because - * GetLocalPendingMembersWithInfo is not - * implemented */ - return NULL; - } - - for (i = 0; array->len > i; i++) { - GValueArray *pending_struct; - GossipTpGroupInfo *info; - const gchar *message; - - info = g_slice_new (GossipTpGroupInfo); - - pending_struct = g_ptr_array_index (array, i); - info->member = g_value_get_uint (g_value_array_get_nth (pending_struct, 0)); - info->actor = g_value_get_uint (g_value_array_get_nth (pending_struct, 1)); - info->reason = g_value_get_uint (g_value_array_get_nth (pending_struct, 2)); - message = g_value_get_string (g_value_array_get_nth (pending_struct, 3)); - info->message = g_strdup (message); - g_value_array_free (pending_struct); - - infos = g_list_prepend (infos, info); - } - g_ptr_array_free (array, TRUE); - - return infos; -} - -void -gossip_telepathy_group_info_list_free (GList *infos) -{ - GList *l; - - for (l = infos; l; l = l->next) { - GossipTpGroupInfo *info; - - info = l->data; - - g_free (info->message); - g_slice_free (GossipTpGroupInfo, info); - } - g_list_free (infos); -} - - -static void -telepathy_group_destroy_cb (DBusGProxy *proxy, - GossipTelepathyGroup *group) -{ - GossipTelepathyGroupPriv *priv; - - priv = GET_PRIV (group); - - g_object_unref (priv->group_iface); - g_object_unref (priv->tp_conn); - g_object_unref (priv->tp_chan); - priv->group_iface = NULL; - priv->tp_chan = NULL; - priv->tp_conn = NULL; -} - -static void -telepathy_group_members_changed_cb (DBusGProxy *group_iface, - gchar *message, - GArray *added, - GArray *removed, - GArray *local_pending, - GArray *remote_pending, - guint actor, - guint reason, - GossipTelepathyGroup *group) -{ - GossipTelepathyGroupPriv *priv; - - priv = GET_PRIV (group); - - /* emit signals */ - if (added->len > 0) { - g_signal_emit (group, signals[MEMBERS_ADDED], 0, - added, actor, reason, message); - } - if (removed->len > 0) { - g_signal_emit (group, signals[MEMBERS_REMOVED], 0, - removed, actor, reason, message); - } - if (local_pending->len > 0) { - g_signal_emit (group, signals[LOCAL_PENDING], 0, - local_pending, actor, reason, message); - } - if (remote_pending->len > 0) { - g_signal_emit (group, signals[REMOTE_PENDING], 0, - remote_pending, actor, reason, message); - } -} - -const gchar * -gossip_telepathy_group_get_name (GossipTelepathyGroup *group) -{ - TelepathyHandleType handle_type; - guint channel_handle; - GArray *group_handles; - gchar **group_names; - GError *error = NULL; - - GossipTelepathyGroupPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group), NULL); - - priv = GET_PRIV (group); - - /* Lazy initialisation */ - if (priv->group_name) { - return priv->group_name; - } - - if (!tp_chan_get_handle (DBUS_G_PROXY (priv->tp_chan), - &handle_type, - &channel_handle, - &error)) { - gossip_debug (DEBUG_DOMAIN, - "Couldn't retreive channel handle for group: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - return NULL; - } - - group_handles = g_array_new (FALSE, FALSE, sizeof (guint)); - g_array_append_val (group_handles, channel_handle); - if (!tp_conn_inspect_handles (DBUS_G_PROXY (priv->tp_conn), - handle_type, - group_handles, - &group_names, - &error)) { - gossip_debug (DEBUG_DOMAIN, - "Couldn't get group name: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - g_array_free (group_handles, TRUE); - return NULL; - } - - priv->group_name = *group_names; - g_array_free (group_handles, TRUE); - g_free (group_names); - - return priv->group_name; -} - -guint -gossip_telepathy_group_get_self_handle (GossipTelepathyGroup *group) -{ - GossipTelepathyGroupPriv *priv; - guint handle; - GError *error = NULL; - - g_return_val_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group), 0 ); - - priv = GET_PRIV (group); - - if (!tp_chan_iface_group_get_self_handle (priv->group_iface, &handle, &error)) { - gossip_debug (DEBUG_DOMAIN, - "Failed to get self handle: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - return 0; - } - - return handle; -} - -const gchar * -gossip_telepathy_group_get_object_path (GossipTelepathyGroup *group) -{ - GossipTelepathyGroupPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group), NULL); - - priv = GET_PRIV (group); - - return dbus_g_proxy_get_path (DBUS_G_PROXY (priv->tp_chan)); -} - -gboolean -gossip_telepathy_group_is_member (GossipTelepathyGroup *group, - guint handle) -{ - GArray *members; - guint i; - gboolean found = FALSE; - - members = gossip_telepathy_group_get_members (group); - for (i = 0; i < members->len; i++) { - if (g_array_index (members, guint, i) == handle) { - found = TRUE; - break; - } - } - g_array_free (members, TRUE); - - return found; -} - diff --git a/libempathy/gossip-telepathy-group.h b/libempathy/gossip-telepathy-group.h deleted file mode 100644 index 17b96de2..00000000 --- a/libempathy/gossip-telepathy-group.h +++ /dev/null @@ -1,87 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006 Xavier Claessens - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GOSSIP_TELEPATHY_GROUP_H__ -#define __GOSSIP_TELEPATHY_GROUP_H__ - -#include - -#include - -G_BEGIN_DECLS - -#define GOSSIP_TYPE_TELEPATHY_GROUP (gossip_telepathy_group_get_type ()) -#define GOSSIP_TELEPATHY_GROUP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOSSIP_TYPE_TELEPATHY_GROUP, GossipTelepathyGroup)) -#define GOSSIP_TELEPATHY_GROUP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GOSSIP_TYPE_TELEPATHY_GROUP, GossipTelepathyGroupClass)) -#define GOSSIP_IS_TELEPATHY_GROUP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOSSIP_TYPE_TELEPATHY_GROUP)) -#define GOSSIP_IS_TELEPATHY_GROUP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOSSIP_TYPE_TELEPATHY_GROUP)) -#define GOSSIP_TELEPATHY_GROUP_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOSSIP_TYPE_TELEPATHY_GROUP, GossipTelepathyGroupClass)) - -typedef struct _GossipTelepathyGroup GossipTelepathyGroup; -typedef struct _GossipTelepathyGroupClass GossipTelepathyGroupClass; -typedef struct _GossipTelepathyGroupPriv GossipTelepathyGroupPriv; - -struct _GossipTelepathyGroup { - GObject parent; -}; - -struct _GossipTelepathyGroupClass { - GObjectClass parent_class; -}; - -typedef struct { - guint member; - guint actor; - guint reason; - gchar *message; -} GossipTpGroupInfo; - -GType gossip_telepathy_group_get_type (void) G_GNUC_CONST; -GossipTelepathyGroup *gossip_telepathy_group_new (TpChan *tp_chan, - TpConn *tp_conn); -void gossip_telepathy_group_add_members (GossipTelepathyGroup *group, - GArray *handles, - const gchar *message); -void gossip_telepathy_group_add_member (GossipTelepathyGroup *group, - guint handle, - const gchar *message); -void gossip_telepathy_group_remove_members (GossipTelepathyGroup *group, - GArray *handle, - const gchar *message); -void gossip_telepathy_group_remove_member (GossipTelepathyGroup *group, - guint handle, - const gchar *message); -GArray * gossip_telepathy_group_get_members (GossipTelepathyGroup *group); -void gossip_telepathy_group_get_all_members (GossipTelepathyGroup *group, - GArray **members, - GArray **local_pending, - GArray **remote_pending); -GList * gossip_telepathy_group_get_local_pending_members_with_info - (GossipTelepathyGroup *group); -void gossip_telepathy_group_info_list_free (GList *infos); -const gchar * gossip_telepathy_group_get_name (GossipTelepathyGroup *group); -guint gossip_telepathy_group_get_self_handle (GossipTelepathyGroup *group); -const gchar * gossip_telepathy_group_get_object_path (GossipTelepathyGroup *group); -gboolean gossip_telepathy_group_is_member (GossipTelepathyGroup *group, - guint handle); - -G_END_DECLS - -#endif /* __GOSSIP_TELEPATHY_GROUP_H__ */ diff --git a/libempathy/gossip-time.c b/libempathy/gossip-time.c deleted file mode 100644 index a1956354..00000000 --- a/libempathy/gossip-time.c +++ /dev/null @@ -1,124 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2003-2007 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Richard Hult - */ - -#include "config.h" - -#include -#include -#include - -#include "gossip-time.h" - -/* Note: GossipTime is always in UTC. */ - -GossipTime -gossip_time_get_current (void) -{ - return time (NULL); -} - -time_t -gossip_time_get_local_time (struct tm *tm) -{ - const gchar *timezone; - time_t t; - - timezone = g_getenv ("TZ"); - g_setenv ("TZ", "", TRUE); - - tzset (); - - t = mktime (tm); - - if (timezone) { - g_setenv ("TZ", timezone, TRUE); - } else { - g_unsetenv ("TZ"); - } - - tzset (); - - return t; -} - -/* The format is: "20021209T23:51:30" and is in UTC. 0 is returned on - * failure. The alternative format "20021209" is also accepted. - */ -GossipTime -gossip_time_parse (const gchar *str) -{ - struct tm tm; - gint year, month; - gint n_parsed; - - memset (&tm, 0, sizeof (struct tm)); - - n_parsed = sscanf (str, "%4d%2d%2dT%2d:%2d:%2d", - &year, &month, &tm.tm_mday, &tm.tm_hour, - &tm.tm_min, &tm.tm_sec); - if (n_parsed != 3 && n_parsed != 6) { - return 0; - } - - tm.tm_year = year - 1900; - tm.tm_mon = month - 1; - tm.tm_isdst = -1; - - return gossip_time_get_local_time (&tm); -} - -/* Converts the UTC timestamp to a string, also in UTC. Returns NULL on failure. */ -gchar * -gossip_time_to_string_utc (GossipTime t, - const gchar *format) -{ - gchar stamp[128]; - struct tm *tm; - - g_return_val_if_fail (format != NULL, NULL); - - tm = gmtime (&t); - if (strftime (stamp, sizeof (stamp), format, tm) == 0) { - return NULL; - } - - return g_strdup (stamp); -} - -/* Converts the UTC timestamp to a string, in local time. Returns NULL on failure. */ -gchar * -gossip_time_to_string_local (GossipTime t, - const gchar *format) -{ - gchar stamp[128]; - struct tm *tm; - - g_return_val_if_fail (format != NULL, NULL); - - tm = localtime (&t); - if (strftime (stamp, sizeof (stamp), format, tm) == 0) { - return NULL; - } - - return g_strdup (stamp); -} - diff --git a/libempathy/gossip-time.h b/libempathy/gossip-time.h deleted file mode 100644 index 06057aa5..00000000 --- a/libempathy/gossip-time.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2004 Imendio AB - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GOSSIP_TIME_H__ -#define __GOSSIP_TIME_H__ - -#define __USE_XOPEN -#include - -#include - -G_BEGIN_DECLS - -#define GOSSIP_TIME_FORMAT_DISPLAY_SHORT "%H:%M" -#define GOSSIP_TIME_FORMAT_DISPLAY_LONG "%a %d %b %Y" - -/* Note: Always in UTC. */ -typedef long GossipTime; - -GossipTime gossip_time_get_current (void); -time_t gossip_time_get_local_time (struct tm *tm); -GossipTime gossip_time_parse (const gchar *str); -GossipTime gossip_time_parse_format (const gchar *str, - const gchar *format); -gchar *gossip_time_to_string_utc (GossipTime t, - const gchar *format); -gchar *gossip_time_to_string_local (GossipTime t, - const gchar *format); - -G_END_DECLS - -#endif /* __GOSSIP_TIME_H__ */ - diff --git a/libempathy/gossip-utils.c b/libempathy/gossip-utils.c deleted file mode 100644 index 27bcb85d..00000000 --- a/libempathy/gossip-utils.c +++ /dev/null @@ -1,495 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2003-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Richard Hult - * Martyn Russell - * Xavier Claessens - */ - -#include "config.h" - -#include -#include -#include -#include - -#include - -#include -#include - -#include "gossip-debug.h" -#include "gossip-utils.h" -#include "empathy-contact-manager.h" - -#define DEBUG_DOMAIN "Utils" - -static void regex_init (void); - -gchar * -gossip_substring (const gchar *str, - gint start, - gint end) -{ - return g_strndup (str + start, end - start); -} - -/* - * Regular Expression code to match urls. - */ -#define USERCHARS "-A-Za-z0-9" -#define PASSCHARS "-A-Za-z0-9,?;.:/!%$^*&~\"#'" -#define HOSTCHARS "-A-Za-z0-9" -#define PATHCHARS "-A-Za-z0-9_$.+!*(),;:@&=?/~#%" -#define SCHEME "(news:|telnet:|nntp:|file:/|https?:|ftps?:|webcal:)" -#define USER "[" USERCHARS "]+(:["PASSCHARS "]+)?" -#define URLPATH "/[" PATHCHARS "]*[^]'.}>) \t\r\n,\\\"]" - -static regex_t dingus[GOSSIP_REGEX_ALL]; - -static void -regex_init (void) -{ - static gboolean inited = FALSE; - const gchar *expression; - gint i; - - if (inited) { - return; - } - - for (i = 0; i < GOSSIP_REGEX_ALL; i++) { - switch (i) { - case GOSSIP_REGEX_AS_IS: - expression = - SCHEME "//(" USER "@)?[" HOSTCHARS ".]+" - "(:[0-9]+)?(" URLPATH ")?"; - break; - case GOSSIP_REGEX_BROWSER: - expression = - "(www|ftp)[" HOSTCHARS "]*\\.[" HOSTCHARS ".]+" - "(:[0-9]+)?(" URLPATH ")?"; - break; - case GOSSIP_REGEX_EMAIL: - expression = - "(mailto:)?[a-z0-9][a-z0-9.-]*@[a-z0-9]" - "[a-z0-9-]*(\\.[a-z0-9][a-z0-9-]*)+"; - break; - case GOSSIP_REGEX_OTHER: - expression = - "news:[-A-Z\\^_a-z{|}~!\"#$%&'()*+,./0-9;:=?`]+" - "@[" HOSTCHARS ".]+(:[0-9]+)?"; - break; - default: - /* Silence the compiler. */ - expression = NULL; - continue; - } - - memset (&dingus[i], 0, sizeof (regex_t)); - regcomp (&dingus[i], expression, REG_EXTENDED | REG_ICASE); - } - - inited = TRUE; -} - -gint -gossip_regex_match (GossipRegExType type, - const gchar *msg, - GArray *start, - GArray *end) -{ - regmatch_t matches[1]; - gint ret = 0; - gint num_matches = 0; - gint offset = 0; - gint i; - - g_return_val_if_fail (type >= 0 || type <= GOSSIP_REGEX_ALL, 0); - - regex_init (); - - while (!ret && type != GOSSIP_REGEX_ALL) { - ret = regexec (&dingus[type], msg + offset, 1, matches, 0); - if (ret == 0) { - gint s; - - num_matches++; - - s = matches[0].rm_so + offset; - offset = matches[0].rm_eo + offset; - - g_array_append_val (start, s); - g_array_append_val (end, offset); - } - } - - if (type != GOSSIP_REGEX_ALL) { - gossip_debug (DEBUG_DOMAIN, - "Found %d matches for regex type:%d", - num_matches, type); - return num_matches; - } - - /* If GOSSIP_REGEX_ALL then we run ALL regex's on the string. */ - for (i = 0; i < GOSSIP_REGEX_ALL; i++, ret = 0) { - while (!ret) { - ret = regexec (&dingus[i], msg + offset, 1, matches, 0); - if (ret == 0) { - gint s; - - num_matches++; - - s = matches[0].rm_so + offset; - offset = matches[0].rm_eo + offset; - - g_array_append_val (start, s); - g_array_append_val (end, offset); - } - } - } - - gossip_debug (DEBUG_DOMAIN, - "Found %d matches for ALL regex types", - num_matches); - - return num_matches; -} - -gint -gossip_strcasecmp (const gchar *s1, - const gchar *s2) -{ - return gossip_strncasecmp (s1, s2, -1); -} - -gint -gossip_strncasecmp (const gchar *s1, - const gchar *s2, - gsize n) -{ - gchar *u1, *u2; - gint ret_val; - - u1 = g_utf8_casefold (s1, n); - u2 = g_utf8_casefold (s2, n); - - ret_val = g_utf8_collate (u1, u2); - g_free (u1); - g_free (u2); - - return ret_val; -} - -gboolean -gossip_xml_validate (xmlDoc *doc, - const gchar *dtd_filename) -{ - gchar *path, *escaped; - xmlValidCtxt cvp; - xmlDtd *dtd; - gboolean ret; - - path = g_build_filename (DATADIR, "empathy", dtd_filename, NULL); - - /* The list of valid chars is taken from libxml. */ - escaped = xmlURIEscapeStr (path, ":@&=+$,/?;"); - - g_free (path); - - memset (&cvp, 0, sizeof (cvp)); - dtd = xmlParseDTD (NULL, escaped); - ret = xmlValidateDtd (&cvp, doc, dtd); - - xmlFree (escaped); - xmlFreeDtd (dtd); - - return ret; -} - -xmlNodePtr -gossip_xml_node_get_child (xmlNodePtr node, - const gchar *child_name) -{ - xmlNodePtr l; - - g_return_val_if_fail (node != NULL, NULL); - g_return_val_if_fail (child_name != NULL, NULL); - - for (l = node->children; l; l = l->next) { - if (l->name && strcmp (l->name, child_name) == 0) { - return l; - } - } - - return NULL; -} - -xmlChar * -gossip_xml_node_get_child_content (xmlNodePtr node, - const gchar *child_name) -{ - xmlNodePtr l; - - g_return_val_if_fail (node != NULL, NULL); - g_return_val_if_fail (child_name != NULL, NULL); - - l = gossip_xml_node_get_child (node, child_name); - if (l) { - return xmlNodeGetContent (l); - } - - return NULL; -} - -xmlNodePtr -gossip_xml_node_find_child_prop_value (xmlNodePtr node, - const gchar *prop_name, - const gchar *prop_value) -{ - xmlNodePtr l; - xmlNodePtr found = NULL; - - g_return_val_if_fail (node != NULL, NULL); - g_return_val_if_fail (prop_name != NULL, NULL); - g_return_val_if_fail (prop_value != NULL, NULL); - - for (l = node->children; l && !found; l = l->next) { - xmlChar *prop; - - if (!xmlHasProp (l, prop_name)) { - continue; - } - - prop = xmlGetProp (l, prop_name); - if (prop && strcmp (prop, prop_value) == 0) { - found = l; - } - - xmlFree (prop); - } - - return found; -} - -GType -gossip_dbus_type_to_g_type (const gchar *dbus_type_string) -{ - if (dbus_type_string == NULL) - return G_TYPE_NONE; - - if (dbus_type_string[0] == 's') { - return G_TYPE_STRING; - } - else if (dbus_type_string[0] == 'b') { - return G_TYPE_BOOLEAN; - } - else if (dbus_type_string[0] == 'q') { - return G_TYPE_UINT; - } - else if (dbus_type_string[0] == 'n') { - return G_TYPE_INT; - } - - g_assert_not_reached (); - return G_TYPE_NONE; -} - -const gchar * -gossip_g_type_to_dbus_type (GType g_type) -{ - switch (g_type) { - case G_TYPE_STRING: - return "s"; - case G_TYPE_BOOLEAN: - return "b"; - case G_TYPE_UINT: - return "q"; - case G_TYPE_INT: - return "n"; - default: - g_assert_not_reached (); - } - - return NULL; -} - -gchar * -gossip_g_value_to_string (const GValue *value) -{ - gchar *return_string = NULL; - GValue string_g_value = {0, }; - - g_value_init (&string_g_value, G_TYPE_STRING); - g_value_transform (value, &string_g_value); - return_string = g_value_dup_string (&string_g_value); - g_value_unset (&string_g_value); - - return return_string; -} - -GValue * -gossip_string_to_g_value (const gchar *str, GType type) -{ - GValue *g_value; - - g_value = g_new0 (GValue, 1); - g_value_init (g_value, type); - - switch (type) { - case G_TYPE_STRING: - g_value_set_string (g_value, str); - break; - case G_TYPE_BOOLEAN: - g_value_set_boolean (g_value, (str[0] == 'y' || str[0] == 'T')); - break; - case G_TYPE_UINT: - g_value_set_uint (g_value, atoi (str)); - break; - case G_TYPE_INT: - g_value_set_int (g_value, atoi (str)); - break; - default: - g_assert_not_reached (); - } - - return g_value; -} - -gboolean -gossip_g_value_equal (const GValue *value1, - const GValue *value2) -{ - GType type; - - g_return_val_if_fail (value1 != NULL, FALSE); - g_return_val_if_fail (value2 != NULL, FALSE); - - type = G_VALUE_TYPE (value1); - if (type != G_VALUE_TYPE (value2)) { - return FALSE; - } - - switch (type) - { - case G_TYPE_STRING: { - const gchar *str1; - const gchar *str2; - - str1 = g_value_get_string (value1); - str2 = g_value_get_string (value2); - return (str1 && str2 && strcmp (str1, str2) == 0) || - (G_STR_EMPTY (str1) && G_STR_EMPTY (str2)); - } - case G_TYPE_BOOLEAN: - return g_value_get_boolean (value1) == g_value_get_boolean (value2); - case G_TYPE_UINT: - return g_value_get_uint (value1) == g_value_get_uint (value2); - case G_TYPE_INT: - return g_value_get_int (value1) == g_value_get_int (value2); - default: - g_warning ("Unsupported GType in value comparaison"); - } - - return FALSE; -} - -guint -gossip_account_hash (gconstpointer key) -{ - return g_str_hash (mc_account_get_unique_name (MC_ACCOUNT (key))); -} - -gboolean -gossip_account_equal (gconstpointer a, - gconstpointer b) -{ - const gchar *name_a; - const gchar *name_b; - - name_a = mc_account_get_unique_name (MC_ACCOUNT (a)); - name_b = mc_account_get_unique_name (MC_ACCOUNT (b)); - - return g_str_equal (name_a, name_b); -} - -MissionControl * -gossip_mission_control_new (void) -{ - static MissionControl *mc = NULL; - - if (!mc) { - mc = mission_control_new (tp_get_bus ()); - g_object_add_weak_pointer (G_OBJECT (mc), (gpointer) &mc); - } else { - g_object_ref (mc); - } - - return mc; -} - -gchar * -gossip_get_channel_id (McAccount *account, - TpChan *tp_chan) -{ - MissionControl *mc; - TpConn *tp_conn; - GArray *handles; - gchar **names; - gchar *name; - GError *error; - - g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); - g_return_val_if_fail (TELEPATHY_IS_CHAN (tp_chan), NULL); - - mc = gossip_mission_control_new (); - tp_conn = mission_control_get_connection (mc, account, NULL); - g_object_unref (mc); - - if (!tp_conn) { - return NULL; - } - - /* Get the handle's name */ - handles = g_array_new (FALSE, FALSE, sizeof (guint)); - g_array_append_val (handles, tp_chan->handle); - if (!tp_conn_inspect_handles (DBUS_G_PROXY (tp_conn), - tp_chan->handle_type, - handles, - &names, - &error)) { - gossip_debug (DEBUG_DOMAIN, - "Couldn't get id: %s", - error ? error->message : "No error given"); - - g_clear_error (&error); - g_array_free (handles, TRUE); - g_object_unref (tp_conn); - - return NULL; - } - - name = *names; - g_free (names); - g_object_unref (tp_conn); - - return name; -} - diff --git a/libempathy/gossip-utils.h b/libempathy/gossip-utils.h deleted file mode 100644 index 638c114b..00000000 --- a/libempathy/gossip-utils.h +++ /dev/null @@ -1,100 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2003-2007 Imendio AB - * Copyright (C) 2007 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Richard Hult - * Martyn Russell - * Xavier Claessens - */ - -#ifndef __GOSSIP_UTILS_H__ -#define __GOSSIP_UTILS_H__ - -#include -#include - -#include -#include - -#include - -#include -#include - -#include "gossip-contact.h" - -G_BEGIN_DECLS - -#define G_STR_EMPTY(x) ((x) == NULL || (x)[0] == '\0') - -typedef enum { - GOSSIP_REGEX_AS_IS, - GOSSIP_REGEX_BROWSER, - GOSSIP_REGEX_EMAIL, - GOSSIP_REGEX_OTHER, - GOSSIP_REGEX_ALL, -} GossipRegExType; - -/* Regular expressions */ -gchar * gossip_substring (const gchar *str, - gint start, - gint end); -gint gossip_regex_match (GossipRegExType type, - const gchar *msg, - GArray *start, - GArray *end); - -/* Strings */ -gint gossip_strcasecmp (const gchar *s1, - const gchar *s2); -gint gossip_strncasecmp (const gchar *s1, - const gchar *s2, - gsize n); - -/* XML */ -gboolean gossip_xml_validate (xmlDoc *doc, - const gchar *dtd_filename); -xmlNodePtr gossip_xml_node_get_child (xmlNodePtr node, - const gchar *child_name); -xmlChar * gossip_xml_node_get_child_content (xmlNodePtr node, - const gchar *child_name); -xmlNodePtr gossip_xml_node_find_child_prop_value (xmlNodePtr node, - const gchar *prop_name, - const gchar *prop_value); - - -/* GValue/GType */ -GType gossip_dbus_type_to_g_type (const gchar *dbus_type_string); -const gchar *gossip_g_type_to_dbus_type (GType g_type); -gchar * gossip_g_value_to_string (const GValue *value); -GValue * gossip_string_to_g_value (const gchar *str, - GType type); -gboolean gossip_g_value_equal (const GValue *value1, - const GValue *value2); - -guint gossip_account_hash (gconstpointer key); -gboolean gossip_account_equal (gconstpointer a, - gconstpointer b); -MissionControl *gossip_mission_control_new (void); -gchar * gossip_get_channel_id (McAccount *account, - TpChan *tp_chan); - -G_END_DECLS - -#endif /* __GOSSIP_UTILS_H__ */ diff --git a/src/empathy-accounts.c b/src/empathy-accounts.c index bc569d31..f5d0b1b4 100644 --- a/src/empathy-accounts.c +++ b/src/empathy-accounts.c @@ -28,7 +28,7 @@ #include #include -#include +#include static void destroy_cb (GtkWidget *dialog, @@ -46,7 +46,7 @@ main (int argc, char *argv[]) gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), DATADIR G_DIR_SEPARATOR_S "empathy"); - dialog = gossip_accounts_dialog_show (NULL); + dialog = empathy_accounts_dialog_show (NULL); g_signal_connect (dialog, "destroy", G_CALLBACK (destroy_cb), diff --git a/src/empathy.c b/src/empathy.c index 91152daa..6ca47192 100644 --- a/src/empathy.c +++ b/src/empathy.c @@ -37,17 +37,17 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include #include #include -#include -#include +#include +#include #define DEBUG_DOMAIN "EmpathyMain" @@ -58,7 +58,7 @@ static void service_ended_cb (MissionControl *mc, gpointer user_data) { - gossip_debug (DEBUG_DOMAIN, "Mission Control stopped"); + empathy_debug (DEBUG_DOMAIN, "Mission Control stopped"); } static void @@ -67,7 +67,7 @@ operation_error_cb (MissionControl *mc, guint error_code, gpointer user_data) { - gossip_debug (DEBUG_DOMAIN, "Error code %d during operation %d", + empathy_debug (DEBUG_DOMAIN, "Error code %d during operation %d", error_code, operation_id); } @@ -92,7 +92,7 @@ account_enabled_cb (McAccountMonitor *monitor, gchar *unique_name, EmpathyIdle *idle) { - gossip_debug (DEBUG_DOMAIN, "Account enabled: %s", unique_name); + empathy_debug (DEBUG_DOMAIN, "Account enabled: %s", unique_name); start_mission_control (idle); } @@ -103,25 +103,25 @@ new_channel_cb (EmpathyChandler *chandler, MissionControl *mc) { McAccount *account; - GossipChat *chat; + EmpathyChat *chat; gchar *id; account = mission_control_get_account_for_connection (mc, tp_conn, NULL); - id = gossip_get_channel_id (account, tp_chan); - chat = gossip_chat_window_find_chat (account, id); + id = empathy_get_channel_id (account, tp_chan); + chat = empathy_chat_window_find_chat (account, id); g_free (id); if (chat) { /* The chat already exists */ - if (!gossip_chat_is_connected (chat)) { + if (!empathy_chat_is_connected (chat)) { EmpathyTpChat *tp_chat; /* The chat died, give him the new text channel */ tp_chat = empathy_tp_chat_new (account, tp_chan); - gossip_chat_set_tp_chat (chat, tp_chat); + empathy_chat_set_tp_chat (chat, tp_chat); g_object_unref (tp_chat); } - gossip_chat_present (chat); + empathy_chat_present (chat); g_object_unref (account); return; @@ -129,14 +129,14 @@ new_channel_cb (EmpathyChandler *chandler, if (tp_chan->handle_type == TP_HANDLE_TYPE_CONTACT) { /* We have a new private chat channel */ - chat = GOSSIP_CHAT (gossip_private_chat_new (account, tp_chan)); + chat = EMPATHY_CHAT (empathy_private_chat_new (account, tp_chan)); } else if (tp_chan->handle_type == TP_HANDLE_TYPE_ROOM) { /* We have a new group chat channel */ - chat = GOSSIP_CHAT (gossip_group_chat_new (account, tp_chan)); + chat = EMPATHY_CHAT (empathy_group_chat_new (account, tp_chan)); } - gossip_chat_present (GOSSIP_CHAT (chat)); + empathy_chat_present (EMPATHY_CHAT (chat)); g_object_unref (chat); g_object_unref (account); @@ -186,7 +186,7 @@ main (int argc, char *argv[]) /* Setting up MC */ monitor = mc_account_monitor_new (); - mc = gossip_mission_control_new (); + mc = empathy_mission_control_new (); idle = empathy_idle_new (); g_signal_connect (monitor, "account-enabled", G_CALLBACK (account_enabled_cb),