summaryrefslogtreecommitdiff
path: root/gnome-2-22/libempathy-gtk
diff options
context:
space:
mode:
Diffstat (limited to 'gnome-2-22/libempathy-gtk')
-rw-r--r--gnome-2-22/libempathy-gtk/.gitignore2
-rw-r--r--gnome-2-22/libempathy-gtk/Makefile.am211
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-about-dialog.c113
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-about-dialog.h36
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-account-chooser.c677
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-account-chooser.h73
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-account-widget-generic.glade89
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-account-widget-icq.glade375
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-account-widget-irc.c511
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-account-widget-irc.glade451
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-account-widget-irc.h33
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-account-widget-jabber.glade566
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-account-widget-msn.glade335
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-account-widget-salut.glade396
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-account-widget-yahoo.glade526
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-account-widget.c680
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-account-widget.h53
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-accounts-dialog.c1083
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-accounts-dialog.glade350
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-accounts-dialog.h36
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-avatar-chooser.c569
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-avatar-chooser.h60
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-avatar-image.c306
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-avatar-image.h58
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-call-window.c519
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-call-window.glade300
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-call-window.h34
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-cell-renderer-activatable.c121
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-cell-renderer-activatable.h54
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-cell-renderer-expander.c482
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-cell-renderer-expander.h59
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-cell-renderer-text.c368
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-cell-renderer-text.h56
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-chat-view.c1570
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-chat-view.h119
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-chat-window.c1892
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-chat-window.h80
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-chat.c1761
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-chat.glade756
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-chat.h123
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-chatrooms-window.c582
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-chatrooms-window.glade477
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-chatrooms-window.h35
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-conf.c373
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-conf.h87
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-contact-dialogs.c344
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-contact-dialogs.glade120
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-contact-dialogs.h41
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-contact-list-store.c1549
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-contact-list-store.h108
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-contact-list-view.c1502
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-contact-list-view.h88
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-contact-widget.c946
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-contact-widget.glade983
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-contact-widget.h52
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-geometry.c186
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-geometry.h45
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-group-chat.c700
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-group-chat.glade123
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-group-chat.h67
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-images.h45
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-irc-network-dialog.c579
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-irc-network-dialog.h35
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-log-window.c1104
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-log-window.glade470
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-log-window.h39
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-main-window.c1160
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-main-window.glade310
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-main-window.h35
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-new-chatroom-dialog.c566
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-new-chatroom-dialog.glade437
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-new-chatroom-dialog.h34
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-new-message-dialog.c164
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-new-message-dialog.glade181
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-new-message-dialog.h33
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-preferences.c990
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-preferences.glade1063
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-preferences.h62
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-presence-chooser.c974
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-presence-chooser.glade200
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-presence-chooser.h57
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-private-chat.c362
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-private-chat.h63
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-profile-chooser.c190
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-profile-chooser.h34
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-smiley-manager.c353
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-smiley-manager.h74
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-spell-dialog.c267
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-spell-dialog.glade205
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-spell-dialog.h39
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-spell.c452
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-spell.h39
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-status-icon.c861
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-status-icon.glade59
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-status-icon.h53
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-theme-boxes.c837
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-theme-boxes.h53
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-theme-irc.c352
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-theme-irc.h53
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-theme-manager.c449
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-theme-manager.h57
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-theme.c417
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-theme.h97
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-ui-utils.c1418
-rw-r--r--gnome-2-22/libempathy-gtk/empathy-ui-utils.h116
-rw-r--r--gnome-2-22/libempathy-gtk/ephy-spinner.c977
-rw-r--r--gnome-2-22/libempathy-gtk/ephy-spinner.h70
-rw-r--r--gnome-2-22/libempathy-gtk/libempathy-gtk.pc.in11
-rw-r--r--gnome-2-22/libempathy-gtk/totem-subtitle-encoding.c585
-rw-r--r--gnome-2-22/libempathy-gtk/totem-subtitle-encoding.h12
110 files changed, 41384 insertions, 0 deletions
diff --git a/gnome-2-22/libempathy-gtk/.gitignore b/gnome-2-22/libempathy-gtk/.gitignore
new file mode 100644
index 000000000..3e3f6f051
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/.gitignore
@@ -0,0 +1,2 @@
+empathy-gtk-marshal.*
+*.gladep
diff --git a/gnome-2-22/libempathy-gtk/Makefile.am b/gnome-2-22/libempathy-gtk/Makefile.am
new file mode 100644
index 000000000..1c1d5eda7
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/Makefile.am
@@ -0,0 +1,211 @@
+AM_CPPFLAGS = \
+ -I. \
+ -I$(top_srcdir) \
+ -DDATADIR=\""$(datadir)"\" \
+ $(EMPATHY_CFLAGS) \
+ $(WARN_CFLAGS)
+
+BUILT_SOURCES = \
+ empathy-gtk-marshal.h \
+ empathy-gtk-marshal.c \
+ empathy-gtk-marshal.list \
+ empathy-gtk-enum-types.h \
+ empathy-gtk-enum-types.c
+
+lib_LTLIBRARIES = libempathy-gtk.la
+
+libempathy_gtk_la_SOURCES = \
+ ephy-spinner.c ephy-spinner.h \
+ empathy-main-window.c \
+ empathy-status-icon.c \
+ empathy-conf.c \
+ empathy-contact-widget.c \
+ empathy-contact-dialogs.c \
+ empathy-accounts-dialog.c \
+ empathy-account-widget.c \
+ empathy-account-widget-irc.c \
+ empathy-profile-chooser.c \
+ empathy-cell-renderer-expander.c \
+ empathy-cell-renderer-text.c \
+ empathy-cell-renderer-activatable.c \
+ empathy-spell.c \
+ empathy-spell-dialog.c \
+ empathy-contact-list-store.c \
+ empathy-contact-list-view.c \
+ empathy-preferences.c \
+ empathy-theme.c \
+ empathy-theme-boxes.c \
+ empathy-theme-irc.c \
+ empathy-theme-manager.c \
+ empathy-smiley-manager.c \
+ empathy-chat-window.c \
+ empathy-chat.c \
+ empathy-chat-view.c \
+ empathy-private-chat.c \
+ empathy-group-chat.c \
+ empathy-geometry.c \
+ empathy-presence-chooser.c \
+ empathy-about-dialog.c \
+ empathy-account-chooser.c \
+ empathy-new-chatroom-dialog.c \
+ empathy-chatrooms-window.c \
+ empathy-log-window.c \
+ empathy-call-window.c \
+ empathy-avatar-chooser.c \
+ empathy-avatar-image.c \
+ empathy-ui-utils.c \
+ empathy-new-message-dialog.c \
+ empathy-irc-network-dialog.c \
+ totem-subtitle-encoding.c totem-subtitle-encoding.h
+
+# do not distribute generated files
+nodist_libempathy_gtk_la_SOURCES =\
+ $(BUILT_SOURCES)
+
+libempathy_gtk_la_LIBADD = \
+ $(EMPATHY_LIBS) \
+ $(top_builddir)/libempathy/libempathy.la
+
+libempathy_gtk_la_LDFLAGS = \
+ -version-info ${LIBEMPATHY_GTK_CURRENT}:${LIBEMPATHY_GTK_REVISION}:${LIBEMPATHY_GTK_AGE} \
+ -export-symbols-regex ^empathy_
+
+libempathy_gtk_headers = \
+ empathy-images.h \
+ empathy-main-window.h \
+ empathy-status-icon.h \
+ empathy-conf.h \
+ empathy-contact-widget.h \
+ empathy-contact-dialogs.h \
+ empathy-accounts-dialog.h \
+ empathy-account-widget.h \
+ empathy-account-widget-irc.h \
+ empathy-profile-chooser.h \
+ empathy-cell-renderer-expander.h \
+ empathy-cell-renderer-text.h \
+ empathy-cell-renderer-activatable.h \
+ empathy-spell.h \
+ empathy-spell-dialog.h \
+ empathy-contact-list-store.h \
+ empathy-contact-list-view.h \
+ empathy-preferences.h \
+ empathy-theme.h \
+ empathy-theme-boxes.h \
+ empathy-theme-irc.h \
+ empathy-theme-manager.h \
+ empathy-smiley-manager.h \
+ empathy-chat-window.h \
+ empathy-chat.h \
+ empathy-chat-view.h \
+ empathy-private-chat.h \
+ empathy-group-chat.h \
+ empathy-geometry.h \
+ empathy-presence-chooser.h \
+ empathy-about-dialog.h \
+ empathy-account-chooser.h \
+ empathy-new-chatroom-dialog.h \
+ empathy-chatrooms-window.h \
+ empathy-log-window.h \
+ empathy-call-window.h \
+ empathy-avatar-chooser.h \
+ empathy-avatar-image.h \
+ empathy-ui-utils.h \
+ empathy-new-message-dialog.h \
+ empathy-irc-network-dialog.h
+
+libempathy_gtk_includedir = $(includedir)/libempathy-gtk/
+libempathy_gtk_include_HEADERS = \
+ $(libempathy_gtk_headers) \
+ empathy-gtk-enum-types.h
+
+gladedir = $(datadir)/empathy
+glade_DATA = \
+ empathy-main-window.glade \
+ empathy-status-icon.glade \
+ empathy-contact-widget.glade \
+ empathy-contact-dialogs.glade \
+ empathy-preferences.glade \
+ empathy-presence-chooser.glade \
+ empathy-accounts-dialog.glade \
+ empathy-account-widget-generic.glade \
+ empathy-account-widget-jabber.glade \
+ empathy-account-widget-msn.glade \
+ empathy-account-widget-sip.glade \
+ empathy-account-widget-salut.glade \
+ empathy-account-widget-irc.glade \
+ empathy-account-widget-icq.glade \
+ empathy-account-widget-yahoo.glade \
+ empathy-new-chatroom-dialog.glade \
+ empathy-group-chat.glade \
+ empathy-chatrooms-window.glade \
+ empathy-spell-dialog.glade \
+ empathy-log-window.glade \
+ empathy-call-window.glade \
+ empathy-chat.glade \
+ empathy-new-message-dialog.glade
+
+empathy-gtk-marshal.list: $(libempathy_gtk_la_SOURCES) Makefile.am
+ ( cd $(srcdir) && \
+ sed -n -e 's/.*empathy_gtk_marshal_\([[:upper:][:digit:]]*__[[:upper:][:digit:]_]*\).*/\1/p' \
+ $(libempathy_gtk_la_SOURCES) ) \
+ | sed -e 's/__/:/' -e 'y/_/,/' | sort -u > $@.tmp
+ if cmp -s $@.tmp $@; then \
+ rm $@.tmp; \
+ else \
+ mv $@.tmp $@; \
+ fi
+
+%-marshal.h: %-marshal.list Makefile
+ $(GLIB_GENMARSHAL) --header --prefix=_$(subst -,_,$*)_marshal $< > $*-marshal.h
+
+%-marshal.c: %-marshal.list Makefile
+ echo "#include \"empathy-gtk-marshal.h\"" > $@ && \
+ $(GLIB_GENMARSHAL) --body --prefix=_$(subst -,_,$*)_marshal $< >> $*-marshal.c
+
+empathy-gtk-enum-types.h: stamp-empathy-gtk-enum-types.h
+ @true
+stamp-empathy-gtk-enum-types.h: Makefile $(libempathy_gtk_headers)
+ (cd $(srcdir) \
+ && glib-mkenums \
+ --fhead "#ifndef __LIBEMPATHY_GTK_ENUM_TYPES_H__\n" \
+ --fhead "#define __LIBEMPATHY_GTK_ENUM_TYPES_H__ 1\n\n" \
+ --fhead "#include <glib-object.h>\n\n" \
+ --fhead "G_BEGIN_DECLS\n\n" \
+ --ftail "G_END_DECLS\n\n" \
+ --ftail "#endif /* __LIBEMPATHY_GTK_ENUM_TYPES_H__ */\n" \
+ --fprod "#include <libempathy-gtk/@filename@>\n" \
+ --eprod "#define EMPATHY_TYPE_@ENUMSHORT@ @enum_name@_get_type()\n" \
+ --eprod "GType @enum_name@_get_type (void);\n" \
+ $(libempathy_gtk_headers) ) > xgen-gth \
+ && (cmp -s xgen-gth empathy-gtk-enum-type.h || cp xgen-gth empathy-gtk-enum-types.h) \
+ && rm -f xgen-gth \
+ && echo timestamp > $(@F)
+
+empathy-gtk-enum-types.c: Makefile $(libempathy_gtk_headers)
+ (cd $(srcdir) \
+ && glib-mkenums \
+ --fhead "#include <config.h>\n" \
+ --fhead "#include <glib-object.h>\n" \
+ --fhead "#include \"empathy-gtk-enum-types.h\"\n\n" \
+ --fprod "\n/* enumerations from \"@filename@\" */" \
+ --vhead "static const G@Type@Value _@enum_name@_values[] = {" \
+ --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \
+ --vtail " { 0, NULL, NULL }\n};\n\n" \
+ --vtail "GType\n@enum_name@_get_type (void)\n{\n" \
+ --vtail " static GType type = 0;\n\n" \
+ --vtail " if (!type)\n" \
+ --vtail " type = g_@type@_register_static (\"@EnumName@\", _@enum_name@_values);\n\n" \
+ --vtail " return type;\n}\n\n" \
+ $(libempathy_gtk_headers) ) > xgen-gtc \
+ && cp xgen-gtc $(@F) \
+ && rm -f xgen-gtc
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libempathy-gtk.pc
+
+EXTRA_DIST = \
+ $(glade_DATA)
+
+CLEANFILES = \
+ $(BUILT_SOURCES) \
+ stamp-empathy-gtk-enum-types.h
diff --git a/gnome-2-22/libempathy-gtk/empathy-about-dialog.c b/gnome-2-22/libempathy-gtk/empathy-about-dialog.c
new file mode 100644
index 000000000..5ecf66749
--- /dev/null
+++ b/gnome-2-22/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-2008 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 <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtkaboutdialog.h>
+#include <gtk/gtksizegroup.h>
+#include <glade/glade.h>
+
+#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 <nisses.mail@home.se>",
+ "Vinicius Depizzol <vdepizzol@gmail.com>",
+ 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/gnome-2-22/libempathy-gtk/empathy-about-dialog.h b/gnome-2-22/libempathy-gtk/empathy-about-dialog.h
new file mode 100644
index 000000000..ff123ab20
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-about-dialog.h
@@ -0,0 +1,36 @@
+/* -*- 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 <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_ABOUT_DIALOG_H__
+#define __EMPATHY_ABOUT_DIALOG_H__
+
+#include <gtk/gtkwindow.h>
+
+G_BEGIN_DECLS
+
+void empathy_about_dialog_new (GtkWindow *parent);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_ABOUT_DIALOG_H__ */
diff --git a/gnome-2-22/libempathy-gtk/empathy-account-chooser.c b/gnome-2-22/libempathy-gtk/empathy-account-chooser.c
new file mode 100644
index 000000000..b6f6542d7
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-account-chooser.c
@@ -0,0 +1,677 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2005-2007 Imendio AB
+ * Copyright (C) 2007-2008 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 <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+
+#include <libtelepathy/tp-conn.h>
+#include <libmissioncontrol/mc-account-monitor.h>
+#include <libmissioncontrol/mission-control.h>
+
+#include <libempathy/empathy-utils.h>
+
+#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 has_all_option;
+ EmpathyAccountChooserFilterFunc filter;
+ gpointer filter_data;
+} 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);
+static void account_chooser_status_changed_cb (MissionControl *mc,
+ TpConnectionStatus status,
+ McPresence presence,
+ TpConnectionStatusReason 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);
+
+enum {
+ PROP_0,
+ 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_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)
+{
+ EmpathyAccountChooserPriv *priv = GET_PRIV (chooser);
+
+ priv->set_active_item = FALSE;
+ priv->filter = NULL;
+ priv->filter_data = NULL;
+}
+
+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_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_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_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, /* Image */
+ 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)
+{
+ GtkListStore *store;
+ GtkComboBox *combobox;
+ GtkTreeIter iter;
+ gint position;
+
+ combobox = GTK_COMBO_BOX (chooser);
+ store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox));
+
+ position = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
+ gtk_list_store_insert_with_values (store, &iter, position,
+ COL_ACCOUNT_POINTER, account,
+ -1);
+ account_chooser_update_iter (chooser, &iter);
+}
+
+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);
+}
+
+typedef struct {
+ McAccount *account;
+ GtkTreeIter *iter;
+ gboolean found;
+} FindAccountData;
+
+static gboolean
+account_chooser_find_account_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ FindAccountData *data = user_data;
+ McAccount *account;
+
+ gtk_tree_model_get (model, iter, COL_ACCOUNT_POINTER, &account, -1);
+
+ if (empathy_account_equal (account, data->account)) {
+ data->found = TRUE;
+ *(data->iter) = *iter;
+ g_object_unref (account);
+
+ return TRUE;
+ }
+
+ g_object_unref (account);
+
+ return FALSE;
+}
+
+static gboolean
+account_chooser_find_account (EmpathyAccountChooser *chooser,
+ McAccount *account,
+ GtkTreeIter *iter)
+{
+ GtkListStore *store;
+ GtkComboBox *combobox;
+ FindAccountData data;
+
+ combobox = GTK_COMBO_BOX (chooser);
+ store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox));
+
+ data.account = account;
+ data.iter = iter;
+ gtk_tree_model_foreach (GTK_TREE_MODEL (store),
+ account_chooser_find_account_foreach,
+ &data);
+
+ return data.found;
+}
+
+static void
+account_chooser_account_remove_foreach (McAccount *account,
+ EmpathyAccountChooser *chooser)
+{
+ GtkListStore *store;
+ GtkComboBox *combobox;
+ GtkTreeIter iter;
+
+ combobox = GTK_COMBO_BOX (chooser);
+ store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox));
+
+ if (account_chooser_find_account (chooser, account, &iter)) {
+ gtk_list_store_remove (store, &iter);
+ }
+}
+
+static void
+account_chooser_update_iter (EmpathyAccountChooser *chooser,
+ GtkTreeIter *iter)
+{
+ EmpathyAccountChooserPriv *priv;
+ GtkListStore *store;
+ GtkComboBox *combobox;
+ McAccount *account;
+ const gchar *icon_name;
+ gboolean is_enabled = TRUE;
+
+ priv = GET_PRIV (chooser);
+
+ combobox = GTK_COMBO_BOX (chooser);
+ store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox));
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+ COL_ACCOUNT_POINTER, &account,
+ -1);
+
+ icon_name = empathy_icon_name_from_account (account);
+ if (priv->filter) {
+ is_enabled = priv->filter (account, priv->filter_data);
+ }
+
+ 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,
+ -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);
+ }
+
+ g_object_unref (account);
+}
+
+static void
+account_chooser_status_changed_cb (MissionControl *mc,
+ TpConnectionStatus status,
+ McPresence presence,
+ TpConnectionStatusReason reason,
+ const gchar *unique_name,
+ EmpathyAccountChooser *chooser)
+{
+ McAccount *account;
+ GtkTreeIter iter;
+
+ account = mc_account_lookup (unique_name);
+ if (account_chooser_find_account (chooser, account, &iter)) {
+ account_chooser_update_iter (chooser, &iter);
+ }
+ g_object_unref (account);
+}
+
+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_filter_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer chooser)
+{
+ account_chooser_update_iter (chooser, iter);
+ return FALSE;
+}
+
+void
+empathy_account_chooser_set_filter (EmpathyAccountChooser *chooser,
+ EmpathyAccountChooserFilterFunc filter,
+ gpointer user_data)
+{
+ EmpathyAccountChooserPriv *priv;
+ GtkTreeModel *model;
+
+ g_return_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser));
+
+ priv = GET_PRIV (chooser);
+
+ priv->filter = filter;
+ priv->filter_data = user_data;
+
+ /* Refilter existing data */
+ priv->set_active_item = FALSE;
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (chooser));
+ gtk_tree_model_foreach (model, account_chooser_filter_foreach, chooser);
+}
+
+gboolean
+empathy_account_chooser_filter_is_connected (McAccount *account,
+ gpointer user_data)
+{
+ MissionControl *mc;
+ TpConnectionStatus status;
+
+ g_return_val_if_fail (MC_IS_ACCOUNT (account), FALSE);
+
+ mc = empathy_mission_control_new ();
+ status = mission_control_get_connection_status (mc, account, NULL);
+ g_object_unref (mc);
+
+ return status == TP_CONNECTION_STATUS_CONNECTED;
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-account-chooser.h b/gnome-2-22/libempathy-gtk/empathy-account-chooser.h
new file mode 100644
index 000000000..528bd83f5
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-account-chooser.h
@@ -0,0 +1,73 @@
+/* -*- 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 <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_ACCOUNT_CHOOSER_H__
+#define __EMPATHY_ACCOUNT_CHOOSER_H__
+
+#include <gtk/gtkcombobox.h>
+
+#include <libmissioncontrol/mc-account.h>
+
+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 gboolean (* EmpathyAccountChooserFilterFunc) (McAccount *account,
+ gpointer user_data);
+
+
+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_has_all_option (EmpathyAccountChooser *chooser);
+void empathy_account_chooser_set_has_all_option (EmpathyAccountChooser *chooser,
+ gboolean has_all_option);
+void empathy_account_chooser_set_filter (EmpathyAccountChooser *chooser,
+ EmpathyAccountChooserFilterFunc filter,
+ gpointer user_data);
+gboolean empathy_account_chooser_filter_is_connected(McAccount *account,
+ gpointer user_data);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_ACCOUNT_CHOOSER_H__ */
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-account-widget-generic.glade b/gnome-2-22/libempathy-gtk/empathy-account-widget-generic.glade
new file mode 100644
index 000000000..5278e0a2b
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-account-widget-generic.glade
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+ <widget class="GtkWindow" id="account_generic_settings">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">generic account settings</property>
+ <property name="resizable">False</property>
+ <child>
+ <widget class="GtkVBox" id="vbox_generic_settings">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <widget class="GtkTable" id="table_common_settings">
+ <property name="visible">True</property>
+ <property name="n_columns">3</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkExpander" id="expander1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkViewport" id="viewport1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="resize_mode">GTK_RESIZE_QUEUE</property>
+ <child>
+ <widget class="GtkTable" id="table_advanced_settings">
+ <property name="visible">True</property>
+ <property name="n_columns">3</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Advanced&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-account-widget-icq.glade b/gnome-2-22/libempathy-gtk/empathy-account-widget-icq.glade
new file mode 100644
index 000000000..235587bd8
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-account-widget-icq.glade
@@ -0,0 +1,375 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="account_icq_settings">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">ICQ account settings</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">False</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox_icq_settings">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkTable" id="table_common_settings">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkEntry" id="entry_password">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">False</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_uin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button_forget">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Forget password and clear the entry.</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkImage" id="image834">
+ <property name="visible">True</property>
+ <property name="stock">gtk-clear</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_uin">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">ICQ _UIN:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_uin</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_password">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Pass_word:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_password</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkExpander" id="expander1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="expanded">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkTable" id="table_advanced_settings">
+ <property name="visible">True</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkEntry" id="entry_charset">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_server">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Server:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_server</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_port">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Port:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">spinbutton_port</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_server">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="spinbutton_port">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">5222 0 65556 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_charset">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Charset:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_charset</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Advanced&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-account-widget-irc.c b/gnome-2-22/libempathy-gtk/empathy-account-widget-irc.c
new file mode 100644
index 000000000..5c74e0958
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-account-widget-irc.c
@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2007-2008 Guillaume Desmottes
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Guillaume Desmottes <gdesmott@gnome.org>
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+
+#include <libmissioncontrol/mc-account.h>
+#include <libmissioncontrol/mc-protocol.h>
+
+#include <libempathy/empathy-utils.h>
+#include <libempathy/empathy-debug.h>
+#include <libempathy/empathy-irc-network-manager.h>
+
+#include "empathy-irc-network-dialog.h"
+#include "empathy-account-widget.h"
+#include "empathy-account-widget-irc.h"
+#include "empathy-ui-utils.h"
+
+#define DEBUG_DOMAIN "AccountWidgetIRC"
+
+#define IRC_NETWORKS_FILENAME "irc-networks.xml"
+
+typedef struct {
+ McAccount *account;
+ EmpathyIrcNetworkManager *network_manager;
+
+ GtkWidget *vbox_settings;
+
+ GtkWidget *combobox_network;
+ GtkWidget *button_add_network;
+ GtkWidget *button_network;
+ GtkWidget *button_remove;
+} EmpathyAccountWidgetIrc;
+
+enum {
+ COL_NETWORK_OBJ,
+ COL_NETWORK_NAME,
+};
+
+static void
+account_widget_irc_destroy_cb (GtkWidget *widget,
+ EmpathyAccountWidgetIrc *settings)
+{
+ g_object_unref (settings->network_manager);
+ g_object_unref (settings->account);
+ g_slice_free (EmpathyAccountWidgetIrc, settings);
+}
+
+static void
+unset_server_params (EmpathyAccountWidgetIrc *settings)
+{
+ empathy_debug (DEBUG_DOMAIN, "Unset server, port and use-ssl");
+ mc_account_unset_param (settings->account, "server");
+ mc_account_unset_param (settings->account, "port");
+ mc_account_unset_param (settings->account, "use-ssl");
+}
+
+static void
+update_server_params (EmpathyAccountWidgetIrc *settings)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ EmpathyIrcNetwork *network;
+ GSList *servers;
+ gchar *charset;
+
+ if (!gtk_combo_box_get_active_iter (
+ GTK_COMBO_BOX (settings->combobox_network), &iter))
+ {
+ unset_server_params (settings);
+ return;
+ }
+
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (settings->combobox_network));
+ gtk_tree_model_get (model, &iter, COL_NETWORK_OBJ, &network, -1);
+
+ g_assert (network != NULL);
+
+ g_object_get (network, "charset", &charset, NULL);
+ empathy_debug (DEBUG_DOMAIN, "Setting charset to %s", charset);
+ mc_account_set_param_string (settings->account, "charset", charset);
+ g_free (charset);
+
+ servers = empathy_irc_network_get_servers (network);
+ if (g_slist_length (servers) > 0)
+ {
+ /* set the first server as CM server */
+ EmpathyIrcServer *server = servers->data;
+ gchar *address;
+ guint port;
+ gboolean ssl;
+
+ g_object_get (server,
+ "address", &address,
+ "port", &port,
+ "ssl", &ssl,
+ NULL);
+
+ empathy_debug (DEBUG_DOMAIN, "Setting server to %s", address);
+ mc_account_set_param_string (settings->account, "server", address);
+ empathy_debug (DEBUG_DOMAIN, "Setting port to %u", port);
+ mc_account_set_param_int (settings->account, "port", port);
+ empathy_debug (DEBUG_DOMAIN, "Setting use-ssl to %s",
+ ssl ? "TRUE": "FALSE" );
+ mc_account_set_param_boolean (settings->account, "use-ssl", ssl);
+
+ g_free (address);
+ }
+ else
+ {
+ /* No server. Unset values */
+ unset_server_params (settings);
+ }
+
+ g_slist_foreach (servers, (GFunc) g_object_unref, NULL);
+ g_slist_free (servers);
+ g_object_unref (network);
+}
+
+static void
+irc_network_dialog_destroy_cb (GtkWidget *widget,
+ EmpathyAccountWidgetIrc *settings)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ EmpathyIrcNetwork *network;
+ gchar *name;
+
+ /* name could be changed */
+ gtk_combo_box_get_active_iter (GTK_COMBO_BOX (settings->combobox_network),
+ &iter);
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (settings->combobox_network));
+ gtk_tree_model_get (model, &iter, COL_NETWORK_OBJ, &network, -1);
+
+ g_object_get (network, "name", &name, NULL);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+ COL_NETWORK_NAME, name, -1);
+
+ update_server_params (settings);
+
+ g_object_unref (network);
+ g_free (name);
+}
+
+static void
+display_irc_network_dialog (EmpathyAccountWidgetIrc *settings,
+ EmpathyIrcNetwork *network)
+{
+ GtkWindow *window;
+ GtkWidget *dialog;
+
+ window = empathy_get_toplevel_window (settings->vbox_settings);
+ dialog = empathy_irc_network_dialog_show (network, GTK_WIDGET (window));
+ g_signal_connect (dialog, "destroy",
+ G_CALLBACK (irc_network_dialog_destroy_cb), settings);
+}
+
+static void
+account_widget_irc_button_edit_network_clicked_cb (
+ GtkWidget *button,
+ EmpathyAccountWidgetIrc *settings)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ EmpathyIrcNetwork *network;
+
+ gtk_combo_box_get_active_iter (GTK_COMBO_BOX (settings->combobox_network),
+ &iter);
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (settings->combobox_network));
+ gtk_tree_model_get (model, &iter, COL_NETWORK_OBJ, &network, -1);
+
+ g_assert (network != NULL);
+
+ display_irc_network_dialog (settings, network);
+
+ g_object_unref (network);
+}
+
+static void
+account_widget_irc_button_remove_clicked_cb (GtkWidget *button,
+ EmpathyAccountWidgetIrc *settings)
+{
+ EmpathyIrcNetwork *network;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ gchar *name;
+
+ gtk_combo_box_get_active_iter (GTK_COMBO_BOX (settings->combobox_network),
+ &iter);
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (settings->combobox_network));
+ gtk_tree_model_get (model, &iter, COL_NETWORK_OBJ, &network, -1);
+
+ g_assert (network != NULL);
+
+ g_object_get (network, "name", &name, NULL);
+ empathy_debug (DEBUG_DOMAIN, "Remove network %s", name);
+
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+ empathy_irc_network_manager_remove (settings->network_manager, network);
+
+ /* Select the first network */
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ {
+ gtk_combo_box_set_active_iter (
+ GTK_COMBO_BOX (settings->combobox_network), &iter);
+ }
+
+ g_free (name);
+ g_object_unref (network);
+}
+
+static void
+account_widget_irc_button_add_network_clicked_cb (GtkWidget *button,
+ EmpathyAccountWidgetIrc *settings)
+{
+ EmpathyIrcNetwork *network;
+ GtkTreeModel *model;
+ GtkListStore *store;
+ gchar *name;
+ GtkTreeIter iter;
+
+ network = empathy_irc_network_new (_("New Network"));
+ empathy_irc_network_manager_add (settings->network_manager, network);
+
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (settings->combobox_network));
+ store = GTK_LIST_STORE (model);
+
+ g_object_get (network, "name", &name, NULL);
+
+ gtk_list_store_insert_with_values (store, &iter, -1,
+ COL_NETWORK_OBJ, network,
+ COL_NETWORK_NAME, name,
+ -1);
+
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (settings->combobox_network),
+ &iter);
+
+ display_irc_network_dialog (settings, network);
+
+ g_free (name);
+ g_object_unref (network);
+}
+
+static void
+account_widget_irc_combobox_network_changed_cb (GtkWidget *combobox,
+ EmpathyAccountWidgetIrc *settings)
+{
+ update_server_params (settings);
+}
+
+static void
+fill_networks_model (EmpathyAccountWidgetIrc *settings,
+ EmpathyIrcNetwork *network_to_select)
+{
+ GSList *networks, *l;
+ GtkTreeModel *model;
+ GtkListStore *store;
+
+ networks = empathy_irc_network_manager_get_networks (
+ settings->network_manager);
+
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (settings->combobox_network));
+ store = GTK_LIST_STORE (model);
+
+ for (l = networks; l != NULL; l = g_slist_next (l))
+ {
+ gchar *name;
+ EmpathyIrcNetwork *network = l->data;
+ GtkTreeIter iter;
+
+ g_object_get (network, "name", &name, NULL);
+
+ gtk_list_store_insert_with_values (store, &iter, -1,
+ COL_NETWORK_OBJ, network,
+ COL_NETWORK_NAME, name,
+ -1);
+
+ if (network == network_to_select)
+ {
+ gtk_combo_box_set_active_iter (
+ GTK_COMBO_BOX (settings->combobox_network), &iter);
+ }
+
+ g_free (name);
+ g_object_unref (network);
+ }
+
+ if (network_to_select == NULL)
+ {
+ /* Select the first network */
+ GtkTreeIter iter;
+
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ {
+ gtk_combo_box_set_active_iter (
+ GTK_COMBO_BOX (settings->combobox_network), &iter);
+
+ update_server_params (settings);
+ }
+ }
+
+ g_slist_free (networks);
+}
+
+static void
+account_widget_irc_setup (EmpathyAccountWidgetIrc *settings)
+{
+ gchar *nick = NULL;
+ gchar *fullname = NULL;
+ gchar *server = NULL;
+ gint port = 6667;
+ gchar *charset;
+ gboolean ssl = FALSE;
+ EmpathyIrcNetwork *network = NULL;
+
+ mc_account_get_param_string (settings->account, "account", &nick);
+ mc_account_get_param_string (settings->account, "fullname", &fullname);
+ mc_account_get_param_string (settings->account, "server", &server);
+ mc_account_get_param_string (settings->account, "charset", &charset);
+ mc_account_get_param_int (settings->account, "port", &port);
+ mc_account_get_param_boolean (settings->account, "use-ssl", &ssl);
+
+ if (!nick)
+ {
+ nick = g_strdup (g_get_user_name ());
+ mc_account_set_param_string (settings->account, "account", nick);
+ }
+
+ if (!fullname)
+ {
+ fullname = g_strdup (g_get_real_name ());
+ if (!fullname)
+ {
+ fullname = g_strdup (nick);
+ }
+ mc_account_set_param_string (settings->account, "fullname", fullname);
+ }
+
+ if (server != NULL)
+ {
+ GtkListStore *store;
+
+ network = empathy_irc_network_manager_find_network_by_address (
+ settings->network_manager, server);
+
+
+ store = GTK_LIST_STORE (gtk_combo_box_get_model (
+ GTK_COMBO_BOX (settings->combobox_network)));
+
+ if (network != NULL)
+ {
+ gchar *name;
+
+ g_object_set (network, "charset", charset, NULL);
+
+ g_object_get (network, "name", &name, NULL);
+ empathy_debug (DEBUG_DOMAIN, "Account use network %s", name);
+
+ g_free (name);
+ }
+ else
+ {
+ /* We don't have this network. Let's create it */
+ EmpathyIrcServer *srv;
+ GtkTreeIter iter;
+
+ empathy_debug (DEBUG_DOMAIN, "Create a network %s", server);
+ network = empathy_irc_network_new (server);
+ srv = empathy_irc_server_new (server, port, ssl);
+
+ empathy_irc_network_append_server (network, srv);
+ empathy_irc_network_manager_add (settings->network_manager, network);
+
+ gtk_list_store_insert_with_values (store, &iter, -1,
+ COL_NETWORK_OBJ, network,
+ COL_NETWORK_NAME, server,
+ -1);
+
+ gtk_combo_box_set_active_iter (
+ GTK_COMBO_BOX (settings->combobox_network), &iter);
+
+ g_object_unref (srv);
+ g_object_unref (network);
+ }
+ }
+
+
+ fill_networks_model (settings, network);
+
+ g_free (nick);
+ g_free (fullname);
+ g_free (server);
+ g_free (charset);
+}
+
+/**
+ * empathy_account_widget_irc_new:
+ * @account: the #McAccount to configure
+ *
+ * Creates a new IRC account widget to configure a given #McAccount
+ *
+ * Returns: The toplevel container of the configuration widget
+ */
+GtkWidget *
+empathy_account_widget_irc_new (McAccount *account)
+{
+ EmpathyAccountWidgetIrc *settings;
+ gchar *dir, *user_file_with_path, *global_file_with_path;
+ GladeXML *glade;
+ GtkListStore *store;
+ GtkCellRenderer *renderer;
+
+ settings = g_slice_new0 (EmpathyAccountWidgetIrc);
+ settings->account = g_object_ref (account);
+
+ dir = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, NULL);
+ g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR);
+ user_file_with_path = g_build_filename (dir, IRC_NETWORKS_FILENAME, NULL);
+ g_free (dir);
+
+ global_file_with_path = g_build_filename (g_getenv ("EMPATHY_SRCDIR"),
+ "libempathy-gtk", IRC_NETWORKS_FILENAME, NULL);
+ if (!g_file_test (global_file_with_path, G_FILE_TEST_EXISTS))
+ {
+ g_free (global_file_with_path);
+ global_file_with_path = g_build_filename (DATADIR, "empathy",
+ IRC_NETWORKS_FILENAME, NULL);
+ }
+
+ settings->network_manager = empathy_irc_network_manager_new (
+ global_file_with_path,
+ user_file_with_path);
+
+ g_free (global_file_with_path);
+ g_free (user_file_with_path);
+
+ glade = empathy_glade_get_file ("empathy-account-widget-irc.glade",
+ "vbox_irc_settings",
+ NULL,
+ "vbox_irc_settings", &settings->vbox_settings,
+ "combobox_network", &settings->combobox_network,
+ "button_network", &settings->button_network,
+ "button_add_network", &settings->button_add_network,
+ "button_remove", &settings->button_remove,
+ NULL);
+
+ /* Fill the networks combobox */
+ store = gtk_list_store_new (2, G_TYPE_OBJECT, G_TYPE_STRING);
+
+ gtk_cell_layout_clear (GTK_CELL_LAYOUT (settings->combobox_network));
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (settings->combobox_network),
+ renderer, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (settings->combobox_network),
+ renderer,
+ "text", COL_NETWORK_NAME,
+ NULL);
+
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+ COL_NETWORK_NAME,
+ GTK_SORT_ASCENDING);
+
+ gtk_combo_box_set_model (GTK_COMBO_BOX (settings->combobox_network),
+ GTK_TREE_MODEL (store));
+ g_object_unref (store);
+
+ account_widget_irc_setup (settings);
+
+ empathy_account_widget_handle_params (account, glade,
+ "entry_nick", "account",
+ "entry_fullname", "fullname",
+ "entry_password", "password",
+ "entry_quit_message", "quit-message",
+ NULL);
+
+ empathy_glade_connect (glade, settings,
+ "vbox_irc_settings", "destroy", account_widget_irc_destroy_cb,
+ "button_network", "clicked", account_widget_irc_button_edit_network_clicked_cb,
+ "button_add_network", "clicked", account_widget_irc_button_add_network_clicked_cb,
+ "button_remove", "clicked", account_widget_irc_button_remove_clicked_cb,
+ "combobox_network", "changed", account_widget_irc_combobox_network_changed_cb,
+ NULL);
+
+ g_object_unref (glade);
+
+ return settings->vbox_settings;
+}
diff --git a/gnome-2-22/libempathy-gtk/empathy-account-widget-irc.glade b/gnome-2-22/libempathy-gtk/empathy-account-widget-irc.glade
new file mode 100644
index 000000000..14c757ce8
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-account-widget-irc.glade
@@ -0,0 +1,451 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.0 on Sun Feb 17 01:08:25 2008 -->
+<glade-interface>
+ <widget class="GtkWindow" id="account_irc_settings">
+ <property name="title" translatable="yes">irc account settings</property>
+ <property name="resizable">False</property>
+ <child>
+ <widget class="GtkTable" id="vbox_irc_settings">
+ <property name="visible">True</property>
+ <property name="n_rows">5</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <widget class="GtkLabel" id="label_network">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Network:</property>
+ <property name="use_underline">True</property>
+ </widget>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox174">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <widget class="GtkComboBox" id="combobox_network">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes"></property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="button_add_network">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip" translatable="yes">Create a new IRC network</property>
+ <property name="response_id">0</property>
+ <child>
+ <widget class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="stock">gtk-add</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="button_network">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip" translatable="yes">Edit the selected IRC network</property>
+ <property name="response_id">0</property>
+ <child>
+ <widget class="GtkImage" id="image834">
+ <property name="visible">True</property>
+ <property name="stock">gtk-edit</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="button_remove">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip" translatable="yes">Remove the selected IRC network</property>
+ <property name="response_id">0</property>
+ <child>
+ <widget class="GtkImage" id="image835">
+ <property name="visible">True</property>
+ <property name="stock">gtk-remove</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label_nick">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Nickname:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">entry_nick</property>
+ </widget>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="entry_nick">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">*</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label_fullname">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Real name:</property>
+ </widget>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label_password">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Password:</property>
+ </widget>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="entry_password">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="visibility">False</property>
+ <property name="invisible_char">*</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="entry_fullname">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label_quit_message">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Quit message:</property>
+ </widget>
+ <packing>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="entry_quit_message">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <widget class="GtkDialog" id="irc_network_dialog">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Network</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="icon_name">gtk-edit</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="skip_taskbar_hint">True</property>
+ <property name="skip_pager_hint">True</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox10">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <widget class="GtkFrame" id="frame14">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment28">
+ <property name="visible">True</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <widget class="GtkTable" id="table14">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <widget class="GtkComboBox" id="combobox_charset">
+ <property name="visible">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="entry_network">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label_charset">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Charset:</property>
+ </widget>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label_network">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Network:</property>
+ </widget>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label_network">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Network&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkFrame" id="frame15">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment29">
+ <property name="visible">True</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <widget class="GtkTable" id="table15">
+ <property name="visible">True</property>
+ <property name="n_rows">1</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">6</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <widget class="GtkVButtonBox" id="vbuttonbox1">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <property name="layout_style">GTK_BUTTONBOX_START</property>
+ <child>
+ <widget class="GtkButton" id="button_add">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="label">gtk-add</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="button_remove">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="label">gtk-remove</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="button_up">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="label">gtk-go-up</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="button_down">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="label">gtk-go-down</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ </widget>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow19">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkTreeView" id="treeview_servers">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="enable_search">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label_servers">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Servers&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area10">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <child>
+ <widget class="GtkButton" id="button_close">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">-7</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-account-widget-irc.h b/gnome-2-22/libempathy-gtk/empathy-account-widget-irc.h
new file mode 100644
index 000000000..6ead048eb
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-account-widget-irc.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007-2008 Guillaume Desmottes
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Guillaume Desmottes <gdesmott@gnome.org>
+ */
+
+#ifndef __EMPATHY_ACCOUNT_WIDGET_IRC_H__
+#define __EMPATHY_ACCOUNT_WIDGET_IRC_H__
+
+#include <gtk/gtkwidget.h>
+#include <libmissioncontrol/mc-account.h>
+
+G_BEGIN_DECLS
+
+GtkWidget * empathy_account_widget_irc_new (McAccount *account);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_ACCOUNT_WIDGET_IRC_H__ */
diff --git a/gnome-2-22/libempathy-gtk/empathy-account-widget-jabber.glade b/gnome-2-22/libempathy-gtk/empathy-account-widget-jabber.glade
new file mode 100644
index 000000000..d691d1418
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-account-widget-jabber.glade
@@ -0,0 +1,566 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="account_jabber_settings">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">jabber account settings</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">False</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox_jabber_settings">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkTable" id="table_common_settings">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label_password">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Pass_word:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_password</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button_forget">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Forget password and clear the entry.</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkImage" id="image834">
+ <property name="visible">True</property>
+ <property name="stock">gtk-clear</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_id">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Login I_D:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_id</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_id">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_password">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">False</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkExpander" id="expander1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="expanded">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkTable" id="table_advanced_settings">
+ <property name="visible">True</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton_encryption">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Encryption required (TLS/SSL)</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_resource">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Reso_urce:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_resource</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_priority">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Pri_ority:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">spinbutton_priority</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton_ignore_ssl_errors">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Ignore SSL certificate errors</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="spinbutton_priority">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">False</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">0 -128 127 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_resource">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label_server">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Server:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_server</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_port">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Port:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">spinbutton_port</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton_ssl">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Use old SS_L</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_server">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="spinbutton_port">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">5222 0 65556 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Override server settings&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Advanced&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-account-widget-msn.glade b/gnome-2-22/libempathy-gtk/empathy-account-widget-msn.glade
new file mode 100644
index 000000000..b7b91c5a9
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-account-widget-msn.glade
@@ -0,0 +1,335 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="account_msn_settings">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">msn account settings</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">False</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox_msn_settings">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkTable" id="table_common_msn_settings">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkEntry" id="entry_id">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">●</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_id">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Login I_D:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_id</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_password">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Pass_word:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkEntry" id="entry_password">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">False</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">●</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button_forget">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Forget password and clear the entry.</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-clear</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkExpander" id="expander1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="expanded">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkTable" id="table_advanced_msn_settings">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkSpinButton" id="spinbutton_port">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">0 0 65536 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_server">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">●</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_server">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Server:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_server</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_port">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Port:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">spinbutton_port</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Advanced&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-account-widget-salut.glade b/gnome-2-22/libempathy-gtk/empathy-account-widget-salut.glade
new file mode 100644
index 000000000..ab725c6ff
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-account-widget-salut.glade
@@ -0,0 +1,396 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="account_salut_settings">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">salut account settings</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">False</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox_salut_settings">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkTable" id="table_common_settings">
+ <property name="visible">True</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label_first_name">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_First Name: </property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_first_name</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_last_name">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Last Name:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_last_name</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_nickname">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Nickname:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_nickname</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_first_name">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_last_name">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_nickname">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkExpander" id="expander1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="expanded">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkTable" id="table_advanced_settings">
+ <property name="visible">True</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label_email">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_E-mail:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_email</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_jid">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Jabber ID:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_jid</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_email">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_jid">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_published">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Published Name:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_published</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_published">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Advanced&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-account-widget-yahoo.glade b/gnome-2-22/libempathy-gtk/empathy-account-widget-yahoo.glade
new file mode 100644
index 000000000..4d0bcc113
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-account-widget-yahoo.glade
@@ -0,0 +1,526 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="account_yahoo_settings">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Yahoo! account settings</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">False</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox_yahoo_settings">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkTable" id="table_common_settings">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label_password">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Pass_word:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_password</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button_forget">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Forget password and clear the entry.</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkImage" id="image834">
+ <property name="visible">True</property>
+ <property name="stock">gtk-clear</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_id">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Login I_D:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_id</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_id">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_password">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">False</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkExpander" id="expander1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="expanded">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkTable" id="table_advanced_settings">
+ <property name="visible">True</property>
+ <property name="n_rows">7</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton_ignore_invites">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Ignore conference and chatroom invitations</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_locale">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Room List locale:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_locale</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_charset">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Charset:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_charset</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_locale">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_charset">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_server">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Server:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_server</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_port">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Port:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">spinbutton_port</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_server">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="spinbutton_port">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">5050 1 65556 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_serverjp">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">J_apan server:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_serverjp</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">6</property>
+ <property name="bottom_attach">7</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_serverjp">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">6</property>
+ <property name="bottom_attach">7</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton_yahoojp">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Use _Yahoo Japan</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Advanced&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-account-widget.c b/gnome-2-22/libempathy-gtk/empathy-account-widget.c
new file mode 100644
index 000000000..9596a1859
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-account-widget.c
@@ -0,0 +1,680 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006-2007 Imendio AB
+ * Copyright (C) 2007-2008 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 <xclaesse@gmail.com>
+ * Martyn Russell <martyn@imendio.com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include <libmissioncontrol/mc-account.h>
+#include <libmissioncontrol/mc-protocol.h>
+
+#include <libempathy/empathy-debug.h>
+
+#include "empathy-account-widget.h"
+#include "empathy-ui-utils.h"
+
+#define DEBUG_DOMAIN "AccountWidget"
+
+static gboolean
+account_widget_entry_focus_cb (GtkWidget *widget,
+ GdkEventFocus *event,
+ McAccount *account)
+{
+ 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");
+
+ if (G_STR_EMPTY (str)) {
+ gchar *value = NULL;
+
+ mc_account_unset_param (account, param_name);
+ mc_account_get_param_string (account, param_name, &value);
+ empathy_debug (DEBUG_DOMAIN, "Unset %s and restore to %s", param_name, value);
+ gtk_entry_set_text (GTK_ENTRY (widget), value ? value : "");
+ g_free (value);
+ } else {
+ empathy_debug (DEBUG_DOMAIN, "Setting %s to %s", param_name, str);
+ mc_account_set_param_string (account, param_name, str);
+ }
+
+ return FALSE;
+}
+
+static void
+account_widget_int_changed_cb (GtkWidget *widget,
+ McAccount *account)
+{
+ const gchar *param_name;
+ gint value;
+
+ value = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
+ param_name = g_object_get_data (G_OBJECT (widget), "param_name");
+
+ if (value == 0) {
+ mc_account_unset_param (account, param_name);
+ mc_account_get_param_int (account, param_name, &value);
+ empathy_debug (DEBUG_DOMAIN, "Unset %s and restore to %d", param_name, value);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+ } else {
+ empathy_debug (DEBUG_DOMAIN, "Setting %s to %d", param_name, value);
+ mc_account_set_param_int (account, param_name, value);
+ }
+}
+
+static void
+account_widget_checkbutton_toggled_cb (GtkWidget *widget,
+ McAccount *account)
+{
+ gboolean value;
+ gboolean default_value;
+ const gchar *param_name;
+
+ value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+ param_name = g_object_get_data (G_OBJECT (widget), "param_name");
+
+ /* FIXME: This is ugly! checkbox don't have a "not-set" value so we
+ * always unset the param and set the value if different from the
+ * default value. */
+ mc_account_unset_param (account, param_name);
+ mc_account_get_param_boolean (account, param_name, &default_value);
+
+ if (default_value == value) {
+ empathy_debug (DEBUG_DOMAIN, "Unset %s and restore to %d", param_name, default_value);
+ } else {
+ empathy_debug (DEBUG_DOMAIN, "Setting %s to %d", param_name, value);
+ mc_account_set_param_boolean (account, param_name, value);
+ }
+}
+
+static void
+account_widget_forget_clicked_cb (GtkWidget *button,
+ GtkWidget *entry)
+{
+ McAccount *account;
+ const gchar *param_name;
+
+ param_name = g_object_get_data (G_OBJECT (entry), "param_name");
+ account = g_object_get_data (G_OBJECT (entry), "account");
+
+ empathy_debug (DEBUG_DOMAIN, "Unset %s", param_name);
+ mc_account_unset_param (account, param_name);
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
+}
+
+static void
+account_widget_password_changed_cb (GtkWidget *entry,
+ GtkWidget *button)
+{
+ const gchar *str;
+
+ str = gtk_entry_get_text (GTK_ENTRY (entry));
+ gtk_widget_set_sensitive (button, !G_STR_EMPTY (str));
+}
+
+static void
+account_widget_jabber_ssl_toggled_cb (GtkWidget *checkbutton_ssl,
+ GtkWidget *spinbutton_port)
+{
+ McAccount *account;
+ gboolean value;
+ gint port = 0;
+
+ value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton_ssl));
+ account = g_object_get_data (G_OBJECT (spinbutton_port), "account");
+ mc_account_get_param_int (account, "port", &port);
+
+ if (value) {
+ if (port == 5222 || port == 0) {
+ port = 5223;
+ }
+ } else {
+ if (port == 5223 || port == 0) {
+ port = 5222;
+ }
+ }
+
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (spinbutton_port), port);
+}
+
+static void
+account_widget_setup_widget (GtkWidget *widget,
+ McAccount *account,
+ const gchar *param_name)
+{
+ g_object_set_data_full (G_OBJECT (widget), "param_name",
+ g_strdup (param_name), g_free);
+ g_object_set_data_full (G_OBJECT (widget), "account",
+ g_object_ref (account), g_object_unref);
+
+ if (GTK_IS_SPIN_BUTTON (widget)) {
+ gint value = 0;
+
+ mc_account_get_param_int (account, param_name, &value);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+ g_signal_connect (widget, "value-changed",
+ G_CALLBACK (account_widget_int_changed_cb),
+ account);
+ }
+ else if (GTK_IS_ENTRY (widget)) {
+ gchar *str = NULL;
+
+ mc_account_get_param_string (account, param_name, &str);
+ gtk_entry_set_text (GTK_ENTRY (widget), str ? 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_entry_focus_cb),
+ account);
+ }
+ else if (GTK_IS_TOGGLE_BUTTON (widget)) {
+ gboolean value = FALSE;
+
+ mc_account_get_param_boolean (account, param_name, &value);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), value);
+
+ g_signal_connect (widget, "toggled",
+ G_CALLBACK (account_widget_checkbutton_toggled_cb),
+ account);
+ } else {
+ empathy_debug (DEBUG_DOMAIN,
+ "Unknown type of widget for param %s",
+ param_name);
+ }
+}
+
+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
+accounts_widget_generic_setup (McAccount *account,
+ GtkWidget *table_common_settings,
+ GtkWidget *table_advanced_settings)
+{
+ McProtocol *protocol;
+ McProfile *profile;
+ GSList *params, *l;
+
+ profile = mc_account_get_profile (account);
+ protocol = mc_profile_get_protocol (profile);
+
+ if (!protocol) {
+ /* The CM is not installed, MC shouldn't list them
+ * see SF bug #1688779
+ * FIXME: We should display something asking the user to
+ * install the CM
+ */
+ g_object_unref (profile);
+ return;
+ }
+
+ params = mc_protocol_get_params (protocol);
+
+ for (l = params; l; l = l->next) {
+ McProtocolParam *param;
+ GtkWidget *table_settings;
+ guint n_rows = 0;
+ GtkWidget *widget = NULL;
+ gchar *param_name_formatted;
+
+ param = l->data;
+ if (param->flags & MC_PROTOCOL_PARAM_REQUIRED) {
+ table_settings = table_common_settings;
+ } else {
+ table_settings = table_advanced_settings;
+ }
+ param_name_formatted = account_widget_generic_format_param_name (param->name);
+ g_object_get (table_settings, "n-rows", &n_rows, NULL);
+ gtk_table_resize (GTK_TABLE (table_settings), ++n_rows, 2);
+
+ if (param->signature[0] == 's') {
+ gchar *str;
+
+ str = g_strdup_printf (_("%s:"), param_name_formatted);
+ widget = gtk_label_new (str);
+ gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
+ g_free (str);
+
+ gtk_table_attach (GTK_TABLE (table_settings),
+ widget,
+ 0, 1,
+ n_rows - 1, n_rows,
+ GTK_FILL, 0,
+ 0, 0);
+
+ widget = gtk_entry_new ();
+ gtk_table_attach (GTK_TABLE (table_settings),
+ widget,
+ 1, 2,
+ n_rows - 1, n_rows,
+ GTK_FILL | GTK_EXPAND, 0,
+ 0, 0);
+ }
+ /* int types: ynqiuxt. double type is 'd' */
+ else if (param->signature[0] == 'y' ||
+ param->signature[0] == 'n' ||
+ param->signature[0] == 'q' ||
+ param->signature[0] == 'i' ||
+ param->signature[0] == 'u' ||
+ param->signature[0] == 'x' ||
+ param->signature[0] == 't' ||
+ param->signature[0] == 'd') {
+ gchar *str = NULL;
+ gdouble minint = 0;
+ gdouble maxint = 0;
+ gdouble step = 1;
+
+ switch (param->signature[0]) {
+ case 'y': minint = G_MININT8; maxint = G_MAXINT8; break;
+ case 'n': minint = G_MININT16; maxint = G_MAXINT16; break;
+ case 'q': minint = 0; maxint = G_MAXUINT16; break;
+ case 'i': minint = G_MININT32; maxint = G_MAXINT32; break;
+ case 'u': minint = 0; maxint = G_MAXUINT32; break;
+ case 'x': minint = G_MININT64; maxint = G_MAXINT64; break;
+ case 't': minint = 0; maxint = G_MAXUINT64; break;
+ case 'd': minint = G_MININT32; maxint = G_MAXINT32; step = 0.1; break;
+ }
+
+ str = g_strdup_printf (_("%s:"), param_name_formatted);
+ widget = gtk_label_new (str);
+ gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
+ g_free (str);
+
+ gtk_table_attach (GTK_TABLE (table_settings),
+ widget,
+ 0, 1,
+ n_rows - 1, n_rows,
+ GTK_FILL, 0,
+ 0, 0);
+
+ widget = gtk_spin_button_new_with_range (minint, maxint, step);
+ gtk_table_attach (GTK_TABLE (table_settings),
+ widget,
+ 1, 2,
+ n_rows - 1, n_rows,
+ GTK_FILL | GTK_EXPAND, 0,
+ 0, 0);
+ }
+ else if (param->signature[0] == 'b') {
+ widget = gtk_check_button_new_with_label (param_name_formatted);
+ gtk_table_attach (GTK_TABLE (table_settings),
+ widget,
+ 0, 2,
+ n_rows - 1, n_rows,
+ GTK_FILL | GTK_EXPAND, 0,
+ 0, 0);
+ } else {
+ empathy_debug (DEBUG_DOMAIN,
+ "Unknown signature for param %s: %s",
+ param_name_formatted, param->signature);
+ }
+
+ if (widget) {
+ account_widget_setup_widget (widget, account, param->name);
+ }
+
+ g_free (param_name_formatted);
+ }
+
+ g_slist_free (params);
+ g_object_unref (profile);
+ g_object_unref (protocol);
+}
+
+static void
+account_widget_handle_params_valist (McAccount *account,
+ GladeXML *gui,
+ const gchar *first_widget_name,
+ va_list args)
+{
+ GtkWidget *widget;
+ const gchar *widget_name;
+
+ for (widget_name = first_widget_name; widget_name; widget_name = va_arg (args, gchar*)) {
+ const gchar *param_name;
+
+ param_name = va_arg (args, gchar*);
+
+ widget = glade_xml_get_widget (gui, widget_name);
+
+ if (!widget) {
+ g_warning ("Glade is missing widget '%s'.", widget_name);
+ continue;
+ }
+
+ account_widget_setup_widget (widget, account, param_name);
+ }
+}
+
+void
+empathy_account_widget_handle_params (McAccount *account,
+ GladeXML *gui,
+ const gchar *first_widget_name,
+ ...)
+{
+ va_list args;
+
+ g_return_if_fail (MC_IS_ACCOUNT (account));
+
+ va_start (args, first_widget_name);
+ account_widget_handle_params_valist (account, gui,
+ first_widget_name,
+ args);
+ va_end (args);
+}
+
+void
+empathy_account_widget_add_forget_button (McAccount *account,
+ GladeXML *glade,
+ const gchar *button,
+ const gchar *entry)
+{
+ GtkWidget *button_forget;
+ GtkWidget *entry_password;
+ gchar *password = NULL;
+
+ button_forget = glade_xml_get_widget (glade, button);
+ entry_password = glade_xml_get_widget (glade, entry);
+
+ mc_account_get_param_string (account, "password", &password);
+ gtk_widget_set_sensitive (button_forget, !G_STR_EMPTY (password));
+ g_free (password);
+
+ g_signal_connect (button_forget, "clicked",
+ G_CALLBACK (account_widget_forget_clicked_cb),
+ entry_password);
+ g_signal_connect (entry_password, "changed",
+ G_CALLBACK (account_widget_password_changed_cb),
+ button_forget);
+}
+
+GtkWidget *
+empathy_account_widget_generic_new (McAccount *account)
+{
+ GladeXML *glade;
+ GtkWidget *widget;
+ GtkWidget *table_common_settings;
+ GtkWidget *table_advanced_settings;
+
+ g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
+
+ glade = empathy_glade_get_file ("empathy-account-widget-generic.glade",
+ "vbox_generic_settings",
+ NULL,
+ "vbox_generic_settings", &widget,
+ "table_common_settings", &table_common_settings,
+ "table_advanced_settings", &table_advanced_settings,
+ NULL);
+
+ accounts_widget_generic_setup (account, table_common_settings, table_advanced_settings);
+
+ g_object_unref (glade);
+
+ gtk_widget_show_all (widget);
+
+ return widget;
+}
+
+GtkWidget *
+empathy_account_widget_salut_new (McAccount *account)
+{
+ GladeXML *glade;
+ GtkWidget *widget;
+
+ glade = empathy_glade_get_file ("empathy-account-widget-salut.glade",
+ "vbox_salut_settings",
+ NULL,
+ "vbox_salut_settings", &widget,
+ NULL);
+
+ empathy_account_widget_handle_params (account, glade,
+ "entry_published", "published-name",
+ "entry_nickname", "nickname",
+ "entry_first_name", "first-name",
+ "entry_last_name", "last-name",
+ "entry_email", "email",
+ "entry_jid", "jid",
+ NULL);
+
+ g_object_unref (glade);
+
+ gtk_widget_show (widget);
+
+ return widget;
+}
+
+GtkWidget *
+empathy_account_widget_msn_new (McAccount *account)
+{
+ GladeXML *glade;
+ GtkWidget *widget;
+
+ glade = empathy_glade_get_file ("empathy-account-widget-msn.glade",
+ "vbox_msn_settings",
+ NULL,
+ "vbox_msn_settings", &widget,
+ NULL);
+
+ empathy_account_widget_handle_params (account, glade,
+ "entry_id", "account",
+ "entry_password", "password",
+ "entry_server", "server",
+ "spinbutton_port", "port",
+ NULL);
+
+ empathy_account_widget_add_forget_button (account, glade,
+ "button_forget",
+ "entry_password");
+
+ g_object_unref (glade);
+
+ gtk_widget_show (widget);
+
+ return widget;
+}
+
+GtkWidget *
+empathy_account_widget_sip_new (McAccount *account)
+{
+ GladeXML *glade;
+ GtkWidget *widget;
+
+ glade = empathy_glade_get_file ("empathy-account-widget-sip.glade",
+ "vbox_sip_settings",
+ NULL,
+ "vbox_sip_settings", &widget,
+ NULL);
+
+ empathy_account_widget_handle_params (account, glade,
+ "entry_userid", "account",
+ "entry_password", "password",
+ "entry_registar", "registar",
+ "entry_proxy","proxy-host",
+ "spinbutton_port", "port",
+ "entry_transport", "transport",
+ "checkbutton_discover-binding","discover-binding",
+ "entry_keepalive-mechanism", "keepalive-mechanism",
+ "entry_keepalive-interval", "keepalive-interval",
+ "checkbutton_discover-stun", "discover-stun",
+ "entry_stun-server", "stun-server",
+ "spinbutton_stun-port", "stun-port",
+ "entry_local-ip", "local-ip-address",
+ "spinbutton_local-port", "local-port",
+ "entry_extra-auth-user", "extra-auth-user",
+ "entry_extra-auth-password", "extra-auth-password",
+ "checkbutton_avoid-difficult", "avoid-difficult",
+ NULL);
+
+ empathy_account_widget_add_forget_button (account, glade,
+ "button_forget",
+ "entry_password");
+
+ g_object_unref (glade);
+
+ gtk_widget_show (widget);
+
+ return widget;
+}
+
+GtkWidget *
+empathy_account_widget_jabber_new (McAccount *account)
+{
+ GladeXML *glade;
+ GtkWidget *widget;
+ GtkWidget *spinbutton_port;
+ GtkWidget *checkbutton_ssl;
+
+ glade = empathy_glade_get_file ("empathy-account-widget-jabber.glade",
+ "vbox_jabber_settings",
+ NULL,
+ "vbox_jabber_settings", &widget,
+ "spinbutton_port", &spinbutton_port,
+ "checkbutton_ssl", &checkbutton_ssl,
+ NULL);
+
+ empathy_account_widget_handle_params (account, glade,
+ "entry_id", "account",
+ "entry_password", "password",
+ "entry_resource", "resource",
+ "entry_server", "server",
+ "spinbutton_port", "port",
+ "spinbutton_priority", "priority",
+ "checkbutton_ssl", "old-ssl",
+ "checkbutton_ignore_ssl_errors", "ignore-ssl-errors",
+ "checkbutton_encryption", "require-encryption",
+ NULL);
+
+ empathy_account_widget_add_forget_button (account, glade,
+ "button_forget",
+ "entry_password");
+
+ g_signal_connect (checkbutton_ssl, "toggled",
+ G_CALLBACK (account_widget_jabber_ssl_toggled_cb),
+ spinbutton_port);
+
+ g_object_unref (glade);
+
+ gtk_widget_show (widget);
+
+ return widget;
+}
+
+GtkWidget *
+empathy_account_widget_icq_new (McAccount *account)
+{
+ GladeXML *glade;
+ GtkWidget *widget;
+ GtkWidget *spinbutton_port;
+
+ glade = empathy_glade_get_file ("empathy-account-widget-icq.glade",
+ "vbox_icq_settings",
+ NULL,
+ "vbox_icq_settings", &widget,
+ "spinbutton_port", &spinbutton_port,
+ NULL);
+
+ empathy_account_widget_handle_params (account, glade,
+ "entry_uin", "account",
+ "entry_password", "password",
+ "entry_server", "server",
+ "spinbutton_port", "port",
+ "entry_charset", "charset",
+ NULL);
+
+ empathy_account_widget_add_forget_button (account, glade,
+ "button_forget",
+ "entry_password");
+
+ g_object_unref (glade);
+
+ gtk_widget_show (widget);
+
+ return widget;
+}
+
+GtkWidget *
+empathy_account_widget_yahoo_new (McAccount *account)
+{
+ GladeXML *glade;
+ GtkWidget *widget;
+
+ glade = empathy_glade_get_file ("empathy-account-widget-yahoo.glade",
+ "vbox_yahoo_settings",
+ NULL,
+ "vbox_yahoo_settings", &widget,
+ NULL);
+
+ empathy_account_widget_handle_params (account, glade,
+ "entry_id", "account",
+ "entry_password", "password",
+ "entry_server", "server",
+ "entry_serverjp", "serverjp",
+ "entry_locale", "room-list-locale",
+ "entry_charset", "charset",
+ "spinbutton_port", "port",
+ "checkbutton_yahoojp", "yahoojp",
+ "checkbutton_ignore_invites", "ignore-invites",
+ NULL);
+
+ empathy_account_widget_add_forget_button (account, glade,
+ "button_forget",
+ "entry_password");
+
+ g_object_unref (glade);
+
+ gtk_widget_show (widget);
+
+ return widget;
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-account-widget.h b/gnome-2-22/libempathy-gtk/empathy-account-widget.h
new file mode 100644
index 000000000..b7ebb6742
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-account-widget.h
@@ -0,0 +1,53 @@
+/* -*- 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 <xclaesse@gmail.com>
+ * Martyn Russell <martyn@imendio.com>
+ */
+
+#ifndef __EMPATHY_ACCOUNT_WIDGET_GENERIC_H__
+#define __EMPATHY_ACCOUNT_WIDGET_GENERIC_H__
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+
+#include <libmissioncontrol/mc-account.h>
+
+G_BEGIN_DECLS
+
+void empathy_account_widget_handle_params (McAccount *account,
+ GladeXML *glade,
+ const gchar *first_widget_name,
+ ...);
+void empathy_account_widget_add_forget_button (McAccount *account,
+ GladeXML *glade,
+ const gchar *button,
+ const gchar *entry);
+GtkWidget *empathy_account_widget_generic_new (McAccount *account);
+GtkWidget *empathy_account_widget_salut_new (McAccount *account);
+GtkWidget *empathy_account_widget_msn_new (McAccount *account);
+GtkWidget *empathy_account_widget_jabber_new (McAccount *account);
+GtkWidget *empathy_account_widget_icq_new (McAccount *account);
+GtkWidget *empathy_account_widget_yahoo_new (McAccount *account);
+GtkWidget *empathy_account_widget_sip_new (McAccount *account);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_ACCOUNT_WIDGET_GENERIC_H__ */
diff --git a/gnome-2-22/libempathy-gtk/empathy-accounts-dialog.c b/gnome-2-22/libempathy-gtk/empathy-accounts-dialog.c
new file mode 100644
index 000000000..f79db0e03
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-accounts-dialog.c
@@ -0,0 +1,1083 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2005-2007 Imendio AB
+ * Copyright (C) 2007-2008 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 <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <glib/gi18n.h>
+#include <dbus/dbus-glib.h>
+
+#include <libmissioncontrol/mc-account.h>
+#include <libmissioncontrol/mc-profile.h>
+#include <libmissioncontrol/mission-control.h>
+#include <libmissioncontrol/mc-account-monitor.h>
+#include <telepathy-glib/util.h>
+#include <libtelepathy/tp-constants.h>
+
+#include <libempathy/empathy-debug.h>
+#include <libempathy/empathy-utils.h>
+#include <libempathy-gtk/empathy-ui-utils.h>
+
+#include "empathy-accounts-dialog.h"
+#include "empathy-profile-chooser.h"
+#include "empathy-account-widget.h"
+#include "empathy-account-widget-irc.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_add;
+ GtkWidget *button_remove;
+
+ GtkWidget *frame_new_account;
+ GtkWidget *combobox_profile;
+ GtkWidget *hbox_type;
+ 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_ENABLED,
+ 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,
+ TpConnectionStatus status,
+ McPresence presence,
+ TpConnectionStatusReason reason,
+ const gchar *unique_name,
+ 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_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_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;
+ GtkTreeIter iter;
+ GList *accounts, *l;
+
+ view = GTK_TREE_VIEW (dialog->treeview);
+ store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
+
+ accounts = mc_accounts_list ();
+
+ for (l = accounts; l; l = l->next) {
+ McAccount *account;
+ const gchar *name;
+ TpConnectionStatus status;
+ gboolean enabled;
+
+ account = l->data;
+
+ name = mc_account_get_display_name (account);
+ if (!name) {
+ continue;
+ }
+
+ status = mission_control_get_connection_status (dialog->mc, account, NULL);
+ enabled = mc_account_is_enabled (account);
+
+ gtk_list_store_insert_with_values (store, &iter,
+ -1,
+ COL_ENABLED, enabled,
+ COL_NAME, name,
+ COL_STATUS, status,
+ COL_ACCOUNT_POINTER, account,
+ -1);
+
+ accounts_dialog_status_changed_cb (dialog->mc,
+ status,
+ MC_PRESENCE_UNSET,
+ TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED,
+ mc_account_get_unique_name (account),
+ dialog);
+
+ g_object_unref (account);
+ }
+
+ g_list_free (accounts);
+}
+
+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;
+ GString *string;
+ gchar *str;
+
+ gtk_widget_show (dialog->frame_no_account);
+ gtk_widget_hide (dialog->vbox_details);
+
+ gtk_widget_set_sensitive (dialog->button_remove, FALSE);
+
+ view = GTK_TREE_VIEW (dialog->treeview);
+ model = gtk_tree_view_get_model (view);
+
+ if (empathy_profile_chooser_n_profiles (dialog->combobox_profile) > 0) {
+ string = g_string_new (_("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 {
+ string = g_string_new (_("To add a new account, you first have to "
+ "install a backend for each protocol "
+ "you want to use."));
+ }
+
+ if (gtk_tree_model_iter_n_children (model, NULL) > 0) {
+ gtk_label_set_markup (GTK_LABEL (dialog->label_no_account),
+ _("<b>No Account Selected</b>"));
+ g_string_append (string, _("\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),
+ _("<b>No Accounts Configured</b>"));
+ }
+
+ str = g_string_free (string, FALSE);
+ gtk_label_set_markup (GTK_LABEL (dialog->label_no_account_blurb),
+ str);
+ g_free (str);
+ } 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);
+ g_object_unref (profile);
+
+ if (!tp_strdiff (config_ui, "jabber")) {
+ dialog->settings_widget =
+ empathy_account_widget_jabber_new (account);
+ }
+ else if (!tp_strdiff (config_ui, "msn")) {
+ dialog ->settings_widget =
+ empathy_account_widget_msn_new (account);
+ }
+ else if (!tp_strdiff (config_ui, "local-xmpp")) {
+ dialog->settings_widget =
+ empathy_account_widget_salut_new (account);
+ }
+ else if (!tp_strdiff (config_ui, "irc")) {
+ dialog->settings_widget =
+ empathy_account_widget_irc_new (account);
+ }
+ else if (!tp_strdiff(config_ui, "icq")) {
+ dialog->settings_widget =
+ empathy_account_widget_icq_new (account);
+ }
+ else if (!tp_strdiff (config_ui, "yahoo")) {
+ dialog->settings_widget =
+ empathy_account_widget_yahoo_new (account);
+ }
+ else if (!tp_strdiff (config_ui, "sofiasip")) {
+ dialog->settings_widget =
+ empathy_account_widget_sip_new (account);
+ }
+ else {
+ dialog->settings_widget =
+ empathy_account_widget_generic_new (account);
+ }
+ }
+
+ if (dialog->settings_widget) {
+ gtk_container_add (GTK_CONTAINER (dialog->alignment_settings),
+ dialog->settings_widget);
+ }
+
+ if (account) {
+ McProfile *profile;
+ gchar *text;
+
+ 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_widget_set_tooltip_text (dialog->image_type,
+ mc_profile_get_display_name (profile));
+
+ text = g_strdup_printf ("<big><b>%s</b></big>", mc_account_get_display_name (account));
+ gtk_label_set_markup (GTK_LABEL (dialog->label_name), text);
+ g_free (text);
+ }
+}
+
+static void
+accounts_dialog_model_setup (EmpathyAccountsDialog *dialog)
+{
+ GtkListStore *store;
+ GtkTreeSelection *selection;
+
+ store = gtk_list_store_new (COL_COUNT,
+ G_TYPE_BOOLEAN, /* enabled */
+ 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_name_edited_cb (GtkCellRendererText *renderer,
+ gchar *path,
+ gchar *new_text,
+ EmpathyAccountsDialog *dialog)
+{
+ McAccount *account;
+ GtkTreeModel *model;
+ GtkTreePath *treepath;
+ GtkTreeIter iter;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
+ treepath = gtk_tree_path_new_from_string (path);
+ gtk_tree_model_get_iter (model, &iter, treepath);
+ gtk_tree_model_get (model, &iter,
+ COL_ACCOUNT_POINTER, &account,
+ -1);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+ COL_NAME, new_text,
+ -1);
+ gtk_tree_path_free (treepath);
+
+ mc_account_set_display_name (account, new_text);
+ g_object_unref (account);
+}
+
+static void
+accounts_dialog_enable_toggled_cb (GtkCellRendererToggle *cell_renderer,
+ gchar *path,
+ EmpathyAccountsDialog *dialog)
+{
+ McAccount *account;
+ GtkTreeModel *model;
+ GtkTreePath *treepath;
+ GtkTreeIter iter;
+ gboolean enabled;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
+ treepath = gtk_tree_path_new_from_string (path);
+ gtk_tree_model_get_iter (model, &iter, treepath);
+ gtk_tree_model_get (model, &iter,
+ COL_ACCOUNT_POINTER, &account,
+ -1);
+ gtk_tree_path_free (treepath);
+
+ enabled = mc_account_is_enabled (account);
+ mc_account_set_enabled (account, !enabled);
+
+ empathy_debug (DEBUG_DOMAIN, "%s account %s",
+ enabled ? "Disabled" : "Enable",
+ mc_account_get_display_name(account));
+
+ g_object_unref (account);
+}
+
+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);
+
+ /* Enabled column */
+ cell = gtk_cell_renderer_toggle_new ();
+ gtk_tree_view_insert_column_with_attributes (view, -1,
+ _("Enabled"),
+ cell,
+ "active", COL_ENABLED,
+ NULL);
+ g_signal_connect (cell, "toggled",
+ G_CALLBACK (accounts_dialog_enable_toggled_cb),
+ dialog);
+
+ /* Account column */
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_title (column, _("Accounts"));
+ gtk_tree_view_column_set_expand (column, TRUE);
+ gtk_tree_view_append_column (view, column);
+
+ /* Icon renderer */
+ 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);
+
+ /* Name renderer */
+ cell = gtk_cell_renderer_text_new ();
+ g_object_set (cell,
+ "ellipsize", PANGO_ELLIPSIZE_END,
+ "editable", TRUE,
+ NULL);
+ gtk_tree_view_column_pack_start (column, cell, TRUE);
+ gtk_tree_view_column_add_attribute (column, cell, "text", COL_NAME);
+ g_signal_connect (cell, "edited",
+ G_CALLBACK (accounts_dialog_name_edited_cb),
+ dialog);
+}
+
+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;
+ TpConnectionStatus 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_CONNECTION_STATUS_DISCONNECTED ||
+ (status == TP_CONNECTION_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 gboolean
+accounts_dialog_get_account_iter (EmpathyAccountsDialog *dialog,
+ McAccount *account,
+ GtkTreeIter *iter)
+{
+ GtkTreeView *view;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ gboolean ok;
+
+ /* 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);
+
+ 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 TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+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)
+{
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->treeview));
+ if (accounts_dialog_get_account_iter (dialog, account, &iter)) {
+ gtk_tree_selection_select_iter (selection, &iter);
+ }
+}
+
+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_add, TRUE);
+ gtk_widget_set_sensitive (dialog->button_remove, is_selection);
+
+ account = accounts_dialog_model_get_selected (dialog);
+ accounts_dialog_update_account (dialog, account);
+
+ if (account) {
+ g_object_unref (account);
+ }
+
+ /* insure new account frame is hidden when a row is selected*/
+ gtk_widget_hide (dialog->frame_new_account);
+}
+
+static void
+accounts_dialog_add_account (EmpathyAccountsDialog *dialog,
+ McAccount *account)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ TpConnectionStatus status;
+ const gchar *name;
+ gboolean enabled;
+
+ if (accounts_dialog_get_account_iter (dialog, account, &iter)) {
+ return;
+ }
+
+ status = mission_control_get_connection_status (dialog->mc, account, NULL);
+ name = mc_account_get_display_name (account);
+ enabled = mc_account_is_enabled (account);
+
+ g_return_if_fail (name != NULL);
+
+ empathy_debug (DEBUG_DOMAIN, "Adding new account: %s", name);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
+ gtk_list_store_insert_with_values (GTK_LIST_STORE (model), &iter,
+ -1,
+ COL_ENABLED, enabled,
+ 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,
+ TpConnectionStatus status,
+ McPresence presence,
+ TpConnectionStatusReason reason,
+ const gchar *unique_name,
+ EmpathyAccountsDialog *dialog)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ McAccount *account;
+ GList *accounts, *l;
+ gboolean found = FALSE;
+
+ /* Update the status in the model */
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
+ account = mc_account_lookup (unique_name);
+
+ empathy_debug (DEBUG_DOMAIN, "Status changed for account %s: "
+ "status=%d presence=%d",
+ unique_name, status, presence);
+
+ if (accounts_dialog_get_account_iter (dialog, account, &iter)) {
+ 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);
+ }
+ g_object_unref (account);
+
+ /* Check if there is still accounts in CONNECTING state */
+ accounts = mc_accounts_list ();
+ for (l = accounts; l; l = l->next) {
+ McAccount *this_account;
+ TpConnectionStatus status;
+
+ this_account = l->data;
+
+ status = mission_control_get_connection_status (mc, this_account, NULL);
+ if (status == TP_CONNECTION_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;
+ }
+ if (found && !dialog->connecting_id) {
+ dialog->connecting_id = g_timeout_add (FLASH_TIMEOUT,
+ (GSourceFunc) accounts_dialog_flash_connecting_cb,
+ dialog);
+ }
+}
+
+static void
+accounts_dialog_account_enabled_cb (McAccountMonitor *monitor,
+ gchar *unique_name,
+ EmpathyAccountsDialog *dialog)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ McAccount *account;
+ gboolean enabled;
+
+ /* Update the status in the model */
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
+ account = mc_account_lookup (unique_name);
+ enabled = mc_account_is_enabled (account);
+
+ empathy_debug (DEBUG_DOMAIN, "Account %s is now %s",
+ mc_account_get_display_name (account),
+ enabled ? "enabled" : "disabled");
+
+ if (accounts_dialog_get_account_iter (dialog, account, &iter)) {
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+ COL_ENABLED, enabled,
+ -1);
+ }
+
+ g_object_unref (account);
+}
+
+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 = mc_account_get_unique_name (account);
+ 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);
+
+ gtk_widget_set_sensitive (dialog->button_add, TRUE);
+
+ account = accounts_dialog_model_get_selected (dialog);
+ accounts_dialog_update_account (dialog, account);
+}
+
+static void
+accounts_dialog_button_add_clicked_cb (GtkWidget *button,
+ EmpathyAccountsDialog *dialog)
+{
+ GtkTreeView *view;
+ GtkTreeSelection *selection;
+
+ view = GTK_TREE_VIEW (dialog->treeview);
+ selection = gtk_tree_view_get_selection (view);
+ gtk_tree_selection_unselect_all (selection);
+
+ gtk_widget_set_sensitive (dialog->button_add, FALSE);
+ 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_widget_grab_focus (dialog->combobox_profile);
+}
+
+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_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);
+ g_signal_handlers_disconnect_by_func (dialog->monitor,
+ accounts_dialog_account_enabled_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,
+ "hbox_type", &dialog->hbox_type,
+ "button_create", &dialog->button_create,
+ "button_back", &dialog->button_back,
+ "image_type", &dialog->image_type,
+ "label_name", &dialog->label_name,
+ "button_add", &dialog->button_add,
+ "button_remove", &dialog->button_remove,
+ "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,
+ "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_box_pack_end (GTK_BOX (dialog->hbox_type),
+ dialog->combobox_profile,
+ TRUE, TRUE, 0);
+ gtk_widget_show (dialog->combobox_profile);
+ if (empathy_profile_chooser_n_profiles (dialog->combobox_profile) <= 0) {
+ gtk_widget_set_sensitive (dialog->button_add, FALSE);
+ }
+
+ /* Set up signalling */
+ dialog->mc = empathy_mission_control_new ();
+ dialog->monitor = mc_account_monitor_new ();
+
+ 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);
+ g_signal_connect (dialog->monitor, "account-enabled",
+ G_CALLBACK (accounts_dialog_account_enabled_cb),
+ dialog);
+ g_signal_connect (dialog->monitor, "account-disabled",
+ G_CALLBACK (accounts_dialog_account_enabled_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/gnome-2-22/libempathy-gtk/empathy-accounts-dialog.glade b/gnome-2-22/libempathy-gtk/empathy-accounts-dialog.glade
new file mode 100644
index 000000000..9ed29b8da
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-accounts-dialog.glade
@@ -0,0 +1,350 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+ <widget class="GtkDialog" id="accounts_dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Accounts</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox3">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <widget class="GtkHBox" id="hbox146">
+ <property name="visible">True</property>
+ <property name="border_width">6</property>
+ <property name="spacing">18</property>
+ <child>
+ <widget class="GtkVBox" id="vbox195">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow17">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkTreeView" id="treeview">
+ <property name="width_request">250</property>
+ <property name="height_request">200</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="enable_search">False</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox148">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <widget class="GtkButton" id="button_add">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-add</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="button_remove">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-remove</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox214">
+ <property name="width_request">415</property>
+ <property name="visible">True</property>
+ <property name="spacing">18</property>
+ <child>
+ <widget class="GtkVBox" id="vbox_details">
+ <property name="visible">True</property>
+ <property name="spacing">18</property>
+ <child>
+ <widget class="GtkHBox" id="hbox183">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <widget class="GtkLabel" id="label_name">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">&lt;big&gt;&lt;b&gt;Gmail&lt;/b&gt;&lt;/big&gt;</property>
+ <property name="use_markup">True</property>
+ <property name="selectable">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkImage" id="image_type">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ <property name="stock">gtk-cut</property>
+ <property name="icon_size">6</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkFrame" id="frame2">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment_settings">
+ <property name="visible">True</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">20</property>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label599">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Settings&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkFrame" id="frame_new_account">
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment29">
+ <property name="visible">True</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">20</property>
+ <child>
+ <widget class="GtkVBox" id="vbox216">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <widget class="GtkHBox" id="hbox_type">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <widget class="GtkLabel" id="label645">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Type:</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox181">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <widget class="GtkButton" id="button_create">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="response_id">0</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <widget class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-new</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Cr_eate</property>
+ <property name="use_underline">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="button_back">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-go-back</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label643">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;New Account&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkFrame" id="frame_no_account">
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment21">
+ <property name="visible">True</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <widget class="GtkLabel" id="label_no_account_blurb">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">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.</property>
+ <property name="use_markup">True</property>
+ <property name="wrap">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label_no_account">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;No Account Selected&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <child>
+ <widget class="GtkButton" id="button_close">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-accounts-dialog.h b/gnome-2-22/libempathy-gtk/empathy-accounts-dialog.h
new file mode 100644
index 000000000..84395e618
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-accounts-dialog.h
@@ -0,0 +1,36 @@
+/* -*- 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 <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_ACCOUNTS_DIALOG_H__
+#define __EMPATHY_ACCOUNTS_DIALOG_H__
+
+#include <gtk/gtkwidget.h>
+
+G_BEGIN_DECLS
+
+GtkWidget *empathy_accounts_dialog_show (GtkWindow *parent);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_ACCOUNTS_DIALOG_H__ */
diff --git a/gnome-2-22/libempathy-gtk/empathy-avatar-chooser.c b/gnome-2-22/libempathy-gtk/empathy-avatar-chooser.c
new file mode 100644
index 000000000..78bb32938
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-avatar-chooser.c
@@ -0,0 +1,569 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006-2007 Imendio AB.
+ * Copyright (C) 2007-2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Based on Novell's e-image-chooser.
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <libgnomevfs/gnome-vfs-ops.h>
+
+#include <libempathy/empathy-debug.h>
+
+
+#include "empathy-avatar-chooser.h"
+#include "empathy-conf.h"
+#include "empathy-preferences.h"
+#include "empathy-ui-utils.h"
+
+#define DEBUG_DOMAIN "AvatarChooser"
+
+#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_AVATAR_CHOOSER, EmpathyAvatarChooserPriv))
+
+#define AVATAR_SIZE_SAVE 96
+#define AVATAR_SIZE_VIEW 64
+#define DEFAULT_DIR DATADIR"/pixmaps/faces"
+
+typedef struct {
+ gchar *image_data;
+ gsize image_data_size;
+} EmpathyAvatarChooserPriv;
+
+static void avatar_chooser_finalize (GObject *object);
+static void avatar_chooser_set_image_from_data (EmpathyAvatarChooser *chooser,
+ gchar *data,
+ gsize size);
+static gboolean avatar_chooser_drag_motion_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time,
+ EmpathyAvatarChooser *chooser);
+static void avatar_chooser_drag_leave_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ guint time,
+ EmpathyAvatarChooser *chooser);
+static gboolean avatar_chooser_drag_drop_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time,
+ EmpathyAvatarChooser *chooser);
+static void avatar_chooser_drag_data_received_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time,
+ EmpathyAvatarChooser *chooser);
+static void avatar_chooser_clicked_cb (GtkWidget *button,
+ EmpathyAvatarChooser *chooser);
+
+enum {
+ CHANGED,
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL];
+
+G_DEFINE_TYPE (EmpathyAvatarChooser, empathy_avatar_chooser, GTK_TYPE_BUTTON);
+
+/*
+ * Drag and drop stuff
+ */
+#define URI_LIST_TYPE "text/uri-list"
+
+enum DndTargetType {
+ DND_TARGET_TYPE_URI_LIST
+};
+
+static const GtkTargetEntry drop_types[] = {
+ { URI_LIST_TYPE, 0, DND_TARGET_TYPE_URI_LIST },
+};
+
+static void
+empathy_avatar_chooser_class_init (EmpathyAvatarChooserClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = avatar_chooser_finalize;
+
+ signals[CHANGED] =
+ g_signal_new ("changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ g_type_class_add_private (object_class, sizeof (EmpathyAvatarChooserPriv));
+}
+
+static void
+empathy_avatar_chooser_init (EmpathyAvatarChooser *chooser)
+{
+ EmpathyAvatarChooserPriv *priv;
+
+ priv = GET_PRIV (chooser);
+
+ gtk_drag_dest_set (GTK_WIDGET (chooser),
+ GTK_DEST_DEFAULT_ALL,
+ drop_types,
+ G_N_ELEMENTS (drop_types),
+ GDK_ACTION_COPY);
+
+ g_signal_connect (chooser, "drag-motion",
+ G_CALLBACK (avatar_chooser_drag_motion_cb),
+ chooser);
+ g_signal_connect (chooser, "drag-leave",
+ G_CALLBACK (avatar_chooser_drag_leave_cb),
+ chooser);
+ g_signal_connect (chooser, "drag-drop",
+ G_CALLBACK (avatar_chooser_drag_drop_cb),
+ chooser);
+ g_signal_connect (chooser, "drag-data-received",
+ G_CALLBACK (avatar_chooser_drag_data_received_cb),
+ chooser);
+ g_signal_connect (chooser, "clicked",
+ G_CALLBACK (avatar_chooser_clicked_cb),
+ chooser);
+
+ empathy_avatar_chooser_set (chooser, NULL);
+}
+
+static void
+avatar_chooser_finalize (GObject *object)
+{
+ EmpathyAvatarChooserPriv *priv;
+
+ priv = GET_PRIV (object);
+
+ g_free (priv->image_data);
+
+ G_OBJECT_CLASS (empathy_avatar_chooser_parent_class)->finalize (object);
+}
+
+static void
+avatar_chooser_set_pixbuf (EmpathyAvatarChooser *chooser,
+ GdkPixbuf *pixbuf)
+{
+ EmpathyAvatarChooserPriv *priv = GET_PRIV (chooser);
+ GtkWidget *image;
+ GdkPixbuf *pixbuf_view = NULL;
+ GdkPixbuf *pixbuf_save = NULL;
+ GError *error = NULL;
+
+ g_free (priv->image_data);
+ priv->image_data = NULL;
+ priv->image_data_size = 0;
+
+ if (pixbuf) {
+ pixbuf_view = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_SIZE_VIEW);
+ pixbuf_save = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_SIZE_SAVE);
+
+ if (!gdk_pixbuf_save_to_buffer (pixbuf_save,
+ &priv->image_data,
+ &priv->image_data_size,
+ "png",
+ &error, NULL)) {
+ empathy_debug (DEBUG_DOMAIN, "Failed to save pixbuf: %s",
+ error ? error->message : "No error given");
+ g_clear_error (&error);
+ }
+ image = gtk_image_new_from_pixbuf (pixbuf_view);
+
+ g_object_unref (pixbuf_save);
+ g_object_unref (pixbuf_view);
+ } else {
+ image = gtk_image_new_from_icon_name ("stock_person",
+ GTK_ICON_SIZE_DIALOG);
+ }
+
+ gtk_button_set_image (GTK_BUTTON (chooser), image);
+ g_signal_emit (chooser, signals[CHANGED], 0);
+}
+
+static void
+avatar_chooser_set_image_from_file (EmpathyAvatarChooser *chooser,
+ const gchar *filename)
+{
+ GdkPixbuf *pixbuf;
+ GError *error = NULL;
+
+ if (!(pixbuf = gdk_pixbuf_new_from_file (filename, &error))) {
+ empathy_debug (DEBUG_DOMAIN, "Failed to load pixbuf from file: %s",
+ error ? error->message : "No error given");
+ g_clear_error (&error);
+ }
+
+ avatar_chooser_set_pixbuf (chooser, pixbuf);
+ if (pixbuf) {
+ g_object_unref (pixbuf);
+ }
+}
+
+static void
+avatar_chooser_set_image_from_data (EmpathyAvatarChooser *chooser,
+ gchar *data,
+ gsize size)
+{
+ GdkPixbuf *pixbuf;
+
+ pixbuf = empathy_pixbuf_from_data (data, size);
+ avatar_chooser_set_pixbuf (chooser, pixbuf);
+ if (pixbuf) {
+ g_object_unref (pixbuf);
+ }
+}
+
+static gboolean
+avatar_chooser_drag_motion_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time,
+ EmpathyAvatarChooser *chooser)
+{
+ EmpathyAvatarChooserPriv *priv;
+ GList *p;
+
+ priv = GET_PRIV (chooser);
+
+ for (p = context->targets; p != NULL; p = p->next) {
+ gchar *possible_type;
+
+ possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
+
+ if (!strcmp (possible_type, URI_LIST_TYPE)) {
+ g_free (possible_type);
+ gdk_drag_status (context, GDK_ACTION_COPY, time);
+
+ return TRUE;
+ }
+
+ g_free (possible_type);
+ }
+
+ return FALSE;
+}
+
+static void
+avatar_chooser_drag_leave_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ guint time,
+ EmpathyAvatarChooser *chooser)
+{
+}
+
+static gboolean
+avatar_chooser_drag_drop_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time,
+ EmpathyAvatarChooser *chooser)
+{
+ EmpathyAvatarChooserPriv *priv;
+ GList *p;
+
+ priv = GET_PRIV (chooser);
+
+ if (context->targets == NULL) {
+ return FALSE;
+ }
+
+ for (p = context->targets; p != NULL; p = p->next) {
+ char *possible_type;
+
+ possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
+ if (!strcmp (possible_type, URI_LIST_TYPE)) {
+ g_free (possible_type);
+ gtk_drag_get_data (widget, context,
+ GDK_POINTER_TO_ATOM (p->data),
+ time);
+
+ return TRUE;
+ }
+
+ g_free (possible_type);
+ }
+
+ return FALSE;
+}
+
+static void
+avatar_chooser_drag_data_received_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time,
+ EmpathyAvatarChooser *chooser)
+{
+ gchar *target_type;
+ gboolean handled = FALSE;
+
+ target_type = gdk_atom_name (selection_data->target);
+ if (!strcmp (target_type, URI_LIST_TYPE)) {
+ GnomeVFSHandle *handle = NULL;
+ GnomeVFSResult result;
+ GnomeVFSFileInfo info;
+ gchar *uri;
+ gchar *nl;
+ gchar *data = NULL;
+
+ nl = strstr (selection_data->data, "\r\n");
+ if (nl) {
+ uri = g_strndup (selection_data->data,
+ nl - (gchar*) selection_data->data);
+ } else {
+ uri = g_strdup (selection_data->data);
+ }
+
+ result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
+ if (result == GNOME_VFS_OK) {
+ result = gnome_vfs_get_file_info_from_handle (handle,
+ &info,
+ GNOME_VFS_FILE_INFO_DEFAULT);
+ if (result == GNOME_VFS_OK) {
+ GnomeVFSFileSize data_size;
+
+ data = g_malloc (info.size);
+
+ result = gnome_vfs_read (handle, data, info.size, &data_size);
+ if (result == GNOME_VFS_OK) {
+ avatar_chooser_set_image_from_data (chooser,
+ data,
+ data_size);
+ handled = TRUE;
+ } else {
+ g_free (data);
+ }
+ }
+
+ gnome_vfs_close (handle);
+ }
+
+ g_free (uri);
+ }
+
+ gtk_drag_finish (context, handled, FALSE, time);
+}
+
+static void
+avatar_chooser_update_preview_cb (GtkFileChooser *file_chooser,
+ EmpathyAvatarChooser *chooser)
+{
+ gchar *filename;
+
+ filename = gtk_file_chooser_get_preview_filename (file_chooser);
+
+ if (filename) {
+ GtkWidget *image;
+ GdkPixbuf *pixbuf = NULL;
+ GdkPixbuf *scaled_pixbuf;
+
+ pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
+
+ image = gtk_file_chooser_get_preview_widget (file_chooser);
+
+ if (pixbuf) {
+ scaled_pixbuf = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_SIZE_SAVE);
+ gtk_image_set_from_pixbuf (GTK_IMAGE (image), scaled_pixbuf);
+ g_object_unref (scaled_pixbuf);
+ g_object_unref (pixbuf);
+ } else {
+ gtk_image_set_from_stock (GTK_IMAGE (image),
+ "gtk-dialog-question",
+ GTK_ICON_SIZE_DIALOG);
+ }
+ }
+
+ gtk_file_chooser_set_preview_widget_active (file_chooser, TRUE);
+}
+
+static void
+avatar_chooser_response_cb (GtkWidget *widget,
+ gint response,
+ EmpathyAvatarChooser *chooser)
+{
+ if (response == GTK_RESPONSE_OK) {
+ gchar *filename;
+ gchar *path;
+
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
+ avatar_chooser_set_image_from_file (chooser, filename);
+ g_free (filename);
+
+ path = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (widget));
+ if (path) {
+ empathy_conf_set_string (empathy_conf_get (),
+ EMPATHY_PREFS_UI_AVATAR_DIRECTORY,
+ path);
+ g_free (path);
+ }
+ }
+ else if (response == GTK_RESPONSE_NO) {
+ avatar_chooser_set_image_from_data (chooser, NULL, 0);
+ }
+
+ gtk_widget_destroy (widget);
+}
+
+static void
+avatar_chooser_clicked_cb (GtkWidget *button,
+ EmpathyAvatarChooser *chooser)
+{
+ GtkFileChooser *chooser_dialog;
+ GtkWidget *image;
+ gchar *saved_dir = NULL;
+ const gchar *default_dir = DEFAULT_DIR;
+ const gchar *pics_dir;
+ GtkFileFilter *filter;
+
+ chooser_dialog = GTK_FILE_CHOOSER (
+ gtk_file_chooser_dialog_new (_("Select Your Avatar Image"),
+ empathy_get_toplevel_window (GTK_WIDGET (chooser)),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ _("No Image"),
+ GTK_RESPONSE_NO,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN,
+ GTK_RESPONSE_OK,
+ NULL));
+
+ /* Get special dirs */
+ empathy_conf_get_string (empathy_conf_get (),
+ EMPATHY_PREFS_UI_AVATAR_DIRECTORY,
+ &saved_dir);
+ if (saved_dir && !g_file_test (saved_dir, G_FILE_TEST_IS_DIR)) {
+ g_free (saved_dir);
+ saved_dir = NULL;
+ }
+ if (!g_file_test (default_dir, G_FILE_TEST_IS_DIR)) {
+ default_dir = NULL;
+ }
+ pics_dir = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
+ if (pics_dir && !g_file_test (pics_dir, G_FILE_TEST_IS_DIR)) {
+ pics_dir = NULL;
+ }
+
+ /* Set current dir to the last one or to DEFAULT_DIR or to home */
+ if (saved_dir) {
+ gtk_file_chooser_set_current_folder (chooser_dialog, saved_dir);
+ }
+ else if (pics_dir) {
+ gtk_file_chooser_set_current_folder (chooser_dialog, pics_dir);
+ }
+ else if (default_dir) {
+ gtk_file_chooser_set_current_folder (chooser_dialog, default_dir);
+ } else {
+ gtk_file_chooser_set_current_folder (chooser_dialog, g_get_home_dir ());
+ }
+
+ /* Add shortcuts to special dirs */
+ if (saved_dir) {
+ gtk_file_chooser_add_shortcut_folder (chooser_dialog, saved_dir, NULL);
+ }
+ else if (pics_dir) {
+ gtk_file_chooser_add_shortcut_folder (chooser_dialog, pics_dir, NULL);
+ }
+ if (default_dir) {
+ gtk_file_chooser_add_shortcut_folder (chooser_dialog, default_dir, NULL);
+ }
+
+ /* Setup preview image */
+ image = gtk_image_new ();
+ gtk_file_chooser_set_preview_widget (chooser_dialog, image);
+ gtk_widget_set_size_request (image, AVATAR_SIZE_SAVE, AVATAR_SIZE_SAVE);
+ gtk_widget_show (image);
+ gtk_file_chooser_set_use_preview_label (chooser_dialog, FALSE);
+ g_signal_connect (chooser_dialog, "update-preview",
+ G_CALLBACK (avatar_chooser_update_preview_cb),
+ chooser);
+
+ /* Setup filers */
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, _("Images"));
+ gtk_file_filter_add_pixbuf_formats (filter);
+ gtk_file_chooser_add_filter (chooser_dialog, filter);
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, _("All Files"));
+ gtk_file_filter_add_pattern(filter, "*");
+ gtk_file_chooser_add_filter (chooser_dialog, filter);
+
+ /* Setup response */
+ gtk_dialog_set_default_response (GTK_DIALOG (chooser_dialog), GTK_RESPONSE_OK);
+ g_signal_connect (chooser_dialog, "response",
+ G_CALLBACK (avatar_chooser_response_cb),
+ chooser);
+
+ gtk_widget_show (GTK_WIDGET (chooser_dialog));
+ g_free (saved_dir);
+}
+
+GtkWidget *
+empathy_avatar_chooser_new (void)
+{
+ return g_object_new (EMPATHY_TYPE_AVATAR_CHOOSER, NULL);
+}
+
+void
+empathy_avatar_chooser_set (EmpathyAvatarChooser *chooser,
+ EmpathyAvatar *avatar)
+{
+ g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser));
+
+ avatar_chooser_set_image_from_data (chooser,
+ avatar ? avatar->data : NULL,
+ avatar ? avatar->len : 0);
+}
+
+void
+empathy_avatar_chooser_get_image_data (EmpathyAvatarChooser *chooser,
+ const gchar **data,
+ gsize *data_size,
+ const gchar **mime_type)
+{
+ EmpathyAvatarChooserPriv *priv;
+
+ g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser));
+
+ priv = GET_PRIV (chooser);
+
+ if (data) {
+ *data = priv->image_data;
+ }
+ if (data_size) {
+ *data_size = priv->image_data_size;
+ }
+ if (mime_type) {
+ *mime_type = "png";
+ }
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-avatar-chooser.h b/gnome-2-22/libempathy-gtk/empathy-avatar-chooser.h
new file mode 100644
index 000000000..83dea2afb
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-avatar-chooser.h
@@ -0,0 +1,60 @@
+/* -*- 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 library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Based on Novell's e-image-chooser.
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_AVATAR_CHOOSER_H__
+#define __EMPATHY_AVATAR_CHOOSER_H__
+
+#include <gtk/gtkbutton.h>
+
+#include <libempathy/empathy-avatar.h>
+
+G_BEGIN_DECLS
+
+#define EMPATHY_TYPE_AVATAR_CHOOSER (empathy_avatar_chooser_get_type ())
+#define EMPATHY_AVATAR_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMPATHY_TYPE_AVATAR_CHOOSER, EmpathyAvatarChooser))
+#define EMPATHY_AVATAR_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EMPATHY_TYPE_AVATAR_CHOOSER, EmpathyAvatarChooserClass))
+#define EMPATHY_IS_AVATAR_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMPATHY_TYPE_AVATAR_CHOOSER))
+#define EMPATHY_IS_AVATAR_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EMPATHY_TYPE_AVATAR_CHOOSER))
+
+typedef struct _EmpathyAvatarChooser EmpathyAvatarChooser;
+typedef struct _EmpathyAvatarChooserClass EmpathyAvatarChooserClass;
+typedef struct _EmpathyAvatarChooserPrivate EmpathyAvatarChooserPrivate;
+
+struct _EmpathyAvatarChooser {
+ GtkButton parent;
+};
+
+struct _EmpathyAvatarChooserClass {
+ GtkButtonClass parent_class;
+};
+
+GType empathy_avatar_chooser_get_type (void);
+GtkWidget *empathy_avatar_chooser_new (void);
+void empathy_avatar_chooser_set (EmpathyAvatarChooser *chooser,
+ EmpathyAvatar *avatar);
+void empathy_avatar_chooser_get_image_data (EmpathyAvatarChooser *chooser,
+ const gchar **data,
+ gsize *data_size,
+ const gchar **mime_type);
+
+#endif /* __EMPATHY_AVATAR_CHOOSER_H__ */
diff --git a/gnome-2-22/libempathy-gtk/empathy-avatar-image.c b/gnome-2-22/libempathy-gtk/empathy-avatar-image.c
new file mode 100644
index 000000000..2aeeba458
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-avatar-image.c
@@ -0,0 +1,306 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006-2007 Imendio AB
+ * Copyright (C) 2007-2008 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 <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+
+#include <libempathy/empathy-debug.h>
+
+#include "empathy-avatar-image.h"
+#include "empathy-ui-utils.h"
+
+#define DEBUG_DOMAIN "AvatarImage"
+
+#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_AVATAR_IMAGE, EmpathyAvatarImagePriv))
+
+#define MAX_SMALL 64
+#define MAX_LARGE 400
+
+typedef struct {
+ GtkWidget *image;
+ GtkWidget *popup;
+ GdkPixbuf *pixbuf;
+} EmpathyAvatarImagePriv;
+
+static void avatar_image_finalize (GObject *object);
+static void avatar_image_add_filter (EmpathyAvatarImage *avatar_image);
+static void avatar_image_remove_filter (EmpathyAvatarImage *avatar_image);
+static gboolean avatar_image_button_press_event (GtkWidget *widget,
+ GdkEventButton *event);
+static gboolean avatar_image_button_release_event (GtkWidget *widget,
+ GdkEventButton *event);
+
+G_DEFINE_TYPE (EmpathyAvatarImage, empathy_avatar_image, GTK_TYPE_EVENT_BOX);
+
+static void
+empathy_avatar_image_class_init (EmpathyAvatarImageClass *klass)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->finalize = avatar_image_finalize;
+
+ widget_class->button_press_event = avatar_image_button_press_event;
+ widget_class->button_release_event = avatar_image_button_release_event;
+
+ g_type_class_add_private (object_class, sizeof (EmpathyAvatarImagePriv));
+}
+
+static void
+empathy_avatar_image_init (EmpathyAvatarImage *avatar_image)
+{
+ EmpathyAvatarImagePriv *priv;
+
+ priv = GET_PRIV (avatar_image);
+
+ priv->image = gtk_image_new ();
+ gtk_container_add (GTK_CONTAINER (avatar_image), priv->image);
+ empathy_avatar_image_set (avatar_image, NULL);
+ gtk_widget_show (priv->image);
+
+ avatar_image_add_filter (avatar_image);
+}
+
+static void
+avatar_image_finalize (GObject *object)
+{
+ EmpathyAvatarImagePriv *priv;
+
+ priv = GET_PRIV (object);
+
+ avatar_image_remove_filter (EMPATHY_AVATAR_IMAGE (object));
+
+ if (priv->popup) {
+ gtk_widget_destroy (priv->popup);
+ }
+
+ if (priv->pixbuf) {
+ g_object_unref (priv->pixbuf);
+ }
+
+ G_OBJECT_CLASS (empathy_avatar_image_parent_class)->finalize (object);
+}
+
+static GdkFilterReturn
+avatar_image_filter_func (GdkXEvent *gdkxevent,
+ GdkEvent *event,
+ gpointer data)
+{
+ XEvent *xevent = gdkxevent;
+ Atom atom;
+ EmpathyAvatarImagePriv *priv;
+
+ priv = GET_PRIV (data);
+
+ switch (xevent->type) {
+ case PropertyNotify:
+ atom = gdk_x11_get_xatom_by_name ("_NET_CURRENT_DESKTOP");
+ if (xevent->xproperty.atom == atom) {
+ if (priv->popup) {
+ gtk_widget_destroy (priv->popup);
+ priv->popup = NULL;
+ }
+ }
+ break;
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static void
+avatar_image_add_filter (EmpathyAvatarImage *avatar_image)
+{
+ Window window;
+ GdkWindow *gdkwindow;
+ gint mask;
+
+ mask = PropertyChangeMask;
+
+ window = GDK_ROOT_WINDOW ();
+ gdkwindow = gdk_xid_table_lookup (window);
+
+ gdk_error_trap_push ();
+ if (gdkwindow) {
+ XWindowAttributes attrs;
+ XGetWindowAttributes (gdk_display, window, &attrs);
+ mask |= attrs.your_event_mask;
+ }
+
+ XSelectInput (gdk_display, window, mask);
+
+ gdk_error_trap_pop ();
+
+ gdk_window_add_filter (NULL, avatar_image_filter_func, avatar_image);
+}
+
+static void
+avatar_image_remove_filter (EmpathyAvatarImage *avatar_image)
+{
+ gdk_window_remove_filter (NULL, avatar_image_filter_func, avatar_image);
+}
+
+static gboolean
+avatar_image_button_press_event (GtkWidget *widget, GdkEventButton *event)
+{
+ EmpathyAvatarImagePriv *priv;
+ GtkWidget *popup;
+ GtkWidget *frame;
+ GtkWidget *image;
+ gint x, y;
+ gint popup_width, popup_height;
+ gint width, height;
+ GdkPixbuf *pixbuf;
+
+ priv = GET_PRIV (widget);
+
+ if (priv->popup) {
+ gtk_widget_destroy (priv->popup);
+ priv->popup = NULL;
+ }
+
+ if (event->button != 1 || event->type != GDK_BUTTON_PRESS || !priv->pixbuf) {
+ return FALSE;
+ }
+
+ popup_width = gdk_pixbuf_get_width (priv->pixbuf);
+ popup_height = gdk_pixbuf_get_height (priv->pixbuf);
+
+ width = priv->image->allocation.width;
+ height = priv->image->allocation.height;
+
+ /* Don't show a popup if the popup is smaller then the currently avatar
+ * image.
+ */
+ if (popup_height <= height && popup_width <= width) {
+ return TRUE;
+ }
+
+ pixbuf = empathy_pixbuf_scale_down_if_necessary (priv->pixbuf, MAX_LARGE);
+ popup_width = gdk_pixbuf_get_width (pixbuf);
+ popup_height = gdk_pixbuf_get_height (pixbuf);
+
+ popup = gtk_window_new (GTK_WINDOW_POPUP);
+
+ frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
+
+ gtk_container_add (GTK_CONTAINER (popup), frame);
+
+ image = gtk_image_new ();
+ gtk_container_add (GTK_CONTAINER (frame), image);
+
+ gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
+ g_object_unref (pixbuf);
+
+ gdk_window_get_origin (priv->image->window, &x, &y);
+
+ x = x - (popup_width - width) / 2;
+ y = y - (popup_height - height) / 2;
+
+ gtk_window_move (GTK_WINDOW (popup), x, y);
+
+ priv->popup = popup;
+
+ gtk_widget_show_all (popup);
+
+ return TRUE;
+}
+
+static gboolean
+avatar_image_button_release_event (GtkWidget *widget, GdkEventButton *event)
+{
+ EmpathyAvatarImagePriv *priv;
+
+ priv = GET_PRIV (widget);
+
+ if (event->button != 1 || event->type != GDK_BUTTON_RELEASE) {
+ return FALSE;
+ }
+
+ if (!priv->popup) {
+ return TRUE;
+ }
+
+ gtk_widget_destroy (priv->popup);
+ priv->popup = NULL;
+
+ return TRUE;
+}
+
+GtkWidget *
+empathy_avatar_image_new (void)
+{
+ EmpathyAvatarImage *avatar_image;
+
+ avatar_image = g_object_new (EMPATHY_TYPE_AVATAR_IMAGE, NULL);
+
+ return GTK_WIDGET (avatar_image);
+}
+
+void
+empathy_avatar_image_set (EmpathyAvatarImage *avatar_image,
+ EmpathyAvatar *avatar)
+{
+ EmpathyAvatarImagePriv *priv = GET_PRIV (avatar_image);
+ GdkPixbuf *scaled_pixbuf;
+
+ g_return_if_fail (EMPATHY_IS_AVATAR_IMAGE (avatar_image));
+
+ if (priv->pixbuf) {
+ g_object_unref (priv->pixbuf);
+ priv->pixbuf = NULL;
+ }
+
+ if (avatar) {
+ priv->pixbuf = empathy_pixbuf_from_data (avatar->data, avatar->len);
+ }
+
+ if (!priv->pixbuf) {
+ gtk_image_set_from_icon_name (GTK_IMAGE (priv->image),
+ "stock_person",
+ GTK_ICON_SIZE_DIALOG);
+ return;
+ }
+
+ scaled_pixbuf = empathy_pixbuf_scale_down_if_necessary (priv->pixbuf, MAX_SMALL);
+ gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), scaled_pixbuf);
+
+ if (scaled_pixbuf != priv->pixbuf) {
+ gtk_widget_set_tooltip_text (GTK_WIDGET (avatar_image),
+ _("Click to enlarge"));
+ } else {
+ gtk_widget_set_tooltip_text (GTK_WIDGET (avatar_image),
+ NULL);
+ }
+
+ g_object_unref (scaled_pixbuf);
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-avatar-image.h b/gnome-2-22/libempathy-gtk/empathy-avatar-image.h
new file mode 100644
index 000000000..8a28ccb9a
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-avatar-image.h
@@ -0,0 +1,58 @@
+/* -*- 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 <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_AVATAR_IMAGE_H__
+#define __EMPATHY_AVATAR_IMAGE_H__
+
+#include <gtk/gtkeventbox.h>
+
+#include <libempathy/empathy-avatar.h>
+
+G_BEGIN_DECLS
+
+#define EMPATHY_TYPE_AVATAR_IMAGE (empathy_avatar_image_get_type ())
+#define EMPATHY_AVATAR_IMAGE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_AVATAR_IMAGE, EmpathyAvatarImage))
+#define EMPATHY_AVATAR_IMAGE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_AVATAR_IMAGE, EmpathyAvatarImageClass))
+#define EMPATHY_IS_AVATAR_IMAGE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_AVATAR_IMAGE))
+#define EMPATHY_IS_AVATAR_IMAGE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_AVATAR_IMAGE))
+#define EMPATHY_AVATAR_IMAGE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_AVATAR_IMAGE, EmpathyAvatarImageClass))
+
+typedef struct _EmpathyAvatarImage EmpathyAvatarImage;
+typedef struct _EmpathyAvatarImageClass EmpathyAvatarImageClass;
+
+struct _EmpathyAvatarImage {
+ GtkEventBox parent;
+};
+
+struct _EmpathyAvatarImageClass {
+ GtkEventBoxClass parent_class;
+};
+
+GType empathy_avatar_image_get_type (void) G_GNUC_CONST;
+GtkWidget * empathy_avatar_image_new (void);
+void empathy_avatar_image_set (EmpathyAvatarImage *avatar_image,
+ EmpathyAvatar *avatar);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_AVATAR_IMAGE_H__ */
diff --git a/gnome-2-22/libempathy-gtk/empathy-call-window.c b/gnome-2-22/libempathy-gtk/empathy-call-window.c
new file mode 100644
index 000000000..bb7a84a91
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-call-window.c
@@ -0,0 +1,519 @@
+/*
+ * Copyright (C) 2007 Elliot Fairweather
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
+ */
+
+#include <string.h>
+
+#include <libtelepathy/tp-chan.h>
+#include <libtelepathy/tp-helpers.h>
+
+#include <libmissioncontrol/mc-account.h>
+#include <libmissioncontrol/mc-account-monitor.h>
+#include <libmissioncontrol/mission-control.h>
+
+#include <libempathy/empathy-contact.h>
+#include <libempathy/empathy-tp-call.h>
+#include <libempathy/empathy-chandler.h>
+#include <libempathy/empathy-debug.h>
+#include <libempathy/empathy-utils.h>
+
+#include <libempathy-gtk/empathy-call-window.h>
+#include <libempathy-gtk/empathy-ui-utils.h>
+
+#define DEBUG_DOMAIN "CallWindow"
+
+typedef struct
+{
+ GtkWidget *window;
+ GtkWidget *status_label;
+ GtkWidget *start_call_button;
+ GtkWidget *end_call_button;
+ GtkWidget *input_volume_scale;
+ GtkWidget *output_volume_scale;
+ GtkWidget *input_mute_button;
+ GtkWidget *output_mute_button;
+ GtkWidget *preview_video_frame;
+ GtkWidget *output_video_frame;
+ GtkWidget *preview_video_socket;
+ GtkWidget *output_video_socket;
+ GtkWidget *video_button;
+ GtkWidget *output_video_label;
+
+ EmpathyTpCall *call;
+
+ GTimeVal start_time;
+ guint timeout_event_id;
+
+ gboolean is_drawing;
+} EmpathyCallWindow;
+
+static gboolean
+call_window_update_timer (gpointer data)
+{
+ EmpathyCallWindow *window = data;
+ GTimeVal current;
+ gchar *str;
+ glong now, then;
+ glong time, seconds, minutes, hours;
+
+ g_get_current_time (&current);
+
+ now = current.tv_sec;
+ then = (window->start_time).tv_sec;
+
+ time = now - then;
+
+ seconds = time % 60;
+ time /= 60;
+ minutes = time % 60;
+ time /= 60;
+ hours = time % 60;
+
+ if (hours > 0)
+ {
+ str = g_strdup_printf ("Connected - %02ld : %02ld : %02ld", hours,
+ minutes, seconds);
+ }
+ else
+ {
+ str = g_strdup_printf ("Connected - %02ld : %02ld", minutes, seconds);
+ }
+
+ gtk_label_set_text (GTK_LABEL (window->status_label), str);
+
+ g_free (str);
+
+ return TRUE;
+}
+
+static void
+call_window_stop_timeout (EmpathyCallWindow *window)
+{
+ GMainContext *context;
+ GSource *source;
+
+ context = g_main_context_default ();
+
+ empathy_debug (DEBUG_DOMAIN, "Timer stopped");
+
+ if (window->timeout_event_id)
+ {
+ source = g_main_context_find_source_by_id (context,
+ window->timeout_event_id);
+ g_source_destroy (source);
+ window->timeout_event_id = 0;
+ }
+}
+
+static void
+call_window_set_output_video_is_drawing (EmpathyCallWindow *window,
+ gboolean is_drawing)
+{
+ GtkWidget* child;
+
+ child = gtk_bin_get_child (GTK_BIN (window->output_video_frame));
+
+ empathy_debug (DEBUG_DOMAIN,
+ "Setting output video is drawing - %d", is_drawing);
+
+ if (is_drawing)
+ {
+ if (!window->is_drawing)
+ {
+ if (child)
+ {
+ gtk_container_remove (GTK_CONTAINER (window->output_video_frame),
+ child);
+ }
+ gtk_container_add (GTK_CONTAINER (window->output_video_frame),
+ window->output_video_socket);
+ gtk_widget_show (window->output_video_socket);
+ empathy_tp_call_add_output_video (window->call,
+ gtk_socket_get_id (GTK_SOCKET (window->output_video_socket)));
+ window->is_drawing = is_drawing;
+ }
+ }
+ else
+ {
+ if (window->is_drawing)
+ {
+ empathy_tp_call_add_output_video (window->call, 0);
+ if (child)
+ {
+ gtk_container_remove (GTK_CONTAINER (window->output_video_frame),
+ child);
+ }
+ gtk_container_add (GTK_CONTAINER (window->output_video_frame),
+ window->output_video_label);
+ gtk_widget_show (window->output_video_label);
+ window->is_drawing = is_drawing;
+ }
+ }
+}
+
+static gboolean
+call_window_delete_event_cb (GtkWidget *widget,
+ GdkEvent *event,
+ EmpathyCallWindow *window)
+{
+ GtkWidget *dialog;
+ gint result;
+ guint status;
+
+ empathy_debug (DEBUG_DOMAIN, "Delete event occurred");
+
+ g_object_get (G_OBJECT (window->call), "status", &status, NULL);
+
+ if (status != EMPATHY_TP_CALL_STATUS_CLOSED)
+ {
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window->window),
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
+ "This call will be ended. Continue?");
+
+ result = gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ switch (result)
+ {
+ case GTK_RESPONSE_YES:
+ call_window_stop_timeout (window);
+ call_window_set_output_video_is_drawing (window, FALSE);
+ empathy_tp_call_close_channel (window->call);
+ empathy_tp_call_remove_preview_video (window->call,
+ gtk_socket_get_id (GTK_SOCKET (window->preview_video_socket)));
+ return FALSE;
+ default:
+ return TRUE;
+ }
+ }
+ else
+ {
+ empathy_tp_call_remove_preview_video (window->call,
+ gtk_socket_get_id (GTK_SOCKET (window->preview_video_socket)));
+ return FALSE;
+ }
+}
+
+static void
+call_window_video_button_toggled_cb (GtkWidget *button,
+ EmpathyCallWindow *window)
+{
+ gboolean is_sending;
+
+ is_sending = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+
+ empathy_debug (DEBUG_DOMAIN, "Send video toggled - %d", is_sending);
+
+ empathy_tp_call_request_video_stream_direction (window->call, is_sending);
+}
+
+static void
+call_window_status_changed_cb (EmpathyTpCall *call,
+ EmpathyCallWindow *window)
+{
+ EmpathyContact *contact;
+ guint status;
+ guint stream_state;
+ EmpathyTpCallStream *audio_stream;
+ EmpathyTpCallStream *video_stream;
+ gboolean is_incoming;
+ gchar *title;
+
+ g_object_get (window->call,
+ "status", &status,
+ "audio-stream", &audio_stream,
+ "video-stream", &video_stream,
+ NULL);
+
+ if (video_stream->state > audio_stream->state)
+ stream_state = video_stream->state;
+ else
+ stream_state = audio_stream->state;
+
+ empathy_debug (DEBUG_DOMAIN, "Status changed - status: %d, stream state: %d",
+ status, stream_state);
+
+ if (window->timeout_event_id)
+ call_window_stop_timeout (window);
+
+ if (status == EMPATHY_TP_CALL_STATUS_CLOSED)
+ {
+ gtk_label_set_text (GTK_LABEL (window->status_label), "Closed");
+ gtk_widget_set_sensitive (window->end_call_button, FALSE);
+ gtk_widget_set_sensitive (window->start_call_button, FALSE);
+
+ call_window_set_output_video_is_drawing (window, FALSE);
+ }
+ else if (stream_state == TP_MEDIA_STREAM_STATE_DISCONNECTED)
+ gtk_label_set_text (GTK_LABEL (window->status_label), "Disconnected");
+ else if (status == EMPATHY_TP_CALL_STATUS_PENDING)
+ {
+ g_object_get (G_OBJECT (window->call), "contact", &contact, NULL);
+
+ title = g_strdup_printf ("%s - Empathy Call",
+ empathy_contact_get_name (contact));
+ gtk_window_set_title (GTK_WINDOW (window->window), title);
+
+ gtk_label_set_text (GTK_LABEL (window->status_label), "Ringing");
+ gtk_widget_set_sensitive (window->end_call_button, TRUE);
+ gtk_widget_set_sensitive (window->video_button, TRUE);
+
+ g_object_get (G_OBJECT (window->call), "is-incoming", &is_incoming, NULL);
+ if (is_incoming)
+ gtk_widget_set_sensitive (window->start_call_button, TRUE);
+ else
+ g_signal_connect (GTK_OBJECT (window->video_button), "toggled",
+ G_CALLBACK (call_window_video_button_toggled_cb),
+ window);
+ }
+ else if (status == EMPATHY_TP_CALL_STATUS_ACCEPTED)
+ {
+ if (stream_state == TP_MEDIA_STREAM_STATE_CONNECTING)
+ gtk_label_set_text (GTK_LABEL (window->status_label), "Connecting");
+ else if (stream_state == TP_MEDIA_STREAM_STATE_CONNECTED)
+ {
+ if ((window->start_time).tv_sec == 0)
+ g_get_current_time (&(window->start_time));
+ window->timeout_event_id = g_timeout_add (1000,
+ call_window_update_timer, window);
+ empathy_debug (DEBUG_DOMAIN, "Timer started");
+ }
+ }
+}
+
+static void
+call_window_receiving_video_cb (EmpathyTpCall *call,
+ gboolean receiving_video,
+ EmpathyCallWindow *window)
+{
+ empathy_debug (DEBUG_DOMAIN, "Receiving video signal received");
+
+ call_window_set_output_video_is_drawing (window, receiving_video);
+}
+
+static void
+call_window_sending_video_cb (EmpathyTpCall *call,
+ gboolean sending_video,
+ EmpathyCallWindow *window)
+{
+ empathy_debug (DEBUG_DOMAIN, "Sending video signal received");
+
+ g_signal_handlers_block_by_func (window->video_button,
+ call_window_video_button_toggled_cb, window);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (window->video_button),
+ sending_video);
+ g_signal_handlers_unblock_by_func (window->video_button,
+ call_window_video_button_toggled_cb, window);
+}
+
+static void
+call_window_socket_realized_cb (GtkWidget *widget,
+ EmpathyCallWindow *window)
+{
+ if (widget == window->preview_video_socket)
+ {
+ empathy_debug (DEBUG_DOMAIN, "Preview socket realized");
+ empathy_tp_call_add_preview_video (window->call,
+ gtk_socket_get_id (GTK_SOCKET (window->preview_video_socket)));
+ }
+ else
+ {
+ empathy_debug (DEBUG_DOMAIN, "Output socket realized");
+ }
+}
+
+static void
+call_window_start_call_button_clicked_cb (GtkWidget *widget,
+ EmpathyCallWindow *window)
+{
+ gboolean send_video;
+ gboolean is_incoming;
+
+ empathy_debug (DEBUG_DOMAIN, "Start call clicked");
+
+ gtk_widget_set_sensitive (window->start_call_button, FALSE);
+ g_object_get (G_OBJECT (window->call), "is-incoming", &is_incoming, NULL);
+ if (is_incoming)
+ {
+ empathy_tp_call_accept_incoming_call (window->call);
+ send_video = gtk_toggle_button_get_active
+ (GTK_TOGGLE_BUTTON (window->video_button));
+ empathy_tp_call_request_video_stream_direction (window->call, send_video);
+ g_signal_connect (GTK_OBJECT (window->video_button), "toggled",
+ G_CALLBACK (call_window_video_button_toggled_cb), window);
+ }
+}
+
+static void
+call_window_end_call_button_clicked_cb (GtkWidget *widget,
+ EmpathyCallWindow *window)
+{
+ empathy_debug (DEBUG_DOMAIN, "End call clicked");
+
+ call_window_set_output_video_is_drawing (window, FALSE);
+ empathy_tp_call_close_channel (window->call);
+ gtk_widget_set_sensitive (window->end_call_button, FALSE);
+ gtk_widget_set_sensitive (window->start_call_button, FALSE);
+}
+
+static void
+call_window_output_volume_changed_cb (GtkWidget *scale,
+ EmpathyCallWindow *window)
+{
+ guint volume;
+
+ volume = (guint) gtk_range_get_value (GTK_RANGE (scale));
+
+ empathy_debug (DEBUG_DOMAIN, "Output volume changed - %u", volume);
+
+ empathy_tp_call_set_output_volume (window->call, volume);
+}
+
+static void
+call_window_output_mute_button_toggled_cb (GtkWidget *button,
+ EmpathyCallWindow *window)
+{
+ gboolean is_muted;
+
+ is_muted = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+
+ empathy_debug (DEBUG_DOMAIN, "Mute output toggled - %d", is_muted);
+
+ empathy_tp_call_mute_output (window->call, is_muted);
+}
+
+static void
+call_window_input_mute_button_toggled_cb (GtkWidget *button,
+ EmpathyCallWindow *window)
+{
+ gboolean is_muted;
+
+ is_muted = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+
+ empathy_debug (DEBUG_DOMAIN, "Mute input toggled - %d", is_muted);
+
+ empathy_tp_call_mute_input (window->call, is_muted);
+}
+
+static void
+call_window_destroy_cb (GtkWidget *widget,
+ EmpathyCallWindow *window)
+{
+ g_signal_handlers_disconnect_by_func (window->call,
+ call_window_status_changed_cb, window);
+ g_signal_handlers_disconnect_by_func (window->call,
+ call_window_receiving_video_cb, window);
+ g_signal_handlers_disconnect_by_func (window->call,
+ call_window_sending_video_cb, window);
+
+ g_object_unref (window->call);
+ g_object_unref (window->output_video_socket);
+ g_object_unref (window->preview_video_socket);
+ g_object_unref (window->output_video_label);
+
+ g_slice_free (EmpathyCallWindow, window);
+}
+
+GtkWidget *
+empathy_call_window_new (EmpathyTpCall *call)
+{
+ EmpathyCallWindow *window;
+ GladeXML *glade;
+ guint status;
+
+ g_return_val_if_fail (EMPATHY_IS_TP_CALL (call), NULL);
+
+ window = g_slice_new0 (EmpathyCallWindow);
+ window->call = g_object_ref (call);
+
+ glade = empathy_glade_get_file ("empathy-call-window.glade",
+ "window",
+ NULL,
+ "window", &window->window,
+ "status_label", &window->status_label,
+ "start_call_button", &window->start_call_button,
+ "end_call_button", &window->end_call_button,
+ "input_volume_scale", &window->input_volume_scale,
+ "output_volume_scale", &window->output_volume_scale,
+ "input_mute_button", &window->input_mute_button,
+ "output_mute_button", &window->output_mute_button,
+ "preview_video_frame", &window->preview_video_frame,
+ "output_video_frame", &window->output_video_frame,
+ "video_button", &window->video_button,
+ NULL);
+
+ empathy_glade_connect (glade,
+ window,
+ "window", "destroy", call_window_destroy_cb,
+ "window", "delete_event", call_window_delete_event_cb,
+ "input_mute_button", "toggled", call_window_input_mute_button_toggled_cb,
+ "output_mute_button", "toggled", call_window_output_mute_button_toggled_cb,
+ "output_volume_scale", "value-changed", call_window_output_volume_changed_cb,
+ "start_call_button", "clicked", call_window_start_call_button_clicked_cb,
+ "end_call_button", "clicked", call_window_end_call_button_clicked_cb,
+ NULL);
+
+ g_object_unref (glade);
+
+ /* Output video label */
+ window->output_video_label = g_object_ref (gtk_label_new ("No video output"));
+ gtk_container_add (GTK_CONTAINER (window->output_video_frame),
+ window->output_video_label);
+ gtk_widget_show (window->output_video_label);
+
+ /* Output video socket */
+ window->output_video_socket = g_object_ref (gtk_socket_new ());
+ g_signal_connect (GTK_OBJECT (window->output_video_socket), "realize",
+ G_CALLBACK (call_window_socket_realized_cb), window);
+ gtk_widget_show (window->output_video_socket);
+
+ /* Preview video socket */
+ window->preview_video_socket = g_object_ref (gtk_socket_new ());
+ g_signal_connect (GTK_OBJECT (window->preview_video_socket), "realize",
+ G_CALLBACK (call_window_socket_realized_cb), window);
+ gtk_container_add (GTK_CONTAINER (window->preview_video_frame),
+ window->preview_video_socket);
+ gtk_widget_show (window->preview_video_socket);
+
+ g_signal_connect (G_OBJECT (window->call), "status-changed",
+ G_CALLBACK (call_window_status_changed_cb),
+ window);
+ g_signal_connect (G_OBJECT (window->call), "receiving-video",
+ G_CALLBACK (call_window_receiving_video_cb),
+ window);
+ g_signal_connect (G_OBJECT (window->call), "sending-video",
+ G_CALLBACK (call_window_sending_video_cb),
+ window);
+
+ window->is_drawing = FALSE;
+
+ g_object_get (G_OBJECT (window->call), "status", &status, NULL);
+
+ if (status == EMPATHY_TP_CALL_STATUS_READYING)
+ {
+ gtk_window_set_title (GTK_WINDOW (window->window), "Empathy Call");
+ gtk_label_set_text (GTK_LABEL (window->status_label), "Readying");
+ }
+
+ gtk_widget_show (window->window);
+
+ return window->window;
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-call-window.glade b/gnome-2-22/libempathy-gtk/empathy-call-window.glade
new file mode 100644
index 000000000..2e388cf07
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-call-window.glade
@@ -0,0 +1,300 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.2 on Fri Apr 4 14:56:48 2008 -->
+<glade-interface>
+ <widget class="GtkWindow" id="window">
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">10</property>
+ <property name="spacing">10</property>
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkLabel" id="status_label">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHSeparator" id="hseparator1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">10</property>
+ <child>
+ <widget class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label_xalign">0</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <child>
+ <widget class="GtkHBox" id="hbox3">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <widget class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="extension_events">GDK_EXTENSION_EVENTS_CURSOR</property>
+ <property name="resize_mode">GTK_RESIZE_QUEUE</property>
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Input</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">5</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVScale" id="input_volume_scale">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="adjustment">100 0 100 1 0 0</property>
+ <property name="inverted">True</property>
+ <property name="draw_value">False</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToggleButton" id="input_mute_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Mute</property>
+ <property name="response_id">0</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">5</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">5</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox5">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Output</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">5</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVScale" id="output_volume_scale">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="adjustment">100 0 100 1 0 0</property>
+ <property name="inverted">True</property>
+ <property name="draw_value">False</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToggleButton" id="output_mute_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Mute</property>
+ <property name="response_id">0</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">5</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">5</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Volume</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkAspectFrame" id="output_video_frame">
+ <property name="width_request">352</property>
+ <property name="height_request">288</property>
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label_xalign">0</property>
+ <property name="ratio">1.2200000286102295</property>
+ <property name="obey_child">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkAspectFrame" id="preview_video_frame">
+ <property name="width_request">176</property>
+ <property name="height_request">144</property>
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label_xalign">0</property>
+ <property name="ratio">1.2200000286102295</property>
+ <property name="obey_child">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkCheckButton" id="video_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Send Video</property>
+ <property name="response_id">0</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">10</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHSeparator" id="hseparator2">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">5</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="start_call_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Start Call</property>
+ <property name="response_id">0</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">10</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="end_call_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">End Call</property>
+ <property name="response_id">0</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">10</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-call-window.h b/gnome-2-22/libempathy-gtk/empathy-call-window.h
new file mode 100644
index 000000000..7d65aaeae
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-call-window.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2007 Elliot Fairweather
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
+ */
+
+#ifndef __EMPATHY_CALL_WINDOW_H__
+#define __EMPATHY_CALL_WINDOW_H__
+
+#include <gtk/gtk.h>
+
+#include <libempathy/empathy-tp-call.h>
+
+G_BEGIN_DECLS
+
+GtkWidget *empathy_call_window_new (EmpathyTpCall *call);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_CALL_WINDOW_H__ */
diff --git a/gnome-2-22/libempathy-gtk/empathy-cell-renderer-activatable.c b/gnome-2-22/libempathy-gtk/empathy-cell-renderer-activatable.c
new file mode 100644
index 000000000..76e3b3bd7
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-cell-renderer-activatable.c
@@ -0,0 +1,121 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007 Raphael Slinckx <raphael@slinckx.net>
+ * Copyright (C) 2007-2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Raphael Slinckx <raphael@slinckx.net>
+ */
+
+#include <gtk/gtktreeview.h>
+
+#include <libempathy/empathy-debug.h>
+
+#include "empathy-cell-renderer-activatable.h"
+
+#define DEBUG_DOMAIN "CellRendererActivatable"
+
+static void empathy_cell_renderer_activatable_init (EmpathyCellRendererActivatable *cell);
+static void empathy_cell_renderer_activatable_class_init (EmpathyCellRendererActivatableClass *klass);
+static gboolean cell_renderer_activatable_activate (GtkCellRenderer *cell,
+ GdkEvent *event,
+ GtkWidget *widget,
+ const gchar *path,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GtkCellRendererState flags);
+
+enum {
+ PATH_ACTIVATED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE (EmpathyCellRendererActivatable, empathy_cell_renderer_activatable, GTK_TYPE_CELL_RENDERER_PIXBUF)
+
+static void
+empathy_cell_renderer_activatable_init (EmpathyCellRendererActivatable *cell)
+{
+ g_object_set (cell,
+ "xpad", 0,
+ "ypad", 0,
+ "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE,
+ "follow-state", TRUE,
+ NULL);
+}
+
+static void
+empathy_cell_renderer_activatable_class_init (EmpathyCellRendererActivatableClass *klass)
+{
+ GtkCellRendererClass *cell_class;
+
+ cell_class = GTK_CELL_RENDERER_CLASS (klass);
+ cell_class->activate = cell_renderer_activatable_activate;
+
+ signals[PATH_ACTIVATED] =
+ g_signal_new ("path-activated",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1, G_TYPE_STRING);
+}
+
+GtkCellRenderer *
+empathy_cell_renderer_activatable_new (void)
+{
+ return g_object_new (EMPATHY_TYPE_CELL_RENDERER_ACTIVATABLE, NULL);
+}
+
+static gboolean
+cell_renderer_activatable_activate (GtkCellRenderer *cell,
+ GdkEvent *event,
+ GtkWidget *widget,
+ const gchar *path_string,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GtkCellRendererState flags)
+{
+ EmpathyCellRendererActivatable *activatable;
+ gint ex, ey, bx, by, bw, bh;
+
+ activatable = EMPATHY_CELL_RENDERER_ACTIVATABLE (cell);
+
+ if (!GTK_IS_TREE_VIEW (widget) ||
+ event->type != GDK_BUTTON_PRESS) {
+ return FALSE;
+ }
+
+ ex = (gint) ((GdkEventButton *) event)->x;
+ ey = (gint) ((GdkEventButton *) event)->y;
+ bx = background_area->x;
+ by = background_area->y;
+ bw = background_area->width;
+ bh = background_area->height;
+
+ if (ex < bx || ex > (bx+bw) || ey < by || ey > (by+bh)){
+ /* Click wasn't on the icon */
+ return FALSE;
+ }
+
+ g_signal_emit (activatable, signals[PATH_ACTIVATED], 0, path_string);
+
+ return TRUE;
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-cell-renderer-activatable.h b/gnome-2-22/libempathy-gtk/empathy-cell-renderer-activatable.h
new file mode 100644
index 000000000..6520e29ca
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-cell-renderer-activatable.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007 Raphael Slinckx <raphael@slinckx.net>
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Raphael Slinckx <raphael@slinckx.net>
+ */
+
+#ifndef __EMPATHY_CELL_RENDERER_ACTIVATABLE_H__
+#define __EMPATHY_CELL_RENDERER_ACTIVATABLE_H__
+
+#include <gtk/gtkcellrendererpixbuf.h>
+
+G_BEGIN_DECLS
+
+#define EMPATHY_TYPE_CELL_RENDERER_ACTIVATABLE (empathy_cell_renderer_activatable_get_type ())
+#define EMPATHY_CELL_RENDERER_ACTIVATABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMPATHY_TYPE_CELL_RENDERER_ACTIVATABLE, EmpathyCellRendererActivatable))
+#define EMPATHY_CELL_RENDERER_ACTIVATABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EMPATHY_TYPE_CELL_RENDERER_ACTIVATABLE, EmpathyCellRendererActivatableClass))
+#define EMPATHY_IS_CELL_RENDERER_ACTIVATABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMPATHY_TYPE_CELL_RENDERER_ACTIVATABLE))
+#define EMPATHY_IS_CELL_RENDERER_ACTIVATABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EMPATHY_TYPE_CELL_RENDERER_ACTIVATABLE))
+#define EMPATHY_CELL_RENDERER_ACTIVATABLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_CELL_RENDERER_ACTIVATABLE, EmpathyCellRendererActivatableClass))
+
+typedef struct _EmpathyCellRendererActivatable EmpathyCellRendererActivatable;
+typedef struct _EmpathyCellRendererActivatableClass EmpathyCellRendererActivatableClass;
+
+struct _EmpathyCellRendererActivatable {
+ GtkCellRendererPixbuf parent;
+};
+
+struct _EmpathyCellRendererActivatableClass {
+ GtkCellRendererPixbufClass parent_class;
+};
+
+GType empathy_cell_renderer_activatable_get_type (void) G_GNUC_CONST;
+GtkCellRenderer *empathy_cell_renderer_activatable_new (void);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_CELL_RENDERER_ACTIVATABLE_H__ */
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-cell-renderer-expander.c b/gnome-2-22/libempathy-gtk/empathy-cell-renderer-expander.c
new file mode 100644
index 000000000..51930ab6a
--- /dev/null
+++ b/gnome-2-22/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 <kris@imendio.com>
+ */
+
+/* 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 <gtk/gtktreeview.h>
+
+#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/gnome-2-22/libempathy-gtk/empathy-cell-renderer-expander.h b/gnome-2-22/libempathy-gtk/empathy-cell-renderer-expander.h
new file mode 100644
index 000000000..d7e5f74b0
--- /dev/null
+++ b/gnome-2-22/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 <kris@imendio.com>
+ */
+
+#ifndef __EMPATHY_CELL_RENDERER_EXPANDER_H__
+#define __EMPATHY_CELL_RENDERER_EXPANDER_H__
+
+#include <gtk/gtkcellrenderer.h>
+
+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/gnome-2-22/libempathy-gtk/empathy-cell-renderer-text.c b/gnome-2-22/libempathy-gtk/empathy-cell-renderer-text.c
new file mode 100644
index 000000000..d48de32b8
--- /dev/null
+++ b/gnome-2-22/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 <micke@imendio.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#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/gnome-2-22/libempathy-gtk/empathy-cell-renderer-text.h b/gnome-2-22/libempathy-gtk/empathy-cell-renderer-text.h
new file mode 100644
index 000000000..76cef3120
--- /dev/null
+++ b/gnome-2-22/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 <micke@imendio.com>
+ */
+
+#ifndef __EMPATHY_CELL_RENDERER_TEXT_H__
+#define __EMPATHY_CELL_RENDERER_TEXT_H__
+
+#include <gtk/gtkcellrenderertext.h>
+
+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/gnome-2-22/libempathy-gtk/empathy-chat-view.c b/gnome-2-22/libempathy-gtk/empathy-chat-view.c
new file mode 100644
index 000000000..f4ad7f316
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-chat-view.c
@@ -0,0 +1,1570 @@
+/* -*- 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 <micke@imendio.com>
+ * Richard Hult <richard@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <string.h>
+#include <time.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtkmenu.h>
+#include <gtk/gtkmenuitem.h>
+#include <gtk/gtkimagemenuitem.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtkscrolledwindow.h>
+#include <gtk/gtksizegroup.h>
+#include <glade/glade.h>
+
+#include <telepathy-glib/util.h>
+#include <libmissioncontrol/mc-account.h>
+
+#include <libempathy/empathy-utils.h>
+#include <libempathy/empathy-debug.h>
+
+#include "empathy-chat-view.h"
+#include "empathy-chat.h"
+#include "empathy-conf.h"
+#include "empathy-preferences.h"
+#include "empathy-theme-manager.h"
+#include "empathy-ui-utils.h"
+#include "empathy-smiley-manager.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))
+
+struct _EmpathyChatViewPriv {
+ GtkTextBuffer *buffer;
+
+ EmpathyTheme *theme;
+
+ time_t last_timestamp;
+ EmpathyChatViewBlock 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;
+};
+
+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 gboolean chat_view_is_scrolled_down (EmpathyChatView *view);
+static void chat_view_theme_changed_cb (EmpathyThemeManager *manager,
+ EmpathyChatView *view);
+static void chat_view_theme_notify_cb (EmpathyTheme *theme,
+ GParamSpec *param,
+ EmpathyChatView *view);
+
+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 = EMPATHY_CHAT_VIEW_BLOCK_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_set_show_avatars (priv->theme, 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);
+ }
+
+ if (priv->theme) {
+ g_signal_handlers_disconnect_by_func (priv->theme,
+ chat_view_theme_notify_cb,
+ view);
+ g_object_unref (priv->theme);
+ }
+
+ 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;
+ EmpathyChatViewPriv *priv;
+ gboolean show_avatars = FALSE;
+
+ view = user_data;
+ priv = GET_PRIV (view);
+
+ 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_set_show_avatars (priv->theme, 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_set_show_avatars (priv->theme, 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 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_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 = EMPATHY_CHAT_VIEW_BLOCK_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_set_show_avatars (priv->theme, 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;
+}
+
+typedef struct {
+ GdkPixbuf *pixbuf;
+ gchar *token;
+} AvatarData;
+
+static void
+chat_view_avatar_cache_data_free (gpointer ptr)
+{
+ AvatarData *data = ptr;
+
+ g_object_unref (data->pixbuf);
+ g_free (data->token);
+ g_slice_free (AvatarData, data);
+}
+
+GdkPixbuf *
+empathy_chat_view_get_avatar_pixbuf_with_cache (EmpathyContact *contact)
+{
+ static GHashTable *avatar_cache = NULL;
+ AvatarData *data;
+ EmpathyAvatar *avatar;
+ GdkPixbuf *tmp_pixbuf;
+ GdkPixbuf *pixbuf = NULL;
+
+ /* Init avatar cache */
+ if (!avatar_cache) {
+ avatar_cache = g_hash_table_new_full (empathy_contact_hash,
+ empathy_contact_equal,
+ g_object_unref,
+ chat_view_avatar_cache_data_free);
+ }
+
+ /* Check if avatar is in cache and if it's up to date */
+ avatar = empathy_contact_get_avatar (contact);
+ data = g_hash_table_lookup (avatar_cache, contact);
+ if (data) {
+ if (avatar && !tp_strdiff (avatar->token, data->token)) {
+ /* We have the avatar in cache */
+ return data->pixbuf;
+ }
+
+ /* The cache is outdate */
+ g_hash_table_remove (avatar_cache, contact);
+ }
+
+ /* Avatar not in cache, create pixbuf */
+ tmp_pixbuf = empathy_pixbuf_avatar_from_contact_scaled (contact, 32, 32);
+ if (tmp_pixbuf) {
+ pixbuf = chat_view_pad_to_size (tmp_pixbuf, 32, 32, 6);
+ g_object_unref (tmp_pixbuf);
+ }
+ if (!pixbuf) {
+ return NULL;
+ }
+
+ /* Insert new pixbuf in cache */
+ data = g_slice_new0 (AvatarData);
+ data->token = g_strdup (avatar->token);
+ data->pixbuf = pixbuf;
+
+ g_hash_table_insert (avatar_cache,
+ g_object_ref (contact),
+ data);
+
+ return data->pixbuf;
+}
+
+EmpathyChatView *
+empathy_chat_view_new (void)
+{
+ return g_object_new (EMPATHY_TYPE_CHAT_VIEW, NULL);
+}
+
+void
+empathy_chat_view_append_message (EmpathyChatView *view,
+ EmpathyMessage *msg)
+{
+ EmpathyChatViewPriv *priv = GET_PRIV (view);
+ EmpathyContact *sender;
+ gboolean bottom;
+ gboolean from_self;
+
+ g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
+ g_return_if_fail (EMPATHY_IS_MESSAGE (msg));
+
+ if (!empathy_message_get_body (msg)) {
+ return;
+ }
+
+ bottom = chat_view_is_scrolled_down (view);
+ sender = empathy_message_get_sender (msg);
+ from_self = empathy_contact_is_user (sender);
+
+ chat_view_maybe_trim_buffer (view);
+
+ empathy_theme_append_message (priv->theme, view, msg);
+
+ if (bottom) {
+ empathy_chat_view_scroll_down (view);
+ }
+}
+
+void
+empathy_chat_view_append_event (EmpathyChatView *view,
+ const gchar *str)
+{
+ EmpathyChatViewPriv *priv;
+ gboolean bottom;
+
+ 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);
+
+ empathy_theme_append_event (priv->theme, view, str);
+
+ if (bottom) {
+ empathy_chat_view_scroll_down (view);
+ }
+
+ priv->last_block_type = EMPATHY_CHAT_VIEW_BLOCK_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);
+
+ tag = "invite";
+
+ bottom = chat_view_is_scrolled_down (view);
+
+ empathy_theme_append_timestamp (priv->theme, view, NULL, TRUE, TRUE);
+
+ if (message) {
+ empathy_theme_append_text (priv->theme, view, message, tag, NULL);
+ }
+
+ 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 = EMPATHY_CHAT_VIEW_BLOCK_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 = EMPATHY_CHAT_VIEW_BLOCK_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);
+}
+
+EmpathyTheme *
+empathy_chat_view_get_theme (EmpathyChatView *view)
+{
+ EmpathyChatViewPriv *priv;
+
+ g_return_val_if_fail (EMPATHY_IS_CHAT_VIEW (view), NULL);
+
+ priv = GET_PRIV (view);
+
+ return priv->theme;
+}
+
+static void
+chat_view_theme_notify_cb (EmpathyTheme *theme,
+ GParamSpec *param,
+ EmpathyChatView *view)
+{
+ empathy_theme_update_view (theme, view);
+}
+
+void
+empathy_chat_view_set_theme (EmpathyChatView *view, EmpathyTheme *theme)
+{
+ EmpathyChatViewPriv *priv;
+
+ g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
+ g_return_if_fail (EMPATHY_IS_THEME (theme));
+
+ priv = GET_PRIV (view);
+
+ if (priv->theme) {
+ g_signal_handlers_disconnect_by_func (priv->theme,
+ chat_view_theme_notify_cb,
+ view);
+ g_object_unref (priv->theme);
+ }
+
+ priv->theme = g_object_ref (theme);
+
+ empathy_theme_update_view (theme, view);
+ g_signal_connect (priv->theme, "notify",
+ G_CALLBACK (chat_view_theme_notify_cb),
+ view);
+
+ /* FIXME: Redraw all messages using the new theme */
+}
+
+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);
+}
+
+GtkWidget *
+empathy_chat_view_get_smiley_menu (GCallback callback,
+ gpointer user_data)
+{
+ EmpathySmileyManager *smiley_manager;
+ GSList *smileys, *l;
+ GtkWidget *menu;
+ gint x = 0;
+ gint y = 0;
+
+ g_return_val_if_fail (callback != NULL, NULL);
+
+ menu = gtk_menu_new ();
+
+ smiley_manager = empathy_smiley_manager_new ();
+ smileys = empathy_smiley_manager_get_all (smiley_manager);
+ for (l = smileys; l; l = l->next) {
+ EmpathySmiley *smiley;
+ GtkWidget *item;
+ GtkWidget *image;
+
+ smiley = l->data;
+ image = gtk_image_new_from_pixbuf (smiley->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);
+
+ gtk_widget_set_tooltip_text (item, smiley->str);
+
+ g_object_set_data (G_OBJECT (item), "smiley_text", smiley->str);
+ g_signal_connect (item, "activate", callback, user_data);
+
+ if (x > 3) {
+ y++;
+ x = 0;
+ } else {
+ x++;
+ }
+ }
+ g_object_unref (smiley_manager);
+
+ 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);
+ }
+}
+
+time_t
+empathy_chat_view_get_last_timestamp (EmpathyChatView *view)
+{
+ EmpathyChatViewPriv *priv;
+
+ g_return_val_if_fail (EMPATHY_IS_CHAT_VIEW (view), 0);
+
+ priv = GET_PRIV (view);
+
+ return priv->last_timestamp;
+}
+
+void
+empathy_chat_view_set_last_timestamp (EmpathyChatView *view,
+ time_t timestamp)
+{
+ EmpathyChatViewPriv *priv;
+
+ g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
+
+ priv = GET_PRIV (view);
+
+ priv->last_timestamp = timestamp;
+}
+
+EmpathyChatViewBlock
+empathy_chat_view_get_last_block_type (EmpathyChatView *view)
+{
+ EmpathyChatViewPriv *priv;
+
+ g_return_val_if_fail (EMPATHY_IS_CHAT_VIEW (view), 0);
+
+ priv = GET_PRIV (view);
+
+ return priv->last_block_type;
+}
+
+void
+empathy_chat_view_set_last_block_type (EmpathyChatView *view,
+ EmpathyChatViewBlock block_type)
+{
+ EmpathyChatViewPriv *priv;
+
+ g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
+
+ priv = GET_PRIV (view);
+
+ priv->last_block_type = block_type;
+}
+
+EmpathyContact *
+empathy_chat_view_get_last_contact (EmpathyChatView *view)
+{
+ EmpathyChatViewPriv *priv;
+
+ g_return_val_if_fail (EMPATHY_IS_CHAT_VIEW (view), NULL);
+
+ priv = GET_PRIV (view);
+
+ return priv->last_contact;
+}
+
+void
+empathy_chat_view_set_last_contact (EmpathyChatView *view, EmpathyContact *contact)
+{
+ EmpathyChatViewPriv *priv;
+
+ g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
+
+ priv = GET_PRIV (view);
+
+ if (priv->last_contact) {
+ g_object_unref (priv->last_contact);
+ priv->last_contact = NULL;
+ }
+
+ if (contact) {
+ priv->last_contact = g_object_ref (contact);
+ }
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-chat-view.h b/gnome-2-22/libempathy-gtk/empathy-chat-view.h
new file mode 100644
index 000000000..58219ca04
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-chat-view.h
@@ -0,0 +1,119 @@
+/* -*- 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 <micke@imendio.com>
+ * Richard Hult <richard@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ */
+
+#ifndef __EMPATHY_CHAT_VIEW_H__
+#define __EMPATHY_CHAT_VIEW_H__
+
+#include <gtk/gtktextview.h>
+
+#include <libempathy/empathy-contact.h>
+#include <libempathy/empathy-message.h>
+
+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;
+
+#include "empathy-theme.h"
+
+struct _EmpathyChatView {
+ GtkTextView parent;
+};
+
+struct _EmpathyChatViewClass {
+ GtkTextViewClass parent_class;
+};
+
+typedef enum {
+ EMPATHY_CHAT_VIEW_BLOCK_NONE,
+ EMPATHY_CHAT_VIEW_BLOCK_SELF,
+ EMPATHY_CHAT_VIEW_BLOCK_OTHER,
+ EMPATHY_CHAT_VIEW_BLOCK_EVENT,
+ EMPATHY_CHAT_VIEW_BLOCK_TIME,
+ EMPATHY_CHAT_VIEW_BLOCK_INVITE
+} EmpathyChatViewBlock;
+
+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);
+EmpathyTheme * empathy_chat_view_get_theme (EmpathyChatView *view);
+void empathy_chat_view_set_theme (EmpathyChatView *view,
+ EmpathyTheme *theme);
+void empathy_chat_view_set_margin (EmpathyChatView *view,
+ gint margin);
+GtkWidget * empathy_chat_view_get_smiley_menu (GCallback callback,
+ gpointer user_data);
+void empathy_chat_view_set_is_group_chat (EmpathyChatView *view,
+ gboolean is_group_chat);
+time_t empathy_chat_view_get_last_timestamp (EmpathyChatView *view);
+void empathy_chat_view_set_last_timestamp (EmpathyChatView *view,
+ time_t timestamp);
+EmpathyChatViewBlock empathy_chat_view_get_last_block_type (EmpathyChatView *view);
+void empathy_chat_view_set_last_block_type (EmpathyChatView *view,
+ EmpathyChatViewBlock block_type);
+EmpathyContact * empathy_chat_view_get_last_contact (EmpathyChatView *view);
+void empathy_chat_view_set_last_contact (EmpathyChatView *view,
+ EmpathyContact *contact);
+GdkPixbuf * empathy_chat_view_get_avatar_pixbuf_with_cache (EmpathyContact *contact);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_CHAT_VIEW_H__ */
diff --git a/gnome-2-22/libempathy-gtk/empathy-chat-window.c b/gnome-2-22/libempathy-gtk/empathy-chat-window.c
new file mode 100644
index 000000000..5e5a854c5
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-chat-window.c
@@ -0,0 +1,1892 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2003-2007 Imendio AB
+ * Copyright (C) 2007-2008 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 <micke@imendio.com>
+ * Richard Hult <richard@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ * Geert-Jan Van den Bogaerde <geertjan@gnome.org>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <glade/glade.h>
+#include <glib/gi18n.h>
+
+#include <libmissioncontrol/mission-control.h>
+
+#include <libempathy/empathy-contact-factory.h>
+#include <libempathy/empathy-contact-list.h>
+#include <libempathy/empathy-log-manager.h>
+#include <libempathy/empathy-chatroom-manager.h>
+#include <libempathy/empathy-contact.h>
+#include <libempathy/empathy-debug.h>
+#include <libempathy/empathy-message.h>
+#include <libempathy/empathy-utils.h>
+
+#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-conf.h"
+#include "empathy-preferences.h"
+#include "empathy-private-chat.h"
+#include "empathy-group-chat.h"
+//#include "empathy-sound.h"
+#include "empathy-ui-utils.h"
+#include "empathy-about-dialog.h"
+
+#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CHAT_WINDOW, EmpathyChatWindowPriv))
+
+#define DEBUG_DOMAIN "ChatWindow"
+
+struct _EmpathyChatWindowPriv {
+ EmpathyChatroomManager *chatroom_manager;
+ GList *chats;
+ GList *chats_new_msg;
+ GList *chats_composing;
+
+ EmpathyChat *current_chat;
+
+ gboolean page_added;
+ gboolean dnd_same_window;
+
+ GtkWidget *dialog;
+ GtkWidget *notebook;
+
+ /* Menu items. */
+ GtkWidget *menu_conv_clear;
+ GtkWidget *menu_conv_insert_smiley;
+ GtkWidget *menu_conv_call;
+ GtkWidget *menu_conv_call_separator;
+ 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;
+
+ GtkWidget *menu_help_contents;
+ GtkWidget *menu_help_about;
+
+ 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_call_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 void chat_window_help_contents_cb (GtkWidget *menuitem,
+ EmpathyChatWindow *window);
+static void chat_window_help_about_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);
+
+ 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_call", &priv->menu_conv_call,
+ "menu_conv_call_separator", &priv->menu_conv_call_separator,
+ "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,
+ "menu_help_contents", &priv->menu_help_contents,
+ "menu_help_about", &priv->menu_help_about,
+ 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_call", "activate", chat_window_call_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,
+ "menu_help_contents", "activate", chat_window_help_contents_cb,
+ "menu_help_about", "activate", chat_window_help_about_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 (GTK_NOTEBOOK (priv->notebook), "EmpathyChatWindow");
+ 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);
+ 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;
+
+ chat_window = l->data;
+
+ dialog = empathy_chat_window_get_dialog (chat_window);
+ if (empathy_window_get_is_visible (GTK_WINDOW (GTK_WINDOW (dialog)))) {
+ /* 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);
+ }
+
+ chat_windows = g_list_remove (chat_windows, window);
+ gtk_widget_destroy (priv->dialog);
+
+ 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;
+ gint n_chats;
+
+ priv = GET_PRIV (window);
+
+ n_chats = g_list_length (priv->chats);
+ if (n_chats == 1) {
+ gtk_window_set_title (GTK_WINDOW (priv->dialog),
+ empathy_chat_get_name (priv->current_chat));
+ } else {
+ gchar *title;
+
+ title = g_strdup_printf (_("Conversations (%d)"), 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,
+ empathy_chat_get_account (priv->current_chat),
+ 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;
+ EmpathyContact *contact;
+ McPresence presence;
+
+ chat = EMPATHY_PRIVATE_CHAT (priv->current_chat);
+
+ /* Show / Hide widgets */
+ gtk_widget_hide (priv->menu_room);
+
+ /* Unset presence means this contact refuses to send us his
+ * presence. By adding the contact we ask the contact to accept
+ * to send his presence. */
+ contact = empathy_private_chat_get_contact (chat);
+ presence = empathy_contact_get_presence (contact);
+ if (presence == MC_PRESENCE_UNSET) {
+ 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_call_activate_cb (GtkWidget *menuitem,
+ EmpathyChatWindow *window)
+{
+ EmpathyChatWindowPriv *priv;
+
+ priv = GET_PRIV (window);
+
+ if (!empathy_chat_is_group_chat (priv->current_chat)) {
+ EmpathyPrivateChat *chat;
+ EmpathyContact *contact;
+
+ chat = EMPATHY_PRIVATE_CHAT (priv->current_chat);
+ contact = empathy_private_chat_get_contact (chat);
+
+ empathy_call_with_contact (contact);
+ }
+}
+
+static void
+chat_window_log_activate_cb (GtkWidget *menuitem,
+ EmpathyChatWindow *window)
+{
+ EmpathyChatWindowPriv *priv;
+
+ priv = GET_PRIV (window);
+
+ empathy_log_window_show (empathy_chat_get_account (priv->current_chat),
+ 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, 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);
+
+ if (priv->save_geometry_id != 0) {
+ g_source_remove (priv->save_geometry_id);
+ }
+
+ priv->save_geometry_id =
+ g_timeout_add_seconds (1,
+ (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;
+ gboolean can_voip = FALSE;
+
+ priv = GET_PRIV (window);
+
+ manager = empathy_log_manager_new ();
+ log_exists = empathy_log_manager_exists (manager,
+ empathy_chat_get_account (priv->current_chat),
+ empathy_chat_get_id (priv->current_chat),
+ empathy_chat_is_group_chat (priv->current_chat));
+ g_object_unref (manager);
+
+ if (!empathy_chat_is_group_chat (priv->current_chat)) {
+ EmpathyPrivateChat *chat;
+ EmpathyContact *contact;
+
+ chat = EMPATHY_PRIVATE_CHAT (priv->current_chat);
+ contact = empathy_private_chat_get_contact (chat);
+ can_voip = empathy_contact_can_voip (contact);
+ }
+
+ gtk_widget_set_sensitive (priv->menu_conv_log, log_exists);
+#ifdef HAVE_VOIP
+ gtk_widget_set_sensitive (priv->menu_conv_call, can_voip);
+#else
+ g_object_set (priv->menu_conv_call, "visible", FALSE, NULL);
+ g_object_set (priv->menu_conv_call_separator, "visible", FALSE, NULL);
+#endif
+}
+
+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 (empathy_chat_get_account (priv->current_chat),
+ 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 void
+chat_window_help_contents_cb (GtkWidget *menuitem,
+ EmpathyChatWindow *window)
+{
+ //empathy_help_show ();
+}
+
+static void
+chat_window_help_about_cb (GtkWidget *menuitem,
+ EmpathyChatWindow *window)
+{
+ empathy_about_dialog_new (GTK_WINDOW (window));
+}
+
+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_widget_set_tooltip_text (widget, str);
+
+ 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)
+{
+ if (info == DND_DRAG_TYPE_CONTACT_ID) {
+ EmpathyContactFactory *factory;
+ EmpathyContact *contact = NULL;
+ EmpathyChat *chat;
+ EmpathyChatWindow *old_window;
+ McAccount *account;
+ const gchar *id = NULL;
+ gchar **strv;
+
+ if (selection) {
+ id = (const gchar*) selection->data;
+ }
+
+ empathy_debug (DEBUG_DOMAIN, "DND contact from roster with id:'%s'", id);
+
+ strv = g_strsplit (id, "/", 2);
+ factory = empathy_contact_factory_new ();
+ account = mc_account_lookup (strv[0]);
+ if (account) {
+ contact = empathy_contact_factory_get_from_id (factory,
+ account,
+ strv[1]);
+ g_object_unref (account);
+ }
+ g_object_unref (factory);
+ g_object_unref (account);
+ g_strfreev (strv);
+
+ 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);
+
+ if (!chat) {
+ empathy_chat_with_contact_id (account, id);
+ return;
+ }
+
+ 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 void
+chat_window_set_urgency_hint (EmpathyChatWindow *window,
+ gboolean urgent)
+{
+ EmpathyChatWindowPriv *priv;
+
+ priv = GET_PRIV (window);
+
+ empathy_debug (DEBUG_DOMAIN, "Turning %s urgency hint",
+ urgent ? "on" : "off");
+ gtk_window_set_urgency_hint (GTK_WINDOW (priv->dialog), urgent);
+}
+
+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;
+ gint x, y, w, h;
+
+ g_return_if_fail (window != NULL);
+ g_return_if_fail (EMPATHY_IS_CHAT (chat));
+
+ priv = GET_PRIV (window);
+
+ /* Reference the chat object */
+ g_object_ref (chat);
+
+ /* Set the chat window */
+ empathy_chat_set_window (chat, window);
+
+ 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;
+
+ g_return_if_fail (window != NULL);
+ g_return_if_fail (EMPATHY_IS_CHAT (chat));
+
+ 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;
+
+ g_return_if_fail (window != NULL);
+ g_return_if_fail (EMPATHY_IS_CHAT (chat));
+
+ 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;
+
+ g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
+ g_return_val_if_fail (!G_STR_EMPTY (id), NULL);
+
+ 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, empathy_chat_get_account (chat)) &&
+ strcmp (id, empathy_chat_get_id (chat)) == 0) {
+ return chat;
+ }
+ }
+ }
+
+ return NULL;
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-chat-window.h b/gnome-2-22/libempathy-gtk/empathy-chat-window.h
new file mode 100644
index 000000000..c79f7519e
--- /dev/null
+++ b/gnome-2-22/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 <micke@imendio.com>
+ * Richard Hult <richard@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ * Geert-Jan Van den Bogaerde <geertjan@gnome.org>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_CHAT_WINDOW_H__
+#define __EMPATHY_CHAT_WINDOW_H__
+
+#include <glib-object.h>
+
+#include <libmissioncontrol/mc-account.h>
+
+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/gnome-2-22/libempathy-gtk/empathy-chat.c b/gnome-2-22/libempathy-gtk/empathy-chat.c
new file mode 100644
index 000000000..b02452476
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-chat.c
@@ -0,0 +1,1761 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002-2007 Imendio AB
+ * Copyright (C) 2007-2008 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 <micke@imendio.com>
+ * Richard Hult <richard@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ * Geert-Jan Van den Bogaerde <geertjan@gnome.org>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include <libmissioncontrol/mission-control.h>
+
+#include <libempathy/empathy-contact-manager.h>
+#include <libempathy/empathy-log-manager.h>
+#include <libempathy/empathy-debug.h>
+#include <libempathy/empathy-utils.h>
+
+#include "empathy-chat.h"
+#include "empathy-chat-window.h"
+#include "empathy-geometry.h"
+#include "empathy-conf.h"
+#include "empathy-preferences.h"
+#include "empathy-spell.h"
+#include "empathy-spell-dialog.h"
+#include "empathy-ui-utils.h"
+#include "empathy-gtk-marshal.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 {
+ EmpathyLogManager *log_manager;
+ EmpathyTpChat *tp_chat;
+ EmpathyChatWindow *window;
+ McAccount *account;
+ MissionControl *mc;
+ 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;
+ gboolean is_first_char;
+ guint block_events_timeout_id;
+ /* 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);
+static void chat_send_error_cb (EmpathyTpChat *tp_chat,
+ EmpathyMessage *message,
+ TpChannelTextSendError error_code,
+ EmpathyChat *chat);
+static void chat_sent_message_add (EmpathyChat *chat,
+ const gchar *str);
+static const gchar * chat_sent_message_get_next (EmpathyChat *chat);
+static 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,
+ TpChannelChatState 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
+};
+
+enum {
+ PROP_0,
+ PROP_TP_CHAT
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (EmpathyChat, empathy_chat, G_TYPE_OBJECT);
+
+static void
+chat_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EmpathyChatPriv *priv = GET_PRIV (object);
+
+ switch (param_id) {
+ case PROP_TP_CHAT:
+ g_value_set_object (value, priv->tp_chat);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ };
+}
+
+static void
+chat_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EmpathyChat *chat = EMPATHY_CHAT (object);
+
+ switch (param_id) {
+ case PROP_TP_CHAT:
+ empathy_chat_set_tp_chat (chat,
+ EMPATHY_TP_CHAT (g_value_get_object (value)));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ };
+}
+
+static void
+chat_status_changed_cb (MissionControl *mc,
+ TpConnectionStatus status,
+ McPresence presence,
+ TpConnectionStatusReason reason,
+ const gchar *unique_name,
+ EmpathyChat *chat)
+{
+ EmpathyChatPriv *priv = GET_PRIV (chat);
+ McAccount *account;
+
+ account = mc_account_lookup (unique_name);
+
+ if (status == TP_CONNECTION_STATUS_CONNECTED && !priv->tp_chat &&
+ empathy_account_equal (account, priv->account)) {
+ TpHandleType handle_type;
+
+ empathy_debug (DEBUG_DOMAIN,
+ "Account reconnected, request a new Text channel");
+
+ if (empathy_chat_is_group_chat (chat)) {
+ handle_type = TP_HANDLE_TYPE_ROOM;
+ } else {
+ handle_type = TP_HANDLE_TYPE_CONTACT;
+ }
+
+ mission_control_request_channel_with_string_handle (mc,
+ priv->account,
+ TP_IFACE_CHANNEL_TYPE_TEXT,
+ priv->id,
+ handle_type,
+ NULL, NULL);
+ }
+
+ g_object_unref (account);
+}
+
+static void
+empathy_chat_class_init (EmpathyChatClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = chat_finalize;
+ object_class->get_property = chat_get_property;
+ object_class->set_property = chat_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_TP_CHAT,
+ g_param_spec_object ("tp-chat",
+ "Empathy tp chat",
+ "The tp chat object",
+ EMPATHY_TYPE_TP_CHAT,
+ G_PARAM_CONSTRUCT |
+ G_PARAM_READWRITE));
+
+ 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_gtk_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 = GET_PRIV (chat);
+ GtkTextBuffer *buffer;
+
+ chat->view = empathy_chat_view_new ();
+ chat->input_text_view = gtk_text_view_new ();
+
+ priv->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->log_manager = empathy_log_manager_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;
+ priv->mc = empathy_mission_control_new ();
+
+ dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc), "AccountStatusChanged",
+ G_CALLBACK (chat_status_changed_cb),
+ chat, NULL);
+
+ 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 (priv->log_manager);
+
+ dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc), "AccountStatusChanged",
+ G_CALLBACK (chat_status_changed_cb),
+ chat);
+ g_object_unref (priv->mc);
+
+
+ if (priv->tp_chat) {
+ g_object_unref (priv->tp_chat);
+ }
+
+ if (priv->account) {
+ g_object_unref (priv->account);
+ }
+
+ if (priv->scroll_idle_id) {
+ g_source_remove (priv->scroll_idle_id);
+ }
+
+ if (priv->block_events_timeout_id) {
+ g_source_remove (priv->block_events_timeout_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 (priv->block_events_timeout_id != 0) {
+ g_source_remove (priv->block_events_timeout_id);
+ }
+
+ 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);
+
+ priv->is_first_char = TRUE;
+}
+
+static void
+chat_message_received_cb (EmpathyTpChat *tp_chat,
+ EmpathyMessage *message,
+ EmpathyChat *chat)
+{
+ EmpathyChatPriv *priv;
+ EmpathyContact *sender;
+
+ priv = GET_PRIV (chat);
+
+ sender = empathy_message_get_sender (message);
+ empathy_debug (DEBUG_DOMAIN, "Appending message ('%s')",
+ empathy_contact_get_name (sender));
+
+ 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);
+ }
+
+ /* We received a message so the contact is no more composing */
+ chat_state_changed_cb (tp_chat, sender,
+ TP_CHANNEL_CHAT_STATE_ACTIVE,
+ chat);
+
+ g_signal_emit (chat, signals[NEW_MESSAGE], 0, message, FALSE);
+}
+
+static void
+chat_send_error_cb (EmpathyTpChat *tp_chat,
+ EmpathyMessage *message,
+ TpChannelTextSendError error_code,
+ EmpathyChat *chat)
+{
+ const gchar *error;
+ gchar *str;
+
+ switch (error_code) {
+ case TP_CHANNEL_TEXT_SEND_ERROR_OFFLINE:
+ error = _("offline");
+ break;
+ case TP_CHANNEL_TEXT_SEND_ERROR_INVALID_CONTACT:
+ error = _("invalid contact");
+ break;
+ case TP_CHANNEL_TEXT_SEND_ERROR_PERMISSION_DENIED:
+ error = _("permission denied");
+ break;
+ case TP_CHANNEL_TEXT_SEND_ERROR_TOO_LONG:
+ error = _("too long message");
+ break;
+ case TP_CHANNEL_TEXT_SEND_ERROR_NOT_IMPLEMENTED:
+ error = _("not implemented");
+ break;
+ default:
+ error = _("unknown");
+ break;
+ }
+
+ str = g_strdup_printf (_("Error sending message '%s': %s"),
+ empathy_message_get_body (message),
+ error);
+ empathy_chat_view_append_event (chat->view, str);
+ g_free (str);
+}
+
+static 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;
+}
+
+static 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);
+}
+
+static 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);
+
+ /* 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/control-enter. */
+ return FALSE;
+ }
+ else if (!(event->state & 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;
+ }
+
+ if (EMPATHY_CHAT_GET_CLASS (chat)->key_press_event) {
+ return EMPATHY_CHAT_GET_CLASS (chat)->key_press_event (chat, event);
+ }
+
+ 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 (priv->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 = &GTK_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;
+
+ priv->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 = &GTK_WIDGET (chat->view)->allocation;
+
+ dialog = empathy_chat_window_get_dialog (priv->window);
+ gtk_window_get_size (GTK_WINDOW (dialog), NULL, &current_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);
+ 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_seconds (
+ 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,
+ TpChannelChatState 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_PAUSED:
+ 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_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);
+
+ /* 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,
+ priv->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);
+}
+
+static const gchar *
+chat_get_window_id_for_geometry (EmpathyChat *chat)
+{
+ gboolean separate_windows;
+
+ empathy_conf_get_bool (empathy_conf_get (),
+ EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS,
+ &separate_windows);
+
+ if (separate_windows) {
+ return empathy_chat_get_id (chat);
+ } else {
+ return "chat-window";
+ }
+}
+
+void
+empathy_chat_save_geometry (EmpathyChat *chat,
+ gint x,
+ gint y,
+ gint w,
+ gint h)
+{
+ empathy_geometry_save (chat_get_window_id_for_geometry (chat), x, y, w, h);
+}
+
+void
+empathy_chat_load_geometry (EmpathyChat *chat,
+ gint *x,
+ gint *y,
+ gint *w,
+ gint *h)
+{
+ empathy_geometry_load (chat_get_window_id_for_geometry (chat), x, y, w, h);
+}
+
+static gboolean
+chat_block_events_timeout_cb (gpointer data)
+{
+ EmpathyChat *chat = EMPATHY_CHAT (data);
+ EmpathyChatPriv *priv = GET_PRIV (chat);
+
+ chat->block_events = FALSE;
+ priv->block_events_timeout_id = 0;
+
+ return FALSE;
+}
+
+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;
+ }
+
+ /* Block events for some time to avoid having "has come online" or
+ * "joined" messages. */
+ chat->block_events = TRUE;
+ if (priv->block_events_timeout_id != 0) {
+ g_source_remove (priv->block_events_timeout_id);
+ }
+ priv->block_events_timeout_id =
+ g_timeout_add_seconds (1, chat_block_events_timeout_cb, chat);
+
+ 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_send_error_cb,
+ chat);
+ g_signal_handlers_disconnect_by_func (priv->tp_chat,
+ chat_destroy_cb,
+ chat);
+ g_object_unref (priv->tp_chat);
+ }
+ if (priv->account) {
+ g_object_unref (priv->account);
+ }
+
+ g_free (priv->id);
+ priv->tp_chat = g_object_ref (tp_chat);
+ priv->id = g_strdup (empathy_tp_chat_get_id (tp_chat));
+ priv->account = g_object_ref (empathy_tp_chat_get_account (tp_chat));
+ empathy_tp_chat_set_acknowledge (tp_chat, TRUE);
+
+ 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, "send-error",
+ G_CALLBACK (chat_send_error_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);
+
+ 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);
+ }
+
+ g_object_notify (G_OBJECT (chat), "tp-chat");
+}
+
+const gchar *
+empathy_chat_get_id (EmpathyChat *chat)
+{
+ EmpathyChatPriv *priv;
+
+ priv = GET_PRIV (chat);
+
+ return priv->id;
+}
+
+McAccount *
+empathy_chat_get_account (EmpathyChat *chat)
+{
+ EmpathyChatPriv *priv = GET_PRIV (chat);
+
+ return priv->account;
+}
+
+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/gnome-2-22/libempathy-gtk/empathy-chat.glade b/gnome-2-22/libempathy-gtk/empathy-chat.glade
new file mode 100644
index 000000000..ca6dd56d0
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-chat.glade
@@ -0,0 +1,756 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="chat_page_window">
+ <property name="title" translatable="yes">Chat</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="default_width">350</property>
+ <property name="default_height">250</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="chat_widget">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">3</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="chat_view_sw">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="input_text_view_sw">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkWindow" id="chat_window">
+ <property name="title" translatable="yes">Chat</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="default_width">350</property>
+ <property name="default_height">250</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="chat_vbox">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkMenuBar" id="chats_menubar">
+ <property name="visible">True</property>
+ <property name="pack_direction">GTK_PACK_DIRECTION_LTR</property>
+ <property name="child_pack_direction">GTK_PACK_DIRECTION_LTR</property>
+
+ <child>
+ <widget class="GtkMenuItem" id="menu_conv">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Conversation</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="menu_conv_menu">
+
+ <child>
+ <widget class="GtkImageMenuItem" id="menu_conv_clear">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">C_lear</property>
+ <property name="use_underline">True</property>
+ <accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image262">
+ <property name="visible">True</property>
+ <property name="stock">gtk-clear</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menu_conv_insert_smiley">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Insert _Smiley</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator13">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="menu_conv_call">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Ca_ll</property>
+ <property name="use_underline">True</property>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="menu_conv_call_image">
+ <property name="visible">True</property>
+ <property name="icon_name">gnome-stock-mic</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="menu_conv_call_separator">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="menu_conv_log">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_View Previous Conversations</property>
+ <property name="use_underline">True</property>
+ <accelerator key="F3" modifiers="0" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image263">
+ <property name="visible">True</property>
+ <property name="icon_name">document-open-recent</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="menu_conv_separator">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="menu_conv_add_contact">
+ <property name="label" translatable="yes">_Add Contact...</property>
+ <property name="use_underline">True</property>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image264">
+ <property name="visible">True</property>
+ <property name="stock">gtk-add</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="menu_conv_info">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Contact Infor_mation</property>
+ <property name="use_underline">True</property>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image265">
+ <property name="visible">True</property>
+ <property name="stock">gtk-info</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator7">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="menu_conv_close">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Close</property>
+ <property name="use_underline">True</property>
+ <accelerator key="W" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image266">
+ <property name="visible">True</property>
+ <property name="stock">gtk-close</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menu_room">
+ <property name="label" translatable="yes">_Room</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="menu_room_menu">
+
+ <child>
+ <widget class="GtkMenuItem" id="menu_room_set_topic">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Change _Topic...</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator12">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menu_room_join_new">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Join _New...</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menu_room_invite">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">In_vite...</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator7">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="menu_room_add">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Add To Favorites</property>
+ <property name="use_underline">True</property>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image268">
+ <property name="visible">True</property>
+ <property name="stock">gtk-add</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator10">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkCheckMenuItem" id="menu_room_show_contacts">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Show Contacts</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <accelerator key="F11" modifiers="0" signal="activate"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menu_edit">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Edit</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="menu_edit_menu">
+
+ <child>
+ <widget class="GtkImageMenuItem" id="menu_edit_cut">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Cu_t</property>
+ <property name="use_underline">True</property>
+ <accelerator key="X" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image269">
+ <property name="visible">True</property>
+ <property name="stock">gtk-cut</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="menu_edit_copy">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Copy</property>
+ <property name="use_underline">True</property>
+ <accelerator key="C" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image270">
+ <property name="visible">True</property>
+ <property name="stock">gtk-copy</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="menu_edit_paste">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Paste</property>
+ <property name="use_underline">True</property>
+ <accelerator key="V" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image271">
+ <property name="visible">True</property>
+ <property name="stock">gtk-paste</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menu_tabs">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Tabs</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="menu_tabs_menu">
+
+ <child>
+ <widget class="GtkMenuItem" id="menu_tabs_prev">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Previous Tab</property>
+ <property name="use_underline">True</property>
+ <accelerator key="Page_Up" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menu_tabs_next">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Next Tab</property>
+ <property name="use_underline">True</property>
+ <accelerator key="Page_Down" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator4">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menu_tabs_left">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Move Tab _Left</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menu_tabs_right">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Move Tab _Right</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menu_tabs_detach">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Detach Tab</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="menu_help">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Help</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="menu_help_menu">
+
+ <child>
+ <widget class="GtkImageMenuItem" id="menu_help_contents">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Contents</property>
+ <property name="use_underline">True</property>
+ <accelerator key="F1" modifiers="0" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image289">
+ <property name="visible">True</property>
+ <property name="stock">gtk-help</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="menu_help_about">
+ <property name="visible">True</property>
+ <property name="label">gtk-about</property>
+ <property name="use_stock">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="chat_invite_dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Invite</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="modal">True</property>
+ <property name="default_width">275</property>
+ <property name="default_height">225</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="vbox6">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="hbuttonbox1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="button_cancel">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button_invite">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">In_vite</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox7">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox7">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Select who would you like to invite:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox8">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Invitation _message:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes">You have been invited to join a chat conference.</property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">True</property>
+ <property name="width_chars">40</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-chat.h b/gnome-2-22/libempathy-gtk/empathy-chat.h
new file mode 100644
index 000000000..bcf382e53
--- /dev/null
+++ b/gnome-2-22/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 <micke@imendio.com>
+ * Richard Hult <richard@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ * Geert-Jan Van den Bogaerde <geertjan@gnome.org>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_CHAT_H__
+#define __EMPATHY_CHAT_H__
+
+#include <glib-object.h>
+
+#include <libempathy/empathy-contact.h>
+#include <libempathy/empathy-message.h>
+#include <libempathy/empathy-tp-chat.h>
+
+#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;
+ GtkWidget *input_text_view;
+ gboolean block_events;
+};
+
+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);
+ gboolean (*key_press_event) (EmpathyChat *chat,
+ GdkEventKey *event);
+};
+
+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);
+McAccount * empathy_chat_get_account (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/gnome-2-22/libempathy-gtk/empathy-chatrooms-window.c b/gnome-2-22/libempathy-gtk/empathy-chatrooms-window.c
new file mode 100644
index 000000000..83d305212
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-chatrooms-window.c
@@ -0,0 +1,582 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2004-2007 Imendio AB
+ * Copyright (C) 2007-2008 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 <xclaesse@gmail.com>
+ * Martyn Russell <martyn@imendio.com>
+ * Mikael Hallendal <micke@imendio.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <libempathy/empathy-chatroom-manager.h>
+#include <libempathy/empathy-utils.h>
+
+#include "empathy-account-chooser.h"
+#include "empathy-chatrooms-window.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_filter (EMPATHY_ACCOUNT_CHOOSER (window->account_chooser),
+ empathy_account_chooser_filter_is_connected,
+ NULL);
+ empathy_account_chooser_set_account (EMPATHY_ACCOUNT_CHOOSER (window->account_chooser), NULL);
+ g_object_set (window->account_chooser,
+ "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_signal_handlers_disconnect_by_func (window->manager,
+ chatrooms_window_chatroom_added_cb,
+ window);
+ g_signal_handlers_disconnect_by_func (window->manager,
+ chatrooms_window_chatroom_removed_cb,
+ 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/gnome-2-22/libempathy-gtk/empathy-chatrooms-window.glade b/gnome-2-22/libempathy-gtk/empathy-chatrooms-window.glade
new file mode 100644
index 000000000..6d47c0936
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-chatrooms-window.glade
@@ -0,0 +1,477 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkDialog" id="edit_chatroom_dialog">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Edit Favorite Room</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">False</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="icon_name">gtk-edit</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox3">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area3">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="button_cancel">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button_save">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-save</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table4">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="n_rows">5</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkEntry" id="entry_room">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_server">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_nickname">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_room">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Room:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_room</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_server">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">S_erver:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_server</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_nickname">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Nickname:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_nickname</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_name">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">N_ame:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_name</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_name">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ <property name="width_chars">25</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton_auto_connect">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Join this chat room when Empathy starts and you are connected</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Join room on start_up</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkWindow" id="chatrooms_window">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Manage Favorite Rooms</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox12">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox18">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox_account">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label_account">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Account:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="height_request">150</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox3">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkButton" id="button_remove">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-remove</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button_edit">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-edit</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button_close">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-chatrooms-window.h b/gnome-2-22/libempathy-gtk/empathy-chatrooms-window.h
new file mode 100644
index 000000000..179082052
--- /dev/null
+++ b/gnome-2-22/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 <xclaesse@gmail.com>
+ * Martyn Russell <martyn@imendio.com>
+ * Mikael Hallendal <micke@imendio.com>
+ */
+
+#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/gnome-2-22/libempathy-gtk/empathy-conf.c b/gnome-2-22/libempathy-gtk/empathy-conf.c
new file mode 100644
index 000000000..1ec3feeb4
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-conf.c
@@ -0,0 +1,373 @@
+/* -*- 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 <richard@imendio.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gconf/gconf-client.h>
+
+#include <libempathy/empathy-debug.h>
+
+#include "empathy-conf.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/gnome-2-22/libempathy-gtk/empathy-conf.h b/gnome-2-22/libempathy-gtk/empathy-conf.h
new file mode 100644
index 000000000..7e8e60e25
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/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 <glib-object.h>
+
+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/gnome-2-22/libempathy-gtk/empathy-contact-dialogs.c b/gnome-2-22/libempathy-gtk/empathy-contact-dialogs.c
new file mode 100644
index 000000000..e0785c3ce
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-contact-dialogs.c
@@ -0,0 +1,344 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007-2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <glib/gi18n.h>
+
+#include <libmissioncontrol/mission-control.h>
+
+#include <libempathy/empathy-contact-manager.h>
+#include <libempathy/empathy-contact-list.h>
+#include <libempathy/empathy-utils.h>
+
+#include "empathy-contact-dialogs.h"
+#include "empathy-contact-widget.h"
+#include "empathy-ui-utils.h"
+
+static GList *subscription_dialogs = NULL;
+static GList *information_dialogs = NULL;
+static GtkWidget *new_contact_dialog = NULL;
+
+
+static gint
+contact_dialogs_find (GtkDialog *dialog,
+ EmpathyContact *contact)
+{
+ GtkWidget *contact_widget;
+ EmpathyContact *this_contact;
+
+ contact_widget = g_object_get_data (G_OBJECT (dialog), "contact_widget");
+ this_contact = empathy_contact_widget_get_contact (contact_widget);
+
+ return !empathy_contact_equal (contact, this_contact);
+}
+
+/*
+ * Subscription dialog
+ */
+
+static void
+subscription_dialog_response_cb (GtkDialog *dialog,
+ gint response,
+ GtkWidget *contact_widget)
+{
+ EmpathyContactManager *manager;
+ EmpathyContact *contact;
+
+ manager = empathy_contact_manager_new ();
+ contact = empathy_contact_widget_get_contact (contact_widget);
+
+ if (response == GTK_RESPONSE_YES) {
+ empathy_contact_list_add (EMPATHY_CONTACT_LIST (manager),
+ contact, "");
+ }
+ else if (response == GTK_RESPONSE_NO) {
+ empathy_contact_list_remove (EMPATHY_CONTACT_LIST (manager),
+ contact, "");
+ }
+
+ subscription_dialogs = g_list_remove (subscription_dialogs, dialog);
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ g_object_unref (manager);
+}
+
+void
+empathy_subscription_dialog_show (EmpathyContact *contact,
+ GtkWindow *parent)
+{
+ GtkWidget *dialog;
+ GtkWidget *hbox_subscription;
+ GtkWidget *contact_widget;
+ GList *l;
+
+ g_return_if_fail (EMPATHY_IS_CONTACT (contact));
+
+ l = g_list_find_custom (subscription_dialogs,
+ contact,
+ (GCompareFunc) contact_dialogs_find);
+ if (l) {
+ gtk_window_present (GTK_WINDOW (l->data));
+ return;
+ }
+
+ empathy_glade_get_file_simple ("empathy-contact-dialogs.glade",
+ "subscription_request_dialog",
+ NULL,
+ "subscription_request_dialog", &dialog,
+ "hbox_subscription", &hbox_subscription,
+ NULL);
+
+ contact_widget = empathy_contact_widget_new (contact,
+ EMPATHY_CONTACT_WIDGET_EDIT_ALIAS |
+ EMPATHY_CONTACT_WIDGET_EDIT_GROUPS);
+ gtk_box_pack_end (GTK_BOX (hbox_subscription),
+ contact_widget,
+ TRUE, TRUE,
+ 0);
+
+ g_object_set_data (G_OBJECT (dialog), "contact_widget", contact_widget);
+ subscription_dialogs = g_list_prepend (subscription_dialogs, dialog);
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (subscription_dialog_response_cb),
+ contact_widget);
+
+ if (parent) {
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
+ }
+
+ gtk_widget_show (dialog);
+}
+
+/*
+ * Information dialog
+ */
+
+static void
+contact_information_response_cb (GtkDialog *dialog,
+ gint response,
+ GtkWidget *contact_widget)
+{
+ information_dialogs = g_list_remove (information_dialogs, dialog);
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+void
+empathy_contact_information_dialog_show (EmpathyContact *contact,
+ GtkWindow *parent,
+ gboolean edit,
+ gboolean is_user)
+{
+ GtkWidget *dialog;
+ GtkWidget *button;
+ GtkWidget *contact_widget;
+ GList *l;
+ EmpathyContactWidgetFlags flags = 0;
+
+ g_return_if_fail (EMPATHY_IS_CONTACT (contact));
+
+ l = g_list_find_custom (information_dialogs,
+ contact,
+ (GCompareFunc) contact_dialogs_find);
+ if (l) {
+ gtk_window_present (GTK_WINDOW (l->data));
+ return;
+ }
+
+ /* Create dialog */
+ dialog = gtk_dialog_new ();
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ if (is_user) {
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Personal Information"));
+ }
+ else if (edit) {
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Edit Contact Information"));
+ }
+ else {
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Contact Information"));
+ }
+
+ /* Close button */
+ button = gtk_button_new_with_label (GTK_STOCK_CLOSE);
+ gtk_button_set_use_stock (GTK_BUTTON (button), TRUE);
+ gtk_dialog_add_action_widget (GTK_DIALOG (dialog),
+ button,
+ GTK_RESPONSE_CLOSE);
+ gtk_widget_show (button);
+
+ /* Contact info widget */
+ if (edit) {
+ flags |= EMPATHY_CONTACT_WIDGET_EDIT_ALIAS;
+ }
+ if (is_user) {
+ flags |= EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT;
+ flags |= EMPATHY_CONTACT_WIDGET_EDIT_AVATAR;
+ }
+ if (!is_user && edit) {
+ flags |= EMPATHY_CONTACT_WIDGET_EDIT_GROUPS;
+ }
+ contact_widget = empathy_contact_widget_new (contact, flags);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+ contact_widget,
+ TRUE, TRUE, 0);
+ if (flags & EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT) {
+ empathy_contact_widget_set_account_filter (contact_widget,
+ empathy_account_chooser_filter_is_connected,
+ NULL);
+ }
+
+ g_object_set_data (G_OBJECT (dialog), "contact_widget", contact_widget);
+ information_dialogs = g_list_prepend (information_dialogs, dialog);
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (contact_information_response_cb),
+ contact_widget);
+
+ if (parent) {
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
+ }
+
+ gtk_widget_show (dialog);
+}
+
+/*
+ * New contact dialog
+ */
+
+static gboolean
+can_add_contact_to_account (McAccount *account,
+ gpointer user_data)
+{
+ MissionControl *mc;
+ TpConnectionStatus status;
+ McProfile *profile;
+ const gchar *protocol_name;
+
+ mc = empathy_mission_control_new ();
+ status = mission_control_get_connection_status (mc, account, NULL);
+ g_object_unref (mc);
+ if (status != TP_CONNECTION_STATUS_CONNECTED) {
+ /* Account is disconnected */
+ return FALSE;
+ }
+
+ profile = mc_account_get_profile (account);
+ protocol_name = mc_profile_get_protocol_name (profile);
+ if (strcmp (protocol_name, "local-xmpp") == 0) {
+ /* We can't add accounts to a XMPP LL connection
+ * FIXME: We should inspect the flags of the contact list group interface
+ */
+ g_object_unref (profile);
+ return FALSE;
+ }
+
+ g_object_unref (profile);
+ return TRUE;
+}
+
+static void
+new_contact_response_cb (GtkDialog *dialog,
+ gint response,
+ GtkWidget *contact_widget)
+{
+ EmpathyContactManager *manager;
+ EmpathyContact *contact;
+
+ manager = empathy_contact_manager_new ();
+ contact = empathy_contact_widget_get_contact (contact_widget);
+
+ if (contact && response == GTK_RESPONSE_OK) {
+ empathy_contact_list_add (EMPATHY_CONTACT_LIST (manager),
+ contact,
+ _("I would like to add you to my contact list."));
+ }
+
+ new_contact_dialog = NULL;
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ g_object_unref (manager);
+}
+
+void
+empathy_new_contact_dialog_show (GtkWindow *parent)
+{
+ GtkWidget *dialog;
+ GtkWidget *button;
+ GtkWidget *contact_widget;
+
+ if (new_contact_dialog) {
+ gtk_window_present (GTK_WINDOW (new_contact_dialog));
+ return;
+ }
+
+ /* Create dialog */
+ dialog = gtk_dialog_new ();
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ gtk_window_set_title (GTK_WINDOW (dialog), _("New Contact"));
+
+ /* Cancel button */
+ button = gtk_button_new_with_label (GTK_STOCK_CANCEL);
+ gtk_button_set_use_stock (GTK_BUTTON (button), TRUE);
+ gtk_dialog_add_action_widget (GTK_DIALOG (dialog),
+ button,
+ GTK_RESPONSE_CANCEL);
+ gtk_widget_show (button);
+
+ /* Add button */
+ button = gtk_button_new_with_label (GTK_STOCK_ADD);
+ gtk_button_set_use_stock (GTK_BUTTON (button), TRUE);
+ gtk_dialog_add_action_widget (GTK_DIALOG (dialog),
+ button,
+ GTK_RESPONSE_OK);
+ gtk_widget_show (button);
+
+ /* Contact info widget */
+ contact_widget = empathy_contact_widget_new (NULL,
+ EMPATHY_CONTACT_WIDGET_EDIT_ALIAS |
+ EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT |
+ EMPATHY_CONTACT_WIDGET_EDIT_ID |
+ EMPATHY_CONTACT_WIDGET_EDIT_GROUPS);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+ contact_widget,
+ TRUE, TRUE, 0);
+ empathy_contact_widget_set_account_filter (contact_widget,
+ can_add_contact_to_account,
+ NULL);
+
+ new_contact_dialog = dialog;
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (new_contact_response_cb),
+ contact_widget);
+
+ if (parent) {
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
+ }
+
+ gtk_widget_show (dialog);
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-contact-dialogs.glade b/gnome-2-22/libempathy-gtk/empathy-contact-dialogs.glade
new file mode 100644
index 000000000..f8a441057
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-contact-dialogs.glade
@@ -0,0 +1,120 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkDialog" id="subscription_request_dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Subscription Request</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="modal">False</property>
+ <property name="resizable">False</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox4">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area4">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="button19">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Decide _Later</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button20">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-no</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-9</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button21">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-yes</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-8</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox_subscription">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkImage" id="image5">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-question</property>
+ <property name="icon_size">6</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-contact-dialogs.h b/gnome-2-22/libempathy-gtk/empathy-contact-dialogs.h
new file mode 100644
index 000000000..a03e0d000
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-contact-dialogs.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_CONTACT_DIALOGS_H__
+#define __EMPATHY_CONTACT_DIALOGS_H__
+
+#include <gtk/gtk.h>
+
+#include <libempathy/empathy-contact.h>
+
+G_BEGIN_DECLS
+
+void empathy_subscription_dialog_show (EmpathyContact *contact,
+ GtkWindow *parent);
+void empathy_contact_information_dialog_show (EmpathyContact *contact,
+ GtkWindow *parent,
+ gboolean edit,
+ gboolean is_user);
+void empathy_new_contact_dialog_show (GtkWindow *parent);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_CONTACT_DIALOGS_H__ */
diff --git a/gnome-2-22/libempathy-gtk/empathy-contact-list-store.c b/gnome-2-22/libempathy-gtk/empathy-contact-list-store.c
new file mode 100644
index 000000000..cf43bce62
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-contact-list-store.c
@@ -0,0 +1,1549 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2005-2007 Imendio AB
+ * Copyright (C) 2007-2008 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 <micke@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include <libempathy/empathy-debug.h>
+
+#include "empathy-contact-list-store.h"
+#include "empathy-ui-utils.h"
+#include "empathy-gtk-enum-types.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 in seconds user is shown as active */
+#define ACTIVE_USER_SHOW_TIME 7
+
+/* Time in seconds after connecting which we wait before active users are enabled */
+#define ACTIVE_USER_WAIT_TO_ENABLE_TIME 5
+
+#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CONTACT_LIST_STORE, EmpathyContactListStorePriv))
+
+typedef struct {
+ EmpathyContactList *list;
+ gboolean show_offline;
+ gboolean show_avatars;
+ gboolean show_groups;
+ gboolean is_compact;
+ gboolean show_active;
+ EmpathyContactListStoreSort sort_criterium;
+ guint inhibit_active;
+} EmpathyContactListStorePriv;
+
+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 gboolean contact_list_store_finalize_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer user_data);
+static void contact_list_store_setup (EmpathyContactListStore *store);
+static gboolean contact_list_store_inibit_active_cb (EmpathyContactListStore *store);
+static void contact_list_store_members_changed_cb (EmpathyContactList *list_iface,
+ EmpathyContact *contact,
+ EmpathyContact *actor,
+ guint reason,
+ gchar *message,
+ gboolean is_member,
+ EmpathyContactListStore *store);
+static void contact_list_store_groups_changed_cb (EmpathyContactList *list_iface,
+ EmpathyContact *contact,
+ gchar *group,
+ gboolean is_member,
+ EmpathyContactListStore *store);
+static void contact_list_store_add_contact (EmpathyContactListStore *store,
+ EmpathyContact *contact);
+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_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_CONTACT_LIST,
+ PROP_SHOW_OFFLINE,
+ PROP_SHOW_AVATARS,
+ PROP_SHOW_GROUPS,
+ PROP_IS_COMPACT,
+ PROP_SORT_CRITERIUM
+};
+
+G_DEFINE_TYPE (EmpathyContactListStore, empathy_contact_list_store, GTK_TYPE_TREE_STORE);
+
+
+static gboolean
+contact_list_store_iface_setup (gpointer user_data)
+{
+ EmpathyContactListStore *store = user_data;
+ EmpathyContactListStorePriv *priv = GET_PRIV (store);
+ GList *contacts, *l;
+
+ /* Signal connection. */
+ g_signal_connect (priv->list,
+ "members-changed",
+ G_CALLBACK (contact_list_store_members_changed_cb),
+ store);
+ g_signal_connect (priv->list,
+ "groups-changed",
+ G_CALLBACK (contact_list_store_groups_changed_cb),
+ store);
+
+ /* Add contacts already created. */
+ contacts = empathy_contact_list_get_members (priv->list);
+ for (l = contacts; l; l = l->next) {
+ contact_list_store_members_changed_cb (priv->list, l->data,
+ NULL, 0, NULL,
+ TRUE,
+ store);
+
+ g_object_unref (l->data);
+ }
+ g_list_free (contacts);
+
+ return FALSE;
+}
+
+
+static void
+contact_list_store_set_contact_list (EmpathyContactListStore *store,
+ EmpathyContactList *list_iface)
+{
+ EmpathyContactListStorePriv *priv = GET_PRIV (store);
+
+ priv->list = g_object_ref (list_iface);
+
+ /* Let a chance to have all properties set before populating */
+ g_idle_add (contact_list_store_iface_setup,
+ 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_CONTACT_LIST,
+ g_param_spec_object ("contact-list",
+ "The contact list iface",
+ "The contact list iface",
+ EMPATHY_TYPE_CONTACT_LIST,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE));
+ 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_SHOW_GROUPS,
+ g_param_spec_boolean ("show-groups",
+ "Show Groups",
+ "Whether contact list should display "
+ "contact groups",
+ 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->show_avatars = TRUE;
+ priv->show_groups = TRUE;
+ priv->inhibit_active = g_timeout_add_seconds (ACTIVE_USER_WAIT_TO_ENABLE_TIME,
+ (GSourceFunc) contact_list_store_inibit_active_cb,
+ store);
+ contact_list_store_setup (store);
+}
+
+static void
+contact_list_store_finalize (GObject *object)
+{
+ EmpathyContactListStorePriv *priv;
+
+ priv = GET_PRIV (object);
+
+ gtk_tree_model_foreach (GTK_TREE_MODEL (object),
+ (GtkTreeModelForeachFunc) contact_list_store_finalize_foreach,
+ object);
+
+ if (priv->list) {
+ g_signal_handlers_disconnect_by_func (priv->list,
+ G_CALLBACK (contact_list_store_members_changed_cb),
+ object);
+ g_signal_handlers_disconnect_by_func (priv->list,
+ G_CALLBACK (contact_list_store_groups_changed_cb),
+ object);
+ 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_CONTACT_LIST:
+ g_value_set_object (value, priv->list);
+ break;
+ 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_SHOW_GROUPS:
+ g_value_set_boolean (value, priv->show_groups);
+ 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_CONTACT_LIST:
+ contact_list_store_set_contact_list (EMPATHY_CONTACT_LIST_STORE (object),
+ g_value_get_object (value));
+ break;
+ 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_SHOW_GROUPS:
+ empathy_contact_list_store_set_show_groups (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)
+{
+ g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST (list_iface), NULL);
+
+ return g_object_new (EMPATHY_TYPE_CONTACT_LIST_STORE,
+ "contact-list", list_iface,
+ NULL);
+}
+
+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) {
+ contact_list_store_contact_update (store, l->data);
+
+ g_object_unref (l->data);
+ }
+ g_list_free (contacts);
+
+ /* Restore to original setting. */
+ priv->show_active = show_active;
+
+ g_object_notify (G_OBJECT (store), "show-offline");
+}
+
+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);
+
+ g_object_notify (G_OBJECT (store), "show-avatars");
+}
+
+gboolean
+empathy_contact_list_store_get_show_groups (EmpathyContactListStore *store)
+{
+ EmpathyContactListStorePriv *priv;
+
+ g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store), TRUE);
+
+ priv = GET_PRIV (store);
+
+ return priv->show_groups;
+}
+
+void
+empathy_contact_list_store_set_show_groups (EmpathyContactListStore *store,
+ gboolean show_groups)
+{
+ EmpathyContactListStorePriv *priv;
+ GList *contacts, *l;
+
+ g_return_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store));
+
+ priv = GET_PRIV (store);
+
+ if (priv->show_groups == show_groups) {
+ return;
+ }
+
+ priv->show_groups = show_groups;
+
+ /* Remove all contacts and add them back, not optimized but that's the
+ * easy way :) */
+ gtk_tree_store_clear (GTK_TREE_STORE (store));
+ contacts = empathy_contact_list_get_members (priv->list);
+ for (l = contacts; l; l = l->next) {
+ contact_list_store_members_changed_cb (priv->list, l->data,
+ NULL, 0, NULL,
+ TRUE,
+ store);
+
+ g_object_unref (l->data);
+ }
+ g_list_free (contacts);
+
+ g_object_notify (G_OBJECT (store), "show-groups");
+}
+
+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);
+
+ g_object_notify (G_OBJECT (store), "is-compact");
+}
+
+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),
+ EMPATHY_CONTACT_LIST_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),
+ EMPATHY_CONTACT_LIST_STORE_COL_NAME,
+ GTK_SORT_ASCENDING);
+ break;
+ }
+
+ g_object_notify (G_OBJECT (store), "sort-criterium");
+}
+
+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,
+ EMPATHY_CONTACT_LIST_STORE_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,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, &is_group,
+ EMPATHY_CONTACT_LIST_STORE_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,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, &is_group,
+ EMPATHY_CONTACT_LIST_STORE_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 TRUE;
+ }
+
+ gtk_tree_model_get (model, iter,
+ EMPATHY_CONTACT_LIST_STORE_COL_NAME, &name,
+ -1);
+
+ if (!name) {
+ return TRUE;
+ }
+
+ 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;
+}
+
+static gboolean
+contact_list_store_finalize_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ EmpathyContactListStore *store = user_data;
+ EmpathyContact *contact = NULL;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+ EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact,
+ -1);
+
+ if (contact) {
+ g_signal_handlers_disconnect_by_func (contact,
+ G_CALLBACK (contact_list_store_contact_updated_cb),
+ store);
+ }
+
+ return FALSE;
+}
+
+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 */
+ G_TYPE_BOOLEAN}; /* Can VoIP */
+
+ priv = GET_PRIV (store);
+
+ gtk_tree_store_set_column_types (GTK_TREE_STORE (store),
+ EMPATHY_CONTACT_LIST_STORE_COL_COUNT,
+ types);
+
+ /* Set up sorting */
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store),
+ EMPATHY_CONTACT_LIST_STORE_COL_NAME,
+ contact_list_store_name_sort_func,
+ store, NULL);
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store),
+ EMPATHY_CONTACT_LIST_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_members_changed_cb (EmpathyContactList *list_iface,
+ EmpathyContact *contact,
+ EmpathyContact *actor,
+ guint reason,
+ gchar *message,
+ gboolean is_member,
+ EmpathyContactListStore *store)
+{
+ EmpathyContactListStorePriv *priv;
+
+ priv = GET_PRIV (store);
+
+ empathy_debug (DEBUG_DOMAIN,
+ "Contact %s (%d) %s",
+ empathy_contact_get_id (contact),
+ empathy_contact_get_handle (contact),
+ is_member ? "added" : "removed");
+
+ if (is_member) {
+ g_signal_connect (contact, "notify::presence",
+ G_CALLBACK (contact_list_store_contact_updated_cb),
+ store);
+ g_signal_connect (contact, "notify::presence-message",
+ 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::capabilities",
+ G_CALLBACK (contact_list_store_contact_updated_cb),
+ store);
+
+ contact_list_store_add_contact (store, contact);
+ } else {
+ 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_groups_changed_cb (EmpathyContactList *list_iface,
+ EmpathyContact *contact,
+ gchar *group,
+ gboolean is_member,
+ EmpathyContactListStore *store)
+{
+ EmpathyContactListStorePriv *priv;
+ gboolean show_active;
+
+ priv = GET_PRIV (store);
+
+ empathy_debug (DEBUG_DOMAIN, "Updating groups for contact %s (%d)",
+ empathy_contact_get_id (contact),
+ empathy_contact_get_handle (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_add_contact (EmpathyContactListStore *store,
+ EmpathyContact *contact)
+{
+ EmpathyContactListStorePriv *priv;
+ GtkTreeIter iter;
+ GList *groups = NULL, *l;
+
+ priv = GET_PRIV (store);
+
+ if (!priv->show_offline && !empathy_contact_is_online (contact)) {
+ return;
+ }
+
+ if (priv->show_groups) {
+ groups = empathy_contact_list_get_groups (priv->list, contact);
+ }
+
+ /* If no groups just add it at the top level. */
+ if (!groups) {
+ gtk_tree_store_append (GTK_TREE_STORE (store), &iter, NULL);
+ gtk_tree_store_set (GTK_TREE_STORE (store), &iter,
+ EMPATHY_CONTACT_LIST_STORE_COL_NAME, empathy_contact_get_name (contact),
+ EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, contact,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, FALSE,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR, FALSE,
+ EMPATHY_CONTACT_LIST_STORE_COL_CAN_VOIP, empathy_contact_can_voip (contact),
+ -1);
+ }
+
+ /* Else add to each group. */
+ for (l = groups; l; l = l->next) {
+ GtkTreeIter iter_group;
+
+ contact_list_store_get_group (store, l->data, &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,
+ EMPATHY_CONTACT_LIST_STORE_COL_NAME, empathy_contact_get_name (contact),
+ EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, contact,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, FALSE,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR, FALSE,
+ EMPATHY_CONTACT_LIST_STORE_COL_CAN_VOIP, empathy_contact_can_voip (contact),
+ -1);
+ g_free (l->data);
+ }
+ g_list_free (groups);
+
+ contact_list_store_contact_update (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,
+ EMPATHY_CONTACT_LIST_STORE_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,
+ EMPATHY_CONTACT_LIST_STORE_COL_ICON_STATUS, empathy_icon_name_for_contact (contact),
+ EMPATHY_CONTACT_LIST_STORE_COL_PIXBUF_AVATAR, pixbuf_avatar,
+ EMPATHY_CONTACT_LIST_STORE_COL_PIXBUF_AVATAR_VISIBLE, priv->show_avatars,
+ EMPATHY_CONTACT_LIST_STORE_COL_NAME, empathy_contact_get_name (contact),
+ EMPATHY_CONTACT_LIST_STORE_COL_STATUS, empathy_contact_get_status (contact),
+ EMPATHY_CONTACT_LIST_STORE_COL_STATUS_VISIBLE, !priv->is_compact,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, FALSE,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_ONLINE, now_online,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR, FALSE,
+ EMPATHY_CONTACT_LIST_STORE_COL_CAN_VOIP, empathy_contact_can_voip (contact),
+ -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_seconds (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_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,
+ EMPATHY_CONTACT_LIST_STORE_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,
+ EMPATHY_CONTACT_LIST_STORE_COL_NAME, &str,
+ EMPATHY_CONTACT_LIST_STORE_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,
+ EMPATHY_CONTACT_LIST_STORE_COL_ICON_STATUS, NULL,
+ EMPATHY_CONTACT_LIST_STORE_COL_NAME, name,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, TRUE,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_ACTIVE, FALSE,
+ EMPATHY_CONTACT_LIST_STORE_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,
+ EMPATHY_CONTACT_LIST_STORE_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,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR, &is_separator,
+ -1);
+
+ if (is_separator && iter_separator_to_set) {
+ *iter_separator_to_set = iter_separator;
+ }
+ }
+ }
+}
+
+static guint
+contact_list_store_ordered_presence (McPresence state)
+{
+ switch (state) {
+ case MC_PRESENCE_UNSET:
+ case MC_PRESENCE_OFFLINE:
+ return 5;
+ case MC_PRESENCE_AVAILABLE:
+ return 0;
+ case MC_PRESENCE_AWAY:
+ return 2;
+ case MC_PRESENCE_EXTENDED_AWAY:
+ return 3;
+ case MC_PRESENCE_HIDDEN:
+ return 4;
+ case MC_PRESENCE_DO_NOT_DISTURB:
+ return 1;
+ default:
+ g_return_val_if_reached (6);
+ }
+}
+
+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;
+ guint presence_a, presence_b;
+
+ gtk_tree_model_get (model, iter_a,
+ EMPATHY_CONTACT_LIST_STORE_COL_NAME, &name_a,
+ EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact_a,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR, &is_separator_a,
+ -1);
+ gtk_tree_model_get (model, iter_b,
+ EMPATHY_CONTACT_LIST_STORE_COL_NAME, &name_b,
+ EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact_b,
+ EMPATHY_CONTACT_LIST_STORE_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_a = contact_list_store_ordered_presence (presence_a);
+ presence_b = empathy_contact_get_presence (EMPATHY_CONTACT (contact_b));
+ presence_b = contact_list_store_ordered_presence (presence_b);
+
+ if (presence_a < presence_b) {
+ ret_val = -1;
+ } else if (presence_a > presence_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,
+ EMPATHY_CONTACT_LIST_STORE_COL_NAME, &name_a,
+ EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact_a,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR, &is_separator_a,
+ -1);
+ gtk_tree_model_get (model, iter_b,
+ EMPATHY_CONTACT_LIST_STORE_COL_NAME, &name_b,
+ EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact_b,
+ EMPATHY_CONTACT_LIST_STORE_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,
+ EMPATHY_CONTACT_LIST_STORE_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,
+ EMPATHY_CONTACT_LIST_STORE_COL_PIXBUF_AVATAR_VISIBLE, show_avatar,
+ EMPATHY_CONTACT_LIST_STORE_COL_STATUS_VISIBLE, !priv->is_compact,
+ -1);
+
+ return FALSE;
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-contact-list-store.h b/gnome-2-22/libempathy-gtk/empathy-contact-list-store.h
new file mode 100644
index 000000000..6766a4e97
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-contact-list-store.h
@@ -0,0 +1,108 @@
+/* -*- 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 <micke@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_CONTACT_LIST_STORE_H__
+#define __EMPATHY_CONTACT_LIST_STORE_H__
+
+#include <gtk/gtktreestore.h>
+
+#include <libempathy/empathy-contact-list.h>
+#include <libempathy/empathy-contact.h>
+
+G_BEGIN_DECLS
+
+#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 enum {
+ EMPATHY_CONTACT_LIST_STORE_SORT_STATE,
+ EMPATHY_CONTACT_LIST_STORE_SORT_NAME
+} EmpathyContactListStoreSort;
+
+typedef enum {
+ EMPATHY_CONTACT_LIST_STORE_COL_ICON_STATUS,
+ EMPATHY_CONTACT_LIST_STORE_COL_PIXBUF_AVATAR,
+ EMPATHY_CONTACT_LIST_STORE_COL_PIXBUF_AVATAR_VISIBLE,
+ EMPATHY_CONTACT_LIST_STORE_COL_NAME,
+ EMPATHY_CONTACT_LIST_STORE_COL_STATUS,
+ EMPATHY_CONTACT_LIST_STORE_COL_STATUS_VISIBLE,
+ EMPATHY_CONTACT_LIST_STORE_COL_CONTACT,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_ACTIVE,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_ONLINE,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR,
+ EMPATHY_CONTACT_LIST_STORE_COL_CAN_VOIP,
+ EMPATHY_CONTACT_LIST_STORE_COL_COUNT
+} EmpathyContactListStoreCol;
+
+struct _EmpathyContactListStore {
+ GtkTreeStore parent;
+};
+
+struct _EmpathyContactListStoreClass {
+ GtkTreeStoreClass parent_class;
+};
+
+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_show_groups (EmpathyContactListStore *store);
+void empathy_contact_list_store_set_show_groups (EmpathyContactListStore *store,
+ gboolean show_groups);
+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);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_CONTACT_LIST_STORE_H__ */
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-contact-list-view.c b/gnome-2-22/libempathy-gtk/empathy-contact-list-view.c
new file mode 100644
index 000000000..b12387419
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-contact-list-view.c
@@ -0,0 +1,1502 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2005-2007 Imendio AB
+ * Copyright (C) 2007-2008 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 <micke@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+
+#include <libtelepathy/tp-helpers.h>
+
+#include <libmissioncontrol/mc-account.h>
+#include <libmissioncontrol/mission-control.h>
+
+#include <libempathy/empathy-contact-factory.h>
+#include <libempathy/empathy-contact-list.h>
+#include <libempathy/empathy-log-manager.h>
+#include <libempathy/empathy-tp-group.h>
+#include <libempathy/empathy-contact-groups.h>
+#include <libempathy/empathy-debug.h>
+#include <libempathy/empathy-utils.h>
+
+#include "empathy-contact-list-view.h"
+#include "empathy-contact-list-store.h"
+#include "empathy-images.h"
+#include "empathy-cell-renderer-expander.h"
+#include "empathy-cell-renderer-text.h"
+#include "empathy-cell-renderer-activatable.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"
+#include "empathy-gtk-enum-types.h"
+#include "empathy-gtk-marshal.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))
+
+typedef struct {
+ EmpathyContactListStore *store;
+ GtkUIManager *ui;
+ GtkTreeRowReference *drag_row;
+ EmpathyContactListFeatures features;
+} EmpathyContactListViewPriv;
+
+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_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);
+#ifdef HAVE_VOIP
+static void contact_list_view_voip_cell_data_func (GtkTreeViewColumn *tree_column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ EmpathyContactListView *view);
+#endif
+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,
+ gboolean can_voip);
+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);
+#ifdef HAVE_VOIP
+static void contact_list_view_voip_activated_cb (EmpathyCellRendererActivatable *cell,
+ const gchar *path_string,
+ EmpathyContactListView *view);
+#endif
+static void contact_list_view_row_expand_or_collapse_cb (EmpathyContactListView *view,
+ GtkTreeIter *iter,
+ GtkTreePath *path,
+ gpointer user_data);
+static void contact_list_view_action_cb (GtkAction *action,
+ EmpathyContactListView *view);
+static void contact_list_view_voip_activated (EmpathyContactListView *view,
+ EmpathyContact *contact);
+
+enum {
+ PROP_0,
+ PROP_FEATURES
+};
+
+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"), "<control>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", EMPATHY_IMAGE_LOG,
+ N_("_View Previous Conversations"), NULL, N_("View previous conversations with this contact"),
+ G_CALLBACK (contact_list_view_action_cb)
+ },
+#ifdef HAVE_VOIP
+ { "Call", EMPATHY_IMAGE_VOIP,
+ N_("_Call"), NULL, N_("Start a voice or video conversation with this contact"),
+ G_CALLBACK (contact_list_view_action_cb)
+ },
+#endif
+};
+
+static guint n_entries = G_N_ELEMENTS (entries);
+
+static const gchar *ui_info =
+ "<ui>"
+ " <popup name='Contact'>"
+ " <menuitem action='Chat'/>"
+#ifdef HAVE_VOIP
+ " <menuitem action='Call'/>"
+#endif
+ " <menuitem action='Log'/>"
+ " <menuitem action='SendFile'/>"
+ " <separator/>"
+ " <menuitem action='Invite'/>"
+ " <separator/>"
+ " <menuitem action='Edit'/>"
+ " <menuitem action='Remove'/>"
+ " <separator/>"
+ " <menuitem action='Information'/>"
+ " </popup>"
+ " <popup name='Group'>"
+ " <menuitem action='Rename'/>"
+ " <menuitem action='Remove'/>"
+ " </popup>"
+ "</ui>";
+
+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_gtk_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_FEATURES,
+ g_param_spec_flags ("features",
+ "Features of the view",
+ "Falgs for all enabled features",
+ EMPATHY_TYPE_CONTACT_LIST_FEATURES,
+ 0,
+ 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);
+ }
+
+ 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_FEATURES:
+ g_value_set_flags (value, priv->features);
+ 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)
+{
+ EmpathyContactListView *view = EMPATHY_CONTACT_LIST_VIEW (object);
+ EmpathyContactListViewPriv *priv;
+
+ priv = GET_PRIV (object);
+
+ switch (param_id) {
+ case PROP_FEATURES:
+ empathy_contact_list_view_set_features (view, g_value_get_flags (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ };
+}
+
+EmpathyContactListView *
+empathy_contact_list_view_new (EmpathyContactListStore *store,
+ EmpathyContactListFeatures features)
+{
+ EmpathyContactListView *view;
+ EmpathyContactListViewPriv *priv;
+
+ g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store), NULL);
+
+ view = g_object_new (EMPATHY_TYPE_CONTACT_LIST_VIEW,
+ "features", features,
+ NULL);
+
+ priv = GET_PRIV (view);
+ priv->store = g_object_ref (store);
+ contact_list_view_setup (EMPATHY_CONTACT_LIST_VIEW (view));
+
+ return view;
+}
+
+void
+empathy_contact_list_view_set_features (EmpathyContactListView *view,
+ EmpathyContactListFeatures features)
+{
+ EmpathyContactListViewPriv *priv = GET_PRIV (view);
+
+ g_return_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view));
+
+ priv->features = features;
+
+ /* Update DnD source/dest */
+ if (features & EMPATHY_CONTACT_LIST_FEATURE_CONTACT_DRAG) {
+ gtk_drag_source_set (GTK_WIDGET (view),
+ GDK_BUTTON1_MASK,
+ drag_types_source,
+ G_N_ELEMENTS (drag_types_source),
+ GDK_ACTION_MOVE | GDK_ACTION_COPY);
+ } else {
+ gtk_drag_source_unset (GTK_WIDGET (view));
+
+ }
+
+ if (features & EMPATHY_CONTACT_LIST_FEATURE_CONTACT_DROP) {
+ 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_COPY);
+ } else {
+ /* FIXME: URI could still be droped depending on FT feature */
+ gtk_drag_dest_unset (GTK_WIDGET (view));
+ }
+
+ g_object_notify (G_OBJECT (view), "features");
+}
+
+EmpathyContactListFeatures
+empathy_contact_list_view_get_features (EmpathyContactListView *view)
+{
+ EmpathyContactListViewPriv *priv = GET_PRIV (view);
+
+ g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view), FALSE);
+
+ return priv->features;
+}
+
+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,
+ EMPATHY_CONTACT_LIST_STORE_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,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, &is_group,
+ EMPATHY_CONTACT_LIST_STORE_COL_NAME, &name,
+ -1);
+
+ if (!is_group) {
+ g_free (name);
+ return NULL;
+ }
+
+ return name;
+}
+
+static void
+contact_list_view_setup (EmpathyContactListView *view)
+{
+ EmpathyContactListViewPriv *priv;
+ GtkCellRenderer *cell;
+ GtkTreeViewColumn *col;
+ gint i;
+
+ priv = GET_PRIV (view);
+
+ gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (view),
+ empathy_contact_list_store_search_equal_func,
+ NULL, NULL);
+
+ g_signal_connect (priv->store, "row-has-child-toggled",
+ G_CALLBACK (contact_list_view_row_has_child_toggled_cb),
+ view);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (view),
+ GTK_TREE_MODEL (priv->store));
+
+ /* 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", EMPATHY_CONTACT_LIST_STORE_COL_NAME);
+ gtk_tree_view_column_add_attribute (col, cell,
+ "status", EMPATHY_CONTACT_LIST_STORE_COL_STATUS);
+ gtk_tree_view_column_add_attribute (col, cell,
+ "is_group", EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP);
+
+#ifdef HAVE_VOIP
+ /* Voip Capability Icon */
+ cell = empathy_cell_renderer_activatable_new ();
+ gtk_tree_view_column_pack_start (col, cell, FALSE);
+ gtk_tree_view_column_set_cell_data_func (
+ col, cell,
+ (GtkTreeCellDataFunc) contact_list_view_voip_cell_data_func,
+ view, NULL);
+
+ g_object_set (cell,
+ "visible", FALSE,
+ NULL);
+
+ g_signal_connect (cell, "path-activated",
+ G_CALLBACK (contact_list_view_voip_activated_cb),
+ view);
+#endif
+
+ /* 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);
+ }
+}
+
+static void
+contact_list_view_row_has_child_toggled_cb (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ EmpathyContactListView *view)
+{
+ EmpathyContactListViewPriv *priv = GET_PRIV (view);
+ gboolean is_group = FALSE;
+ gchar *name = NULL;
+
+ gtk_tree_model_get (model, iter,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, &is_group,
+ EMPATHY_CONTACT_LIST_STORE_COL_NAME, &name,
+ -1);
+
+ if (!is_group || G_STR_EMPTY (name)) {
+ g_free (name);
+ return;
+ }
+
+ if (!(priv->features & EMPATHY_CONTACT_LIST_FEATURE_GROUPS_SAVE) ||
+ 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_drag_data_received (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection,
+ guint info,
+ guint time)
+{
+ EmpathyContactListViewPriv *priv;
+ EmpathyContactList *list;
+ EmpathyContactFactory *factory;
+ McAccount *account;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeViewDropPosition position;
+ EmpathyContact *contact = NULL;
+ const gchar *id;
+ gchar **strv;
+ 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);
+
+ strv = g_strsplit (id, "/", 2);
+ factory = empathy_contact_factory_new ();
+ account = mc_account_lookup (strv[0]);
+ if (account) {
+ contact = empathy_contact_factory_get_from_id (factory,
+ account,
+ strv[1]);
+ g_object_unref (account);
+ }
+ g_object_unref (factory);
+ g_strfreev (strv);
+
+ 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 (%d) dragged from '%s' to '%s'",
+ empathy_contact_get_id (contact),
+ empathy_contact_get_handle (contact),
+ old_group, new_group);
+
+ list = empathy_contact_list_store_get_list_iface (priv->store);
+ if (new_group) {
+ empathy_contact_list_add_to_group (list, contact, new_group);
+ }
+ if (old_group && context->action == GDK_ACTION_MOVE) {
+ empathy_contact_list_remove_from_group (list, contact, old_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_seconds (1,
+ (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;
+ McAccount *account;
+ const gchar *contact_id;
+ const gchar *account_id;
+ gchar *str;
+
+ 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;
+ }
+
+ account = empathy_contact_get_account (contact);
+ account_id = mc_account_get_unique_name (account);
+ contact_id = empathy_contact_get_id (contact);
+ g_object_unref (contact);
+ str = g_strconcat (account_id, "/", contact_id, NULL);
+
+ switch (info) {
+ case DND_DRAG_TYPE_CONTACT_ID:
+ gtk_selection_data_set (selection, drag_atoms_source[info], 8,
+ (guchar*)str, strlen (str) + 1);
+ break;
+ }
+
+ g_free (str);
+}
+
+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 && 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);
+ }
+}
+
+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,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, &is_group,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_ACTIVE, &is_active,
+ EMPATHY_CONTACT_LIST_STORE_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);
+}
+
+#ifdef HAVE_VOIP
+static void
+contact_list_view_voip_cell_data_func (GtkTreeViewColumn *tree_column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ EmpathyContactListView *view)
+{
+ gboolean is_group;
+ gboolean is_active;
+ gboolean can_voip;
+
+ gtk_tree_model_get (model, iter,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, &is_group,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_ACTIVE, &is_active,
+ EMPATHY_CONTACT_LIST_STORE_COL_CAN_VOIP, &can_voip,
+ -1);
+
+ g_object_set (cell,
+ "visible", !is_group && can_voip,
+ "icon-name", EMPATHY_IMAGE_VOIP,
+ NULL);
+
+ contact_list_view_cell_set_background (view, cell, is_group, is_active);
+}
+#endif
+
+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,
+ EMPATHY_CONTACT_LIST_STORE_COL_PIXBUF_AVATAR, &pixbuf,
+ EMPATHY_CONTACT_LIST_STORE_COL_PIXBUF_AVATAR_VISIBLE, &show_avatar,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, &is_group,
+ EMPATHY_CONTACT_LIST_STORE_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,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, &is_group,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_ACTIVE, &is_active,
+ EMPATHY_CONTACT_LIST_STORE_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,
+ EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, &is_group,
+ EMPATHY_CONTACT_LIST_STORE_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,
+ gboolean can_voip)
+{
+ EmpathyContactListViewPriv *priv = GET_PRIV (view);
+ GtkAction *action;
+
+ if (!(priv->features & (EMPATHY_CONTACT_LIST_FEATURE_CONTACT_CHAT |
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_CALL |
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_LOG |
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_FT |
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_INVITE |
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_EDIT |
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_INFO |
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_REMOVE))) {
+ return NULL;
+ }
+
+ /* Sort out sensitive/visible items */
+ action = gtk_ui_manager_get_action (priv->ui, "/Contact/Chat");
+ gtk_action_set_visible (action, priv->features & EMPATHY_CONTACT_LIST_FEATURE_CONTACT_CHAT);
+
+#ifdef HAVE_VOIP
+ action = gtk_ui_manager_get_action (priv->ui, "/Contact/Call");
+ gtk_action_set_sensitive (action, can_voip);
+ gtk_action_set_visible (action, priv->features & EMPATHY_CONTACT_LIST_FEATURE_CONTACT_CALL);
+#endif
+
+ action = gtk_ui_manager_get_action (priv->ui, "/Contact/Log");
+ gtk_action_set_sensitive (action, can_show_log);
+ gtk_action_set_visible (action, priv->features & EMPATHY_CONTACT_LIST_FEATURE_CONTACT_LOG);
+
+
+ action = gtk_ui_manager_get_action (priv->ui, "/Contact/SendFile");
+ gtk_action_set_visible (action, can_send_file && (priv->features & EMPATHY_CONTACT_LIST_FEATURE_CONTACT_FT));
+
+ action = gtk_ui_manager_get_action (priv->ui, "/Contact/Invite");
+ gtk_action_set_visible (action, priv->features & EMPATHY_CONTACT_LIST_FEATURE_CONTACT_INVITE);
+
+ action = gtk_ui_manager_get_action (priv->ui, "/Contact/Edit");
+ gtk_action_set_visible (action, priv->features & EMPATHY_CONTACT_LIST_FEATURE_CONTACT_EDIT);
+
+ action = gtk_ui_manager_get_action (priv->ui, "/Contact/Information");
+ gtk_action_set_visible (action, priv->features & EMPATHY_CONTACT_LIST_FEATURE_CONTACT_INFO);
+
+ action = gtk_ui_manager_get_action (priv->ui, "/Contact/Remove");
+ gtk_action_set_visible (action, priv->features & EMPATHY_CONTACT_LIST_FEATURE_CONTACT_REMOVE);
+
+ return gtk_ui_manager_get_widget (priv->ui, "/Contact");
+}
+
+GtkWidget *
+empathy_contact_list_view_get_group_menu (EmpathyContactListView *view)
+{
+ EmpathyContactListViewPriv *priv = GET_PRIV (view);
+ GtkAction *action;
+
+ g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view), NULL);
+
+ if (!(priv->features & (EMPATHY_CONTACT_LIST_FEATURE_GROUPS_RENAME |
+ EMPATHY_CONTACT_LIST_FEATURE_GROUPS_REMOVE))) {
+ return NULL;
+ }
+
+ action = gtk_ui_manager_get_action (priv->ui, "/Group/Rename");
+ gtk_action_set_visible (action, priv->features & EMPATHY_CONTACT_LIST_FEATURE_GROUPS_RENAME);
+
+ action = gtk_ui_manager_get_action (priv->ui, "/Group/Remove");
+ gtk_action_set_visible (action, priv->features & EMPATHY_CONTACT_LIST_FEATURE_GROUPS_REMOVE);
+
+ return gtk_ui_manager_get_widget (priv->ui, "/Group");
+}
+
+GtkWidget *
+empathy_contact_list_view_get_contact_menu (EmpathyContactListView *view,
+ EmpathyContact *contact)
+{
+ EmpathyLogManager *log_manager;
+ gboolean can_show_log;
+ gboolean can_send_file;
+ gboolean can_voip;
+
+ 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);
+ g_object_unref (log_manager);
+ can_send_file = FALSE;
+ can_voip = empathy_contact_can_voip (contact);
+
+ return contact_list_view_get_contact_menu (view,
+ can_send_file,
+ can_show_log,
+ can_voip);
+}
+
+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;
+
+ priv = GET_PRIV (view);
+
+ if (event->button != 3) {
+ return FALSE;
+ }
+
+ 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,
+ EMPATHY_CONTACT_LIST_STORE_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)
+{
+ EmpathyContactListViewPriv *priv = GET_PRIV (view);
+ EmpathyContact *contact;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ if (!(priv->features & EMPATHY_CONTACT_LIST_FEATURE_CONTACT_CHAT)) {
+ return;
+ }
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter,
+ EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact,
+ -1);
+
+ if (contact) {
+ empathy_chat_with_contact (contact);
+ g_object_unref (contact);
+ }
+}
+
+#ifdef HAVE_VOIP
+static void
+contact_list_view_voip_activated_cb (EmpathyCellRendererActivatable *cell,
+ const gchar *path_string,
+ EmpathyContactListView *view)
+{
+ EmpathyContactListViewPriv *priv = GET_PRIV (view);
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ EmpathyContact *contact;
+
+ if (!(priv->features & EMPATHY_CONTACT_LIST_FEATURE_CONTACT_CALL)) {
+ return;
+ }
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
+ if (!gtk_tree_model_get_iter_from_string (model, &iter, path_string)) {
+ return;
+ }
+
+ gtk_tree_model_get (model, &iter,
+ EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact,
+ -1);
+
+ if (contact) {
+ contact_list_view_voip_activated (view, contact);
+ g_object_unref (contact);
+ }
+}
+#endif
+
+
+static void
+contact_list_view_row_expand_or_collapse_cb (EmpathyContactListView *view,
+ GtkTreeIter *iter,
+ GtkTreePath *path,
+ gpointer user_data)
+{
+ EmpathyContactListViewPriv *priv = GET_PRIV (view);
+ GtkTreeModel *model;
+ gchar *name;
+ gboolean expanded;
+
+ if (!(priv->features & EMPATHY_CONTACT_LIST_FEATURE_GROUPS_SAVE)) {
+ return;
+ }
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
+
+ gtk_tree_model_get (model, iter,
+ EMPATHY_CONTACT_LIST_STORE_COL_NAME, &name,
+ -1);
+
+ expanded = GPOINTER_TO_INT (user_data);
+ empathy_contact_group_set_expanded (name, expanded);
+
+ g_free (name);
+}
+
+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) {
+ empathy_chat_with_contact (contact);
+ }
+ else if (contact && strcmp (name, "Call") == 0) {
+ contact_list_view_voip_activated (view, contact);
+ }
+ else if (contact && strcmp (name, "Information") == 0) {
+ empathy_contact_information_dialog_show (contact, parent, FALSE, FALSE);
+ }
+ else if (contact && strcmp (name, "Edit") == 0) {
+ empathy_contact_information_dialog_show (contact, parent, TRUE, FALSE);
+ }
+ 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) {
+ }
+ else if (group && strcmp (name, "Remove") == 0) {
+ EmpathyContactList *list;
+
+ list = empathy_contact_list_store_get_list_iface (priv->store);
+ empathy_contact_list_remove_group (list, group);
+ }
+
+ g_free (group);
+ if (contact) {
+ g_object_unref (contact);
+ }
+}
+
+static void
+contact_list_view_voip_activated (EmpathyContactListView *view,
+ EmpathyContact *contact)
+{
+ empathy_call_with_contact (contact);
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-contact-list-view.h b/gnome-2-22/libempathy-gtk/empathy-contact-list-view.h
new file mode 100644
index 000000000..13a685d33
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-contact-list-view.h
@@ -0,0 +1,88 @@
+/* -*- 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 <micke@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_CONTACT_LIST_VIEW_H__
+#define __EMPATHY_CONTACT_LIST_VIEW_H__
+
+#include <gtk/gtktreeview.h>
+
+#include <libempathy/empathy-contact.h>
+
+#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 enum {
+ EMPATHY_CONTACT_LIST_FEATURE_NONE = 0,
+ EMPATHY_CONTACT_LIST_FEATURE_GROUPS_SAVE = 1 << 0,
+ EMPATHY_CONTACT_LIST_FEATURE_GROUPS_RENAME = 1 << 1,
+ EMPATHY_CONTACT_LIST_FEATURE_GROUPS_REMOVE = 1 << 2,
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_CHAT = 1 << 3,
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_CALL = 1 << 4,
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_LOG = 1 << 5,
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_FT = 1 << 6,
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_INVITE = 1 << 7,
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_EDIT = 1 << 8,
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_INFO = 1 << 9,
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_REMOVE = 1 << 10,
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_DROP = 1 << 11,
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_DRAG = 1 << 12,
+ EMPATHY_CONTACT_LIST_FEATURE_ALL = (1 << 13) - 1,
+} EmpathyContactListFeatures;
+
+struct _EmpathyContactListView {
+ GtkTreeView parent;
+};
+
+struct _EmpathyContactListViewClass {
+ GtkTreeViewClass parent_class;
+};
+
+GType empathy_contact_list_view_get_type (void) G_GNUC_CONST;
+EmpathyContactListView * empathy_contact_list_view_new (EmpathyContactListStore *store,
+ EmpathyContactListFeatures features);
+void empathy_contact_list_view_set_features (EmpathyContactListView *view,
+ EmpathyContactListFeatures features);
+EmpathyContactListFeatures empathy_contact_list_view_get_features (EmpathyContactListView *view);
+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);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_CONTACT_LIST_VIEW_H__ */
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-contact-widget.c b/gnome-2-22/libempathy-gtk/empathy-contact-widget.c
new file mode 100644
index 000000000..0c3f40dc1
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-contact-widget.c
@@ -0,0 +1,946 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007-2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <glib/gi18n.h>
+
+#include <libmissioncontrol/mc-account.h>
+
+#include <libempathy/empathy-contact-factory.h>
+#include <libempathy/empathy-contact-manager.h>
+#include <libempathy/empathy-contact-list.h>
+#include <libempathy/empathy-utils.h>
+
+#include "empathy-contact-widget.h"
+#include "empathy-account-chooser.h"
+#include "empathy-avatar-chooser.h"
+#include "empathy-avatar-image.h"
+#include "empathy-ui-utils.h"
+
+/* Delay before updating the widget when the id entry changed (seconds) */
+#define ID_CHANGED_TIMEOUT 1
+
+typedef struct {
+ EmpathyContactFactory *factory;
+ EmpathyContactManager *manager;
+ EmpathyContact *contact;
+ EmpathyContactWidgetFlags flags;
+ GtkCellRenderer *renderer;
+ guint widget_id_timeout;
+
+ GtkWidget *vbox_contact_widget;
+
+ /* Contact */
+ GtkWidget *vbox_contact;
+ GtkWidget *widget_avatar;
+ GtkWidget *widget_account;
+ GtkWidget *widget_id;
+ GtkWidget *widget_alias;
+ GtkWidget *label_alias;
+ GtkWidget *entry_alias;
+ GtkWidget *hbox_presence;
+ GtkWidget *image_state;
+ GtkWidget *label_status;
+ GtkWidget *table_contact;
+ GtkWidget *vbox_avatar;
+
+ /* Groups */
+ GtkWidget *vbox_groups;
+ GtkWidget *entry_group;
+ GtkWidget *button_group;
+ GtkWidget *treeview_groups;
+
+ /* Details */
+ GtkWidget *vbox_details;
+ GtkWidget *table_details;
+ GtkWidget *hbox_details_requested;
+
+ /* Client */
+ GtkWidget *vbox_client;
+ GtkWidget *table_client;
+ GtkWidget *hbow_client_requested;
+} EmpathyContactWidget;
+
+typedef struct {
+ EmpathyContactWidget *information;
+ const gchar *name;
+ gboolean found;
+ GtkTreeIter found_iter;
+} FindName;
+
+static void contact_widget_destroy_cb (GtkWidget *widget,
+ EmpathyContactWidget *information);
+static void contact_widget_remove_contact (EmpathyContactWidget *information);
+static void contact_widget_set_contact (EmpathyContactWidget *information,
+ EmpathyContact *contact);
+static void contact_widget_contact_setup (EmpathyContactWidget *information);
+static void contact_widget_contact_update (EmpathyContactWidget *information);
+static void contact_widget_change_contact (EmpathyContactWidget *information);
+static void contact_widget_avatar_changed_cb (EmpathyAvatarChooser *chooser,
+ EmpathyContactWidget *information);
+static void contact_widget_account_changed_cb (GtkComboBox *widget,
+ EmpathyContactWidget *information);
+static gboolean contact_widget_id_focus_out_cb (GtkWidget *widget,
+ GdkEventFocus *event,
+ EmpathyContactWidget *information);
+static gboolean contact_widget_entry_alias_focus_event_cb (GtkEditable *editable,
+ GdkEventFocus *event,
+ EmpathyContactWidget *information);
+static void contact_widget_name_notify_cb (EmpathyContactWidget *information);
+static void contact_widget_presence_notify_cb (EmpathyContactWidget *information);
+static void contact_widget_avatar_notify_cb (EmpathyContactWidget *information);
+static void contact_widget_groups_setup (EmpathyContactWidget *information);
+static void contact_widget_groups_update (EmpathyContactWidget *information);
+static void contact_widget_model_setup (EmpathyContactWidget *information);
+static void contact_widget_model_populate_columns (EmpathyContactWidget *information);
+static void contact_widget_groups_populate_data (EmpathyContactWidget *information);
+static void contact_widget_groups_notify_cb (EmpathyContactWidget *information);
+static gboolean contact_widget_model_find_name (EmpathyContactWidget *information,
+ const gchar *name,
+ GtkTreeIter *iter);
+static gboolean contact_widget_model_find_name_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ FindName *data);
+static void contact_widget_cell_toggled (GtkCellRendererToggle *cell,
+ gchar *path_string,
+ EmpathyContactWidget *information);
+static void contact_widget_entry_group_changed_cb (GtkEditable *editable,
+ EmpathyContactWidget *information);
+static void contact_widget_entry_group_activate_cb (GtkEntry *entry,
+ EmpathyContactWidget *information);
+static void contact_widget_button_group_clicked_cb (GtkButton *button,
+ EmpathyContactWidget *information);
+static void contact_widget_details_setup (EmpathyContactWidget *information);
+static void contact_widget_details_update (EmpathyContactWidget *information);
+static void contact_widget_client_setup (EmpathyContactWidget *information);
+static void contact_widget_client_update (EmpathyContactWidget *information);
+
+enum {
+ COL_NAME,
+ COL_ENABLED,
+ COL_EDITABLE,
+ COL_COUNT
+};
+
+GtkWidget *
+empathy_contact_widget_new (EmpathyContact *contact,
+ EmpathyContactWidgetFlags flags)
+{
+ EmpathyContactWidget *information;
+ GladeXML *glade;
+
+ information = g_slice_new0 (EmpathyContactWidget);
+ information->flags = flags;
+ information->factory = empathy_contact_factory_new ();
+
+ glade = empathy_glade_get_file ("empathy-contact-widget.glade",
+ "vbox_contact_widget",
+ NULL,
+ "vbox_contact_widget", &information->vbox_contact_widget,
+ "vbox_contact", &information->vbox_contact,
+ "hbox_presence", &information->hbox_presence,
+ "label_alias", &information->label_alias,
+ "image_state", &information->image_state,
+ "label_status", &information->label_status,
+ "table_contact", &information->table_contact,
+ "vbox_avatar", &information->vbox_avatar,
+ "vbox_groups", &information->vbox_groups,
+ "entry_group", &information->entry_group,
+ "button_group", &information->button_group,
+ "treeview_groups", &information->treeview_groups,
+ "vbox_details", &information->vbox_details,
+ "table_details", &information->table_details,
+ "hbox_details_requested", &information->hbox_details_requested,
+ "vbox_client", &information->vbox_client,
+ "table_client", &information->table_client,
+ "hbox_client_requested", &information->hbow_client_requested,
+ NULL);
+
+ empathy_glade_connect (glade,
+ information,
+ "vbox_contact_widget", "destroy", contact_widget_destroy_cb,
+ "entry_group", "changed", contact_widget_entry_group_changed_cb,
+ "entry_group", "activate", contact_widget_entry_group_activate_cb,
+ "button_group", "clicked", contact_widget_button_group_clicked_cb,
+ NULL);
+
+ g_object_unref (glade);
+
+ g_object_set_data (G_OBJECT (information->vbox_contact_widget),
+ "EmpathyContactWidget",
+ information);
+
+ /* Create widgets */
+ contact_widget_contact_setup (information);
+ contact_widget_groups_setup (information);
+ contact_widget_details_setup (information);
+ contact_widget_client_setup (information);
+
+ contact_widget_set_contact (information, contact);
+
+ gtk_widget_show (information->vbox_contact_widget);
+
+ return information->vbox_contact_widget;
+}
+
+EmpathyContact *
+empathy_contact_widget_get_contact (GtkWidget *widget)
+{
+ EmpathyContactWidget *information;
+
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+
+ information = g_object_get_data (G_OBJECT (widget), "EmpathyContactWidget");
+ if (!information) {
+ return NULL;
+ }
+
+ return information->contact;
+}
+
+void
+empathy_contact_widget_set_contact (GtkWidget *widget,
+ EmpathyContact *contact)
+{
+ EmpathyContactWidget *information;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (EMPATHY_IS_CONTACT (contact));
+
+ information = g_object_get_data (G_OBJECT (widget), "EmpathyContactWidget");
+ if (!information) {
+ return;
+ }
+
+ contact_widget_set_contact (information, contact);
+}
+
+void
+empathy_contact_widget_set_account_filter (GtkWidget *widget,
+ EmpathyAccountChooserFilterFunc filter,
+ gpointer user_data)
+{
+ EmpathyContactWidget *information;
+ EmpathyAccountChooser *chooser;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ information = g_object_get_data (G_OBJECT (widget), "EmpathyContactWidget");
+ if (!information) {
+ return;
+ }
+
+ chooser = EMPATHY_ACCOUNT_CHOOSER (information->widget_account);
+ if (chooser) {
+ empathy_account_chooser_set_filter (chooser, filter, user_data);
+ }
+}
+
+static void
+contact_widget_destroy_cb (GtkWidget *widget,
+ EmpathyContactWidget *information)
+{
+ contact_widget_remove_contact (information);
+
+ if (information->widget_id_timeout != 0) {
+ g_source_remove (information->widget_id_timeout);
+ }
+ if (information->factory) {
+ g_object_unref (information->factory);
+ }
+ if (information->manager) {
+ g_object_unref (information->manager);
+ }
+
+ g_slice_free (EmpathyContactWidget, information);
+}
+
+static void
+contact_widget_remove_contact (EmpathyContactWidget *information)
+{
+ if (information->contact) {
+ g_signal_handlers_disconnect_by_func (information->contact,
+ contact_widget_name_notify_cb,
+ information);
+ g_signal_handlers_disconnect_by_func (information->contact,
+ contact_widget_presence_notify_cb,
+ information);
+ g_signal_handlers_disconnect_by_func (information->contact,
+ contact_widget_avatar_notify_cb,
+ information);
+ g_signal_handlers_disconnect_by_func (information->contact,
+ contact_widget_groups_notify_cb,
+ information);
+
+ g_object_unref (information->contact);
+ information->contact = NULL;
+ }
+}
+
+static void
+contact_widget_set_contact (EmpathyContactWidget *information,
+ EmpathyContact *contact)
+{
+ if (contact == information->contact ||
+ (contact && information->contact &&
+ empathy_contact_equal (contact, information->contact))) {
+ return;
+ }
+
+ contact_widget_remove_contact (information);
+ if (contact) {
+ information->contact = g_object_ref (contact);
+ }
+
+ /* Update information for widgets */
+ contact_widget_contact_update (information);
+ contact_widget_groups_update (information);
+ contact_widget_details_update (information);
+ contact_widget_client_update (information);
+}
+
+static gboolean
+contact_widget_id_activate_timeout (EmpathyContactWidget *self)
+{
+ contact_widget_change_contact (self);
+ return FALSE;
+}
+
+static void
+contact_widget_id_changed_cb (GtkEntry *entry,
+ EmpathyContactWidget *self)
+{
+ if (self->widget_id_timeout != 0) {
+ g_source_remove (self->widget_id_timeout);
+ }
+
+ self->widget_id_timeout =
+ g_timeout_add_seconds (ID_CHANGED_TIMEOUT,
+ (GSourceFunc) contact_widget_id_activate_timeout,
+ self);
+}
+
+static void
+contact_widget_contact_setup (EmpathyContactWidget *information)
+{
+ if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_AVATAR) {
+ information->widget_avatar = empathy_avatar_chooser_new ();
+ g_signal_connect (information->widget_avatar, "changed",
+ G_CALLBACK (contact_widget_avatar_changed_cb),
+ information);
+ } else {
+ information->widget_avatar = empathy_avatar_image_new ();
+ }
+ gtk_box_pack_start (GTK_BOX (information->vbox_avatar),
+ information->widget_avatar,
+ FALSE, FALSE,
+ 6);
+ gtk_widget_show (information->widget_avatar);
+
+ /* Setup account label/chooser */
+ if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT) {
+ information->widget_account = empathy_account_chooser_new ();
+
+ g_signal_connect (information->widget_account, "changed",
+ G_CALLBACK (contact_widget_account_changed_cb),
+ information);
+ } else {
+ information->widget_account = gtk_label_new (NULL);
+ gtk_label_set_selectable (GTK_LABEL (information->widget_account), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (information->widget_account), 0, 0.5);
+ }
+ gtk_table_attach_defaults (GTK_TABLE (information->table_contact),
+ information->widget_account,
+ 1, 2, 0, 1);
+ gtk_widget_show (information->widget_account);
+
+ /* Setup id label/entry */
+ if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_ID) {
+ information->widget_id = gtk_entry_new ();
+ g_signal_connect (information->widget_id, "focus-out-event",
+ G_CALLBACK (contact_widget_id_focus_out_cb),
+ information);
+ g_signal_connect (information->widget_id, "changed",
+ G_CALLBACK (contact_widget_id_changed_cb),
+ information);
+ } else {
+ information->widget_id = gtk_label_new (NULL);
+ gtk_label_set_selectable (GTK_LABEL (information->widget_id), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (information->widget_id), 0, 0.5);
+ }
+ gtk_table_attach_defaults (GTK_TABLE (information->table_contact),
+ information->widget_id,
+ 1, 2, 1, 2);
+ gtk_widget_show (information->widget_id);
+
+ /* Setup alias label/entry */
+ if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_ALIAS) {
+ information->widget_alias = gtk_entry_new ();
+ g_signal_connect (information->widget_alias, "focus-out-event",
+ G_CALLBACK (contact_widget_entry_alias_focus_event_cb),
+ information);
+ } else {
+ information->widget_alias = gtk_label_new (NULL);
+ gtk_label_set_selectable (GTK_LABEL (information->widget_alias), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (information->widget_alias), 0, 0.5);
+ }
+ gtk_table_attach_defaults (GTK_TABLE (information->table_contact),
+ information->widget_alias,
+ 1, 2, 2, 3);
+ gtk_widget_show (information->widget_alias);
+}
+
+static void
+contact_widget_contact_update (EmpathyContactWidget *information)
+{
+ McAccount *account = NULL;
+ const gchar *id = NULL;
+
+ /* Connect and get info from new contact */
+ if (information->contact) {
+ g_signal_connect_swapped (information->contact, "notify::name",
+ G_CALLBACK (contact_widget_name_notify_cb),
+ information);
+ g_signal_connect_swapped (information->contact, "notify::presence",
+ G_CALLBACK (contact_widget_presence_notify_cb),
+ information);
+ g_signal_connect_swapped (information->contact, "notify::presence-message",
+ G_CALLBACK (contact_widget_presence_notify_cb),
+ information);
+ g_signal_connect_swapped (information->contact, "notify::avatar",
+ G_CALLBACK (contact_widget_avatar_notify_cb),
+ information);
+
+ account = empathy_contact_get_account (information->contact);
+ id = empathy_contact_get_id (information->contact);
+ }
+
+ /* Update account widget */
+ if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT) {
+ if (account) {
+ g_signal_handlers_block_by_func (information->widget_account,
+ contact_widget_account_changed_cb,
+ information);
+ 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,
+ information);
+ }
+ } else {
+ if (account) {
+ const gchar *name;
+
+ name = mc_account_get_display_name (account);
+ gtk_label_set_label (GTK_LABEL (information->widget_account), name);
+ }
+ }
+
+ /* Update id widget */
+ if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_ID) {
+ gtk_entry_set_text (GTK_ENTRY (information->widget_id), id ? id : "");
+ } else {
+ gtk_label_set_label (GTK_LABEL (information->widget_id), id ? id : "");
+ }
+ /* Update other widgets */
+ if (information->contact) {
+ contact_widget_name_notify_cb (information);
+ contact_widget_presence_notify_cb (information);
+ contact_widget_avatar_notify_cb (information);
+
+ gtk_widget_show (information->label_alias);
+ gtk_widget_show (information->widget_alias);
+ gtk_widget_show (information->hbox_presence);
+ gtk_widget_show (information->widget_avatar);
+ } else {
+ gtk_widget_hide (information->label_alias);
+ gtk_widget_hide (information->widget_alias);
+ gtk_widget_hide (information->hbox_presence);
+ gtk_widget_hide (information->widget_avatar);
+ }
+}
+
+static void
+contact_widget_change_contact (EmpathyContactWidget *information)
+{
+ EmpathyContact *contact;
+ McAccount *account;
+
+ account = empathy_account_chooser_get_account (EMPATHY_ACCOUNT_CHOOSER (information->widget_account));
+ if (!account) {
+ return;
+ }
+
+ if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_ID) {
+ const gchar *id;
+
+ id = gtk_entry_get_text (GTK_ENTRY (information->widget_id));
+ if (G_STR_EMPTY (id)) {
+ return;
+ }
+
+ contact = empathy_contact_factory_get_from_id (information->factory,
+ account, id);
+ } else {
+ contact = empathy_contact_factory_get_user (information->factory,
+ account);
+ }
+
+ if (contact) {
+ contact_widget_set_contact (information, contact);
+ g_object_unref (contact);
+ }
+}
+
+static void
+contact_widget_avatar_changed_cb (EmpathyAvatarChooser *chooser,
+ EmpathyContactWidget *information)
+{
+ if (information->contact &&
+ empathy_contact_is_user (information->contact)) {
+ McAccount *account;
+ const gchar *data;
+ gsize size;
+ const gchar *mime_type;
+
+ account = empathy_contact_get_account (information->contact);
+ empathy_avatar_chooser_get_image_data (EMPATHY_AVATAR_CHOOSER (information->widget_avatar),
+ &data, &size, &mime_type);
+ empathy_contact_factory_set_avatar (information->factory,
+ account,
+ data, size, mime_type);
+ }
+}
+
+static void
+contact_widget_account_changed_cb (GtkComboBox *widget,
+ EmpathyContactWidget *information)
+{
+ contact_widget_change_contact (information);
+}
+
+static gboolean
+contact_widget_id_focus_out_cb (GtkWidget *widget,
+ GdkEventFocus *event,
+ EmpathyContactWidget *information)
+{
+ contact_widget_change_contact (information);
+ return FALSE;
+}
+
+static gboolean
+contact_widget_entry_alias_focus_event_cb (GtkEditable *editable,
+ GdkEventFocus *event,
+ EmpathyContactWidget *information)
+{
+ if (information->contact) {
+ const gchar *alias;
+
+ alias = gtk_entry_get_text (GTK_ENTRY (editable));
+ empathy_contact_factory_set_alias (information->factory,
+ information->contact,
+ alias);
+ }
+
+ return FALSE;
+}
+
+static void
+contact_widget_name_notify_cb (EmpathyContactWidget *information)
+{
+ if (GTK_IS_ENTRY (information->widget_alias)) {
+ gtk_entry_set_text (GTK_ENTRY (information->widget_alias),
+ empathy_contact_get_name (information->contact));
+ } else {
+ gtk_label_set_label (GTK_LABEL (information->widget_alias),
+ empathy_contact_get_name (information->contact));
+ }
+}
+
+static void
+contact_widget_presence_notify_cb (EmpathyContactWidget *information)
+{
+ gtk_label_set_text (GTK_LABEL (information->label_status),
+ empathy_contact_get_status (information->contact));
+ gtk_image_set_from_icon_name (GTK_IMAGE (information->image_state),
+ empathy_icon_name_for_contact (information->contact),
+ GTK_ICON_SIZE_BUTTON);
+
+}
+
+static void
+contact_widget_avatar_notify_cb (EmpathyContactWidget *information)
+{
+ EmpathyAvatar *avatar = NULL;
+
+ if (information->contact) {
+ avatar = empathy_contact_get_avatar (information->contact);
+ }
+ if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_AVATAR) {
+ g_signal_handlers_block_by_func (information->widget_avatar,
+ contact_widget_avatar_changed_cb,
+ information);
+ empathy_avatar_chooser_set (EMPATHY_AVATAR_CHOOSER (information->widget_avatar),
+ avatar);
+ g_signal_handlers_unblock_by_func (information->widget_avatar,
+ contact_widget_avatar_changed_cb,
+ information);
+ } else {
+ empathy_avatar_image_set (EMPATHY_AVATAR_IMAGE (information->widget_avatar),
+ avatar);
+ }
+}
+
+static void
+contact_widget_groups_setup (EmpathyContactWidget *information)
+{
+ if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_GROUPS) {
+ information->manager = empathy_contact_manager_new ();
+ contact_widget_model_setup (information);
+ }
+}
+
+static void
+contact_widget_groups_update (EmpathyContactWidget *information)
+{
+ if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_GROUPS &&
+ information->contact) {
+ g_signal_connect_swapped (information->contact, "notify::groups",
+ G_CALLBACK (contact_widget_groups_notify_cb),
+ information);
+ contact_widget_groups_populate_data (information);
+
+ gtk_widget_show (information->vbox_groups);
+ } else {
+ gtk_widget_hide (information->vbox_groups);
+ }
+}
+
+static void
+contact_widget_model_setup (EmpathyContactWidget *information)
+{
+ GtkTreeView *view;
+ GtkListStore *store;
+ GtkTreeSelection *selection;
+
+ view = GTK_TREE_VIEW (information->treeview_groups);
+
+ store = gtk_list_store_new (COL_COUNT,
+ G_TYPE_STRING, /* name */
+ G_TYPE_BOOLEAN, /* enabled */
+ G_TYPE_BOOLEAN); /* editable */
+
+ 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);
+
+ contact_widget_model_populate_columns (information);
+
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+ COL_NAME, GTK_SORT_ASCENDING);
+
+ g_object_unref (store);
+}
+
+static void
+contact_widget_model_populate_columns (EmpathyContactWidget *information)
+{
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+ guint col_offset;
+
+ view = GTK_TREE_VIEW (information->treeview_groups);
+ model = gtk_tree_view_get_model (view);
+
+ renderer = gtk_cell_renderer_toggle_new ();
+ g_signal_connect (renderer, "toggled",
+ G_CALLBACK (contact_widget_cell_toggled),
+ information);
+
+ column = gtk_tree_view_column_new_with_attributes (_("Select"), renderer,
+ "active", COL_ENABLED,
+ NULL);
+
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
+ gtk_tree_view_column_set_fixed_width (column, 50);
+ gtk_tree_view_append_column (view, column);
+
+ renderer = gtk_cell_renderer_text_new ();
+ col_offset = gtk_tree_view_insert_column_with_attributes (view,
+ -1, _("Group"),
+ renderer,
+ "text", COL_NAME,
+ /* "editable", COL_EDITABLE, */
+ NULL);
+
+ g_object_set_data (G_OBJECT (renderer),
+ "column", GINT_TO_POINTER (COL_NAME));
+
+ column = gtk_tree_view_get_column (view, col_offset - 1);
+ gtk_tree_view_column_set_sort_column_id (column, COL_NAME);
+ gtk_tree_view_column_set_resizable (column,FALSE);
+ gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
+
+ if (information->renderer) {
+ g_object_unref (information->renderer);
+ }
+
+ information->renderer = g_object_ref (renderer);
+}
+
+static void
+contact_widget_groups_populate_data (EmpathyContactWidget *information)
+{
+ GtkTreeView *view;
+ GtkListStore *store;
+ GtkTreeIter iter;
+ GList *my_groups, *l;
+ GList *all_groups;
+
+ view = GTK_TREE_VIEW (information->treeview_groups);
+ store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
+ gtk_list_store_clear (store);
+
+ all_groups = empathy_contact_list_get_all_groups (EMPATHY_CONTACT_LIST (information->manager));
+ my_groups = empathy_contact_list_get_groups (EMPATHY_CONTACT_LIST (information->manager),
+ information->contact);
+
+ for (l = all_groups; l; l = l->next) {
+ const gchar *group_str;
+ gboolean enabled;
+
+ group_str = l->data;
+
+ enabled = g_list_find_custom (my_groups,
+ group_str,
+ (GCompareFunc) strcmp) != NULL;
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_NAME, group_str,
+ COL_EDITABLE, TRUE,
+ COL_ENABLED, enabled,
+ -1);
+ }
+
+ g_list_foreach (all_groups, (GFunc) g_free, NULL);
+ g_list_foreach (my_groups, (GFunc) g_free, NULL);
+ g_list_free (all_groups);
+ g_list_free (my_groups);
+}
+
+static void
+contact_widget_groups_notify_cb (EmpathyContactWidget *information)
+{
+ /* FIXME: not implemented */
+}
+
+static gboolean
+contact_widget_model_find_name (EmpathyContactWidget *information,
+ const gchar *name,
+ GtkTreeIter *iter)
+{
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ FindName data;
+
+ if (G_STR_EMPTY (name)) {
+ return FALSE;
+ }
+
+ data.information = information;
+ data.name = name;
+ data.found = FALSE;
+
+ view = GTK_TREE_VIEW (information->treeview_groups);
+ model = gtk_tree_view_get_model (view);
+
+ gtk_tree_model_foreach (model,
+ (GtkTreeModelForeachFunc) contact_widget_model_find_name_foreach,
+ &data);
+
+ if (data.found == TRUE) {
+ *iter = data.found_iter;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+contact_widget_model_find_name_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ FindName *data)
+{
+ gchar *name;
+
+ gtk_tree_model_get (model, iter,
+ COL_NAME, &name,
+ -1);
+
+ if (!name) {
+ return FALSE;
+ }
+
+ if (data->name && strcmp (data->name, name) == 0) {
+ data->found = TRUE;
+ data->found_iter = *iter;
+
+ g_free (name);
+
+ return TRUE;
+ }
+
+ g_free (name);
+
+ return FALSE;
+}
+
+static void
+contact_widget_cell_toggled (GtkCellRendererToggle *cell,
+ gchar *path_string,
+ EmpathyContactWidget *information)
+{
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkListStore *store;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ gboolean enabled;
+ gchar *group;
+
+ view = GTK_TREE_VIEW (information->treeview_groups);
+ 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_ENABLED, &enabled,
+ COL_NAME, &group,
+ -1);
+
+ gtk_list_store_set (store, &iter, COL_ENABLED, !enabled, -1);
+ gtk_tree_path_free (path);
+
+ if (group) {
+ if (enabled) {
+ empathy_contact_list_remove_from_group (EMPATHY_CONTACT_LIST (information->manager),
+ information->contact,
+ group);
+ } else {
+ empathy_contact_list_add_to_group (EMPATHY_CONTACT_LIST (information->manager),
+ information->contact,
+ group);
+ }
+
+ g_free (group);
+ }
+}
+
+static void
+contact_widget_entry_group_changed_cb (GtkEditable *editable,
+ EmpathyContactWidget *information)
+{
+ GtkTreeIter iter;
+ const gchar *group;
+
+ group = gtk_entry_get_text (GTK_ENTRY (information->entry_group));
+
+ if (contact_widget_model_find_name (information, group, &iter)) {
+ gtk_widget_set_sensitive (GTK_WIDGET (information->button_group), FALSE);
+
+ } else {
+ gtk_widget_set_sensitive (GTK_WIDGET (information->button_group),
+ !G_STR_EMPTY (group));
+ }
+}
+
+static void
+contact_widget_entry_group_activate_cb (GtkEntry *entry,
+ EmpathyContactWidget *information)
+{
+ gtk_widget_activate (GTK_WIDGET (information->button_group));
+}
+
+static void
+contact_widget_button_group_clicked_cb (GtkButton *button,
+ EmpathyContactWidget *information)
+{
+ GtkTreeView *view;
+ GtkListStore *store;
+ GtkTreeIter iter;
+ const gchar *group;
+
+ view = GTK_TREE_VIEW (information->treeview_groups);
+ store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
+
+ group = gtk_entry_get_text (GTK_ENTRY (information->entry_group));
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_NAME, group,
+ COL_ENABLED, TRUE,
+ -1);
+
+ empathy_contact_list_add_to_group (EMPATHY_CONTACT_LIST (information->manager),
+ information->contact,
+ group);
+}
+
+static void
+contact_widget_details_setup (EmpathyContactWidget *information)
+{
+ /* FIXME: Needs new telepathy spec */
+ gtk_widget_hide (information->vbox_details);
+}
+
+static void
+contact_widget_details_update (EmpathyContactWidget *information)
+{
+ /* FIXME: Needs new telepathy spec */
+}
+
+static void
+contact_widget_client_setup (EmpathyContactWidget *information)
+{
+ /* FIXME: Needs new telepathy spec */
+ gtk_widget_hide (information->vbox_client);
+}
+
+static void
+contact_widget_client_update (EmpathyContactWidget *information)
+{
+ /* FIXME: Needs new telepathy spec */
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-contact-widget.glade b/gnome-2-22/libempathy-gtk/empathy-contact-widget.glade
new file mode 100644
index 000000000..4b204b7b6
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-contact-widget.glade
@@ -0,0 +1,983 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="contact_window">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Contact information</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox_contact_widget">
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox_contact">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label654">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Contact&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment31">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox189">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox225">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkTable" id="table_contact">
+ <property name="visible">True</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label_alias">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Alias:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label655">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Identifier:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label680">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Account:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox_presence">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkImage" id="image_state">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_status">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox_avatar">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox_groups">
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label672">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Groups&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment33">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox224">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label679">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Select the groups you want this contact to appear in, you can select more than one group or no groups.</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox188">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkEntry" id="entry_group">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button_group">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="label">_Add Group</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow17">
+ <property name="height_request">100</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="treeview_groups">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">False</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox_details">
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label649">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Contact Details&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment30">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox218">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkTable" id="table_details">
+ <property name="n_rows">4</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label652">
+ <property name="label" translatable="yes">Birthday:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label651">
+ <property name="label" translatable="yes">Web site:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label650">
+ <property name="label" translatable="yes">Email:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label670">
+ <property name="label" translatable="yes">Fullname:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox_details_requested">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkImage" id="image885">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-info</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label653">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Information requested...</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox_client">
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label662">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Client Information&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment32">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox222">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkTable" id="table_client">
+ <property name="n_rows">3</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label_os">
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">2</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_version">
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">2</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_client">
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">2</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label666">
+ <property name="label" translatable="yes">Client:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label667">
+ <property name="label" translatable="yes">Version:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label668">
+ <property name="label" translatable="yes">OS:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox_client_requested">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkImage" id="image887">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-info</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label669">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Information requested...</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-contact-widget.h b/gnome-2-22/libempathy-gtk/empathy-contact-widget.h
new file mode 100644
index 000000000..643867ef5
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-contact-widget.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_CONTACT_WIDGET_H__
+#define __EMPATHY_CONTACT_WIDGET_H__
+
+#include <gtk/gtk.h>
+
+#include <libempathy/empathy-contact.h>
+#include "empathy-account-chooser.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+ EMPATHY_CONTACT_WIDGET_EDIT_NONE = 0,
+ EMPATHY_CONTACT_WIDGET_EDIT_ALIAS = 1 << 0,
+ EMPATHY_CONTACT_WIDGET_EDIT_AVATAR = 1 << 1,
+ EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT = 1 << 2,
+ EMPATHY_CONTACT_WIDGET_EDIT_ID = 1 << 3,
+ EMPATHY_CONTACT_WIDGET_EDIT_GROUPS = 1 << 4,
+} EmpathyContactWidgetFlags;
+
+GtkWidget * empathy_contact_widget_new (EmpathyContact *contact,
+ EmpathyContactWidgetFlags flags);
+EmpathyContact *empathy_contact_widget_get_contact (GtkWidget *widget);
+void empathy_contact_widget_set_contact (GtkWidget *widget,
+ EmpathyContact *contact);
+void empathy_contact_widget_set_account_filter (GtkWidget *widget,
+ EmpathyAccountChooserFilterFunc filter,
+ gpointer user_data);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_CONTACT_WIDGET_H__ */
diff --git a/gnome-2-22/libempathy-gtk/empathy-geometry.c b/gnome-2-22/libempathy-gtk/empathy-geometry.c
new file mode 100644
index 000000000..c8bbd2b21
--- /dev/null
+++ b/gnome-2-22/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-2008 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 <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <sys/stat.h>
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+#include <libempathy/empathy-debug.h>
+
+#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/gnome-2-22/libempathy-gtk/empathy-geometry.h b/gnome-2-22/libempathy-gtk/empathy-geometry.h
new file mode 100644
index 000000000..512b64696
--- /dev/null
+++ b/gnome-2-22/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 <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_GEOMETRY_H__
+#define __EMPATHY_GEOMETRY_H__
+
+#include <glib.h>
+
+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/gnome-2-22/libempathy-gtk/empathy-group-chat.c b/gnome-2-22/libempathy-gtk/empathy-group-chat.c
new file mode 100644
index 000000000..16fb841be
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-group-chat.c
@@ -0,0 +1,700 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002-2007 Imendio AB
+ * Copyright (C) 2007-2008 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 <micke@imendio.com>
+ * Richard Hult <richard@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <glib/gi18n.h>
+
+#include <telepathy-glib/util.h>
+
+#include <libempathy/empathy-tp-chat.h>
+#include <libempathy/empathy-tp-chatroom.h>
+#include <libempathy/empathy-contact.h>
+#include <libempathy/empathy-utils.h>
+#include <libempathy/empathy-debug.h>
+
+#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"
+#include "empathy-conf.h"
+#include "empathy-preferences.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_members_changed_cb (EmpathyTpChatroom *tp_chat,
+ EmpathyContact *contact,
+ EmpathyContact *actor,
+ guint reason,
+ gchar *message,
+ gboolean is_member,
+ 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 (EmpathyChat *chat,
+ GdkEventKey *event);
+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;
+ chat_class->key_press_event = group_chat_key_press_event;
+
+ 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 (EmpathyTpChatroom *tp_chat)
+{
+ EmpathyGroupChat *chat;
+
+ g_return_val_if_fail (EMPATHY_IS_TP_CHAT (tp_chat), NULL);
+
+ chat = g_object_new (EMPATHY_TYPE_GROUP_CHAT,
+ "tp-chat", tp_chat,
+ NULL);
+
+ 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 ((GCompletionFunc) empathy_contact_get_name);
+ 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_members_changed_cb (EmpathyTpChatroom *tp_chat,
+ EmpathyContact *contact,
+ EmpathyContact *actor,
+ guint reason,
+ gchar *message,
+ gboolean is_member,
+ EmpathyGroupChat *chat)
+{
+ if (!EMPATHY_CHAT (chat)->block_events) {
+ gchar *str;
+ if (is_member) {
+ str = g_strdup_printf (_("%s has joined the room"),
+ empathy_contact_get_name (contact));
+ } else {
+ 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);
+
+ if (empathy_tp_chatroom_get_invitation (priv->tp_chat, NULL, NULL)) {
+ 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,
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_CHAT |
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_CALL |
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_LOG |
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_FT |
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_INVITE |
+ EMPATHY_CONTACT_LIST_FEATURE_CONTACT_INFO);
+
+ 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, "members-changed",
+ G_CALLBACK (group_chat_members_changed_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 = NULL;
+
+ priv = GET_PRIV (chat);
+
+ g_object_get (priv->tp_chat, "subject", &str, NULL);
+ if (!tp_strdiff (priv->topic, str)) {
+ g_free (str);
+ return;
+ }
+
+ g_free (priv->topic);
+ priv->topic = str;
+ gtk_label_set_text (GTK_LABEL (priv->label_topic), priv->topic);
+
+ if (!EMPATHY_CHAT (chat)->block_events) {
+ if (!G_STR_EMPTY (priv->topic)) {
+ str = g_strdup_printf (_("Topic set to: %s"), priv->topic);
+ } else {
+ str = g_strdup (_("No topic defined"));
+ }
+ 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);
+}
+
+static gboolean
+group_chat_key_press_event (EmpathyChat *chat,
+ GdkEventKey *event)
+{
+ EmpathyGroupChatPriv *priv = GET_PRIV (chat);
+
+ if (!(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) &&
+ event->keyval == GDK_Tab) {
+ GtkTextBuffer *buffer;
+ GtkTextIter start, current;
+ gchar *nick, *completed;
+ GList *list, *completed_list;
+ gboolean is_start_of_buffer;
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (EMPATHY_CHAT (chat)->input_text_view));
+ gtk_text_buffer_get_iter_at_mark (buffer, &current, 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);
+
+ list = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (priv->tp_chat));
+ g_completion_add_items (priv->completion, list);
+
+ nick = gtk_text_buffer_get_text (buffer, &start, &current, FALSE);
+ completed_list = g_completion_complete (priv->completion,
+ nick,
+ &completed);
+
+ g_free (nick);
+
+ if (completed) {
+ guint len;
+ const gchar *text;
+ gchar *complete_char = NULL;
+
+ gtk_text_buffer_delete (buffer, &start, &current);
+
+ 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 = empathy_contact_get_name (completed_list->data);
+ } else {
+ text = completed;
+ }
+
+ gtk_text_buffer_insert_at_cursor (buffer, text, strlen (text));
+
+ if (len == 1 && is_start_of_buffer &&
+ empathy_conf_get_string (empathy_conf_get (),
+ EMPATHY_PREFS_CHAT_NICK_COMPLETION_CHAR,
+ &complete_char) &&
+ complete_char != NULL) {
+ gtk_text_buffer_insert_at_cursor (buffer,
+ complete_char,
+ strlen (complete_char));
+ gtk_text_buffer_insert_at_cursor (buffer, " ", 1);
+ g_free (complete_char);
+ }
+
+ g_free (completed);
+ }
+
+ g_completion_clear_items (priv->completion);
+
+ g_list_foreach (list, (GFunc) g_object_unref, NULL);
+ g_list_free (list);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+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/gnome-2-22/libempathy-gtk/empathy-group-chat.glade b/gnome-2-22/libempathy-gtk/empathy-group-chat.glade
new file mode 100644
index 000000000..5b40dc375
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-group-chat.glade
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+ <widget class="GtkWindow" id="group_chat_window">
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes">Group Chat</property>
+ <property name="default_width">1000</property>
+ <property name="default_height">800</property>
+ <property name="icon_name">system-users</property>
+ <child>
+ <widget class="GtkVBox" id="group_chat_widget">
+ <property name="visible">True</property>
+ <property name="border_width">4</property>
+ <property name="spacing">6</property>
+ <child>
+ <widget class="GtkHBox" id="hbox_topic">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <widget class="GtkLabel" id="label80">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="label" translatable="yes">&lt;b&gt;Topic:&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label_topic">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="xalign">0</property>
+ <property name="use_markup">True</property>
+ <property name="wrap">True</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_END</property>
+ <property name="single_line_mode">True</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHPaned" id="hpaned">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <widget class="GtkVBox" id="vbox_left">
+ <property name="width_request">600</property>
+ <property name="height_request">500</property>
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolled_window_chat">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolled_window_input">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="resize">True</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolled_window_contacts">
+ <property name="width_request">200</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="resize">True</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-group-chat.h b/gnome-2-22/libempathy-gtk/empathy-group-chat.h
new file mode 100644
index 000000000..e0ce79462
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-group-chat.h
@@ -0,0 +1,67 @@
+/* -*- 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 <micke@imendio.com>
+ * Richard Hult <richard@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_GROUP_CHAT_H__
+#define __EMPATHY_GROUP_CHAT_H__
+
+G_BEGIN_DECLS
+
+#include <libempathy/empathy-tp-chatroom.h>
+#include <libempathy/empathy-contact.h>
+
+#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 (EmpathyTpChatroom *tp_chat);
+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/gnome-2-22/libempathy-gtk/empathy-images.h b/gnome-2-22/libempathy-gtk/empathy-images.h
new file mode 100644
index 000000000..254467819
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-images.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_IMAGES_H__
+#define __EMPATHY_IMAGES_H__
+
+G_BEGIN_DECLS
+
+#define EMPATHY_IMAGE_OFFLINE "empathy-offline"
+#define EMPATHY_IMAGE_HIDDEN "empathy-offline"
+#define EMPATHY_IMAGE_AVAILABLE "empathy-available"
+#define EMPATHY_IMAGE_BUSY "empathy-busy"
+#define EMPATHY_IMAGE_AWAY "empathy-away"
+#define EMPATHY_IMAGE_EXT_AWAY "empathy-extended-away"
+#define EMPATHY_IMAGE_UNKNOWN "empathy-pending"
+
+#define EMPATHY_IMAGE_MESSAGE "im-message"
+#define EMPATHY_IMAGE_NEW_MESSAGE "im-message-new"
+#define EMPATHY_IMAGE_TYPING "user-typing"
+#define EMPATHY_IMAGE_CONTACT_INFORMATION "gtk-info"
+#define EMPATHY_IMAGE_GROUP_MESSAGE "system-users"
+#define EMPATHY_IMAGE_VOIP "gnome-stock-mic"
+#define EMPATHY_IMAGE_LOG "document-open-recent"
+
+G_END_DECLS
+
+#endif /* __EMPATHY_IMAGES_ICONS_H__ */
diff --git a/gnome-2-22/libempathy-gtk/empathy-irc-network-dialog.c b/gnome-2-22/libempathy-gtk/empathy-irc-network-dialog.c
new file mode 100644
index 000000000..9a42c649c
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-irc-network-dialog.c
@@ -0,0 +1,579 @@
+/*
+ * Copyright (C) 2007-2008 Guillaume Desmottes
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Guillaume Desmottes <gdesmott@gnome.org>
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+
+#include <libmissioncontrol/mc-account.h>
+#include <libmissioncontrol/mc-protocol.h>
+
+#include <libempathy/empathy-utils.h>
+#include <libempathy/empathy-debug.h>
+
+#include <libempathy/empathy-irc-network-manager.h>
+#include "empathy-ui-utils.h"
+#include "totem-subtitle-encoding.h"
+
+#include "empathy-irc-network-dialog.h"
+
+#define DEBUG_DOMAIN "AccountWidgetIRC"
+
+typedef struct {
+ EmpathyIrcNetwork *network;
+
+ GtkWidget *dialog;
+ GtkWidget *button_close;
+
+ GtkWidget *entry_network;
+ GtkWidget *combobox_charset;
+
+ GtkWidget *treeview_servers;
+ GtkWidget *button_add;
+ GtkWidget *button_remove;
+ GtkWidget *button_up;
+ GtkWidget *button_down;
+} EmpathyIrcNetworkDialog;
+
+static void
+irc_network_dialog_destroy_cb (GtkWidget *widget,
+ EmpathyIrcNetworkDialog *dialog)
+{
+ g_object_unref (dialog->network);
+
+ g_slice_free (EmpathyIrcNetworkDialog, dialog);
+}
+
+static void
+irc_network_dialog_close_clicked_cb (GtkWidget *widget,
+ EmpathyIrcNetworkDialog *dialog)
+{
+ gtk_widget_destroy (dialog->dialog);
+}
+
+enum {
+ COL_SRV_OBJ,
+ COL_ADR,
+ COL_PORT,
+ COL_SSL
+};
+
+static void
+add_server_to_store (GtkListStore *store,
+ EmpathyIrcServer *server,
+ GtkTreeIter *iter)
+{
+ gchar *address;
+ guint port;
+ gboolean ssl;
+
+ g_object_get (server,
+ "address", &address,
+ "port", &port,
+ "ssl", &ssl,
+ NULL);
+
+ gtk_list_store_insert_with_values (store, iter, -1,
+ COL_SRV_OBJ, server,
+ COL_ADR, address,
+ COL_PORT, port,
+ COL_SSL, ssl,
+ -1);
+
+ g_free (address);
+}
+
+static void
+irc_network_dialog_setup (EmpathyIrcNetworkDialog *dialog)
+{
+ gchar *name, *charset;
+ GSList *servers, *l;
+ GtkListStore *store;
+
+ g_object_get (dialog->network,
+ "name", &name,
+ "charset", &charset,
+ NULL);
+ gtk_entry_set_text (GTK_ENTRY (dialog->entry_network), name);
+
+ store = GTK_LIST_STORE (gtk_tree_view_get_model (
+ GTK_TREE_VIEW (dialog->treeview_servers)));
+
+ servers = empathy_irc_network_get_servers (dialog->network);
+ for (l = servers; l != NULL; l = g_slist_next (l))
+ {
+ EmpathyIrcServer *server = l->data;
+ GtkTreeIter iter;
+
+ add_server_to_store (store, server, &iter);
+ }
+
+ totem_subtitle_encoding_set (GTK_COMBO_BOX (dialog->combobox_charset),
+ charset);
+
+ g_slist_foreach (servers, (GFunc) g_object_unref, NULL);
+ g_slist_free (servers);
+ g_free (name);
+ g_free (charset);
+}
+
+static void
+irc_network_dialog_address_edited_cb (GtkCellRendererText *renderer,
+ gchar *path,
+ gchar *new_text,
+ EmpathyIrcNetworkDialog *dialog)
+{
+ EmpathyIrcServer *server;
+ GtkTreeModel *model;
+ GtkTreePath *treepath;
+ GtkTreeIter iter;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview_servers));
+ treepath = gtk_tree_path_new_from_string (path);
+ gtk_tree_model_get_iter (model, &iter, treepath);
+ gtk_tree_model_get (model, &iter,
+ COL_SRV_OBJ, &server,
+ -1);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+ COL_ADR, new_text,
+ -1);
+
+ g_object_set (server, "address", new_text, NULL);
+
+ gtk_tree_path_free (treepath);
+ g_object_unref (server);
+}
+
+static void
+irc_network_dialog_port_edited_cb (GtkCellRendererText *renderer,
+ gchar *path,
+ gchar *new_text,
+ EmpathyIrcNetworkDialog *dialog)
+{
+ EmpathyIrcServer *server;
+ GtkTreeModel *model;
+ GtkTreePath *treepath;
+ GtkTreeIter iter;
+ guint port;
+
+ port = strtoul (new_text, NULL, 10);
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview_servers));
+ treepath = gtk_tree_path_new_from_string (path);
+ gtk_tree_model_get_iter (model, &iter, treepath);
+ gtk_tree_model_get (model, &iter,
+ COL_SRV_OBJ, &server,
+ -1);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+ COL_PORT, port,
+ -1);
+
+ g_object_set (server, "port", port, NULL);
+
+ gtk_tree_path_free (treepath);
+ g_object_unref (server);
+}
+
+static void
+irc_network_dialog_ssl_toggled_cb (GtkCellRendererText *renderer,
+ gchar *path,
+ EmpathyIrcNetworkDialog *dialog)
+{
+ EmpathyIrcServer *server;
+ GtkTreeModel *model;
+ GtkTreePath *treepath;
+ GtkTreeIter iter;
+ gboolean ssl;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview_servers));
+ treepath = gtk_tree_path_new_from_string (path);
+ gtk_tree_model_get_iter (model, &iter, treepath);
+ gtk_tree_model_get (model, &iter,
+ COL_SRV_OBJ, &server,
+ COL_SSL, &ssl,
+ -1);
+ ssl = !ssl;
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+ COL_SSL, ssl,
+ -1);
+
+ g_object_set (server, "ssl", ssl, NULL);
+
+ gtk_tree_path_free (treepath);
+ g_object_unref (server);
+}
+
+static gboolean
+irc_network_dialog_network_focus_cb (GtkWidget *widget,
+ GdkEventFocus *event,
+ EmpathyIrcNetworkDialog *dialog)
+{
+ const gchar *str;
+
+ str = gtk_entry_get_text (GTK_ENTRY (widget));
+
+ g_object_set (dialog->network, "name", str, NULL);
+
+ return FALSE;
+}
+
+static void
+irc_network_dialog_network_update_buttons (EmpathyIrcNetworkDialog *dialog)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ gboolean can_remove = FALSE, can_move_up = FALSE, can_move_down = FALSE;
+ int selected;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (
+ dialog->treeview_servers));
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter))
+ {
+ path = gtk_tree_model_get_path (model, &iter);
+
+ selected = gtk_tree_path_get_indices (path)[0];
+
+ can_remove = TRUE;
+ can_move_up = selected > 0;
+ can_move_down =
+ selected < gtk_tree_model_iter_n_children (model, NULL) - 1;
+
+ gtk_tree_path_free (path);
+ }
+
+ gtk_widget_set_sensitive (dialog->button_remove, can_remove);
+ gtk_widget_set_sensitive (dialog->button_up, can_move_up);
+ gtk_widget_set_sensitive (dialog->button_down, can_move_down);
+}
+
+static void
+irc_network_dialog_button_add_clicked_cb (GtkWidget *widget,
+ EmpathyIrcNetworkDialog *dialog)
+{
+ EmpathyIrcServer *server;
+ GtkListStore *store;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+
+ store = GTK_LIST_STORE (gtk_tree_view_get_model (
+ GTK_TREE_VIEW (dialog->treeview_servers)));
+
+ server = empathy_irc_server_new (_("new server"), 6667, FALSE);
+ empathy_irc_network_append_server (dialog->network, server);
+ add_server_to_store (store, server, &iter);
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW (dialog->treeview_servers),
+ 0);
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (dialog->treeview_servers), path,
+ column, TRUE);
+
+ irc_network_dialog_network_update_buttons (dialog);
+
+ gtk_tree_path_free (path);
+ g_object_unref (server);
+}
+
+static void
+irc_network_dialog_button_remove_clicked_cb (GtkWidget *widget,
+ EmpathyIrcNetworkDialog *dialog)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ EmpathyIrcServer *server;
+
+ selection = gtk_tree_view_get_selection (
+ GTK_TREE_VIEW (dialog->treeview_servers));
+
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return;
+
+ gtk_tree_model_get (model, &iter, COL_SRV_OBJ, &server, -1);
+
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+ empathy_irc_network_remove_server (dialog->network, server);
+
+ irc_network_dialog_network_update_buttons (dialog);
+
+ g_object_unref (server);
+}
+
+static void
+irc_network_dialog_button_up_clicked_cb (GtkWidget *widget,
+ EmpathyIrcNetworkDialog *dialog)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter, iter_prev;
+ GtkTreePath *path;
+ gint *pos;
+ EmpathyIrcServer *server;
+
+ selection = gtk_tree_view_get_selection (
+ GTK_TREE_VIEW (dialog->treeview_servers));
+
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return;
+
+ path = gtk_tree_model_get_path (model, &iter);
+
+ if (!gtk_tree_path_prev (path))
+ {
+ gtk_tree_path_free (path);
+ return;
+ }
+
+ gtk_tree_model_get (model, &iter, COL_SRV_OBJ, &server, -1);
+
+ gtk_tree_model_get_iter (model, &iter_prev, path);
+ gtk_list_store_swap (GTK_LIST_STORE (model), &iter_prev, &iter);
+
+ pos = gtk_tree_path_get_indices (path);
+ empathy_irc_network_set_server_position (dialog->network, server, *pos);
+
+ irc_network_dialog_network_update_buttons (dialog);
+
+ g_object_unref (server);
+ gtk_tree_path_free (path);
+}
+
+static void
+irc_network_dialog_button_down_clicked_cb (GtkWidget *widget,
+ EmpathyIrcNetworkDialog *dialog)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter, iter_prev;
+ GtkTreePath *path;
+ EmpathyIrcServer *server;
+ gint *pos;
+
+ selection = gtk_tree_view_get_selection (
+ GTK_TREE_VIEW (dialog->treeview_servers));
+
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return;
+
+ path = gtk_tree_model_get_path (model, &iter);
+
+ gtk_tree_path_next (path);
+ if (!gtk_tree_model_get_iter (model, &iter_prev, path))
+ {
+ gtk_tree_path_free (path);
+ return;
+ }
+
+ gtk_tree_model_get (model, &iter, COL_SRV_OBJ, &server, -1);
+
+ gtk_list_store_swap (GTK_LIST_STORE (model), &iter_prev, &iter);
+
+ pos = gtk_tree_path_get_indices (path);
+ empathy_irc_network_set_server_position (dialog->network, server, *pos);
+
+ irc_network_dialog_network_update_buttons (dialog);
+
+ gtk_tree_path_free (path);
+}
+
+static void
+irc_network_dialog_selection_changed_cb (GtkTreeSelection *treeselection,
+ EmpathyIrcNetworkDialog *dialog)
+{
+ irc_network_dialog_network_update_buttons (dialog);
+}
+
+static void
+irc_network_dialog_combobox_charset_changed_cb (GtkWidget *combobox,
+ EmpathyIrcNetworkDialog *dialog)
+{
+ const gchar *charset;
+
+ charset = totem_subtitle_encoding_get_selected (GTK_COMBO_BOX (combobox));
+ g_object_set (dialog->network, "charset", charset, NULL);
+}
+
+static void
+change_network (EmpathyIrcNetworkDialog *dialog,
+ EmpathyIrcNetwork *network)
+{
+ GtkListStore *store;
+
+ if (dialog->network == network)
+ /* No need to change */
+ return;
+
+ if (dialog->network != NULL)
+ {
+ g_object_unref (dialog->network);
+ }
+
+ dialog->network = network;
+ g_object_ref (network);
+
+ store = GTK_LIST_STORE (gtk_tree_view_get_model (
+ GTK_TREE_VIEW (dialog->treeview_servers)));
+ gtk_list_store_clear (store);
+
+ irc_network_dialog_setup (dialog);
+}
+
+/**
+ * empathy_irc_network_dialog_show:
+ * @network: the #EmpathyIrcNetwork to configure
+ * @parent: the parent of this dialog
+ *
+ * Display a dialog to configure a given #EmpathyIrcNetwork.
+ * This function is a singleton so if a configuration dialog already
+ * exists we use this one to edit the network.
+ *
+ * Returns: The displayed #GtkDialog
+ */
+GtkWidget *
+empathy_irc_network_dialog_show (EmpathyIrcNetwork *network,
+ GtkWidget *parent)
+{
+ static EmpathyIrcNetworkDialog *dialog = NULL;
+ GladeXML *glade;
+ GtkListStore *store;
+ GtkCellRenderer *renderer;
+ GtkAdjustment *adjustment;
+ GtkTreeSelection *selection;
+ GtkTreeViewColumn *column;
+
+ g_return_val_if_fail (network != NULL, NULL);
+
+ if (dialog != NULL)
+ {
+ change_network (dialog, network);
+ gtk_window_present (GTK_WINDOW (dialog->dialog));
+
+ return dialog->dialog;
+ }
+
+ dialog = g_slice_new0 (EmpathyIrcNetworkDialog);
+
+ dialog->network = network;
+ g_object_ref (dialog->network);
+
+ glade = empathy_glade_get_file ("empathy-account-widget-irc.glade",
+ "irc_network_dialog",
+ NULL,
+ "irc_network_dialog", &dialog->dialog,
+ "button_close", &dialog->button_close,
+ "entry_network", &dialog->entry_network,
+ "combobox_charset", &dialog->combobox_charset,
+ "treeview_servers", &dialog->treeview_servers,
+ "button_add", &dialog->button_add,
+ "button_remove", &dialog->button_remove,
+ "button_up", &dialog->button_up,
+ "button_down", &dialog->button_down,
+ NULL);
+
+ store = gtk_list_store_new (4, G_TYPE_OBJECT, G_TYPE_STRING,
+ G_TYPE_UINT, G_TYPE_BOOLEAN);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->treeview_servers),
+ GTK_TREE_MODEL (store));
+ g_object_unref (store);
+
+ /* address */
+ renderer = gtk_cell_renderer_text_new ();
+ g_object_set (renderer, "editable", TRUE, NULL);
+ g_signal_connect (renderer, "edited",
+ G_CALLBACK (irc_network_dialog_address_edited_cb), dialog);
+ gtk_tree_view_insert_column_with_attributes (
+ GTK_TREE_VIEW (dialog->treeview_servers),
+ -1, _("Server"), renderer, "text", COL_ADR,
+ NULL);
+
+ /* port */
+ adjustment = (GtkAdjustment *) gtk_adjustment_new (6667, 1, G_MAXUINT16,
+ 1, 10, 0);
+ renderer = gtk_cell_renderer_spin_new ();
+ g_object_set (renderer,
+ "editable", TRUE,
+ "adjustment", adjustment,
+ NULL);
+ g_signal_connect (renderer, "edited",
+ G_CALLBACK (irc_network_dialog_port_edited_cb), dialog);
+ gtk_tree_view_insert_column_with_attributes (
+ GTK_TREE_VIEW (dialog->treeview_servers),
+ -1, _("Port"), renderer, "text", COL_PORT,
+ NULL);
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW (dialog->treeview_servers),
+ 1);
+ gtk_tree_view_column_set_expand (column, TRUE);
+
+ /* SSL */
+ renderer = gtk_cell_renderer_toggle_new ();
+ g_object_set (renderer, "activatable", TRUE, NULL);
+ g_signal_connect (renderer, "toggled",
+ G_CALLBACK (irc_network_dialog_ssl_toggled_cb), dialog);
+ gtk_tree_view_insert_column_with_attributes (
+ GTK_TREE_VIEW (dialog->treeview_servers),
+ -1, _("SSL"), renderer, "active", COL_SSL,
+ NULL);
+
+ selection = gtk_tree_view_get_selection (
+ GTK_TREE_VIEW (dialog->treeview_servers));
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+
+ /* charset */
+ totem_subtitle_encoding_init (GTK_COMBO_BOX (dialog->combobox_charset));
+
+ irc_network_dialog_setup (dialog);
+
+ empathy_glade_connect (glade, dialog,
+ "irc_network_dialog", "destroy", irc_network_dialog_destroy_cb,
+ "button_close", "clicked", irc_network_dialog_close_clicked_cb,
+ "entry_network", "focus-out-event", irc_network_dialog_network_focus_cb,
+ "button_add", "clicked", irc_network_dialog_button_add_clicked_cb,
+ "button_remove", "clicked", irc_network_dialog_button_remove_clicked_cb,
+ "button_up", "clicked", irc_network_dialog_button_up_clicked_cb,
+ "button_down", "clicked", irc_network_dialog_button_down_clicked_cb,
+ "combobox_charset", "changed", irc_network_dialog_combobox_charset_changed_cb,
+ NULL);
+
+ g_object_unref (glade);
+
+ g_object_add_weak_pointer (G_OBJECT (dialog->dialog),
+ (gpointer) &dialog);
+
+ g_signal_connect (selection, "changed",
+ G_CALLBACK (irc_network_dialog_selection_changed_cb),
+ dialog);
+
+ gtk_window_set_transient_for (GTK_WINDOW (dialog->dialog),
+ GTK_WINDOW (parent));
+ gtk_window_set_modal (GTK_WINDOW (dialog->dialog), TRUE);
+
+ irc_network_dialog_network_update_buttons (dialog);
+
+ return dialog->dialog;
+}
diff --git a/gnome-2-22/libempathy-gtk/empathy-irc-network-dialog.h b/gnome-2-22/libempathy-gtk/empathy-irc-network-dialog.h
new file mode 100644
index 000000000..985849696
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-irc-network-dialog.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007-2008 Guillaume Desmottes
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Guillaume Desmottes <gdesmott@gnome.org>
+ */
+
+#ifndef __EMPATHY_IRC_NETWORK_DIALOG_H__
+#define __EMPATHY_IRC_NETWORK_DIALOG_H__
+
+#include <gtk/gtkwidget.h>
+
+#include <libempathy/empathy-irc-network.h>
+
+G_BEGIN_DECLS
+
+GtkWidget * empathy_irc_network_dialog_show (EmpathyIrcNetwork *network,
+ GtkWidget *parent);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_IRC_NETWORK_DIALOG_H__ */
diff --git a/gnome-2-22/libempathy-gtk/empathy-log-window.c b/gnome-2-22/libempathy-gtk/empathy-log-window.c
new file mode 100644
index 000000000..c239ef5c3
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-log-window.c
@@ -0,0 +1,1104 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006-2007 Imendio AB
+ * Copyright (C) 2007-2008 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 <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+
+#include <libempathy/empathy-log-manager.h>
+#include <libempathy/empathy-chatroom-manager.h>
+#include <libempathy/empathy-chatroom.h>
+#include <libempathy/empathy-message.h>
+#include <libempathy/empathy-debug.h>
+#include <libempathy/empathy-utils.h>
+#include <libempathy/empathy-time.h>
+
+#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
+};
+
+GtkWidget *
+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->window;
+ }
+
+ 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);
+
+ 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);
+
+ return 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);
+
+ if (!date) {
+ goto OUT;
+ }
+
+ /* 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);
+
+ /* 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);
+
+OUT:
+ g_list_foreach (dates, (GFunc) g_free, NULL);
+ g_list_free (dates);
+ g_object_unref (account);
+ g_free (chat_id);
+}
+
+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/gnome-2-22/libempathy-gtk/empathy-log-window.glade b/gnome-2-22/libempathy-gtk/empathy-log-window.glade
new file mode 100644
index 000000000..8dfd59c99
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-log-window.glade
@@ -0,0 +1,470 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="log_window">
+ <property name="title" translatable="yes">Previous Conversations</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="default_width">640</property>
+ <property name="default_height">450</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="icon_name">document-open-recent</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+
+ <child>
+ <widget class="GtkNotebook" id="notebook">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="show_tabs">True</property>
+ <property name="show_border">True</property>
+ <property name="tab_pos">GTK_POS_TOP</property>
+ <property name="scrollable">False</property>
+ <property name="enable_popup">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox192">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox144">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label628">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_For:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_find</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_find">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button_find">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-find</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVPaned" id="vpaned1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="position">120</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow14">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="treeview_find">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">False</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">True</property>
+ <property name="resize">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox215">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow_find">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox171">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <placeholder/>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button_next">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-go-forward</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button_previous">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-go-back</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">True</property>
+ <property name="resize">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label595">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Search</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table7">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox143">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkImage" id="image247">
+ <property name="visible">True</property>
+ <property name="stock">gtk-find</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_chats">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox191">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow13">
+ <property name="width_request">150</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="treeview_chats">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCalendar" id="calendar_chats">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="display_options">GTK_CALENDAR_SHOW_HEADING|GTK_CALENDAR_SHOW_DAY_NAMES</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow_chats">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox_chats">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label596">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Conversations</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-log-window.h b/gnome-2-22/libempathy-gtk/empathy-log-window.h
new file mode 100644
index 000000000..a45cbbb84
--- /dev/null
+++ b/gnome-2-22/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 <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_LOG_WINDOW_H__
+#define __EMPATHY_LOG_WINDOW_H__
+
+#include <libmissioncontrol/mc-account.h>
+
+G_BEGIN_DECLS
+
+GtkWidget * 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/gnome-2-22/libempathy-gtk/empathy-main-window.c b/gnome-2-22/libempathy-gtk/empathy-main-window.c
new file mode 100644
index 000000000..ca8a16abf
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-main-window.c
@@ -0,0 +1,1160 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002-2007 Imendio AB
+ * Copyright (C) 2007-2008 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 <xclaesse@gmail.com>
+ */
+
+#include <config.h>
+
+#include <sys/stat.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <glib/gi18n.h>
+
+#include <libempathy/empathy-contact.h>
+#include <libempathy/empathy-debug.h>
+#include <libempathy/empathy-utils.h>
+#include <libempathy/empathy-chatroom-manager.h>
+#include <libempathy/empathy-chatroom.h>
+#include <libempathy/empathy-contact-list.h>
+#include <libempathy/empathy-contact-manager.h>
+#include <libempathy/empathy-contact-factory.h>
+#include <libempathy/empathy-status-presets.h>
+
+#include "empathy-main-window.h"
+#include "empathy-contact-dialogs.h"
+#include "ephy-spinner.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-geometry.h"
+#include "empathy-conf.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"
+#include "empathy-new-message-dialog.h"
+#include "empathy-gtk-enum-types.h"
+
+#define DEBUG_DOMAIN "MainWindow"
+
+/* Minimum width of roster window if something goes wrong. */
+#define MIN_WIDTH 50
+
+/* Accels (menu shortcuts) can be configured and saved */
+#define ACCELS_FILENAME "accels.txt"
+
+/* Name in the geometry file */
+#define GEOMETRY_NAME "main-window"
+
+typedef struct {
+ EmpathyContactListView *list_view;
+ EmpathyContactListStore *list_store;
+ MissionControl *mc;
+ EmpathyChatroomManager *chatroom_manager;
+
+ GtkWidget *window;
+ GtkWidget *main_vbox;
+ GtkWidget *throbber;
+ GtkWidget *presence_toolbar;
+ GtkWidget *presence_chooser;
+ GtkWidget *errors_vbox;
+
+ GtkWidget *room;
+ GtkWidget *room_menu;
+ GtkWidget *room_sep;
+ GtkWidget *room_join_favorites;
+ GtkWidget *edit_context;
+ GtkWidget *edit_context_separator;
+
+ guint size_timeout_id;
+ GHashTable *errors;
+
+ /* Widgets that are enabled when there is... */
+ GList *widgets_connected; /* ... connected accounts */
+ GList *widgets_disconnected; /* ... disconnected accounts */
+} EmpathyMainWindow;
+
+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 (EmpathyChatroomManager *manager,
+ EmpathyChatroom *chatroom,
+ EmpathyMainWindow *window);
+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,
+ EmpathyChatroom *chatroom);
+static void main_window_favorite_chatroom_menu_update (EmpathyMainWindow *window);
+static void main_window_favorite_chatroom_menu_add (EmpathyMainWindow *window,
+ 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,
+ EmpathyMainWindow *window);
+static void main_window_chat_history_cb (GtkWidget *widget,
+ EmpathyMainWindow *window);
+static void main_window_room_join_new_cb (GtkWidget *widget,
+ EmpathyMainWindow *window);
+static void main_window_room_join_favorites_cb (GtkWidget *widget,
+ EmpathyMainWindow *window);
+static void main_window_room_manage_favorites_cb (GtkWidget *widget,
+ EmpathyMainWindow *window);
+static void main_window_chat_add_contact_cb (GtkWidget *widget,
+ EmpathyMainWindow *window);
+static void main_window_chat_show_offline_cb (GtkCheckMenuItem *item,
+ EmpathyMainWindow *window);
+static gboolean main_window_edit_button_press_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ EmpathyMainWindow *window);
+static void main_window_edit_accounts_cb (GtkWidget *widget,
+ EmpathyMainWindow *window);
+static void main_window_edit_personal_information_cb (GtkWidget *widget,
+ EmpathyMainWindow *window);
+static void main_window_edit_preferences_cb (GtkWidget *widget,
+ EmpathyMainWindow *window);
+static void main_window_help_about_cb (GtkWidget *widget,
+ EmpathyMainWindow *window);
+static void main_window_help_contents_cb (GtkWidget *widget,
+ EmpathyMainWindow *window);
+static gboolean main_window_throbber_button_press_event_cb (GtkWidget *throbber_ebox,
+ GdkEventButton *event,
+ EmpathyMainWindow *window);
+static void main_window_status_changed_cb (MissionControl *mc,
+ TpConnectionStatus status,
+ McPresence presence,
+ TpConnectionStatusReason reason,
+ const gchar *unique_name,
+ EmpathyMainWindow *window);
+static void main_window_update_status (EmpathyMainWindow *window);
+static void main_window_accels_load (void);
+static void main_window_accels_save (void);
+static void main_window_connection_items_setup (EmpathyMainWindow *window,
+ GladeXML *glade);
+static gboolean main_window_configure_event_timeout_cb (EmpathyMainWindow *window);
+static gboolean main_window_configure_event_cb (GtkWidget *widget,
+ GdkEventConfigure *event,
+ EmpathyMainWindow *window);
+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 (EmpathyConf *conf,
+ const gchar *key,
+ EmpathyMainWindow *window);
+static void main_window_notify_compact_contact_list_cb (EmpathyConf *conf,
+ const gchar *key,
+ EmpathyMainWindow *window);
+static void main_window_notify_sort_criterium_cb (EmpathyConf *conf,
+ const gchar *key,
+ EmpathyMainWindow *window);
+
+GtkWidget *
+empathy_main_window_show (void)
+{
+ static EmpathyMainWindow *window = NULL;
+ EmpathyContactList *list_iface;
+ GladeXML *glade;
+ EmpathyConf *conf;
+ GtkWidget *sw;
+ GtkWidget *show_offline_widget;
+ GtkWidget *ebox;
+ GtkToolItem *item;
+ gboolean show_offline;
+ gboolean show_avatars;
+ gboolean compact_contact_list;
+ gint x, y, w, h;
+
+ if (window) {
+ empathy_window_present (GTK_WINDOW (window->window), TRUE);
+ return window->window;
+ }
+
+ window = g_new0 (EmpathyMainWindow, 1);
+
+ /* Set up interface */
+ glade = empathy_glade_get_file ("empathy-main-window.glade",
+ "main_window",
+ NULL,
+ "main_window", &window->window,
+ "main_vbox", &window->main_vbox,
+ "errors_vbox", &window->errors_vbox,
+ "chat_show_offline", &show_offline_widget,
+ "room", &window->room,
+ "room_sep", &window->room_sep,
+ "room_join_favorites", &window->room_join_favorites,
+ "edit_context", &window->edit_context,
+ "edit_context_separator", &window->edit_context_separator,
+ "presence_toolbar", &window->presence_toolbar,
+ "roster_scrolledwindow", &sw,
+ NULL);
+
+ empathy_glade_connect (glade,
+ window,
+ "main_window", "destroy", main_window_destroy_cb,
+ "main_window", "configure_event", main_window_configure_event_cb,
+ "chat_quit", "activate", main_window_chat_quit_cb,
+ "chat_new_message", "activate", main_window_chat_new_message_cb,
+ "chat_history", "activate", main_window_chat_history_cb,
+ "room_join_new", "activate", main_window_room_join_new_cb,
+ "room_join_favorites", "activate", main_window_room_join_favorites_cb,
+ "room_manage_favorites", "activate", main_window_room_manage_favorites_cb,
+ "chat_add_contact", "activate", main_window_chat_add_contact_cb,
+ "chat_show_offline", "toggled", main_window_chat_show_offline_cb,
+ "edit", "button-press-event", main_window_edit_button_press_event_cb,
+ "edit_accounts", "activate", main_window_edit_accounts_cb,
+ "edit_personal_information", "activate", main_window_edit_personal_information_cb,
+ "edit_preferences", "activate", main_window_edit_preferences_cb,
+ "help_about", "activate", main_window_help_about_cb,
+ "help_contents", "activate", main_window_help_contents_cb,
+ NULL);
+
+ /* Set up connection related widgets. */
+ main_window_connection_items_setup (window, glade);
+ g_object_unref (glade);
+
+ 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);
+
+ window->errors = g_hash_table_new_full (empathy_account_hash,
+ empathy_account_equal,
+ g_object_unref,
+ NULL);
+
+ /* Set up menu */
+ main_window_favorite_chatroom_menu_setup (window);
+
+ gtk_widget_hide (window->edit_context);
+ gtk_widget_hide (window->edit_context_separator);
+
+ /* Set up presence chooser */
+ window->presence_chooser = empathy_presence_chooser_new ();
+ gtk_widget_show (window->presence_chooser);
+ item = gtk_tool_item_new ();
+ gtk_widget_show (GTK_WIDGET (item));
+ gtk_container_add (GTK_CONTAINER (item), window->presence_chooser);
+ gtk_tool_item_set_is_important (item, TRUE);
+ gtk_tool_item_set_expand (item, TRUE);
+ gtk_toolbar_insert (GTK_TOOLBAR (window->presence_toolbar), item, -1);
+
+ /* Set up the throbber */
+ ebox = gtk_event_box_new ();
+ gtk_event_box_set_visible_window (GTK_EVENT_BOX (ebox), FALSE);
+ gtk_widget_set_tooltip_text (ebox, _("Show and edit accounts"));
+ g_signal_connect (ebox,
+ "button-press-event",
+ G_CALLBACK (main_window_throbber_button_press_event_cb),
+ window);
+ gtk_widget_show (ebox);
+
+ window->throbber = ephy_spinner_new ();
+ ephy_spinner_set_size (EPHY_SPINNER (window->throbber), GTK_ICON_SIZE_LARGE_TOOLBAR);
+ gtk_container_add (GTK_CONTAINER (ebox), window->throbber);
+ gtk_widget_show (window->throbber);
+
+ item = gtk_tool_item_new ();
+ gtk_container_add (GTK_CONTAINER (item), ebox);
+ gtk_toolbar_insert (GTK_TOOLBAR (window->presence_toolbar), item, -1);
+ gtk_widget_show (GTK_WIDGET (item));
+
+ /* Set up contact list. */
+ empathy_status_presets_get_all ();
+
+ list_iface = EMPATHY_CONTACT_LIST (empathy_contact_manager_new ());
+ window->list_store = empathy_contact_list_store_new (list_iface);
+ window->list_view = empathy_contact_list_view_new (window->list_store,
+ EMPATHY_CONTACT_LIST_FEATURE_ALL);
+ g_object_unref (list_iface);
+
+ gtk_widget_show (GTK_WIDGET (window->list_view));
+ gtk_container_add (GTK_CONTAINER (sw),
+ GTK_WIDGET (window->list_view));
+
+ /* Load user-defined accelerators. */
+ main_window_accels_load ();
+
+ /* Set window size. */
+ 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.
+ */
+ 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);
+ }
+
+ if (x >= 0 && y >= 0) {
+ /* Let the window manager position it if we
+ * don't have good x, y coordinates.
+ */
+ empathy_debug (DEBUG_DOMAIN, "Configuring window default position x:%d, y:%d", x, y);
+ gtk_window_move (GTK_WINDOW (window->window), x, y);
+ }
+
+ conf = empathy_conf_get ();
+
+ /* Show offline ? */
+ empathy_conf_get_bool (conf,
+ EMPATHY_PREFS_CONTACTS_SHOW_OFFLINE,
+ &show_offline);
+ empathy_conf_notify_add (conf,
+ EMPATHY_PREFS_CONTACTS_SHOW_OFFLINE,
+ main_window_notify_show_offline_cb,
+ show_offline_widget);
+
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (show_offline_widget),
+ show_offline);
+
+ /* Show avatars ? */
+ empathy_conf_get_bool (conf,
+ EMPATHY_PREFS_UI_SHOW_AVATARS,
+ &show_avatars);
+ empathy_conf_notify_add (conf,
+ EMPATHY_PREFS_UI_SHOW_AVATARS,
+ (EmpathyConfNotifyFunc) main_window_notify_show_avatars_cb,
+ window);
+ empathy_contact_list_store_set_show_avatars (window->list_store, show_avatars);
+
+ /* Is compact ? */
+ empathy_conf_get_bool (conf,
+ EMPATHY_PREFS_UI_COMPACT_CONTACT_LIST,
+ &compact_contact_list);
+ empathy_conf_notify_add (conf,
+ EMPATHY_PREFS_UI_COMPACT_CONTACT_LIST,
+ (EmpathyConfNotifyFunc) main_window_notify_compact_contact_list_cb,
+ window);
+ empathy_contact_list_store_set_is_compact (window->list_store, compact_contact_list);
+
+ /* Sort criterium */
+ 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,
+ EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM,
+ window);
+
+ main_window_update_status (window);
+
+ return window->window;
+}
+
+static void
+main_window_destroy_cb (GtkWidget *widget,
+ EmpathyMainWindow *window)
+{
+ /* Save user-defined accelerators. */
+ main_window_accels_save ();
+
+ dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (window->mc), "AccountStatusChanged",
+ G_CALLBACK (main_window_status_changed_cb),
+ window);
+
+ if (window->size_timeout_id) {
+ g_source_remove (window->size_timeout_id);
+ }
+
+ g_list_free (window->widgets_connected);
+ g_list_free (window->widgets_disconnected);
+
+ g_object_unref (window->mc);
+ g_object_unref (window->list_store);
+ g_hash_table_destroy (window->errors);
+
+ g_free (window);
+}
+
+static void
+main_window_favorite_chatroom_menu_setup (EmpathyMainWindow *window)
+{
+ GList *chatrooms, *l;
+
+ 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) {
+ main_window_favorite_chatroom_menu_add (window, l->data);
+ }
+
+ if (!chatrooms) {
+ gtk_widget_hide (window->room_sep);
+ }
+
+ gtk_widget_set_sensitive (window->room_join_favorites, chatrooms != NULL);
+
+ g_signal_connect (window->chatroom_manager, "chatroom-added",
+ G_CALLBACK (main_window_favorite_chatroom_menu_added_cb),
+ window);
+ g_signal_connect (window->chatroom_manager, "chatroom-removed",
+ G_CALLBACK (main_window_favorite_chatroom_menu_removed_cb),
+ window);
+
+ g_list_free (chatrooms);
+}
+
+static void
+main_window_favorite_chatroom_menu_added_cb (EmpathyChatroomManager *manager,
+ EmpathyChatroom *chatroom,
+ EmpathyMainWindow *window)
+{
+ main_window_favorite_chatroom_menu_add (window, chatroom);
+ gtk_widget_show (window->room_sep);
+ gtk_widget_set_sensitive (window->room_join_favorites, TRUE);
+}
+
+static void
+main_window_favorite_chatroom_menu_removed_cb (EmpathyChatroomManager *manager,
+ EmpathyChatroom *chatroom,
+ EmpathyMainWindow *window)
+{
+ GtkWidget *menu_item;
+
+ menu_item = g_object_get_data (G_OBJECT (chatroom), "menu_item");
+
+ g_object_set_data (G_OBJECT (chatroom), "menu_item", NULL);
+ gtk_widget_destroy (menu_item);
+
+ main_window_favorite_chatroom_menu_update (window);
+}
+
+static void
+main_window_favorite_chatroom_menu_activate_cb (GtkMenuItem *menu_item,
+ EmpathyChatroom *chatroom)
+{
+ main_window_favorite_chatroom_join (chatroom);
+}
+
+static void
+main_window_favorite_chatroom_menu_update (EmpathyMainWindow *window)
+{
+ GList *chatrooms;
+
+ chatrooms = empathy_chatroom_manager_get_chatrooms (window->chatroom_manager, NULL);
+
+ if (chatrooms) {
+ gtk_widget_show (window->room_sep);
+ } else {
+ gtk_widget_hide (window->room_sep);
+ }
+
+ gtk_widget_set_sensitive (window->room_join_favorites, chatrooms != NULL);
+ g_list_free (chatrooms);
+}
+
+static void
+main_window_favorite_chatroom_menu_add (EmpathyMainWindow *window,
+ EmpathyChatroom *chatroom)
+{
+ GtkWidget *menu_item;
+ const gchar *name;
+
+ if (g_object_get_data (G_OBJECT (chatroom), "menu_item")) {
+ return;
+ }
+
+ 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);
+ g_signal_connect (menu_item, "activate",
+ G_CALLBACK (main_window_favorite_chatroom_menu_activate_cb),
+ chatroom);
+
+ gtk_menu_shell_insert (GTK_MENU_SHELL (window->room_menu),
+ menu_item, 3);
+
+ gtk_widget_show (menu_item);
+}
+
+static void
+main_window_favorite_chatroom_join (EmpathyChatroom *chatroom)
+{
+ MissionControl *mc;
+ McAccount *account;
+ const gchar *room;
+
+ mc = empathy_mission_control_new ();
+ account = empathy_chatroom_get_account (chatroom);
+ room = empathy_chatroom_get_room (chatroom);
+
+ empathy_debug (DEBUG_DOMAIN, "Requesting channel for '%s'", room);
+
+ mission_control_request_channel_with_string_handle (mc,
+ account,
+ TP_IFACE_CHANNEL_TYPE_TEXT,
+ room,
+ TP_HANDLE_TYPE_ROOM,
+ NULL, NULL);
+ g_object_unref (mc);
+}
+
+static void
+main_window_chat_quit_cb (GtkWidget *widget,
+ EmpathyMainWindow *window)
+{
+ gtk_main_quit ();
+}
+
+static void
+main_window_chat_new_message_cb (GtkWidget *widget,
+ EmpathyMainWindow *window)
+{
+ empathy_new_message_dialog_show (GTK_WINDOW (window->window));
+}
+
+static void
+main_window_chat_history_cb (GtkWidget *widget,
+ EmpathyMainWindow *window)
+{
+ empathy_log_window_show (NULL, NULL, FALSE, GTK_WINDOW (window->window));
+}
+
+static void
+main_window_room_join_new_cb (GtkWidget *widget,
+ EmpathyMainWindow *window)
+{
+ empathy_new_chatroom_dialog_show (GTK_WINDOW (window->window));
+}
+
+static void
+main_window_room_join_favorites_cb (GtkWidget *widget,
+ EmpathyMainWindow *window)
+{
+ GList *chatrooms, *l;
+
+ chatrooms = empathy_chatroom_manager_get_chatrooms (window->chatroom_manager, NULL);
+ for (l = chatrooms; l; l = l->next) {
+ main_window_favorite_chatroom_join (l->data);
+ }
+ g_list_free (chatrooms);
+}
+
+static void
+main_window_room_manage_favorites_cb (GtkWidget *widget,
+ EmpathyMainWindow *window)
+{
+ empathy_chatrooms_window_show (GTK_WINDOW (window->window));
+}
+
+static void
+main_window_chat_add_contact_cb (GtkWidget *widget,
+ EmpathyMainWindow *window)
+{
+ empathy_new_contact_dialog_show (GTK_WINDOW (window->window));
+}
+
+static void
+main_window_chat_show_offline_cb (GtkCheckMenuItem *item,
+ EmpathyMainWindow *window)
+{
+ gboolean current;
+
+ current = gtk_check_menu_item_get_active (item);
+
+ empathy_conf_set_bool (empathy_conf_get (),
+ EMPATHY_PREFS_CONTACTS_SHOW_OFFLINE,
+ current);
+
+ /* Turn off sound just while we alter the contact list. */
+ // FIXME: empathy_sound_set_enabled (FALSE);
+ empathy_contact_list_store_set_show_offline (window->list_store, current);
+ //empathy_sound_set_enabled (TRUE);
+}
+
+static gboolean
+main_window_edit_button_press_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ EmpathyMainWindow *window)
+{
+ EmpathyContact *contact;
+ gchar *group;
+
+ if (!event->button == 1) {
+ return FALSE;
+ }
+
+ group = empathy_contact_list_view_get_selected_group (window->list_view);
+ if (group) {
+ GtkMenuItem *item;
+ GtkWidget *label;
+ GtkWidget *submenu;
+
+ item = GTK_MENU_ITEM (window->edit_context);
+ label = gtk_bin_get_child (GTK_BIN (item));
+ gtk_label_set_text (GTK_LABEL (label), _("Group"));
+
+ gtk_widget_show (window->edit_context);
+ gtk_widget_show (window->edit_context_separator);
+
+ submenu = empathy_contact_list_view_get_group_menu (window->list_view);
+ gtk_menu_item_set_submenu (item, submenu);
+
+ g_free (group);
+
+ return FALSE;
+ }
+
+ contact = empathy_contact_list_view_get_selected (window->list_view);
+ if (contact) {
+ GtkMenuItem *item;
+ GtkWidget *label;
+ GtkWidget *submenu;
+
+ item = GTK_MENU_ITEM (window->edit_context);
+ label = gtk_bin_get_child (GTK_BIN (item));
+ gtk_label_set_text (GTK_LABEL (label), _("Contact"));
+
+ gtk_widget_show (window->edit_context);
+ gtk_widget_show (window->edit_context_separator);
+
+ submenu = empathy_contact_list_view_get_contact_menu (window->list_view,
+ contact);
+ gtk_menu_item_set_submenu (item, submenu);
+
+ g_object_unref (contact);
+
+ return FALSE;
+ }
+
+ gtk_widget_hide (window->edit_context);
+ gtk_widget_hide (window->edit_context_separator);
+
+ return FALSE;
+}
+
+static void
+main_window_edit_accounts_cb (GtkWidget *widget,
+ EmpathyMainWindow *window)
+{
+ empathy_accounts_dialog_show (GTK_WINDOW (window->window));
+}
+
+static void
+main_window_edit_personal_information_cb (GtkWidget *widget,
+ EmpathyMainWindow *window)
+{
+ GSList *accounts;
+
+ accounts = mission_control_get_online_connections (window->mc, NULL);
+ if (accounts) {
+ EmpathyContactFactory *factory;
+ EmpathyContact *contact;
+ McAccount *account;
+
+ account = accounts->data;
+ factory = empathy_contact_factory_new ();
+ contact = empathy_contact_factory_get_user (factory, account);
+ empathy_contact_information_dialog_show (contact,
+ GTK_WINDOW (window->window),
+ TRUE, TRUE);
+ g_slist_foreach (accounts, (GFunc) g_object_unref, NULL);
+ g_slist_free (accounts);
+ g_object_unref (factory);
+ g_object_unref (contact);
+ }
+}
+
+static void
+main_window_edit_preferences_cb (GtkWidget *widget,
+ EmpathyMainWindow *window)
+{
+ empathy_preferences_show (GTK_WINDOW (window->window));
+}
+
+static void
+main_window_help_about_cb (GtkWidget *widget,
+ EmpathyMainWindow *window)
+{
+ empathy_about_dialog_new (GTK_WINDOW (window->window));
+}
+
+static void
+main_window_help_contents_cb (GtkWidget *widget,
+ EmpathyMainWindow *window)
+{
+ //empathy_help_show ();
+}
+
+static gboolean
+main_window_throbber_button_press_event_cb (GtkWidget *throbber_ebox,
+ GdkEventButton *event,
+ EmpathyMainWindow *window)
+{
+ if (event->type != GDK_BUTTON_PRESS ||
+ event->button != 1) {
+ return FALSE;
+ }
+
+ empathy_accounts_dialog_show (GTK_WINDOW (window->window));
+
+ return FALSE;
+}
+
+static void
+main_window_error_edit_clicked_cb (GtkButton *button,
+ EmpathyMainWindow *window)
+{
+ McAccount *account;
+ GtkWidget *error_widget;
+
+ empathy_accounts_dialog_show (GTK_WINDOW (window->window));
+
+ account = g_object_get_data (G_OBJECT (button), "account");
+ error_widget = g_hash_table_lookup (window->errors, account);
+ gtk_widget_destroy (error_widget);
+ g_hash_table_remove (window->errors, account);
+}
+
+static void
+main_window_error_clear_clicked_cb (GtkButton *button,
+ EmpathyMainWindow *window)
+{
+ McAccount *account;
+ GtkWidget *error_widget;
+
+ account = g_object_get_data (G_OBJECT (button), "account");
+ error_widget = g_hash_table_lookup (window->errors, account);
+ gtk_widget_destroy (error_widget);
+ g_hash_table_remove (window->errors, account);
+}
+
+static void
+main_window_error_display (EmpathyMainWindow *window,
+ McAccount *account,
+ const gchar *message)
+{
+ GtkWidget *child;
+ GtkWidget *table;
+ GtkWidget *image;
+ GtkWidget *button_edit;
+ GtkWidget *alignment;
+ GtkWidget *hbox;
+ GtkWidget *label;
+ GtkWidget *fixed;
+ GtkWidget *vbox;
+ GtkWidget *button_close;
+ gchar *str;
+
+ child = g_hash_table_lookup (window->errors, account);
+ if (child) {
+ label = g_object_get_data (G_OBJECT (child), "label");
+
+ /* Just set the latest error and return */
+ str = g_markup_printf_escaped ("<b>%s</b>\n%s",
+ mc_account_get_display_name (account),
+ message);
+ gtk_label_set_markup (GTK_LABEL (label), str);
+ g_free (str);
+
+ return;
+ }
+
+ child = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (window->errors_vbox), child, FALSE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (child), 6);
+ gtk_widget_show (child);
+
+ table = gtk_table_new (2, 4, FALSE);
+ gtk_widget_show (table);
+ gtk_box_pack_start (GTK_BOX (child), table, TRUE, TRUE, 0);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 12);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+
+ image = gtk_image_new_from_stock (GTK_STOCK_DISCONNECT, GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image);
+ gtk_table_attach (GTK_TABLE (table), image, 0, 1, 0, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (GTK_FILL), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0);
+
+ button_edit = gtk_button_new ();
+ gtk_widget_show (button_edit);
+ gtk_table_attach (GTK_TABLE (table), button_edit, 1, 2, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
+ gtk_widget_show (alignment);
+ gtk_container_add (GTK_CONTAINER (button_edit), alignment);
+
+ hbox = gtk_hbox_new (FALSE, 2);
+ gtk_widget_show (hbox);
+ gtk_container_add (GTK_CONTAINER (alignment), hbox);
+
+ image = gtk_image_new_from_stock (GTK_STOCK_EDIT, GTK_ICON_SIZE_BUTTON);
+ gtk_widget_show (image);
+ gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+
+ label = gtk_label_new_with_mnemonic (_("_Edit account"));
+ gtk_widget_show (label);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ fixed = gtk_fixed_new ();
+ gtk_widget_show (fixed);
+ gtk_table_attach (GTK_TABLE (table), fixed, 2, 3, 1, 2,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (GTK_FILL), 0, 0);
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_widget_show (vbox);
+ gtk_table_attach (GTK_TABLE (table), vbox, 3, 4, 0, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (GTK_FILL), 0, 0);
+
+ button_close = gtk_button_new ();
+ gtk_widget_show (button_close);
+ gtk_box_pack_start (GTK_BOX (vbox), button_close, FALSE, FALSE, 0);
+ gtk_button_set_relief (GTK_BUTTON (button_close), GTK_RELIEF_NONE);
+
+
+ image = gtk_image_new_from_stock ("gtk-close", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image);
+ gtk_container_add (GTK_CONTAINER (button_close), image);
+
+ label = gtk_label_new ("");
+ gtk_widget_show (label);
+ gtk_table_attach (GTK_TABLE (table), label, 1, 3, 0, 1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK | GTK_FILL),
+ (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK | GTK_FILL), 0, 0);
+ gtk_widget_set_size_request (label, 175, -1);
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
+
+ str = g_markup_printf_escaped ("<b>%s</b>\n%s",
+ mc_account_get_display_name (account),
+ message);
+ gtk_label_set_markup (GTK_LABEL (label), str);
+ g_free (str);
+
+ g_object_set_data (G_OBJECT (child), "label", label);
+ g_object_set_data_full (G_OBJECT (button_edit),
+ "account", g_object_ref (account),
+ g_object_unref);
+ g_object_set_data_full (G_OBJECT (button_close),
+ "account", g_object_ref (account),
+ g_object_unref);
+
+ g_signal_connect (button_edit, "clicked",
+ G_CALLBACK (main_window_error_edit_clicked_cb),
+ window);
+
+ g_signal_connect (button_close, "clicked",
+ G_CALLBACK (main_window_error_clear_clicked_cb),
+ window);
+
+ gtk_widget_show (window->errors_vbox);
+
+ g_hash_table_insert (window->errors, g_object_ref (account), child);
+}
+
+static void
+main_window_status_changed_cb (MissionControl *mc,
+ TpConnectionStatus status,
+ McPresence presence,
+ TpConnectionStatusReason reason,
+ const gchar *unique_name,
+ EmpathyMainWindow *window)
+{
+ McAccount *account;
+
+ main_window_update_status (window);
+
+ account = mc_account_lookup (unique_name);
+
+ if (status == TP_CONNECTION_STATUS_DISCONNECTED &&
+ reason > TP_CONNECTION_STATUS_REASON_REQUESTED) {
+ const gchar *message;
+
+ switch (reason) {
+ case TP_CONNECTION_STATUS_REASON_NETWORK_ERROR:
+ message = _("Network error");
+ break;
+ case TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED:
+ message = _("Authentication failed");
+ break;
+ case TP_CONNECTION_STATUS_REASON_ENCRYPTION_ERROR:
+ message = _("Encryption error");
+ break;
+ case TP_CONNECTION_STATUS_REASON_NAME_IN_USE:
+ message = _("Name in use");
+ break;
+ case TP_CONNECTION_STATUS_REASON_CERT_NOT_PROVIDED:
+ message = _("Certificate not provided");
+ break;
+ case TP_CONNECTION_STATUS_REASON_CERT_UNTRUSTED:
+ message = _("Certificate untrusted");
+ break;
+ case TP_CONNECTION_STATUS_REASON_CERT_EXPIRED:
+ message = _("Certificate expired");
+ break;
+ case TP_CONNECTION_STATUS_REASON_CERT_NOT_ACTIVATED:
+ message = _("Certificate not activated");
+ break;
+ case TP_CONNECTION_STATUS_REASON_CERT_HOSTNAME_MISMATCH:
+ message = _("Certificate hostname mismatch");
+ break;
+ case TP_CONNECTION_STATUS_REASON_CERT_FINGERPRINT_MISMATCH:
+ message = _("Certificate fingerprint mismatch");
+ break;
+ case TP_CONNECTION_STATUS_REASON_CERT_SELF_SIGNED:
+ message = _("Certificate self signed");
+ break;
+ case TP_CONNECTION_STATUS_REASON_CERT_OTHER_ERROR:
+ message = _("Certificate error");
+ break;
+ default:
+ message = _("Unknown error");
+ break;
+ }
+
+ main_window_error_display (window, account, message);
+ }
+
+ if (status == TP_CONNECTION_STATUS_CONNECTED) {
+ GtkWidget *error_widget;
+
+ /* Account connected without error, remove error message if any */
+ error_widget = g_hash_table_lookup (window->errors, account);
+ if (error_widget) {
+ gtk_widget_destroy (error_widget);
+ g_hash_table_remove (window->errors, account);
+ }
+ }
+
+ g_object_unref (account);
+}
+
+static void
+main_window_update_status (EmpathyMainWindow *window)
+{
+ GList *accounts, *l;
+ guint connected = 0;
+ guint connecting = 0;
+ guint disconnected = 0;
+
+ /* Count number of connected/connecting/disconnected accounts */
+ accounts = mc_accounts_list ();
+ for (l = accounts; l; l = l->next) {
+ McAccount *account;
+ guint status;
+
+ account = l->data;
+
+ status = mission_control_get_connection_status (window->mc,
+ account,
+ NULL);
+
+ if (status == 0) {
+ connected++;
+ } else if (status == 1) {
+ connecting++;
+ } else if (status == 2) {
+ disconnected++;
+ }
+
+ g_object_unref (account);
+ }
+ g_list_free (accounts);
+
+ /* Update the spinner state */
+ if (connecting > 0) {
+ ephy_spinner_start (EPHY_SPINNER (window->throbber));
+ } else {
+ ephy_spinner_stop (EPHY_SPINNER (window->throbber));
+ }
+
+ /* Update widgets sensibility */
+ for (l = window->widgets_connected; l; l = l->next) {
+ gtk_widget_set_sensitive (l->data, (connected > 0));
+ }
+
+ for (l = window->widgets_disconnected; l; l = l->next) {
+ gtk_widget_set_sensitive (l->data, (disconnected > 0));
+ }
+}
+
+/*
+ * Accels
+ */
+static void
+main_window_accels_load (void)
+{
+ gchar *filename;
+
+ filename = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, ACCELS_FILENAME, NULL);
+ if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
+ empathy_debug (DEBUG_DOMAIN, "Loading from:'%s'", filename);
+ gtk_accel_map_load (filename);
+ }
+
+ g_free (filename);
+}
+
+static void
+main_window_accels_save (void)
+{
+ gchar *dir;
+ gchar *file_with_path;
+
+ 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, ACCELS_FILENAME, NULL);
+ g_free (dir);
+
+ empathy_debug (DEBUG_DOMAIN, "Saving to:'%s'", file_with_path);
+ gtk_accel_map_save (file_with_path);
+
+ g_free (file_with_path);
+}
+
+static void
+main_window_connection_items_setup (EmpathyMainWindow *window,
+ GladeXML *glade)
+{
+ GList *list;
+ GtkWidget *w;
+ gint i;
+ const gchar *widgets_connected[] = {
+ "room",
+ "chat_new_message",
+ "chat_add_contact",
+ "edit_personal_information"
+ };
+ const gchar *widgets_disconnected[] = {
+ };
+
+ for (i = 0, list = NULL; i < G_N_ELEMENTS (widgets_connected); i++) {
+ w = glade_xml_get_widget (glade, widgets_connected[i]);
+ list = g_list_prepend (list, w);
+ }
+
+ window->widgets_connected = list;
+
+ for (i = 0, list = NULL; i < G_N_ELEMENTS (widgets_disconnected); i++) {
+ w = glade_xml_get_widget (glade, widgets_disconnected[i]);
+ list = g_list_prepend (list, w);
+ }
+
+ window->widgets_disconnected = list;
+}
+
+static gboolean
+main_window_configure_event_timeout_cb (EmpathyMainWindow *window)
+{
+ gint x, y, w, h;
+
+ gtk_window_get_size (GTK_WINDOW (window->window), &w, &h);
+ gtk_window_get_position (GTK_WINDOW (window->window), &x, &y);
+
+ empathy_geometry_save (GEOMETRY_NAME, x, y, w, h);
+
+ window->size_timeout_id = 0;
+
+ return FALSE;
+}
+
+static gboolean
+main_window_configure_event_cb (GtkWidget *widget,
+ GdkEventConfigure *event,
+ EmpathyMainWindow *window)
+{
+ if (window->size_timeout_id) {
+ g_source_remove (window->size_timeout_id);
+ }
+
+ window->size_timeout_id = g_timeout_add_seconds (1,
+ (GSourceFunc) main_window_configure_event_timeout_cb,
+ window);
+
+ return FALSE;
+}
+
+static void
+main_window_notify_show_offline_cb (EmpathyConf *conf,
+ const gchar *key,
+ gpointer check_menu_item)
+{
+ gboolean 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 (EmpathyConf *conf,
+ const gchar *key,
+ EmpathyMainWindow *window)
+{
+ gboolean show_avatars;
+
+ 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 (EmpathyConf *conf,
+ const gchar *key,
+ EmpathyMainWindow *window)
+{
+ gboolean compact_contact_list;
+
+ 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 (EmpathyConf *conf,
+ const gchar *key,
+ EmpathyMainWindow *window)
+{
+ gchar *str = NULL;
+
+ if (empathy_conf_get_string (conf, key, &str) && str) {
+ GType type;
+ GEnumClass *enum_class;
+ GEnumValue *enum_value;
+
+ 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) {
+ empathy_contact_list_store_set_sort_criterium (window->list_store,
+ enum_value->value);
+ }
+ }
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-main-window.glade b/gnome-2-22/libempathy-gtk/empathy-main-window.glade
new file mode 100644
index 000000000..02f69a38d
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-main-window.glade
@@ -0,0 +1,310 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+ <widget class="GtkWindow" id="main_window">
+ <property name="title" translatable="yes">Contact List</property>
+ <property name="default_width">225</property>
+ <property name="default_height">325</property>
+ <child>
+ <widget class="GtkVBox" id="main_vbox">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkMenuBar" id="menubar2">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkMenuItem" id="chat">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Chat</property>
+ <property name="use_underline">True</property>
+ <child>
+ <widget class="GtkMenu" id="chat_menu">
+ <child>
+ <widget class="GtkImageMenuItem" id="chat_new_message">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_New Conversation...</property>
+ <property name="use_underline">True</property>
+ <accelerator key="N" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+ <child internal-child="image">
+ <widget class="GtkImage" id="image885">
+ <property name="visible">True</property>
+ <property name="icon_size">1</property>
+ <property name="icon_name">im-message-new</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkImageMenuItem" id="chat_history">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_View Previous Conversations</property>
+ <property name="use_underline">True</property>
+ <accelerator key="F3" modifiers="" signal="activate"/>
+ <child internal-child="image">
+ <widget class="GtkImage" id="image886">
+ <property name="visible">True</property>
+ <property name="icon_size">1</property>
+ <property name="icon_name">document-open-recent</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator5">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkImageMenuItem" id="chat_add_contact">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Add Contact...</property>
+ <property name="use_underline">True</property>
+ <child internal-child="image">
+ <widget class="GtkImage" id="image887">
+ <property name="visible">True</property>
+ <property name="stock">gtk-add</property>
+ <property name="icon_size">1</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator3">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkCheckMenuItem" id="chat_show_offline">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Show _Offline Contacts</property>
+ <property name="use_underline">True</property>
+ <accelerator key="H" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator6">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkImageMenuItem" id="chat_quit">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Quit</property>
+ <property name="use_underline">True</property>
+ <accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+ <child internal-child="image">
+ <widget class="GtkImage" id="image888">
+ <property name="visible">True</property>
+ <property name="stock">gtk-quit</property>
+ <property name="icon_size">1</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="edit">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Edit</property>
+ <property name="use_underline">True</property>
+ <child>
+ <widget class="GtkMenu" id="edit_menu">
+ <child>
+ <widget class="GtkMenuItem" id="edit_context">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Context</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="edit_context_separator">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="edit_accounts">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Accounts</property>
+ <property name="use_underline">True</property>
+ <accelerator key="F4" modifiers="" signal="activate"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkImageMenuItem" id="edit_personal_information">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Personal Information</property>
+ <property name="use_underline">True</property>
+ <child internal-child="image">
+ <widget class="GtkImage" id="image894">
+ <property name="visible">True</property>
+ <property name="icon_size">1</property>
+ <property name="icon_name">user-info</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator2">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkImageMenuItem" id="edit_preferences">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Preferences</property>
+ <property name="use_underline">True</property>
+ <child internal-child="image">
+ <widget class="GtkImage" id="image891">
+ <property name="visible">True</property>
+ <property name="stock">gtk-preferences</property>
+ <property name="icon_size">1</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="room">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Room</property>
+ <property name="use_underline">True</property>
+ <child>
+ <widget class="GtkMenu" id="room_menu">
+ <child>
+ <widget class="GtkMenuItem" id="room_join_new">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Join _New...</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="room_join_favorites">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Join _Favorites</property>
+ <property name="use_underline">True</property>
+ <accelerator key="F5" modifiers="" signal="activate"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="room_sep">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="room_sep2">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkImageMenuItem" id="room_manage_favorites">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Manage Favorites</property>
+ <property name="use_underline">True</property>
+ <child internal-child="image">
+ <widget class="GtkImage" id="image890">
+ <property name="visible">True</property>
+ <property name="icon_size">1</property>
+ <property name="icon_name">system-users</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="help">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Help</property>
+ <property name="use_underline">True</property>
+ <child>
+ <widget class="GtkMenu" id="help_menu">
+ <child>
+ <widget class="GtkImageMenuItem" id="help_contents">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Contents</property>
+ <property name="use_underline">True</property>
+ <accelerator key="F1" modifiers="" signal="activate"/>
+ <child internal-child="image">
+ <widget class="GtkImage" id="image892">
+ <property name="visible">True</property>
+ <property name="stock">gtk-help</property>
+ <property name="icon_size">1</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkImageMenuItem" id="help_about">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_About</property>
+ <property name="use_underline">True</property>
+ <child internal-child="image">
+ <widget class="GtkImage" id="image893">
+ <property name="visible">True</property>
+ <property name="stock">gtk-about</property>
+ <property name="icon_size">1</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolbar" id="presence_toolbar">
+ <property name="visible">True</property>
+ <property name="toolbar_style">GTK_TOOLBAR_BOTH</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="errors_vbox">
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="roster_scrolledwindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-main-window.h b/gnome-2-22/libempathy-gtk/empathy-main-window.h
new file mode 100644
index 000000000..669a97872
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-main-window.h
@@ -0,0 +1,35 @@
+/* -*- 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: Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_MAIN_WINDOW_H__
+#define __EMPATHY_MAIN_WINDOW_H__
+
+#include <gtk/gtkwidget.h>
+
+G_BEGIN_DECLS
+
+GtkWidget *empathy_main_window_show (void);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_MAIN_WINDOW_H__ */
diff --git a/gnome-2-22/libempathy-gtk/empathy-new-chatroom-dialog.c b/gnome-2-22/libempathy-gtk/empathy-new-chatroom-dialog.c
new file mode 100644
index 000000000..b33439407
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-new-chatroom-dialog.c
@@ -0,0 +1,566 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006-2007 Imendio AB
+ * Copyright (C) 2007-2008 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 <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <libmissioncontrol/mission-control.h>
+#include <libmissioncontrol/mc-account.h>
+#include <libmissioncontrol/mc-profile.h>
+
+#include <libempathy/empathy-tp-roomlist.h>
+#include <libempathy/empathy-chatroom.h>
+#include <libempathy/empathy-utils.h>
+#include <libempathy/empathy-debug.h>
+
+#include "empathy-new-chatroom-dialog.h"
+#include "empathy-account-chooser.h"
+#include "empathy-ui-utils.h"
+#include "ephy-spinner.h"
+
+#define DEBUG_DOMAIN "NewChatroomDialog"
+
+typedef struct {
+ EmpathyTpRoomlist *room_list;
+
+ GtkWidget *window;
+ GtkWidget *vbox_widgets;
+ GtkWidget *table_info;
+ GtkWidget *label_account;
+ GtkWidget *account_chooser;
+ GtkWidget *label_server;
+ GtkWidget *entry_server;
+ GtkWidget *togglebutton_refresh;
+ GtkWidget *label_room;
+ GtkWidget *entry_room;
+ GtkWidget *vbox_browse;
+ GtkWidget *image_status;
+ GtkWidget *label_status;
+ GtkWidget *hbox_status;
+ GtkWidget *throbber;
+ GtkWidget *treeview;
+ GtkTreeModel *model;
+ GtkWidget *button_join;
+ GtkWidget *button_close;
+} EmpathyNewChatroomDialog;
+
+enum {
+ COL_NAME,
+ COL_ROOM,
+ 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_widgets (EmpathyNewChatroomDialog *dialog);
+static void new_chatroom_dialog_account_changed_cb (GtkComboBox *combobox,
+ EmpathyNewChatroomDialog *dialog);
+static void new_chatroom_dialog_roomlist_destroy_cb (EmpathyTpRoomlist *room_list,
+ EmpathyNewChatroomDialog *dialog);
+static void new_chatroom_dialog_new_room_cb (EmpathyTpRoomlist *room_list,
+ EmpathyChatroom *chatroom,
+ EmpathyNewChatroomDialog *dialog);
+static void new_chatroom_dialog_listing_cb (EmpathyTpRoomlist *room_list,
+ gboolean listing,
+ EmpathyNewChatroomDialog *dialog);
+static void new_chatroom_dialog_model_clear (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_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;
+ 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,
+ "table_info", &dialog->table_info,
+ "label_account", &dialog->label_account,
+ "label_server", &dialog->label_server,
+ "label_room", &dialog->label_room,
+ "entry_server", &dialog->entry_server,
+ "entry_room", &dialog->entry_room,
+ "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_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);
+
+ g_object_unref (size_group);
+
+ /* Set up chatrooms treeview */
+ new_chatroom_dialog_model_setup (dialog);
+
+ /* 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);
+
+ /* Account chooser for custom */
+ dialog->account_chooser = empathy_account_chooser_new ();
+ empathy_account_chooser_set_filter (EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser),
+ empathy_account_chooser_filter_is_connected,
+ NULL);
+ gtk_table_attach_defaults (GTK_TABLE (dialog->table_info),
+ dialog->account_chooser,
+ 1, 3, 0, 1);
+ 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);
+ new_chatroom_dialog_account_changed_cb (GTK_COMBO_BOX (dialog->account_chooser),
+ 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)
+{
+ if (dialog->room_list) {
+ g_object_unref (dialog->room_list);
+ }
+ g_object_unref (dialog->model);
+
+ 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_STRING); /* Room */
+
+ dialog->model = GTK_TREE_MODEL (store);
+ gtk_tree_view_set_model (view, dialog->model);
+
+ /* Selection */
+ selection = gtk_tree_view_get_selection (view);
+ 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);
+
+ cell = gtk_cell_renderer_text_new ();
+ g_object_set (cell,
+ "xpad", (guint) 4,
+ "ypad", (guint) 1,
+ "ellipsize", PANGO_ELLIPSIZE_END,
+ NULL);
+
+ column = gtk_tree_view_column_new_with_attributes (_("Chat Rooms"),
+ cell,
+ "text", COL_NAME,
+ NULL);
+
+ gtk_tree_view_column_set_expand (column, TRUE);
+ gtk_tree_view_append_column (view, column);
+}
+
+static void
+new_chatroom_dialog_update_widgets (EmpathyNewChatroomDialog *dialog)
+{
+ EmpathyAccountChooser *account_chooser;
+ McAccount *account;
+ McProfile *profile;
+ const gchar *protocol;
+ const gchar *room;
+
+ 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);
+
+ gtk_entry_set_text (GTK_ENTRY (dialog->entry_server), "");
+
+ /* hardcode here known protocols */
+ if (strcmp (protocol, "jabber") == 0) {
+ gtk_widget_set_sensitive (dialog->entry_server, TRUE);
+ gtk_widget_show (dialog->vbox_browse);
+
+ }
+ else if (strcmp (protocol, "local-xmpp") == 0) {
+ gtk_widget_set_sensitive (dialog->entry_server, FALSE);
+ gtk_widget_show (dialog->vbox_browse);
+ }
+ else if (strcmp (protocol, "irc") == 0) {
+ gtk_widget_set_sensitive (dialog->entry_server, FALSE);
+ gtk_widget_show (dialog->vbox_browse);
+ } else {
+ gtk_widget_set_sensitive (dialog->entry_server, TRUE);
+ gtk_widget_show (dialog->vbox_browse);
+ }
+
+ room = gtk_entry_get_text (GTK_ENTRY (dialog->entry_room));
+ gtk_widget_set_sensitive (dialog->button_join, !G_STR_EMPTY (room));
+
+ /* 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)
+{
+ EmpathyAccountChooser *account_chooser;
+ McAccount *account;
+ gboolean listing = FALSE;
+
+ if (dialog->room_list) {
+ g_object_unref (dialog->room_list);
+ }
+
+ ephy_spinner_stop (EPHY_SPINNER (dialog->throbber));
+ new_chatroom_dialog_model_clear (dialog);
+
+ account_chooser = EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser);
+ account = empathy_account_chooser_get_account (account_chooser);
+ dialog->room_list = empathy_tp_roomlist_new (account);
+
+ if (dialog->room_list) {
+ g_signal_connect (dialog->room_list, "destroy",
+ G_CALLBACK (new_chatroom_dialog_roomlist_destroy_cb),
+ dialog);
+ g_signal_connect (dialog->room_list, "new-room",
+ G_CALLBACK (new_chatroom_dialog_new_room_cb),
+ dialog);
+ g_signal_connect (dialog->room_list, "listing",
+ G_CALLBACK (new_chatroom_dialog_listing_cb),
+ dialog);
+
+ listing = empathy_tp_roomlist_is_listing (dialog->room_list);
+ if (listing) {
+ ephy_spinner_start (EPHY_SPINNER (dialog->throbber));
+ }
+ }
+
+ new_chatroom_dialog_update_widgets (dialog);
+}
+
+static void
+new_chatroom_dialog_roomlist_destroy_cb (EmpathyTpRoomlist *room_list,
+ EmpathyNewChatroomDialog *dialog)
+{
+ g_object_unref (dialog->room_list);
+ dialog->room_list = NULL;
+}
+
+static void
+new_chatroom_dialog_new_room_cb (EmpathyTpRoomlist *room_list,
+ EmpathyChatroom *chatroom,
+ EmpathyNewChatroomDialog *dialog)
+{
+ GtkTreeView *view;
+ GtkTreeSelection *selection;
+ GtkListStore *store;
+ GtkTreeIter iter;
+
+ empathy_debug (DEBUG_DOMAIN, "New chatroom listed: %s (%s)",
+ empathy_chatroom_get_name (chatroom),
+ empathy_chatroom_get_room (chatroom));
+
+ /* 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, empathy_chatroom_get_name (chatroom),
+ COL_ROOM, empathy_chatroom_get_room (chatroom),
+ -1);
+}
+
+static void
+new_chatroom_dialog_listing_cb (EmpathyTpRoomlist *room_list,
+ gboolean listing,
+ EmpathyNewChatroomDialog *dialog)
+{
+ /* Update the throbber */
+ if (listing) {
+ ephy_spinner_start (EPHY_SPINNER (dialog->throbber));
+ } else {
+ ephy_spinner_stop (EPHY_SPINNER (dialog->throbber));
+ }
+
+ /* Update the refresh toggle button */
+ g_signal_handlers_block_by_func (dialog->togglebutton_refresh,
+ new_chatroom_dialog_togglebutton_refresh_toggled_cb,
+ dialog);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->togglebutton_refresh),
+ listing);
+ g_signal_handlers_unblock_by_func (dialog->togglebutton_refresh,
+ new_chatroom_dialog_togglebutton_refresh_toggled_cb,
+ dialog);
+}
+
+static void
+new_chatroom_dialog_model_clear (EmpathyNewChatroomDialog *dialog)
+{
+ GtkListStore *store;
+
+ store = GTK_LIST_STORE (dialog->model);
+ gtk_list_store_clear (store);
+}
+
+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_selection_changed (GtkTreeSelection *selection,
+ EmpathyNewChatroomDialog *dialog)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gchar *room = NULL;
+ gchar *server = NULL;
+
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
+ return;
+ }
+
+ gtk_tree_model_get (model, &iter, COL_ROOM, &room, -1);
+ server = strstr (room, "@");
+ if (server) {
+ *server = '\0';
+ server++;
+ }
+
+ gtk_entry_set_text (GTK_ENTRY (dialog->entry_server), server ? server : "");
+ gtk_entry_set_text (GTK_ENTRY (dialog->entry_room), room ? room : "");
+
+ g_free (room);
+}
+
+static void
+new_chatroom_dialog_join (EmpathyNewChatroomDialog *dialog)
+{
+ McAccount *account;
+ EmpathyAccountChooser *account_chooser;
+ MissionControl *mc;
+ const gchar *room;
+ const gchar *server = NULL;
+ gchar *room_name = NULL;
+
+ room = gtk_entry_get_text (GTK_ENTRY (dialog->entry_room));
+ 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) {
+ const gchar *room;
+
+ room = gtk_entry_get_text (GTK_ENTRY (dialog->entry_room));
+ gtk_widget_set_sensitive (dialog->button_join, !G_STR_EMPTY (room));
+ /* FIXME: Select the room in the list */
+ }
+}
+
+static void
+new_chatroom_dialog_browse_start (EmpathyNewChatroomDialog *dialog)
+{
+ new_chatroom_dialog_model_clear (dialog);
+ if (dialog->room_list) {
+ empathy_tp_roomlist_start (dialog->room_list);
+ }
+}
+
+static void
+new_chatroom_dialog_browse_stop (EmpathyNewChatroomDialog *dialog)
+{
+ if (dialog->room_list) {
+ empathy_tp_roomlist_stop (dialog->room_list);
+ }
+}
+
+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/gnome-2-22/libempathy-gtk/empathy-new-chatroom-dialog.glade b/gnome-2-22/libempathy-gtk/empathy-new-chatroom-dialog.glade
new file mode 100644
index 000000000..6b99dc3e1
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-new-chatroom-dialog.glade
@@ -0,0 +1,437 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkDialog" id="new_chatroom_dialog">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Join New</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="default_width">350</property>
+ <property name="resizable">False</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox4">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area4">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="button_cancel">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-7</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button_join">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-5</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment4">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox29">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image4">
+ <property name="visible">True</property>
+ <property name="stock">gtk-execute</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label79">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Join</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox_widgets">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkTable" id="table_info">
+ <property name="visible">True</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label_account">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Account:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_server">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Server:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_server</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_room">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Room:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_room</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_server">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Enter the server which hosts the room, or leave it empty if the room is on the current account's server</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ <property name="width_chars">25</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToggleButton" id="togglebutton_refresh">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Re_fresh</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_room">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Enter the room name to join here or click on one or more rooms in the list.</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">True</property>
+ <property name="width_chars">32</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox_browse">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox_status">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox35">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">3</property>
+
+ <child>
+ <widget class="GtkImage" id="image_status">
+ <property name="visible">True</property>
+ <property name="icon_size">2</property>
+ <property name="icon_name">gtk-find</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label_status">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Browse:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow2">
+ <property name="height_request">150</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="treeview">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">This list represents all chat rooms hosted on the server you have entered.</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-new-chatroom-dialog.h b/gnome-2-22/libempathy-gtk/empathy-new-chatroom-dialog.h
new file mode 100644
index 000000000..2a126085d
--- /dev/null
+++ b/gnome-2-22/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 <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#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/gnome-2-22/libempathy-gtk/empathy-new-message-dialog.c b/gnome-2-22/libempathy-gtk/empathy-new-message-dialog.c
new file mode 100644
index 000000000..6c588a660
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-new-message-dialog.c
@@ -0,0 +1,164 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007-2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <glib/gi18n.h>
+
+#include <libmissioncontrol/mc-account.h>
+#include <libmissioncontrol/mission-control.h>
+
+#include <libempathy/empathy-contact-factory.h>
+#include <libempathy/empathy-debug.h>
+#include <libempathy/empathy-utils.h>
+
+#include <libempathy-gtk/empathy-ui-utils.h>
+
+#include "empathy-new-message-dialog.h"
+#include "empathy-account-chooser.h"
+
+#define DEBUG_DOMAIN "NewMessageDialog"
+
+typedef struct {
+ GtkWidget *dialog;
+ GtkWidget *table_contact;
+ GtkWidget *account_chooser;
+ GtkWidget *entry_id;
+ GtkWidget *button_chat;
+ GtkWidget *button_call;
+} EmpathyNewMessageDialog;
+
+static void
+new_message_dialog_response_cb (GtkWidget *widget,
+ gint response,
+ EmpathyNewMessageDialog *dialog)
+{
+ McAccount *account;
+ const gchar *id;
+
+ account = empathy_account_chooser_get_account (EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser));
+ id = gtk_entry_get_text (GTK_ENTRY (dialog->entry_id));
+ if (!account || G_STR_EMPTY (id)) {
+ if (account) {
+ g_object_unref (account);
+ }
+ gtk_widget_destroy (widget);
+ return;
+ }
+
+ if (response == 1) {
+ empathy_call_with_contact_id (account, id);
+ }
+ else if (response == 2) {
+ empathy_chat_with_contact_id (account, id);
+ }
+
+ g_object_unref (account);
+ gtk_widget_destroy (widget);
+}
+
+static void
+new_message_change_state_button_cb (GtkEditable *editable,
+ EmpathyNewMessageDialog *dialog)
+{
+ const gchar *id;
+ gboolean sensitive;
+
+ id = gtk_entry_get_text (GTK_ENTRY (editable));
+ sensitive = !G_STR_EMPTY (id);
+
+ gtk_widget_set_sensitive (dialog->button_chat, sensitive);
+ gtk_widget_set_sensitive (dialog->button_call, sensitive);
+}
+
+static void
+new_message_dialog_destroy_cb (GtkWidget *widget,
+ EmpathyNewMessageDialog *dialog)
+{
+ g_free (dialog);
+}
+
+GtkWidget *
+empathy_new_message_dialog_show (GtkWindow *parent)
+{
+ static EmpathyNewMessageDialog *dialog = NULL;
+ GladeXML *glade;
+
+ if (dialog) {
+ gtk_window_present (GTK_WINDOW (dialog->dialog));
+ return dialog->dialog;
+ }
+
+ dialog = g_new0 (EmpathyNewMessageDialog, 1);
+
+ glade = empathy_glade_get_file ("empathy-new-message-dialog.glade",
+ "new_message_dialog",
+ NULL,
+ "new_message_dialog", &dialog->dialog,
+ "table_contact", &dialog->table_contact,
+ "entry_id", &dialog->entry_id,
+ "button_chat", &dialog->button_chat,
+ "button_call",&dialog->button_call,
+ NULL);
+
+ empathy_glade_connect (glade,
+ dialog,
+ "new_message_dialog", "destroy", new_message_dialog_destroy_cb,
+ "new_message_dialog", "response", new_message_dialog_response_cb,
+ "entry_id", "changed", new_message_change_state_button_cb,
+ NULL);
+
+ g_object_add_weak_pointer (G_OBJECT (dialog->dialog), (gpointer) &dialog);
+
+ g_object_unref (glade);
+
+ /* Create account chooser */
+ dialog->account_chooser = empathy_account_chooser_new ();
+ gtk_table_attach_defaults (GTK_TABLE (dialog->table_contact),
+ dialog->account_chooser,
+ 1, 2, 0, 1);
+ empathy_account_chooser_set_filter (EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser),
+ empathy_account_chooser_filter_is_connected,
+ NULL);
+ gtk_widget_show (dialog->account_chooser);
+
+ if (parent) {
+ gtk_window_set_transient_for (GTK_WINDOW (dialog->dialog),
+ GTK_WINDOW (parent));
+ }
+
+ gtk_widget_set_sensitive (dialog->button_chat, FALSE);
+ gtk_widget_set_sensitive (dialog->button_call, FALSE);
+
+#ifndef HAVE_VOIP
+ gtk_widget_hide (dialog->button_call);
+#endif
+
+ gtk_widget_show (dialog->dialog);
+
+ return dialog->dialog;
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-new-message-dialog.glade b/gnome-2-22/libempathy-gtk/empathy-new-message-dialog.glade
new file mode 100644
index 000000000..25f4b2254
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-new-message-dialog.glade
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+ <widget class="GtkDialog" id="new_message_dialog">
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">New Conversation</property>
+ <property name="resizable">False</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <widget class="GtkTable" id="table_contact">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">6</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="entry_id">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Contact ID:</property>
+ </widget>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Account:</property>
+ </widget>
+ <packing>
+ <property name="x_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <child>
+ <widget class="GtkButton" id="button1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="button_call">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="response_id">1</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <widget class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="icon_name">gnome-stock-mic</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Call</property>
+ <property name="use_underline">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="button_chat">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="response_id">2</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <child>
+ <widget class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <widget class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="icon_name">im-message-new</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Chat</property>
+ <property name="use_underline">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-new-message-dialog.h b/gnome-2-22/libempathy-gtk/empathy-new-message-dialog.h
new file mode 100644
index 000000000..27e461f9b
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-new-message-dialog.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_NEW_MESSAGE_DIALOG_H__
+#define __EMPATHY_NEW_MESSAGE_DIALOG_H__
+
+#include <gtk/gtkwidget.h>
+
+G_BEGIN_DECLS
+
+GtkWidget *empathy_new_message_dialog_show (GtkWindow *parent);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_NEW_MESSAGE_DIALOG_H__ */
diff --git a/gnome-2-22/libempathy-gtk/empathy-preferences.c b/gnome-2-22/libempathy-gtk/empathy-preferences.c
new file mode 100644
index 000000000..50c9d5660
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-preferences.c
@@ -0,0 +1,990 @@
+/* -*- 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 <micke@imendio.com>
+ * Richard Hult <richard@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <glib/gi18n.h>
+
+#include "empathy-conf.h"
+#include "empathy-preferences.h"
+#include "empathy-ui-utils.h"
+#include "empathy-theme-manager.h"
+#include "empathy-spell.h"
+#include "empathy-contact-list-store.h"
+#include "empathy-gtk-enum-types.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 *checkbutton_autoconnect;
+ 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;
+
+ 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_radio_button (preferences,
+ EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM,
+ preferences->radiobutton_contact_list_sort_by_name);
+
+ preferences_hookup_toggle_button (preferences,
+ EMPATHY_PREFS_AUTOCONNECT,
+ preferences->checkbutton_autoconnect);
+}
+
+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 ();
+
+ empathy_conf_set_bool (empathy_conf_get(),
+ EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED,
+ codes != NULL);
+ if (!codes) {
+ gtk_widget_set_sensitive (preferences->treeview_spell_checker, FALSE);
+ }
+
+ 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 user selects no languages, we don't want spell check */
+ empathy_conf_set_bool (empathy_conf_get (),
+ EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED,
+ languages != NULL);
+
+ empathy_conf_set_string (empathy_conf_get (),
+ EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES,
+ 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,
+ "checkbutton_autoconnect", &preferences->checkbutton_autoconnect,
+ "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,
+ 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/gnome-2-22/libempathy-gtk/empathy-preferences.glade b/gnome-2-22/libempathy-gtk/empathy-preferences.glade
new file mode 100644
index 000000000..725844491
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-preferences.glade
@@ -0,0 +1,1063 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkDialog" id="preferences_dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Preferences</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="icon_name">gtk-preferences</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox5">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area5">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="button_close">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkNotebook" id="notebook">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="show_tabs">True</property>
+ <property name="show_border">True</property>
+ <property name="tab_pos">GTK_POS_TOP</property>
+ <property name="scrollable">False</property>
+ <property name="enable_popup">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox197">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkFrame" id="frame3">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment11">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">6</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox199">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton_show_avatars">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Avatars are user chosen images shown in the contact list</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Show _avatars</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">True</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton_compact_contact_list">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Show co_mpact contact list</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton_show_smileys">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Show _smileys as images</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">True</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label611">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Appearance&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFrame" id="frame4">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment12">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">6</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox218">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton_separate_chat_windows">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Open new chats in separate windows</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton_autoconnect">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Automatically _connect on startup </property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">True</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label612">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Behaviour&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFrame" id="frame13">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment31">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">6</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox217">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkRadioButton" id="radiobutton_contact_list_sort_by_name">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Sort by _name</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="radiobutton_contact_list_sort_by_state">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Sort by s_tate</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">radiobutton_contact_list_sort_by_name</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label644">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Contact List&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label602">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">General</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="outer_vbox">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkFrame" id="frame5">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment13">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">6</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox106">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton_sounds_for_messages">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Play sound when messages arrive</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton_sounds_when_busy">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Enable sounds when _busy</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton_sounds_when_away">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Enable sounds when _away</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label613">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Audio&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFrame" id="frame6">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment14">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">6</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton_popups_when_available">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Display notifications when contacts come _online</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label614">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Visual&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label607">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Notifications</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox168">
+ <property name="border_width">12</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkFrame" id="frame7">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment15">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">6</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox201">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox153">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox154">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow18">
+ <property name="visible">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="treeview_spell_checker">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox155">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkImage" id="image422">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-info</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label616">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;small&gt;The list of languages reflects only the languages for which you have a dictionary installed.&lt;/small&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label615">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Enable spell checking for languages:&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label567">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Spell Checking</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox206">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkFrame" id="frame11">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment19">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">6</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox207">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox139">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label586">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Chat Th_eme:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">combobox_chat_theme</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="combobox_chat_theme">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes"></property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label626">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Appearance&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFrame" id="frame12">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment20">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">6</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton_theme_chat_room">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Use for chat rooms</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label627">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Options&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label624">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Themes</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-preferences.h b/gnome-2-22/libempathy-gtk/empathy-preferences.h
new file mode 100644
index 000000000..750666b09
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-preferences.h
@@ -0,0 +1,62 @@
+/* -*- 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 <micke@imendio.com>
+ * Richard Hult <richard@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ */
+
+#ifndef __EMPATHY_PREFERENCES_H__
+#define __EMPATHY_PREFERENCES_H__
+
+#include <gtk/gtkwindow.h>
+
+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_CHAT_NICK_COMPLETION_CHAR EMPATHY_PREFS_PATH "/conversation/nick_completion_char"
+#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"
+#define EMPATHY_PREFS_SALUT_ACCOUNT_CREATED EMPATHY_PREFS_PATH "/accounts/salut_created"
+#define EMPATHY_PREFS_USE_NM EMPATHY_PREFS_PATH "/use_nm"
+#define EMPATHY_PREFS_AUTOCONNECT EMPATHY_PREFS_PATH "/autoconnect"
+
+GtkWidget * empathy_preferences_show (GtkWindow *parent);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_PREFERENCES_H__ */
+
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-presence-chooser.c b/gnome-2-22/libempathy-gtk/empathy-presence-chooser.c
new file mode 100644
index 000000000..dfed7bfc7
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-presence-chooser.c
@@ -0,0 +1,974 @@
+/* -*- 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 <richard@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+
+#include <telepathy-glib/util.h>
+#include <libmissioncontrol/mc-enum-types.h>
+
+#include <libempathy/empathy-idle.h>
+#include <libempathy/empathy-utils.h>
+#include <libempathy/empathy-debug.h>
+#include <libempathy/empathy-status-presets.h>
+
+#include "empathy-ui-utils.h"
+#include "empathy-images.h"
+#include "empathy-presence-chooser.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 {
+ GtkWidget *dialog;
+ GtkWidget *checkbutton_save;
+ GtkWidget *comboboxentry_message;
+ GtkWidget *entry_message;
+ GtkWidget *combobox_status;
+ GtkTreeModel *model_status;
+} CustomMessageDialog;
+
+enum {
+ COL_ICON,
+ COL_LABEL,
+ COL_PRESENCE,
+ COL_COUNT
+};
+
+typedef struct {
+ McPresence state;
+ const gchar *status;
+} StateAndStatus;
+
+static CustomMessageDialog *message_dialog = NULL;
+/* States to be listed in the menu.
+ * Each state has a boolean telling if it can have custom message */
+static guint states[] = {MC_PRESENCE_AVAILABLE, TRUE,
+ MC_PRESENCE_DO_NOT_DISTURB, TRUE,
+ MC_PRESENCE_AWAY, TRUE,
+ MC_PRESENCE_HIDDEN, FALSE,
+ MC_PRESENCE_OFFLINE, FALSE};
+
+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);
+static void presence_chooser_noncustom_activate_cb (GtkWidget *item,
+ gpointer user_data);
+static void presence_chooser_set_state (McPresence state,
+ const gchar *status);
+static void presence_chooser_custom_activate_cb (GtkWidget *item,
+ gpointer user_data);
+static void presence_chooser_dialog_show (void);
+
+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_seconds (1,
+ (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_get_default_message (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 += 2) {
+ GList *presets, *p;
+ StateAndStatus *sas;
+ const gchar *status;
+
+ status = empathy_presence_get_default_message (states[i]);
+ sas = presence_chooser_state_and_status_new (states[i], status);
+ list = g_list_prepend (list, sas);
+
+ /* Go to next state if we don't want messages for that state */
+ if (!states[i+1]) {
+ continue;
+ }
+
+ 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_prepend (list, sas);
+ }
+ g_list_free (presets);
+ }
+ list = g_list_reverse (list);
+
+ 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),
+ 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),
+ 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 += 2) {
+ GList *list, *l;
+
+ status = empathy_presence_get_default_message (states[i]);
+ presence_chooser_menu_add_item (menu,
+ status,
+ states[i]);
+
+ if (states[i+1]) {
+ /* Set custom messages if wanted */
+ 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]);
+ }
+ g_list_free (list);
+ }
+
+ }
+
+ /* Separator. */
+ item = gtk_menu_item_new ();
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ gtk_widget_show (item);
+
+ /* Custom messages */
+ item = gtk_image_menu_item_new_with_label (_("Custom messages..."));
+ image = gtk_image_new_from_stock (GTK_STOCK_EDIT, 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_custom_activate_cb),
+ NULL);
+
+ return menu;
+}
+
+static void
+presence_chooser_menu_add_item (GtkWidget *menu,
+ const gchar *str,
+ McPresence state)
+{
+ 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);
+
+ 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_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);
+}
+
+static void
+presence_chooser_set_state (McPresence state,
+ const gchar *status)
+{
+ EmpathyIdle *idle;
+
+ 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)
+{
+ presence_chooser_dialog_show ();
+}
+
+static McPresence
+presence_chooser_dialog_get_selected (CustomMessageDialog *dialog)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ McPresence presence = LAST_MC_PRESENCE;
+
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (dialog->combobox_status));
+ if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (dialog->combobox_status), &iter)) {
+ gtk_tree_model_get (model, &iter,
+ COL_PRESENCE, &presence,
+ -1);
+ }
+
+ return presence;
+}
+
+static void
+presence_chooser_dialog_status_changed_cb (GtkWidget *widget,
+ CustomMessageDialog *dialog)
+{
+ GtkListStore *store;
+ GtkTreeIter iter;
+ McPresence presence = LAST_MC_PRESENCE;
+ GList *messages, *l;
+
+ presence = presence_chooser_dialog_get_selected (dialog);
+
+ store = gtk_list_store_new (1, G_TYPE_STRING);
+ messages = empathy_status_presets_get (presence, -1);
+ for (l = messages; l; l = l->next) {
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, l->data, -1);
+ }
+
+ gtk_entry_set_text (GTK_ENTRY (dialog->entry_message),
+ messages ? messages->data : "");
+
+ g_list_free (messages);
+
+ gtk_combo_box_set_model (GTK_COMBO_BOX (dialog->comboboxentry_message),
+ GTK_TREE_MODEL (store));
+
+ g_object_unref (store);
+}
+
+static void
+presence_chooser_dialog_message_changed_cb (GtkWidget *widget,
+ CustomMessageDialog *dialog)
+{
+ McPresence presence;
+ GList *messages, *l;
+ const gchar *text;
+ gboolean found = FALSE;
+
+ presence = presence_chooser_dialog_get_selected (dialog);
+ text = gtk_entry_get_text (GTK_ENTRY (dialog->entry_message));
+
+ messages = empathy_status_presets_get (presence, -1);
+ for (l = messages; l; l = l->next) {
+ if (!tp_strdiff (text, l->data)) {
+ found = TRUE;
+ break;
+ }
+ }
+ g_list_free (messages);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->checkbutton_save),
+ found);
+}
+
+static void
+presence_chooser_dialog_save_toggled_cb (GtkWidget *widget,
+ CustomMessageDialog *dialog)
+{
+ gboolean active;
+ McPresence state;
+ const gchar *text;
+
+ active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->checkbutton_save));
+ state = presence_chooser_dialog_get_selected (dialog);
+ text = gtk_entry_get_text (GTK_ENTRY (dialog->entry_message));
+
+ if (active) {
+ empathy_status_presets_set_last (state, text);
+ } else {
+ empathy_status_presets_remove (state, text);
+ }
+}
+
+static void
+presence_chooser_dialog_setup (CustomMessageDialog *dialog)
+{
+ GtkListStore *store;
+ GtkCellRenderer *renderer;
+ GtkTreeIter iter;
+ guint i;
+
+ store = gtk_list_store_new (COL_COUNT,
+ G_TYPE_STRING, /* Icon name */
+ G_TYPE_STRING, /* Label */
+ MC_TYPE_PRESENCE); /* Presence */
+ gtk_combo_box_set_model (GTK_COMBO_BOX (dialog->combobox_status),
+ GTK_TREE_MODEL (store));
+
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (dialog->combobox_status), renderer, FALSE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (dialog->combobox_status), 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 (dialog->combobox_status), renderer, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (dialog->combobox_status), renderer,
+ "text", COL_LABEL,
+ NULL);
+
+ for (i = 0; i < G_N_ELEMENTS (states); i += 2) {
+ if (!states[i+1]) {
+ continue;
+ }
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_ICON, empathy_icon_name_for_presence (states[i]),
+ COL_LABEL, empathy_presence_get_default_message (states[i]),
+ COL_PRESENCE, states[i],
+ -1);
+ }
+
+ gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->combobox_status), 0);
+}
+
+static void
+presence_chooser_dialog_response_cb (GtkWidget *widget,
+ gint response,
+ CustomMessageDialog *dialog)
+{
+ if (response == GTK_RESPONSE_APPLY) {
+ McPresence state;
+ const gchar *text;
+
+ state = presence_chooser_dialog_get_selected (dialog);
+ text = gtk_entry_get_text (GTK_ENTRY (dialog->entry_message));
+
+ presence_chooser_set_state (state, text);
+ }
+
+ gtk_widget_destroy (widget);
+}
+
+static void
+presence_chooser_dialog_destroy_cb (GtkWidget *widget,
+ CustomMessageDialog *dialog)
+{
+
+ g_free (dialog);
+ message_dialog = NULL;
+}
+
+static void
+presence_chooser_dialog_show (void)
+{
+ GladeXML *glade;
+
+ if (message_dialog) {
+ gtk_window_present (GTK_WINDOW (message_dialog->dialog));
+ return;
+ }
+
+ message_dialog = g_new0 (CustomMessageDialog, 1);
+ glade = empathy_glade_get_file ("empathy-presence-chooser.glade",
+ "custom_message_dialog",
+ NULL,
+ "custom_message_dialog", &message_dialog->dialog,
+ "checkbutton_save", &message_dialog->checkbutton_save,
+ "comboboxentry_message", &message_dialog->comboboxentry_message,
+ "combobox_status", &message_dialog->combobox_status,
+ NULL);
+ empathy_glade_connect (glade,
+ message_dialog,
+ "custom_message_dialog", "destroy", presence_chooser_dialog_destroy_cb,
+ "custom_message_dialog", "response", presence_chooser_dialog_response_cb,
+ "combobox_status", "changed", presence_chooser_dialog_status_changed_cb,
+ "checkbutton_save", "toggled", presence_chooser_dialog_save_toggled_cb,
+ NULL);
+
+ g_object_unref (glade);
+
+ /* Setup the message combobox */
+ message_dialog->entry_message = GTK_BIN (message_dialog->comboboxentry_message)->child;
+ gtk_entry_set_activates_default (GTK_ENTRY (message_dialog->entry_message), TRUE);
+ gtk_entry_set_width_chars (GTK_ENTRY (message_dialog->entry_message), 25);
+ g_signal_connect (message_dialog->entry_message, "changed",
+ G_CALLBACK (presence_chooser_dialog_message_changed_cb),
+ message_dialog);
+
+ presence_chooser_dialog_setup (message_dialog);
+
+ gtk_combo_box_entry_set_text_column (GTK_COMBO_BOX_ENTRY (message_dialog->comboboxentry_message), 0);
+
+ /* FIXME: Set transian for a window ? */
+
+ gtk_widget_show_all (message_dialog->dialog);
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-presence-chooser.glade b/gnome-2-22/libempathy-gtk/empathy-presence-chooser.glade
new file mode 100644
index 000000000..a3a26a156
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-presence-chooser.glade
@@ -0,0 +1,200 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+<requires lib="gnome"/>
+
+<widget class="GtkDialog" id="custom_message_dialog">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Custom message</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">False</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox6">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area6">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="closebutton1">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button1">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-apply</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-10</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table1">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label471">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Status:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label472">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Message:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton_save">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Save message</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBoxEntry" id="comboboxentry_message">
+ <property name="visible">True</property>
+ <property name="add_tearoffs">False</property>
+ <property name="has_frame">True</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="combobox_status">
+ <property name="visible">True</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-presence-chooser.h b/gnome-2-22/libempathy-gtk/empathy-presence-chooser.h
new file mode 100644
index 000000000..a04458d83
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-presence-chooser.h
@@ -0,0 +1,57 @@
+/* -*- 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 <richard@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_PRESENCE_CHOOSER_H__
+#define __EMPATHY_PRESENCE_CHOOSER_H__
+
+#include <gtk/gtk.h>
+
+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/gnome-2-22/libempathy-gtk/empathy-private-chat.c b/gnome-2-22/libempathy-gtk/empathy-private-chat.c
new file mode 100644
index 000000000..4ee02e467
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-private-chat.c
@@ -0,0 +1,362 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002-2007 Imendio AB
+ * Copyright (C) 2007-2008 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 <micke@imendio.com>
+ * Richard Hult <richard@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ * Geert-Jan Van den Bogaerde <geertjan@gnome.org>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <glib/gi18n.h>
+
+#include <libmissioncontrol/mission-control.h>
+
+#include <libempathy/empathy-debug.h>
+#include <libempathy/empathy-tp-chat.h>
+#include <libempathy/empathy-tp-contact-list.h>
+#include <libempathy/empathy-contact-factory.h>
+#include <libempathy/empathy-utils.h>
+
+#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 {
+ EmpathyContactFactory *factory;
+ 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 GObject *
+private_chat_constructor (GType type,
+ guint n_props,
+ GObjectConstructParam *props)
+{
+ GObject *chat;
+ EmpathyPrivateChatPriv *priv;
+ EmpathyTpChat *tp_chat;
+ TpChan *tp_chan;
+ McAccount *account;
+
+ chat = G_OBJECT_CLASS (empathy_private_chat_parent_class)->constructor (type, n_props, props);
+
+ priv = GET_PRIV (chat);
+
+ g_object_get (chat, "tp-chat", &tp_chat, NULL);
+ tp_chan = empathy_tp_chat_get_channel (tp_chat);
+ account = empathy_tp_chat_get_account (tp_chat);
+
+ priv->factory = empathy_contact_factory_new ();
+ priv->contact = empathy_contact_factory_get_from_handle (priv->factory,
+ account,
+ tp_chan->handle);
+
+ priv->name = g_strdup (empathy_contact_get_name (priv->contact));
+
+ 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);
+
+ g_object_unref (tp_chat);
+
+ return 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;
+ object_class->constructor = private_chat_constructor;
+
+ 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)
+{
+ 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);
+ }
+ if (priv->factory) {
+ g_object_unref (priv->factory);
+ }
+ 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 && !EMPATHY_CHAT (chat)->block_events) {
+ 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 && !EMPATHY_CHAT (chat)->block_events) {
+ 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;
+
+ /* If offline message is not supported by CM we need to
+ * request a new Text Channel. */
+ if (!empathy_chat_is_connected (EMPATHY_CHAT (chat))) {
+ empathy_chat_with_contact (contact);
+ }
+ }
+
+ 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;
+}
+
+EmpathyPrivateChat *
+empathy_private_chat_new (EmpathyTpChat *tp_chat)
+{
+ EmpathyPrivateChat *chat;
+
+ g_return_val_if_fail (EMPATHY_IS_TP_CHAT (tp_chat), NULL);
+
+ chat = g_object_new (EMPATHY_TYPE_PRIVATE_CHAT,
+ "tp-chat", tp_chat,
+ NULL);
+
+ return chat;
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-private-chat.h b/gnome-2-22/libempathy-gtk/empathy-private-chat.h
new file mode 100644
index 000000000..169809bb0
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-private-chat.h
@@ -0,0 +1,63 @@
+/* -*- 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 <micke@imendio.com>
+ * Richard Hult <richard@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ * Geert-Jan Van den Bogaerde <geertjan@gnome.org>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_PRIVATE_CHAT_H__
+#define __EMPATHY_PRIVATE_CHAT_H__
+
+#include <libempathy/empathy-tp-chat.h>
+#include <libempathy/empathy-contact.h>
+
+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 (EmpathyTpChat *tp_chat);
+EmpathyContact * empathy_private_chat_get_contact (EmpathyPrivateChat *chat);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_PRIVATE_CHAT_H__ */
diff --git a/gnome-2-22/libempathy-gtk/empathy-profile-chooser.c b/gnome-2-22/libempathy-gtk/empathy-profile-chooser.c
new file mode 100644
index 000000000..6c46b6cc5
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-profile-chooser.c
@@ -0,0 +1,190 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007-2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <libmissioncontrol/mc-profile.h>
+#include <libmissioncontrol/mc-protocol.h>
+
+#include "empathy-profile-chooser.h"
+#include "empathy-ui-utils.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;
+}
+
+gint
+empathy_profile_chooser_n_profiles (GtkWidget *widget)
+{
+ GtkTreeModel *model;
+
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
+
+ return gtk_tree_model_iter_n_children (model, NULL);
+}
+
+static gint
+profile_chooser_sort_profile_value (McProfile *profile)
+{
+ guint i;
+ const gchar *profile_name;
+ const gchar *names[] = {"jabber",
+ "salut",
+ "gtalk",
+ NULL};
+
+ profile_name = mc_profile_get_unique_name (profile);
+
+ for (i = 0 ; names[i]; i++) {
+ if (strcmp (profile_name, names[i]) == 0) {
+ return i;
+ }
+ }
+
+ return i;
+}
+
+static gint
+profile_chooser_sort_func (GtkTreeModel *model,
+ GtkTreeIter *iter_a,
+ GtkTreeIter *iter_b,
+ gpointer user_data)
+{
+ McProfile *profile_a;
+ McProfile *profile_b;
+ gint cmp;
+
+ gtk_tree_model_get (model, iter_a,
+ COL_PROFILE, &profile_a,
+ -1);
+ gtk_tree_model_get (model, iter_b,
+ COL_PROFILE, &profile_b,
+ -1);
+
+ cmp = profile_chooser_sort_profile_value (profile_a);
+ cmp -= profile_chooser_sort_profile_value (profile_b);
+ if (cmp == 0) {
+ cmp = strcmp (mc_profile_get_display_name (profile_a),
+ mc_profile_get_display_name (profile_b));
+ }
+
+ g_object_unref (profile_a);
+ g_object_unref (profile_b);
+
+ return cmp;
+}
+
+GtkWidget *
+empathy_profile_chooser_new (void)
+{
+ GList *profiles, *l;
+ GtkListStore *store;
+ GtkCellRenderer *renderer;
+ GtkWidget *combo_box;
+ GtkTreeIter iter;
+ gboolean iter_set = FALSE;
+
+ /* 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;
+ McProtocol *protocol;
+
+ profile = l->data;
+
+ /* Check if the CM is installed, otherwise skip that profile.
+ * Workaround SF bug #1688779 */
+ protocol = mc_profile_get_protocol (profile);
+ if (!protocol) {
+ continue;
+ }
+ g_object_unref (protocol);
+
+ gtk_list_store_insert_with_values (store, &iter, 0,
+ COL_ICON, mc_profile_get_icon_name (profile),
+ COL_LABEL, mc_profile_get_display_name (profile),
+ COL_PROFILE, profile,
+ -1);
+ iter_set = TRUE;
+ }
+
+ /* Set the profile sort function */
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store),
+ COL_PROFILE,
+ profile_chooser_sort_func,
+ NULL, NULL);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+ COL_PROFILE,
+ GTK_SORT_ASCENDING);
+
+ if (iter_set) {
+ 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/gnome-2-22/libempathy-gtk/empathy-profile-chooser.h b/gnome-2-22/libempathy-gtk/empathy-profile-chooser.h
new file mode 100644
index 000000000..2cd74e351
--- /dev/null
+++ b/gnome-2-22/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 library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_PROTOCOL_CHOOSER_H__
+#define __EMPATHY_PROTOCOL_CHOOSER_H__
+
+#include <libmissioncontrol/mc-profile.h>
+
+G_BEGIN_DECLS
+
+GtkWidget * empathy_profile_chooser_new (void);
+McProfile * empathy_profile_chooser_get_selected (GtkWidget *widget);
+gint empathy_profile_chooser_n_profiles (GtkWidget *widget);
+
+G_END_DECLS
+#endif /* __EMPATHY_PROTOCOL_CHOOSER_H__ */
diff --git a/gnome-2-22/libempathy-gtk/empathy-smiley-manager.c b/gnome-2-22/libempathy-gtk/empathy-smiley-manager.c
new file mode 100644
index 000000000..d32570bb3
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-smiley-manager.c
@@ -0,0 +1,353 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007-2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Dafydd Harrie <dafydd.harries@collabora.co.uk>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <libempathy/empathy-debug.h>
+
+#include "empathy-smiley-manager.h"
+#include "empathy-ui-utils.h"
+
+#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
+ EMPATHY_TYPE_SMILEY_MANAGER, EmpathySmileyManagerPriv))
+
+#define DEBUG_DOMAIN "SmileyManager"
+
+typedef struct {
+ gunichar c;
+ GdkPixbuf *pixbuf;
+ GSList *childrens;
+} SmileyManagerTree;
+
+struct _EmpathySmileyManagerPriv {
+ SmileyManagerTree *tree;
+ GSList *smileys;
+};
+
+static void empathy_smiley_manager_class_init (EmpathySmileyManagerClass *klass);
+static void empathy_smiley_manager_init (EmpathySmileyManager *manager);
+
+G_DEFINE_TYPE (EmpathySmileyManager, empathy_smiley_manager, G_TYPE_OBJECT);
+
+static SmileyManagerTree *
+smiley_manager_tree_new (gunichar c)
+{
+ SmileyManagerTree *tree;
+
+ tree = g_slice_new0 (SmileyManagerTree);
+ tree->c = c;
+ tree->pixbuf = NULL;
+ tree->childrens = NULL;
+
+ return tree;
+}
+
+static void
+smiley_manager_tree_free (SmileyManagerTree *tree)
+{
+ GSList *l;
+
+ if (!tree) {
+ return;
+ }
+
+ for (l = tree->childrens; l; l = l->next) {
+ smiley_manager_tree_free (l->data);
+ }
+
+ if (tree->pixbuf) {
+ g_object_unref (tree->pixbuf);
+ }
+ g_slist_free (tree->childrens);
+ g_slice_free (SmileyManagerTree, tree);
+}
+
+static EmpathySmiley *
+smiley_new (GdkPixbuf *pixbuf, const gchar *str)
+{
+ EmpathySmiley *smiley;
+
+ smiley = g_slice_new0 (EmpathySmiley);
+ if (pixbuf) {
+ smiley->pixbuf = g_object_ref (pixbuf);
+ }
+ smiley->str = g_strdup (str);
+
+ return smiley;
+}
+
+void
+empathy_smiley_free (EmpathySmiley *smiley)
+{
+ if (!smiley) {
+ return;
+ }
+
+ if (smiley->pixbuf) {
+ g_object_unref (smiley->pixbuf);
+ }
+ g_free (smiley->str);
+ g_slice_free (EmpathySmiley, smiley);
+}
+
+static void
+smiley_manager_finalize (GObject *object)
+{
+ EmpathySmileyManagerPriv *priv = GET_PRIV (object);
+
+ smiley_manager_tree_free (priv->tree);
+ g_slist_foreach (priv->smileys, (GFunc) empathy_smiley_free, NULL);
+ g_slist_free (priv->smileys);
+}
+
+static void
+empathy_smiley_manager_class_init (EmpathySmileyManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = smiley_manager_finalize;
+
+ g_type_class_add_private (object_class, sizeof (EmpathySmileyManagerPriv));
+}
+
+static void
+empathy_smiley_manager_init (EmpathySmileyManager *manager)
+{
+ EmpathySmileyManagerPriv *priv = GET_PRIV (manager);
+
+ priv->tree = smiley_manager_tree_new ('\0');
+ priv->smileys = NULL;
+}
+
+EmpathySmileyManager *
+empathy_smiley_manager_new (void)
+{
+ static EmpathySmileyManager *manager = NULL;
+
+ if (!manager) {
+ manager = g_object_new (EMPATHY_TYPE_SMILEY_MANAGER, NULL);
+ g_object_add_weak_pointer (G_OBJECT (manager), (gpointer) &manager);
+ empathy_smiley_manager_load (manager);
+ } else {
+ g_object_ref (manager);
+ }
+
+ return manager;
+}
+
+static SmileyManagerTree *
+smiley_manager_tree_find_child (SmileyManagerTree *tree, gunichar c)
+{
+ GSList *l;
+
+ for (l = tree->childrens; l; l = l->next) {
+ SmileyManagerTree *child = l->data;
+
+ if (child->c == c) {
+ return child;
+ }
+ }
+
+ return NULL;
+}
+
+static SmileyManagerTree *
+smiley_manager_tree_find_or_insert_child (SmileyManagerTree *tree, gunichar c)
+{
+ SmileyManagerTree *child;
+
+ child = smiley_manager_tree_find_child (tree, c);
+
+ if (!child) {
+ child = smiley_manager_tree_new (c);
+ tree->childrens = g_slist_prepend (tree->childrens, child);
+ }
+
+ return child;
+}
+
+static void
+smiley_manager_tree_insert (SmileyManagerTree *tree,
+ GdkPixbuf *smiley,
+ const gchar *str)
+{
+ SmileyManagerTree *child;
+
+ child = smiley_manager_tree_find_or_insert_child (tree, g_utf8_get_char (str));
+
+ str = g_utf8_next_char (str);
+ if (*str) {
+ smiley_manager_tree_insert (child, smiley, str);
+ return;
+ }
+
+ child->pixbuf = g_object_ref (smiley);
+}
+
+static void
+smiley_manager_add_valist (EmpathySmileyManager *manager,
+ GdkPixbuf *smiley,
+ const gchar *first_str,
+ va_list var_args)
+{
+ EmpathySmileyManagerPriv *priv = GET_PRIV (manager);
+ const gchar *str;
+
+ for (str = first_str; str; str = va_arg (var_args, gchar*)) {
+ smiley_manager_tree_insert (priv->tree, smiley, str);
+ }
+
+ priv->smileys = g_slist_prepend (priv->smileys, smiley_new (smiley, first_str));
+}
+
+void
+empathy_smiley_manager_add (EmpathySmileyManager *manager,
+ const gchar *icon_name,
+ const gchar *first_str,
+ ...)
+{
+ GdkPixbuf *smiley;
+ va_list var_args;
+
+ g_return_if_fail (EMPATHY_IS_SMILEY_MANAGER (manager));
+ g_return_if_fail (!G_STR_EMPTY (icon_name));
+ g_return_if_fail (!G_STR_EMPTY (first_str));
+
+ smiley = empathy_pixbuf_from_icon_name (icon_name, GTK_ICON_SIZE_MENU);
+ if (smiley) {
+ va_start (var_args, first_str);
+ smiley_manager_add_valist (manager, smiley, first_str, var_args);
+ va_end (var_args);
+ g_object_unref (smiley);
+ }
+}
+
+void
+empathy_smiley_manager_add_from_pixbuf (EmpathySmileyManager *manager,
+ GdkPixbuf *smiley,
+ const gchar *first_str,
+ ...)
+{
+ va_list var_args;
+
+ g_return_if_fail (EMPATHY_IS_SMILEY_MANAGER (manager));
+ g_return_if_fail (GDK_IS_PIXBUF (smiley));
+ g_return_if_fail (!G_STR_EMPTY (first_str));
+
+ va_start (var_args, first_str);
+ smiley_manager_add_valist (manager, smiley, first_str, var_args);
+ va_end (var_args);
+}
+
+void
+empathy_smiley_manager_load (EmpathySmileyManager *manager)
+{
+ g_return_if_fail (EMPATHY_IS_SMILEY_MANAGER (manager));
+
+ /* From fd.o icon-naming spec */
+ empathy_smiley_manager_add (manager, "face-angel", "O:-)", "O:)", NULL);
+ empathy_smiley_manager_add (manager, "face-cool", "B-)", "B)", NULL);
+ empathy_smiley_manager_add (manager, "face-crying", ":'(", NULL);
+ empathy_smiley_manager_add (manager, "face-devilish", ">:-)", ">:)", NULL);
+ empathy_smiley_manager_add (manager, "face-embarrassed",":-[", ":[", ":-$", ":$", NULL);
+ empathy_smiley_manager_add (manager, "face-kiss", ":-*", ":*", NULL);
+ empathy_smiley_manager_add (manager, "face-monkey", ":-(|)", ":(|)", NULL);
+ empathy_smiley_manager_add (manager, "face-plain", ":-|", ":|", NULL);
+ empathy_smiley_manager_add (manager, "face-raspberry", ":-P", ":P", ":-p", ":p", NULL);
+ empathy_smiley_manager_add (manager, "face-sad", ":-(", ":(", NULL);
+ empathy_smiley_manager_add (manager, "face-smile", ":-)", ":)", NULL);
+ empathy_smiley_manager_add (manager, "face-smile-big", ":-D", ":D", ":-d", ":d", NULL);
+ empathy_smiley_manager_add (manager, "face-smirk", ":-!", ":!", NULL);
+ empathy_smiley_manager_add (manager, "face-surprise", ":-O", ":O", NULL);
+ empathy_smiley_manager_add (manager, "face-wink", ";-)", ";)", NULL);
+}
+
+GSList *
+empathy_smiley_manager_parse (EmpathySmileyManager *manager,
+ const gchar *text)
+{
+ EmpathySmileyManagerPriv *priv = GET_PRIV (manager);
+ EmpathySmiley *smiley;
+ SmileyManagerTree *cur_tree = priv->tree;
+ const gchar *t;
+ const gchar *cur_str = text;
+ GSList *smileys = NULL;
+
+ g_return_val_if_fail (EMPATHY_IS_SMILEY_MANAGER (manager), NULL);
+ g_return_val_if_fail (text != NULL, NULL);
+
+ for (t = text; *t; t = g_utf8_next_char (t)) {
+ SmileyManagerTree *child;
+ gunichar c;
+
+ c = g_utf8_get_char (t);
+ child = smiley_manager_tree_find_child (cur_tree, c);
+
+ if (cur_tree == priv->tree) {
+ if (child) {
+ if (t > cur_str) {
+ smiley = smiley_new (NULL, g_strndup (cur_str, t - cur_str));
+ smileys = g_slist_prepend (smileys, smiley);
+ }
+ cur_str = t;
+ cur_tree = child;
+ }
+
+ continue;
+ }
+
+ if (child) {
+ cur_tree = child;
+ continue;
+ }
+
+ smiley = smiley_new (cur_tree->pixbuf, g_strndup (cur_str, t - cur_str));
+ smileys = g_slist_prepend (smileys, smiley);
+ if (cur_tree->pixbuf) {
+ cur_str = t;
+ cur_tree = smiley_manager_tree_find_child (priv->tree, c);
+
+ if (!cur_tree) {
+ cur_tree = priv->tree;
+ }
+ } else {
+ cur_str = t;
+ cur_tree = priv->tree;
+ }
+ }
+
+ smiley = smiley_new (cur_tree->pixbuf, g_strndup (cur_str, t - cur_str));
+ smileys = g_slist_prepend (smileys, smiley);
+
+ return g_slist_reverse (smileys);
+}
+
+GSList *
+empathy_smiley_manager_get_all (EmpathySmileyManager *manager)
+{
+ EmpathySmileyManagerPriv *priv = GET_PRIV (manager);
+
+ return priv->smileys;
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-smiley-manager.h b/gnome-2-22/libempathy-gtk/empathy-smiley-manager.h
new file mode 100644
index 000000000..19604f108
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-smiley-manager.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Dafydd Harrie <dafydd.harries@collabora.co.uk>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_SMILEY_MANAGER__H__
+#define __EMPATHY_SMILEY_MANAGER_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define EMPATHY_TYPE_SMILEY_MANAGER (empathy_smiley_manager_get_type ())
+#define EMPATHY_SMILEY_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_SMILEY_MANAGER, EmpathySmileyManager))
+#define EMPATHY_SMILEY_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_SMILEY_MANAGER, EmpathySmileyManagerClass))
+#define EMPATHY_IS_SMILEY_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_SMILEY_MANAGER))
+#define EMPATHY_IS_SMILEY_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_SMILEY_MANAGER))
+#define EMPATHY_SMILEY_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_SMILEY_MANAGER, EmpathySmileyManagerClass))
+
+typedef struct _EmpathySmileyManager EmpathySmileyManager;
+typedef struct _EmpathySmileyManagerClass EmpathySmileyManagerClass;
+typedef struct _EmpathySmileyManagerPriv EmpathySmileyManagerPriv;
+
+struct _EmpathySmileyManager {
+ GObject parent;
+};
+
+struct _EmpathySmileyManagerClass {
+ GObjectClass parent_class;
+};
+
+typedef struct {
+ GdkPixbuf *pixbuf;
+ gchar *str;
+} EmpathySmiley;
+
+GType empathy_smiley_manager_get_type (void) G_GNUC_CONST;
+EmpathySmileyManager *empathy_smiley_manager_new (void);
+void empathy_smiley_manager_load (EmpathySmileyManager *manager);
+void empathy_smiley_manager_add (EmpathySmileyManager *manager,
+ const gchar *icon_name,
+ const gchar *first_str,
+ ...);
+void empathy_smiley_manager_add_from_pixbuf (EmpathySmileyManager *manager,
+ GdkPixbuf *smiley,
+ const gchar *first_str,
+ ...);
+GSList * empathy_smiley_manager_get_all (EmpathySmileyManager *manager);
+GSList * empathy_smiley_manager_parse (EmpathySmileyManager *manager,
+ const gchar *text);
+void empathy_smiley_free (EmpathySmiley *smiley);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_SMILEY_MANAGER_H__ */
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-spell-dialog.c b/gnome-2-22/libempathy-gtk/empathy-spell-dialog.c
new file mode 100644
index 000000000..7f4d75a13
--- /dev/null
+++ b/gnome-2-22/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 <string.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <gtk/gtkdialog.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkliststore.h>
+#include <gtk/gtktreeview.h>
+#include <gtk/gtktreeselection.h>
+#include <gtk/gtksizegroup.h>
+#include <glade/glade.h>
+
+#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<b>%s</b>",
+ _("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/gnome-2-22/libempathy-gtk/empathy-spell-dialog.glade b/gnome-2-22/libempathy-gtk/empathy-spell-dialog.glade
new file mode 100644
index 000000000..502fb0d13
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-spell-dialog.glade
@@ -0,0 +1,205 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkDialog" id="spell_dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Spell Checker</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="modal">True</property>
+ <property name="default_width">275</property>
+ <property name="default_height">225</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox7">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area7">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="button_cancel">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button_replace">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-5</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment6">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox135">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image245">
+ <property name="visible">True</property>
+ <property name="stock">gtk-convert</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label594">
+ <property name="visible">True</property>
+ <property name="label">_Replace</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox128">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label_word">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Suggestions for the word:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow9">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="treeview_words">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-spell-dialog.h b/gnome-2-22/libempathy-gtk/empathy-spell-dialog.h
new file mode 100644
index 000000000..e6d2e4c7a
--- /dev/null
+++ b/gnome-2-22/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 <martyn@imendio.com>
+ * Richard Hult <richard@imendio.com>
+ */
+
+#ifndef __EMPATHY_SPELL_DIALOG_H__
+#define __EMPATHY_SPELL_DIALOG_H__
+
+#include <gtk/gtktextiter.h>
+#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/gnome-2-22/libempathy-gtk/empathy-spell.c b/gnome-2-22/libempathy-gtk/empathy-spell.c
new file mode 100644
index 000000000..b6620118a
--- /dev/null
+++ b/gnome-2-22/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 <martyn@imendio.com>
+ * Richard Hult <richard@imendio.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib/gi18n.h>
+
+#ifdef HAVE_ASPELL
+#include <aspell.h>
+#endif
+
+#include <libempathy/empathy-debug.h>
+
+#include "empathy-spell.h"
+#include "empathy-conf.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/gnome-2-22/libempathy-gtk/empathy-spell.h b/gnome-2-22/libempathy-gtk/empathy-spell.h
new file mode 100644
index 000000000..4f483cf35
--- /dev/null
+++ b/gnome-2-22/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 <martyn@imendio.com>
+ * Richard Hult <richard@imendio.com>
+ */
+
+#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/gnome-2-22/libempathy-gtk/empathy-status-icon.c b/gnome-2-22/libempathy-gtk/empathy-status-icon.c
new file mode 100644
index 000000000..9f10bd37e
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-status-icon.c
@@ -0,0 +1,861 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007-2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <glib/gi18n.h>
+
+#include <libmissioncontrol/mission-control.h>
+
+#include <libempathy/empathy-contact-list.h>
+#include <libempathy/empathy-contact-manager.h>
+#include <libempathy/empathy-contact.h>
+#include <libempathy/empathy-tp-chat.h>
+#include <libempathy/empathy-debug.h>
+#include <libempathy/empathy-utils.h>
+#include <libempathy/empathy-idle.h>
+#include <libempathy/empathy-filter.h>
+
+#include "empathy-status-icon.h"
+#include "empathy-contact-dialogs.h"
+#include "empathy-presence-chooser.h"
+#include "empathy-conf.h"
+#include "empathy-preferences.h"
+#include "empathy-ui-utils.h"
+#include "empathy-accounts-dialog.h"
+#include "empathy-images.h"
+#include "empathy-new-message-dialog.h"
+
+
+#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
+ EMPATHY_TYPE_STATUS_ICON, EmpathyStatusIconPriv))
+
+#define DEBUG_DOMAIN "StatusIcon"
+
+/* Number of ms to wait when blinking */
+#define BLINK_TIMEOUT 500
+
+typedef struct _StatusIconEvent StatusIconEvent;
+
+struct _EmpathyStatusIconPriv {
+ GtkStatusIcon *icon;
+ EmpathyContactManager *manager;
+ EmpathyFilter *text_filter;
+ EmpathyFilter *call_filter;
+ EmpathyIdle *idle;
+ MissionControl *mc;
+ GList *events;
+ gboolean showing_event_icon;
+ StatusIconEvent *flash_state_event;
+ guint blink_timeout;
+
+ GtkWindow *window;
+ GtkWidget *popup_menu;
+ GtkWidget *show_window_item;
+ GtkWidget *message_item;
+ GtkWidget *status_item;
+};
+
+typedef void (*EventActivatedFunc) (StatusIconEvent *event);
+
+struct _StatusIconEvent {
+ gchar *icon_name;
+ gchar *message;
+ EventActivatedFunc func;
+ gpointer user_data;
+};
+
+
+static void empathy_status_icon_class_init (EmpathyStatusIconClass *klass);
+static void empathy_status_icon_init (EmpathyStatusIcon *icon);
+static void status_icon_finalize (GObject *object);
+static void status_icon_text_filter_new_channel (EmpathyFilter *filter,
+ TpConn *tp_conn,
+ TpChan *tp_chan,
+ EmpathyStatusIcon *icon);
+static void status_icon_call_filter_new_channel (EmpathyFilter *filter,
+ TpConn *tp_conn,
+ TpChan *tp_chan,
+ EmpathyStatusIcon *icon);
+static void status_icon_message_received_cb (EmpathyTpChat *tp_chat,
+ EmpathyMessage *message,
+ EmpathyStatusIcon *icon);
+static void status_icon_idle_notify_cb (EmpathyStatusIcon *icon);
+static void status_icon_update_tooltip (EmpathyStatusIcon *icon);
+static void status_icon_set_from_state (EmpathyStatusIcon *icon);
+static void status_icon_set_visibility (EmpathyStatusIcon *icon,
+ gboolean visible,
+ gboolean store);
+static void status_icon_toggle_visibility (EmpathyStatusIcon *icon);
+static void status_icon_activate_cb (GtkStatusIcon *status_icon,
+ EmpathyStatusIcon *icon);
+static gboolean status_icon_delete_event_cb (GtkWidget *widget,
+ GdkEvent *event,
+ EmpathyStatusIcon *icon);
+static void status_icon_popup_menu_cb (GtkStatusIcon *status_icon,
+ guint button,
+ guint activate_time,
+ EmpathyStatusIcon *icon);
+static void status_icon_create_menu (EmpathyStatusIcon *icon);
+static void status_icon_new_message_cb (GtkWidget *widget,
+ EmpathyStatusIcon *icon);
+static void status_icon_quit_cb (GtkWidget *window,
+ EmpathyStatusIcon *icon);
+static void status_icon_show_hide_window_cb (GtkWidget *widget,
+ EmpathyStatusIcon *icon);
+static void status_icon_pendings_changed_cb (EmpathyContactManager *manager,
+ EmpathyContact *contact,
+ EmpathyContact *actor,
+ guint reason,
+ gchar *message,
+ gboolean is_pending,
+ EmpathyStatusIcon *icon);
+static void status_icon_event_subscribe_cb (StatusIconEvent *event);
+static void status_icon_event_flash_state_cb (StatusIconEvent *event);
+static void status_icon_event_msg_cb (StatusIconEvent *event);
+static StatusIconEvent * status_icon_event_new (EmpathyStatusIcon *icon,
+ const gchar *icon_name,
+ const gchar *message);
+static void status_icon_event_remove (EmpathyStatusIcon *icon,
+ StatusIconEvent *event);
+static gboolean status_icon_event_timeout_cb (EmpathyStatusIcon *icon);
+static void status_icon_event_free (StatusIconEvent *event);
+
+G_DEFINE_TYPE (EmpathyStatusIcon, empathy_status_icon, G_TYPE_OBJECT);
+
+static void
+status_icon_notify_use_nm_cb (EmpathyConf *conf,
+ const gchar *key,
+ gpointer user_data)
+{
+ EmpathyStatusIconPriv *priv = GET_PRIV (user_data);
+ gboolean use_nm;
+
+ if (empathy_conf_get_bool (conf, key, &use_nm)) {
+ empathy_idle_set_use_nm (priv->idle, use_nm);
+ }
+}
+
+static void
+status_icon_notify_visibility_cb (EmpathyConf *conf,
+ const gchar *key,
+ gpointer user_data)
+{
+ EmpathyStatusIcon *icon = user_data;
+ gboolean hidden = FALSE;
+
+ if (empathy_conf_get_bool (conf, key, &hidden)) {
+ status_icon_set_visibility (icon, !hidden, FALSE);
+ }
+}
+
+static void
+empathy_status_icon_class_init (EmpathyStatusIconClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = status_icon_finalize;
+
+ g_type_class_add_private (object_class, sizeof (EmpathyStatusIconPriv));
+}
+
+static void
+empathy_status_icon_init (EmpathyStatusIcon *icon)
+{
+ EmpathyStatusIconPriv *priv;
+ GList *pendings, *l;
+ gboolean use_nm;
+
+ priv = GET_PRIV (icon);
+
+ priv->icon = gtk_status_icon_new ();
+ priv->manager = empathy_contact_manager_new ();
+ priv->mc = empathy_mission_control_new ();
+ priv->text_filter = empathy_filter_new ("org.gnome.Empathy.ChatFilter",
+ "/org/gnome/Empathy/ChatFilter",
+ TP_IFACE_CHANNEL_TYPE_TEXT,
+ MC_FILTER_PRIORITY_DIALOG,
+ MC_FILTER_FLAG_INCOMING);
+ priv->call_filter = empathy_filter_new ("org.gnome.Empathy.CallFilter",
+ "/org/gnome/Empathy/CallFilter",
+ TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA,
+ MC_FILTER_PRIORITY_DIALOG,
+ MC_FILTER_FLAG_INCOMING);
+
+ /* Setup EmpathyIdle */
+ priv->idle = empathy_idle_new ();
+ empathy_conf_get_bool (empathy_conf_get (),
+ EMPATHY_PREFS_USE_NM,
+ &use_nm);
+ empathy_conf_notify_add (empathy_conf_get (),
+ EMPATHY_PREFS_USE_NM,
+ status_icon_notify_use_nm_cb,
+ icon);
+ empathy_idle_set_auto_away (priv->idle, TRUE);
+ empathy_idle_set_use_nm (priv->idle, use_nm);
+
+ /* make icon listen and respond to MAIN_WINDOW_HIDDEN changes */
+ empathy_conf_notify_add (empathy_conf_get (),
+ EMPATHY_PREFS_UI_MAIN_WINDOW_HIDDEN,
+ status_icon_notify_visibility_cb,
+ icon);
+
+ status_icon_create_menu (icon);
+ status_icon_idle_notify_cb (icon);
+
+ g_signal_connect (priv->text_filter, "new-channel",
+ G_CALLBACK (status_icon_text_filter_new_channel),
+ icon);
+ g_signal_connect (priv->call_filter, "new-channel",
+ G_CALLBACK (status_icon_call_filter_new_channel),
+ icon);
+ g_signal_connect_swapped (priv->idle, "notify",
+ G_CALLBACK (status_icon_idle_notify_cb),
+ icon);
+ g_signal_connect (priv->icon, "activate",
+ G_CALLBACK (status_icon_activate_cb),
+ icon);
+ g_signal_connect (priv->icon, "popup-menu",
+ G_CALLBACK (status_icon_popup_menu_cb),
+ icon);
+ g_signal_connect (priv->manager, "pendings-changed",
+ G_CALLBACK (status_icon_pendings_changed_cb),
+ icon);
+
+ pendings = empathy_contact_list_get_pendings (EMPATHY_CONTACT_LIST (priv->manager));
+ for (l = pendings; l; l = l->next) {
+ EmpathyPendingInfo *info;
+
+ info = l->data;
+ status_icon_pendings_changed_cb (priv->manager,
+ info->member,
+ info->actor,
+ 0,
+ info->message,
+ TRUE,
+ icon);
+ empathy_pending_info_free (info);
+ }
+ g_list_free (pendings);
+}
+
+static void
+status_icon_finalize (GObject *object)
+{
+ EmpathyStatusIconPriv *priv;
+
+ priv = GET_PRIV (object);
+
+ g_list_foreach (priv->events, (GFunc) status_icon_event_free, NULL);
+ g_list_free (priv->events);
+
+ if (priv->blink_timeout) {
+ g_source_remove (priv->blink_timeout);
+ }
+
+ g_object_unref (priv->icon);
+ g_object_unref (priv->window);
+ g_object_unref (priv->idle);
+ g_object_unref (priv->manager);
+ g_object_unref (priv->mc);
+ g_object_unref (priv->text_filter);
+ g_object_unref (priv->call_filter);
+}
+
+EmpathyStatusIcon *
+empathy_status_icon_new (GtkWindow *window)
+{
+ EmpathyStatusIconPriv *priv;
+ EmpathyStatusIcon *icon;
+ gboolean should_hide;
+
+ g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
+
+ icon = g_object_new (EMPATHY_TYPE_STATUS_ICON, NULL);
+ priv = GET_PRIV (icon);
+
+ priv->window = g_object_ref (window);
+
+ g_signal_connect (priv->window, "delete-event",
+ G_CALLBACK (status_icon_delete_event_cb),
+ icon);
+
+ empathy_conf_get_bool (empathy_conf_get (),
+ EMPATHY_PREFS_UI_MAIN_WINDOW_HIDDEN,
+ &should_hide);
+
+ if (gtk_window_is_active (priv->window) == should_hide) {
+ status_icon_set_visibility (icon, !should_hide, FALSE);
+ }
+
+ return icon;
+}
+
+static void
+status_icon_text_filter_new_channel (EmpathyFilter *filter,
+ TpConn *tp_conn,
+ TpChan *tp_chan,
+ EmpathyStatusIcon *icon)
+{
+ EmpathyStatusIconPriv *priv;
+ McAccount *account;
+ EmpathyTpChat *tp_chat;
+
+ priv = GET_PRIV (icon);
+
+ account = mission_control_get_account_for_connection (priv->mc, tp_conn, NULL);
+
+ empathy_debug (DEBUG_DOMAIN, "New text channel to be filtered for contact %s",
+ empathy_inspect_channel (account, tp_chan));
+
+ tp_chat = empathy_tp_chat_new (account, tp_chan);
+ g_object_set_data (G_OBJECT (tp_chat), "filter", filter);
+ g_object_unref (account);
+
+ g_signal_connect (tp_chat, "message-received",
+ G_CALLBACK (status_icon_message_received_cb),
+ icon);
+}
+
+static void
+status_icon_message_received_cb (EmpathyTpChat *tp_chat,
+ EmpathyMessage *message,
+ EmpathyStatusIcon *icon)
+{
+ EmpathyContact *sender;
+ gchar *msg;
+ StatusIconEvent *event;
+
+ empathy_debug (DEBUG_DOMAIN, "Message received, add event");
+
+ g_signal_handlers_disconnect_by_func (tp_chat,
+ status_icon_message_received_cb,
+ icon);
+
+ sender = empathy_message_get_sender (message);
+ msg = g_strdup_printf (_("New message from %s:\n%s"),
+ empathy_contact_get_name (sender),
+ empathy_message_get_body (message));
+
+ event = status_icon_event_new (icon, EMPATHY_IMAGE_NEW_MESSAGE, msg);
+ event->func = status_icon_event_msg_cb;
+ event->user_data = tp_chat;
+ g_free (msg);
+}
+
+static void
+status_icon_call_member_added_cb (EmpathyTpGroup *group,
+ EmpathyContact *member,
+ EmpathyContact *actor,
+ guint reason,
+ const gchar *message,
+ EmpathyStatusIcon *icon)
+{
+ EmpathyFilter *filter;
+
+ if (empathy_contact_is_user (member)) {
+ /* We are member, it's an outgoing call, we can dispatch
+ * the channel without asking the user */
+ empathy_debug (DEBUG_DOMAIN, "Process OUTGOING call channel");
+ filter = g_object_get_data (G_OBJECT (group), "filter");
+ empathy_filter_process (filter,
+ empathy_tp_group_get_channel (group),
+ TRUE);
+ g_object_unref (group);
+ }
+}
+
+static void
+status_icon_event_call_cb (StatusIconEvent *event)
+{
+ EmpathyFilter *filter;
+ EmpathyTpGroup *group;
+
+ empathy_debug (DEBUG_DOMAIN, "Dispatching call channel");
+
+ group = event->user_data;
+ filter = g_object_get_data (G_OBJECT (group), "filter");
+ empathy_filter_process (filter,
+ empathy_tp_group_get_channel (group),
+ TRUE);
+ g_object_unref (group);
+}
+
+static void
+status_icon_call_local_pending_cb (EmpathyTpGroup *group,
+ EmpathyContact *member,
+ EmpathyContact *actor,
+ guint reason,
+ const gchar *message,
+ EmpathyStatusIcon *icon)
+{
+ StatusIconEvent *event;
+
+ if (empathy_contact_is_user (member)) {
+ gchar *msg;
+
+ /* We are local pending, it's an incoming call, we need to ask
+ * the user if he wants to accept the call. */
+ empathy_debug (DEBUG_DOMAIN, "INCOMING call, add event");
+
+ msg = g_strdup_printf (_("Incoming call from %s:\n%s"),
+ empathy_contact_get_name (member),
+ message);
+
+ event = status_icon_event_new (icon, EMPATHY_IMAGE_VOIP, msg);
+ event->func = status_icon_event_call_cb;
+ event->user_data = group;
+ g_free (msg);
+ }
+}
+
+static void
+status_icon_call_filter_new_channel (EmpathyFilter *filter,
+ TpConn *tp_conn,
+ TpChan *tp_chan,
+ EmpathyStatusIcon *icon)
+{
+ EmpathyStatusIconPriv *priv;
+ McAccount *account;
+ EmpathyTpGroup *group;
+
+ priv = GET_PRIV (icon);
+
+ account = mission_control_get_account_for_connection (priv->mc, tp_conn, NULL);
+
+ empathy_debug (DEBUG_DOMAIN, "New media channel to be filtered");
+
+ /* FIXME: We have to check if the user is member or local-pending to
+ * know if it's an incoming or outgoing call because of the way we
+ * request media channels MC can't know if it's incoming or outgoing */
+ group = empathy_tp_group_new (account, tp_chan);
+ g_object_set_data (G_OBJECT (group), "filter", filter);
+ g_object_unref (account);
+
+ g_signal_connect (group, "member-added",
+ G_CALLBACK (status_icon_call_member_added_cb),
+ icon);
+ g_signal_connect (group, "local-pending",
+ G_CALLBACK (status_icon_call_local_pending_cb),
+ icon);
+}
+
+static void
+status_icon_idle_notify_cb (EmpathyStatusIcon *icon)
+{
+ EmpathyStatusIconPriv *priv;
+ McPresence flash_state;
+
+ priv = GET_PRIV (icon);
+
+ flash_state = empathy_idle_get_flash_state (priv->idle);
+ if (flash_state != MC_PRESENCE_UNSET) {
+ const gchar *icon_name;
+
+ icon_name = empathy_icon_name_for_presence (flash_state);
+ if (!priv->flash_state_event) {
+ /* We are now flashing */
+ priv->flash_state_event = status_icon_event_new (icon, icon_name, NULL);
+ priv->flash_state_event->user_data = icon;
+ priv->flash_state_event->func = status_icon_event_flash_state_cb;
+ } else {
+ /* We are still flashing but with another state */
+ g_free (priv->flash_state_event->icon_name);
+ priv->flash_state_event->icon_name = g_strdup (icon_name);
+ }
+ }
+ else if (priv->flash_state_event) {
+ /* We are no more flashing */
+ status_icon_event_remove (icon, priv->flash_state_event);
+ priv->flash_state_event = NULL;
+ }
+
+ if (!priv->showing_event_icon) {
+ status_icon_set_from_state (icon);
+ }
+
+ status_icon_update_tooltip (icon);
+}
+
+static void
+status_icon_update_tooltip (EmpathyStatusIcon *icon)
+{
+ EmpathyStatusIconPriv *priv;
+ const gchar *tooltip = NULL;
+
+ priv = GET_PRIV (icon);
+
+ if (priv->events) {
+ StatusIconEvent *event;
+
+ event = priv->events->data;
+ tooltip = event->message;
+ }
+
+ if (!tooltip) {
+ tooltip = empathy_idle_get_status (priv->idle);
+ }
+
+ gtk_status_icon_set_tooltip (priv->icon, tooltip);
+}
+
+static void
+status_icon_set_from_state (EmpathyStatusIcon *icon)
+{
+ EmpathyStatusIconPriv *priv;
+ McPresence state;
+ const gchar *icon_name;
+
+ priv = GET_PRIV (icon);
+
+ state = empathy_idle_get_state (priv->idle);
+ icon_name = empathy_icon_name_for_presence (state);
+ gtk_status_icon_set_from_icon_name (priv->icon, icon_name);
+}
+
+static void
+status_icon_set_visibility (EmpathyStatusIcon *icon,
+ gboolean visible,
+ gboolean store)
+{
+ EmpathyStatusIconPriv *priv;
+
+ priv = GET_PRIV (icon);
+
+ if (store) {
+ empathy_conf_set_bool (empathy_conf_get (),
+ EMPATHY_PREFS_UI_MAIN_WINDOW_HIDDEN, !visible);
+ }
+
+ if (!visible) {
+ empathy_window_iconify (priv->window, priv->icon);
+ } else {
+ GList *accounts;
+
+ empathy_window_present (GTK_WINDOW (priv->window), TRUE);
+
+ /* 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 {
+ empathy_debug (DEBUG_DOMAIN,
+ "No enabled account, Showing account dialog");
+ empathy_accounts_dialog_show (GTK_WINDOW (priv->window));
+ }
+ }
+}
+
+static void
+status_icon_toggle_visibility (EmpathyStatusIcon *icon)
+{
+ EmpathyStatusIconPriv *priv = GET_PRIV (icon);
+ gboolean visible;
+
+ visible = gtk_window_is_active (priv->window);
+ status_icon_set_visibility (icon, !visible, TRUE);
+}
+
+static void
+status_icon_activate_cb (GtkStatusIcon *status_icon,
+ EmpathyStatusIcon *icon)
+{
+ EmpathyStatusIconPriv *priv;
+
+ priv = GET_PRIV (icon);
+
+ empathy_debug (DEBUG_DOMAIN, "Activated: %s",
+ priv->events ? "event" : "toggle");
+
+ if (priv->events) {
+ status_icon_event_remove (icon, priv->events->data);
+ } else {
+ status_icon_toggle_visibility (icon);
+ }
+}
+
+static gboolean
+status_icon_delete_event_cb (GtkWidget *widget,
+ GdkEvent *event,
+ EmpathyStatusIcon *icon)
+{
+ status_icon_set_visibility (icon, FALSE, TRUE);
+
+ return TRUE;
+}
+
+static void
+status_icon_popup_menu_cb (GtkStatusIcon *status_icon,
+ guint button,
+ guint activate_time,
+ EmpathyStatusIcon *icon)
+{
+ EmpathyStatusIconPriv *priv;
+ GtkWidget *submenu;
+ gboolean show;
+
+ priv = GET_PRIV (icon);
+
+ 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,
+ icon);
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (priv->show_window_item),
+ show);
+ g_signal_handlers_unblock_by_func (priv->show_window_item,
+ status_icon_show_hide_window_cb,
+ icon);
+
+ submenu = empathy_presence_chooser_create_menu ();
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (priv->status_item),
+ submenu);
+
+ gtk_menu_popup (GTK_MENU (priv->popup_menu),
+ NULL, NULL,
+ gtk_status_icon_position_menu,
+ priv->icon,
+ button,
+ activate_time);
+}
+
+static void
+status_icon_create_menu (EmpathyStatusIcon *icon)
+{
+ EmpathyStatusIconPriv *priv;
+ GladeXML *glade;
+
+ priv = GET_PRIV (icon);
+
+ glade = empathy_glade_get_file ("empathy-status-icon.glade",
+ "tray_menu",
+ NULL,
+ "tray_menu", &priv->popup_menu,
+ "tray_show_list", &priv->show_window_item,
+ "tray_new_message", &priv->message_item,
+ "tray_status", &priv->status_item,
+ NULL);
+
+ empathy_glade_connect (glade,
+ icon,
+ "tray_show_list", "toggled", status_icon_show_hide_window_cb,
+ "tray_new_message", "activate", status_icon_new_message_cb,
+ "tray_quit", "activate", status_icon_quit_cb,
+ NULL);
+
+ g_object_unref (glade);
+}
+
+static void
+status_icon_new_message_cb (GtkWidget *widget,
+ EmpathyStatusIcon *icon)
+{
+ EmpathyStatusIconPriv *priv;
+
+ priv = GET_PRIV (icon);
+
+ empathy_new_message_dialog_show (NULL);
+}
+
+static void
+status_icon_quit_cb (GtkWidget *window,
+ EmpathyStatusIcon *icon)
+{
+ gtk_main_quit ();
+}
+
+static void
+status_icon_show_hide_window_cb (GtkWidget *widget,
+ EmpathyStatusIcon *icon)
+{
+ gboolean visible;
+
+ visible = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget));
+ status_icon_set_visibility (icon, visible, TRUE);
+}
+
+static void
+status_icon_pendings_changed_cb (EmpathyContactManager *manager,
+ EmpathyContact *contact,
+ EmpathyContact *actor,
+ guint reason,
+ gchar *message,
+ gboolean is_pending,
+ EmpathyStatusIcon *icon)
+{
+ EmpathyStatusIconPriv *priv;
+ StatusIconEvent *event;
+ GString *str;
+ GList *l;
+
+ priv = GET_PRIV (icon);
+
+ if (!is_pending) {
+ /* FIXME: We should remove the event */
+ return;
+ }
+
+ for (l = priv->events; l; l = l->next) {
+ if (empathy_contact_equal (contact, ((StatusIconEvent*)l->data)->user_data)) {
+ return;
+ }
+ }
+
+ str = g_string_new (NULL);
+ g_string_printf (str, _("Subscription requested by %s"),
+ empathy_contact_get_name (contact));
+ if (!G_STR_EMPTY (message)) {
+ g_string_append_printf (str, _("\nMessage: %s"), message);
+ }
+
+ event = status_icon_event_new (icon, GTK_STOCK_DIALOG_QUESTION, str->str);
+ event->user_data = g_object_ref (contact);
+ event->func = status_icon_event_subscribe_cb;
+
+ g_string_free (str, TRUE);
+}
+
+static void
+status_icon_event_subscribe_cb (StatusIconEvent *event)
+{
+ EmpathyContact *contact;
+
+ contact = EMPATHY_CONTACT (event->user_data);
+
+ empathy_subscription_dialog_show (contact, NULL);
+
+ g_object_unref (contact);
+}
+
+static void
+status_icon_event_flash_state_cb (StatusIconEvent *event)
+{
+ EmpathyStatusIconPriv *priv;
+
+ priv = GET_PRIV (event->user_data);
+
+ empathy_idle_set_flash_state (priv->idle, MC_PRESENCE_UNSET);
+}
+
+static void
+status_icon_event_msg_cb (StatusIconEvent *event)
+{
+ EmpathyFilter *filter;
+ EmpathyTpChat *tp_chat;
+
+ empathy_debug (DEBUG_DOMAIN, "Dispatching text channel");
+
+ tp_chat = event->user_data;
+ filter = g_object_get_data (G_OBJECT (tp_chat), "filter");
+ empathy_filter_process (filter,
+ empathy_tp_chat_get_channel (tp_chat),
+ TRUE);
+
+ g_object_unref (tp_chat);
+}
+
+static StatusIconEvent *
+status_icon_event_new (EmpathyStatusIcon *icon,
+ const gchar *icon_name,
+ const gchar *message)
+{
+ EmpathyStatusIconPriv *priv;
+ StatusIconEvent *event;
+
+ priv = GET_PRIV (icon);
+
+ event = g_slice_new0 (StatusIconEvent);
+ event->icon_name = g_strdup (icon_name);
+ event->message = g_strdup (message);
+
+ priv->events = g_list_append (priv->events, event);
+ if (!priv->blink_timeout) {
+ priv->showing_event_icon = FALSE;
+ priv->blink_timeout = g_timeout_add (BLINK_TIMEOUT,
+ (GSourceFunc) status_icon_event_timeout_cb,
+ icon);
+ status_icon_event_timeout_cb (icon);
+ status_icon_update_tooltip (icon);
+ }
+
+ return event;
+}
+
+static void
+status_icon_event_remove (EmpathyStatusIcon *icon,
+ StatusIconEvent *event)
+{
+ EmpathyStatusIconPriv *priv;
+
+ priv = GET_PRIV (icon);
+
+ if (event->func) {
+ event->func (event);
+ }
+ priv->events = g_list_remove (priv->events, event);
+ status_icon_event_free (event);
+ priv->showing_event_icon = FALSE;
+ status_icon_update_tooltip (icon);
+ status_icon_set_from_state (icon);
+
+ if (priv->events) {
+ return;
+ }
+
+ if (priv->blink_timeout) {
+ g_source_remove (priv->blink_timeout);
+ priv->blink_timeout = 0;
+ }
+}
+
+static gboolean
+status_icon_event_timeout_cb (EmpathyStatusIcon *icon)
+{
+ EmpathyStatusIconPriv *priv;
+
+ priv = GET_PRIV (icon);
+
+ priv->showing_event_icon = !priv->showing_event_icon;
+
+ if (!priv->showing_event_icon) {
+ status_icon_set_from_state (icon);
+ } else {
+ StatusIconEvent *event;
+
+ event = priv->events->data;
+ gtk_status_icon_set_from_icon_name (priv->icon, event->icon_name);
+ }
+
+ return TRUE;
+}
+
+static void
+status_icon_event_free (StatusIconEvent *event)
+{
+ g_free (event->icon_name);
+ g_free (event->message);
+ g_slice_free (StatusIconEvent, event);
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-status-icon.glade b/gnome-2-22/libempathy-gtk/empathy-status-icon.glade
new file mode 100644
index 000000000..ab0f09f84
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-status-icon.glade
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+ <widget class="GtkMenu" id="tray_menu">
+ <child>
+ <widget class="GtkCheckMenuItem" id="tray_show_list">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Show Contact List</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="avskiljare5">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkImageMenuItem" id="tray_new_message">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_New Conversation...</property>
+ <property name="use_underline">True</property>
+ <child internal-child="image">
+ <widget class="GtkImage" id="image599">
+ <property name="visible">True</property>
+ <property name="icon_size">1</property>
+ <property name="icon_name">im-message-new</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="tray_status">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Status</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="avskiljare6">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkImageMenuItem" id="tray_quit">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Quit</property>
+ <property name="use_underline">True</property>
+ <child internal-child="image">
+ <widget class="GtkImage" id="image600">
+ <property name="visible">True</property>
+ <property name="stock">gtk-quit</property>
+ <property name="icon_size">1</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
diff --git a/gnome-2-22/libempathy-gtk/empathy-status-icon.h b/gnome-2-22/libempathy-gtk/empathy-status-icon.h
new file mode 100644
index 000000000..a7ca3c395
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-status-icon.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_STATUS_ICON_H__
+#define __EMPATHY_STATUS_ICON_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define EMPATHY_TYPE_STATUS_ICON (empathy_status_icon_get_type ())
+#define EMPATHY_STATUS_ICON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_STATUS_ICON, EmpathyStatusIcon))
+#define EMPATHY_STATUS_ICON_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_STATUS_ICON, EmpathyStatusIconClass))
+#define EMPATHY_IS_STATUS_ICON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_STATUS_ICON))
+#define EMPATHY_IS_STATUS_ICON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_STATUS_ICON))
+#define EMPATHY_STATUS_ICON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_STATUS_ICON, EmpathyStatusIconClass))
+
+typedef struct _EmpathyStatusIcon EmpathyStatusIcon;
+typedef struct _EmpathyStatusIconClass EmpathyStatusIconClass;
+typedef struct _EmpathyStatusIconPriv EmpathyStatusIconPriv;
+
+struct _EmpathyStatusIcon {
+ GObject parent;
+};
+
+struct _EmpathyStatusIconClass {
+ GObjectClass parent_class;
+};
+
+GType empathy_status_icon_get_type (void) G_GNUC_CONST;
+EmpathyStatusIcon *empathy_status_icon_new (GtkWindow *window);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_STATUS_ICON_H__ */
diff --git a/gnome-2-22/libempathy-gtk/empathy-theme-boxes.c b/gnome-2-22/libempathy-gtk/empathy-theme-boxes.c
new file mode 100644
index 000000000..7285a9e9e
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-theme-boxes.c
@@ -0,0 +1,837 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 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 <string.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include <libempathy/empathy-debug.h>
+
+#include "empathy-ui-utils.h"
+#include "empathy-main-window.h"
+#include "empathy-theme-boxes.h"
+
+#define DEBUG_DOMAIN "FancyTheme"
+
+#define MARGIN 4
+#define HEADER_PADDING 2
+
+#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_THEME_BOXES, EmpathyThemeBoxesPriv))
+
+typedef struct _EmpathyThemeBoxesPriv EmpathyThemeBoxesPriv;
+
+struct _EmpathyThemeBoxesPriv {
+ gchar *header_foreground;
+ gchar *header_background;
+ gchar *header_line_background;
+ gchar *text_foreground;
+ gchar *text_background;
+ gchar *action_foreground;
+ gchar *highlight_foreground;
+ gchar *time_foreground;
+ gchar *event_foreground;
+ gchar *invite_foreground;
+ gchar *link_foreground;
+};
+
+static void theme_boxes_finalize (GObject *object);
+static void theme_boxes_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void theme_boxes_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void theme_boxes_define_theme_tags (EmpathyTheme *theme,
+ EmpathyChatView *view);
+static void theme_boxes_update_view (EmpathyTheme *theme,
+ EmpathyChatView *view);
+static void theme_boxes_append_message (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ EmpathyMessage *message);
+static void theme_boxes_append_event (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ const gchar *str);
+static void theme_boxes_append_timestamp (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ EmpathyMessage *message,
+ gboolean show_date,
+ gboolean show_time);
+static void theme_boxes_append_spacing (EmpathyTheme *theme,
+ EmpathyChatView *view);
+
+enum {
+ PROP_0,
+ PROP_HEADER_FOREGROUND,
+ PROP_HEADER_BACKGROUND,
+ PROP_HEADER_LINE_BACKGROUND,
+ PROP_TEXT_FOREGROUND,
+ PROP_TEXT_BACKGROUND,
+ PROP_ACTION_FOREGROUND,
+ PROP_HIGHLIGHT_FOREGROUND,
+ PROP_TIME_FOREGROUND,
+ PROP_EVENT_FOREGROUND,
+ PROP_INVITE_FOREGROUND,
+ PROP_LINK_FOREGROUND
+};
+
+enum {
+ PROP_FLOP,
+ PROP_MY_PROP
+};
+
+G_DEFINE_TYPE (EmpathyThemeBoxes, empathy_theme_boxes, EMPATHY_TYPE_THEME);
+
+static void
+empathy_theme_boxes_class_init (EmpathyThemeBoxesClass *class)
+{
+ GObjectClass *object_class;
+ EmpathyThemeClass *theme_class;
+
+ object_class = G_OBJECT_CLASS (class);
+ theme_class = EMPATHY_THEME_CLASS (class);
+
+ object_class->finalize = theme_boxes_finalize;
+ object_class->get_property = theme_boxes_get_property;
+ object_class->set_property = theme_boxes_set_property;
+
+ theme_class->update_view = theme_boxes_update_view;
+ theme_class->append_message = theme_boxes_append_message;
+ theme_class->append_event = theme_boxes_append_event;
+ theme_class->append_timestamp = theme_boxes_append_timestamp;
+ theme_class->append_spacing = theme_boxes_append_spacing;
+
+ g_object_class_install_property (object_class,
+ PROP_HEADER_FOREGROUND,
+ g_param_spec_string ("header-foreground",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_HEADER_BACKGROUND,
+ g_param_spec_string ("header-background",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_HEADER_LINE_BACKGROUND,
+ g_param_spec_string ("header-line-background",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+
+
+ g_object_class_install_property (object_class,
+ PROP_TEXT_FOREGROUND,
+ g_param_spec_string ("text-foreground",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_TEXT_BACKGROUND,
+ g_param_spec_string ("text-background",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_ACTION_FOREGROUND,
+ g_param_spec_string ("action-foreground",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_HIGHLIGHT_FOREGROUND,
+ g_param_spec_string ("highlight-foreground",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_TIME_FOREGROUND,
+ g_param_spec_string ("time-foreground",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_EVENT_FOREGROUND,
+ g_param_spec_string ("event-foreground",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_INVITE_FOREGROUND,
+ g_param_spec_string ("invite-foreground",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_LINK_FOREGROUND,
+ g_param_spec_string ("link-foreground",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_type_class_add_private (object_class, sizeof (EmpathyThemeBoxesPriv));
+}
+
+static void
+empathy_theme_boxes_init (EmpathyThemeBoxes *theme)
+{
+ EmpathyThemeBoxesPriv *priv;
+
+ priv = GET_PRIV (theme);
+}
+
+static void
+theme_boxes_finalize (GObject *object)
+{
+ EmpathyThemeBoxesPriv *priv;
+
+ priv = GET_PRIV (object);
+
+ g_free (priv->header_foreground);
+ g_free (priv->header_background);
+ g_free (priv->header_line_background);
+ g_free (priv->text_foreground);
+ g_free (priv->text_background);
+ g_free (priv->action_foreground);
+ g_free (priv->highlight_foreground);
+ g_free (priv->time_foreground);
+ g_free (priv->event_foreground);
+ g_free (priv->invite_foreground);
+ g_free (priv->link_foreground);
+
+ (G_OBJECT_CLASS (empathy_theme_boxes_parent_class)->finalize) (object);
+}
+
+static void
+theme_boxes_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EmpathyThemeBoxesPriv *priv;
+
+ priv = GET_PRIV (object);
+
+ switch (param_id) {
+ case PROP_HEADER_FOREGROUND:
+ g_value_set_string (value, priv->header_foreground);
+ break;
+ case PROP_HEADER_BACKGROUND:
+ g_value_set_string (value, priv->header_background);
+ break;
+ case PROP_HEADER_LINE_BACKGROUND:
+ g_value_set_string (value, priv->header_line_background);
+ break;
+ case PROP_TEXT_FOREGROUND:
+ g_value_set_string (value, priv->text_foreground);
+ break;
+ case PROP_TEXT_BACKGROUND:
+ g_value_set_string (value, priv->text_background);
+ break;
+ case PROP_ACTION_FOREGROUND:
+ g_value_set_string (value, priv->action_foreground);
+ break;
+ case PROP_HIGHLIGHT_FOREGROUND:
+ g_value_set_string (value, priv->highlight_foreground);
+ break;
+ case PROP_TIME_FOREGROUND:
+ g_value_set_string (value, priv->time_foreground);
+ break;
+ case PROP_EVENT_FOREGROUND:
+ g_value_set_string (value, priv->event_foreground);
+ break;
+ case PROP_INVITE_FOREGROUND:
+ g_value_set_string (value, priv->invite_foreground);
+ break;
+ case PROP_LINK_FOREGROUND:
+ g_value_set_string (value, priv->link_foreground);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+static void
+theme_boxes_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EmpathyThemeBoxesPriv *priv;
+
+ priv = GET_PRIV (object);
+
+ switch (param_id) {
+ case PROP_HEADER_FOREGROUND:
+ g_free (priv->header_foreground);
+ priv->header_foreground = g_value_dup_string (value);
+ g_object_notify (object, "header-foreground");
+ break;
+ case PROP_HEADER_BACKGROUND:
+ g_free (priv->header_background);
+ priv->header_background = g_value_dup_string (value);
+ g_object_notify (object, "header-background");
+ break;
+ case PROP_HEADER_LINE_BACKGROUND:
+ g_free (priv->header_line_background);
+ priv->header_line_background = g_value_dup_string (value);
+ g_object_notify (object, "header-line_background");
+ break;
+ case PROP_TEXT_FOREGROUND:
+ g_free (priv->text_foreground);
+ priv->text_foreground = g_value_dup_string (value);
+ g_object_notify (object, "text-foreground");
+ break;
+ case PROP_TEXT_BACKGROUND:
+ g_free (priv->text_background);
+ priv->text_background = g_value_dup_string (value);
+ g_object_notify (object, "text-background");
+ break;
+ case PROP_ACTION_FOREGROUND:
+ g_free (priv->action_foreground);
+ priv->action_foreground = g_value_dup_string (value);
+ g_object_notify (object, "action-foreground");
+ break;
+ case PROP_HIGHLIGHT_FOREGROUND:
+ g_free (priv->highlight_foreground);
+ priv->highlight_foreground = g_value_dup_string (value);
+ g_object_notify (object, "highlight-foreground");
+ break;
+ case PROP_TIME_FOREGROUND:
+ g_free (priv->time_foreground);
+ priv->time_foreground = g_value_dup_string (value);
+ g_object_notify (object, "time-foreground");
+ break;
+ case PROP_EVENT_FOREGROUND:
+ g_free (priv->event_foreground);
+ priv->event_foreground = g_value_dup_string (value);
+ g_object_notify (object, "event-foreground");
+ break;
+ case PROP_INVITE_FOREGROUND:
+ g_free (priv->invite_foreground);
+ priv->invite_foreground = g_value_dup_string (value);
+ g_object_notify (object, "invite-foreground");
+ break;
+ case PROP_LINK_FOREGROUND:
+ g_free (priv->link_foreground);
+ priv->link_foreground = g_value_dup_string (value);
+ g_object_notify (object, "link-foreground");
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+theme_boxes_define_theme_tags (EmpathyTheme *theme, EmpathyChatView *view)
+{
+ EmpathyThemeBoxesPriv *priv;
+ GtkTextBuffer *buffer;
+ GtkTextTag *tag;
+
+ priv = GET_PRIV (theme);
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ empathy_text_buffer_tag_set (buffer, "fancy-spacing",
+ "size", 3000,
+ "pixels-above-lines", 8,
+ NULL);
+
+ tag = empathy_text_buffer_tag_set (buffer, "fancy-header",
+ "weight", PANGO_WEIGHT_BOLD,
+ "pixels-above-lines", HEADER_PADDING,
+ "pixels-below-lines", HEADER_PADDING,
+ NULL);
+ if (priv->header_foreground) {
+ g_object_set (tag,
+ "foreground", priv->header_foreground,
+ "paragraph-background", priv->header_background,
+ NULL);
+ }
+
+ tag = empathy_text_buffer_tag_set (buffer, "fancy-header-line",
+ "size", 1,
+ NULL);
+ if (priv->header_line_background) {
+ g_object_set (tag,
+ "paragraph-background", priv->header_line_background,
+ NULL);
+ }
+
+ tag = empathy_text_buffer_tag_set (buffer, "fancy-body",
+ "pixels-above-lines", 4,
+ NULL);
+ if (priv->text_background) {
+ g_object_set (tag,
+ "paragraph-background", priv->text_background,
+ NULL);
+ }
+
+ if (priv->text_foreground) {
+ g_object_set (tag,
+ "foreground", priv->text_foreground,
+ NULL);
+ }
+
+ tag = empathy_text_buffer_tag_set (buffer, "fancy-action",
+ "style", PANGO_STYLE_ITALIC,
+ "pixels-above-lines", 4,
+ NULL);
+
+ if (priv->text_background) {
+ g_object_set (tag,
+ "paragraph-background", priv->text_background,
+ NULL);
+ }
+
+ if (priv->action_foreground) {
+ g_object_set (tag,
+ "foreground", priv->action_foreground,
+ NULL);
+ }
+
+ tag = empathy_text_buffer_tag_set (buffer, "fancy-highlight",
+ "weight", PANGO_WEIGHT_BOLD,
+ "pixels-above-lines", 4,
+ NULL);
+ if (priv->text_background) {
+ g_object_set (tag,
+ "paragraph-background", priv->text_background,
+ NULL);
+ }
+
+
+ if (priv->highlight_foreground) {
+ g_object_set (tag,
+ "foreground", priv->highlight_foreground,
+ NULL);
+ }
+
+ tag = empathy_text_buffer_tag_set (buffer, "fancy-time",
+ "justification", GTK_JUSTIFY_CENTER,
+ NULL);
+ if (priv->time_foreground) {
+ g_object_set (tag,
+ "foreground", priv->time_foreground,
+ NULL);
+ }
+
+ tag = empathy_text_buffer_tag_set (buffer, "fancy-event",
+ "justification", GTK_JUSTIFY_LEFT,
+ NULL);
+ if (priv->event_foreground) {
+ g_object_set (tag,
+ "foreground", priv->event_foreground,
+ NULL);
+ }
+
+ tag = empathy_text_buffer_tag_set (buffer, "invite", NULL);
+ if (priv->invite_foreground) {
+ g_object_set (tag,
+ "foreground", priv->invite_foreground,
+ NULL);
+ }
+
+ tag = empathy_text_buffer_tag_set (buffer, "fancy-link",
+ "underline", PANGO_UNDERLINE_SINGLE,
+ NULL);
+ if (priv->link_foreground) {
+ g_object_set (tag,
+ "foreground", priv->link_foreground,
+ NULL);
+ }
+}
+
+static void
+theme_boxes_update_view (EmpathyTheme *theme, EmpathyChatView *view)
+{
+ EmpathyThemeBoxesPriv *priv;
+
+ g_return_if_fail (EMPATHY_IS_THEME_BOXES (theme));
+ g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
+
+ priv = GET_PRIV (theme);
+
+ theme_boxes_define_theme_tags (theme, view);
+
+ empathy_chat_view_set_margin (view, MARGIN);
+}
+
+static void
+table_size_allocate_cb (GtkWidget *view,
+ GtkAllocation *allocation,
+ GtkWidget *box)
+{
+ gint width, height;
+
+ gtk_widget_get_size_request (box, NULL, &height);
+
+ width = allocation->width;
+
+ width -= \
+ gtk_text_view_get_right_margin (GTK_TEXT_VIEW (view)) - \
+ gtk_text_view_get_left_margin (GTK_TEXT_VIEW (view));
+ width -= 2 * MARGIN;
+ width -= 2 * HEADER_PADDING;
+
+ gtk_widget_set_size_request (box, width, height);
+}
+
+static void
+theme_boxes_maybe_append_header (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ EmpathyMessage *msg)
+{
+ EmpathyThemeBoxesPriv *priv;
+ EmpathyContact *contact;
+ GdkPixbuf *avatar = NULL;
+ GtkTextBuffer *buffer;
+ const gchar *name;
+ gboolean header;
+ GtkTextIter iter;
+ GtkWidget *label1, *label2;
+ GtkTextChildAnchor *anchor;
+ GtkWidget *box;
+ gchar *str;
+ time_t time;
+ gchar *tmp;
+ GtkTextIter start;
+ GdkColor color;
+ gboolean parse_success;
+ gboolean from_self;
+
+ priv = GET_PRIV (theme);
+
+ contact = empathy_message_get_sender (msg);
+ from_self = empathy_contact_is_user (contact);
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ empathy_debug (DEBUG_DOMAIN, "Maybe add fancy header");
+
+ name = empathy_contact_get_name (contact);
+
+ 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 (empathy_chat_view_get_last_block_type (view) != EMPATHY_CHAT_VIEW_BLOCK_SELF &&
+ empathy_chat_view_get_last_block_type (view) != EMPATHY_CHAT_VIEW_BLOCK_OTHER) {
+ header = TRUE;
+ }
+ else if (from_self &&
+ empathy_chat_view_get_last_block_type (view) == EMPATHY_CHAT_VIEW_BLOCK_OTHER) {
+ header = TRUE;
+ }
+ else if (!from_self &&
+ empathy_chat_view_get_last_block_type (view) == EMPATHY_CHAT_VIEW_BLOCK_SELF) {
+ header = TRUE;
+ }
+ else if (!from_self &&
+ (!empathy_chat_view_get_last_contact (view) ||
+ !empathy_contact_equal (contact, empathy_chat_view_get_last_contact (view)))) {
+ header = TRUE;
+ }
+
+ if (!header) {
+ return;
+ }
+
+ empathy_theme_append_spacing (theme, view);
+
+ gtk_text_buffer_get_end_iter (buffer, &iter);
+ gtk_text_buffer_insert_with_tags_by_name (buffer,
+ &iter,
+ "\n",
+ -1,
+ "fancy-header-line",
+ NULL);
+
+ gtk_text_buffer_get_end_iter (buffer, &iter);
+ anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
+
+ box = gtk_hbox_new (FALSE, 0);
+
+
+ if (empathy_theme_get_show_avatars (theme)) {
+ avatar = empathy_chat_view_get_avatar_pixbuf_with_cache (contact);
+ if (avatar) {
+ GtkWidget *image;
+
+ image = gtk_image_new_from_pixbuf (avatar);
+
+ gtk_box_pack_start (GTK_BOX (box), image,
+ FALSE, TRUE, 2);
+ }
+ }
+
+ g_signal_connect_object (view, "size-allocate",
+ G_CALLBACK (table_size_allocate_cb),
+ box, 0);
+
+ str = g_strdup_printf ("<b>%s</b>", name);
+
+ label1 = g_object_new (GTK_TYPE_LABEL,
+ "label", str,
+ "use-markup", TRUE,
+ "xalign", 0.0,
+ NULL);
+
+ parse_success = priv->header_foreground &&
+ gdk_color_parse (priv->header_foreground, &color);
+
+ if (parse_success) {
+ gtk_widget_modify_fg (label1, GTK_STATE_NORMAL, &color);
+ }
+
+ g_free (str);
+
+ time = empathy_message_get_timestamp (msg);
+
+ tmp = empathy_time_to_string_local (time,
+ EMPATHY_TIME_FORMAT_DISPLAY_SHORT);
+ str = g_strdup_printf ("<i>%s</i>", tmp);
+ g_free (tmp);
+
+ label2 = g_object_new (GTK_TYPE_LABEL,
+ "label", str,
+ "use-markup", TRUE,
+ "xalign", 1.0,
+ NULL);
+
+ if (parse_success) {
+ gtk_widget_modify_fg (label2, GTK_STATE_NORMAL, &color);
+ }
+
+ g_free (str);
+
+ gtk_misc_set_alignment (GTK_MISC (label1), 0.0, 0.5);
+ gtk_misc_set_alignment (GTK_MISC (label2), 1.0, 0.5);
+
+ gtk_box_pack_start (GTK_BOX (box), label1, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (box), label2, TRUE, TRUE, 0);
+
+ gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view),
+ box,
+ anchor);
+
+ gtk_widget_show_all (box);
+
+ gtk_text_buffer_get_end_iter (buffer, &iter);
+ start = iter;
+ gtk_text_iter_backward_char (&start);
+ gtk_text_buffer_apply_tag_by_name (buffer,
+ "fancy-header",
+ &start, &iter);
+
+ gtk_text_buffer_insert_with_tags_by_name (buffer,
+ &iter,
+ "\n",
+ -1,
+ "fancy-header",
+ NULL);
+
+ gtk_text_buffer_get_end_iter (buffer, &iter);
+ gtk_text_buffer_insert_with_tags_by_name (buffer,
+ &iter,
+ "\n",
+ -1,
+ "fancy-header-line",
+ NULL);
+}
+
+static void
+theme_boxes_append_message (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ EmpathyMessage *message)
+{
+ EmpathyContact *sender;
+
+ empathy_theme_maybe_append_date_and_time (theme, view, message);
+ theme_boxes_maybe_append_header (theme, view, message);
+
+ sender = empathy_message_get_sender (message);
+
+ if (empathy_message_get_type (message) == EMPATHY_MESSAGE_TYPE_ACTION) {
+ gchar *body;
+
+ body = g_strdup_printf (" * %s %s",
+ empathy_contact_get_name (sender),
+ empathy_message_get_body (message));
+ empathy_theme_append_text (theme, view, body,
+ "fancy-action", "fancy-link");
+ } else {
+ empathy_theme_append_text (theme, view,
+ empathy_message_get_body (message),
+ "fancy-body", "fancy-link");
+ }
+
+ if (empathy_contact_is_user (sender)) {
+ empathy_chat_view_set_last_block_type (view, EMPATHY_CHAT_VIEW_BLOCK_SELF);
+ empathy_chat_view_set_last_contact (view, NULL);
+ } else {
+ empathy_chat_view_set_last_block_type (view, EMPATHY_CHAT_VIEW_BLOCK_OTHER);
+ empathy_chat_view_set_last_contact (view, sender);
+ }
+}
+
+static void
+theme_boxes_append_event (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ const gchar *str)
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter iter;
+ gchar *msg;
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ empathy_theme_maybe_append_date_and_time (theme, view, NULL);
+
+ gtk_text_buffer_get_end_iter (buffer, &iter);
+
+ msg = g_strdup_printf (" - %s\n", str);
+
+ gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
+ msg, -1,
+ "fancy-event",
+ NULL);
+ g_free (msg);
+
+ empathy_chat_view_set_last_block_type (view, EMPATHY_CHAT_VIEW_BLOCK_EVENT);
+}
+
+static void
+theme_boxes_append_timestamp (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ EmpathyMessage *message,
+ gboolean show_date,
+ gboolean show_time)
+{
+ GtkTextBuffer *buffer;
+ time_t timestamp;
+ GDate *date;
+ GtkTextIter iter;
+ GString *str;
+
+ if (!show_date) {
+ return;
+ }
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ date = empathy_message_get_date_and_time (message, &timestamp);
+
+ str = g_string_new (NULL);
+
+ if (show_time || show_date) {
+ empathy_theme_append_spacing (theme, view);
+
+ g_string_append (str, "- ");
+ }
+
+ if (show_date) {
+ gchar buf[256];
+
+ g_date_strftime (buf, 256, _("%A %d %B %Y"), date);
+ g_string_append (str, buf);
+
+ if (show_time) {
+ g_string_append (str, ", ");
+ }
+ }
+
+ g_date_free (date);
+
+ if (show_time) {
+ gchar *tmp;
+
+ tmp = empathy_time_to_string_local (timestamp, EMPATHY_TIME_FORMAT_DISPLAY_SHORT);
+ g_string_append (str, tmp);
+ g_free (tmp);
+ }
+
+ if (show_time || show_date) {
+ g_string_append (str, " -\n");
+
+ gtk_text_buffer_get_end_iter (buffer, &iter);
+ gtk_text_buffer_insert_with_tags_by_name (buffer,
+ &iter,
+ str->str, -1,
+ "fancy-time",
+ NULL);
+
+ empathy_chat_view_set_last_block_type (view, EMPATHY_CHAT_VIEW_BLOCK_TIME);
+ empathy_chat_view_set_last_timestamp (view, timestamp);
+ }
+
+ g_string_free (str, TRUE);
+
+}
+
+static void
+theme_boxes_append_spacing (EmpathyTheme *theme,
+ EmpathyChatView *view)
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter iter;
+
+ g_return_if_fail (EMPATHY_IS_THEME (theme));
+ g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ gtk_text_buffer_get_end_iter (buffer, &iter);
+ gtk_text_buffer_insert_with_tags_by_name (buffer,
+ &iter,
+ "\n",
+ -1,
+ "cut",
+ "fancy-spacing",
+ NULL);
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-theme-boxes.h b/gnome-2-22/libempathy-gtk/empathy-theme-boxes.h
new file mode 100644
index 000000000..b1f0033f3
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-theme-boxes.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef __EMPATHY_THEME_BOXES_H__
+#define __EMPATHY_THEME_BOXES_H__
+
+#include <glib-object.h>
+
+#include "empathy-theme.h"
+
+G_BEGIN_DECLS
+
+#define EMPATHY_TYPE_THEME_BOXES (empathy_theme_boxes_get_type ())
+#define EMPATHY_THEME_BOXES(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_THEME_BOXES, EmpathyThemeBoxes))
+#define EMPATHY_THEME_BOXES_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_THEME_BOXES, EmpathyThemeBoxesClass))
+#define EMPATHY_IS_THEME_BOXES(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_THEME_BOXES))
+#define EMPATHY_IS_THEME_BOXES_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_THEME_BOXES))
+#define EMPATHY_THEME_BOXES_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_THEME_BOXES, EmpathyThemeBoxesClass))
+
+typedef struct _EmpathyThemeBoxes EmpathyThemeBoxes;
+typedef struct _EmpathyThemeBoxesClass EmpathyThemeBoxesClass;
+
+struct _EmpathyThemeBoxes {
+ EmpathyTheme parent;
+};
+
+struct _EmpathyThemeBoxesClass {
+ EmpathyThemeClass parent_class;
+};
+
+GType empathy_theme_boxes_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __EMPATHY_THEME_BOXES_H__ */
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-theme-irc.c b/gnome-2-22/libempathy-gtk/empathy-theme-irc.c
new file mode 100644
index 000000000..7cd9588bb
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-theme-irc.c
@@ -0,0 +1,352 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 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 <glib/gi18n.h>
+#include <libempathy/empathy-debug.h>
+
+#include "empathy-chat.h"
+#include "empathy-ui-utils.h"
+#include "empathy-theme-irc.h"
+
+#define DEBUG_DOMAIN "Theme"
+
+#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_THEME_IRC, EmpathyThemeIrcPriv))
+
+typedef struct _EmpathyThemeIrcPriv EmpathyThemeIrcPriv;
+
+struct _EmpathyThemeIrcPriv {
+ gint my_prop;
+};
+
+static void theme_irc_finalize (GObject *object);
+static void theme_irc_update_view (EmpathyTheme *theme,
+ EmpathyChatView *view);
+static void theme_irc_append_message (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ EmpathyMessage *message);
+static void theme_irc_append_event (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ const gchar *str);
+static void theme_irc_append_timestamp (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ EmpathyMessage *message,
+ gboolean show_date,
+ gboolean show_time);
+static void theme_irc_append_spacing (EmpathyTheme *theme,
+ EmpathyChatView *view);
+
+
+enum {
+ PROP_0,
+ PROP_MY_PROP
+};
+
+G_DEFINE_TYPE (EmpathyThemeIrc, empathy_theme_irc, EMPATHY_TYPE_THEME);
+
+static void
+empathy_theme_irc_class_init (EmpathyThemeIrcClass *class)
+{
+ GObjectClass *object_class;
+ EmpathyThemeClass *theme_class;
+
+ object_class = G_OBJECT_CLASS (class);
+ theme_class = EMPATHY_THEME_CLASS (class);
+
+ object_class->finalize = theme_irc_finalize;
+
+ theme_class->update_view = theme_irc_update_view;
+ theme_class->append_message = theme_irc_append_message;
+ theme_class->append_event = theme_irc_append_event;
+ theme_class->append_timestamp = theme_irc_append_timestamp;
+ theme_class->append_spacing = theme_irc_append_spacing;
+
+ g_type_class_add_private (object_class, sizeof (EmpathyThemeIrcPriv));
+}
+
+static void
+empathy_theme_irc_init (EmpathyThemeIrc *presence)
+{
+ EmpathyThemeIrcPriv *priv;
+
+ priv = GET_PRIV (presence);
+}
+
+static void
+theme_irc_finalize (GObject *object)
+{
+ EmpathyThemeIrcPriv *priv;
+
+ priv = GET_PRIV (object);
+
+ (G_OBJECT_CLASS (empathy_theme_irc_parent_class)->finalize) (object);
+}
+
+static void
+theme_irc_apply_theme_classic (EmpathyTheme *theme, EmpathyChatView *view)
+{
+ EmpathyThemeIrcPriv *priv;
+ GtkTextBuffer *buffer;
+
+ priv = GET_PRIV (theme);
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ empathy_text_buffer_tag_set (buffer, "irc-spacing",
+ "size", 2000,
+ NULL);
+
+ empathy_text_buffer_tag_set (buffer, "irc-nick-self",
+ "foreground", "sea green",
+ NULL);
+
+ empathy_text_buffer_tag_set (buffer, "irc-body-self",
+ /* To get the default theme color: */
+ "foreground-set", FALSE,
+ NULL);
+
+ empathy_text_buffer_tag_set (buffer, "irc-action-self",
+ "foreground", "brown4",
+ "style", PANGO_STYLE_ITALIC,
+ NULL);
+
+ empathy_text_buffer_tag_set (buffer, "irc-nick-highlight",
+ "foreground", "indian red",
+ "weight", PANGO_WEIGHT_BOLD,
+ NULL);
+
+ empathy_text_buffer_tag_set (buffer, "irc-nick-other",
+ "foreground", "skyblue4",
+ NULL);
+
+ empathy_text_buffer_tag_set (buffer, "irc-body-other",
+ /* To get the default theme color: */
+ "foreground-set", FALSE,
+ NULL);
+
+ empathy_text_buffer_tag_set (buffer, "irc-action-other",
+ "foreground", "brown4",
+ "style", PANGO_STYLE_ITALIC,
+ NULL);
+
+ empathy_text_buffer_tag_set (buffer, "irc-time",
+ "foreground", "darkgrey",
+ "justification", GTK_JUSTIFY_CENTER,
+ NULL);
+
+ empathy_text_buffer_tag_set (buffer, "irc-event",
+ "foreground", "PeachPuff4",
+ "justification", GTK_JUSTIFY_LEFT,
+ NULL);
+
+ empathy_text_buffer_tag_set (buffer, "invite",
+ "foreground", "sienna",
+ NULL);
+
+ empathy_text_buffer_tag_set (buffer, "irc-link",
+ "foreground", "steelblue",
+ "underline", PANGO_UNDERLINE_SINGLE,
+ NULL);
+}
+
+
+static void
+theme_irc_update_view (EmpathyTheme *theme, EmpathyChatView *view)
+{
+ theme_irc_apply_theme_classic (theme, view);
+ empathy_chat_view_set_margin (view, 3);
+}
+
+static void
+theme_irc_append_message (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ EmpathyMessage *message)
+{
+ GtkTextBuffer *buffer;
+ const gchar *name;
+ const gchar *nick_tag;
+ const gchar *body_tag;
+ GtkTextIter iter;
+ gchar *tmp;
+ EmpathyContact *contact;
+
+ empathy_theme_maybe_append_date_and_time (theme, view, message);
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ contact = empathy_message_get_sender (message);
+ name = empathy_contact_get_name (contact);
+
+ if (empathy_message_get_type (message) == EMPATHY_MESSAGE_TYPE_ACTION) {
+ if (empathy_contact_is_user (contact)) {
+ body_tag = "irc-action-self";
+ } else {
+ body_tag = "irc-action-other";
+ }
+
+ tmp = g_strdup_printf (" * %s %s",
+ empathy_contact_get_name (contact),
+ empathy_message_get_body (message));
+ empathy_theme_append_text (theme, view, tmp,
+ body_tag, "irc-link");
+ g_free (tmp);
+ return;
+ }
+
+ if (empathy_contact_is_user (contact)) {
+ nick_tag = "irc-nick-self";
+ body_tag = "irc-body-self";
+ } else {
+ if (empathy_chat_should_highlight_nick (message)) {
+ nick_tag = "irc-nick-highlight";
+ } else {
+ nick_tag = "irc-nick-other";
+ }
+
+ body_tag = "irc-body-other";
+ }
+
+ gtk_text_buffer_get_end_iter (buffer, &iter);
+
+ /* The nickname. */
+ tmp = g_strdup_printf ("%s: ", name);
+ gtk_text_buffer_insert_with_tags_by_name (buffer,
+ &iter,
+ tmp,
+ -1,
+ "cut",
+ nick_tag,
+ NULL);
+ g_free (tmp);
+
+ /* The text body. */
+ empathy_theme_append_text (theme, view,
+ empathy_message_get_body (message),
+ body_tag, "irc-link");
+}
+
+static void
+theme_irc_append_event (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ const gchar *str)
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter iter;
+ gchar *msg;
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ empathy_theme_maybe_append_date_and_time (theme, view, NULL);
+
+ gtk_text_buffer_get_end_iter (buffer, &iter);
+
+ msg = g_strdup_printf (" - %s\n", str);
+ gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
+ msg, -1,
+ "irc-event",
+ NULL);
+ g_free (msg);
+}
+
+static void
+theme_irc_append_timestamp (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ EmpathyMessage *message,
+ gboolean show_date,
+ gboolean show_time)
+{
+ GtkTextBuffer *buffer;
+ time_t timestamp;
+ GDate *date;
+ GtkTextIter iter;
+ GString *str;
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ date = empathy_message_get_date_and_time (message, &timestamp);
+
+ str = g_string_new (NULL);
+
+ if (show_time || show_date) {
+ empathy_theme_append_spacing (theme, view);
+
+ g_string_append (str, "- ");
+ }
+
+ if (show_date) {
+ gchar buf[256];
+
+ g_date_strftime (buf, 256, _("%A %d %B %Y"), date);
+ g_string_append (str, buf);
+
+ if (show_time) {
+ g_string_append (str, ", ");
+ }
+ }
+
+ g_date_free (date);
+
+ if (show_time) {
+ gchar *tmp;
+
+ tmp = empathy_time_to_string_local (timestamp, EMPATHY_TIME_FORMAT_DISPLAY_SHORT);
+ g_string_append (str, tmp);
+ g_free (tmp);
+ }
+
+ if (show_time || show_date) {
+ g_string_append (str, " -\n");
+
+ gtk_text_buffer_get_end_iter (buffer, &iter);
+ gtk_text_buffer_insert_with_tags_by_name (buffer,
+ &iter,
+ str->str, -1,
+ "irc-time",
+ NULL);
+
+ empathy_chat_view_set_last_timestamp (view, timestamp);
+ }
+
+ g_string_free (str, TRUE);
+}
+
+static void
+theme_irc_append_spacing (EmpathyTheme *theme,
+ EmpathyChatView *view)
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter iter;
+
+ g_return_if_fail (EMPATHY_IS_THEME (theme));
+ g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ gtk_text_buffer_get_end_iter (buffer, &iter);
+ gtk_text_buffer_insert_with_tags_by_name (buffer,
+ &iter,
+ "\n",
+ -1,
+ "cut",
+ "irc-spacing",
+ NULL);
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-theme-irc.h b/gnome-2-22/libempathy-gtk/empathy-theme-irc.h
new file mode 100644
index 000000000..dc52a56c5
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-theme-irc.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef __EMPATHY_THEME_IRC_H__
+#define __EMPATHY_THEME_IRC_H__
+
+#include <glib-object.h>
+
+#include "empathy-theme.h"
+
+G_BEGIN_DECLS
+
+#define EMPATHY_TYPE_THEME_IRC (empathy_theme_irc_get_type ())
+#define EMPATHY_THEME_IRC(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_THEME_IRC, EmpathyThemeIrc))
+#define EMPATHY_THEME_IRC_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_THEME_IRC, EmpathyThemeIrcClass))
+#define EMPATHY_IS_THEME_IRC(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_THEME_IRC))
+#define EMPATHY_IS_THEME_IRC_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_THEME_IRC))
+#define EMPATHY_THEME_IRC_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_THEME_IRC, EmpathyThemeIrcClass))
+
+typedef struct _EmpathyThemeIrc EmpathyThemeIrc;
+typedef struct _EmpathyThemeIrcClass EmpathyThemeIrcClass;
+
+struct _EmpathyThemeIrc {
+ EmpathyTheme parent;
+};
+
+struct _EmpathyThemeIrcClass {
+ EmpathyThemeClass parent_class;
+};
+
+GType empathy_theme_irc_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __EMPATHY_THEME_IRC_H__ */
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-theme-manager.c b/gnome-2-22/libempathy-gtk/empathy-theme-manager.c
new file mode 100644
index 000000000..94276c964
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-theme-manager.c
@@ -0,0 +1,449 @@
+/* -*- 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.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include <libempathy/empathy-utils.h>
+
+#include "empathy-chat-view.h"
+#include "empathy-conf.h"
+#include "empathy-preferences.h"
+#include "empathy-theme.h"
+#include "empathy-theme-boxes.h"
+#include "empathy-theme-irc.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;
+
+ EmpathyTheme *clean_theme;
+ EmpathyTheme *simple_theme;
+ EmpathyTheme *blue_theme;
+ EmpathyTheme *classic_theme;
+
+ GtkSettings *settings;
+} 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_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
+theme_manager_gdk_color_to_hex (GdkColor *gdk_color, gchar *str_color)
+{
+ g_snprintf (str_color, 10,
+ "#%02x%02x%02x",
+ gdk_color->red >> 8,
+ gdk_color->green >> 8,
+ gdk_color->blue >> 8);
+}
+
+ static void
+theme_manager_color_hash_notify_cb (EmpathyThemeManager *manager)
+{
+ EmpathyThemeManagerPriv *priv;
+ GtkStyle *style;
+ gchar color[10];
+
+ priv = GET_PRIV (manager);
+
+ style = gtk_widget_get_default_style ();
+
+ g_object_freeze_notify (G_OBJECT (priv->simple_theme));
+
+ theme_manager_gdk_color_to_hex (&style->base[GTK_STATE_SELECTED], color);
+ g_object_set (priv->simple_theme,
+ "action-foreground", color,
+ "link-foreground", color,
+ NULL);
+
+ theme_manager_gdk_color_to_hex (&style->bg[GTK_STATE_SELECTED], color);
+ g_object_set (priv->simple_theme,
+ "header-background", color,
+ NULL);
+
+ theme_manager_gdk_color_to_hex (&style->dark[GTK_STATE_SELECTED], color);
+ g_object_set (priv->simple_theme,
+ "header-line-background", color,
+ NULL);
+
+ theme_manager_gdk_color_to_hex (&style->fg[GTK_STATE_SELECTED], color);
+ g_object_set (priv->simple_theme,
+ "header-foreground", color,
+ NULL);
+
+ g_object_thaw_notify (G_OBJECT (priv->simple_theme));
+
+#if 0
+
+FIXME: Make that work, it should update color when theme changes but it
+ doesnt seems to work with all themes.
+
+ g_object_get (priv->settings,
+ "color-hash", &color_hash,
+ NULL);
+
+ /*
+ * base_color: #ffffffffffff
+ * fg_color: #000000000000
+ * bg_color: #e6e6e7e7e8e8
+ * text_color: #000000000000
+ * selected_bg_color: #58589a9adbdb
+ * selected_fg_color: #ffffffffffff
+ */
+
+ color = g_hash_table_lookup (color_hash, "base_color");
+ if (color) {
+ theme_manager_gdk_color_to_hex (color, color_str);
+ g_object_set (priv->simple_theme,
+ "action-foreground", color_str,
+ "link-foreground", color_str,
+ NULL);
+ }
+
+ color = g_hash_table_lookup (color_hash, "selected_bg_color");
+ if (color) {
+ theme_manager_gdk_color_to_hex (color, color_str);
+ g_object_set (priv->simple_theme,
+ "header-background", color_str,
+ NULL);
+ }
+
+ color = g_hash_table_lookup (color_hash, "bg_color");
+ if (color) {
+ GdkColor tmp;
+
+ tmp = *color;
+ tmp.red /= 2;
+ tmp.green /= 2;
+ tmp.blue /= 2;
+ theme_manager_gdk_color_to_hex (&tmp, color_str);
+ g_object_set (priv->simple_theme,
+ "header-line-background", color_str,
+ NULL);
+ }
+
+ color = g_hash_table_lookup (color_hash, "selected_fg_color");
+ if (color) {
+ theme_manager_gdk_color_to_hex (color, color_str);
+ g_object_set (priv->simple_theme,
+ "header-foreground", color_str,
+ NULL);
+ }
+
+ g_hash_table_unref (color_hash);
+
+#endif
+}
+
+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);
+
+ priv->settings = gtk_settings_get_default ();
+ g_signal_connect_swapped (priv->settings, "notify::color-hash",
+ G_CALLBACK (theme_manager_color_hash_notify_cb),
+ manager);
+
+ priv->simple_theme = g_object_new (EMPATHY_TYPE_THEME_BOXES, NULL);
+ theme_manager_color_hash_notify_cb (manager);
+
+ priv->clean_theme = g_object_new (EMPATHY_TYPE_THEME_BOXES,
+ "header-foreground", "black",
+ "header-background", "#efefdf",
+ "header_line_background", "#e3e3d3",
+ "action_foreground", "brown4",
+ "time_foreground", "darkgrey",
+ "event_foreground", "darkgrey",
+ "invite_foreground", "sienna",
+ "link_foreground","#49789e",
+ NULL);
+
+ priv->blue_theme = g_object_new (EMPATHY_TYPE_THEME_BOXES,
+ "header_foreground", "black",
+ "header_background", "#88a2b4",
+ "header_line_background", "#7f96a4",
+ "text_foreground", "black",
+ "text_background", "#adbdc8",
+ "highlight_foreground", "black",
+ "action_foreground", "brown4",
+ "time_foreground", "darkgrey",
+ "event_foreground", "#7f96a4",
+ "invite_foreground", "sienna",
+ "link_foreground", "#49789e",
+ NULL);
+
+ priv->classic_theme = g_object_new (EMPATHY_TYPE_THEME_IRC, NULL);
+}
+
+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_unref (priv->clean_theme);
+ g_object_unref (priv->simple_theme);
+ g_object_unref (priv->blue_theme);
+ g_object_unref (priv->classic_theme);
+
+ 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 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 void
+theme_manager_apply_theme (EmpathyThemeManager *manager,
+ EmpathyChatView *view,
+ const gchar *name)
+{
+ EmpathyThemeManagerPriv *priv;
+ EmpathyTheme *theme;
+
+ priv = GET_PRIV (manager);
+
+ /* Make sure all tags are present. Note: not useful now but when we have
+ * user defined theme it will be.
+ */
+ if (theme_manager_ensure_theme_exists (name)) {
+ if (strcmp (name, "clean") == 0) {
+ theme = priv->clean_theme;
+ }
+ else if (strcmp (name, "simple") == 0) {
+ theme = priv->simple_theme;
+ }
+ else if (strcmp (name, "blue") == 0) {
+ theme = priv->blue_theme;
+ } else {
+ theme = priv->classic_theme;
+ }
+ } else {
+ theme = priv->classic_theme;
+ }
+
+ empathy_chat_view_set_theme (view, theme);
+}
+
+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);
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-theme-manager.h b/gnome-2-22/libempathy-gtk/empathy-theme-manager.h
new file mode 100644
index 000000000..6bd2d41f5
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-theme-manager.h
@@ -0,0 +1,57 @@
+/* -*- 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.
+ */
+
+#ifndef __EMPATHY_THEME_MANAGER_H__
+#define __EMPATHY_THEME_MANAGER_H__
+
+#include <glib-object.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);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_THEME_MANAGER_H__ */
diff --git a/gnome-2-22/libempathy-gtk/empathy-theme.c b/gnome-2-22/libempathy-gtk/empathy-theme.c
new file mode 100644
index 000000000..dae690b5c
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-theme.c
@@ -0,0 +1,417 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 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 <string.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include <libempathy/empathy-debug.h>
+#include <libempathy/empathy-utils.h>
+
+#include "empathy-chat.h"
+#include "empathy-conf.h"
+#include "empathy-preferences.h"
+#include "empathy-theme.h"
+#include "empathy-smiley-manager.h"
+
+#define DEBUG_DOMAIN "Theme"
+
+/* Number of seconds between timestamps when using normal mode, 5 minutes. */
+#define TIMESTAMP_INTERVAL 300
+
+#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_THEME, EmpathyThemePriv))
+
+typedef struct _EmpathyThemePriv EmpathyThemePriv;
+
+struct _EmpathyThemePriv {
+ EmpathySmileyManager *smiley_manager;
+ gboolean show_avatars;
+};
+
+static void theme_finalize (GObject *object);
+static void theme_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void theme_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+
+G_DEFINE_TYPE (EmpathyTheme, empathy_theme, G_TYPE_OBJECT);
+
+enum {
+ PROP_0,
+ PROP_SHOW_AVATARS
+};
+
+static void
+empathy_theme_class_init (EmpathyThemeClass *class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = theme_finalize;
+ object_class->get_property = theme_get_property;
+ object_class->set_property = theme_set_property;
+
+ class->update_view = NULL;
+ class->append_message = NULL;
+ class->append_event = NULL;
+ class->append_timestamp = NULL;
+ class->append_spacing = NULL;
+
+ g_object_class_install_property (object_class,
+ PROP_SHOW_AVATARS,
+ g_param_spec_boolean ("show-avatars",
+ "", "",
+ TRUE,
+ G_PARAM_READWRITE));
+
+ g_type_class_add_private (object_class, sizeof (EmpathyThemePriv));
+}
+
+static void
+empathy_theme_init (EmpathyTheme *presence)
+{
+ EmpathyThemePriv *priv;
+
+ priv = GET_PRIV (presence);
+
+ priv->smiley_manager = empathy_smiley_manager_new ();
+}
+
+static void
+theme_finalize (GObject *object)
+{
+ EmpathyThemePriv *priv;
+
+ priv = GET_PRIV (object);
+
+ if (priv->smiley_manager) {
+ g_object_unref (priv->smiley_manager);
+ }
+
+ (G_OBJECT_CLASS (empathy_theme_parent_class)->finalize) (object);
+}
+
+static void
+theme_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EmpathyThemePriv *priv;
+
+ priv = GET_PRIV (object);
+
+ switch (param_id) {
+ case PROP_SHOW_AVATARS:
+ g_value_set_boolean (value, priv->show_avatars);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+theme_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EmpathyThemePriv *priv;
+
+ priv = GET_PRIV (object);
+
+ switch (param_id) {
+ case PROP_SHOW_AVATARS:
+ empathy_theme_set_show_avatars (EMPATHY_THEME (object),
+ g_value_get_boolean (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+void
+empathy_theme_maybe_append_date_and_time (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ EmpathyMessage *message)
+{
+ time_t timestamp;
+ GDate *date, *last_date;
+ gboolean append_date, append_time;
+
+ date = empathy_message_get_date_and_time (message, &timestamp);
+
+ last_date = g_date_new ();
+ g_date_set_time (last_date, empathy_chat_view_get_last_timestamp (view));
+
+ append_date = FALSE;
+ append_time = FALSE;
+
+ if (g_date_compare (date, last_date) > 0) {
+ append_date = TRUE;
+ append_time = TRUE;
+ }
+
+ g_date_free (last_date);
+ g_date_free (date);
+
+ if (empathy_chat_view_get_last_timestamp (view) + TIMESTAMP_INTERVAL < timestamp) {
+ append_time = TRUE;
+ }
+
+ if (append_time || append_date) {
+ empathy_theme_append_timestamp (theme, view, message,
+ append_date, append_time);
+ }
+}
+
+void
+empathy_theme_update_view (EmpathyTheme *theme,
+ EmpathyChatView *view)
+{
+ if (!EMPATHY_THEME_GET_CLASS(theme)->update_view) {
+ g_error ("Theme must override update_view");
+ }
+
+ return EMPATHY_THEME_GET_CLASS(theme)->update_view (theme, view);
+}
+
+void
+empathy_theme_append_message (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ EmpathyMessage *message)
+{
+ if (!EMPATHY_THEME_GET_CLASS(theme)->append_message) {
+ g_warning ("Theme should override append_message");
+ return;
+ }
+
+ EMPATHY_THEME_GET_CLASS(theme)->append_message (theme, view, message);
+}
+
+static void
+theme_insert_text_with_emoticons (GtkTextBuffer *buf,
+ GtkTextIter *iter,
+ const gchar *str,
+ EmpathySmileyManager *smiley_manager)
+{
+ gboolean use_smileys = FALSE;
+ GSList *smileys, *l;
+
+ 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;
+ }
+
+ smileys = empathy_smiley_manager_parse (smiley_manager, str);
+ for (l = smileys; l; l = l->next) {
+ EmpathySmiley *smiley;
+
+ smiley = l->data;
+ if (smiley->pixbuf) {
+ gtk_text_buffer_insert_pixbuf (buf, iter, smiley->pixbuf);
+ } else {
+ gtk_text_buffer_insert (buf, iter, smiley->str, -1);
+ }
+ empathy_smiley_free (smiley);
+ }
+ g_slist_free (smileys);
+}
+
+void
+empathy_theme_append_text (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ const gchar *body,
+ const gchar *tag,
+ const gchar *link_tag)
+{
+ EmpathyThemePriv *priv;
+ GtkTextBuffer *buffer;
+ GtkTextIter start_iter, end_iter;
+ GtkTextMark *mark;
+ GtkTextIter iter;
+ gint num_matches, i;
+ GArray *start, *end;
+
+ priv = GET_PRIV (theme);
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ gtk_text_buffer_get_end_iter (buffer, &start_iter);
+ mark = gtk_text_buffer_create_mark (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 (buffer, &iter);
+ theme_insert_text_with_emoticons (buffer, &iter, body, priv->smiley_manager);
+ } 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 (buffer, &iter);
+ theme_insert_text_with_emoticons (buffer,
+ &iter,
+ tmp,
+ priv->smiley_manager);
+ g_free (tmp);
+ }
+
+ tmp = empathy_substring (body, s, e);
+
+ gtk_text_buffer_get_end_iter (buffer, &iter);
+ if (!link_tag) {
+ gtk_text_buffer_insert (buffer, &iter,
+ tmp, -1);
+ } {
+ gtk_text_buffer_insert_with_tags_by_name (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 (buffer, &iter);
+ theme_insert_text_with_emoticons (buffer,
+ &iter,
+ tmp,
+ priv->smiley_manager);
+ g_free (tmp);
+ }
+ }
+
+ g_array_free (start, TRUE);
+ g_array_free (end, TRUE);
+
+ gtk_text_buffer_get_end_iter (buffer, &iter);
+ gtk_text_buffer_insert (buffer, &iter, "\n", 1);
+
+ /* Apply the style to the inserted text. */
+ gtk_text_buffer_get_iter_at_mark (buffer, &start_iter, mark);
+ gtk_text_buffer_get_end_iter (buffer, &end_iter);
+
+ gtk_text_buffer_apply_tag_by_name (buffer,
+ tag,
+ &start_iter,
+ &end_iter);
+
+ gtk_text_buffer_delete_mark (buffer, mark);
+}
+
+void
+empathy_theme_append_event (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ const gchar *str)
+{
+ if (!EMPATHY_THEME_GET_CLASS(theme)->append_event) {
+ return;
+ }
+
+ EMPATHY_THEME_GET_CLASS(theme)->append_event (theme, view, str);
+}
+
+void
+empathy_theme_append_spacing (EmpathyTheme *theme,
+ EmpathyChatView *view)
+{
+ if (!EMPATHY_THEME_GET_CLASS(theme)->append_spacing) {
+ return;
+ }
+
+ EMPATHY_THEME_GET_CLASS(theme)->append_spacing (theme, view);
+}
+
+
+void
+empathy_theme_append_timestamp (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ EmpathyMessage *message,
+ gboolean show_date,
+ gboolean show_time)
+{
+ if (!EMPATHY_THEME_GET_CLASS(theme)->append_timestamp) {
+ return;
+ }
+
+ EMPATHY_THEME_GET_CLASS(theme)->append_timestamp (theme, view,
+ message, show_date,
+ show_time);
+}
+
+gboolean
+empathy_theme_get_show_avatars (EmpathyTheme *theme)
+{
+ EmpathyThemePriv *priv;
+
+ g_return_val_if_fail (EMPATHY_IS_THEME (theme), FALSE);
+
+ priv = GET_PRIV (theme);
+
+ return priv->show_avatars;
+}
+
+void
+empathy_theme_set_show_avatars (EmpathyTheme *theme, gboolean show)
+{
+ EmpathyThemePriv *priv;
+
+ g_return_if_fail (EMPATHY_IS_THEME (theme));
+
+ priv = GET_PRIV (theme);
+
+ priv->show_avatars = show;
+
+ g_object_notify (G_OBJECT (theme), "show-avatars");
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-theme.h b/gnome-2-22/libempathy-gtk/empathy-theme.h
new file mode 100644
index 000000000..34875bcb4
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-theme.h
@@ -0,0 +1,97 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef __EMPATHY_THEME_H__
+#define __EMPATHY_THEME_H__
+
+#include <glib-object.h>
+#include <gtk/gtktextbuffer.h>
+
+G_BEGIN_DECLS
+
+#define EMPATHY_TYPE_THEME (empathy_theme_get_type ())
+#define EMPATHY_THEME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_THEME, EmpathyTheme))
+#define EMPATHY_THEME_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_THEME, EmpathyThemeClass))
+#define EMPATHY_IS_THEME(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_THEME))
+#define EMPATHY_IS_THEME_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_THEME))
+#define EMPATHY_THEME_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_THEME, EmpathyThemeClass))
+
+typedef struct _EmpathyTheme EmpathyTheme;
+typedef struct _EmpathyThemeClass EmpathyThemeClass;
+
+#include "empathy-chat-view.h"
+
+struct _EmpathyTheme {
+ GObject parent;
+};
+
+struct _EmpathyThemeClass {
+ GObjectClass parent_class;
+
+ /* <vtable> */
+ void (*update_view) (EmpathyTheme *theme,
+ EmpathyChatView *view);
+ void (*append_message) (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ EmpathyMessage *message);
+ void (*append_event) (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ const gchar *str);
+ void (*append_timestamp) (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ EmpathyMessage *message,
+ gboolean show_date,
+ gboolean show_time);
+ void (*append_spacing) (EmpathyTheme *theme,
+ EmpathyChatView *view);
+};
+
+GType empathy_theme_get_type (void) G_GNUC_CONST;
+void empathy_theme_update_view (EmpathyTheme *theme,
+ EmpathyChatView *view);
+void empathy_theme_append_message (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ EmpathyMessage *msg);
+void empathy_theme_append_text (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ const gchar *body,
+ const gchar *tag,
+ const gchar *link_tag);
+void empathy_theme_append_spacing (EmpathyTheme *theme,
+ EmpathyChatView *view);
+void empathy_theme_append_event (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ const gchar *str);
+void empathy_theme_append_timestamp (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ EmpathyMessage *message,
+ gboolean show_date,
+ gboolean show_time);
+void empathy_theme_maybe_append_date_and_time (EmpathyTheme *theme,
+ EmpathyChatView *view,
+ EmpathyMessage *message);
+gboolean empathy_theme_get_show_avatars (EmpathyTheme *theme);
+void empathy_theme_set_show_avatars (EmpathyTheme *theme,
+ gboolean show);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_THEME_H__ */
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-ui-utils.c b/gnome-2-22/libempathy-gtk/empathy-ui-utils.c
new file mode 100644
index 000000000..80dcd4227
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-ui-utils.c
@@ -0,0 +1,1418 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002-2007 Imendio AB
+ * Copyright (C) 2007-2008 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 <micke@imendio.com>
+ * Richard Hult <richard@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ *
+ * Part of this file is copied from GtkSourceView (gtksourceiter.c):
+ * Paolo Maggi
+ * Jeroen Zwartepoorte
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <X11/Xatom.h>
+#include <gdk/gdkx.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <libgnomevfs/gnome-vfs-utils.h>
+
+#include <libmissioncontrol/mc-profile.h>
+
+#include <libempathy/empathy-debug.h>
+
+#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)
+{
+ GladeXML *gui;
+ gchar *path;
+ const char *name;
+ GtkWidget **widget_ptr;
+
+ path = g_build_filename (g_getenv ("EMPATHY_SRCDIR"), "libempathy-gtk",
+ filename, NULL);
+ if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
+ g_free (path);
+ path = g_build_filename (DATADIR, "empathy", filename, NULL);
+ }
+ empathy_debug (DEBUG_DOMAIN, "Loading glade file %s", path);
+
+ gui = glade_xml_new (path, root, domain);
+ g_free (path);
+
+ if (!gui) {
+ g_warning ("Couldn't find necessary glade file '%s'", filename);
+ }
+
+ 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) {
+ 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);
+}
+
+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 (McPresence presence)
+{
+ switch (presence) {
+ 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:
+ return EMPATHY_IMAGE_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_contact (EmpathyContact *contact)
+{
+ McPresence presence;
+
+ g_return_val_if_fail (EMPATHY_IS_CONTACT (contact),
+ EMPATHY_IMAGE_OFFLINE);
+
+ presence = empathy_contact_get_presence (contact);
+ return empathy_icon_name_for_presence (presence);
+}
+
+GdkPixbuf *
+empathy_pixbuf_from_data (gchar *data,
+ gsize data_size)
+{
+ GdkPixbufLoader *loader;
+ GdkPixbuf *pixbuf = NULL;
+ GError *error = NULL;
+
+ if (!data) {
+ return NULL;
+ }
+
+ loader = gdk_pixbuf_loader_new ();
+ if (!gdk_pixbuf_loader_write (loader, data, data_size, &error)) {
+ empathy_debug (DEBUG_DOMAIN, "Failed to write to pixbuf loader: %s",
+ error ? error->message : "No error given");
+ g_clear_error (&error);
+ g_object_unref (loader);
+ return NULL;
+ }
+ if (!gdk_pixbuf_loader_close (loader, &error)) {
+ empathy_debug (DEBUG_DOMAIN, "Failed to close pixbuf loader: %s",
+ error ? error->message : "No error given");
+ g_clear_error (&error);
+ g_object_unref (loader);
+ return NULL;
+ }
+
+ pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+ if (pixbuf) {
+ 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);
+}
+
+static void
+empathy_avatar_pixbuf_roundify (GdkPixbuf *pixbuf)
+{
+ gint width, height, rowstride;
+ guchar *pixels;
+
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+ if (width < 6 || height < 6) {
+ return;
+ }
+
+ /* Top left */
+ pixels[3] = 0;
+ pixels[7] = 0x80;
+ pixels[11] = 0xC0;
+ pixels[rowstride + 3] = 0x80;
+ pixels[rowstride * 2 + 3] = 0xC0;
+
+ /* Top right */
+ pixels[width * 4 - 1] = 0;
+ pixels[width * 4 - 5] = 0x80;
+ pixels[width * 4 - 9] = 0xC0;
+ pixels[rowstride + (width * 4) - 1] = 0x80;
+ pixels[(2 * rowstride) + (width * 4) - 1] = 0xC0;
+
+ /* Bottom left */
+ pixels[(height - 1) * rowstride + 3] = 0;
+ pixels[(height - 1) * rowstride + 7] = 0x80;
+ pixels[(height - 1) * rowstride + 11] = 0xC0;
+ pixels[(height - 2) * rowstride + 3] = 0x80;
+ pixels[(height - 3) * rowstride + 3] = 0xC0;
+
+ /* Bottom right */
+ pixels[height * rowstride - 1] = 0;
+ pixels[(height - 1) * rowstride - 1] = 0x80;
+ pixels[(height - 2) * rowstride - 1] = 0xC0;
+ pixels[height * rowstride - 5] = 0x80;
+ pixels[height * rowstride - 9] = 0xC0;
+}
+
+static gboolean
+empathy_gdk_pixbuf_is_opaque (GdkPixbuf *pixbuf)
+{
+ gint width, height, rowstride, i;
+ guchar *pixels;
+ guchar *row;
+
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+ row = pixels;
+ for (i = 3; i < rowstride; i+=4) {
+ if (row[i] < 0xfe) {
+ return FALSE;
+ }
+ }
+
+ for (i = 1; i < height - 1; i++) {
+ row = pixels + (i*rowstride);
+ if (row[3] < 0xfe || row[rowstride-1] < 0xfe) {
+ return FALSE;
+ }
+ }
+
+ row = pixels + ((height-1) * rowstride);
+ for (i = 3; i < rowstride; i+=4) {
+ if (row[i] < 0xfe) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+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);
+ if (!gdk_pixbuf_get_has_alpha (pixbuf)) {
+ GdkPixbuf *rounded_pixbuf;
+
+ rounded_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
+ gdk_pixbuf_get_width (pixbuf),
+ gdk_pixbuf_get_height (pixbuf));
+ gdk_pixbuf_copy_area (pixbuf, 0, 0,
+ gdk_pixbuf_get_width (pixbuf),
+ gdk_pixbuf_get_height (pixbuf),
+ rounded_pixbuf,
+ 0, 0);
+ pixbuf = rounded_pixbuf;
+ } else {
+ g_object_ref (pixbuf);
+ }
+
+ if (empathy_gdk_pixbuf_is_opaque (pixbuf)) {
+ empathy_avatar_pixbuf_roundify (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);
+}
+
+GdkPixbuf *
+empathy_pixbuf_scale_down_if_necessary (GdkPixbuf *pixbuf, gint max_size)
+{
+ gint width, height;
+ gdouble factor;
+
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+
+ if (width > max_size || height > max_size) {
+ factor = (gdouble) max_size / MAX (width, height);
+
+ width = width * factor;
+ height = height * factor;
+
+ return gdk_pixbuf_scale_simple (pixbuf,
+ width, height,
+ GDK_INTERP_HYPER);
+ }
+
+ return g_object_ref (pixbuf);
+}
+
+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;
+
+ if (!icon_name) {
+ return NULL;
+ }
+
+ 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;
+}
+
+/* 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;
+}
+
+gboolean
+empathy_window_get_is_visible (GtkWindow *window)
+{
+ GdkWindowState state;
+ GdkWindow *gdk_window;
+
+ g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
+
+ gdk_window = GTK_WIDGET (window)->window;
+ if (!gdk_window) {
+ return FALSE;
+ }
+
+ state = gdk_window_get_state (gdk_window);
+ if (state & (GDK_WINDOW_STATE_WITHDRAWN | GDK_WINDOW_STATE_ICONIFIED)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void
+empathy_window_iconify (GtkWindow *window, GtkStatusIcon *status_icon)
+{
+ GdkRectangle icon_location;
+ gulong data[4];
+ Display *dpy;
+ GdkWindow *gdk_window;
+
+ gtk_status_icon_get_geometry (status_icon, NULL, &icon_location, NULL);
+ gdk_window = GTK_WIDGET (window)->window;
+ dpy = gdk_x11_drawable_get_xdisplay (gdk_window);
+
+ data[0] = icon_location.x;
+ data[1] = icon_location.y;
+ data[2] = icon_location.width;
+ data[3] = icon_location.height;
+
+ XChangeProperty (dpy,
+ GDK_WINDOW_XID (gdk_window),
+ gdk_x11_get_xatom_by_name_for_display (gdk_drawable_get_display (gdk_window),
+ "_NET_WM_ICON_GEOMETRY"),
+ XA_CARDINAL, 32, PropModeReplace,
+ (guchar *)&data, 4);
+
+ gtk_window_set_skip_taskbar_hint (window, TRUE);
+ gtk_window_iconify (window);
+}
+
+/* Takes care of moving the window to the current workspace. */
+void
+empathy_window_present (GtkWindow *window,
+ gboolean steal_focus)
+{
+ guint32 timestamp;
+
+ g_return_if_fail (GTK_IS_WINDOW (window));
+
+ /* There are three cases: hidden, visible, visible on another
+ * workspace.
+ */
+
+ if (!empathy_window_get_is_visible (window)) {
+ /* Hide it so present brings it to the current workspace. */
+ gtk_widget_hide (GTK_WIDGET (window));
+ }
+
+ timestamp = gtk_get_current_event_time ();
+ gtk_window_set_skip_taskbar_hint (window, FALSE);
+ gtk_window_present_with_time (window, timestamp);
+ /* FIXME: This shouldn't be required as gtk_window_present's doc says
+ * it deiconify automatically. */
+ gtk_window_deiconify (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) &&
+ GTK_WIDGET_TOPLEVEL (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);
+}
+
+GtkTextTag *
+empathy_text_buffer_tag_set (GtkTextBuffer *buffer,
+ const gchar *tag_name,
+ const gchar *first_property_name,
+ ...)
+{
+ GtkTextTagTable *table;
+ GtkTextTag *tag;
+
+ g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
+ g_return_val_if_fail (tag_name != NULL, NULL);
+
+ table = gtk_text_buffer_get_tag_table (buffer);
+ tag = gtk_text_tag_table_lookup (table, tag_name);
+
+ if (!tag) {
+ tag = gtk_text_tag_new (tag_name);
+ gtk_text_tag_table_add (table, tag);
+ g_object_unref (tag);
+ } else {
+ /* 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);
+ }
+
+ if (first_property_name) {
+ va_list list;
+
+ va_start (list, first_property_name);
+ g_object_set_valist (G_OBJECT (tag), first_property_name, list);
+ va_end (list);
+ }
+
+ return tag;
+}
+
diff --git a/gnome-2-22/libempathy-gtk/empathy-ui-utils.h b/gnome-2-22/libempathy-gtk/empathy-ui-utils.h
new file mode 100644
index 000000000..1fb29a97d
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/empathy-ui-utils.h
@@ -0,0 +1,116 @@
+/* -*- 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 <micke@imendio.com>
+ * Richard Hult <richard@imendio.com>
+ * Martyn Russell <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ *
+ * 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 <gtk/gtk.h>
+#include <glade/glade.h>
+
+#include <libmissioncontrol/mc-account.h>
+#include <libmissioncontrol/mc-profile.h>
+
+#include <libempathy/empathy-contact.h>
+#include <libempathy/empathy-avatar.h>
+
+#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 */
+const gchar * empathy_icon_name_from_account (McAccount *account);
+const gchar * empathy_icon_name_for_presence (McPresence presence);
+const gchar * empathy_icon_name_for_contact (EmpathyContact *contact);
+GdkPixbuf * empathy_pixbuf_from_data (gchar *data,
+ gsize data_size);
+GdkPixbuf * empathy_pixbuf_from_avatar_scaled (EmpathyAvatar *avatar,
+ gint width,
+ gint height);
+GdkPixbuf * empathy_pixbuf_avatar_from_contact_scaled (EmpathyContact *contact,
+ gint width,
+ gint height);
+GdkPixbuf * empathy_pixbuf_scale_down_if_necessary (GdkPixbuf *pixbuf,
+ gint max_size);
+GdkPixbuf * empathy_pixbuf_from_icon_name (const gchar *icon_name,
+ GtkIconSize icon_size);
+/* 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);
+void empathy_window_iconify (GtkWindow *window,
+ GtkStatusIcon *status_icon);
+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);
+GtkTextTag *empathy_text_buffer_tag_set (GtkTextBuffer *buffer,
+ const gchar *tag_name,
+ const gchar *first_property_name,
+ ...);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_UI_UTILS_H__ */
diff --git a/gnome-2-22/libempathy-gtk/ephy-spinner.c b/gnome-2-22/libempathy-gtk/ephy-spinner.c
new file mode 100644
index 000000000..a8f371df3
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/ephy-spinner.c
@@ -0,0 +1,977 @@
+/*
+ * Copyright © 2000 Eazel, Inc.
+ * Copyright © 2002-2004 Marco Pesenti Gritti
+ * Copyright © 2004, 2006 Christian Persch
+ *
+ * Nautilus 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.
+ *
+ * Nautilus 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: Andy Hertzfeld <andy@eazel.com>
+ *
+ * Ephy port by Marco Pesenti Gritti <marco@it.gnome.org>
+ *
+ * $Id: ephy-spinner.c 2114 2006-12-25 12:15:00Z mr $
+ */
+
+#include "config.h"
+
+#include "ephy-spinner.h"
+
+/* #include "ephy-debug.h" */
+#define LOG(msg, args...)
+#define START_PROFILER(name)
+#define STOP_PROFILER(name)
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gtk/gtkicontheme.h>
+#include <gtk/gtkiconfactory.h>
+#include <gtk/gtksettings.h>
+
+/* Spinner cache implementation */
+
+#define EPHY_TYPE_SPINNER_CACHE (ephy_spinner_cache_get_type())
+#define EPHY_SPINNER_CACHE(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_SPINNER_CACHE, EphySpinnerCache))
+#define EPHY_SPINNER_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_SPINNER_CACHE, EphySpinnerCacheClass))
+#define EPHY_IS_SPINNER_CACHE(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_SPINNER_CACHE))
+#define EPHY_IS_SPINNER_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_SPINNER_CACHE))
+#define EPHY_SPINNER_CACHE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_SPINNER_CACHE, EphySpinnerCacheClass))
+
+typedef struct _EphySpinnerCache EphySpinnerCache;
+typedef struct _EphySpinnerCacheClass EphySpinnerCacheClass;
+typedef struct _EphySpinnerCachePrivate EphySpinnerCachePrivate;
+
+struct _EphySpinnerCacheClass
+{
+ GObjectClass parent_class;
+};
+
+struct _EphySpinnerCache
+{
+ GObject parent_object;
+
+ /*< private >*/
+ EphySpinnerCachePrivate *priv;
+};
+
+#define EPHY_SPINNER_CACHE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_SPINNER_CACHE, EphySpinnerCachePrivate))
+
+struct _EphySpinnerCachePrivate
+{
+ /* Hash table of GdkScreen -> EphySpinnerCacheData */
+ GHashTable *hash;
+};
+
+typedef struct
+{
+ guint ref_count;
+ GtkIconSize size;
+ int width;
+ int height;
+ GdkPixbuf **animation_pixbufs;
+ guint n_animation_pixbufs;
+} EphySpinnerImages;
+
+#define LAST_ICON_SIZE GTK_ICON_SIZE_DIALOG + 1
+#define SPINNER_ICON_NAME "process-working"
+#define SPINNER_FALLBACK_ICON_NAME "gnome-spinner"
+#define EPHY_SPINNER_IMAGES_INVALID ((EphySpinnerImages *) 0x1)
+
+typedef struct
+{
+ GdkScreen *screen;
+ GtkIconTheme *icon_theme;
+ EphySpinnerImages *images[LAST_ICON_SIZE];
+} EphySpinnerCacheData;
+
+static void ephy_spinner_cache_class_init (EphySpinnerCacheClass *klass);
+static void ephy_spinner_cache_init (EphySpinnerCache *cache);
+
+static GObjectClass *ephy_spinner_cache_parent_class;
+
+static GType
+ephy_spinner_cache_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0))
+ {
+ const GTypeInfo our_info =
+ {
+ sizeof (EphySpinnerCacheClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) ephy_spinner_cache_class_init,
+ NULL,
+ NULL,
+ sizeof (EphySpinnerCache),
+ 0,
+ (GInstanceInitFunc) ephy_spinner_cache_init
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "EphySpinnerCache",
+ &our_info, 0);
+ }
+
+ return type;
+}
+
+static EphySpinnerImages *
+ephy_spinner_images_ref (EphySpinnerImages *images)
+{
+ g_return_val_if_fail (images != NULL, NULL);
+
+ images->ref_count++;
+
+ return images;
+}
+
+static void
+ephy_spinner_images_unref (EphySpinnerImages *images)
+{
+ g_return_if_fail (images != NULL);
+
+ images->ref_count--;
+ if (images->ref_count == 0)
+ {
+ guint i;
+
+ LOG ("Freeing spinner images %p for size %d", images, images->size);
+
+ for (i = 0; i < images->n_animation_pixbufs; ++i)
+ {
+ g_object_unref (images->animation_pixbufs[i]);
+ }
+ g_free (images->animation_pixbufs);
+
+ g_free (images);
+ }
+}
+
+static void
+ephy_spinner_cache_data_unload (EphySpinnerCacheData *data)
+{
+ GtkIconSize size;
+ EphySpinnerImages *images;
+
+ g_return_if_fail (data != NULL);
+
+ LOG ("EphySpinnerDataCache unload for screen %p", data->screen);
+
+ for (size = GTK_ICON_SIZE_INVALID; size < LAST_ICON_SIZE; ++size)
+ {
+ images = data->images[size];
+ data->images[size] = NULL;
+
+ if (images != NULL && images != EPHY_SPINNER_IMAGES_INVALID)
+ {
+ ephy_spinner_images_unref (images);
+ }
+ }
+}
+
+static GdkPixbuf *
+extract_frame (GdkPixbuf *grid_pixbuf,
+ int x,
+ int y,
+ int size)
+{
+ GdkPixbuf *pixbuf;
+
+ if (x + size > gdk_pixbuf_get_width (grid_pixbuf) ||
+ y + size > gdk_pixbuf_get_height (grid_pixbuf))
+ {
+ return NULL;
+ }
+
+ pixbuf = gdk_pixbuf_new_subpixbuf (grid_pixbuf,
+ x, y,
+ size, size);
+ g_return_val_if_fail (pixbuf != NULL, NULL);
+
+ return pixbuf;
+}
+
+static GdkPixbuf *
+scale_to_size (GdkPixbuf *pixbuf,
+ int dw,
+ int dh)
+{
+ GdkPixbuf *result;
+ int pw, ph;
+
+ g_return_val_if_fail (pixbuf != NULL, NULL);
+
+ pw = gdk_pixbuf_get_width (pixbuf);
+ ph = gdk_pixbuf_get_height (pixbuf);
+
+ if (pw != dw || ph != dh)
+ {
+ result = gdk_pixbuf_scale_simple (pixbuf, dw, dh,
+ GDK_INTERP_BILINEAR);
+ g_object_unref (pixbuf);
+ return result;
+ }
+
+ return pixbuf;
+}
+
+static EphySpinnerImages *
+ephy_spinner_images_load (GdkScreen *screen,
+ GtkIconTheme *icon_theme,
+ GtkIconSize icon_size)
+{
+ EphySpinnerImages *images;
+ GdkPixbuf *icon_pixbuf, *pixbuf;
+ GtkIconInfo *icon_info = NULL;
+ int grid_width, grid_height, x, y, requested_size, size, isw, ish, n;
+ const char *icon;
+ GSList *list = NULL, *l;
+
+ LOG ("EphySpinnerCacheData loading for screen %p at size %d", screen, icon_size);
+
+ START_PROFILER ("loading spinner animation")
+
+ if (!gtk_icon_size_lookup_for_settings (gtk_settings_get_for_screen (screen),
+ icon_size, &isw, &ish)) goto loser;
+
+ requested_size = MAX (ish, isw);
+
+ /* Load the animation. The 'rest icon' is the 0th frame */
+ icon_info = gtk_icon_theme_lookup_icon (icon_theme,
+ SPINNER_ICON_NAME,
+ requested_size, 0);
+ if (icon_info == NULL)
+ {
+ g_warning ("Throbber animation not found");
+
+ /* If the icon naming spec compliant name wasn't found, try the old name */
+ icon_info = gtk_icon_theme_lookup_icon (icon_theme,
+ SPINNER_FALLBACK_ICON_NAME,
+ requested_size, 0);
+ if (icon_info == NULL)
+ {
+ g_warning ("Throbber fallback animation not found either");
+ goto loser;
+ }
+ }
+ g_assert (icon_info != NULL);
+
+ size = gtk_icon_info_get_base_size (icon_info);
+ icon = gtk_icon_info_get_filename (icon_info);
+ if (icon == NULL) goto loser;
+
+ icon_pixbuf = gdk_pixbuf_new_from_file (icon, NULL);
+ gtk_icon_info_free (icon_info);
+ icon_info = NULL;
+
+ if (icon_pixbuf == NULL)
+ {
+ g_warning ("Could not load the spinner file");
+ goto loser;
+ }
+
+ grid_width = gdk_pixbuf_get_width (icon_pixbuf);
+ grid_height = gdk_pixbuf_get_height (icon_pixbuf);
+
+ n = 0;
+ for (y = 0; y < grid_height; y += size)
+ {
+ for (x = 0; x < grid_width ; x += size)
+ {
+ pixbuf = extract_frame (icon_pixbuf, x, y, size);
+
+ if (pixbuf)
+ {
+ list = g_slist_prepend (list, pixbuf);
+ ++n;
+ }
+ else
+ {
+ g_warning ("Cannot extract frame (%d, %d) from the grid\n", x, y);
+ }
+ }
+ }
+
+ g_object_unref (icon_pixbuf);
+
+ if (list == NULL) goto loser;
+ g_assert (n > 0);
+
+ if (size > requested_size)
+ {
+ for (l = list; l != NULL; l = l->next)
+ {
+ l->data = scale_to_size (l->data, isw, ish);
+ }
+ }
+
+ /* Now we've successfully got all the data */
+ images = g_new (EphySpinnerImages, 1);
+ images->ref_count = 1;
+
+ images->size = icon_size;
+ images->width = images->height = requested_size;
+
+ images->n_animation_pixbufs = n;
+ images->animation_pixbufs = g_new (GdkPixbuf *, n);
+
+ for (l = list; l != NULL; l = l->next)
+ {
+ g_assert (l->data != NULL);
+ images->animation_pixbufs[--n] = l->data;
+ }
+ g_assert (n == 0);
+
+ g_slist_free (list);
+
+ STOP_PROFILER ("loading spinner animation")
+
+ return images;
+
+loser:
+ if (icon_info)
+ {
+ gtk_icon_info_free (icon_info);
+ }
+ g_slist_foreach (list, (GFunc) g_object_unref, NULL);
+
+ STOP_PROFILER ("loading spinner animation")
+
+ return NULL;
+}
+
+static EphySpinnerCacheData *
+ephy_spinner_cache_data_new (GdkScreen *screen)
+{
+ EphySpinnerCacheData *data;
+
+ data = g_new0 (EphySpinnerCacheData, 1);
+
+ data->screen = screen;
+ data->icon_theme = gtk_icon_theme_get_for_screen (screen);
+ g_signal_connect_swapped (data->icon_theme, "changed",
+ G_CALLBACK (ephy_spinner_cache_data_unload),
+ data);
+
+ return data;
+}
+
+static void
+ephy_spinner_cache_data_free (EphySpinnerCacheData *data)
+{
+ g_return_if_fail (data != NULL);
+ g_return_if_fail (data->icon_theme != NULL);
+
+ g_signal_handlers_disconnect_by_func
+ (data->icon_theme,
+ G_CALLBACK (ephy_spinner_cache_data_unload), data);
+
+ ephy_spinner_cache_data_unload (data);
+
+ g_free (data);
+}
+
+static EphySpinnerImages *
+ephy_spinner_cache_get_images (EphySpinnerCache *cache,
+ GdkScreen *screen,
+ GtkIconSize icon_size)
+{
+ EphySpinnerCachePrivate *priv = cache->priv;
+ EphySpinnerCacheData *data;
+ EphySpinnerImages *images;
+
+ LOG ("Getting animation images for screen %p at size %d", screen, icon_size);
+
+ g_return_val_if_fail (icon_size >= 0 && icon_size < LAST_ICON_SIZE, NULL);
+
+ /* Backward compat: "invalid" meant "native" size which doesn't exist anymore */
+ if (icon_size == GTK_ICON_SIZE_INVALID)
+ {
+ icon_size = GTK_ICON_SIZE_DIALOG;
+ }
+
+ data = g_hash_table_lookup (priv->hash, screen);
+ if (data == NULL)
+ {
+ data = ephy_spinner_cache_data_new (screen);
+ /* FIXME: think about what happens when the screen's display is closed later on */
+ g_hash_table_insert (priv->hash, screen, data);
+ }
+
+ images = data->images[icon_size];
+ if (images == EPHY_SPINNER_IMAGES_INVALID)
+ {
+ /* Load failed, but don't try endlessly again! */
+ return NULL;
+ }
+
+ if (images != NULL)
+ {
+ /* Return cached data */
+ return ephy_spinner_images_ref (images);
+ }
+
+ images = ephy_spinner_images_load (screen, data->icon_theme, icon_size);
+
+ if (images == NULL)
+ {
+ /* Mark as failed-to-load */
+ data->images[icon_size] = EPHY_SPINNER_IMAGES_INVALID;
+
+ return NULL;
+ }
+
+ data->images[icon_size] = images;
+
+ return ephy_spinner_images_ref (images);
+}
+
+static void
+ephy_spinner_cache_init (EphySpinnerCache *cache)
+{
+ EphySpinnerCachePrivate *priv;
+
+ priv = cache->priv = EPHY_SPINNER_CACHE_GET_PRIVATE (cache);
+
+ LOG ("EphySpinnerCache initialising");
+
+ priv->hash = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL,
+ (GDestroyNotify) ephy_spinner_cache_data_free);
+}
+
+static void
+ephy_spinner_cache_finalize (GObject *object)
+{
+ EphySpinnerCache *cache = EPHY_SPINNER_CACHE (object);
+ EphySpinnerCachePrivate *priv = cache->priv;
+
+ g_hash_table_destroy (priv->hash);
+
+ LOG ("EphySpinnerCache finalised");
+
+ G_OBJECT_CLASS (ephy_spinner_cache_parent_class)->finalize (object);
+}
+
+static void
+ephy_spinner_cache_class_init (EphySpinnerCacheClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ ephy_spinner_cache_parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = ephy_spinner_cache_finalize;
+
+ g_type_class_add_private (object_class, sizeof (EphySpinnerCachePrivate));
+}
+
+static EphySpinnerCache *spinner_cache = NULL;
+
+static EphySpinnerCache *
+ephy_spinner_cache_ref (void)
+{
+ if (spinner_cache == NULL)
+ {
+ EphySpinnerCache **cache_ptr;
+
+ spinner_cache = g_object_new (EPHY_TYPE_SPINNER_CACHE, NULL);
+ cache_ptr = &spinner_cache;
+ g_object_add_weak_pointer (G_OBJECT (spinner_cache),
+ (gpointer *) cache_ptr);
+
+ return spinner_cache;
+ }
+
+ return g_object_ref (spinner_cache);
+}
+
+/* Spinner implementation */
+
+#define SPINNER_TIMEOUT 125 /* ms */
+
+#define EPHY_SPINNER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_SPINNER, EphySpinnerDetails))
+
+struct _EphySpinnerDetails
+{
+ GtkIconTheme *icon_theme;
+ EphySpinnerCache *cache;
+ GtkIconSize size;
+ EphySpinnerImages *images;
+ guint current_image;
+ guint timeout;
+ guint timer_task;
+ guint spinning : 1;
+ guint need_load : 1;
+};
+
+static void ephy_spinner_class_init (EphySpinnerClass *class);
+static void ephy_spinner_init (EphySpinner *spinner);
+
+static GObjectClass *parent_class;
+
+GType
+ephy_spinner_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0))
+ {
+ const GTypeInfo our_info =
+ {
+ sizeof (EphySpinnerClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ephy_spinner_class_init,
+ NULL,
+ NULL, /* class_data */
+ sizeof (EphySpinner),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ephy_spinner_init
+ };
+
+ type = g_type_register_static (GTK_TYPE_WIDGET,
+ "EphySpinner",
+ &our_info, 0);
+ }
+
+ return type;
+}
+
+static gboolean
+ephy_spinner_load_images (EphySpinner *spinner)
+{
+ EphySpinnerDetails *details = spinner->details;
+
+ if (details->need_load)
+ {
+ START_PROFILER ("ephy_spinner_load_images")
+
+ details->images =
+ ephy_spinner_cache_get_images
+ (details->cache,
+ gtk_widget_get_screen (GTK_WIDGET (spinner)),
+ details->size);
+
+ STOP_PROFILER ("ephy_spinner_load_images")
+
+ details->current_image = 0; /* 'rest' icon */
+ details->need_load = FALSE;
+ }
+
+ return details->images != NULL;
+}
+
+static void
+ephy_spinner_unload_images (EphySpinner *spinner)
+{
+ EphySpinnerDetails *details = spinner->details;
+
+ if (details->images != NULL)
+ {
+ ephy_spinner_images_unref (details->images);
+ details->images = NULL;
+ }
+
+ details->current_image = 0;
+ details->need_load = TRUE;
+}
+
+static void
+icon_theme_changed_cb (GtkIconTheme *icon_theme,
+ EphySpinner *spinner)
+{
+ ephy_spinner_unload_images (spinner);
+ gtk_widget_queue_resize (GTK_WIDGET (spinner));
+}
+
+static void
+ephy_spinner_init (EphySpinner *spinner)
+{
+ EphySpinnerDetails *details;
+
+ details = spinner->details = EPHY_SPINNER_GET_PRIVATE (spinner);
+
+ GTK_WIDGET_SET_FLAGS (GTK_WIDGET (spinner), GTK_NO_WINDOW);
+
+ details->cache = ephy_spinner_cache_ref ();
+ details->size = GTK_ICON_SIZE_DIALOG;
+ details->spinning = FALSE;
+ details->timeout = SPINNER_TIMEOUT;
+ details->need_load = TRUE;
+}
+
+static int
+ephy_spinner_expose (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ EphySpinner *spinner = EPHY_SPINNER (widget);
+ EphySpinnerDetails *details = spinner->details;
+ EphySpinnerImages *images;
+ GdkPixbuf *pixbuf;
+ GdkGC *gc;
+ int x_offset, y_offset, width, height;
+ GdkRectangle pix_area, dest;
+
+ if (!GTK_WIDGET_DRAWABLE (spinner))
+ {
+ return FALSE;
+ }
+
+ if (details->need_load &&
+ !ephy_spinner_load_images (spinner))
+ {
+ return FALSE;
+ }
+
+ images = details->images;
+ if (images == NULL)
+ {
+ return FALSE;
+ }
+
+ /* Otherwise |images| will be NULL anyway */
+ g_assert (images->n_animation_pixbufs > 0);
+
+ g_assert (details->current_image >= 0 &&
+ details->current_image < images->n_animation_pixbufs);
+
+ pixbuf = images->animation_pixbufs[details->current_image];
+
+ g_assert (pixbuf != NULL);
+
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+
+ /* Compute the offsets for the image centered on our allocation */
+ x_offset = (widget->allocation.width - width) / 2;
+ y_offset = (widget->allocation.height - height) / 2;
+
+ pix_area.x = x_offset + widget->allocation.x;
+ pix_area.y = y_offset + widget->allocation.y;
+ pix_area.width = width;
+ pix_area.height = height;
+
+ if (!gdk_rectangle_intersect (&event->area, &pix_area, &dest))
+ {
+ return FALSE;
+ }
+
+ gc = gdk_gc_new (widget->window);
+ gdk_draw_pixbuf (widget->window, gc, pixbuf,
+ dest.x - x_offset - widget->allocation.x,
+ dest.y - y_offset - widget->allocation.y,
+ dest.x, dest.y,
+ dest.width, dest.height,
+ GDK_RGB_DITHER_MAX, 0, 0);
+ g_object_unref (gc);
+
+ return FALSE;
+}
+
+static gboolean
+bump_spinner_frame_cb (EphySpinner *spinner)
+{
+ EphySpinnerDetails *details = spinner->details;
+
+ /* This can happen when we've unloaded the images on a theme
+ * change, but haven't been in the queued size request yet.
+ * Just skip this update.
+ */
+ if (details->images == NULL) return TRUE;
+
+ details->current_image++;
+ if (details->current_image >= details->images->n_animation_pixbufs)
+ {
+ /* the 0th frame is the 'rest' icon */
+ details->current_image = MIN (1, details->images->n_animation_pixbufs);
+ }
+
+ gtk_widget_queue_draw (GTK_WIDGET (spinner));
+
+ /* run again */
+ return TRUE;
+}
+
+/**
+ * ephy_spinner_start:
+ * @spinner: a #EphySpinner
+ *
+ * Start the spinner animation.
+ **/
+void
+ephy_spinner_start (EphySpinner *spinner)
+{
+ EphySpinnerDetails *details = spinner->details;
+
+ details->spinning = TRUE;
+
+ if (GTK_WIDGET_MAPPED (GTK_WIDGET (spinner)) &&
+ details->timer_task == 0 &&
+ ephy_spinner_load_images (spinner))
+ {
+ /* the 0th frame is the 'rest' icon */
+ details->current_image = MIN (1, details->images->n_animation_pixbufs);
+
+ details->timer_task =
+ g_timeout_add_full (G_PRIORITY_LOW,
+ details->timeout,
+ (GSourceFunc) bump_spinner_frame_cb,
+ spinner,
+ NULL);
+ }
+}
+
+static void
+ephy_spinner_remove_update_callback (EphySpinner *spinner)
+{
+ EphySpinnerDetails *details = spinner->details;
+
+ if (details->timer_task != 0)
+ {
+ g_source_remove (details->timer_task);
+ details->timer_task = 0;
+ }
+}
+
+/**
+ * ephy_spinner_stop:
+ * @spinner: a #EphySpinner
+ *
+ * Stop the spinner animation.
+ **/
+void
+ephy_spinner_stop (EphySpinner *spinner)
+{
+ EphySpinnerDetails *details = spinner->details;
+
+ details->spinning = FALSE;
+ details->current_image = 0;
+
+ if (details->timer_task != 0)
+ {
+ ephy_spinner_remove_update_callback (spinner);
+
+ if (GTK_WIDGET_MAPPED (GTK_WIDGET (spinner)))
+ {
+ gtk_widget_queue_draw (GTK_WIDGET (spinner));
+ }
+ }
+}
+
+/*
+ * ephy_spinner_set_size:
+ * @spinner: a #EphySpinner
+ * @size: the size of type %GtkIconSize
+ *
+ * Set the size of the spinner.
+ **/
+void
+ephy_spinner_set_size (EphySpinner *spinner,
+ GtkIconSize size)
+{
+ if (size == GTK_ICON_SIZE_INVALID)
+ {
+ size = GTK_ICON_SIZE_DIALOG;
+ }
+
+ if (size != spinner->details->size)
+ {
+ ephy_spinner_unload_images (spinner);
+
+ spinner->details->size = size;
+
+ gtk_widget_queue_resize (GTK_WIDGET (spinner));
+ }
+}
+
+#if 0
+/*
+ * ephy_spinner_set_timeout:
+ * @spinner: a #EphySpinner
+ * @timeout: time delay between updates to the spinner.
+ *
+ * Sets the timeout delay for spinner updates.
+ **/
+void
+ephy_spinner_set_timeout (EphySpinner *spinner,
+ guint timeout)
+{
+ EphySpinnerDetails *details = spinner->details;
+
+ if (timeout != details->timeout)
+ {
+ ephy_spinner_stop (spinner);
+
+ details->timeout = timeout;
+
+ if (details->spinning)
+ {
+ ephy_spinner_start (spinner);
+ }
+ }
+}
+#endif
+
+static void
+ephy_spinner_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ EphySpinner *spinner = EPHY_SPINNER (widget);
+ EphySpinnerDetails *details = spinner->details;
+
+ if ((details->need_load &&
+ !ephy_spinner_load_images (spinner)) ||
+ details->images == NULL)
+ {
+ requisition->width = requisition->height = 0;
+ gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (widget),
+ details->size,
+ &requisition->width,
+ &requisition->height);
+ return;
+ }
+
+ requisition->width = details->images->width;
+ requisition->height = details->images->height;
+
+ /* FIXME fix this hack */
+ /* allocate some extra margin so we don't butt up against toolbar edges */
+ if (details->size != GTK_ICON_SIZE_MENU)
+ {
+ requisition->width += 2;
+ requisition->height += 2;
+ }
+}
+
+static void
+ephy_spinner_map (GtkWidget *widget)
+{
+ EphySpinner *spinner = EPHY_SPINNER (widget);
+ EphySpinnerDetails *details = spinner->details;
+
+ GTK_WIDGET_CLASS (parent_class)->map (widget);
+
+ if (details->spinning)
+ {
+ ephy_spinner_start (spinner);
+ }
+}
+
+static void
+ephy_spinner_unmap (GtkWidget *widget)
+{
+ EphySpinner *spinner = EPHY_SPINNER (widget);
+
+ ephy_spinner_remove_update_callback (spinner);
+
+ GTK_WIDGET_CLASS (parent_class)->unmap (widget);
+}
+
+static void
+ephy_spinner_dispose (GObject *object)
+{
+ EphySpinner *spinner = EPHY_SPINNER (object);
+
+ g_signal_handlers_disconnect_by_func
+ (spinner->details->icon_theme,
+ G_CALLBACK (icon_theme_changed_cb), spinner);
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+ephy_spinner_finalize (GObject *object)
+{
+ EphySpinner *spinner = EPHY_SPINNER (object);
+
+ ephy_spinner_remove_update_callback (spinner);
+ ephy_spinner_unload_images (spinner);
+
+ g_object_unref (spinner->details->cache);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+ephy_spinner_screen_changed (GtkWidget *widget,
+ GdkScreen *old_screen)
+{
+ EphySpinner *spinner = EPHY_SPINNER (widget);
+ EphySpinnerDetails *details = spinner->details;
+ GdkScreen *screen;
+
+ if (GTK_WIDGET_CLASS (parent_class)->screen_changed)
+ {
+ GTK_WIDGET_CLASS (parent_class)->screen_changed (widget, old_screen);
+ }
+
+ screen = gtk_widget_get_screen (widget);
+
+ /* FIXME: this seems to be happening when then spinner is destroyed!? */
+ if (old_screen == screen) return;
+
+ /* We'll get mapped again on the new screen, but not unmapped from
+ * the old screen, so remove timeout here.
+ */
+ ephy_spinner_remove_update_callback (spinner);
+
+ ephy_spinner_unload_images (spinner);
+
+ if (old_screen != NULL)
+ {
+ g_signal_handlers_disconnect_by_func
+ (gtk_icon_theme_get_for_screen (old_screen),
+ G_CALLBACK (icon_theme_changed_cb), spinner);
+ }
+
+ details->icon_theme = gtk_icon_theme_get_for_screen (screen);
+ g_signal_connect (details->icon_theme, "changed",
+ G_CALLBACK (icon_theme_changed_cb), spinner);
+}
+
+static void
+ephy_spinner_class_init (EphySpinnerClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+
+ parent_class = g_type_class_peek_parent (class);
+
+ object_class->dispose = ephy_spinner_dispose;
+ object_class->finalize = ephy_spinner_finalize;
+
+ widget_class->expose_event = ephy_spinner_expose;
+ widget_class->size_request = ephy_spinner_size_request;
+ widget_class->map = ephy_spinner_map;
+ widget_class->unmap = ephy_spinner_unmap;
+ widget_class->screen_changed = ephy_spinner_screen_changed;
+
+ g_type_class_add_private (object_class, sizeof (EphySpinnerDetails));
+}
+
+/*
+ * ephy_spinner_new:
+ *
+ * Create a new #EphySpinner. The spinner is a widget
+ * that gives the user feedback about network status with
+ * an animated image.
+ *
+ * Return Value: the spinner #GtkWidget
+ **/
+GtkWidget *
+ephy_spinner_new (void)
+{
+ return GTK_WIDGET (g_object_new (EPHY_TYPE_SPINNER, NULL));
+}
diff --git a/gnome-2-22/libempathy-gtk/ephy-spinner.h b/gnome-2-22/libempathy-gtk/ephy-spinner.h
new file mode 100644
index 000000000..4435fe371
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/ephy-spinner.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright © 2000 Eazel, Inc.
+ * Copyright © 2004, 2006 Christian Persch
+ *
+ * Nautilus 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.
+ *
+ * Nautilus 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: Andy Hertzfeld <andy@eazel.com>
+ *
+ * $Id: ephy-spinner.h 2114 2006-12-25 12:15:00Z mr $
+ */
+
+#ifndef EPHY_SPINNER_H
+#define EPHY_SPINNER_H
+
+#include <gtk/gtkwidget.h>
+#include <gtk/gtkenums.h>
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_SPINNER (ephy_spinner_get_type ())
+#define EPHY_SPINNER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_SPINNER, EphySpinner))
+#define EPHY_SPINNER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_SPINNER, EphySpinnerClass))
+#define EPHY_IS_SPINNER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_SPINNER))
+#define EPHY_IS_SPINNER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_SPINNER))
+#define EPHY_SPINNER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_SPINNER, EphySpinnerClass))
+
+typedef struct _EphySpinner EphySpinner;
+typedef struct _EphySpinnerClass EphySpinnerClass;
+typedef struct _EphySpinnerDetails EphySpinnerDetails;
+
+struct _EphySpinner
+{
+ GtkWidget parent;
+
+ /*< private >*/
+ EphySpinnerDetails *details;
+};
+
+struct _EphySpinnerClass
+{
+ GtkWidgetClass parent_class;
+};
+
+GType ephy_spinner_get_type (void);
+
+GtkWidget *ephy_spinner_new (void);
+
+void ephy_spinner_start (EphySpinner *throbber);
+
+void ephy_spinner_stop (EphySpinner *throbber);
+
+void ephy_spinner_set_size (EphySpinner *spinner,
+ GtkIconSize size);
+
+G_END_DECLS
+
+#endif /* EPHY_SPINNER_H */
diff --git a/gnome-2-22/libempathy-gtk/libempathy-gtk.pc.in b/gnome-2-22/libempathy-gtk/libempathy-gtk.pc.in
new file mode 100644
index 000000000..4248387e8
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/libempathy-gtk.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libempathy-gtk
+Description: Empathy interface library
+Requires: glib-2.0, gobject-2.0, gtk+-2.0, libglade-2.0, libmissioncontrol, libtelepathy, libempathy
+Version: @VERSION@
+Libs: -L${libdir} -lempathy-gtk
+Cflags: -I${includedir}
diff --git a/gnome-2-22/libempathy-gtk/totem-subtitle-encoding.c b/gnome-2-22/libempathy-gtk/totem-subtitle-encoding.c
new file mode 100644
index 000000000..e0eef082c
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/totem-subtitle-encoding.c
@@ -0,0 +1,585 @@
+/*
+ * Copyright (C) 2001-2006 Bastien Nocera <hadess@hadess.net>
+ *
+ * encoding list copied from gnome-terminal/encoding.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ *
+ * The Totem project hereby grant permission for non-gpl compatible GStreamer
+ * plugins to be used and distributed together with GStreamer and Totem. This
+ * permission are above and beyond the permissions granted by the GPL license
+ * Totem is covered by.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add exception clause.
+ * See license_change file for details.
+ *
+ */
+
+#include "config.h"
+#include <glib/gi18n.h>
+#include "totem-subtitle-encoding.h"
+#include <string.h>
+
+typedef enum
+{
+ SUBTITLE_ENCODING_CURRENT_LOCALE,
+
+ SUBTITLE_ENCODING_ISO_8859_6,
+ SUBTITLE_ENCODING_IBM_864,
+ SUBTITLE_ENCODING_MAC_ARABIC,
+ SUBTITLE_ENCODING_WINDOWS_1256,
+
+ SUBTITLE_ENCODING_ARMSCII_8,
+
+ SUBTITLE_ENCODING_ISO_8859_4,
+ SUBTITLE_ENCODING_ISO_8859_13,
+ SUBTITLE_ENCODING_WINDOWS_1257,
+
+ SUBTITLE_ENCODING_ISO_8859_14,
+
+ SUBTITLE_ENCODING_ISO_8859_2,
+ SUBTITLE_ENCODING_IBM_852,
+ SUBTITLE_ENCODING_MAC_CE,
+ SUBTITLE_ENCODING_WINDOWS_1250,
+
+ SUBTITLE_ENCODING_GB18030,
+ SUBTITLE_ENCODING_GB2312,
+ SUBTITLE_ENCODING_GBK,
+ SUBTITLE_ENCODING_HZ,
+
+ SUBTITLE_ENCODING_BIG5,
+ SUBTITLE_ENCODING_BIG5_HKSCS,
+ SUBTITLE_ENCODING_EUC_TW,
+
+ SUBTITLE_ENCODING_MAC_CROATIAN,
+
+ SUBTITLE_ENCODING_ISO_8859_5,
+ SUBTITLE_ENCODING_IBM_855,
+ SUBTITLE_ENCODING_ISO_IR_111,
+ SUBTITLE_ENCODING_KOI8_R,
+ SUBTITLE_ENCODING_MAC_CYRILLIC,
+ SUBTITLE_ENCODING_WINDOWS_1251,
+
+ SUBTITLE_ENCODING_CP_866,
+
+ SUBTITLE_ENCODING_MAC_UKRAINIAN,
+ SUBTITLE_ENCODING_KOI8_U,
+
+ SUBTITLE_ENCODING_GEOSTD8,
+
+ SUBTITLE_ENCODING_ISO_8859_7,
+ SUBTITLE_ENCODING_MAC_GREEK,
+ SUBTITLE_ENCODING_WINDOWS_1253,
+
+ SUBTITLE_ENCODING_MAC_GUJARATI,
+
+ SUBTITLE_ENCODING_MAC_GURMUKHI,
+
+ SUBTITLE_ENCODING_ISO_8859_8_I,
+ SUBTITLE_ENCODING_IBM_862,
+ SUBTITLE_ENCODING_MAC_HEBREW,
+ SUBTITLE_ENCODING_WINDOWS_1255,
+
+ SUBTITLE_ENCODING_ISO_8859_8,
+
+ SUBTITLE_ENCODING_MAC_DEVANAGARI,
+
+ SUBTITLE_ENCODING_MAC_ICELANDIC,
+
+ SUBTITLE_ENCODING_EUC_JP,
+ SUBTITLE_ENCODING_ISO_2022_JP,
+ SUBTITLE_ENCODING_SHIFT_JIS,
+
+ SUBTITLE_ENCODING_EUC_KR,
+ SUBTITLE_ENCODING_ISO_2022_KR,
+ SUBTITLE_ENCODING_JOHAB,
+ SUBTITLE_ENCODING_UHC,
+
+ SUBTITLE_ENCODING_ISO_8859_10,
+
+ SUBTITLE_ENCODING_MAC_FARSI,
+
+ SUBTITLE_ENCODING_ISO_8859_16,
+ SUBTITLE_ENCODING_MAC_ROMANIAN,
+
+ SUBTITLE_ENCODING_ISO_8859_3,
+
+ SUBTITLE_ENCODING_TIS_620,
+
+ SUBTITLE_ENCODING_ISO_8859_9,
+ SUBTITLE_ENCODING_IBM_857,
+ SUBTITLE_ENCODING_MAC_TURKISH,
+ SUBTITLE_ENCODING_WINDOWS_1254,
+
+ SUBTITLE_ENCODING_UTF_7,
+ SUBTITLE_ENCODING_UTF_8,
+ SUBTITLE_ENCODING_UTF_16,
+ SUBTITLE_ENCODING_UCS_2,
+ SUBTITLE_ENCODING_UCS_4,
+
+ SUBTITLE_ENCODING_ISO_8859_1,
+ SUBTITLE_ENCODING_ISO_8859_15,
+ SUBTITLE_ENCODING_IBM_850,
+ SUBTITLE_ENCODING_MAC_ROMAN,
+ SUBTITLE_ENCODING_WINDOWS_1252,
+
+ SUBTITLE_ENCODING_TCVN,
+ SUBTITLE_ENCODING_VISCII,
+ SUBTITLE_ENCODING_WINDOWS_1258,
+
+ SUBTITLE_ENCODING_LAST
+} SubtitleEncodingIndex;
+
+
+typedef struct
+{
+ int index;
+ gboolean valid;
+ char *charset;
+ char *name;
+} SubtitleEncoding;
+
+
+static SubtitleEncoding encodings[] = {
+
+ {SUBTITLE_ENCODING_CURRENT_LOCALE, TRUE,
+ NULL, N_("Current Locale")},
+
+ {SUBTITLE_ENCODING_ISO_8859_6, FALSE,
+ "ISO-8859-6", N_("Arabic")},
+ {SUBTITLE_ENCODING_IBM_864, FALSE,
+ "IBM864", N_("Arabic")},
+ {SUBTITLE_ENCODING_MAC_ARABIC, FALSE,
+ "MAC_ARABIC", N_("Arabic")},
+ {SUBTITLE_ENCODING_WINDOWS_1256, FALSE,
+ "WINDOWS-1256", N_("Arabic")},
+
+ {SUBTITLE_ENCODING_ARMSCII_8, FALSE,
+ "ARMSCII-8", N_("Armenian")},
+
+ {SUBTITLE_ENCODING_ISO_8859_4, FALSE,
+ "ISO-8859-4", N_("Baltic")},
+ {SUBTITLE_ENCODING_ISO_8859_13, FALSE,
+ "ISO-8859-13", N_("Baltic")},
+ {SUBTITLE_ENCODING_WINDOWS_1257, FALSE,
+ "WINDOWS-1257", N_("Baltic")},
+
+ {SUBTITLE_ENCODING_ISO_8859_14, FALSE,
+ "ISO-8859-14", N_("Celtic")},
+
+ {SUBTITLE_ENCODING_ISO_8859_2, FALSE,
+ "ISO-8859-2", N_("Central European")},
+ {SUBTITLE_ENCODING_IBM_852, FALSE,
+ "IBM852", N_("Central European")},
+ {SUBTITLE_ENCODING_MAC_CE, FALSE,
+ "MAC_CE", N_("Central European")},
+ {SUBTITLE_ENCODING_WINDOWS_1250, FALSE,
+ "WINDOWS-1250", N_("Central European")},
+
+ {SUBTITLE_ENCODING_GB18030, FALSE,
+ "GB18030", N_("Chinese Simplified")},
+ {SUBTITLE_ENCODING_GB2312, FALSE,
+ "GB2312", N_("Chinese Simplified")},
+ {SUBTITLE_ENCODING_GBK, FALSE,
+ "GBK", N_("Chinese Simplified")},
+ {SUBTITLE_ENCODING_HZ, FALSE,
+ "HZ", N_("Chinese Simplified")},
+
+ {SUBTITLE_ENCODING_BIG5, FALSE,
+ "BIG5", N_("Chinese Traditional")},
+ {SUBTITLE_ENCODING_BIG5_HKSCS, FALSE,
+ "BIG5-HKSCS", N_("Chinese Traditional")},
+ {SUBTITLE_ENCODING_EUC_TW, FALSE,
+ "EUC-TW", N_("Chinese Traditional")},
+
+ {SUBTITLE_ENCODING_MAC_CROATIAN, FALSE,
+ "MAC_CROATIAN", N_("Croatian")},
+
+ {SUBTITLE_ENCODING_ISO_8859_5, FALSE,
+ "ISO-8859-5", N_("Cyrillic")},
+ {SUBTITLE_ENCODING_IBM_855, FALSE,
+ "IBM855", N_("Cyrillic")},
+ {SUBTITLE_ENCODING_ISO_IR_111, FALSE,
+ "ISO-IR-111", N_("Cyrillic")},
+ {SUBTITLE_ENCODING_KOI8_R, FALSE,
+ "KOI8-R", N_("Cyrillic")},
+ {SUBTITLE_ENCODING_MAC_CYRILLIC, FALSE,
+ "MAC-CYRILLIC", N_("Cyrillic")},
+ {SUBTITLE_ENCODING_WINDOWS_1251, FALSE,
+ "WINDOWS-1251", N_("Cyrillic")},
+
+ {SUBTITLE_ENCODING_CP_866, FALSE,
+ "CP866", N_("Cyrillic/Russian")},
+
+ {SUBTITLE_ENCODING_MAC_UKRAINIAN, FALSE,
+ "MAC_UKRAINIAN", N_("Cyrillic/Ukrainian")},
+ {SUBTITLE_ENCODING_KOI8_U, FALSE,
+ "KOI8-U", N_("Cyrillic/Ukrainian")},
+
+ {SUBTITLE_ENCODING_GEOSTD8, FALSE,
+ "GEORGIAN-PS", N_("Georgian")},
+
+ {SUBTITLE_ENCODING_ISO_8859_7, FALSE,
+ "ISO-8859-7", N_("Greek")},
+ {SUBTITLE_ENCODING_MAC_GREEK, FALSE,
+ "MAC_GREEK", N_("Greek")},
+ {SUBTITLE_ENCODING_WINDOWS_1253, FALSE,
+ "WINDOWS-1253", N_("Greek")},
+
+ {SUBTITLE_ENCODING_MAC_GUJARATI, FALSE,
+ "MAC_GUJARATI", N_("Gujarati")},
+
+ {SUBTITLE_ENCODING_MAC_GURMUKHI, FALSE,
+ "MAC_GURMUKHI", N_("Gurmukhi")},
+
+ {SUBTITLE_ENCODING_ISO_8859_8_I, FALSE,
+ "ISO-8859-8-I", N_("Hebrew")},
+ {SUBTITLE_ENCODING_IBM_862, FALSE,
+ "IBM862", N_("Hebrew")},
+ {SUBTITLE_ENCODING_MAC_HEBREW, FALSE,
+ "MAC_HEBREW", N_("Hebrew")},
+ {SUBTITLE_ENCODING_WINDOWS_1255, FALSE,
+ "WINDOWS-1255", N_("Hebrew")},
+
+ {SUBTITLE_ENCODING_ISO_8859_8, FALSE,
+ "ISO-8859-8", N_("Hebrew Visual")},
+
+ {SUBTITLE_ENCODING_MAC_DEVANAGARI, FALSE,
+ "MAC_DEVANAGARI", N_("Hindi")},
+
+ {SUBTITLE_ENCODING_MAC_ICELANDIC, FALSE,
+ "MAC_ICELANDIC", N_("Icelandic")},
+
+ {SUBTITLE_ENCODING_EUC_JP, FALSE,
+ "EUC-JP", N_("Japanese")},
+ {SUBTITLE_ENCODING_ISO_2022_JP, FALSE,
+ "ISO2022JP", N_("Japanese")},
+ {SUBTITLE_ENCODING_SHIFT_JIS, FALSE,
+ "SHIFT-JIS", N_("Japanese")},
+
+ {SUBTITLE_ENCODING_EUC_KR, FALSE,
+ "EUC-KR", N_("Korean")},
+ {SUBTITLE_ENCODING_ISO_2022_KR, FALSE,
+ "ISO2022KR", N_("Korean")},
+ {SUBTITLE_ENCODING_JOHAB, FALSE,
+ "JOHAB", N_("Korean")},
+ {SUBTITLE_ENCODING_UHC, FALSE,
+ "UHC", N_("Korean")},
+
+ {SUBTITLE_ENCODING_ISO_8859_10, FALSE,
+ "ISO-8859-10", N_("Nordic")},
+
+ {SUBTITLE_ENCODING_MAC_FARSI, FALSE,
+ "MAC_FARSI", N_("Persian")},
+
+ {SUBTITLE_ENCODING_ISO_8859_16, FALSE,
+ "ISO-8859-16", N_("Romanian")},
+ {SUBTITLE_ENCODING_MAC_ROMANIAN, FALSE,
+ "MAC_ROMANIAN", N_("Romanian")},
+
+ {SUBTITLE_ENCODING_ISO_8859_3, FALSE,
+ "ISO-8859-3", N_("South European")},
+
+ {SUBTITLE_ENCODING_TIS_620, FALSE,
+ "TIS-620", N_("Thai")},
+
+ {SUBTITLE_ENCODING_ISO_8859_9, FALSE,
+ "ISO-8859-9", N_("Turkish")},
+ {SUBTITLE_ENCODING_IBM_857, FALSE,
+ "IBM857", N_("Turkish")},
+ {SUBTITLE_ENCODING_MAC_TURKISH, FALSE,
+ "MAC_TURKISH", N_("Turkish")},
+ {SUBTITLE_ENCODING_WINDOWS_1254, FALSE,
+ "WINDOWS-1254", N_("Turkish")},
+
+ {SUBTITLE_ENCODING_UTF_7, FALSE,
+ "UTF-7", N_("Unicode")},
+ {SUBTITLE_ENCODING_UTF_8, FALSE,
+ "UTF-8", N_("Unicode")},
+ {SUBTITLE_ENCODING_UTF_16, FALSE,
+ "UTF-16", N_("Unicode")},
+ {SUBTITLE_ENCODING_UCS_2, FALSE,
+ "UCS-2", N_("Unicode")},
+ {SUBTITLE_ENCODING_UCS_4, FALSE,
+ "UCS-4", N_("Unicode")},
+
+ {SUBTITLE_ENCODING_ISO_8859_1, FALSE,
+ "ISO-8859-1", N_("Western")},
+ {SUBTITLE_ENCODING_ISO_8859_15, FALSE,
+ "ISO-8859-15", N_("Western")},
+ {SUBTITLE_ENCODING_IBM_850, FALSE,
+ "IBM850", N_("Western")},
+ {SUBTITLE_ENCODING_MAC_ROMAN, FALSE,
+ "MAC_ROMAN", N_("Western")},
+ {SUBTITLE_ENCODING_WINDOWS_1252, FALSE,
+ "WINDOWS-1252", N_("Western")},
+
+ {SUBTITLE_ENCODING_TCVN, FALSE,
+ "TCVN", N_("Vietnamese")},
+ {SUBTITLE_ENCODING_VISCII, FALSE,
+ "VISCII", N_("Vietnamese")},
+ {SUBTITLE_ENCODING_WINDOWS_1258, FALSE,
+ "WINDOWS-1258", N_("Vietnamese")}
+};
+
+static const SubtitleEncoding *
+find_encoding_by_charset (const char *charset)
+{
+ int i;
+
+ i = 1; /* skip current locale */
+ while (i < SUBTITLE_ENCODING_LAST) {
+ if (strcasecmp (charset, encodings[i].charset) == 0)
+ return &encodings[i];
+
+ ++i;
+ }
+
+ if (strcasecmp (charset,
+ encodings[SUBTITLE_ENCODING_CURRENT_LOCALE].charset) == 0)
+ return &encodings[SUBTITLE_ENCODING_CURRENT_LOCALE];
+
+ return NULL;
+}
+
+static void
+subtitle_encoding_init (void)
+{
+ int i;
+ gsize bytes_read, bytes_written;
+ gchar *converted;
+ gchar ascii_sample[96];
+
+ g_get_charset ((const char **)
+ &encodings[SUBTITLE_ENCODING_CURRENT_LOCALE].charset);
+
+ g_assert (G_N_ELEMENTS (encodings) == SUBTITLE_ENCODING_LAST);
+
+ /* Initialize the sample text with all of the printing ASCII characters
+ * from space (32) to the tilde (126), 95 in all. */
+ for (i = 0; i < (int) sizeof (ascii_sample); i++)
+ ascii_sample[i] = i + 32;
+
+ ascii_sample[sizeof (ascii_sample) - 1] = '\0';
+
+ i = 0;
+ while (i < SUBTITLE_ENCODING_LAST) {
+ bytes_read = 0;
+ bytes_written = 0;
+
+ g_assert (encodings[i].index == i);
+
+ /* Translate the names */
+ encodings[i].name = _(encodings[i].name);
+
+ /* Test that the encoding is a proper superset of ASCII (which naive
+ * apps are going to use anyway) by attempting to validate the text
+ * using the current encoding. This also flushes out any encodings
+ * which the underlying GIConv implementation can't support.
+ */
+ converted = g_convert (ascii_sample, sizeof (ascii_sample) - 1,
+ encodings[i].charset, encodings[i].charset,
+ &bytes_read, &bytes_written, NULL);
+
+ /* The encoding is only valid if ASCII passes through cleanly. */
+ if (i == SUBTITLE_ENCODING_CURRENT_LOCALE)
+ encodings[i].valid = TRUE;
+ else
+ encodings[i].valid =
+ (bytes_read == (sizeof (ascii_sample) - 1)) &&
+ (converted != NULL) && (strcmp (converted, ascii_sample) == 0);
+
+#ifdef DEBUG_ENCODINGS
+ if (!encodings[i].valid) {
+ g_print ("Rejecting encoding %s as invalid:\n", encodings[i].charset);
+ g_print (" input \"%s\"\n", ascii_sample);
+ g_print (" output \"%s\"\n\n", converted ? converted : "(null)");
+ }
+#endif
+
+ /* Discard the converted string. */
+ g_free (converted);
+
+ ++i;
+ }
+}
+
+static int
+subtitle_encoding_get_index (const char *charset)
+{
+ const SubtitleEncoding *e;
+
+ e = find_encoding_by_charset (charset);
+ if (e != NULL)
+ return e->index;
+ else
+ return SUBTITLE_ENCODING_CURRENT_LOCALE;
+}
+
+static const char *
+subtitle_encoding_get_charset (int index)
+{
+ const SubtitleEncoding *e;
+
+ if (index >= SUBTITLE_ENCODING_LAST)
+ e = &encodings[SUBTITLE_ENCODING_CURRENT_LOCALE];
+ else if (index < SUBTITLE_ENCODING_CURRENT_LOCALE)
+ e = &encodings[SUBTITLE_ENCODING_CURRENT_LOCALE];
+ else if (!encodings[index].valid)
+ e = &encodings[SUBTITLE_ENCODING_CURRENT_LOCALE];
+ else
+ e = &encodings[index];
+ return e->charset;
+}
+
+enum
+{
+ INDEX_COL,
+ NAME_COL
+};
+
+static gint
+compare (GtkTreeModel * model, GtkTreeIter * a, GtkTreeIter * b, gpointer data)
+{
+ gchar *str_a, *str_b;
+ gint result;
+
+ gtk_tree_model_get (model, a, NAME_COL, &str_a, -1);
+ gtk_tree_model_get (model, b, NAME_COL, &str_b, -1);
+
+ result = strcmp (str_a, str_b);
+
+ g_free (str_a);
+ g_free (str_b);
+
+ return result;
+}
+
+static void
+is_encoding_sensitive (GtkCellLayout * cell_layout,
+ GtkCellRenderer * cell,
+ GtkTreeModel * tree_model, GtkTreeIter * iter, gpointer data)
+{
+
+ gboolean sensitive;
+
+ sensitive = !gtk_tree_model_iter_has_child (tree_model, iter);
+ g_object_set (cell, "sensitive", sensitive, NULL);
+}
+
+static GtkTreeModel *
+subtitle_encoding_create_store (void)
+{
+ gchar *label;
+ gchar *lastlang = "";
+ GtkTreeIter iter, iter2;
+ GtkTreeStore *store;
+ int i;
+
+ store = gtk_tree_store_new (2, G_TYPE_INT, G_TYPE_STRING);
+
+ for (i = 0; i < SUBTITLE_ENCODING_LAST; i++) {
+ if (encodings[i].valid) {
+ if (strcmp (lastlang, encodings[i].name)) {
+ lastlang = encodings[i].name;
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter, INDEX_COL,
+ -1, NAME_COL, lastlang, -1);
+ }
+ label = g_strdup_printf("%s (%s)", lastlang, encodings[i].charset);
+ gtk_tree_store_append (store, &iter2, &iter);
+ gtk_tree_store_set (store, &iter2, INDEX_COL,
+ encodings[i].index, NAME_COL, label, -1);
+ g_free(label);
+ }
+ }
+ gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (store),
+ compare, NULL, NULL);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+ NAME_COL, GTK_SORT_ASCENDING);
+ return GTK_TREE_MODEL (store);
+}
+
+static void
+subtitle_encoding_combo_render (GtkComboBox * combo)
+{
+ GtkCellRenderer *renderer;
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
+ "text", NAME_COL, NULL);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo),
+ renderer, is_encoding_sensitive, NULL, NULL);
+}
+
+const char *
+totem_subtitle_encoding_get_selected (GtkComboBox * combo)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gint index = -1;
+
+ model = gtk_combo_box_get_model (combo);
+ if (gtk_combo_box_get_active_iter (combo, &iter)) {
+ gtk_tree_model_get (model, &iter, INDEX_COL, &index, -1);
+ }
+ if (index == -1)
+ return NULL;
+ return subtitle_encoding_get_charset (index);
+}
+
+void
+totem_subtitle_encoding_set (GtkComboBox * combo, const char *encoding)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter, iter2;
+ gint index, i;
+
+ g_return_if_fail (encoding != NULL);
+
+ model = gtk_combo_box_get_model (combo);
+ index = subtitle_encoding_get_index (encoding);
+ gtk_tree_model_get_iter_first (model, &iter);
+ do {
+ if (!gtk_tree_model_iter_has_child (model, &iter))
+ continue;
+ if (!gtk_tree_model_iter_children (model, &iter2, &iter))
+ continue;
+ do {
+ gtk_tree_model_get (model, &iter2, INDEX_COL, &i, -1);
+ if (i == index)
+ break;
+ } while (gtk_tree_model_iter_next (model, &iter2));
+ if (i == index)
+ break;
+ } while (gtk_tree_model_iter_next (model, &iter));
+ gtk_combo_box_set_active_iter (combo, &iter2);
+}
+
+void
+totem_subtitle_encoding_init (GtkComboBox *combo)
+{
+ GtkTreeModel *model;
+ subtitle_encoding_init ();
+ model = subtitle_encoding_create_store ();
+ gtk_combo_box_set_model (combo, model);
+ g_object_unref (model);
+ subtitle_encoding_combo_render (combo);
+}
+
+/*
+ * vim: sw=2 ts=8 cindent noai bs=2
+ */
diff --git a/gnome-2-22/libempathy-gtk/totem-subtitle-encoding.h b/gnome-2-22/libempathy-gtk/totem-subtitle-encoding.h
new file mode 100644
index 000000000..7283f003a
--- /dev/null
+++ b/gnome-2-22/libempathy-gtk/totem-subtitle-encoding.h
@@ -0,0 +1,12 @@
+/* Encoding stuff */
+
+#ifndef TOTEM_SUBTITLE_ENCODING_H
+#define TOTEM_SUBTITLE_ENCODING_H
+
+#include <gtk/gtk.h>
+
+void totem_subtitle_encoding_init (GtkComboBox *combo);
+void totem_subtitle_encoding_set (GtkComboBox *combo, const char *encoding);
+const char * totem_subtitle_encoding_get_selected (GtkComboBox *combo);
+
+#endif /* SUBTITLE_ENCODING_H */