diff options
Diffstat (limited to 'src')
45 files changed, 2918 insertions, 992 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index b776396aa..081b6f4f2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,16 +1,20 @@ +include $(top_srcdir)/tools/shave.mk + AM_CPPFLAGS = \ -I$(top_srcdir) \ $(EMPATHY_CFLAGS) \ $(LIBNOTIFY_CFLAGS) \ - $(WARN_CFLAGS) \ + $(LIBCHAMPLAIN_CFLAGS) \ $(DISABLE_DEPRECATED) + $(WARN_CFLAGS) LDADD = \ $(top_builddir)/libempathy-gtk/libempathy-gtk.la \ $(top_builddir)/libempathy/libempathy.la \ $(top_builddir)/extensions/libemp-extensions.la \ $(LIBNOTIFY_LIBS) \ - $(EMPATHY_LIBS) + $(EMPATHY_LIBS) \ + $(LIBCHAMPLAIN_LIBS) bin_PROGRAMS = \ empathy \ @@ -20,12 +24,12 @@ BUILT_SOURCES= \ empathy-tube-dispatch-enumtypes.h \ empathy-tube-dispatch-enumtypes.c -empathy_SOURCES = \ - bacon-message-connection.c bacon-message-connection.h \ +empathy_handwritten_source = \ empathy.c \ empathy-about-dialog.c empathy-about-dialog.h \ empathy-accounts-dialog.c empathy-accounts-dialog.h \ empathy-call-window.c empathy-call-window.h \ + empathy-call-window-fullscreen.c empathy-call-window-fullscreen.h \ empathy-chatrooms-window.c empathy-chatrooms-window.h \ empathy-debug-dialog.c empathy-debug-dialog.h \ empathy-chat-window.c empathy-chat-window.h \ @@ -39,17 +43,28 @@ empathy_SOURCES = \ empathy-preferences.c empathy-preferences.h \ empathy-sidebar.c empathy-sidebar.h \ empathy-status-icon.c empathy-status-icon.h \ - empathy-tube-dispatch.c empathy-tube-dispatch.h \ + empathy-tube-dispatch.c empathy-tube-dispatch.h + +empathy_SOURCES = \ + $(empathy_handwritten_source) \ + bacon-message-connection.c bacon-message-connection.h \ ephy-spinner.c ephy-spinner.h nodist_empathy_SOURCES = $(BUILT_SOURCES) empathy_logs_SOURCES = empathy-logs.c +check_c_sources = \ + $(empathy_handwritten_source) \ + $(empathy_logs_SOURCES) +include $(top_srcdir)/tools/check-coding-style.mk +check-local: check-coding-style + uidir = $(datadir)/empathy ui_DATA = \ empathy-accounts-dialog.ui \ empathy-call-window.ui \ + empathy-call-window-fullscreen.ui \ empathy-chatrooms-window.ui \ empathy-chat-window.ui \ empathy-ft-manager.ui \ @@ -59,12 +74,20 @@ ui_DATA = \ empathy-preferences.ui \ empathy-status-icon.ui +if HAVE_LIBCHAMPLAIN +empathy_SOURCES += \ + empathy-map-view.c empathy-map-view.h + +ui_DATA += \ + empathy-map-view.ui +endif + dist_man_MANS = \ empathy.1 # rules for making the glib enum objects %-enumtypes.h: %.h Makefile.in - glib-mkenums \ + $(QUIET_GEN)glib-mkenums \ --fhead "#ifndef __$(shell echo $* | tr [:lower:]- [:upper:]_)_ENUM_TYPES_H__\n#define __$(shell echo $* | tr [:lower:]- [:upper:]_)_ENUM_TYPES_H__\n\n#include <glib-object.h>\n\nG_BEGIN_DECLS\n" \ --fprod "/* enumerations from \"@filename@\" */\n" \ --vhead "GType @enum_name@_get_type (void);\n#define $(shell echo $* | tr [:lower:]- [:upper:]_ | sed 's/_.*//')_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n" \ @@ -72,7 +95,7 @@ dist_man_MANS = \ $< > $@ %-enumtypes.c: %.h Makefile.in - glib-mkenums \ + $(QUIET_GEN)glib-mkenums \ --fhead "#include <$*.h>\n#include <$*-enumtypes.h>" \ --fprod "\n/* enumerations from \"@filename@\" */" \ --vhead "GType\n@enum_name@_get_type (void)\n{\n static GType etype = 0;\n if (etype == 0) {\n static const G@Type@Value values[] = {" \ diff --git a/src/empathy-about-dialog.c b/src/empathy-about-dialog.c index a743f22c4..62c545864 100644 --- a/src/empathy-about-dialog.c +++ b/src/empathy-about-dialog.c @@ -15,9 +15,9 @@ * * 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. - * + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * * Authors: Martyn Russell <martyn@imendio.com> * Xavier Claessens <xclaesse@gmail.com> */ @@ -44,6 +44,7 @@ static const char *authors[] = { "Aurelien Naldi", "Bastien Nocera", "Christoffer Olsen", + "Cosimo Cecchi", "Elliot Fairweather", "Frederic Crozat", "Frederic Peters", diff --git a/src/empathy-about-dialog.h b/src/empathy-about-dialog.h index e7eac5ff9..3e8f40531 100644 --- a/src/empathy-about-dialog.h +++ b/src/empathy-about-dialog.h @@ -15,9 +15,9 @@ * * 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. - * + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * * Authors: Martyn Russell <martyn@imendio.com> * Xavier Claessens <xclaesse@gmail.com> */ diff --git a/src/empathy-accounts-dialog.c b/src/empathy-accounts-dialog.c index e15c0eab1..e311ac637 100644 --- a/src/empathy-accounts-dialog.c +++ b/src/empathy-accounts-dialog.c @@ -15,9 +15,9 @@ * * 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. - * + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * * Authors: Martyn Russell <martyn@imendio.com> * Xavier Claessens <xclaesse@gmail.com> */ @@ -217,9 +217,9 @@ accounts_dialog_update_account (EmpathyAccountsDialog *dialog, profile = mc_account_get_profile (account); config_ui = mc_profile_get_configuration_ui (profile); if (!tp_strdiff (config_ui, "jabber")) { - dialog->settings_widget = + 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); @@ -232,11 +232,11 @@ accounts_dialog_update_account (EmpathyAccountsDialog *dialog, dialog->settings_widget = empathy_account_widget_irc_new (account); } - else if (!tp_strdiff(config_ui, "icq")) { + else if (!tp_strdiff (config_ui, "icq")) { dialog->settings_widget = empathy_account_widget_icq_new (account); } - else if (!tp_strdiff(config_ui, "aim")) { + else if (!tp_strdiff (config_ui, "aim")) { dialog->settings_widget = empathy_account_widget_aim_new (account); } @@ -253,7 +253,7 @@ accounts_dialog_update_account (EmpathyAccountsDialog *dialog, empathy_account_widget_groupwise_new (account); } else { - dialog->settings_widget = + dialog->settings_widget = empathy_account_widget_generic_new (account); } @@ -358,7 +358,7 @@ accounts_dialog_enable_toggled_cb (GtkCellRendererToggle *cell_renderer, mc_account_set_enabled (account, !enabled); DEBUG ("%s account %s", enabled ? "Disabled" : "Enable", - mc_account_get_display_name(account)); + mc_account_get_display_name (account)); g_object_unref (account); } @@ -469,7 +469,7 @@ accounts_dialog_model_pixbuf_data_func (GtkTreeViewColumn *tree_column, if (pixbuf) { if (status == TP_CONNECTION_STATUS_DISCONNECTED || - (status == TP_CONNECTION_STATUS_CONNECTING && + (status == TP_CONNECTION_STATUS_CONNECTING && !dialog->connecting_show)) { GdkPixbuf *modded_pixbuf; @@ -954,10 +954,10 @@ accounts_dialog_button_remove_clicked_cb (GtkWidget *button, "they will still be available.")); gtk_dialog_add_button (GTK_DIALOG (message_dialog), - GTK_STOCK_CANCEL, + GTK_STOCK_CANCEL, GTK_RESPONSE_NO); gtk_dialog_add_button (GTK_DIALOG (message_dialog), - GTK_STOCK_REMOVE, + GTK_STOCK_REMOVE, GTK_RESPONSE_YES); gtk_widget_show (message_dialog); diff --git a/src/empathy-accounts-dialog.h b/src/empathy-accounts-dialog.h index 369b2f75b..40ea24f3e 100644 --- a/src/empathy-accounts-dialog.h +++ b/src/empathy-accounts-dialog.h @@ -15,9 +15,9 @@ * * 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. - * + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * * Authors: Martyn Russell <martyn@imendio.com> * Xavier Claessens <xclaesse@gmail.com> */ diff --git a/src/empathy-call-window-fullscreen.c b/src/empathy-call-window-fullscreen.c new file mode 100644 index 000000000..33f4085b3 --- /dev/null +++ b/src/empathy-call-window-fullscreen.c @@ -0,0 +1,294 @@ +/* + * empathy-call-window-fullscreen.c - Source for EmpathyCallWindowFullscreen + * Copyright (C) 2009 Collabora Ltd. + * + * Some code is based on the Totem Movie Player, especially + * totem-fullscreen.c which has the following copyright: + * Copyright (C) 2001-2007 Bastien Nocera <hadess@hadess.net> + * Copyright (C) 2007 Sunil Mohan Adapa <sunilmohan@gnu.org.in> + * + * 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 + */ + +#include "empathy-call-window-fullscreen.h" + +#include <gtk/gtk.h> + +#include <libempathy/empathy-utils.h> +#include <libempathy-gtk/empathy-ui-utils.h> + +/* The number of seconds for which the "leave fullscreen" popup should + be shown */ +#define FULLSCREEN_POPUP_TIMEOUT 5 + +G_DEFINE_TYPE (EmpathyCallWindowFullscreen, empathy_call_window_fullscreen, + G_TYPE_OBJECT) + +/* private structure */ +typedef struct _EmpathyCallWindowFullscreenPriv + EmpathyCallWindowFullscreenPriv; + +struct _EmpathyCallWindowFullscreenPriv +{ + EmpathyCallWindow *parent_window; + + GtkWidget *leave_fullscreen_popup; + GtkWidget *video_widget; + + guint popup_timeout; + gboolean popup_creation_in_progress; + gboolean dispose_has_run; +}; + +#define GET_PRIV(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_CALL_WINDOW_FULLSCREEN, \ + EmpathyCallWindowFullscreenPriv)) + +static void empathy_call_window_fullscreen_dispose (GObject *object); +static void empathy_call_window_fullscreen_finalize (GObject *object); + +static gboolean empathy_call_window_fullscreen_hide_popup ( + EmpathyCallWindowFullscreen *fs); + +static void +empathy_call_window_fullscreen_set_cursor_visible ( + EmpathyCallWindowFullscreen *fs, + gboolean show_cursor) +{ + EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (fs); + + if (priv->video_widget != NULL && !show_cursor) + { + gdk_window_set_cursor (priv->video_widget->window, + gdk_cursor_new (GDK_BLANK_CURSOR)); + } + else + gdk_window_set_cursor (priv->video_widget->window, NULL); +} + +static void +empathy_call_window_fullscreen_add_popup_timeout ( + EmpathyCallWindowFullscreen *self) +{ + EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (self); + + if (priv->popup_timeout == 0) + { + priv->popup_timeout = g_timeout_add_seconds (FULLSCREEN_POPUP_TIMEOUT, + (GSourceFunc) empathy_call_window_fullscreen_hide_popup, self); + } +} + +static void +empathy_call_window_fullscreen_remove_popup_timeout ( + EmpathyCallWindowFullscreen *self) +{ + EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (self); + + if (priv->popup_timeout != 0) + { + g_source_remove (priv->popup_timeout); + priv->popup_timeout = 0; + } +} + +void +empathy_call_window_fullscreen_show_popup (EmpathyCallWindowFullscreen *self) +{ + gint leave_fullscreen_width, leave_fullscreen_height; + GdkScreen *screen; + GdkRectangle fullscreen_rect; + EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (self); + + g_assert (self->is_fullscreen); + + g_return_if_fail (priv->parent_window != NULL); + + if (priv->popup_creation_in_progress) + return; + + if (!gtk_window_is_active (GTK_WINDOW (priv->parent_window))) + return; + + priv->popup_creation_in_progress = TRUE; + + empathy_call_window_fullscreen_set_cursor_visible (self, TRUE); + + /* Obtaining the screen rectangle */ + screen = gtk_window_get_screen (GTK_WINDOW (priv->parent_window)); + gdk_screen_get_monitor_geometry (screen, + gdk_screen_get_monitor_at_window (screen, + GTK_WIDGET (priv->parent_window)->window), + &fullscreen_rect); + + /* Getting the popup window sizes */ + gtk_window_get_size (GTK_WINDOW (priv->leave_fullscreen_popup), + &leave_fullscreen_width, &leave_fullscreen_height); + + /* Moving the popup to the top-right corner (if the direction is LTR) or the + top-left corner (if the direction is RTL).*/ + if (gtk_widget_get_direction (priv->leave_fullscreen_popup) + == GTK_TEXT_DIR_LTR) + { + gtk_window_move (GTK_WINDOW (priv->leave_fullscreen_popup), + fullscreen_rect.width + fullscreen_rect.x - leave_fullscreen_width, + fullscreen_rect.y); + + } + else + { + gtk_window_move (GTK_WINDOW (priv->leave_fullscreen_popup), + fullscreen_rect.x, fullscreen_rect.y); + } + + gtk_widget_show_all (priv->leave_fullscreen_popup); + empathy_call_window_fullscreen_add_popup_timeout (self); + + priv->popup_creation_in_progress = FALSE; +} + +static gboolean +empathy_call_window_fullscreen_hide_popup (EmpathyCallWindowFullscreen *fs) +{ + EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (fs); + + if (priv->video_widget == NULL || !fs->is_fullscreen) + return TRUE; + + gtk_widget_hide (priv->leave_fullscreen_popup); + empathy_call_window_fullscreen_remove_popup_timeout (fs); + + empathy_call_window_fullscreen_set_cursor_visible (fs, FALSE); + + return FALSE; +} + +static void +empathy_call_window_fullscreen_init (EmpathyCallWindowFullscreen *self) +{ + EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (self); + GtkBuilder *gui; + gchar *filename; + + filename = empathy_file_lookup ("empathy-call-window-fullscreen.ui", "src"); + gui = empathy_builder_get_file (filename, + "leave_fullscreen_window", &priv->leave_fullscreen_popup, + "leave_fullscreen_button", &self->leave_fullscreen_button, + NULL); + + gtk_widget_add_events (priv->leave_fullscreen_popup, GDK_POINTER_MOTION_MASK); + + g_object_unref (gui); + g_free (filename); +} + +static void +empathy_call_window_fullscreen_class_init ( + EmpathyCallWindowFullscreenClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (EmpathyCallWindowFullscreenPriv)); + + object_class->dispose = empathy_call_window_fullscreen_dispose; + object_class->finalize = empathy_call_window_fullscreen_finalize; +} + +void +empathy_call_window_fullscreen_dispose (GObject *object) +{ + EmpathyCallWindowFullscreen *self = EMPATHY_CALL_WINDOW_FULLSCREEN (object); + EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (self); + + if (priv->dispose_has_run) + return; + + priv->dispose_has_run = TRUE; + + if (priv->leave_fullscreen_popup != NULL) + gtk_widget_destroy (priv->leave_fullscreen_popup); + priv->leave_fullscreen_popup = NULL; + + if (G_OBJECT_CLASS (empathy_call_window_fullscreen_parent_class)->dispose) + { + G_OBJECT_CLASS ( + empathy_call_window_fullscreen_parent_class)->dispose (object); + } +} + +void +empathy_call_window_fullscreen_finalize (GObject *object) +{ + EmpathyCallWindowFullscreen *self = EMPATHY_CALL_WINDOW_FULLSCREEN (object); + + empathy_call_window_fullscreen_remove_popup_timeout (self); + + G_OBJECT_CLASS ( + empathy_call_window_fullscreen_parent_class)->finalize (object); +} + +static void +empathy_call_window_fullscreen_parent_window_notify (GtkWidget *parent_window, + GParamSpec *property, EmpathyCallWindowFullscreen *fs) +{ + EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (fs); + + if (!fs->is_fullscreen) + return; + + if (parent_window == GTK_WIDGET (priv->parent_window) && + !gtk_window_is_active (GTK_WINDOW (parent_window))) + { + empathy_call_window_fullscreen_hide_popup (fs); + empathy_call_window_fullscreen_set_cursor_visible (fs, TRUE); + } +} + +EmpathyCallWindowFullscreen * +empathy_call_window_fullscreen_new (EmpathyCallWindow *parent_window) +{ + EmpathyCallWindowFullscreen *self = EMPATHY_CALL_WINDOW_FULLSCREEN ( + g_object_new (EMPATHY_TYPE_CALL_WINDOW_FULLSCREEN, NULL)); + EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (self); + + priv->parent_window = parent_window; + g_signal_connect (G_OBJECT (priv->parent_window), "notify::is-active", + G_CALLBACK (empathy_call_window_fullscreen_parent_window_notify), self); + + return self; +} + +void +empathy_call_window_fullscreen_set_fullscreen (EmpathyCallWindowFullscreen *fs, + gboolean set_fullscreen) +{ + + if (set_fullscreen) + empathy_call_window_fullscreen_remove_popup_timeout (fs); + else + empathy_call_window_fullscreen_hide_popup (fs); + + empathy_call_window_fullscreen_set_cursor_visible (fs, !set_fullscreen); + fs->is_fullscreen = set_fullscreen; +} + +void +empathy_call_window_fullscreen_set_video_widget ( + EmpathyCallWindowFullscreen *fs, + GtkWidget *video_widget) +{ + EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (fs); + priv->video_widget = video_widget; +} diff --git a/src/empathy-call-window-fullscreen.h b/src/empathy-call-window-fullscreen.h new file mode 100644 index 000000000..8bde16ced --- /dev/null +++ b/src/empathy-call-window-fullscreen.h @@ -0,0 +1,77 @@ +/* + * empathy-call-window-fullscreen.h - Header for EmpathyCallWindowFullscreen + * Copyright (C) 2009 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 + */ + +#ifndef __EMPATHY_CALL_WINDOW_FULLSCREEN_H__ +#define __EMPATHY_CALL_WINDOW_FULLSCREEN_H__ + +#include <glib-object.h> +#include <gtk/gtk.h> + +#include "empathy-call-window.h" + +G_BEGIN_DECLS + +typedef struct _EmpathyCallWindowFullscreen EmpathyCallWindowFullscreen; +typedef struct _EmpathyCallWindowFullscreenClass + EmpathyCallWindowFullscreenClass; + +struct _EmpathyCallWindowFullscreenClass { + GObjectClass parent_class; +}; + +struct _EmpathyCallWindowFullscreen { + GObject parent; + gboolean is_fullscreen; + GtkWidget *leave_fullscreen_button; +}; + +GType empathy_call_window_fullscreen_get_type (void); + +/* TYPE MACROS */ +#define EMPATHY_TYPE_CALL_WINDOW_FULLSCREEN \ + (empathy_call_window_fullscreen_get_type ()) +#define EMPATHY_CALL_WINDOW_FULLSCREEN(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), EMPATHY_TYPE_CALL_WINDOW_FULLSCREEN, \ + EmpathyCallWindowFullscreen)) +#define EMPATHY_CALL_WINDOW_FULLSCREEN_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), EMPATHY_TYPE_CALL_WINDOW_FULLSCREEN, \ + EmpathyCallWindowClassFullscreen)) +#define EMPATHY_IS_CALL_WINDOW_FULLSCREEN(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), EMPATHY_TYPE_CALL_WINDOW_FULLSCREEN)) +#define EMPATHY_IS_CALL_WINDOW_FULLSCREEN_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), EMPATHY_TYPE_CALL_WINDOW_FULLSCREEN)) +#define EMPATHY_CALL_WINDOW_FULLSCREEN_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_CALL_WINDOW_FULLSCREEN, \ + EmpathyCallWindowFullscreenClass)) + +EmpathyCallWindowFullscreen *empathy_call_window_fullscreen_new ( + EmpathyCallWindow *parent); + +void empathy_call_window_fullscreen_set_fullscreen ( + EmpathyCallWindowFullscreen *fs, + gboolean set_fullscreen); +void empathy_call_window_fullscreen_set_video_widget ( + EmpathyCallWindowFullscreen *fs, + GtkWidget *video_widget); +void empathy_call_window_fullscreen_show_popup ( + EmpathyCallWindowFullscreen *fs); + +G_END_DECLS + +#endif /* #ifndef __EMPATHY_CALL_WINDOW_FULLSCREEN_H__*/ diff --git a/src/empathy-call-window-fullscreen.ui b/src/empathy-call-window-fullscreen.ui new file mode 100644 index 000000000..5bf5e509b --- /dev/null +++ b/src/empathy-call-window-fullscreen.ui @@ -0,0 +1,23 @@ +<?xml version="1.0"?> +<interface> + <requires lib="gtk+" version="2.16"/> + <!-- interface-naming-policy toplevel-contextual --> + <object class="GtkWindow" id="leave_fullscreen_window"> + <property name="type">popup</property> + <property name="resizable">False</property> + <property name="skip_taskbar_hint">True</property> + <property name="skip_pager_hint">True</property> + <property name="decorated">False</property> + <property name="deletable">False</property> + <signal name="motion_notify_event" handler="empathy_call_window_fullscreen_motion_notify_cb"/> + <child> + <object class="GtkButton" id="leave_fullscreen_button"> + <property name="label" translatable="yes">gtk-leave-fullscreen</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + </child> + </object> +</interface> diff --git a/src/empathy-call-window.c b/src/empathy-call-window.c index 01c2c4f5c..08c0e7ea2 100644 --- a/src/empathy-call-window.c +++ b/src/empathy-call-window.c @@ -1,6 +1,6 @@ /* * empathy-call-window.c - Source for EmpathyCallWindow - * Copyright (C) 2008 Collabora Ltd. + * Copyright (C) 2008-2009 Collabora Ltd. * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> * * This library is free software; you can redistribute it and/or @@ -24,13 +24,16 @@ #include <math.h> +#include <gdk/gdkkeysyms.h> #include <gst/gst.h> #include <gtk/gtk.h> #include <glib/gi18n.h> #include <telepathy-farsight/channel.h> +#include <libempathy/empathy-tp-contact-factory.h> #include <libempathy/empathy-utils.h> +#include <libempathy-gtk/empathy-avatar-image.h> #include <libempathy-gtk/empathy-video-widget.h> #include <libempathy-gtk/empathy-audio-src.h> #include <libempathy-gtk/empathy-audio-sink.h> @@ -39,10 +42,23 @@ #include "empathy-call-window.h" +#include "empathy-call-window-fullscreen.h" #include "empathy-sidebar.h" #define BUTTON_ID "empathy-call-dtmf-button-id" +#define CONTENT_HBOX_BORDER_WIDTH 6 +#define CONTENT_HBOX_SPACING 3 +#define CONTENT_HBOX_CHILDREN_PACKING_PADDING 3 + +#define SELF_VIDEO_SECTION_WIDTH 160 +#define SELF_VIDEO_SECTION_HEIGTH 120 + +/* The avatar's default width and height are set to the same value because we + want a square icon. */ +#define REMOTE_CONTACT_AVATAR_DEFAULT_WIDTH EMPATHY_VIDEO_WIDGET_DEFAULT_HEIGHT +#define REMOTE_CONTACT_AVATAR_DEFAULT_HEIGHT EMPATHY_VIDEO_WIDGET_DEFAULT_HEIGHT + G_DEFINE_TYPE(EmpathyCallWindow, empathy_call_window, GTK_TYPE_WINDOW) /* signal enum */ @@ -66,12 +82,15 @@ struct _EmpathyCallWindowPriv { gboolean dispose_has_run; EmpathyCallHandler *handler; + EmpathyContact *contact; gboolean connected; GtkUIManager *ui_manager; GtkWidget *video_output; GtkWidget *video_preview; + GtkWidget *remote_user_avatar_widget; + GtkWidget *self_user_avatar_widget; GtkWidget *sidebar; GtkWidget *sidebar_button; GtkWidget *statusbar; @@ -81,6 +100,17 @@ struct _EmpathyCallWindowPriv GtkWidget *toolbar; GtkWidget *pane; GtkAction *send_video; + GtkAction *menu_fullscreen; + + /* We keep a reference on the hbox which contains the main content so we can + easilly repack everything when toggling fullscreen */ + GtkWidget *content_hbox; + + /* This vbox is contained in the content_hbox. When toggling fullscreen, + it needs to be repacked. We keep a reference on it for easier access. */ + GtkWidget *vbox; + + gulong video_output_motion_handler_id; gdouble volume; GtkAdjustment *audio_input_adj; @@ -108,6 +138,15 @@ struct _EmpathyCallWindowPriv GMutex *lock; gboolean call_started; gboolean sending_video; + + EmpathyCallWindowFullscreen *fullscreen; + gboolean is_fullscreen; + + /* Those fields represent the state of the window before it actually was in + fullscreen mode. */ + gboolean sidebar_was_visible_before_fs; + gint original_width_before_fs; + gint original_height_before_fs; }; #define GET_PRIV(o) \ @@ -118,7 +157,10 @@ static void empathy_call_window_realized_cb (GtkWidget *widget, EmpathyCallWindow *window); static gboolean empathy_call_window_delete_cb (GtkWidget *widget, - GdkEvent*event, EmpathyCallWindow *window); + GdkEvent *event, EmpathyCallWindow *window); + +static gboolean empathy_call_window_state_event_cb (GtkWidget *widget, + GdkEventWindowState *event, EmpathyCallWindow *window); static void empathy_call_window_sidebar_toggled_cb (GtkToggleButton *toggle, EmpathyCallWindow *window); @@ -138,9 +180,29 @@ static void empathy_call_window_mic_toggled_cb ( static void empathy_call_window_sidebar_hidden_cb (EmpathySidebar *sidebar, EmpathyCallWindow *window); +static void empathy_call_window_sidebar_shown_cb (EmpathySidebar *sidebar, + EmpathyCallWindow *window); + static void empathy_call_window_hangup_cb (gpointer object, EmpathyCallWindow *window); +static void empathy_call_window_fullscreen_cb (gpointer object, + EmpathyCallWindow *window); + +static void empathy_call_window_fullscreen_toggle (EmpathyCallWindow *window); + +static gboolean empathy_call_window_video_button_press_cb (GtkWidget *video_output, + GdkEventButton *event, EmpathyCallWindow *window); + +static gboolean empathy_call_window_key_press_cb (GtkWidget *video_output, + GdkEventKey *event, EmpathyCallWindow *window); + +static gboolean empathy_call_window_video_output_motion_notify (GtkWidget *widget, + GdkEventMotion *event, EmpathyCallWindow *window); + +static void empathy_call_window_video_menu_popup (EmpathyCallWindow *window, + guint button); + static void empathy_call_window_status_message (EmpathyCallWindow *window, gchar *message); @@ -458,10 +520,12 @@ empathy_call_window_init (EmpathyCallWindow *self) { EmpathyCallWindowPriv *priv = GET_PRIV (self); GtkBuilder *gui; - GtkWidget *vbox, *top_vbox; - GtkWidget *hbox, *h; + GtkWidget *top_vbox; + GtkWidget *h; GtkWidget *arrow; GtkWidget *page; + GtkWidget *remote_user_output_frame, *self_user_output_frame; + GtkWidget *remote_user_output_hbox, *self_user_output_hbox; GstBus *bus; gchar *filename; @@ -475,6 +539,7 @@ empathy_call_window_init (EmpathyCallWindow *self) "toolbar", &priv->toolbar, "send_video", &priv->send_video, "ui_manager", &priv->ui_manager, + "menufullscreen", &priv->menu_fullscreen, NULL); empathy_builder_connect (gui, self, @@ -484,6 +549,7 @@ empathy_call_window_init (EmpathyCallWindow *self) "camera", "toggled", empathy_call_window_camera_toggled_cb, "send_video", "toggled", empathy_call_window_send_video_toggled_cb, "show_preview", "toggled", empathy_call_window_show_preview_toggled_cb, + "menufullscreen", "activate", empathy_call_window_fullscreen_cb, NULL); priv->lock = g_mutex_new (); @@ -494,27 +560,66 @@ empathy_call_window_init (EmpathyCallWindow *self) priv->pipeline = gst_pipeline_new (NULL); - hbox = gtk_hbox_new (FALSE, 3); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 6); - gtk_paned_pack1 (GTK_PANED (priv->pane), hbox, TRUE, FALSE); + priv->content_hbox = gtk_hbox_new (FALSE, CONTENT_HBOX_SPACING); + gtk_container_set_border_width (GTK_CONTAINER (priv->content_hbox), + CONTENT_HBOX_BORDER_WIDTH); + gtk_paned_pack1 (GTK_PANED (priv->pane), priv->content_hbox, TRUE, FALSE); bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline)); gst_bus_add_watch (bus, empathy_call_window_bus_message, self); + remote_user_output_frame = gtk_frame_new (NULL); + gtk_widget_set_size_request (remote_user_output_frame, + EMPATHY_VIDEO_WIDGET_DEFAULT_WIDTH, EMPATHY_VIDEO_WIDGET_DEFAULT_HEIGHT); + remote_user_output_hbox = gtk_hbox_new (FALSE, 0); + + priv->remote_user_avatar_widget = gtk_image_new (); + gtk_box_pack_start (GTK_BOX (remote_user_output_hbox), + priv->remote_user_avatar_widget, TRUE, TRUE, 0); + priv->video_output = empathy_video_widget_new (bus); - gtk_box_pack_start (GTK_BOX (hbox), priv->video_output, TRUE, TRUE, 3); + gtk_box_pack_start (GTK_BOX (remote_user_output_hbox), + priv->video_output, TRUE, TRUE, 0); + + gtk_container_add (GTK_CONTAINER (remote_user_output_frame), + remote_user_output_hbox); + + gtk_widget_add_events (priv->video_output, + GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK); + g_signal_connect (G_OBJECT (priv->video_output), "button-press-event", + G_CALLBACK (empathy_call_window_video_button_press_cb), self); + gtk_box_pack_start (GTK_BOX (priv->content_hbox), remote_user_output_frame, + TRUE, TRUE, CONTENT_HBOX_CHILDREN_PACKING_PADDING); priv->video_tee = gst_element_factory_make ("tee", NULL); gst_object_ref (priv->video_tee); gst_object_sink (priv->video_tee); - vbox = gtk_vbox_new (FALSE, 3); - gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 3); + priv->vbox = gtk_vbox_new (FALSE, 3); + gtk_box_pack_start (GTK_BOX (priv->content_hbox), priv->vbox, + FALSE, FALSE, CONTENT_HBOX_CHILDREN_PACKING_PADDING); - priv->video_preview = empathy_video_widget_new_with_size (bus, 160, 120); + self_user_output_frame = gtk_frame_new (NULL); + gtk_widget_set_size_request (self_user_output_frame, SELF_VIDEO_SECTION_WIDTH, + SELF_VIDEO_SECTION_HEIGTH); + self_user_output_hbox = gtk_hbox_new (FALSE, 0); + + priv->self_user_avatar_widget = gtk_image_new (); + gtk_box_pack_start (GTK_BOX (self_user_output_hbox), + priv->self_user_avatar_widget, TRUE, TRUE, 0); + + priv->video_preview = empathy_video_widget_new_with_size (bus, + SELF_VIDEO_SECTION_WIDTH, SELF_VIDEO_SECTION_HEIGTH); g_object_set (priv->video_preview, "sync", FALSE, "async", TRUE, NULL); - gtk_box_pack_start (GTK_BOX (vbox), priv->video_preview, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (self_user_output_hbox), priv->video_preview, + TRUE, TRUE, 0); + + gtk_container_add (GTK_CONTAINER (self_user_output_frame), + self_user_output_hbox); + + gtk_box_pack_start (GTK_BOX (priv->vbox), self_user_output_frame, FALSE, + FALSE, 0); priv->video_input = empathy_video_src_new (); gst_object_ref (priv->video_input); @@ -538,13 +643,14 @@ empathy_call_window_init (EmpathyCallWindow *self) gtk_button_set_image (GTK_BUTTON (priv->sidebar_button), arrow); h = gtk_hbox_new (FALSE, 3); - gtk_box_pack_end (GTK_BOX (vbox), h, FALSE, FALSE, 3); + gtk_box_pack_end (GTK_BOX (priv->vbox), h, FALSE, FALSE, 3); gtk_box_pack_end (GTK_BOX (h), priv->sidebar_button, FALSE, FALSE, 3); priv->sidebar = empathy_sidebar_new (); g_signal_connect (G_OBJECT (priv->sidebar), - "hide", G_CALLBACK (empathy_call_window_sidebar_hidden_cb), - self); + "hide", G_CALLBACK (empathy_call_window_sidebar_hidden_cb), self); + g_signal_connect (G_OBJECT (priv->sidebar), + "show", G_CALLBACK (empathy_call_window_sidebar_shown_cb), self); gtk_paned_pack2 (GTK_PANED (priv->pane), priv->sidebar, FALSE, FALSE); priv->dtmf_panel = empathy_call_window_create_dtmf (self); @@ -565,18 +671,153 @@ empathy_call_window_init (EmpathyCallWindow *self) gtk_widget_hide (priv->sidebar); + priv->fullscreen = empathy_call_window_fullscreen_new (self); + empathy_call_window_fullscreen_set_video_widget (priv->fullscreen, priv->video_output); + g_signal_connect (G_OBJECT (priv->fullscreen->leave_fullscreen_button), + "clicked", G_CALLBACK (empathy_call_window_fullscreen_cb), self); + g_signal_connect (G_OBJECT (self), "realize", G_CALLBACK (empathy_call_window_realized_cb), self); g_signal_connect (G_OBJECT (self), "delete-event", G_CALLBACK (empathy_call_window_delete_cb), self); + g_signal_connect (G_OBJECT (self), "window-state-event", + G_CALLBACK (empathy_call_window_state_event_cb), self); + + g_signal_connect (G_OBJECT (self), "key-press-event", + G_CALLBACK (empathy_call_window_key_press_cb), self); + empathy_call_window_status_message (self, _("Connecting...")); priv->timer = g_timer_new (); g_object_ref (priv->ui_manager); g_object_unref (gui); + g_free (filename); +} + +/* Instead of specifying a width and a height, we specify only one size. That's + because we want a square avatar icon. */ +static void +init_contact_avatar_with_size (EmpathyContact *contact, GtkWidget *image_widget, + gint size) +{ + + GdkPixbuf *pixbuf_avatar = NULL; + + if (contact != NULL) + { + pixbuf_avatar = empathy_pixbuf_avatar_from_contact_scaled (contact, + size, size); + } + + if (pixbuf_avatar == NULL) + { + pixbuf_avatar = empathy_pixbuf_from_icon_name_sized ("stock_person", + size); + } + + gtk_image_set_from_pixbuf (GTK_IMAGE (image_widget), pixbuf_avatar); +} + +static void +set_window_title (EmpathyCallWindow *self) +{ + EmpathyCallWindowPriv *priv = GET_PRIV (self); + gchar *tmp; + + tmp = g_strdup_printf (_("Call with %s"), + empathy_contact_get_name (priv->contact)); + gtk_window_set_title (GTK_WINDOW (self), tmp); + g_free (tmp); +} + +static void +contact_name_changed_cb (EmpathyContact *contact, + GParamSpec *pspec, EmpathyCallWindow *self) +{ + set_window_title (self); +} + +static void +contact_avatar_changed_cb (EmpathyContact *contact, + GParamSpec *pspec, GtkWidget *avatar_widget) +{ + init_contact_avatar_with_size (contact, avatar_widget, + avatar_widget->allocation.height); +} + +static void +empathy_call_window_got_self_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, const GError *error, gpointer user_data, + GObject *weak_object) +{ + EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (user_data); + EmpathyCallWindowPriv *priv = GET_PRIV (self); + + init_contact_avatar_with_size (contact, priv->self_user_avatar_widget, + MIN (SELF_VIDEO_SECTION_WIDTH, SELF_VIDEO_SECTION_HEIGTH)); + + g_signal_connect (contact, "notify::avatar", + G_CALLBACK (contact_avatar_changed_cb), priv->self_user_avatar_widget); +} + +static void +empathy_call_window_constructed (GObject *object) +{ + EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (object); + EmpathyCallWindowPriv *priv = GET_PRIV (self); + + g_assert (priv->handler != NULL); + + g_object_get (priv->handler, "contact", &(priv->contact), NULL); + + if (priv->contact != NULL) + { + TpConnection *connection; + EmpathyTpContactFactory *factory; + + set_window_title (self); + + g_signal_connect (priv->contact, "notify::name", + G_CALLBACK (contact_name_changed_cb), self); + g_signal_connect (priv->contact, "notify::avatar", + G_CALLBACK (contact_avatar_changed_cb), + priv->remote_user_avatar_widget); + + /* Retreiving the self avatar */ + connection = empathy_contact_get_connection (priv->contact); + factory = empathy_tp_contact_factory_dup_singleton (connection); + empathy_tp_contact_factory_get_from_handle (factory, + tp_connection_get_self_handle (connection), + empathy_call_window_got_self_contact_cb, self, NULL, NULL); + + g_object_unref (factory); + } + else + { + g_warning ("call handler doesn't have a contact"); + gtk_window_set_title (GTK_WINDOW (self), _("Call")); + + /* Since we can't access the remote contact, we can't get a connection + to it and can't get the self contact (and its avatar). This means + that we have to manually set the self avatar. */ + init_contact_avatar_with_size (NULL, priv->self_user_avatar_widget, + MIN (SELF_VIDEO_SECTION_WIDTH, SELF_VIDEO_SECTION_HEIGTH)); + } + + init_contact_avatar_with_size (priv->contact, + priv->remote_user_avatar_widget, MIN (REMOTE_CONTACT_AVATAR_DEFAULT_WIDTH, + REMOTE_CONTACT_AVATAR_DEFAULT_HEIGHT)); + + /* We hide the self avatar. It will be shown if a problem is + encountered when we try to send video. As for the remote avatar, it + is shown by default and will be hidden when we receive video from + the remote side. */ + gtk_widget_hide (priv->self_user_avatar_widget); + gtk_widget_hide (priv->video_output); + gtk_widget_show (priv->remote_user_avatar_widget); } static void empathy_call_window_dispose (GObject *object); @@ -624,6 +865,7 @@ empathy_call_window_class_init ( g_type_class_add_private (empathy_call_window_class, sizeof (EmpathyCallWindowPriv)); + object_class->constructed = empathy_call_window_constructed; object_class->set_property = empathy_call_window_set_property; object_class->get_property = empathy_call_window_get_property; @@ -633,7 +875,7 @@ empathy_call_window_class_init ( param_spec = g_param_spec_object ("handler", "handler", "The call handler", EMPATHY_TYPE_CALL_HANDLER, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CALL_HANDLER, param_spec); @@ -683,6 +925,14 @@ empathy_call_window_dispose (GObject *object) g_object_unref (priv->ui_manager); priv->ui_manager = NULL; + if (priv->contact != NULL) + { + g_signal_handlers_disconnect_by_func (priv->contact, + contact_name_changed_cb, self); + g_object_unref (priv->contact); + priv->contact = NULL; + } + /* release any references held by the object here */ if (G_OBJECT_CLASS (empathy_call_window_parent_class)->dispose) G_OBJECT_CLASS (empathy_call_window_parent_class)->dispose (object); @@ -694,6 +944,13 @@ empathy_call_window_finalize (GObject *object) EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (object); EmpathyCallWindowPriv *priv = GET_PRIV (self); + if (priv->video_output_motion_handler_id != 0) + { + g_signal_handler_disconnect (G_OBJECT (priv->video_output), + priv->video_output_motion_handler_id); + priv->video_output_motion_handler_id = 0; + } + /* free any data held directly by the object here */ g_mutex_free (priv->lock); @@ -902,6 +1159,8 @@ empathy_call_window_src_added_cb (EmpathyCallHandler *handler, pad = empathy_call_window_get_audio_sink_pad (self); break; case TP_MEDIA_STREAM_TYPE_VIDEO: + gtk_widget_hide (priv->remote_user_avatar_widget); + gtk_widget_show (priv->video_output); pad = empathy_call_window_get_video_sink_pad (self); break; default: @@ -936,7 +1195,7 @@ empathy_call_window_sink_added_cb (EmpathyCallHandler *handler, case TP_MEDIA_STREAM_TYPE_VIDEO: if (priv->video_input != NULL) { - pad = gst_element_get_request_pad (priv->video_tee, "src%d"); + pad = gst_element_get_request_pad (priv->video_tee, "src%d"); gst_pad_link (pad, sink); } break; @@ -1005,6 +1264,9 @@ empathy_call_window_remove_video_input (EmpathyCallWindow *self) priv->video_input = NULL; g_object_unref (priv->video_tee); priv->video_tee = NULL; + + gtk_widget_hide (priv->video_preview); + gtk_widget_show (priv->self_user_avatar_widget); } @@ -1041,7 +1303,7 @@ empathy_call_window_bus_message (GstBus *bus, GstMessage *message, break; case GST_MESSAGE_ERROR: { - GError *error; + GError *error = NULL; gchar *debug; gst_message_parse_error (message, &error, &debug); @@ -1112,6 +1374,108 @@ empathy_call_window_delete_cb (GtkWidget *widget, GdkEvent*event, } static void +show_controls (EmpathyCallWindow *window, gboolean set_fullscreen) +{ + GtkWidget *menu; + EmpathyCallWindowPriv *priv = GET_PRIV (window); + + menu = gtk_ui_manager_get_widget (priv->ui_manager, + "/menubar1"); + + if (set_fullscreen) + { + gtk_widget_hide (priv->sidebar); + gtk_widget_hide (menu); + gtk_widget_hide (priv->vbox); + gtk_widget_hide (priv->statusbar); + gtk_widget_hide (priv->toolbar); + } + else + { + if (priv->sidebar_was_visible_before_fs) + gtk_widget_show (priv->sidebar); + + gtk_widget_show (menu); + gtk_widget_show (priv->vbox); + gtk_widget_show (priv->statusbar); + gtk_widget_show (priv->toolbar); + + gtk_window_resize (GTK_WINDOW (window), priv->original_width_before_fs, + priv->original_height_before_fs); + } +} + +static void +show_borders (EmpathyCallWindow *window, gboolean set_fullscreen) +{ + EmpathyCallWindowPriv *priv = GET_PRIV (window); + + gtk_container_set_border_width (GTK_CONTAINER (priv->content_hbox), + set_fullscreen ? 0 : CONTENT_HBOX_BORDER_WIDTH); + gtk_box_set_spacing (GTK_BOX (priv->content_hbox), + set_fullscreen ? 0 : CONTENT_HBOX_SPACING); + gtk_box_set_child_packing (GTK_BOX (priv->content_hbox), + priv->video_output, TRUE, TRUE, + set_fullscreen ? 0 : CONTENT_HBOX_CHILDREN_PACKING_PADDING, + GTK_PACK_START); + gtk_box_set_child_packing (GTK_BOX (priv->content_hbox), + priv->vbox, TRUE, TRUE, + set_fullscreen ? 0 : CONTENT_HBOX_CHILDREN_PACKING_PADDING, + GTK_PACK_START); +} + +static gboolean +empathy_call_window_state_event_cb (GtkWidget *widget, + GdkEventWindowState *event, EmpathyCallWindow *window) +{ + if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) + { + EmpathyCallWindowPriv *priv = GET_PRIV (window); + gboolean set_fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN; + + if (set_fullscreen) + { + gboolean sidebar_was_visible; + gint original_width = GTK_WIDGET (window)->allocation.width; + gint original_height = GTK_WIDGET (window)->allocation.height; + + g_object_get (priv->sidebar, "visible", &sidebar_was_visible, NULL); + + priv->sidebar_was_visible_before_fs = sidebar_was_visible; + priv->original_width_before_fs = original_width; + priv->original_height_before_fs = original_height; + + if (priv->video_output_motion_handler_id == 0 && + priv->video_output != NULL) + { + priv->video_output_motion_handler_id = g_signal_connect ( + G_OBJECT (priv->video_output), "motion-notify-event", + G_CALLBACK (empathy_call_window_video_output_motion_notify), window); + } + } + else + { + if (priv->video_output_motion_handler_id != 0) + { + g_signal_handler_disconnect (G_OBJECT (priv->video_output), + priv->video_output_motion_handler_id); + priv->video_output_motion_handler_id = 0; + } + } + + empathy_call_window_fullscreen_set_fullscreen (priv->fullscreen, + set_fullscreen); + show_controls (window, set_fullscreen); + show_borders (window, set_fullscreen); + gtk_action_set_stock_id (priv->menu_fullscreen, + (set_fullscreen ? "gtk-leave-fullscreen" : "gtk-fullscreen")); + priv->is_fullscreen = set_fullscreen; + } + + return FALSE; +} + +static void empathy_call_window_sidebar_toggled_cb (GtkToggleButton *toggle, EmpathyCallWindow *window) { @@ -1166,10 +1530,10 @@ empathy_call_window_camera_toggled_cb (GtkToggleToolButton *toggle, if (priv->sending_video == active) return; + priv->sending_video = active; empathy_call_window_set_send_video (window, active); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->send_video), active); - priv->sending_video = active; } static void @@ -1183,11 +1547,11 @@ empathy_call_window_send_video_toggled_cb (GtkToggleAction *toggle, if (priv->sending_video == active) return; + priv->sending_video = active; empathy_call_window_set_send_video (window, active); gtk_toggle_tool_button_set_active ( GTK_TOGGLE_TOOL_BUTTON (priv->camera_button), active); - priv->sending_video = active; } static void @@ -1236,6 +1600,16 @@ empathy_call_window_sidebar_hidden_cb (EmpathySidebar *sidebar, } static void +empathy_call_window_sidebar_shown_cb (EmpathySidebar *sidebar, + EmpathyCallWindow *window) +{ + EmpathyCallWindowPriv *priv = GET_PRIV (window); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->sidebar_button), + TRUE); +} + +static void empathy_call_window_hangup_cb (gpointer object, EmpathyCallWindow *window) { @@ -1246,6 +1620,83 @@ empathy_call_window_hangup_cb (gpointer object, } static void +empathy_call_window_fullscreen_cb (gpointer object, + EmpathyCallWindow *window) +{ + empathy_call_window_fullscreen_toggle (window); +} + +static void +empathy_call_window_fullscreen_toggle (EmpathyCallWindow *window) +{ + EmpathyCallWindowPriv *priv = GET_PRIV (window); + + if (priv->is_fullscreen) + gtk_window_unfullscreen (GTK_WINDOW (window)); + else + gtk_window_fullscreen (GTK_WINDOW (window)); +} + +static gboolean +empathy_call_window_video_button_press_cb (GtkWidget *video_output, + GdkEventButton *event, EmpathyCallWindow *window) +{ + if (event->button == 3 && event->type == GDK_BUTTON_PRESS) + { + empathy_call_window_video_menu_popup (window, event->button); + return TRUE; + } + + return FALSE; +} + +static gboolean +empathy_call_window_key_press_cb (GtkWidget *video_output, + GdkEventKey *event, EmpathyCallWindow *window) +{ + EmpathyCallWindowPriv *priv = GET_PRIV (window); + + if (priv->is_fullscreen && event->keyval == GDK_Escape) + { + /* Since we are in fullscreen mode, toggling will bring us back to + normal mode. */ + empathy_call_window_fullscreen_toggle (window); + return TRUE; + } + + return FALSE; +} + +static gboolean +empathy_call_window_video_output_motion_notify (GtkWidget *widget, + GdkEventMotion *event, EmpathyCallWindow *window) +{ + EmpathyCallWindowPriv *priv = GET_PRIV (window); + + if (priv->is_fullscreen) + { + empathy_call_window_fullscreen_show_popup (priv->fullscreen); + return TRUE; + } + + return FALSE; +} + +static void +empathy_call_window_video_menu_popup (EmpathyCallWindow *window, + guint button) +{ + GtkWidget *menu; + EmpathyCallWindowPriv *priv = GET_PRIV (window); + + menu = gtk_ui_manager_get_widget (priv->ui_manager, + "/video-popup"); + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, + button, gtk_get_current_event_time ()); + gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE); +} + +static void empathy_call_window_status_message (EmpathyCallWindow *window, gchar *message) { diff --git a/src/empathy-call-window.h b/src/empathy-call-window.h index 26b0e7881..01ea5def7 100644 --- a/src/empathy-call-window.h +++ b/src/empathy-call-window.h @@ -38,11 +38,11 @@ struct _EmpathyCallWindow { GtkWindow parent; }; -GType empathy_call_window_get_type(void); +GType empathy_call_window_get_type (void); /* TYPE MACROS */ #define EMPATHY_TYPE_CALL_WINDOW \ - (empathy_call_window_get_type()) + (empathy_call_window_get_type ()) #define EMPATHY_CALL_WINDOW(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), EMPATHY_TYPE_CALL_WINDOW, \ EmpathyCallWindow)) @@ -57,8 +57,7 @@ GType empathy_call_window_get_type(void); (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_CALL_WINDOW, \ EmpathyCallWindowClass)) -EmpathyCallWindow * -empathy_call_window_new (EmpathyCallHandler *handler); +EmpathyCallWindow *empathy_call_window_new (EmpathyCallHandler *handler); G_END_DECLS diff --git a/src/empathy-call-window.ui b/src/empathy-call-window.ui index ce3d85b56..a0e1e1304 100644 --- a/src/empathy-call-window.ui +++ b/src/empathy-call-window.ui @@ -36,6 +36,13 @@ <property name="label" translatable="yes">Video preview</property> </object> </child> + <child> + <object class="GtkAction" id="menufullscreen"> + <property name="stock_id">gtk-fullscreen</property> + <property name="name">menufullscreen</property> + </object> + <accelerator key="F11"/> + </child> </object> </child> <ui> @@ -46,8 +53,12 @@ </menu> <menu action="view"> <menuitem action="show_preview"/> + <menuitem action="menufullscreen"/> </menu> </menubar> + <popup name="video-popup"> + <menuitem name="menufullscreen" action="menufullscreen"/> + </popup> </ui> </object> <object class="GtkVBox" id="call_window_vbox"> diff --git a/src/empathy-chat-window.c b/src/empathy-chat-window.c index 0738f6e52..bf02c3cc6 100644 --- a/src/empathy-chat-window.c +++ b/src/empathy-chat-window.c @@ -15,9 +15,9 @@ * * 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. - * + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * * Authors: Mikael Hallendal <micke@imendio.com> * Richard Hult <richard@imendio.com> * Martyn Russell <martyn@imendio.com> @@ -76,7 +76,6 @@ typedef struct { /* Menu items. */ GtkUIManager *ui_manager; GtkAction *menu_conv_insert_smiley; - GtkAction *menu_conv_contact; GtkAction *menu_conv_favorite; GtkAction *menu_edit_cut; @@ -162,21 +161,39 @@ chat_window_close_clicked_cb (GtkAction *action, } static void -chat_window_close_button_style_set_cb (GtkWidget *button, +chat_tab_style_set_cb (GtkWidget *hbox, GtkStyle *previous_style, gpointer user_data) { - gint h, w; + GtkWidget *button; + int char_width, h, w; + PangoContext *context; + PangoFontMetrics *metrics; + + button = g_object_get_data (G_OBJECT (user_data), + "chat-window-tab-close-button"); + context = gtk_widget_get_pango_context (hbox); + + metrics = pango_context_get_metrics (context, hbox->style->font_desc, + pango_context_get_language (context)); + char_width = pango_font_metrics_get_approximate_char_width (metrics); + pango_font_metrics_unref (metrics); gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (button), GTK_ICON_SIZE_MENU, &w, &h); + /* Request at least about 12 chars width plus at least space for the status + * image and the close button */ + gtk_widget_set_size_request (hbox, + 12 * PANGO_PIXELS (char_width) + 2 * w, -1); + gtk_widget_set_size_request (button, w, h); } static GtkWidget * chat_window_create_label (EmpathyChatWindow *window, - EmpathyChat *chat) + EmpathyChat *chat, + gboolean is_tab_label) { EmpathyChatWindowPriv *priv; GtkWidget *hbox; @@ -198,7 +215,8 @@ chat_window_create_label (EmpathyChatWindow *window, gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE); name_label = gtk_label_new (NULL); - gtk_label_set_ellipsize (GTK_LABEL (name_label), PANGO_ELLIPSIZE_END); + if (is_tab_label) + 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); @@ -210,7 +228,9 @@ chat_window_create_label (EmpathyChatWindow *window, 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); + g_object_set_data (G_OBJECT (chat), + is_tab_label ? "chat-window-tab-label" : "chat-window-menu-label", + name_label); status_image = gtk_image_new (); @@ -220,42 +240,47 @@ chat_window_create_label (EmpathyChatWindow *window, 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); + g_object_set_data (G_OBJECT (chat), + is_tab_label ? "chat-window-tab-image" : "chat-window-menu-image", + status_image); + g_object_set_data (G_OBJECT (chat), + is_tab_label ? "chat-window-tab-tooltip-widget" : "chat-window-menu-tooltip-widget", + event_box); - close_button = gtk_button_new (); - gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE); - g_object_set_data (G_OBJECT (chat), "chat-window-tab-close-button", close_button); + gtk_container_add (GTK_CONTAINER (event_box), event_box_hbox); + gtk_box_pack_start (GTK_BOX (hbox), event_box, TRUE, TRUE, 0); - /* 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); + if (is_tab_label) { + close_button = gtk_button_new (); + gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE); + g_object_set_data (G_OBJECT (chat), "chat-window-tab-close-button", close_button); - /* Set the name to make the special rc style match. */ - gtk_widget_set_name (close_button, "empathy-close-button"); + /* 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); - close_image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU); + /* Set the name to make the special rc style match. */ + gtk_widget_set_name (close_button, "empathy-close-button"); - gtk_container_add (GTK_CONTAINER (close_button), close_image); + close_image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU); - 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); + gtk_container_add (GTK_CONTAINER (close_button), close_image); - /* 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); + gtk_box_pack_end (GTK_BOX (hbox), close_button, FALSE, FALSE, 0); - g_signal_connect (close_button, - "clicked", - G_CALLBACK (chat_window_close_clicked_cb), - chat); + g_signal_connect (close_button, + "clicked", + G_CALLBACK (chat_window_close_clicked_cb), + chat); + + /* React to theme changes and also setup the size correctly. */ + g_signal_connect (hbox, + "style-set", + G_CALLBACK (chat_tab_style_set_cb), + chat); + } gtk_widget_show_all (hbox); @@ -279,6 +304,8 @@ chat_window_update (EmpathyChatWindow *window) gboolean avatar_in_icon; GtkWidget *chat; GtkWidget *chat_close_button; + GtkWidget *submenu; + GtkWidget *menu; /* Get information */ page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)); @@ -299,6 +326,13 @@ chat_window_update (EmpathyChatWindow *window) gtk_action_set_sensitive (priv->menu_tabs_right, !last_page); gtk_action_set_sensitive (priv->menu_conv_insert_smiley, is_connected); + /* Update Contact menu */ + menu = gtk_ui_manager_get_widget (priv->ui_manager, + "/chats_menubar/menu_contact"); + submenu = empathy_chat_get_contact_menu (priv->current_chat); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu), submenu); + gtk_widget_show (menu); + /* Update window title */ if (n_chats == 1) { gtk_window_set_title (GTK_WINDOW (priv->dialog), name); @@ -390,6 +424,8 @@ chat_window_update_chat_tab (EmpathyChat *chat) } widget = g_object_get_data (G_OBJECT (chat), "chat-window-tab-image"); gtk_image_set_from_icon_name (GTK_IMAGE (widget), icon_name, GTK_ICON_SIZE_MENU); + widget = g_object_get_data (G_OBJECT (chat), "chat-window-menu-image"); + gtk_image_set_from_icon_name (GTK_IMAGE (widget), icon_name, GTK_ICON_SIZE_MENU); /* Update tab tooltip */ tooltip = g_string_new (NULL); @@ -423,11 +459,15 @@ chat_window_update_chat_tab (EmpathyChat *chat) markup = g_string_free (tooltip, FALSE); widget = g_object_get_data (G_OBJECT (chat), "chat-window-tab-tooltip-widget"); gtk_widget_set_tooltip_markup (widget, markup); + widget = g_object_get_data (G_OBJECT (chat), "chat-window-menu-tooltip-widget"); + gtk_widget_set_tooltip_markup (widget, markup); g_free (markup); - /* Update tab label */ + /* Update tab and menu label */ widget = g_object_get_data (G_OBJECT (chat), "chat-window-tab-label"); gtk_label_set_text (GTK_LABEL (widget), name); + widget = g_object_get_data (G_OBJECT (chat), "chat-window-menu-label"); + gtk_label_set_text (GTK_LABEL (widget), name); /* Update the window if it's the current chat */ if (priv->current_chat == chat) { @@ -488,20 +528,8 @@ chat_window_conv_activate_cb (GtkAction *action, EmpathyChatWindow *window) { EmpathyChatWindowPriv *priv = GET_PRIV (window); - GtkWidget *menu = NULL; - GtkWidget *submenu = NULL; gboolean is_room; - /* Contact submenu */ - submenu = empathy_chat_get_contact_menu (priv->current_chat); - if (submenu) { - menu = gtk_ui_manager_get_widget (priv->ui_manager, - "/chats_menubar/menu_conv/menu_conv_contact"); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu), submenu); - gtk_widget_show (submenu); - } - gtk_action_set_visible (priv->menu_conv_contact, submenu != NULL); - /* Favorite room menu */ is_room = empathy_chat_is_room (priv->current_chat); if (is_room) { @@ -930,32 +958,23 @@ chat_window_new_message_cb (EmpathyChat *chat, /* - if we're the sender, we play the sound if it's specified in the * preferences and we're not away. * - if we receive a message, we play the sound if it's specified in the - * prefereces and the window does not have focus on the chat receiving + * preferences and the window does not have focus on the chat receiving * the message. */ sender = empathy_message_get_sender (message); - if (empathy_contact_is_user (sender) != FALSE) { + if (empathy_contact_is_user (sender)) { empathy_sound_play (GTK_WIDGET (priv->dialog), EMPATHY_SOUND_MESSAGE_OUTGOING); - } else { - if ((!has_focus || priv->current_chat != chat)) { - empathy_sound_play (GTK_WIDGET (priv->dialog), - EMPATHY_SOUND_MESSAGE_INCOMING); - } - } - - if (!has_focus) { - chat_window_show_or_update_notification (window, message, chat); } if (has_focus && priv->current_chat == chat) { return; } - /* If empathy_chat_is_room() returns TRUE, that means it's a named MUC. - * If empathy_chat_get_remote_contact() returns NULL, that means it's + /* If empathy_chat_is_room () returns TRUE, that means it's a named MUC. + * If empathy_chat_get_remote_contact () returns NULL, that means it's * an unamed MUC (msn-like). * In case of a MUC, we set urgency only if the message contains our * alias. */ @@ -966,8 +985,13 @@ chat_window_new_message_cb (EmpathyChat *chat, needs_urgency = TRUE; } - if (needs_urgency && !has_focus) { - chat_window_set_urgency_hint (window, TRUE); + if (needs_urgency) { + if (!has_focus) + chat_window_set_urgency_hint (window, TRUE); + + empathy_sound_play (GTK_WIDGET (priv->dialog), + EMPATHY_SOUND_MESSAGE_INCOMING); + chat_window_show_or_update_notification (window, message, chat); } if (!g_list_find (priv->chats_new_msg, chat)) { @@ -1213,7 +1237,7 @@ chat_window_drag_data_received (GtkWidget *widget, /* 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(). + * anyway with add_chat () and remove_chat (). */ gtk_drag_finish (context, TRUE, FALSE, time); } @@ -1223,7 +1247,7 @@ chat_window_drag_data_received (GtkWidget *widget, DEBUG ("DND tab"); - chat = (void*) selection->data; + chat = (void *) selection->data; old_window = chat_window_find_chat (*chat); if (old_window) { @@ -1244,7 +1268,7 @@ chat_window_drag_data_received (GtkWidget *widget, /* 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(). + * anyway with add_chat () and remove_chat (). */ gtk_drag_finish (context, TRUE, FALSE, time); } else { @@ -1326,7 +1350,6 @@ empathy_chat_window_init (EmpathyChatWindow *window) "chat_vbox", &chat_vbox, "ui_manager", &priv->ui_manager, "menu_conv_insert_smiley", &priv->menu_conv_insert_smiley, - "menu_conv_contact", &priv->menu_conv_contact, "menu_conv_favorite", &priv->menu_conv_favorite, "menu_edit_cut", &priv->menu_edit_cut, "menu_edit_copy", &priv->menu_edit_copy, @@ -1362,7 +1385,9 @@ empathy_chat_window_init (EmpathyChatWindow *window) priv->chatroom_manager = empathy_chatroom_manager_dup_singleton (NULL); priv->notebook = gtk_notebook_new (); - gtk_notebook_set_group (GTK_NOTEBOOK (priv->notebook), "EmpathyChatWindow"); + gtk_notebook_set_group (GTK_NOTEBOOK (priv->notebook), "EmpathyChatWindow"); + gtk_notebook_set_scrollable (GTK_NOTEBOOK (priv->notebook), TRUE); + gtk_notebook_popup_enable (GTK_NOTEBOOK (priv->notebook)); gtk_box_pack_start (GTK_BOX (chat_vbox), priv->notebook, TRUE, TRUE, 0); gtk_widget_show (priv->notebook); @@ -1508,6 +1533,7 @@ empathy_chat_window_add_chat (EmpathyChatWindow *window, { EmpathyChatWindowPriv *priv; GtkWidget *label; + GtkWidget *popup_label; GtkWidget *child; gint x, y, w, h; @@ -1539,7 +1565,8 @@ empathy_chat_window_add_chat (EmpathyChatWindow *window, } child = GTK_WIDGET (chat); - label = chat_window_create_label (window, chat); + label = chat_window_create_label (window, chat, TRUE); + popup_label = chat_window_create_label (window, chat, FALSE); gtk_widget_show (child); g_signal_connect (chat, "notify::name", @@ -1553,11 +1580,11 @@ empathy_chat_window_add_chat (EmpathyChatWindow *window, NULL); chat_window_chat_notify_cb (chat); - gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), child, label); + gtk_notebook_append_page_menu (GTK_NOTEBOOK (priv->notebook), child, label, popup_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); + TRUE, TRUE, GTK_PACK_START); DEBUG ("Chat added (%d references)", G_OBJECT (chat)->ref_count); } @@ -1713,6 +1740,6 @@ empathy_chat_window_present_chat (EmpathyChat *chat) empathy_chat_window_switch_to_chat (window, chat); empathy_window_present (GTK_WINDOW (priv->dialog), TRUE); - gtk_widget_grab_focus (chat->input_text_view); + gtk_widget_grab_focus (chat->input_text_view); } diff --git a/src/empathy-chat-window.h b/src/empathy-chat-window.h index 8b7fe06a9..835d67296 100644 --- a/src/empathy-chat-window.h +++ b/src/empathy-chat-window.h @@ -15,9 +15,9 @@ * * 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. - * + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * * Authors: Mikael Hallendal <micke@imendio.com> * Richard Hult <richard@imendio.com> * Martyn Russell <martyn@imendio.com> diff --git a/src/empathy-chat-window.ui b/src/empathy-chat-window.ui index a347a454e..0d5a83180 100644 --- a/src/empathy-chat-window.ui +++ b/src/empathy-chat-window.ui @@ -26,12 +26,6 @@ </object> </child> <child> - <object class="GtkAction" id="menu_conv_contact"> - <property name="name">menu_conv_contact</property> - <property name="label" translatable="yes">_Contact</property> - </object> - </child> - <child> <object class="GtkToggleAction" id="menu_conv_favorite"> <property name="name">menu_conv_favorite</property> <property name="label" translatable="yes">_Favorite Chatroom</property> @@ -45,6 +39,12 @@ <accelerator key="W" modifiers="GDK_CONTROL_MASK"/> </child> <child> + <object class="GtkAction" id="menu_contact"> + <property name="name">menu_contact</property> + <property name="label" translatable="yes">_Contact</property> + </object> + </child> + <child> <object class="GtkAction" id="menu_edit"> <property name="name">menu_edit</property> <property name="label" translatable="yes">_Edit</property> @@ -136,11 +136,11 @@ <menu action="menu_conv"> <menuitem action="menu_conv_clear"/> <menuitem action="menu_conv_insert_smiley"/> - <menuitem action="menu_conv_contact"/> <menuitem action="menu_conv_favorite"/> <separator/> <menuitem action="menu_conv_close"/> </menu> + <menu action="menu_contact" /> <menu action="menu_edit"> <menuitem action="menu_edit_cut"/> <menuitem action="menu_edit_copy"/> diff --git a/src/empathy-chatrooms-window.c b/src/empathy-chatrooms-window.c index fa63d5a51..a0fb8e6ec 100644 --- a/src/empathy-chatrooms-window.c +++ b/src/empathy-chatrooms-window.c @@ -15,8 +15,8 @@ * * 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA * * Authors: Xavier Claessens <xclaesse@gmail.com> * Martyn Russell <martyn@imendio.com> @@ -154,7 +154,7 @@ empathy_chatrooms_window_show (GtkWindow *parent) empathy_account_chooser_set_filter (EMPATHY_ACCOUNT_CHOOSER (window->account_chooser), empathy_account_chooser_filter_is_connected, NULL); - g_object_set (window->account_chooser, + g_object_set (window->account_chooser, "has-all-option", TRUE, NULL); empathy_account_chooser_set_account (EMPATHY_ACCOUNT_CHOOSER (window->account_chooser), NULL); @@ -222,7 +222,7 @@ chatrooms_window_model_setup (EmpathyChatroomsWindow *window) gtk_tree_view_set_model (view, GTK_TREE_MODEL (store)); - /* Selection */ + /* Selection */ selection = gtk_tree_view_get_selection (view); gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); @@ -273,8 +273,8 @@ chatrooms_window_model_add_columns (EmpathyChatroomsWindow *window) /* Room */ cell = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes (_("Room"), cell, - "text", COL_ROOM, + 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); @@ -293,7 +293,7 @@ chatrooms_window_model_add_columns (EmpathyChatroomsWindow *window) window); /* Sort model */ - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), 0, + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), 0, GTK_SORT_ASCENDING); } @@ -323,7 +323,7 @@ chatrooms_window_model_refresh_data (EmpathyChatroomsWindow *window, 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. + * selected protocol types, such as Jabber. */ if (account) { column = gtk_tree_view_get_column (view, window->room_column); diff --git a/src/empathy-chatrooms-window.h b/src/empathy-chatrooms-window.h index 727188f01..1d8476ecc 100644 --- a/src/empathy-chatrooms-window.h +++ b/src/empathy-chatrooms-window.h @@ -15,8 +15,8 @@ * * 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA * * Authors: Xavier Claessens <xclaesse@gmail.com> * Martyn Russell <martyn@imendio.com> diff --git a/src/empathy-event-manager.c b/src/empathy-event-manager.c index 7d8721c3e..81d98ef74 100644 --- a/src/empathy-event-manager.c +++ b/src/empathy-event-manager.c @@ -14,7 +14,7 @@ * 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> * Sjoerd Simons <sjoerd.simons@collabora.co.uk> */ @@ -373,8 +373,7 @@ event_channel_process_voip_func (EventPriv *event) return; } - dialog = gtk_message_dialog_new (GTK_WINDOW (empathy_main_window_get()), - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, _("Incoming call")); gtk_message_dialog_format_secondary_text ( GTK_MESSAGE_DIALOG (dialog), @@ -573,7 +572,7 @@ static void event_manager_tube_dispatch_ability_cb (GObject *object, GParamSpec *spec, gpointer user_data) { - EventManagerApproval *approval = (EventManagerApproval *)user_data; + EventManagerApproval *approval = (EventManagerApproval *) user_data; EmpathyTubeDispatchAbility dispatchability; dispatchability = @@ -594,7 +593,7 @@ event_manager_tube_got_contact_cb (EmpathyTpContactFactory *factory, gpointer user_data, GObject *object) { - EventManagerApproval *approval = (EventManagerApproval *)user_data; + EventManagerApproval *approval = (EventManagerApproval *) user_data; EmpathyTubeDispatchAbility dispatchability; if (error != NULL) @@ -753,6 +752,32 @@ event_manager_muc_invite_got_contact_cb (EmpathyTpContactFactory *factory, } static void +event_manager_ft_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *object) +{ + EventManagerApproval *approval = (EventManagerApproval *) user_data; + char *header; + + approval->contact = contact; + + header = g_strdup_printf (_("Incoming file transfer from %s"), + empathy_contact_get_name (approval->contact)); + + event_manager_add (approval->manager, approval->contact, + EMPATHY_IMAGE_DOCUMENT_SEND, header, NULL, approval, + event_channel_process_func, NULL); + + /* FIXME better sound for incoming file transfers ?*/ + empathy_sound_play (empathy_main_window_get (), + EMPATHY_SOUND_CONVERSATION_NEW); + + g_free (header); +} + +static void event_manager_approve_channel_cb (EmpathyDispatcher *dispatcher, EmpathyDispatchOperation *operation, EmpathyEventManager *manager) { @@ -840,26 +865,23 @@ event_manager_approve_channel_cb (EmpathyDispatcher *dispatcher, } else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER)) { - EmpathyTpFile *file; - gchar *header; - - file = EMPATHY_TP_FILE (empathy_dispatch_operation_get_channel_wrapper (operation)); - approval->contact = g_object_ref (empathy_tp_file_get_contact (file)); - - header = g_strdup_printf (_("Incoming file transfer from %s"), - empathy_contact_get_name (approval->contact)); + TpChannel *channel; + TpConnection *connection; + TpHandle handle; + EmpathyTpContactFactory *factory; - event_manager_add (manager, approval->contact, EMPATHY_IMAGE_DOCUMENT_SEND, - header, NULL, approval, event_channel_process_func, NULL); + channel = empathy_dispatch_operation_get_channel (operation); + handle = tp_channel_get_handle (channel, NULL); - /* FIXME better sound for incoming file transfers ?*/ - empathy_sound_play (empathy_main_window_get (), - EMPATHY_SOUND_CONVERSATION_NEW); + connection = tp_channel_borrow_connection (channel); + factory = empathy_tp_contact_factory_dup_singleton (connection); + empathy_tp_contact_factory_get_from_handle (factory, handle, + event_manager_ft_got_contact_cb, approval, NULL, G_OBJECT (manager)); - g_free (header); + g_object_unref (factory); } - else if (!tp_strdiff (channel_type, EMP_IFACE_CHANNEL_TYPE_STREAM_TUBE) || - !tp_strdiff (channel_type, EMP_IFACE_CHANNEL_TYPE_DBUS_TUBE)) + else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE) || + !tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE)) { TpChannel *channel; TpHandle handle; @@ -882,7 +904,7 @@ event_manager_approve_channel_cb (EmpathyDispatcher *dispatcher, } else { - DEBUG ("Unknown channel type, ignoring.."); + DEBUG ("Unknown channel type (%s), ignoring..", channel_type); } } @@ -1054,7 +1076,7 @@ empathy_event_manager_get_top_event (EmpathyEventManager *manager) void empathy_event_activate (EmpathyEvent *event_public) { - EventPriv *event = (EventPriv*) event_public; + EventPriv *event = (EventPriv *) event_public; g_return_if_fail (event_public != NULL); diff --git a/src/empathy-ft-manager.c b/src/empathy-ft-manager.c index 98e58d4f3..bc4f2a7b7 100644 --- a/src/empathy-ft-manager.c +++ b/src/empathy-ft-manager.c @@ -1,8 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2003, 2004 Xan Lopez * Copyright (C) 2007 Marco Barisione <marco@barisione.org> - * Copyright (C) 2008 Collabora Ltd. + * Copyright (C) 2008-2009 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 @@ -16,13 +15,14 @@ * * 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA * * Authors: Xan Lopez * Marco Barisione <marco@barisione.org> * Jonny Lamb <jonny.lamb@collabora.co.uk> * Xavier Claessens <xclaesse@gmail.com> + * Cosimo Cecchi <cosimo.cecchi@collabora.co.uk> */ /* The original file transfer manager code was copied from Epiphany */ @@ -46,19 +46,6 @@ #include "empathy-ft-manager.h" -#include "extensions/extensions.h" - -/** - * SECTION:empathy-ft-manager - * @short_description: File transfer dialog - * @see_also: #EmpathyTpFile, empathy_dispatcher_send_file() - * @include: libempthy-gtk/empathy-ft-manager.h - * - * The #EmpathyFTManager object represents the file transfer dialog, - * it can show multiple file transfers at the same time (added - * with empathy_ft_manager_add_tp_file()). - */ - enum { COL_PERCENT, @@ -68,24 +55,19 @@ enum COL_FT_OBJECT }; -/** - * EmpathyFTManagerPriv: - * - * Private fields of the #EmpathyFTManager class. - */ -struct _EmpathyFTManagerPriv -{ +typedef struct { GtkTreeModel *model; - GHashTable *tp_file_to_row_ref; + GHashTable *ft_handler_to_row_ref; /* Widgets */ GtkWidget *window; GtkWidget *treeview; GtkWidget *open_button; GtkWidget *abort_button; + GtkWidget *clear_button; guint save_geometry_id; -}; +} EmpathyFTManagerPriv; enum { @@ -96,10 +78,15 @@ enum G_DEFINE_TYPE (EmpathyFTManager, empathy_ft_manager, G_TYPE_OBJECT); +#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyFTManager) + static EmpathyFTManager *manager_singleton = NULL; +static void ft_handler_hashing_started_cb (EmpathyFTHandler *handler, + EmpathyFTManager *manager); + static gchar * -ft_manager_format_interval (gint interval) +ft_manager_format_interval (guint interval) { gint hours, mins, secs; @@ -117,235 +104,62 @@ ft_manager_format_interval (gint interval) return g_strdup_printf (_("%02u.%02u"), mins, secs); } -static GtkTreeRowReference * -ft_manager_get_row_from_tp_file (EmpathyFTManager *ft_manager, - EmpathyTpFile *tp_file) -{ - return g_hash_table_lookup (ft_manager->priv->tp_file_to_row_ref, tp_file); -} - static void -ft_manager_update_buttons (EmpathyFTManager *ft_manager) +ft_manager_update_buttons (EmpathyFTManager *manager) { GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; - EmpathyTpFile *tp_file; - TpFileTransferState state; + EmpathyFTHandler *handler; gboolean open_enabled = FALSE; gboolean abort_enabled = FALSE; + gboolean clear_enabled = FALSE; + gboolean is_completed, is_cancelled; + GHashTableIter hash_iter; + EmpathyFTManagerPriv *priv = GET_PRIV (manager); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview)); - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW ( - ft_manager->priv->treeview)); if (gtk_tree_selection_get_selected (selection, &model, &iter)) { - gtk_tree_model_get (model, &iter, COL_FT_OBJECT, &tp_file, -1); - state = empathy_tp_file_get_state (tp_file, NULL); + gtk_tree_model_get (model, &iter, COL_FT_OBJECT, &handler, -1); + + is_completed = empathy_ft_handler_is_completed (handler); + is_cancelled = empathy_ft_handler_is_cancelled (handler); /* I can open the file if the transfer is completed and was incoming */ - open_enabled = (state == TP_FILE_TRANSFER_STATE_COMPLETED && - empathy_tp_file_is_incoming (tp_file)); + open_enabled = (is_completed && empathy_ft_handler_is_incoming (handler)); /* I can abort if the transfer is not already finished */ - abort_enabled = (state != TP_FILE_TRANSFER_STATE_CANCELLED && - state != TP_FILE_TRANSFER_STATE_COMPLETED); + abort_enabled = (is_cancelled == FALSE && is_completed == FALSE); - g_object_unref (tp_file); + g_object_unref (handler); } - gtk_widget_set_sensitive (ft_manager->priv->open_button, open_enabled); - gtk_widget_set_sensitive (ft_manager->priv->abort_button, abort_enabled); -} + g_hash_table_iter_init (&hash_iter, priv->ft_handler_to_row_ref); -static const gchar * -ft_manager_state_change_reason_to_string (TpFileTransferStateChangeReason reason) -{ - switch (reason) + while (g_hash_table_iter_next (&hash_iter, (gpointer *) &handler, NULL)) { - case TP_FILE_TRANSFER_STATE_CHANGE_REASON_NONE: - return _("No reason was specified"); - case TP_FILE_TRANSFER_STATE_CHANGE_REASON_REQUESTED: - return _("The change in state was requested"); - case TP_FILE_TRANSFER_STATE_CHANGE_REASON_LOCAL_STOPPED: - return _("You canceled the file transfer"); - case TP_FILE_TRANSFER_STATE_CHANGE_REASON_REMOTE_STOPPED: - return _("The other participant canceled the file transfer"); - case TP_FILE_TRANSFER_STATE_CHANGE_REASON_LOCAL_ERROR: - return _("Error while trying to transfer the file"); - case TP_FILE_TRANSFER_STATE_CHANGE_REASON_REMOTE_ERROR: - return _("The other participant is unable to transfer the file"); - } - return _("Unknown reason"); -} - -static void -ft_manager_update_ft_row (EmpathyFTManager *ft_manager, - EmpathyTpFile *tp_file) -{ - GtkTreeRowReference *row_ref; - GtkTreePath *path; - GtkTreeIter iter; - const gchar *filename; - const gchar *contact_name; - const gchar *msg; - gchar *msg_dup = NULL; - gchar *remaining_str = NULL; - gchar *first_line_format; - gchar *first_line = NULL; - gchar *second_line = NULL; - guint64 transferred_bytes; - guint64 total_size; - gint remaining = -1; - gint percent; - TpFileTransferState state; - TpFileTransferStateChangeReason reason; - gboolean incoming; - - row_ref = ft_manager_get_row_from_tp_file (ft_manager, tp_file); - g_return_if_fail (row_ref != NULL); - - filename = empathy_tp_file_get_filename (tp_file); - contact_name = empathy_contact_get_name (empathy_tp_file_get_contact (tp_file)); - transferred_bytes = empathy_tp_file_get_transferred_bytes (tp_file); - total_size = empathy_tp_file_get_size (tp_file); - state = empathy_tp_file_get_state (tp_file, &reason); - incoming = empathy_tp_file_is_incoming (tp_file); + if (empathy_ft_handler_is_completed (handler) || + empathy_ft_handler_is_cancelled (handler)) + clear_enabled = TRUE; - switch (state) - { - case TP_FILE_TRANSFER_STATE_NONE: - /* This should never happen, the CM is broken. But we avoid warning - * because it's not our fault. */ - DEBUG ("State is NONE, probably a broken CM"); + if (clear_enabled) break; - case TP_FILE_TRANSFER_STATE_PENDING: - case TP_FILE_TRANSFER_STATE_OPEN: - case TP_FILE_TRANSFER_STATE_ACCEPTED: - if (incoming) - /* translators: first %s is filename, second %s is the contact name */ - first_line_format = _("Receiving \"%s\" from %s"); - else - /* translators: first %s is filename, second %s is the contact name */ - first_line_format = _("Sending \"%s\" to %s"); - - first_line = g_strdup_printf (first_line_format, filename, contact_name); - - if (state == TP_FILE_TRANSFER_STATE_OPEN || incoming) - { - gchar *total_size_str; - gchar *transferred_bytes_str; - - if (total_size == EMPATHY_TP_FILE_UNKNOWN_SIZE) - total_size_str = g_strdup (C_("file size", "Unknown")); - else - total_size_str = g_format_size_for_display (total_size); - - transferred_bytes_str = g_format_size_for_display (transferred_bytes); - - /* translators: first %s is the transferred size, second %s is - * the total file size */ - second_line = g_strdup_printf (_("%s of %s"), transferred_bytes_str, - total_size_str); - g_free (transferred_bytes_str); - g_free (total_size_str); - - } - else - second_line = g_strdup (_("Waiting for the other participant's response")); - - remaining = empathy_tp_file_get_remaining_time (tp_file); - break; - - case TP_FILE_TRANSFER_STATE_COMPLETED: - if (incoming) - /* translators: first %s is filename, second %s - * is the contact name */ - first_line = g_strdup_printf ( - _("\"%s\" received from %s"), filename, - contact_name); - else - /* translators: first %s is filename, second %s - * is the contact name */ - first_line = g_strdup_printf ( - _("\"%s\" sent to %s"), filename, - contact_name); - - second_line = g_strdup (_("File transfer completed")); - - break; - - case TP_FILE_TRANSFER_STATE_CANCELLED: - if (incoming) - /* translators: first %s is filename, second %s - * is the contact name */ - first_line = g_strdup_printf ( - _("\"%s\" receiving from %s"), filename, - contact_name); - else - /* translators: first %s is filename, second %s - * is the contact name */ - first_line = g_strdup_printf ( - _("\"%s\" sending to %s"), filename, - contact_name); - - second_line = g_strdup_printf (_("File transfer canceled: %s"), - ft_manager_state_change_reason_to_string (reason)); - - break; - } - - if (total_size != EMPATHY_TP_FILE_UNKNOWN_SIZE && total_size != 0) - percent = transferred_bytes * 100 / total_size; - else - percent = -1; - - if (remaining < 0) - { - if (state != TP_FILE_TRANSFER_STATE_COMPLETED && - state != TP_FILE_TRANSFER_STATE_CANCELLED) - remaining_str = g_strdup (C_("remaining time", "Unknown")); } - else - remaining_str = ft_manager_format_interval (remaining); - - if (first_line != NULL && second_line != NULL) - msg = msg_dup = g_strdup_printf ("%s\n%s", first_line, second_line); - else - msg = first_line ? first_line : second_line; - - /* Set new values in the store */ - path = gtk_tree_row_reference_get_path (row_ref); - gtk_tree_model_get_iter (ft_manager->priv->model, &iter, path); - gtk_list_store_set (GTK_LIST_STORE (ft_manager->priv->model), - &iter, - COL_PERCENT, percent, - COL_MESSAGE, msg ? msg : "", - COL_REMAINING, remaining_str ? remaining_str : "", - -1); - - gtk_tree_path_free (path); - - g_free (msg_dup); - g_free (first_line); - g_free (second_line); - g_free (remaining_str); - ft_manager_update_buttons (ft_manager); -} + gtk_widget_set_sensitive (priv->open_button, open_enabled); + gtk_widget_set_sensitive (priv->abort_button, abort_enabled); -static void -ft_manager_transferred_bytes_changed_cb (EmpathyTpFile *tp_file, - GParamSpec *pspec, - EmpathyFTManager *ft_manager) -{ - ft_manager_update_ft_row (ft_manager, tp_file); + if (clear_enabled) + gtk_widget_set_sensitive (priv->clear_button, TRUE); } static void ft_manager_selection_changed (GtkTreeSelection *selection, - EmpathyFTManager *ft_manager) + EmpathyFTManager *manager) { - ft_manager_update_buttons (ft_manager); + ft_manager_update_buttons (manager); } static void @@ -369,79 +183,57 @@ ft_manager_progress_cell_data_func (GtkTreeViewColumn *col, g_object_set (renderer, "text", text, "value", percent, NULL); } -static gboolean -ft_manager_save_geometry_timeout_cb (EmpathyFTManager *ft_manager) -{ - gint x, y, w, h; - - gtk_window_get_size (GTK_WINDOW (ft_manager->priv->window), &w, &h); - gtk_window_get_position (GTK_WINDOW (ft_manager->priv->window), &x, &y); - - empathy_geometry_save ("ft-manager", x, y, w, h); - - ft_manager->priv->save_geometry_id = 0; - - return FALSE; -} - -static gboolean -ft_manager_configure_event_cb (GtkWidget *widget, - GdkEventConfigure *event, - EmpathyFTManager *ft_manager) +static GtkTreeRowReference * +ft_manager_get_row_from_handler (EmpathyFTManager *manager, + EmpathyFTHandler *handler) { - if (ft_manager->priv->save_geometry_id != 0) - g_source_remove (ft_manager->priv->save_geometry_id); + EmpathyFTManagerPriv *priv = GET_PRIV (manager); - ft_manager->priv->save_geometry_id = g_timeout_add (500, - (GSourceFunc) ft_manager_save_geometry_timeout_cb, ft_manager); - - return FALSE; + return g_hash_table_lookup (priv->ft_handler_to_row_ref, handler); } static void -ft_manager_remove_file_from_model (EmpathyFTManager *ft_manager, - EmpathyTpFile *tp_file) +ft_manager_remove_file_from_model (EmpathyFTManager *manager, + EmpathyFTHandler *handler) { GtkTreeRowReference *row_ref; GtkTreeSelection *selection; GtkTreePath *path = NULL; GtkTreeIter iter; gboolean update_selection; + EmpathyFTManagerPriv *priv = GET_PRIV (manager); - row_ref = ft_manager_get_row_from_tp_file (ft_manager, tp_file); + row_ref = ft_manager_get_row_from_handler (manager, handler); g_return_if_fail (row_ref); DEBUG ("Removing file transfer from window: contact=%s, filename=%s", - empathy_contact_get_name (empathy_tp_file_get_contact (tp_file)), - empathy_tp_file_get_filename (tp_file)); + empathy_contact_get_name (empathy_ft_handler_get_contact (handler)), + empathy_ft_handler_get_filename (handler)); /* Get the iter from the row_ref */ path = gtk_tree_row_reference_get_path (row_ref); - gtk_tree_model_get_iter (ft_manager->priv->model, &iter, path); + gtk_tree_model_get_iter (priv->model, &iter, path); gtk_tree_path_free (path); /* We have to update the selection only if we are removing the selected row */ - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ft_manager->priv->treeview)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview)); update_selection = gtk_tree_selection_iter_is_selected (selection, &iter); /* Remove tp_file's row. After that iter points to the next row */ - if (!gtk_list_store_remove (GTK_LIST_STORE (ft_manager->priv->model), &iter)) + if (!gtk_list_store_remove (GTK_LIST_STORE (priv->model), &iter)) { gint n_row; /* There is no next row, set iter to the last row */ - n_row = gtk_tree_model_iter_n_children (ft_manager->priv->model, NULL); + n_row = gtk_tree_model_iter_n_children (priv->model, NULL); if (n_row > 0) - gtk_tree_model_iter_nth_child (ft_manager->priv->model, &iter, NULL, - n_row - 1); + gtk_tree_model_iter_nth_child (priv->model, &iter, NULL, n_row - 1); else update_selection = FALSE; } if (update_selection) gtk_tree_selection_select_iter (selection, &iter); - - empathy_tp_file_close (tp_file); } static gboolean @@ -449,113 +241,679 @@ remove_finished_transfer_foreach (gpointer key, gpointer value, gpointer user_data) { - EmpathyTpFile *tp_file = EMPATHY_TP_FILE (key); - EmpathyFTManager *self = EMPATHY_FT_MANAGER (user_data); - TpFileTransferState state; + EmpathyFTHandler *handler = key; + EmpathyFTManager *manager = user_data; - state = empathy_tp_file_get_state (tp_file, NULL); - if (state == TP_FILE_TRANSFER_STATE_COMPLETED || - state == TP_FILE_TRANSFER_STATE_CANCELLED) + if (empathy_ft_handler_is_completed (handler) || + empathy_ft_handler_is_cancelled (handler)) { - ft_manager_remove_file_from_model (self, tp_file); + ft_manager_remove_file_from_model (manager, handler); return TRUE; } return FALSE; } +static gchar * +ft_manager_format_progress_bytes_and_percentage (guint64 current, + guint64 total, + gdouble speed, + int *percentage) +{ + char *total_str, *current_str, *retval; + char *speed_str = NULL; + + total_str = g_format_size_for_display (total); + current_str = g_format_size_for_display (current); + + if (speed > 0) + speed_str = g_format_size_for_display ((goffset) speed); + + /* translators: first %s is the currently processed size, second %s is + * the total file size */ + retval = speed_str ? + g_strdup_printf (_("%s of %s at %s/s"), current_str, total_str, speed_str) : + g_strdup_printf (_("%s of %s"), current_str, total_str); + + g_free (total_str); + g_free (current_str); + g_free (speed_str); + + if (percentage != NULL) + { + if (total != 0) + *percentage = current * 100 / total; + else + *percentage = -1; + } + + return retval; +} + +static gchar * +ft_manager_format_contact_info (EmpathyFTHandler *handler) +{ + gboolean incoming; + const char *filename, *contact_name, *first_line_format; + char *retval; + + incoming = empathy_ft_handler_is_incoming (handler); + contact_name = empathy_contact_get_name + (empathy_ft_handler_get_contact (handler)); + filename = empathy_ft_handler_get_filename (handler); + + if (incoming) + /* translators: first %s is filename, second %s is the contact name */ + first_line_format = _("Receiving \"%s\" from %s"); + else + /* translators: first %s is filename, second %s is the contact name */ + first_line_format = _("Sending \"%s\" to %s"); + + retval = g_strdup_printf (first_line_format, filename, contact_name); + + return retval; +} + +static gchar * +ft_manager_format_error_message (EmpathyFTHandler *handler, + const GError *error) +{ + const char *contact_name, *filename; + EmpathyContact *contact; + char *first_line, *message; + gboolean incoming; + + contact_name = NULL; + incoming = empathy_ft_handler_is_incoming (handler); + + contact = empathy_ft_handler_get_contact (handler); + if (contact) + contact_name = empathy_contact_get_name (contact); + + filename = empathy_ft_handler_get_filename (handler); + + if (incoming) + /* filename/contact_name here are either both NULL or both valid */ + if (filename && contact_name) + /* translators: first %s is filename, second %s + * is the contact name */ + first_line = g_strdup_printf (_("Error receiving \"%s\" from %s"), filename, + contact_name); + else + first_line = g_strdup (_("Error receiving a file")); + else + /* translators: first %s is filename, second %s + * is the contact name */ + if (filename && contact_name) + first_line = g_strdup_printf (_("Error sending \"%s\" to %s"), filename, + contact_name); + else + first_line = g_strdup (_("Error sending a file")); + + message = g_strdup_printf ("%s\n%s", first_line, error->message); + + g_free (first_line); + + return message; +} + +static void +ft_manager_update_handler_message (EmpathyFTManager *manager, + GtkTreeRowReference *row_ref, + const char *message) +{ + GtkTreePath *path; + GtkTreeIter iter; + EmpathyFTManagerPriv *priv = GET_PRIV (manager); + + /* Set new value in the store */ + path = gtk_tree_row_reference_get_path (row_ref); + gtk_tree_model_get_iter (priv->model, &iter, path); + gtk_list_store_set (GTK_LIST_STORE (priv->model), + &iter, + COL_MESSAGE, message ? message : "", + -1); + + gtk_tree_path_free (path); +} + +static void +ft_manager_update_handler_progress (EmpathyFTManager *manager, + GtkTreeRowReference *row_ref, + int percentage) +{ + GtkTreePath *path; + GtkTreeIter iter; + EmpathyFTManagerPriv *priv = GET_PRIV (manager); + + /* Set new value in the store */ + path = gtk_tree_row_reference_get_path (row_ref); + gtk_tree_model_get_iter (priv->model, &iter, path); + gtk_list_store_set (GTK_LIST_STORE (priv->model), + &iter, + COL_PERCENT, percentage, + -1); + + gtk_tree_path_free (path); + +} + +static void +ft_manager_update_handler_time (EmpathyFTManager *manager, + GtkTreeRowReference *row_ref, + guint remaining_time) +{ + GtkTreePath *path; + GtkTreeIter iter; + EmpathyFTManagerPriv *priv = GET_PRIV (manager); + char *remaining_str; + + remaining_str = ft_manager_format_interval (remaining_time); + + /* Set new value in the store */ + path = gtk_tree_row_reference_get_path (row_ref); + gtk_tree_model_get_iter (priv->model, &iter, path); + gtk_list_store_set (GTK_LIST_STORE (priv->model), + &iter, + COL_REMAINING, remaining_str, + -1); + + gtk_tree_path_free (path); + g_free (remaining_str); +} + +static void +ft_manager_clear_handler_time (EmpathyFTManager *manager, + GtkTreeRowReference *row_ref) +{ + GtkTreePath *path; + GtkTreeIter iter; + EmpathyFTManagerPriv *priv = GET_PRIV (manager); + + /* Set new value in the store */ + path = gtk_tree_row_reference_get_path (row_ref); + gtk_tree_model_get_iter (priv->model, &iter, path); + gtk_list_store_set (GTK_LIST_STORE (priv->model), + &iter, + COL_REMAINING, NULL, + -1); + + gtk_tree_path_free (path); +} + +static void +ft_handler_transfer_error_cb (EmpathyFTHandler *handler, + GError *error, + EmpathyFTManager *manager) +{ + char *message; + GtkTreeRowReference *row_ref; + + DEBUG ("Transfer error %s", error->message); + + row_ref = ft_manager_get_row_from_handler (manager, handler); + g_return_if_fail (row_ref != NULL); + + message = ft_manager_format_error_message (handler, error); + + ft_manager_update_handler_message (manager, row_ref, message); + ft_manager_clear_handler_time (manager, row_ref); + ft_manager_update_buttons (manager); + + g_free (message); +} + +static void +do_real_transfer_done (EmpathyFTManager *manager, + EmpathyFTHandler *handler) +{ + const char *contact_name; + const char *filename; + char *first_line, *second_line, *message; + char *uri; + gboolean incoming; + GtkTreeRowReference *row_ref; + GtkRecentManager *recent_manager; + GFile *file; + + row_ref = ft_manager_get_row_from_handler (manager, handler); + g_return_if_fail (row_ref != NULL); + + incoming = empathy_ft_handler_is_incoming (handler); + contact_name = empathy_contact_get_name + (empathy_ft_handler_get_contact (handler)); + filename = empathy_ft_handler_get_filename (handler); + + if (incoming) + /* translators: first %s is filename, second %s + * is the contact name */ + first_line = g_strdup_printf (_("\"%s\" received from %s"), filename, + contact_name); + else + /* translators: first %s is filename, second %s + * is the contact name */ + first_line = g_strdup_printf (_("\"%s\" sent to %s"), filename, + contact_name); + + second_line = g_strdup (_("File transfer completed")); + + message = g_strdup_printf ("%s\n%s", first_line, second_line); + ft_manager_update_handler_message (manager, row_ref, message); + ft_manager_clear_handler_time (manager, row_ref); + + /* update buttons */ + ft_manager_update_buttons (manager); + + g_free (message); + g_free (first_line); + g_free (second_line); + + recent_manager = gtk_recent_manager_get_default (); + file = empathy_ft_handler_get_gfile (handler); + uri = g_file_get_uri (file); + + gtk_recent_manager_add_item (recent_manager, uri); + + g_free (uri); +} + +static void +ft_handler_transfer_done_cb (EmpathyFTHandler *handler, + EmpathyTpFile *tp_file, + EmpathyFTManager *manager) +{ + if (empathy_ft_handler_is_incoming (handler) && + empathy_ft_handler_get_use_hash (handler)) + { + DEBUG ("Transfer done, waiting for hashing-started"); + + /* connect to the signal and return early */ + g_signal_connect (handler, "hashing-started", + G_CALLBACK (ft_handler_hashing_started_cb), manager); + + return; + } + + DEBUG ("Transfer done, no hashing"); + + do_real_transfer_done (manager, handler); +} + +static void +ft_handler_transfer_progress_cb (EmpathyFTHandler *handler, + guint64 current_bytes, + guint64 total_bytes, + guint remaining_time, + gdouble speed, + EmpathyFTManager *manager) +{ + char *first_line, *second_line, *message; + int percentage; + GtkTreeRowReference *row_ref; + + DEBUG ("Transfer progress"); + + row_ref = ft_manager_get_row_from_handler (manager, handler); + g_return_if_fail (row_ref != NULL); + + first_line = ft_manager_format_contact_info (handler); + second_line = ft_manager_format_progress_bytes_and_percentage + (current_bytes, total_bytes, speed, &percentage); + + message = g_strdup_printf ("%s\n%s", first_line, second_line); + + ft_manager_update_handler_message (manager, row_ref, message); + ft_manager_update_handler_progress (manager, row_ref, percentage); + + if (remaining_time > 0) + ft_manager_update_handler_time (manager, row_ref, remaining_time); + + g_free (message); + g_free (first_line); + g_free (second_line); +} + +static void +ft_handler_transfer_started_cb (EmpathyFTHandler *handler, + EmpathyTpFile *tp_file, + EmpathyFTManager *manager) +{ + guint64 transferred_bytes, total_bytes; + + DEBUG ("Transfer started"); + + g_signal_connect (handler, "transfer-progress", + G_CALLBACK (ft_handler_transfer_progress_cb), manager); + g_signal_connect (handler, "transfer-done", + G_CALLBACK (ft_handler_transfer_done_cb), manager); + + transferred_bytes = empathy_ft_handler_get_transferred_bytes (handler); + total_bytes = empathy_ft_handler_get_total_bytes (handler); + + ft_handler_transfer_progress_cb (handler, transferred_bytes, total_bytes, + 0, -1, manager); +} + +static void +ft_handler_hashing_done_cb (EmpathyFTHandler *handler, + EmpathyFTManager *manager) +{ + GtkTreeRowReference *row_ref; + char *first_line, *second_line, *message; + + DEBUG ("Hashing done"); + + /* update the message */ + if (empathy_ft_handler_is_incoming (handler)) + { + do_real_transfer_done (manager, handler); + return; + } + + row_ref = ft_manager_get_row_from_handler (manager, handler); + g_return_if_fail (row_ref != NULL); + + first_line = ft_manager_format_contact_info (handler); + second_line = g_strdup (_("Waiting for the other participant's response")); + message = g_strdup_printf ("%s\n%s", first_line, second_line); + + ft_manager_update_handler_message (manager, row_ref, message); + + g_free (message); + g_free (first_line); + g_free (second_line); + + g_signal_connect (handler, "transfer-started", + G_CALLBACK (ft_handler_transfer_started_cb), manager); +} + +static void +ft_handler_hashing_progress_cb (EmpathyFTHandler *handler, + guint64 current_bytes, + guint64 total_bytes, + EmpathyFTManager *manager) +{ + char *first_line, *second_line, *message; + GtkTreeRowReference *row_ref; + + row_ref = ft_manager_get_row_from_handler (manager, handler); + g_return_if_fail (row_ref != NULL); + + if (empathy_ft_handler_is_incoming (handler)) + first_line = g_strdup_printf (_("Checking integrity of \"%s\""), + empathy_ft_handler_get_filename (handler)); + else + first_line = g_strdup_printf (_("Hashing \"%s\""), + empathy_ft_handler_get_filename (handler)); + + second_line = ft_manager_format_progress_bytes_and_percentage + (current_bytes, total_bytes, -1, NULL); + + message = g_strdup_printf ("%s\n%s", first_line, second_line); + + ft_manager_update_handler_message (manager, row_ref, message); + + g_free (message); + g_free (first_line); + g_free (second_line); +} + +static void +ft_handler_hashing_started_cb (EmpathyFTHandler *handler, + EmpathyFTManager *manager) +{ + char *message, *first_line, *second_line; + GtkTreeRowReference *row_ref; + + DEBUG ("Hashing started"); + + g_signal_connect (handler, "hashing-progress", + G_CALLBACK (ft_handler_hashing_progress_cb), manager); + g_signal_connect (handler, "hashing-done", + G_CALLBACK (ft_handler_hashing_done_cb), manager); + + row_ref = ft_manager_get_row_from_handler (manager, handler); + g_return_if_fail (row_ref != NULL); + + first_line = ft_manager_format_contact_info (handler); + + if (empathy_ft_handler_is_incoming (handler)) + second_line = g_strdup_printf (_("Checking integrity of \"%s\""), + empathy_ft_handler_get_filename (handler)); + else + second_line = g_strdup_printf (_("Hashing \"%s\""), + empathy_ft_handler_get_filename (handler)); + + message = g_strdup_printf ("%s\n%s", first_line, second_line); + + ft_manager_update_handler_message (manager, row_ref, message); + + g_free (first_line); + g_free (second_line); + g_free (message); +} + static void -ft_manager_state_changed_cb (EmpathyTpFile *tp_file, - GParamSpec *pspec, - EmpathyFTManager *ft_manager) +ft_manager_start_transfer (EmpathyFTManager *manager, + EmpathyFTHandler *handler) { - if (empathy_tp_file_get_state (tp_file, NULL) == - TP_FILE_TRANSFER_STATE_COMPLETED) + EmpathyFTManagerPriv *priv; + gboolean is_outgoing; + + priv = GET_PRIV (manager); + + is_outgoing = !empathy_ft_handler_is_incoming (handler); + + DEBUG ("Start transfer, is outgoing %s", + is_outgoing ? "True" : "False"); + + /* now connect the signals */ + g_signal_connect (handler, "transfer-error", + G_CALLBACK (ft_handler_transfer_error_cb), manager); + + if (is_outgoing && empathy_ft_handler_get_use_hash (handler)) { + g_signal_connect (handler, "hashing-started", + G_CALLBACK (ft_handler_hashing_started_cb), manager); + } else { + /* either incoming or outgoing without hash */ + g_signal_connect (handler, "transfer-started", + G_CALLBACK (ft_handler_transfer_started_cb), manager); + } + + empathy_ft_handler_start_transfer (handler); +} + +static void +ft_manager_add_handler_to_list (EmpathyFTManager *manager, + EmpathyFTHandler *handler, + const GError *error) +{ + GtkTreeRowReference *row_ref; + GtkTreeIter iter; + GtkTreeSelection *selection; + GtkTreePath *path; + GIcon *icon; + const char *content_type, *second_line; + char *first_line, *message; + EmpathyFTManagerPriv *priv = GET_PRIV (manager); + + icon = NULL; + + /* get the icon name from the mime-type of the file. */ + content_type = empathy_ft_handler_get_content_type (handler); + + if (content_type != NULL) + icon = g_content_type_get_icon (content_type); + + /* append the handler in the store */ + gtk_list_store_insert_with_values (GTK_LIST_STORE (priv->model), + &iter, G_MAXINT, COL_FT_OBJECT, handler, + COL_ICON, icon, -1); + + if (icon != NULL) + g_object_unref (icon); + + /* insert the new row_ref in the hash table */ + path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->model), &iter); + row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (priv->model), path); + gtk_tree_path_free (path); + g_hash_table_insert (priv->ft_handler_to_row_ref, g_object_ref (handler), + row_ref); + + /* select the new row */ + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview)); + gtk_tree_selection_select_iter (selection, &iter); + + if (error != NULL) { - GtkRecentManager *manager; - const gchar *uri; + message = ft_manager_format_error_message (handler, error); + ft_manager_update_handler_message (manager, row_ref, message); - manager = gtk_recent_manager_get_default (); - uri = g_object_get_data (G_OBJECT (tp_file), "uri"); - if (uri != NULL) - gtk_recent_manager_add_item (manager, uri); + g_free (message); + return; } - ft_manager_update_ft_row (ft_manager, tp_file); + /* update the row with the initial values. + * the only case where we postpone this is in case we're managing + * an outgoing+hashing transfer, as the hashing started signal will + * take care of updating the information. + */ + if (empathy_ft_handler_is_incoming (handler) || + !empathy_ft_handler_get_use_hash (handler)) { + first_line = ft_manager_format_contact_info (handler); + second_line = _("Waiting for the other participant's response"); + message = g_strdup_printf ("%s\n%s", first_line, second_line); + + ft_manager_update_handler_message (manager, row_ref, message); + + g_free (first_line); + g_free (message); + } + + /* hook up the signals and start the transfer */ + ft_manager_start_transfer (manager, handler); } static void -ft_manager_clear (EmpathyFTManager *ft_manager) +ft_manager_clear (EmpathyFTManager *manager) { + EmpathyFTManagerPriv *priv; + DEBUG ("Clearing file transfer list"); + priv = GET_PRIV (manager); + /* Remove completed and cancelled transfers */ - g_hash_table_foreach_remove (ft_manager->priv->tp_file_to_row_ref, - remove_finished_transfer_foreach, ft_manager); + g_hash_table_foreach_remove (priv->ft_handler_to_row_ref, + remove_finished_transfer_foreach, manager); + + /* set the clear button back to insensitive */ + gtk_widget_set_sensitive (priv->clear_button, FALSE); } static void -ft_manager_open (EmpathyFTManager *ft_manager) +ft_manager_open (EmpathyFTManager *manager) { GtkTreeSelection *selection; GtkTreeIter iter; GtkTreeModel *model; - EmpathyTpFile *tp_file; - const gchar *uri; + EmpathyFTHandler *handler; + char *uri; + GFile *file; + EmpathyFTManagerPriv *priv = GET_PRIV (manager); - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ft_manager->priv->treeview)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview)); if (!gtk_tree_selection_get_selected (selection, &model, &iter)) return; - gtk_tree_model_get (model, &iter, COL_FT_OBJECT, &tp_file, -1); - g_return_if_fail (tp_file != NULL); + gtk_tree_model_get (model, &iter, COL_FT_OBJECT, &handler, -1); + + file = empathy_ft_handler_get_gfile (handler); + uri = g_file_get_uri (file); - uri = g_object_get_data (G_OBJECT (tp_file), "uri"); DEBUG ("Opening URI: %s", uri); - empathy_url_show (GTK_WIDGET (ft_manager->priv->window), uri); - g_object_unref (tp_file); + empathy_url_show (GTK_WIDGET (priv->window), uri); + + g_object_unref (handler); + g_free (uri); } static void -ft_manager_stop (EmpathyFTManager *ft_manager) +ft_manager_stop (EmpathyFTManager *manager) { GtkTreeSelection *selection; GtkTreeIter iter; GtkTreeModel *model; - EmpathyTpFile *tp_file; + EmpathyFTHandler *handler; + EmpathyFTManagerPriv *priv; + + priv = GET_PRIV (manager); - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ft_manager->priv->treeview)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview)); if (!gtk_tree_selection_get_selected (selection, &model, &iter)) return; - gtk_tree_model_get (model, &iter, COL_FT_OBJECT, &tp_file, -1); - g_return_if_fail (tp_file != NULL); + gtk_tree_model_get (model, &iter, COL_FT_OBJECT, &handler, -1); + g_return_if_fail (handler != NULL); DEBUG ("Stopping file transfer: contact=%s, filename=%s", - empathy_contact_get_name (empathy_tp_file_get_contact (tp_file)), - empathy_tp_file_get_filename (tp_file)); + empathy_contact_get_name (empathy_ft_handler_get_contact (handler)), + empathy_ft_handler_get_filename (handler)); - empathy_tp_file_cancel (tp_file); - g_object_unref (tp_file); + empathy_ft_handler_cancel_transfer (handler); + + g_object_unref (handler); +} + +static gboolean +ft_manager_save_geometry_timeout_cb (EmpathyFTManager *manager) +{ + EmpathyFTManagerPriv *priv = GET_PRIV (manager); + gint x, y, w, h; + + gtk_window_get_size (GTK_WINDOW (priv->window), &w, &h); + gtk_window_get_position (GTK_WINDOW (priv->window), &x, &y); + + empathy_geometry_save ("ft-manager", x, y, w, h); + + priv->save_geometry_id = 0; + + return FALSE; +} + +static gboolean +ft_manager_configure_event_cb (GtkWidget *widget, + GdkEventConfigure *event, + EmpathyFTManager *manager) +{ + EmpathyFTManagerPriv *priv = GET_PRIV (manager); + + if (priv->save_geometry_id != 0) + g_source_remove (priv->save_geometry_id); + + priv->save_geometry_id = g_timeout_add (500, + (GSourceFunc) ft_manager_save_geometry_timeout_cb, manager); + + return FALSE; } static void ft_manager_response_cb (GtkWidget *widget, gint response, - EmpathyFTManager *ft_manager) + EmpathyFTManager *manager) { switch (response) { case RESPONSE_CLEAR: - ft_manager_clear (ft_manager); + ft_manager_clear (manager); break; case RESPONSE_OPEN: - ft_manager_open (ft_manager); + ft_manager_open (manager); break; case RESPONSE_STOP: - ft_manager_stop (ft_manager); + ft_manager_stop (manager); break; } } @@ -563,10 +921,16 @@ ft_manager_response_cb (GtkWidget *widget, static gboolean ft_manager_delete_event_cb (GtkWidget *widget, GdkEvent *event, - EmpathyFTManager *ft_manager) + EmpathyFTManager *manager) { - ft_manager_clear (ft_manager); - if (g_hash_table_size (ft_manager->priv->tp_file_to_row_ref) > 0) + EmpathyFTManagerPriv *priv = GET_PRIV (manager); + + DEBUG ("%p", manager); + + /* remove all the completed/cancelled/errored transfers */ + ft_manager_clear (manager); + + if (g_hash_table_size (priv->ft_handler_to_row_ref) > 0) { /* There is still FTs on flight, just hide the window */ DEBUG ("Hiding window"); @@ -579,16 +943,15 @@ ft_manager_delete_event_cb (GtkWidget *widget, static void ft_manager_destroy_cb (GtkWidget *widget, - EmpathyFTManager *ft_manager) + EmpathyFTManager *manager) { - ft_manager->priv->window = NULL; - if (ft_manager->priv->save_geometry_id != 0) - g_source_remove (ft_manager->priv->save_geometry_id); - g_hash_table_remove_all (ft_manager->priv->tp_file_to_row_ref); + DEBUG ("%p", manager); + + g_object_unref (manager); } static void -ft_manager_build_ui (EmpathyFTManager *ft_manager) +ft_manager_build_ui (EmpathyFTManager *manager) { GtkBuilder *gui; gint x, y, w, h; @@ -598,27 +961,26 @@ ft_manager_build_ui (EmpathyFTManager *ft_manager) GtkCellRenderer *renderer; GtkTreeSelection *selection; gchar *filename; - - if (ft_manager->priv->window != NULL) - return; + EmpathyFTManagerPriv *priv = GET_PRIV (manager); filename = empathy_file_lookup ("empathy-ft-manager.ui", "src"); gui = empathy_builder_get_file (filename, - "ft_manager_dialog", &ft_manager->priv->window, - "ft_list", &ft_manager->priv->treeview, - "open_button", &ft_manager->priv->open_button, - "abort_button", &ft_manager->priv->abort_button, + "ft_manager_dialog", &priv->window, + "ft_list", &priv->treeview, + "clear_button", &priv->clear_button, + "open_button", &priv->open_button, + "abort_button", &priv->abort_button, NULL); g_free (filename); - empathy_builder_connect (gui, ft_manager, + empathy_builder_connect (gui, manager, "ft_manager_dialog", "destroy", ft_manager_destroy_cb, "ft_manager_dialog", "response", ft_manager_response_cb, "ft_manager_dialog", "delete-event", ft_manager_delete_event_cb, "ft_manager_dialog", "configure-event", ft_manager_configure_event_cb, NULL); - g_object_unref (gui); + empathy_builder_unref_and_keep_widget (gui, priv->window); /* Window geometry. */ empathy_geometry_load ("ft-manager", &x, &y, &w, &h); @@ -627,22 +989,22 @@ ft_manager_build_ui (EmpathyFTManager *ft_manager) { /* Let the window manager position it if we don't have * good x, y coordinates. */ - gtk_window_move (GTK_WINDOW (ft_manager->priv->window), x, y); + gtk_window_move (GTK_WINDOW (priv->window), x, y); } if (w > 0 && h > 0) { /* Use the defaults from the ui file if we don't have * good w, h geometry. */ - gtk_window_resize (GTK_WINDOW (ft_manager->priv->window), w, h); + gtk_window_resize (GTK_WINDOW (priv->window), w, h); } /* Setup the tree view */ - view = GTK_TREE_VIEW (ft_manager->priv->treeview); + view = GTK_TREE_VIEW (priv->treeview); selection = gtk_tree_view_get_selection (view); gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); g_signal_connect (selection, "changed", - G_CALLBACK (ft_manager_selection_changed), ft_manager); + G_CALLBACK (ft_manager_selection_changed), manager); gtk_tree_view_set_headers_visible (view, TRUE); gtk_tree_view_set_enable_search (view, FALSE); @@ -652,9 +1014,9 @@ ft_manager_build_ui (EmpathyFTManager *ft_manager) G_TYPE_ICON, /* icon */ G_TYPE_STRING, /* message */ G_TYPE_STRING, /* remaining */ - G_TYPE_OBJECT); /* ft_file */ + G_TYPE_OBJECT); /* ft_handler */ gtk_tree_view_set_model (view, GTK_TREE_MODEL (liststore)); - ft_manager->priv->model = GTK_TREE_MODEL (liststore); + priv->model = GTK_TREE_MODEL (liststore); g_object_unref (liststore); /* Progress column */ @@ -702,36 +1064,45 @@ ft_manager_build_ui (EmpathyFTManager *ft_manager) gtk_tree_view_column_pack_start (column, renderer, FALSE); gtk_tree_view_column_set_attributes (column, renderer, "text", COL_REMAINING, NULL); + + /* clear button should be sensitive only if there are completed/cancelled + * handlers in the store. + */ + gtk_widget_set_sensitive (priv->clear_button, FALSE); } +/* GObject method overrides */ + static void empathy_ft_manager_finalize (GObject *object) { - EmpathyFTManager *ft_manager = (EmpathyFTManager *) object; + EmpathyFTManagerPriv *priv = GET_PRIV (object); - DEBUG ("%p", object); + DEBUG ("FT Manager %p", object); - if (ft_manager->priv->window) - gtk_widget_destroy (ft_manager->priv->window); + g_hash_table_destroy (priv->ft_handler_to_row_ref); - g_hash_table_destroy (ft_manager->priv->tp_file_to_row_ref); + if (priv->save_geometry_id != 0) + g_source_remove (priv->save_geometry_id); G_OBJECT_CLASS (empathy_ft_manager_parent_class)->finalize (object); } static void -empathy_ft_manager_init (EmpathyFTManager *ft_manager) +empathy_ft_manager_init (EmpathyFTManager *manager) { EmpathyFTManagerPriv *priv; - priv = G_TYPE_INSTANCE_GET_PRIVATE ((ft_manager), EMPATHY_TYPE_FT_MANAGER, + priv = G_TYPE_INSTANCE_GET_PRIVATE ((manager), EMPATHY_TYPE_FT_MANAGER, EmpathyFTManagerPriv); - ft_manager->priv = priv; + manager->priv = priv; - priv->tp_file_to_row_ref = g_hash_table_new_full (g_direct_hash, + priv->ft_handler_to_row_ref = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify) g_object_unref, (GDestroyNotify) gtk_tree_row_reference_free); + + ft_manager_build_ui (manager); } static GObject * @@ -743,7 +1114,7 @@ empathy_ft_manager_constructor (GType type, if (manager_singleton) { - retval = g_object_ref (manager_singleton); + retval = G_OBJECT (manager_singleton); } else { @@ -768,325 +1139,50 @@ empathy_ft_manager_class_init (EmpathyFTManagerClass *klass) g_type_class_add_private (object_class, sizeof (EmpathyFTManagerPriv)); } -/** - * empathy_ft_manager_dup_singleton: - * - * Returns a reference to the #EmpathyFTManager singleton object. - * - * Returns: a #EmpathyFTManager - */ -EmpathyFTManager * -empathy_ft_manager_dup_singleton (void) -{ - return g_object_new (EMPATHY_TYPE_FT_MANAGER, NULL); -} - -/** - * empathy_ft_manager_get_dialog: - * @ft_manager: an #EmpathyFTManager - * - * Returns the #GtkWidget of @ft_manager. - * - * Returns: the dialog - */ -GtkWidget * -empathy_ft_manager_get_dialog (EmpathyFTManager *ft_manager) -{ - g_return_val_if_fail (EMPATHY_IS_FT_MANAGER (ft_manager), NULL); - - ft_manager_build_ui (ft_manager); - - return ft_manager->priv->window; -} - -static void -ft_manager_add_tp_file_to_list (EmpathyFTManager *ft_manager, - EmpathyTpFile *tp_file) -{ - GtkTreeRowReference *row_ref; - GtkTreeIter iter; - GtkTreeSelection *selection; - GtkTreePath *path; - GIcon *icon; - const gchar *content_type; - - ft_manager_build_ui (ft_manager); - - /* Get the icon name from the mime-type of the file. */ - content_type = empathy_tp_file_get_content_type (tp_file); - icon = g_content_type_get_icon (content_type); - - /* Append the ft in the store */ - gtk_list_store_insert_with_values (GTK_LIST_STORE (ft_manager->priv->model), - &iter, G_MAXINT, COL_FT_OBJECT, tp_file, COL_ICON, icon, -1); - - g_object_unref (icon); - - /* Insert the new row_ref in the hash table */ - path = gtk_tree_model_get_path (GTK_TREE_MODEL (ft_manager->priv->model), - &iter); - row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL ( - ft_manager->priv->model), path); - gtk_tree_path_free (path); - g_hash_table_insert (ft_manager->priv->tp_file_to_row_ref, - g_object_ref (tp_file), row_ref); - - /* Select the new row */ - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW ( - ft_manager->priv->treeview)); - gtk_tree_selection_select_iter (selection, &iter); - - /* Update the row with the initial values, and keep track of changes */ - ft_manager_update_ft_row (ft_manager, tp_file); - g_signal_connect (tp_file, "notify::state", - G_CALLBACK (ft_manager_state_changed_cb), ft_manager); - g_signal_connect (tp_file, "notify::transferred-bytes", - G_CALLBACK (ft_manager_transferred_bytes_changed_cb), ft_manager); - - gtk_window_present (GTK_WINDOW (ft_manager->priv->window)); -} - -typedef struct { - EmpathyFTManager *ft_manager; - EmpathyTpFile *tp_file; -} ReceiveResponseData; +/* public methods */ -static void -ft_manager_receive_response_data_free (ReceiveResponseData *response_data) -{ - if (!response_data) - return; - - g_object_unref (response_data->tp_file); - g_object_unref (response_data->ft_manager); - g_slice_free (ReceiveResponseData, response_data); -} - -static void -ft_manager_save_dialog_response_cb (GtkDialog *widget, - gint response_id, - ReceiveResponseData *response_data) +void +empathy_ft_manager_add_handler (EmpathyFTHandler *handler) { - if (response_id == GTK_RESPONSE_OK) - { - gchar *uri; - gchar *folder; - - uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (widget)); - - if (uri) - { - GFile *file; - GError *error = NULL; - - file = g_file_new_for_uri (uri); - empathy_tp_file_accept (response_data->tp_file, 0, file, &error); - - if (error) - { - GtkWidget *dialog; - - DEBUG ("Error with opening file to write to: %s", - error->message ? error->message : "no error"); - - /* Error is already translated */ - dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, - GTK_BUTTONS_CLOSE, _("Cannot save file to this location")); - - gtk_message_dialog_format_secondary_text ( - GTK_MESSAGE_DIALOG (dialog), "%s", - error->message); - - g_signal_connect (dialog, "response", - G_CALLBACK (gtk_widget_destroy), NULL); - - gtk_widget_show (dialog); - - g_error_free (error); - return; - } + EmpathyFTManager *manager; + EmpathyFTManagerPriv *priv; - g_object_set_data_full (G_OBJECT (response_data->tp_file), - "uri", uri, g_free); + DEBUG ("Adding handler"); - ft_manager_add_tp_file_to_list (response_data->ft_manager, - response_data->tp_file); + g_return_if_fail (EMPATHY_IS_FT_HANDLER (handler)); - g_object_unref (file); - } + manager = g_object_new (EMPATHY_TYPE_FT_MANAGER, NULL); + priv = GET_PRIV (manager); - folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (widget)); - if (folder) - { - empathy_conf_set_string (empathy_conf_get (), - EMPATHY_PREFS_FILE_TRANSFER_DEFAULT_FOLDER, - folder); - g_free (folder); - } - } - - gtk_widget_destroy (GTK_WIDGET (widget)); - ft_manager_receive_response_data_free (response_data); + ft_manager_add_handler_to_list (manager, handler, NULL); + gtk_window_present (GTK_WINDOW (priv->window)); } -static void -ft_manager_create_save_dialog (ReceiveResponseData *response_data) +void +empathy_ft_manager_display_error (EmpathyFTHandler *handler, + const GError *error) { - GtkWidget *widget; - gchar *folder; - - DEBUG ("Creating save file chooser"); - - widget = gtk_file_chooser_dialog_new (_("Save file as..."), - NULL, GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE_AS, GTK_RESPONSE_OK, - NULL); - - if (!empathy_conf_get_string (empathy_conf_get (), - EMPATHY_PREFS_FILE_TRANSFER_DEFAULT_FOLDER, - &folder) || !folder) - folder = g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_DOWNLOAD)); - - if (folder) - gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (widget), folder); - - gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (widget), - empathy_tp_file_get_filename (response_data->tp_file)); - - gtk_dialog_set_default_response (GTK_DIALOG (widget), - GTK_RESPONSE_OK); - - gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (widget), - TRUE); - - g_signal_connect (widget, "response", - G_CALLBACK (ft_manager_save_dialog_response_cb), response_data); - - gtk_widget_show (widget); - - g_free (folder); -} + EmpathyFTManager *manager; + EmpathyFTManagerPriv *priv; -static void -ft_manager_receive_file_response_cb (GtkWidget *dialog, - gint response, - ReceiveResponseData *response_data) -{ - if (response == GTK_RESPONSE_ACCEPT) - ft_manager_create_save_dialog (response_data); - else - { - empathy_tp_file_cancel (response_data->tp_file); - ft_manager_receive_response_data_free (response_data); - } + g_return_if_fail (EMPATHY_IS_FT_HANDLER (handler)); + g_return_if_fail (error != NULL); - gtk_widget_destroy (dialog); -} + manager = g_object_new (EMPATHY_TYPE_FT_MANAGER, NULL); + priv = GET_PRIV (manager); -static void -ft_manager_display_accept_dialog (EmpathyFTManager *ft_manager, - EmpathyTpFile *tp_file) -{ - GtkWidget *dialog; - GtkWidget *image; - GtkWidget *button; - const gchar *contact_name; - const gchar *filename; - guint64 size; - gchar *size_str; - ReceiveResponseData *response_data; - - g_return_if_fail (EMPATHY_IS_FT_MANAGER (ft_manager)); - g_return_if_fail (EMPATHY_IS_TP_FILE (tp_file)); - - DEBUG ("Creating accept dialog"); - - contact_name = empathy_contact_get_name (empathy_tp_file_get_contact (tp_file)); - filename = empathy_tp_file_get_filename (tp_file); - - size = empathy_tp_file_get_size (tp_file); - if (size == EMPATHY_TP_FILE_UNKNOWN_SIZE) - size_str = g_strdup (_("unknown size")); - else - size_str = g_format_size_for_display (size); - - dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_INFO, - GTK_BUTTONS_NONE, - _("%s would like to send you a file"), - contact_name); - - gtk_message_dialog_format_secondary_text - (GTK_MESSAGE_DIALOG (dialog), - /* Translators: the first %s is the file name, the second %s is the file size */ - _("Do you want to accept the file \"%s\" (%s)?"), - filename, size_str); - - /* Icon */ - image = gtk_image_new_from_stock (GTK_STOCK_SAVE, GTK_ICON_SIZE_DIALOG); - gtk_widget_show (image); - gtk_message_dialog_set_image (GTK_MESSAGE_DIALOG (dialog), image); - - /* Decline button */ - button = gtk_button_new_with_mnemonic (_("_Decline")); - gtk_button_set_image (GTK_BUTTON (button), - gtk_image_new_from_stock (GTK_STOCK_CANCEL, - GTK_ICON_SIZE_BUTTON)); - gtk_widget_show (button); - gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, - GTK_RESPONSE_REJECT); - - /* Accept button */ - button = gtk_button_new_with_mnemonic (_("_Accept")); - gtk_button_set_image (GTK_BUTTON (button), - gtk_image_new_from_stock (GTK_STOCK_SAVE, - GTK_ICON_SIZE_BUTTON)); - gtk_widget_show (button); - gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, - GTK_RESPONSE_ACCEPT); - GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); - gtk_widget_grab_default (button); - - response_data = g_slice_new0 (ReceiveResponseData); - response_data->ft_manager = g_object_ref (ft_manager); - response_data->tp_file = g_object_ref (tp_file); - - g_signal_connect (dialog, "response", - G_CALLBACK (ft_manager_receive_file_response_cb), response_data); - - gtk_widget_show (dialog); - - g_free (size_str); + ft_manager_add_handler_to_list (manager, handler, error); + gtk_window_present (GTK_WINDOW (priv->window)); } -/** - * empathy_ft_manager_add_tp_file: - * @ft_manager: an #EmpathyFTManager - * @ft: an #EmpathyFT - * - * Adds a file transfer to the file transfer manager dialog @ft_manager. - * The manager dialog then shows the progress and other information about - * @ft. - */ void -empathy_ft_manager_add_tp_file (EmpathyFTManager *ft_manager, - EmpathyTpFile *tp_file) +empathy_ft_manager_show (void) { - TpFileTransferState state; - - g_return_if_fail (EMPATHY_IS_FT_MANAGER (ft_manager)); - g_return_if_fail (EMPATHY_IS_TP_FILE (tp_file)); - - state = empathy_tp_file_get_state (tp_file, NULL); + EmpathyFTManager *manager; + EmpathyFTManagerPriv *priv; - DEBUG ("Adding a file transfer: contact=%s, filename=%s, state=%d", - empathy_contact_get_name (empathy_tp_file_get_contact (tp_file)), - empathy_tp_file_get_filename (tp_file), state); + manager = g_object_new (EMPATHY_TYPE_FT_MANAGER, NULL); + priv = GET_PRIV (manager); - if (state == TP_FILE_TRANSFER_STATE_PENDING && - empathy_tp_file_is_incoming (tp_file)) - ft_manager_display_accept_dialog (ft_manager, tp_file); - else - ft_manager_add_tp_file_to_list (ft_manager, tp_file); + gtk_window_present (GTK_WINDOW (priv->window)); } - diff --git a/src/empathy-ft-manager.h b/src/empathy-ft-manager.h index 4803bc814..0ff820f06 100644 --- a/src/empathy-ft-manager.h +++ b/src/empathy-ft-manager.h @@ -1,7 +1,6 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2007 Marco Barisione <marco@barisione.org> - * Copyright (C) 2008 Collabora Ltd. + * Copyright (C) 2008-2009 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 @@ -15,11 +14,12 @@ * * 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA * * Authors: Marco Barisione <marco@barisione.org> * Jonny Lamb <jonny.lamb@collabora.co.uk> + * Cosimo Cecchi <cosimo.cecchi@collabora.co.uk> */ #ifndef __EMPATHY_FT_MANAGER_H__ @@ -29,38 +29,42 @@ #include <glib-object.h> #include <glib.h> -#include <libempathy/empathy-tp-file.h> +#include <libempathy/empathy-ft-handler.h> G_BEGIN_DECLS -#define EMPATHY_TYPE_FT_MANAGER (empathy_ft_manager_get_type ()) -#define EMPATHY_FT_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_FT_MANAGER, EmpathyFTManager)) -#define EMPATHY_FT_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_FT_MANAGER, EmpathyFTManagerClass)) -#define EMPATHY_IS_FT_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_FT_MANAGER)) -#define EMPATHY_IS_FT_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_FT_MANAGER)) -#define EMPATHY_FT_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_FT_MANAGER, EmpathyFTManagerClass)) +#define EMPATHY_TYPE_FT_MANAGER \ + (empathy_ft_manager_get_type ()) +#define EMPATHY_FT_MANAGER(o) \ + (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_FT_MANAGER, EmpathyFTManager)) +#define EMPATHY_FT_MANAGER_CLASS(k) \ + (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_FT_MANAGER, EmpathyFTManagerClass)) +#define EMPATHY_IS_FT_MANAGER(o) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_FT_MANAGER)) +#define EMPATHY_IS_FT_MANAGER_CLASS(k) \ + (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_FT_MANAGER)) +#define EMPATHY_FT_MANAGER_GET_CLASS(o) \ + (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_FT_MANAGER, EmpathyFTManagerClass)) typedef struct _EmpathyFTManager EmpathyFTManager; -typedef struct _EmpathyFTManagerPriv EmpathyFTManagerPriv; typedef struct _EmpathyFTManagerClass EmpathyFTManagerClass; -struct _EmpathyFTManager -{ +struct _EmpathyFTManager { GObject parent; - - EmpathyFTManagerPriv *priv; + gpointer priv; }; -struct _EmpathyFTManagerClass -{ +struct _EmpathyFTManagerClass { GObjectClass parent_class; }; GType empathy_ft_manager_get_type (void); -EmpathyFTManager *empathy_ft_manager_dup_singleton (void); -void empathy_ft_manager_add_tp_file (EmpathyFTManager *ft_manager, EmpathyTpFile *tp_file); -GtkWidget *empathy_ft_manager_get_dialog (EmpathyFTManager *ft_manager); +/* public methods */ +void empathy_ft_manager_add_handler (EmpathyFTHandler *handler); +void empathy_ft_manager_display_error (EmpathyFTHandler *handler, + const GError *error); +void empathy_ft_manager_show (void); G_END_DECLS diff --git a/src/empathy-import-dialog.c b/src/empathy-import-dialog.c index c7c321f96..8e9a04595 100644 --- a/src/empathy-import-dialog.c +++ b/src/empathy-import-dialog.c @@ -13,8 +13,8 @@ * * 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA * * Authors: Jonny Lamb <jonny.lamb@collabora.co.uk> * */ @@ -396,10 +396,10 @@ empathy_import_dialog_show (GtkWindow *parent, return; } - + /* We have accounts, let's display the window with them */ dialog = g_slice_new0 (EmpathyImportDialog); - dialog->accounts = accounts; + dialog->accounts = accounts; filename = empathy_file_lookup ("empathy-import-dialog.ui", "src"); gui = empathy_builder_get_file (filename, diff --git a/src/empathy-import-dialog.h b/src/empathy-import-dialog.h index 278afc701..a3ef3e13c 100644 --- a/src/empathy-import-dialog.h +++ b/src/empathy-import-dialog.h @@ -13,8 +13,8 @@ * * 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA * * Authors: Jonny Lamb <jonny.lamb@collabora.co.uk> */ diff --git a/src/empathy-import-pidgin.c b/src/empathy-import-pidgin.c index 76295c702..a58111d59 100644 --- a/src/empathy-import-pidgin.c +++ b/src/empathy-import-pidgin.c @@ -13,8 +13,8 @@ * * 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA * * Authors: Jonny Lamb <jonny.lamb@collabora.co.uk> * */ @@ -294,7 +294,7 @@ empathy_import_pidgin_load (void) } OUT: - xmlFreeDoc(doc); + xmlFreeDoc (doc); xmlFreeParserCtxt (ctxt); FILENAME: diff --git a/src/empathy-import-pidgin.h b/src/empathy-import-pidgin.h index fc7d2e491..b72acf553 100644 --- a/src/empathy-import-pidgin.h +++ b/src/empathy-import-pidgin.h @@ -13,8 +13,8 @@ * * 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA * * Authors: Jonny Lamb <jonny.lamb@collabora.co.uk> */ diff --git a/src/empathy-logs.c b/src/empathy-logs.c index 502be67d7..b9f38e0e7 100644 --- a/src/empathy-logs.c +++ b/src/empathy-logs.c @@ -14,9 +14,9 @@ * * 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. - * + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * * Authors: Xavier Claessens <xclaesse@gmail.com> */ diff --git a/src/empathy-main-window.c b/src/empathy-main-window.c index 9015a5d25..5830d2b71 100644 --- a/src/empathy-main-window.c +++ b/src/empathy-main-window.c @@ -15,9 +15,9 @@ * * 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. - * + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * * Authors: Xavier Claessens <xclaesse@gmail.com> */ @@ -57,8 +57,10 @@ #include "empathy-about-dialog.h" #include "empathy-debug-dialog.h" #include "empathy-new-chatroom-dialog.h" +#include "empathy-map-view.h" #include "empathy-chatrooms-window.h" #include "empathy-event-manager.h" +#include "empathy-ft-manager.h" #define DEBUG_FLAG EMPATHY_DEBUG_OTHER #include <libempathy/empathy-debug.h> @@ -93,7 +95,7 @@ typedef struct { GtkWidget *errors_vbox; GtkUIManager *ui_manager; - GtkAction *chat_history; + GtkAction *view_history; GtkAction *room_join_favorites; GtkWidget *room_menu; GtkWidget *room_separator; @@ -133,7 +135,7 @@ main_window_flash_foreach (GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) { - FlashForeachData *data = (FlashForeachData*) user_data; + FlashForeachData *data = (FlashForeachData *) user_data; EmpathyContact *contact; const gchar *icon_name; GtkTreePath *parent_path = NULL; @@ -165,7 +167,7 @@ main_window_flash_foreach (GtkTreeModel *model, /* To make sure the parent is shown correctly, we emit * the row-changed signal on the parent so it prompts - * it to be refreshed by the filter func. + * it to be refreshed by the filter func. */ if (gtk_tree_model_iter_parent (model, &parent_iter, iter)) { parent_path = gtk_tree_model_get_path (model, &parent_iter); @@ -562,8 +564,8 @@ main_window_connection_changed_cb (EmpathyAccountManager *manager, static void main_window_contact_presence_changed_cb (EmpathyContactMonitor *monitor, EmpathyContact *contact, - McPresence current, - McPresence previous, + TpConnectionPresenceType current, + TpConnectionPresenceType previous, EmpathyMainWindow *window) { McAccount *account; @@ -576,18 +578,25 @@ main_window_contact_presence_changed_cb (EmpathyContactMonitor *monitor, return; } - if (previous < MC_PRESENCE_AVAILABLE && current > MC_PRESENCE_OFFLINE) { - /* someone is logging in */ - empathy_sound_play (GTK_WIDGET (window->window), - EMPATHY_SOUND_CONTACT_CONNECTED); - return; - } - - if (previous > MC_PRESENCE_OFFLINE && current < MC_PRESENCE_AVAILABLE) { - /* someone is logging off */ - empathy_sound_play (GTK_WIDGET (window->window), - EMPATHY_SOUND_CONTACT_DISCONNECTED); - } + if (tp_connection_presence_type_cmp_availability (previous, + TP_CONNECTION_PRESENCE_TYPE_OFFLINE) > 0) + { + /* contact was online */ + if (tp_connection_presence_type_cmp_availability (current, + TP_CONNECTION_PRESENCE_TYPE_OFFLINE) <= 0) + /* someone is logging off */ + empathy_sound_play (GTK_WIDGET (window->window), + EMPATHY_SOUND_CONTACT_DISCONNECTED); + } + else + { + /* contact was offline */ + if (tp_connection_presence_type_cmp_availability (current, + TP_CONNECTION_PRESENCE_TYPE_OFFLINE) > 0) + /* someone is logging in */ + empathy_sound_play (GTK_WIDGET (window->window), + EMPATHY_SOUND_CONTACT_CONNECTED); + } } static void @@ -663,7 +672,7 @@ main_window_chat_quit_cb (GtkAction *action, } static void -main_window_chat_history_cb (GtkAction *action, +main_window_view_history_cb (GtkAction *action, EmpathyMainWindow *window) { empathy_log_window_show (NULL, NULL, FALSE, GTK_WINDOW (window->window)); @@ -684,7 +693,14 @@ main_window_chat_add_contact_cb (GtkAction *action, } static void -main_window_chat_show_offline_cb (GtkToggleAction *action, +main_window_view_show_ft_manager (GtkAction *action, + EmpathyMainWindow *window) +{ + empathy_ft_manager_show (); +} + +static void +main_window_view_show_offline_cb (GtkToggleAction *action, EmpathyMainWindow *window) { gboolean current; @@ -701,6 +717,15 @@ main_window_chat_show_offline_cb (GtkToggleAction *action, } static void +main_window_view_show_map_cb (GtkCheckMenuItem *item, + EmpathyMainWindow *window) +{ +#if HAVE_LIBCHAMPLAIN + empathy_map_view_show (); +#endif +} + +static void main_window_favorite_chatroom_join (EmpathyChatroom *chatroom) { EmpathyAccountManager *manager; @@ -986,7 +1011,7 @@ main_window_account_created_or_deleted_cb (EmpathyAccountManager *manager, McAccount *account, EmpathyMainWindow *window) { - gtk_action_set_sensitive (window->chat_history, + gtk_action_set_sensitive (window->view_history, empathy_account_manager_get_count (manager) > 0); } @@ -1046,7 +1071,7 @@ main_window_notify_sort_criterium_cb (EmpathyConf *conf, g_free (str); if (enum_value) { - empathy_contact_list_store_set_sort_criterium (window->list_store, + empathy_contact_list_store_set_sort_criterium (window->list_store, enum_value->value); } } @@ -1090,6 +1115,7 @@ empathy_main_window_show (void) GtkWidget *sw; GtkToggleAction *show_offline_widget; GtkWidget *ebox; + GtkAction *show_map_widget; GtkToolItem *item; gboolean show_offline; gboolean show_avatars; @@ -1112,8 +1138,9 @@ empathy_main_window_show (void) "main_vbox", &window->main_vbox, "errors_vbox", &window->errors_vbox, "ui_manager", &window->ui_manager, - "chat_show_offline", &show_offline_widget, - "chat_history", &window->chat_history, + "view_show_offline", &show_offline_widget, + "view_history", &window->view_history, + "view_show_map", &show_map_widget, "room_join_favorites", &window->room_join_favorites, "presence_toolbar", &window->presence_toolbar, "roster_scrolledwindow", &sw, @@ -1125,12 +1152,14 @@ empathy_main_window_show (void) "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, + "view_history", "activate", main_window_view_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, + "view_show_ft_manager", "activate", main_window_view_show_ft_manager, + "view_show_offline", "toggled", main_window_view_show_offline_cb, + "view_show_map", "activate", main_window_view_show_map_cb, "edit", "activate", main_window_edit_cb, "edit_accounts", "activate", main_window_edit_accounts_cb, "edit_personal_information", "activate", main_window_edit_personal_information_cb, @@ -1146,6 +1175,10 @@ empathy_main_window_show (void) g_object_ref (window->ui_manager); g_object_unref (gui); +#if !HAVE_LIBCHAMPLAIN + gtk_action_set_visible (show_map_widget, FALSE); +#endif + window->mc = empathy_mission_control_dup_singleton (); window->account_manager = empathy_account_manager_dup_singleton (); diff --git a/src/empathy-main-window.h b/src/empathy-main-window.h index 7960c460c..562fa12c6 100644 --- a/src/empathy-main-window.h +++ b/src/empathy-main-window.h @@ -15,9 +15,9 @@ * * 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. - * + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * * Authors: Xavier Claessens <xclaesse@gmail.com> */ diff --git a/src/empathy-main-window.ui b/src/empathy-main-window.ui index 73b49a5db..f914979f6 100644 --- a/src/empathy-main-window.ui +++ b/src/empathy-main-window.ui @@ -19,10 +19,10 @@ <accelerator key="N" modifiers="GDK_CONTROL_MASK"/> </child> <child> - <object class="GtkAction" id="chat_history"> + <object class="GtkAction" id="view_history"> <property name="icon-name">document-open-recent</property> - <property name="name">chat_history</property> - <property name="label" translatable="yes">_View Previous Conversations</property> + <property name="name">view_history</property> + <property name="label" translatable="yes">_Previous Conversations</property> </object> <accelerator key="F3" modifiers=""/> </child> @@ -34,13 +34,26 @@ </object> </child> <child> - <object class="GtkToggleAction" id="chat_show_offline"> - <property name="name">chat_show_offline</property> - <property name="label" translatable="yes">Show _Offline Contacts</property> + <object class="GtkAction" id="view_show_ft_manager"> + <property name="icon-name">document-send</property> + <property name="name">view_show_ft_manager</property> + <property name="label" translatable="yes">_File Transfers</property> + </object> + </child> + <child> + <object class="GtkToggleAction" id="view_show_offline"> + <property name="name">view_show_offline</property> + <property name="label" translatable="yes">_Offline Contacts</property> </object> <accelerator key="H" modifiers="GDK_CONTROL_MASK"/> </child> <child> + <object class="GtkAction" id="view_show_map"> + <property name="name">view_show_map</property> + <property name="label" translatable="yes">Contacts on a _Map</property> + </object> + </child> + <child> <object class="GtkAction" id="chat_quit"> <property name="stock_id">gtk-quit</property> <property name="name">chat_quit</property> @@ -80,6 +93,12 @@ </object> </child> <child> + <object class="GtkAction" id="view"> + <property name="name">view</property> + <property name="label" translatable="yes">_View</property> + </object> + </child> + <child> <object class="GtkAction" id="room"> <property name="name">room</property> <property name="label" translatable="yes">_Room</property> @@ -137,12 +156,9 @@ <menubar name="menubar"> <menu action="chat"> <menuitem action="chat_new_message"/> - <menuitem action="chat_history"/> <separator/> <menuitem action="chat_add_contact"/> <separator/> - <menuitem action="chat_show_offline"/> - <separator/> <menuitem action="chat_quit"/> </menu> <menu action="edit"> @@ -153,6 +169,13 @@ <separator/> <menuitem action="edit_preferences"/> </menu> + <menu action="view"> + <menuitem action="view_show_offline"/> + <separator/> + <menuitem action="view_history"/> + <menuitem action="view_show_ft_manager"/> + <menuitem action="view_show_map"/> + </menu> <menu action="room"> <menuitem action="room_join_new"/> <menuitem action="room_join_favorites"/> diff --git a/src/empathy-map-view.c b/src/empathy-map-view.c new file mode 100644 index 000000000..b8a32885c --- /dev/null +++ b/src/empathy-map-view.c @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2008, 2009 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: Pierre-Luc Beaudoin <pierre-luc.beaudoin@collabora.co.uk> + */ + +#include <config.h> + +#include <sys/stat.h> +#include <gtk/gtk.h> +#include <glib/gi18n.h> + +#include <champlain/champlain.h> +#include <champlain-gtk/champlain-gtk.h> +#include <clutter-gtk/gtk-clutter-embed.h> +#include <telepathy-glib/util.h> + +#include <libempathy/empathy-contact.h> +#include <libempathy/empathy-contact-manager.h> +#include <libempathy/empathy-utils.h> +#include <libempathy/empathy-location.h> + +#include <libempathy-gtk/empathy-contact-list-store.h> +#include <libempathy-gtk/empathy-contact-list-view.h> +#include <libempathy-gtk/empathy-presence-chooser.h> +#include <libempathy-gtk/empathy-ui-utils.h> + +#include "empathy-map-view.h" + +#define DEBUG_FLAG EMPATHY_DEBUG_LOCATION +#include <libempathy/empathy-debug.h> + +typedef struct { + EmpathyContactListStore *list_store; + + GtkWidget *window; + GtkWidget *zoom_in; + GtkWidget *zoom_out; + ChamplainView *map_view; + ChamplainLayer *layer; +} EmpathyMapView; + +static void map_view_destroy_cb (GtkWidget *widget, + EmpathyMapView *window); +static gboolean map_view_contacts_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data); +static void map_view_zoom_in_cb (GtkWidget *widget, + EmpathyMapView *window); +static void map_view_zoom_out_cb (GtkWidget *widget, + EmpathyMapView *window); +static void map_view_contact_location_notify (GObject *gobject, + GParamSpec *arg1, + gpointer user_data); + +GtkWidget * +empathy_map_view_show (void) +{ + static EmpathyMapView *window = NULL; + GtkBuilder *gui; + GtkWidget *sw; + GtkWidget *embed; + gchar *filename; + GtkTreeModel *model; + EmpathyContactList *list_iface; + EmpathyContactListStore *list_store; + + if (window) + { + empathy_window_present (GTK_WINDOW (window->window), TRUE); + return window->window; + } + + window = g_slice_new0 (EmpathyMapView); + + /* Set up interface */ + filename = empathy_file_lookup ("empathy-map-view.ui", "src"); + gui = empathy_builder_get_file (filename, + "map_view", &window->window, + "zoom_in", &window->zoom_in, + "zoom_out", &window->zoom_out, + "map_scrolledwindow", &sw, + NULL); + g_free (filename); + + empathy_builder_connect (gui, window, + "map_view", "destroy", map_view_destroy_cb, + "zoom_in", "clicked", map_view_zoom_in_cb, + "zoom_out", "clicked", map_view_zoom_out_cb, + NULL); + + g_object_unref (gui); + + /* Clear the static pointer to window if the dialog is destroyed */ + g_object_add_weak_pointer (G_OBJECT (window->window), (gpointer *) &window); + + list_iface = EMPATHY_CONTACT_LIST (empathy_contact_manager_dup_singleton ()); + list_store = empathy_contact_list_store_new (list_iface); + empathy_contact_list_store_set_show_groups (list_store, FALSE); + empathy_contact_list_store_set_show_avatars (list_store, TRUE); + g_object_unref (list_iface); + + window->list_store = list_store; + + /* Set up map view */ + window->map_view = CHAMPLAIN_VIEW (champlain_view_new ()); + g_object_set (G_OBJECT (window->map_view), "zoom-level", 1, + "scroll-mode", CHAMPLAIN_SCROLL_MODE_KINETIC, NULL); + champlain_view_center_on (window->map_view, 36, 0); + + embed = champlain_view_embed_new (window->map_view); + gtk_container_add (GTK_CONTAINER (sw), + GTK_WIDGET (embed)); + gtk_widget_show_all (embed); + + window->layer = g_object_ref (champlain_layer_new ()); + champlain_view_add_layer (window->map_view, window->layer); + + /* Set up contact list. */ + model = GTK_TREE_MODEL (window->list_store); + gtk_tree_model_foreach (model, map_view_contacts_foreach, window); + + empathy_window_present (GTK_WINDOW (window->window), TRUE); + return window->window; +} + +static void +map_view_destroy_cb (GtkWidget *widget, + EmpathyMapView *window) +{ + GList *item; + + item = clutter_container_get_children (window->layer); + while (item != NULL) + { + EmpathyContact *contact; + ChamplainMarker *marker; + + marker = CHAMPLAIN_MARKER (item->data); + contact = g_object_get_data (G_OBJECT (marker), "contact"); + g_signal_handlers_disconnect_by_func (contact, map_view_contact_location_notify, marker); + + item = g_list_next (item); + } + + g_object_unref (window->list_store); + g_object_unref (window->layer); + g_slice_free (EmpathyMapView, window); +} + +static void +map_view_marker_update_position (ChamplainMarker *marker, + EmpathyContact *contact) +{ + gdouble lon, lat; + GValue *value; + GHashTable *location; + + location = empathy_contact_get_location (contact); + + if (location == NULL || + g_hash_table_size (location) == 0) + { + clutter_actor_hide (CLUTTER_ACTOR (marker)); + return; + } + + value = g_hash_table_lookup (location, EMPATHY_LOCATION_LAT); + if (value == NULL) + { + clutter_actor_hide (CLUTTER_ACTOR (marker)); + return; + } + lat = g_value_get_double (value); + + value = g_hash_table_lookup (location, EMPATHY_LOCATION_LON); + if (value == NULL) + { + clutter_actor_hide (CLUTTER_ACTOR (marker)); + return; + } + lon = g_value_get_double (value); + + clutter_actor_show (CLUTTER_ACTOR (marker)); + champlain_base_marker_set_position (CHAMPLAIN_BASE_MARKER (marker), lat, lon); +} + +static void +map_view_contact_location_notify (GObject *gobject, + GParamSpec *arg1, + gpointer user_data) +{ + ChamplainMarker *marker = CHAMPLAIN_MARKER (user_data); + EmpathyContact *contact = EMPATHY_CONTACT (gobject); + map_view_marker_update_position (marker, contact); +} + +static gboolean +map_view_contacts_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data) +{ + EmpathyMapView *window = (EmpathyMapView*) user_data; + EmpathyContact *contact; + ClutterActor *marker; + ClutterActor *texture; + GHashTable *location; + GdkPixbuf *avatar; + const gchar *name; + gchar *date; + gchar *label; + GValue *gtime; + time_t time; + + gtk_tree_model_get (model, iter, EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, + &contact, -1); + + if (contact == NULL) + return FALSE; + + location = empathy_contact_get_location (contact); + + if (location == NULL) + return FALSE; + + marker = champlain_marker_new (); + + avatar = empathy_pixbuf_avatar_from_contact_scaled (contact, 32, 32); + if (avatar != NULL) + { + texture = clutter_texture_new (); + gtk_clutter_texture_set_from_pixbuf (CLUTTER_TEXTURE (texture), avatar); + champlain_marker_set_image (CHAMPLAIN_MARKER (marker), texture); + g_object_unref (avatar); + } + else + champlain_marker_set_image (CHAMPLAIN_MARKER (marker), NULL); + + name = empathy_contact_get_name (contact); + gtime = g_hash_table_lookup (location, EMPATHY_LOCATION_TIMESTAMP); + if (gtime != NULL) + { + time = g_value_get_int64 (gtime); + date = empathy_time_to_string_relative (time); + label = g_strconcat ("<b>", name, "</b>\n<small>", date, "</small>", NULL); + g_free (date); + } + else + { + label = g_strconcat ("<b>", name, "</b>\n", NULL); + } + champlain_marker_set_use_markup (CHAMPLAIN_MARKER (marker), TRUE); + champlain_marker_set_text (CHAMPLAIN_MARKER (marker), label); + g_free (label); + + clutter_container_add (CLUTTER_CONTAINER (window->layer), marker, NULL); + + g_signal_connect (contact, "notify::location", + G_CALLBACK (map_view_contact_location_notify), marker); + g_object_set_data_full (G_OBJECT (marker), "contact", g_object_ref (contact), g_object_unref); + + map_view_marker_update_position (CHAMPLAIN_MARKER (marker), contact); + + g_object_unref (contact); + return FALSE; +} + +static void +map_view_zoom_in_cb (GtkWidget *widget, + EmpathyMapView *window) +{ + champlain_view_zoom_in (window->map_view); +} + +static void +map_view_zoom_out_cb (GtkWidget *widget, + EmpathyMapView *window) +{ + champlain_view_zoom_out (window->map_view); +} diff --git a/src/empathy-map-view.h b/src/empathy-map-view.h new file mode 100644 index 000000000..80a05a129 --- /dev/null +++ b/src/empathy-map-view.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 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: Pierre-Luc Beaudoin <pierre-luc@pierlux.com> + */ + +#ifndef __EMPATHY_MAP_VIEW_H__ +#define __EMPATHY_MAP_VIEW_H__ + +#include <gtk/gtkwidget.h> + +G_BEGIN_DECLS + +GtkWidget *empathy_map_view_show (void); + +G_END_DECLS + +#endif /* __EMPATHY_MAP_VIEW_H__ */ diff --git a/src/empathy-map-view.ui b/src/empathy-map-view.ui new file mode 100644 index 000000000..f1140399b --- /dev/null +++ b/src/empathy-map-view.ui @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<interface> + <requires lib="gtk+" version="2.16"/> + <!-- interface-naming-policy toplevel-contextual --> + <object class="GtkWindow" id="map_view"> + <property name="title" translatable="yes">Contact Map View</property> + <property name="role">map_view</property> + <property name="window_position">center</property> + <property name="default_width">512</property> + <property name="default_height">384</property> + <child> + <object class="GtkVBox" id="main_vbox"> + <property name="visible">True</property> + <child> + <object class="GtkToolbar" id="toolbar"> + <property name="visible">True</property> + <child> + <object class="GtkToolButton" id="zoom_in"> + <property name="visible">True</property> + <property name="stock_id">gtk-zoom-in</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="zoom_out"> + <property name="visible">True</property> + <property name="stock_id">gtk-zoom-out</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkViewport" id="map_scrolledwindow"> + <property name="visible">True</property> + <property name="resize_mode">queue</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> +</interface> diff --git a/src/empathy-misc.c b/src/empathy-misc.c index 0a943bb6d..a1a084740 100644 --- a/src/empathy-misc.c +++ b/src/empathy-misc.c @@ -14,9 +14,9 @@ * * 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. - * + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * * Author: Cosimo Cecchi <cosimo.cecchi@collabora.co.uk> * */ diff --git a/src/empathy-misc.h b/src/empathy-misc.h index aaa743ca6..b3fe8fdbf 100644 --- a/src/empathy-misc.h +++ b/src/empathy-misc.h @@ -14,9 +14,9 @@ * * 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. - * + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * * Author: Cosimo Cecchi <cosimo.cecchi@collabora.co.uk> * */ diff --git a/src/empathy-new-chatroom-dialog.c b/src/empathy-new-chatroom-dialog.c index 837d9acfe..563665932 100644 --- a/src/empathy-new-chatroom-dialog.c +++ b/src/empathy-new-chatroom-dialog.c @@ -15,9 +15,9 @@ * * 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. - * + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * * Authors: Martyn Russell <martyn@imendio.com> * Xavier Claessens <xclaesse@gmail.com> */ @@ -30,6 +30,7 @@ #include <gtk/gtk.h> #include <glib.h> #include <glib/gi18n.h> +#include <glib/gprintf.h> #include <libmissioncontrol/mission-control.h> #include <libmissioncontrol/mc-account.h> @@ -66,7 +67,8 @@ typedef struct { GtkWidget *treeview; GtkTreeModel *model; GtkWidget *button_join; - GtkWidget *button_close; + GtkWidget *label_error_message; + GtkWidget *viewport_error; } EmpathyNewChatroomDialog; enum { @@ -75,6 +77,7 @@ enum { COL_NAME, COL_ROOM, COL_MEMBERS, + COL_MEMBERS_INT, COL_TOOLTIP, COL_COUNT }; @@ -97,6 +100,12 @@ static void new_chatroom_dialog_new_room_cb (EmpathyTpRo static void new_chatroom_dialog_listing_cb (EmpathyTpRoomlist *room_list, gpointer unused, EmpathyNewChatroomDialog *dialog); +static void start_listing_error_cb (EmpathyTpRoomlist *room_list, + GError *error, + EmpathyNewChatroomDialog *dialog); +static void stop_listing_error_cb (EmpathyTpRoomlist *room_list, + GError *error, + 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, @@ -116,6 +125,8 @@ static void new_chatroom_dialog_expander_browse_activate_cb (GtkWidget static gboolean new_chatroom_dialog_entry_server_focus_out_cb (GtkWidget *widget, GdkEventFocus *event, EmpathyNewChatroomDialog *dialog); +static void new_chatroom_dialog_button_close_error_clicked_cb (GtkButton *button, + EmpathyNewChatroomDialog *dialog); static EmpathyNewChatroomDialog *dialog_p = NULL; @@ -146,6 +157,8 @@ empathy_new_chatroom_dialog_show (GtkWindow *parent) "treeview", &dialog->treeview, "button_join", &dialog->button_join, "expander_browse", &dialog->expander_browse, + "label_error_message", &dialog->label_error_message, + "viewport_error", &dialog->viewport_error, NULL); g_free (filename); @@ -157,6 +170,7 @@ empathy_new_chatroom_dialog_show (GtkWindow *parent) "entry_server", "focus-out-event", new_chatroom_dialog_entry_server_focus_out_cb, "entry_room", "changed", new_chatroom_dialog_entry_changed_cb, "expander_browse", "activate", new_chatroom_dialog_expander_browse_activate_cb, + "button_close_error", "clicked", new_chatroom_dialog_button_close_error_clicked_cb, NULL); g_object_unref (gui); @@ -227,7 +241,7 @@ new_chatroom_dialog_destroy_cb (GtkWidget *widget, if (dialog->room_list) { g_object_unref (dialog->room_list); } - g_object_unref (dialog->model); + g_object_unref (dialog->model); g_free (dialog); } @@ -253,6 +267,7 @@ new_chatroom_dialog_model_setup (EmpathyNewChatroomDialog *dialog) G_TYPE_STRING, /* Name */ G_TYPE_STRING, /* Room */ G_TYPE_STRING, /* Member count */ + G_TYPE_INT, /* Member count int */ G_TYPE_STRING); /* Tool tip */ dialog->model = GTK_TREE_MODEL (store); @@ -295,12 +310,16 @@ new_chatroom_dialog_model_add_columns (EmpathyNewChatroomDialog *dialog) cell, "stock-id", COL_INVITE_ONLY, NULL); + + gtk_tree_view_column_set_sort_column_id (column, COL_INVITE_ONLY); gtk_tree_view_append_column (view, column); column = gtk_tree_view_column_new_with_attributes (NULL, cell, "stock-id", COL_NEED_PASSWORD, NULL); + + gtk_tree_view_column_set_sort_column_id (column, COL_NEED_PASSWORD); gtk_tree_view_append_column (view, column); cell = gtk_cell_renderer_text_new (); @@ -315,6 +334,7 @@ new_chatroom_dialog_model_add_columns (EmpathyNewChatroomDialog *dialog) "text", COL_NAME, NULL); + gtk_tree_view_column_set_sort_column_id (column, COL_NAME); gtk_tree_view_column_set_expand (column, TRUE); gtk_tree_view_append_column (view, column); @@ -329,6 +349,8 @@ new_chatroom_dialog_model_add_columns (EmpathyNewChatroomDialog *dialog) cell, "text", COL_MEMBERS, NULL); + + gtk_tree_view_column_set_sort_column_id (column, COL_MEMBERS_INT); gtk_tree_view_append_column (view, column); } @@ -379,6 +401,7 @@ new_chatroom_dialog_account_changed_cb (GtkComboBox *combobox, EmpathyAccountChooser *account_chooser; McAccount *account; gboolean listing = FALSE; + gboolean expanded = FALSE; if (dialog->room_list) { g_object_unref (dialog->room_list); @@ -401,6 +424,19 @@ new_chatroom_dialog_account_changed_cb (GtkComboBox *combobox, g_signal_connect (dialog->room_list, "notify::is-listing", G_CALLBACK (new_chatroom_dialog_listing_cb), dialog); + g_signal_connect (dialog->room_list, "error::start", + G_CALLBACK (start_listing_error_cb), + dialog); + g_signal_connect (dialog->room_list, "error::stop", + G_CALLBACK (stop_listing_error_cb), + dialog); + + expanded = gtk_expander_get_expanded (GTK_EXPANDER (dialog->expander_browse)); + if (expanded) { + gtk_widget_hide (dialog->viewport_error); + gtk_widget_set_sensitive (dialog->treeview, TRUE); + new_chatroom_dialog_browse_start (dialog); + } listing = empathy_tp_roomlist_is_listing (dialog->room_list); if (listing) { @@ -414,6 +450,13 @@ new_chatroom_dialog_account_changed_cb (GtkComboBox *combobox, } static void +new_chatroom_dialog_button_close_error_clicked_cb (GtkButton *button, + EmpathyNewChatroomDialog *dialog) +{ + gtk_widget_hide (dialog->viewport_error); +} + +static void new_chatroom_dialog_roomlist_destroy_cb (EmpathyTpRoomlist *room_list, EmpathyNewChatroomDialog *dialog) { @@ -463,6 +506,7 @@ new_chatroom_dialog_new_room_cb (EmpathyTpRoomlist *room_list, COL_NAME, empathy_chatroom_get_name (chatroom), COL_ROOM, empathy_chatroom_get_room (chatroom), COL_MEMBERS, members, + COL_MEMBERS_INT, empathy_chatroom_get_members_count (chatroom), COL_TOOLTIP, tooltip, -1); @@ -471,6 +515,26 @@ new_chatroom_dialog_new_room_cb (EmpathyTpRoomlist *room_list, } static void +start_listing_error_cb (EmpathyTpRoomlist *room_list, + GError *error, + EmpathyNewChatroomDialog *dialog) +{ + gtk_label_set_text (GTK_LABEL (dialog->label_error_message), _("Could not start room listing")); + gtk_widget_show_all (dialog->viewport_error); + gtk_widget_set_sensitive (dialog->treeview, FALSE); +} + +static void +stop_listing_error_cb (EmpathyTpRoomlist *room_list, + GError *error, + EmpathyNewChatroomDialog *dialog) +{ + gtk_label_set_text (GTK_LABEL (dialog->label_error_message), _("Could not stop room listing")); + gtk_widget_show_all (dialog->viewport_error); + gtk_widget_set_sensitive (dialog->treeview, FALSE); +} + +static void new_chatroom_dialog_listing_cb (EmpathyTpRoomlist *room_list, gpointer unused, EmpathyNewChatroomDialog *dialog) @@ -606,6 +670,8 @@ new_chatroom_dialog_expander_browse_activate_cb (GtkWidget *widget new_chatroom_dialog_browse_stop (dialog); gtk_window_set_resizable (GTK_WINDOW (dialog->window), FALSE); } else { + gtk_widget_hide (dialog->viewport_error); + gtk_widget_set_sensitive (dialog->treeview, TRUE); new_chatroom_dialog_browse_start (dialog); gtk_window_set_resizable (GTK_WINDOW (dialog->window), TRUE); } diff --git a/src/empathy-new-chatroom-dialog.h b/src/empathy-new-chatroom-dialog.h index ae8b2385e..b1cef0daa 100644 --- a/src/empathy-new-chatroom-dialog.h +++ b/src/empathy-new-chatroom-dialog.h @@ -15,9 +15,9 @@ * * 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. - * + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * * Authors: Martyn Russell <martyn@imendio.com> * Xavier Claessens <xclaesse@gmail.com> */ diff --git a/src/empathy-new-chatroom-dialog.ui b/src/empathy-new-chatroom-dialog.ui index ba7a326ef..a8fccf4a0 100644 --- a/src/empathy-new-chatroom-dialog.ui +++ b/src/empathy-new-chatroom-dialog.ui @@ -1,13 +1,14 @@ <?xml version="1.0"?> -<!--*- mode: xml -*--> <interface> + <requires lib="gtk+" version="2.16"/> + <!-- interface-naming-policy toplevel-contextual --> <object class="GtkDialog" id="new_chatroom_dialog"> <property name="visible">True</property> <property name="border_width">5</property> <property name="title" translatable="yes">Join Room</property> <property name="role">join_new_chatroom</property> <property name="default_width">350</property> - <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="type_hint">dialog</property> <property name="has_separator">False</property> <child internal-child="vbox"> <object class="GtkVBox" id="dialog-vbox4"> @@ -25,16 +26,10 @@ <property name="column_spacing">5</property> <property name="row_spacing">5</property> <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child> <object class="GtkEntry" id="entry_room"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="tooltip-text" translatable="yes">Enter the room name to join here or click on one or more rooms in the list.</property> + <property name="tooltip_text" translatable="yes">Enter the room name to join here or click on one or more rooms in the list.</property> <property name="activates_default">True</property> <property name="width_chars">25</property> </object> @@ -64,7 +59,7 @@ <object class="GtkEntry" id="entry_server"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="tooltip-text" 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="tooltip_text" 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="width_chars">25</property> </object> <packing> @@ -73,7 +68,7 @@ <property name="top_attach">1</property> <property name="bottom_attach">2</property> <property name="x_options">GTK_FILL</property> - <property name="y_options"/> + <property name="y_options"></property> </packing> </child> <child> @@ -88,7 +83,7 @@ <property name="top_attach">1</property> <property name="bottom_attach">2</property> <property name="x_options">GTK_FILL</property> - <property name="y_options"/> + <property name="y_options"></property> </packing> </child> <child> @@ -99,13 +94,20 @@ </object> <packing> <property name="x_options">GTK_FILL</property> - <property name="y_options"/> + <property name="y_options"></property> </packing> </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> </object> <packing> <property name="expand">False</property> <property name="fill">False</property> + <property name="position">0</property> </packing> </child> <child> @@ -113,21 +115,90 @@ <property name="visible">True</property> <property name="can_focus">True</property> <child> - <object class="GtkScrolledWindow" id="scrolledwindow2"> - <property name="width_request">350</property> - <property name="height_request">150</property> + <object class="GtkVBox" id="vbox1"> <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="orientation">vertical</property> + <property name="spacing">2</property> + <child> + <object class="GtkViewport" id="viewport_error"> + <property name="resize_mode">queue</property> + <child> + <object class="GtkHBox" id="hbox1"> + <property name="visible">True</property> + <child> + <object class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="stock">gtk-dialog-error</property> + <property name="icon-size">1</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="padding">5</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label_error_message"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">10</property> + <property name="label" translatable="yes">Couldn't load room list</property> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="button_close_error"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="relief">none</property> + <child> + <object class="GtkImage" id="image2"> + <property name="visible">True</property> + <property name="stock">gtk-close</property> + <property name="icon-size">1</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> <child> - <object class="GtkTreeView" id="treeview"> + <object class="GtkScrolledWindow" id="scrolledwindow2"> + <property name="width_request">350</property> + <property name="height_request">150</property> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="search_column">0</property> - <property name="show_expanders">False</property> + <property name="hscrollbar_policy">never</property> + <property name="vscrollbar_policy">automatic</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="treeview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="search_column">0</property> + <property name="show_expanders">False</property> + </object> + </child> </object> + <packing> + <property name="position">1</property> + </packing> </child> </object> </child> @@ -150,15 +221,21 @@ <child internal-child="action_area"> <object class="GtkHButtonBox" id="dialog-action_area4"> <property name="visible">True</property> - <property name="layout_style">GTK_BUTTONBOX_END</property> + <property name="layout_style">end</property> <child> <object class="GtkButton" id="button_cancel"> + <property name="label">gtk-cancel</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="can_default">True</property> - <property name="label">gtk-cancel</property> + <property name="receives_default">False</property> <property name="use_stock">True</property> </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> </child> <child> <object class="GtkButton" id="button_join"> @@ -167,6 +244,7 @@ <property name="can_focus">True</property> <property name="can_default">True</property> <property name="has_default">True</property> + <property name="receives_default">False</property> <child> <object class="GtkAlignment" id="alignment4"> <property name="visible">True</property> @@ -184,6 +262,7 @@ <packing> <property name="expand">False</property> <property name="fill">False</property> + <property name="position">0</property> </packing> </child> <child> @@ -204,13 +283,16 @@ </child> </object> <packing> + <property name="expand">False</property> + <property name="fill">False</property> <property name="position">1</property> </packing> </child> </object> <packing> <property name="expand">False</property> - <property name="pack_type">GTK_PACK_END</property> + <property name="pack_type">end</property> + <property name="position">0</property> </packing> </child> </object> diff --git a/src/empathy-preferences.c b/src/empathy-preferences.c index b2388f88d..406db4c9f 100644 --- a/src/empathy-preferences.c +++ b/src/empathy-preferences.c @@ -14,8 +14,8 @@ * * 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA * * Authors: Mikael Hallendal <micke@imendio.com> * Richard Hult <richard@imendio.com> @@ -64,6 +64,12 @@ typedef struct { GtkWidget *treeview_spell_checker; + GtkWidget *checkbutton_location_publish; + GtkWidget *checkbutton_location_reduce_accuracy; + GtkWidget *checkbutton_location_resource_network; + GtkWidget *checkbutton_location_resource_cell; + GtkWidget *checkbutton_location_resource_gps; + GList *notify_ids; } EmpathyPreferences; @@ -247,6 +253,38 @@ preferences_setup_widgets (EmpathyPreferences *preferences) EMPATHY_PREFS_AUTOCONNECT, preferences->checkbutton_autoconnect); + preferences_hookup_toggle_button (preferences, + EMPATHY_PREFS_LOCATION_PUBLISH, + preferences->checkbutton_location_publish); + + preferences_hookup_toggle_button (preferences, + EMPATHY_PREFS_LOCATION_RESOURCE_NETWORK, + preferences->checkbutton_location_resource_network); + preferences_hookup_sensitivity (preferences, + EMPATHY_PREFS_LOCATION_PUBLISH, + preferences->checkbutton_location_resource_network); + + preferences_hookup_toggle_button (preferences, + EMPATHY_PREFS_LOCATION_RESOURCE_CELL, + preferences->checkbutton_location_resource_cell); + preferences_hookup_sensitivity (preferences, + EMPATHY_PREFS_LOCATION_PUBLISH, + preferences->checkbutton_location_resource_cell); + + preferences_hookup_toggle_button (preferences, + EMPATHY_PREFS_LOCATION_RESOURCE_GPS, + preferences->checkbutton_location_resource_gps); + preferences_hookup_sensitivity (preferences, + EMPATHY_PREFS_LOCATION_PUBLISH, + preferences->checkbutton_location_resource_gps); + + preferences_hookup_toggle_button (preferences, + EMPATHY_PREFS_LOCATION_REDUCE_ACCURACY, + preferences->checkbutton_location_reduce_accuracy); + preferences_hookup_sensitivity (preferences, + EMPATHY_PREFS_LOCATION_PUBLISH, + preferences->checkbutton_location_reduce_accuracy); + id = empathy_conf_notify_add (empathy_conf_get (), EMPATHY_PREFS_UI_COMPACT_CONTACT_LIST, preferences_compact_contact_list_changed_cb, @@ -422,7 +460,7 @@ preferences_languages_add (EmpathyPreferences *preferences) codes = empathy_spell_get_language_codes (); - empathy_conf_set_bool (empathy_conf_get(), + empathy_conf_set_bool (empathy_conf_get (), EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED, codes != NULL); if (!codes) { @@ -668,7 +706,7 @@ preferences_widget_sync_string (const gchar *key, GtkWidget *widget) enum_class = G_ENUM_CLASS (g_type_class_peek (type)); enum_value = g_enum_get_value_by_nick (enum_class, value); - if (enum_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); @@ -1003,12 +1041,14 @@ preferences_radio_button_toggled_cb (GtkWidget *button, 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_warning ("No GEnumValue for EmpathyContactListSort with GtkRadioButton index:%d", g_slist_index (group, button)); return; } value = enum_value->value_nick; + } else if (key && strcmp (key, EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM) == 0) { + return; } empathy_conf_set_string (empathy_conf_get (), key, value); @@ -1067,6 +1107,7 @@ empathy_preferences_show (GtkWindow *parent) static EmpathyPreferences *preferences; GtkBuilder *gui; gchar *filename; + GtkWidget *page; if (preferences) { gtk_window_present (GTK_WINDOW (preferences->dialog)); @@ -1094,6 +1135,11 @@ empathy_preferences_show (GtkWindow *parent) "checkbutton_sounds_disabled_away", &preferences->checkbutton_sounds_disabled_away, "treeview_sounds", &preferences->treeview_sounds, "treeview_spell_checker", &preferences->treeview_spell_checker, + "checkbutton_location_publish", &preferences->checkbutton_location_publish, + "checkbutton_location_reduce_accuracy", &preferences->checkbutton_location_reduce_accuracy, + "checkbutton_location_resource_network", &preferences->checkbutton_location_resource_network, + "checkbutton_location_resource_cell", &preferences->checkbutton_location_resource_cell, + "checkbutton_location_resource_gps", &preferences->checkbutton_location_resource_gps, NULL); g_free (filename); @@ -1124,6 +1170,14 @@ empathy_preferences_show (GtkWindow *parent) gtk_widget_show (page); } + page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (preferences->notebook), 3); +#if HAVE_GEOCLUE + gtk_widget_show (page); +#else + gtk_widget_hide (page); +#endif + + if (parent) { gtk_window_set_transient_for (GTK_WINDOW (preferences->dialog), GTK_WINDOW (parent)); diff --git a/src/empathy-preferences.h b/src/empathy-preferences.h index 07ae6b523..6cc86d1d6 100644 --- a/src/empathy-preferences.h +++ b/src/empathy-preferences.h @@ -14,8 +14,8 @@ * * 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA * * Authors: Mikael Hallendal <micke@imendio.com> * Richard Hult <richard@imendio.com> diff --git a/src/empathy-preferences.ui b/src/empathy-preferences.ui index c20d271e2..d92fc8f88 100644 --- a/src/empathy-preferences.ui +++ b/src/empathy-preferences.ui @@ -308,7 +308,7 @@ <property name="label" translatable="yes">Notifications</property> </object> <packing> - <property name="position">4</property> + <property name="position">1</property> <property name="tab_fill">False</property> </packing> </child> @@ -424,6 +424,202 @@ </packing> </child> <child> + <object class="GtkVBox" id="vbox1"> + <property name="visible">True</property> + <property name="border_width">12</property> + <property name="orientation">vertical</property> + <property name="spacing">18</property> + <child> + <object class="GtkCheckButton" id="checkbutton_location_publish"> + <property name="label" translatable="yes">_Publish location to my contacts</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="frame1"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment2"> + <property name="visible">True</property> + <property name="top_padding">6</property> + <property name="left_padding">12</property> + <child> + <object class="GtkVBox" id="vbox4"> + <property name="visible">True</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkHBox" id="hbox1"> + <property name="visible">True</property> + <property name="spacing">6</property> + <child> + <object class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="yalign">0</property> + <property name="stock">gtk-dialog-info</property> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label6"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes"><small>Reduced location accuracy means that nothing more precise than your city, state and country will be published. GPS coordinates will have a random value added (±0.25°).</small></property> + <property name="use_markup">True</property> + <property name="wrap">True</property> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="checkbutton_location_reduce_accuracy"> + <property name="label" translatable="yes">_Reduce location accuracy</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label3"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Privacy</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="frame5"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment4"> + <property name="visible">True</property> + <property name="top_padding">6</property> + <property name="left_padding">12</property> + <child> + <object class="GtkVBox" id="vbox5"> + <property name="visible">True</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkCheckButton" id="checkbutton_location_resource_gps"> + <property name="label" translatable="yes">Allow _GPS usage</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="checkbutton_location_resource_cell"> + <property name="label" translatable="yes">Allow _cellphone usage</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="checkbutton_location_resource_network"> + <property name="label" translatable="yes">Allow _network usage</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label5"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Geoclue Settings</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="position">3</property> + </packing> + </child> + <child type="tab"> + <object class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="label" translatable="yes">Location</property> + </object> + <packing> + <property name="position">3</property> + <property name="tab_fill">False</property> + </packing> + </child> + <child> <object class="GtkVBox" id="vbox168"> <property name="visible">True</property> <property name="border_width">12</property> @@ -532,7 +728,7 @@ </child> </object> <packing> - <property name="position">3</property> + <property name="position">4</property> </packing> </child> <child type="tab"> @@ -541,7 +737,7 @@ <property name="label" translatable="yes">Spell Checking</property> </object> <packing> - <property name="position">3</property> + <property name="position">4</property> <property name="tab_fill">False</property> </packing> </child> @@ -616,7 +812,7 @@ </child> </object> <packing> - <property name="position">4</property> + <property name="position">5</property> </packing> </child> <child type="tab"> @@ -625,7 +821,7 @@ <property name="label" translatable="yes">Themes</property> </object> <packing> - <property name="position">4</property> + <property name="position">5</property> <property name="tab_fill">False</property> </packing> </child> diff --git a/src/empathy-sidebar.c b/src/empathy-sidebar.c index a66abc757..caca6b5e3 100644 --- a/src/empathy-sidebar.c +++ b/src/empathy-sidebar.c @@ -3,7 +3,7 @@ * Copyright (C) 2007 The Free Software Foundation * Copyright (C) 2008 Marco Barisione <marco@barisione.org> * - * Based on evince code (shell/ev-sidebar.c) by: + * Based on evince code (shell/ev-sidebar.c) by: * - Jonathan Blandford <jrb@alum.mit.edu> * * Base on eog code (src/eog-sidebar.c) by: @@ -21,7 +21,7 @@ * * 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. + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H @@ -102,7 +102,7 @@ empathy_sidebar_select_page (EmpathySidebar *sidebar, gint index; gtk_tree_model_get (sidebar->priv->page_model, iter, - PAGE_COLUMN_TITLE, &title, + PAGE_COLUMN_TITLE, &title, PAGE_COLUMN_NOTEBOOK_INDEX, &index, -1); @@ -397,7 +397,7 @@ empathy_sidebar_init (EmpathySidebar *sidebar) gtk_widget_show (hbox); sidebar->priv->select_button = gtk_toggle_button_new (); - gtk_button_set_relief (GTK_BUTTON (sidebar->priv->select_button), + gtk_button_set_relief (GTK_BUTTON (sidebar->priv->select_button), GTK_RELIEF_NONE); g_signal_connect (sidebar->priv->select_button, "button_press_event", @@ -514,7 +514,7 @@ empathy_sidebar_add_page (EmpathySidebar *sidebar, -1); gtk_list_store_move_before (GTK_LIST_STORE(sidebar->priv->page_model), - &iter, + &iter, NULL); /* Set the first item added as active */ @@ -571,15 +571,15 @@ empathy_sidebar_remove_page (EmpathySidebar *sidebar, if (valid) { - gtk_notebook_remove_page (GTK_NOTEBOOK (sidebar->priv->notebook), + gtk_notebook_remove_page (GTK_NOTEBOOK (sidebar->priv->notebook), index); gtk_container_remove (GTK_CONTAINER (sidebar->priv->menu), menu_item); - gtk_list_store_remove (GTK_LIST_STORE (sidebar->priv->page_model), + gtk_list_store_remove (GTK_LIST_STORE (sidebar->priv->page_model), &iter); - g_signal_emit (G_OBJECT (sidebar), + g_signal_emit (G_OBJECT (sidebar), signals[SIGNAL_PAGE_REMOVED], 0, main_widget); } } diff --git a/src/empathy-sidebar.h b/src/empathy-sidebar.h index 6e88e789d..095336fac 100644 --- a/src/empathy-sidebar.h +++ b/src/empathy-sidebar.h @@ -3,7 +3,7 @@ * Copyright (C) 2007 The Free Software Foundation * Copyright (C) 2008 Marco Barisione <marco@barisione.org> * - * Based on evince code (shell/ev-sidebar.h) by: + * Based on evince code (shell/ev-sidebar.h) by: * - Jonathan Blandford <jrb@alum.mit.edu> * * Base on eog code (src/eog-sidebar.c) by: @@ -21,7 +21,7 @@ * * 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. + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __EMPATHY_SIDEBAR_H__ @@ -53,10 +53,10 @@ struct _EmpathySidebarClass { GtkVBoxClass base_class; - void (* page_added) (EmpathySidebar *sidebar, + void (* page_added) (EmpathySidebar *sidebar, GtkWidget *main_widget); - void (* page_removed) (EmpathySidebar *sidebar, + void (* page_removed) (EmpathySidebar *sidebar, GtkWidget *main_widget); }; diff --git a/src/empathy-status-icon.c b/src/empathy-status-icon.c index 1824be5e6..9c2194880 100644 --- a/src/empathy-status-icon.c +++ b/src/empathy-status-icon.c @@ -15,7 +15,7 @@ * 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> */ @@ -195,13 +195,14 @@ status_icon_update_icon (EmpathyStatusIcon *icon) if (priv->event && priv->showing_event_icon) { icon_name = priv->event->icon_name; } else { - McPresence state; + TpConnectionPresenceType state; 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); + if (icon_name != NULL) + gtk_status_icon_set_from_icon_name (priv->icon, icon_name); } static gboolean diff --git a/src/empathy-tube-dispatch.c b/src/empathy-tube-dispatch.c index 63b31b2b6..67db5a3a3 100644 --- a/src/empathy-tube-dispatch.c +++ b/src/empathy-tube-dispatch.c @@ -149,7 +149,7 @@ empathy_tube_dispatch_constructed (GObject *object) const gchar *channel_type; TpTubeType type; - priv->dbus = tp_dbus_daemon_new (tp_get_bus()); + priv->dbus = tp_dbus_daemon_new (tp_get_bus ()); channel = empathy_dispatch_operation_get_channel (priv->operation); properties = tp_channel_borrow_immutable_properties (channel); @@ -159,19 +159,19 @@ empathy_tube_dispatch_constructed (GObject *object) if (channel_type == NULL) goto failed; - if (!tp_strdiff (channel_type, EMP_IFACE_CHANNEL_TYPE_STREAM_TUBE)) + if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE)) { type = TP_TUBE_TYPE_STREAM; service = tp_asv_get_string (properties, - EMP_IFACE_CHANNEL_TYPE_STREAM_TUBE ".Service"); + TP_IFACE_CHANNEL_TYPE_STREAM_TUBE ".Service"); } - else if (!tp_strdiff (channel_type, EMP_IFACE_CHANNEL_TYPE_DBUS_TUBE)) + else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE)) { GError *error = NULL; type = TP_TUBE_TYPE_DBUS; service = tp_asv_get_string (properties, - EMP_IFACE_CHANNEL_TYPE_DBUS_TUBE ".ServiceName"); + TP_IFACE_CHANNEL_TYPE_DBUS_TUBE ".ServiceName"); if (!tp_dbus_check_valid_bus_name (service, TP_DBUS_NAME_TYPE_WELL_KNOWN, &error)) diff --git a/src/empathy-tube-dispatch.h b/src/empathy-tube-dispatch.h index f1328bb68..844c88145 100644 --- a/src/empathy-tube-dispatch.h +++ b/src/empathy-tube-dispatch.h @@ -44,11 +44,11 @@ struct _EmpathyTubeDispatch { GObject parent; }; -GType empathy_tube_dispatch_get_type(void); +GType empathy_tube_dispatch_get_type (void); /* TYPE MACROS */ #define EMPATHY_TYPE_TUBE_DISPATCH \ - (empathy_tube_dispatch_get_type()) + (empathy_tube_dispatch_get_type ()) #define EMPATHY_TUBE_DISPATCH(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), EMPATHY_TYPE_TUBE_DISPATCH, \ EmpathyTubeDispatch)) diff --git a/src/empathy.c b/src/empathy.c index 817b9bc37..d5be4df8d 100644 --- a/src/empathy.c +++ b/src/empathy.c @@ -14,9 +14,9 @@ * * 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. - * + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * * Authors: Xavier Claessens <xclaesse@gmail.com> */ @@ -31,6 +31,10 @@ #include <gtk/gtk.h> #include <gdk/gdkx.h> +#if HAVE_LIBCHAMPLAIN +#include <clutter-gtk/gtk-clutter-embed.h> +#endif + #include <libebook/e-book.h> #include <libnotify/notify.h> @@ -46,11 +50,13 @@ #include <libempathy/empathy-dispatcher.h> #include <libempathy/empathy-dispatch-operation.h> #include <libempathy/empathy-log-manager.h> +#include <libempathy/empathy-ft-factory.h> #include <libempathy/empathy-tp-chat.h> #include <libempathy/empathy-tp-call.h> #include <libempathy-gtk/empathy-conf.h> #include <libempathy-gtk/empathy-ui-utils.h> +#include <libempathy-gtk/empathy-location-manager.h> #include "empathy-accounts-dialog.h" #include "empathy-main-window.h" @@ -124,15 +130,17 @@ dispatch_cb (EmpathyDispatcher *dispatcher, factory = empathy_call_factory_get (); empathy_call_factory_claim_channel (factory, operation); } else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_FILE_TRANSFER) { - EmpathyFTManager *ft_manager; - EmpathyTpFile *tp_file; + EmpathyFTFactory *factory; - ft_manager = empathy_ft_manager_dup_singleton (); - tp_file = EMPATHY_TP_FILE ( - empathy_dispatch_operation_get_channel_wrapper (operation)); - empathy_ft_manager_add_tp_file (ft_manager, tp_file); - empathy_dispatch_operation_claim (operation); - g_object_unref (ft_manager); + factory = empathy_ft_factory_dup_singleton (); + + /* if the operation is not incoming, don't claim it, + * as it might have been triggered by another client, and + * we are observing it. + */ + if (empathy_dispatch_operation_is_incoming (operation)) { + empathy_ft_factory_claim_channel (factory, operation); + } } } @@ -229,7 +237,7 @@ create_salut_account (void) GError *error = NULL; /* Check if we already created a salut account */ - empathy_conf_get_bool (empathy_conf_get(), + empathy_conf_get_bool (empathy_conf_get (), EMPATHY_PREFS_SALUT_ACCOUNT_CREATED, &salut_created); if (salut_created) { @@ -312,7 +320,7 @@ create_salut_account (void) /* The code that handles single-instance and startup notification is * copied from gedit. * - * Copyright (C) 2005 - Paolo Maggi + * Copyright (C) 2005 - Paolo Maggi */ static void on_bacon_message_received (const char *message, @@ -404,30 +412,61 @@ show_version_cb (const char *option_name, } static void +new_incoming_transfer_cb (EmpathyFTFactory *factory, + EmpathyFTHandler *handler, + GError *error, + gpointer user_data) +{ + if (error) { + empathy_ft_manager_display_error (handler, error); + } else { + empathy_receive_file_with_file_chooser (handler); + } +} + +static void +new_ft_handler_cb (EmpathyFTFactory *factory, + EmpathyFTHandler *handler, + GError *error, + gpointer user_data) +{ + if (error) { + empathy_ft_manager_display_error (handler, error); + } else { + empathy_ft_manager_add_handler (handler); + } + + g_object_unref (handler); +} + +static void new_call_handler_cb (EmpathyCallFactory *factory, EmpathyCallHandler *handler, gboolean outgoing, gpointer user_data) { - EmpathyCallWindow *window; + EmpathyCallWindow *window; - window = empathy_call_window_new (handler); - gtk_widget_show (GTK_WIDGET (window)); + window = empathy_call_window_new (handler); + gtk_widget_show (GTK_WIDGET (window)); } int main (int argc, char *argv[]) { guint32 startup_timestamp; +#if HAVE_GEOCLUE + EmpathyLocationManager *location_manager = NULL; +#endif EmpathyStatusIcon *icon; EmpathyDispatcher *dispatcher; EmpathyLogManager *log_manager; EmpathyChatroomManager *chatroom_manager; - EmpathyFTManager *ft_manager; EmpathyCallFactory *call_factory; + EmpathyFTFactory *ft_factory; GtkWidget *window; MissionControl *mc; EmpathyIdle *idle; gboolean autoconnect = TRUE; - gboolean no_connect = FALSE; + gboolean no_connect = FALSE; gboolean hide_contact_list = FALSE; gboolean accounts_dialog = FALSE; GError *error = NULL; @@ -462,10 +501,14 @@ main (int argc, char *argv[]) empathy_gtk_init (); g_set_application_name (_(PACKAGE_NAME)); - g_setenv("PULSE_PROP_media.role", "phone", TRUE); + g_setenv ("PULSE_PROP_media.role", "phone", TRUE); gst_init (&argc, &argv); +#if HAVE_LIBCHAMPLAIN + gtk_clutter_init (&argc, &argv); +#endif + gtk_window_set_default_icon_name ("empathy"); textdomain (GETTEXT_PACKAGE); @@ -533,11 +576,12 @@ main (int argc, char *argv[]) use_nm_notify_cb, idle); /* Autoconnect */ - empathy_conf_get_bool (empathy_conf_get(), + empathy_conf_get_bool (empathy_conf_get (), EMPATHY_PREFS_AUTOCONNECT, &autoconnect); if (autoconnect && ! no_connect && - empathy_idle_get_state (idle) <= MC_PRESENCE_OFFLINE) { + tp_connection_presence_type_cmp_availability (empathy_idle_get_state + (idle), TP_CONNECTION_PRESENCE_TYPE_OFFLINE) <= 0) { empathy_idle_set_state (idle, MC_PRESENCE_AVAILABLE); } @@ -565,17 +609,26 @@ main (int argc, char *argv[]) chatroom_manager = empathy_chatroom_manager_dup_singleton (NULL); empathy_chatroom_manager_observe (chatroom_manager, dispatcher); - ft_manager = empathy_ft_manager_dup_singleton (); - notify_init (_(PACKAGE_NAME)); /* Create the call factory */ call_factory = empathy_call_factory_initialise (); g_signal_connect (G_OBJECT (call_factory), "new-call-handler", G_CALLBACK (new_call_handler_cb), NULL); + /* Create the FT factory */ + ft_factory = empathy_ft_factory_dup_singleton (); + g_signal_connect (ft_factory, "new-ft-handler", + G_CALLBACK (new_ft_handler_cb), NULL); + g_signal_connect (ft_factory, "new-incoming-transfer", + G_CALLBACK (new_incoming_transfer_cb), NULL); + + /* Location mananger */ +#if HAVE_GEOCLUE + location_manager = empathy_location_manager_dup_singleton (); +#endif gtk_main (); - empathy_idle_set_state (idle, MC_PRESENCE_OFFLINE); + empathy_idle_set_state (idle, TP_CONNECTION_PRESENCE_TYPE_OFFLINE); g_object_unref (mc); g_object_unref (idle); @@ -583,7 +636,10 @@ main (int argc, char *argv[]) g_object_unref (log_manager); g_object_unref (dispatcher); g_object_unref (chatroom_manager); - g_object_unref (ft_manager); +#if HAVE_GEOCLUE + g_object_unref (location_manager); +#endif + g_object_unref (ft_factory); notify_uninit (); diff --git a/src/ephy-spinner.c b/src/ephy-spinner.c index 43b9bc990..be82ca71b 100644 --- a/src/ephy-spinner.c +++ b/src/ephy-spinner.c @@ -1,4 +1,4 @@ -/* +/* * Copyright © 2000 Eazel, Inc. * Copyright © 2002-2004 Marco Pesenti Gritti * Copyright © 2004, 2006 Christian Persch @@ -20,7 +20,7 @@ * 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 $ */ @@ -455,7 +455,7 @@ ephy_spinner_cache_init (EphySpinnerCache *cache) static void ephy_spinner_cache_finalize (GObject *object) { - EphySpinnerCache *cache = EPHY_SPINNER_CACHE (object); + EphySpinnerCache *cache = EPHY_SPINNER_CACHE (object); EphySpinnerCachePrivate *priv = cache->priv; g_hash_table_destroy (priv->hash); |