diff options
Diffstat (limited to 'libempathy-gtk')
31 files changed, 1260 insertions, 223 deletions
diff --git a/libempathy-gtk/Makefile.am b/libempathy-gtk/Makefile.am index 94cc4ee15..7f93accd3 100644 --- a/libempathy-gtk/Makefile.am +++ b/libempathy-gtk/Makefile.am @@ -41,6 +41,7 @@ libempathy_gtk_handwritten_source = \ empathy-contact-list-store.c \ empathy-contact-list-view.c \ empathy-contact-menu.c \ + empathy-share-my-desktop.c \ empathy-contact-selector.c \ empathy-contact-widget.c \ empathy-geometry.c \ @@ -60,6 +61,7 @@ libempathy_gtk_handwritten_source = \ empathy-theme-boxes.c \ empathy-theme-irc.c \ empathy-theme-manager.c \ + empathy-kludge-label.c \ empathy-ui-utils.c libempathy_gtk_la_SOURCES = \ @@ -100,6 +102,7 @@ libempathy_gtk_headers = \ empathy-contact-list-store.h \ empathy-contact-list-view.h \ empathy-contact-menu.h \ + empathy-share-my-desktop.h \ empathy-contact-selector.h \ empathy-contact-widget.h \ empathy-geometry.h \ @@ -120,6 +123,7 @@ libempathy_gtk_headers = \ empathy-theme-boxes.h \ empathy-theme-irc.h \ empathy-theme-manager.h \ + empathy-kludge-label.h \ empathy-ui-utils.h check_c_sources = \ diff --git a/libempathy-gtk/empathy-account-chooser.c b/libempathy-gtk/empathy-account-chooser.c index fa05bbcc9..7c6f52fa5 100644 --- a/libempathy-gtk/empathy-account-chooser.c +++ b/libempathy-gtk/empathy-account-chooser.c @@ -56,6 +56,7 @@ typedef struct { EmpathyAccountManager *manager; gboolean set_active_item; + gboolean account_manually_set; gboolean has_all_option; EmpathyAccountChooserFilterFunc filter; gpointer filter_data; @@ -151,6 +152,7 @@ empathy_account_chooser_init (EmpathyAccountChooser *chooser) chooser->priv = priv; priv->set_active_item = FALSE; + priv->account_manually_set = FALSE; priv->filter = NULL; priv->filter_data = NULL; @@ -320,6 +322,7 @@ gboolean empathy_account_chooser_set_account (EmpathyAccountChooser *chooser, EmpathyAccount *account) { + EmpathyAccountChooserPriv *priv; GtkComboBox *combobox; GtkTreeModel *model; GtkTreeIter iter; @@ -327,6 +330,8 @@ empathy_account_chooser_set_account (EmpathyAccountChooser *chooser, g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), FALSE); + priv = GET_PRIV (chooser); + combobox = GTK_COMBO_BOX (chooser); model = gtk_combo_box_get_model (combobox); gtk_combo_box_get_active_iter (combobox, &iter); @@ -338,6 +343,8 @@ empathy_account_chooser_set_account (EmpathyAccountChooser *chooser, (GtkTreeModelForeachFunc) account_chooser_set_account_foreach, &data); + priv->account_manually_set = data.set; + return data.set; } @@ -620,7 +627,8 @@ account_chooser_update_iter (EmpathyAccountChooser *chooser, -1); /* set first connected account as active account */ - if (priv->set_active_item == FALSE && is_enabled) { + if (priv->account_manually_set == FALSE && + priv->set_active_item == FALSE && is_enabled) { priv->set_active_item = TRUE; gtk_combo_box_set_active_iter (combobox, iter); } diff --git a/libempathy-gtk/empathy-account-widget-irc.c b/libempathy-gtk/empathy-account-widget-irc.c index 4bca91073..c04f3463d 100644 --- a/libempathy-gtk/empathy-account-widget-irc.c +++ b/libempathy-gtk/empathy-account-widget-irc.c @@ -431,7 +431,7 @@ empathy_account_widget_irc_new (EmpathyAccountSettings *account_settings) settings = g_slice_new0 (EmpathyAccountWidgetIrc); settings->settings = g_object_ref (account_settings); - dir = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, NULL); + dir = g_build_filename (g_get_user_config_dir (), PACKAGE_NAME, NULL); g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR); user_file_with_path = g_build_filename (dir, IRC_NETWORKS_FILENAME, NULL); g_free (dir); diff --git a/libempathy-gtk/empathy-avatar-chooser.c b/libempathy-gtk/empathy-avatar-chooser.c index 83475b565..af96885e4 100644 --- a/libempathy-gtk/empathy-avatar-chooser.c +++ b/libempathy-gtk/empathy-avatar-chooser.c @@ -786,24 +786,24 @@ avatar_chooser_drag_data_received_cb (GtkWidget *widget, gchar *target_type; gboolean handled = FALSE; - target_type = gdk_atom_name (selection_data->target); + target_type = gdk_atom_name (gtk_selection_data_get_target (selection_data)); if (!strcmp (target_type, URI_LIST_TYPE)) { GFile *file; GFileInputStream *input_stream; gchar *nl; gchar *data = NULL; - nl = strstr (selection_data->data, "\r\n"); + nl = strstr (gtk_selection_data_get_data (selection_data), "\r\n"); if (nl) { gchar *uri; - uri = g_strndup (selection_data->data, - nl - (gchar *) selection_data->data); + uri = g_strndup (gtk_selection_data_get_data (selection_data), + nl - (gchar *) gtk_selection_data_get_data (selection_data)); file = g_file_new_for_uri (uri); g_free (uri); } else { - file = g_file_new_for_uri (selection_data->data); + file = g_file_new_for_uri (gtk_selection_data_get_data (selection_data)); } input_stream = g_file_read (file, NULL, NULL); diff --git a/libempathy-gtk/empathy-avatar-image.c b/libempathy-gtk/empathy-avatar-image.c index d430c0fa6..f7898e1bd 100644 --- a/libempathy-gtk/empathy-avatar-image.c +++ b/libempathy-gtk/empathy-avatar-image.c @@ -232,7 +232,7 @@ avatar_image_button_press_event (GtkWidget *widget, GdkEventButton *event) gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf); g_object_unref (pixbuf); - gdk_window_get_origin (priv->image->window, &x, &y); + gdk_window_get_origin (gtk_widget_get_window (priv->image), &x, &y); x = x - (popup_width - width) / 2; y = y - (popup_height - height) / 2; diff --git a/libempathy-gtk/empathy-cell-renderer-expander.c b/libempathy-gtk/empathy-cell-renderer-expander.c index 6fb7cfded..bd5c89f19 100644 --- a/libempathy-gtk/empathy-cell-renderer-expander.c +++ b/libempathy-gtk/empathy-cell-renderer-expander.c @@ -101,9 +101,11 @@ empathy_cell_renderer_expander_init (EmpathyCellRendererExpander *expander) priv->activatable = TRUE; priv->animation_node = NULL; - GTK_CELL_RENDERER (expander)->xpad = 2; - GTK_CELL_RENDERER (expander)->ypad = 2; - GTK_CELL_RENDERER (expander)->mode = GTK_CELL_RENDERER_MODE_ACTIVATABLE; + g_object_set (expander, + "xpad", 2, + "ypad", 2, + "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, + NULL); } static void @@ -252,18 +254,27 @@ empathy_cell_renderer_expander_get_size (GtkCellRenderer *cell, { EmpathyCellRendererExpander *expander; EmpathyCellRendererExpanderPriv *priv; + gfloat xalign, yalign; + guint xpad, ypad; expander = (EmpathyCellRendererExpander *) cell; priv = GET_PRIV (expander); + g_object_get (cell, + "xalign", &xalign, + "yalign", &yalign, + "xpad", &xpad, + "ypad", &ypad, + NULL); + if (cell_area) { if (x_offset) { - *x_offset = cell->xalign * (cell_area->width - (priv->expander_size + (2 * cell->xpad))); + *x_offset = xalign * (cell_area->width - (priv->expander_size + (2 * xpad))); *x_offset = MAX (*x_offset, 0); } if (y_offset) { - *y_offset = cell->yalign * (cell_area->height - (priv->expander_size + (2 * cell->ypad))); + *y_offset = yalign * (cell_area->height - (priv->expander_size + (2 * ypad))); *y_offset = MAX (*y_offset, 0); } } else { @@ -275,10 +286,10 @@ empathy_cell_renderer_expander_get_size (GtkCellRenderer *cell, } if (width) - *width = cell->xpad * 2 + priv->expander_size; + *width = xpad * 2 + priv->expander_size; if (height) - *height = cell->ypad * 2 + priv->expander_size; + *height = ypad * 2 + priv->expander_size; } static void @@ -294,6 +305,8 @@ empathy_cell_renderer_expander_render (GtkCellRenderer *cell, EmpathyCellRendererExpanderPriv *priv; GtkExpanderStyle expander_style; gint x_offset, y_offset; + guint xpad, ypad; + expander = (EmpathyCellRendererExpander *) cell; priv = GET_PRIV (expander); @@ -319,14 +332,19 @@ empathy_cell_renderer_expander_render (GtkCellRenderer *cell, &x_offset, &y_offset, NULL, NULL); - gtk_paint_expander (widget->style, + g_object_get (cell, + "xpad", &xpad, + "ypad", &ypad, + NULL); + + gtk_paint_expander (gtk_widget_get_style (widget), window, GTK_STATE_NORMAL, expose_area, widget, "treeview", - cell_area->x + x_offset + cell->xpad + priv->expander_size / 2, - cell_area->y + y_offset + cell->ypad + priv->expander_size / 2, + cell_area->x + x_offset + xpad + priv->expander_size / 2, + cell_area->y + y_offset + ypad + priv->expander_size / 2, expander_style); } diff --git a/libempathy-gtk/empathy-chat-text-view.c b/libempathy-gtk/empathy-chat-text-view.c index 5ed7c69c3..d7ebda647 100644 --- a/libempathy-gtk/empathy-chat-text-view.c +++ b/libempathy-gtk/empathy-chat-text-view.c @@ -495,7 +495,9 @@ chat_text_view_size_allocate (GtkWidget *widget, GtkAdjustment *adj; adj = GTK_TEXT_VIEW (widget)->vadjustment; - gtk_adjustment_set_value (adj, adj->upper - adj->page_size); + gtk_adjustment_set_value (adj, + gtk_adjustment_get_upper (adj) - + gtk_adjustment_get_page_size (adj)); } } @@ -652,7 +654,7 @@ chat_text_view_scroll_cb (EmpathyChatTextView *view) priv = GET_PRIV (view); adj = GTK_TEXT_VIEW (view)->vadjustment; - max_val = adj->upper - adj->page_size; + max_val = gtk_adjustment_get_upper (adj) - gtk_adjustment_get_page_size (adj); g_return_val_if_fail (priv->scroll_time != NULL, FALSE); @@ -817,6 +819,10 @@ chat_text_view_clear (EmpathyChatView *view) priv = GET_PRIV (view); priv->last_timestamp = 0; + if (priv->last_contact) { + g_object_unref (priv->last_contact); + priv->last_contact = NULL; + } } static gboolean diff --git a/libempathy-gtk/empathy-chat.c b/libempathy-gtk/empathy-chat.c index 1f5225348..a8ca745e2 100644 --- a/libempathy-gtk/empathy-chat.c +++ b/libempathy-gtk/empathy-chat.c @@ -748,13 +748,14 @@ chat_input_key_press_event_cb (GtkWidget *widget, if (!(event->state & GDK_CONTROL_MASK) && event->keyval == GDK_Page_Up) { adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (text_view_sw)); - gtk_adjustment_set_value (adj, adj->value - adj->page_size); + gtk_adjustment_set_value (adj, gtk_adjustment_get_value (adj) - gtk_adjustment_get_page_size (adj)); return TRUE; } if ((event->state & GDK_CONTROL_MASK) != GDK_CONTROL_MASK && event->keyval == GDK_Page_Down) { adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (text_view_sw)); - val = MIN (adj->value + adj->page_size, adj->upper - adj->page_size); + val = MIN (gtk_adjustment_get_value (adj) + gtk_adjustment_get_page_size (adj), + gtk_adjustment_get_upper (adj) - gtk_adjustment_get_page_size (adj)); gtk_adjustment_set_value (adj, val); return TRUE; } @@ -1161,6 +1162,56 @@ chat_contacts_completion_func (const gchar *s1, return ret; } +static gchar * +build_part_message (guint reason, + const gchar *name, + EmpathyContact *actor, + const gchar *message) +{ + GString *s = g_string_new (""); + const gchar *actor_name = NULL; + + if (actor != NULL) { + actor_name = empathy_contact_get_name (actor); + } + + /* Having an actor only really makes sense for a few actions... */ + switch (reason) { + case TP_CHANNEL_GROUP_CHANGE_REASON_OFFLINE: + g_string_append_printf (s, _("%s has disconnected"), name); + break; + case TP_CHANNEL_GROUP_CHANGE_REASON_KICKED: + if (actor_name != NULL) { + g_string_append_printf (s, _("%s was kicked by %s"), + name, actor_name); + } else { + g_string_append_printf (s, _("%s was kicked"), name); + } + break; + case TP_CHANNEL_GROUP_CHANGE_REASON_BANNED: + if (actor_name != NULL) { + g_string_append_printf (s, _("%s was banned by %s"), + name, actor_name); + } else { + g_string_append_printf (s, _("%s was banned"), name); + } + break; + default: + g_string_append_printf (s, _("%s has left the room"), name); + } + + if (!EMP_STR_EMPTY (message)) { + /* Note to translators: this string is appended to + * notifications like "foo has left the room", with the message + * given by the user living the room. If this poses a problem, + * please let us know. :-) + */ + g_string_append_printf (s, _(" (%s)"), message); + } + + return g_string_free (s, FALSE); +} + static void chat_members_changed_cb (EmpathyTpChat *tp_chat, EmpathyContact *contact, @@ -1171,20 +1222,21 @@ chat_members_changed_cb (EmpathyTpChat *tp_chat, EmpathyChat *chat) { EmpathyChatPriv *priv = GET_PRIV (chat); + const gchar *name = empathy_contact_get_name (contact); + gchar *str; - if (priv->block_events_timeout_id == 0) { - gchar *str; + if (priv->block_events_timeout_id != 0) + return; - if (is_member) { - str = g_strdup_printf (_("%s has joined the room"), - empathy_contact_get_name (contact)); - } else { - str = g_strdup_printf (_("%s has left the room"), - empathy_contact_get_name (contact)); - } - empathy_chat_view_append_event (chat->view, str); - g_free (str); + if (is_member) { + str = g_strdup_printf (_("%s has joined the room"), + name); + } else { + str = build_part_message (reason, name, actor, message); } + + empathy_chat_view_append_event (chat->view, str); + g_free (str); } static gboolean @@ -1427,15 +1479,18 @@ chat_size_request (GtkWidget *widget, GtkRequisition *requisition) { GtkBin *bin = GTK_BIN (widget); + GtkWidget *child; + + requisition->width = gtk_container_get_border_width (GTK_CONTAINER (widget)) * 2; + requisition->height = gtk_container_get_border_width (GTK_CONTAINER (widget)) * 2; - requisition->width = GTK_CONTAINER (widget)->border_width * 2; - requisition->height = GTK_CONTAINER (widget)->border_width * 2; + child = gtk_bin_get_child (bin); - if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + if (child && GTK_WIDGET_VISIBLE (child)) { GtkRequisition child_requisition; - gtk_widget_size_request (bin->child, &child_requisition); + gtk_widget_size_request (child, &child_requisition); requisition->width += child_requisition.width; requisition->height += child_requisition.height; @@ -1448,17 +1503,20 @@ chat_size_allocate (GtkWidget *widget, { GtkBin *bin = GTK_BIN (widget); GtkAllocation child_allocation; + GtkWidget *child; widget->allocation = *allocation; - if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + child = gtk_bin_get_child (bin); + + if (child && GTK_WIDGET_VISIBLE (child)) { - child_allocation.x = allocation->x + GTK_CONTAINER (widget)->border_width; - child_allocation.y = allocation->y + GTK_CONTAINER (widget)->border_width; - child_allocation.width = MAX (allocation->width - GTK_CONTAINER (widget)->border_width * 2, 0); - child_allocation.height = MAX (allocation->height - GTK_CONTAINER (widget)->border_width * 2, 0); + child_allocation.x = allocation->x + gtk_container_get_border_width (GTK_CONTAINER (widget)); + child_allocation.y = allocation->y + gtk_container_get_border_width (GTK_CONTAINER (widget)); + child_allocation.width = MAX (allocation->width - gtk_container_get_border_width (GTK_CONTAINER (widget)) * 2, 0); + child_allocation.height = MAX (allocation->height - gtk_container_get_border_width (GTK_CONTAINER (widget)) * 2, 0); - gtk_widget_size_allocate (bin->child, &child_allocation); + gtk_widget_size_allocate (child, &child_allocation); } } diff --git a/libempathy-gtk/empathy-contact-dialogs.c b/libempathy-gtk/empathy-contact-dialogs.c index 5b11ddc2e..fc1cbbc8e 100644 --- a/libempathy-gtk/empathy-contact-dialogs.c +++ b/libempathy-gtk/empathy-contact-dialogs.c @@ -191,7 +191,7 @@ empathy_contact_information_dialog_show (EmpathyContact *contact, EMPATHY_CONTACT_WIDGET_SHOW_LOCATION | EMPATHY_CONTACT_WIDGET_EDIT_NONE); gtk_container_set_border_width (GTK_CONTAINER (contact_widget), 8); - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), + gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), contact_widget, TRUE, TRUE, 0); gtk_widget_show (contact_widget); @@ -250,7 +250,7 @@ empathy_contact_edit_dialog_show (EmpathyContact *contact, EMPATHY_CONTACT_WIDGET_EDIT_ALIAS | EMPATHY_CONTACT_WIDGET_EDIT_GROUPS); gtk_container_set_border_width (GTK_CONTAINER (contact_widget), 8); - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), + gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), contact_widget, TRUE, TRUE, 0); gtk_widget_show (contact_widget); @@ -302,7 +302,7 @@ empathy_contact_personal_dialog_show (GtkWindow *parent) EMPATHY_CONTACT_WIDGET_EDIT_ALIAS | EMPATHY_CONTACT_WIDGET_EDIT_AVATAR); gtk_container_set_border_width (GTK_CONTAINER (contact_widget), 8); - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (personal_dialog)->vbox), + gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (personal_dialog))), contact_widget, TRUE, TRUE, 0); empathy_contact_widget_set_account_filter (contact_widget, @@ -334,9 +334,11 @@ can_add_contact_to_account (EmpathyAccount *account, gboolean result; connection = empathy_account_get_connection (account); + if (connection == NULL) + return FALSE; contact_manager = empathy_contact_manager_dup_singleton (); - result = empathy_contact_manager_can_add (contact_manager, connection); + result = empathy_contact_manager_get_flags_for_connection (contact_manager, connection) & EMPATHY_CONTACT_LIST_CAN_ADD; g_object_unref (contact_manager); return result; @@ -366,6 +368,13 @@ new_contact_response_cb (GtkDialog *dialog, void empathy_new_contact_dialog_show (GtkWindow *parent) { + empathy_new_contact_dialog_show_with_contact (parent, NULL); +} + +void +empathy_new_contact_dialog_show_with_contact (GtkWindow *parent, + EmpathyContact *contact) +{ GtkWidget *dialog; GtkWidget *button; GtkWidget *contact_widget; @@ -398,12 +407,12 @@ empathy_new_contact_dialog_show (GtkWindow *parent) gtk_widget_show (button); /* Contact info widget */ - contact_widget = empathy_contact_widget_new (NULL, + contact_widget = empathy_contact_widget_new (contact, EMPATHY_CONTACT_WIDGET_EDIT_ALIAS | EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT | EMPATHY_CONTACT_WIDGET_EDIT_ID | EMPATHY_CONTACT_WIDGET_EDIT_GROUPS); - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), + gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), contact_widget, TRUE, TRUE, 0); empathy_contact_widget_set_account_filter (contact_widget, diff --git a/libempathy-gtk/empathy-contact-dialogs.h b/libempathy-gtk/empathy-contact-dialogs.h index c714c6b96..21aa5ce73 100644 --- a/libempathy-gtk/empathy-contact-dialogs.h +++ b/libempathy-gtk/empathy-contact-dialogs.h @@ -35,7 +35,9 @@ void empathy_contact_information_dialog_show (EmpathyContact *contact, void empathy_contact_edit_dialog_show (EmpathyContact *contact, GtkWindow *parent); void empathy_contact_personal_dialog_show (GtkWindow *parent); -void empathy_new_contact_dialog_show (GtkWindow *parent); +void empathy_new_contact_dialog_show (GtkWindow *parent); +void empathy_new_contact_dialog_show_with_contact (GtkWindow *parent, + EmpathyContact *contact); G_END_DECLS diff --git a/libempathy-gtk/empathy-contact-list-store.c b/libempathy-gtk/empathy-contact-list-store.c index 0e9372be1..a4c1d7ab9 100644 --- a/libempathy-gtk/empathy-contact-list-store.c +++ b/libempathy-gtk/empathy-contact-list-store.c @@ -33,6 +33,9 @@ #include <telepathy-glib/util.h> #include <libempathy/empathy-utils.h> +#include <libempathy/empathy-enum-types.h> +#include <libempathy/empathy-contact-manager.h> + #include "empathy-contact-list-store.h" #include "empathy-ui-utils.h" #include "empathy-gtk-enum-types.h" @@ -725,19 +728,22 @@ static void contact_list_store_setup (EmpathyContactListStore *store) { EmpathyContactListStorePriv *priv; - GType types[] = {G_TYPE_STRING, /* Status icon-name */ - GDK_TYPE_PIXBUF, /* Avatar pixbuf */ - G_TYPE_BOOLEAN, /* Avatar pixbuf visible */ - G_TYPE_STRING, /* Name */ - G_TYPE_STRING, /* Status string */ - G_TYPE_BOOLEAN, /* Show status */ - EMPATHY_TYPE_CONTACT, /* Contact type */ - G_TYPE_BOOLEAN, /* Is group */ - G_TYPE_BOOLEAN, /* Is active */ - G_TYPE_BOOLEAN, /* Is online */ - G_TYPE_BOOLEAN, /* Is separator */ - G_TYPE_BOOLEAN, /* Can make audio calls */ - G_TYPE_BOOLEAN}; /* Can make video calls */ + GType types[] = { + G_TYPE_STRING, /* Status icon-name */ + GDK_TYPE_PIXBUF, /* Avatar pixbuf */ + G_TYPE_BOOLEAN, /* Avatar pixbuf visible */ + G_TYPE_STRING, /* Name */ + G_TYPE_STRING, /* Status string */ + G_TYPE_BOOLEAN, /* Show status */ + EMPATHY_TYPE_CONTACT, /* Contact type */ + G_TYPE_BOOLEAN, /* Is group */ + G_TYPE_BOOLEAN, /* Is active */ + G_TYPE_BOOLEAN, /* Is online */ + G_TYPE_BOOLEAN, /* Is separator */ + G_TYPE_BOOLEAN, /* Can make audio calls */ + G_TYPE_BOOLEAN, /* Can make video calls */ + EMPATHY_TYPE_CONTACT_LIST_FLAGS, /* Flags */ + }; priv = GET_PRIV (store); @@ -851,6 +857,8 @@ contact_list_store_add_contact (EmpathyContactListStore *store, EmpathyContactListStorePriv *priv; GtkTreeIter iter; GList *groups = NULL, *l; + TpConnection *connection; + EmpathyContactListFlags flags; priv = GET_PRIV (store); @@ -863,6 +871,14 @@ contact_list_store_add_contact (EmpathyContactListStore *store, groups = empathy_contact_list_get_groups (priv->list, contact); } + connection = empathy_contact_get_connection (contact); + if (EMPATHY_IS_CONTACT_MANAGER (priv->list)) { + flags = empathy_contact_manager_get_flags_for_connection ( + EMPATHY_CONTACT_MANAGER (priv->list), connection); + } else { + flags = 0; + } + /* If no groups just add it at the top level. */ if (!groups) { gtk_tree_store_append (GTK_TREE_STORE (store), &iter, NULL); @@ -877,6 +893,7 @@ contact_list_store_add_contact (EmpathyContactListStore *store, EMPATHY_CONTACT_LIST_STORE_COL_CAN_VIDEO_CALL, empathy_contact_get_capabilities (contact) & EMPATHY_CAPABILITIES_VIDEO, + EMPATHY_CONTACT_LIST_STORE_COL_FLAGS, flags, -1); } @@ -899,6 +916,7 @@ contact_list_store_add_contact (EmpathyContactListStore *store, EMPATHY_CONTACT_LIST_STORE_COL_CAN_VIDEO_CALL, empathy_contact_get_capabilities (contact) & EMPATHY_CAPABILITIES_VIDEO, + EMPATHY_CONTACT_LIST_STORE_COL_FLAGS, flags, -1); g_free (l->data); } diff --git a/libempathy-gtk/empathy-contact-list-store.h b/libempathy-gtk/empathy-contact-list-store.h index 007a6b069..f97853991 100644 --- a/libempathy-gtk/empathy-contact-list-store.h +++ b/libempathy-gtk/empathy-contact-list-store.h @@ -62,6 +62,7 @@ typedef enum { EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR, EMPATHY_CONTACT_LIST_STORE_COL_CAN_AUDIO_CALL, EMPATHY_CONTACT_LIST_STORE_COL_CAN_VIDEO_CALL, + EMPATHY_CONTACT_LIST_STORE_COL_FLAGS, EMPATHY_CONTACT_LIST_STORE_COL_COUNT } EmpathyContactListStoreCol; diff --git a/libempathy-gtk/empathy-contact-list-view.c b/libempathy-gtk/empathy-contact-list-view.c index f7b506e7c..783d986d0 100644 --- a/libempathy-gtk/empathy-contact-list-view.c +++ b/libempathy-gtk/empathy-contact-list-view.c @@ -292,7 +292,7 @@ contact_list_view_drag_data_received (GtkWidget *view, goto OUT; } - id = (const gchar*) selection->data; + id = (const gchar*) gtk_selection_data_get_data (selection); DEBUG ("Received %s%s drag & drop contact from roster with id:'%s'", context->action == GDK_ACTION_MOVE ? "move" : "", context->action == GDK_ACTION_COPY ? "copy" : "", @@ -817,16 +817,20 @@ contact_list_view_text_cell_data_func (GtkTreeViewColumn *tree_column, gboolean is_group; gboolean is_active; gboolean show_status; + gchar *name; gtk_tree_model_get (model, iter, EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, &is_group, EMPATHY_CONTACT_LIST_STORE_COL_IS_ACTIVE, &is_active, EMPATHY_CONTACT_LIST_STORE_COL_STATUS_VISIBLE, &show_status, + EMPATHY_CONTACT_LIST_STORE_COL_NAME, &name, -1); g_object_set (cell, "show-status", show_status, + "text", name, NULL); + g_free (name); contact_list_view_cell_set_background (view, cell, is_group, is_active); } @@ -851,7 +855,7 @@ contact_list_view_expander_cell_data_func (GtkTreeViewColumn *column, gboolean row_expanded; path = gtk_tree_model_get_path (model, iter); - row_expanded = gtk_tree_view_row_expanded (GTK_TREE_VIEW (column->tree_view), path); + row_expanded = gtk_tree_view_row_expanded (GTK_TREE_VIEW (gtk_tree_view_column_get_tree_view (column)), path); gtk_tree_path_free (path); g_object_set (cell, @@ -1302,6 +1306,31 @@ empathy_contact_list_view_dup_selected (EmpathyContactListView *view) return contact; } +EmpathyContactListFlags +empathy_contact_list_view_get_flags (EmpathyContactListView *view) +{ + EmpathyContactListViewPriv *priv; + GtkTreeSelection *selection; + GtkTreeIter iter; + GtkTreeModel *model; + EmpathyContactListFlags flags; + + g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view), 0); + + priv = GET_PRIV (view); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { + return 0; + } + + gtk_tree_model_get (model, &iter, + EMPATHY_CONTACT_LIST_STORE_COL_FLAGS, &flags, + -1); + + return flags; +} + gchar * empathy_contact_list_view_get_selected_group (EmpathyContactListView *view) { @@ -1473,6 +1502,7 @@ empathy_contact_list_view_get_contact_menu (EmpathyContactListView *view) GtkWidget *menu; GtkWidget *item; GtkWidget *image; + EmpathyContactListFlags flags; g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view), NULL); @@ -1480,25 +1510,23 @@ empathy_contact_list_view_get_contact_menu (EmpathyContactListView *view) if (!contact) { return NULL; } + flags = empathy_contact_list_view_get_flags (view); menu = empathy_contact_menu_new (contact, priv->contact_features); - if (!(priv->list_features & EMPATHY_CONTACT_LIST_FEATURE_CONTACT_REMOVE)) { - g_object_unref (contact); - return menu; - } - - if (menu) { - /* Separator */ - item = gtk_separator_menu_item_new (); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - } else { - menu = gtk_menu_new (); - } - /* Remove contact */ - if (priv->list_features & EMPATHY_CONTACT_LIST_FEATURE_CONTACT_REMOVE) { + if (priv->list_features & EMPATHY_CONTACT_LIST_FEATURE_CONTACT_REMOVE && + flags & EMPATHY_CONTACT_LIST_CAN_REMOVE) { + /* create the menu if required, or just add a separator */ + if (!menu) { + menu = gtk_menu_new (); + } else { + item = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + } + + /* Remove */ item = gtk_image_menu_item_new_with_mnemonic (_("_Remove")); image = gtk_image_new_from_icon_name (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU); diff --git a/libempathy-gtk/empathy-contact-list-view.h b/libempathy-gtk/empathy-contact-list-view.h index e9c3457d8..6666cfbb7 100644 --- a/libempathy-gtk/empathy-contact-list-view.h +++ b/libempathy-gtk/empathy-contact-list-view.h @@ -71,6 +71,7 @@ EmpathyContactListView * empathy_contact_list_view_new (Empathy EmpathyContactListFeatureFlags list_features, EmpathyContactFeatureFlags contact_features); EmpathyContact * empathy_contact_list_view_dup_selected (EmpathyContactListView *view); +EmpathyContactListFlags empathy_contact_list_view_get_flags (EmpathyContactListView *view); gchar * empathy_contact_list_view_get_selected_group (EmpathyContactListView *view); GtkWidget * empathy_contact_list_view_get_contact_menu (EmpathyContactListView *view); GtkWidget * empathy_contact_list_view_get_group_menu (EmpathyContactListView *view); diff --git a/libempathy-gtk/empathy-contact-menu.c b/libempathy-gtk/empathy-contact-menu.c index 2bad5c9fe..070d91267 100644 --- a/libempathy-gtk/empathy-contact-menu.c +++ b/libempathy-gtk/empathy-contact-menu.c @@ -28,15 +28,18 @@ #include <libempathy/empathy-call-factory.h> #include <libempathy/empathy-log-manager.h> +#include <libempathy/empathy-contact-manager.h> #include <libempathy/empathy-dispatcher.h> #include <libempathy/empathy-utils.h> #include <libempathy/empathy-chatroom-manager.h> +#include <libempathy/empathy-contact-manager.h> #include "empathy-contact-menu.h" #include "empathy-images.h" #include "empathy-log-window.h" #include "empathy-contact-dialogs.h" #include "empathy-ui-utils.h" +#include "empathy-share-my-desktop.h" GtkWidget * empathy_contact_menu_new (EmpathyContact *contact, @@ -55,6 +58,13 @@ empathy_contact_menu_new (EmpathyContact *contact, menu = gtk_menu_new (); shell = GTK_MENU_SHELL (menu); + /* Add Contact */ + item = empathy_contact_add_menu_item_new (contact); + if (item) { + gtk_menu_shell_append (shell, item); + gtk_widget_show (item); + } + /* Chat */ if (features & EMPATHY_CONTACT_FEATURE_CHAT) { item = empathy_contact_chat_menu_item_new (contact); @@ -91,6 +101,13 @@ empathy_contact_menu_new (EmpathyContact *contact, gtk_menu_shell_append (shell, item); gtk_widget_show (item); + /* Share my desktop */ + /* FIXME we should add the "Share my desktop" menu item if Vino is + a registered handler in MC5 */ + item = empathy_contact_share_my_desktop_menu_item_new (contact); + gtk_menu_shell_append (shell, item); + gtk_widget_show (item); + /* Separator */ if (features & (EMPATHY_CONTACT_FEATURE_EDIT | EMPATHY_CONTACT_FEATURE_INFO)) { @@ -117,13 +134,83 @@ empathy_contact_menu_new (EmpathyContact *contact, } static void +empathy_contact_add_menu_item_activated (GtkMenuItem *item, + EmpathyContact *contact) +{ + GtkWidget *toplevel; + + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item)); + if (!GTK_WIDGET_TOPLEVEL (toplevel) || !GTK_IS_WINDOW (toplevel)) { + toplevel = NULL; + } + + empathy_new_contact_dialog_show_with_contact (GTK_WINDOW (toplevel), + contact); +} + +GtkWidget * +empathy_contact_add_menu_item_new (EmpathyContact *contact) +{ + GtkWidget *item; + GtkWidget *image; + EmpathyContactManager *manager; + TpConnection *connection; + GList *l, *members; + gboolean found = FALSE; + EmpathyContactListFlags flags; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + + if (!empathy_contact_manager_initialized ()) { + return NULL; + } + + manager = empathy_contact_manager_dup_singleton (); + connection = empathy_contact_get_connection (contact); + + flags = empathy_contact_manager_get_flags_for_connection (manager, + connection); + + if (!(flags & EMPATHY_CONTACT_LIST_CAN_ADD)) { + return NULL; + } + + members = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (manager)); + for (l = members; l; l = l->next) { + if (!found && empathy_contact_equal (l->data, contact)) { + found = TRUE; + /* we keep iterating so that we don't leak contact + * refs */ + } + + g_object_unref (l->data); + } + g_list_free (members); + g_object_unref (manager); + + if (found) { + return NULL; + } + + item = gtk_image_menu_item_new_with_mnemonic (_("_Add Contact...")); + image = gtk_image_new_from_icon_name (GTK_STOCK_ADD, + GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); + + g_signal_connect (item, "activate", + G_CALLBACK (empathy_contact_add_menu_item_activated), + contact); + + return item; +} + +static void empathy_contact_chat_menu_item_activated (GtkMenuItem *item, EmpathyContact *contact) { empathy_dispatcher_chat_with_contact (contact, NULL, NULL); } - GtkWidget * empathy_contact_chat_menu_item_new (EmpathyContact *contact) { @@ -167,7 +254,7 @@ empathy_contact_audio_call_menu_item_new (EmpathyContact *contact) image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_VOIP, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); - gtk_widget_set_sensitive (item, empathy_contact_can_voip (contact)); + gtk_widget_set_sensitive (item, empathy_contact_can_voip_audio (contact)); gtk_widget_show (image); g_signal_connect (item, "activate", @@ -199,7 +286,7 @@ empathy_contact_video_call_menu_item_new (EmpathyContact *contact) image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_VIDEO_CALL, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); - gtk_widget_set_sensitive (item, empathy_contact_can_voip (contact)); + gtk_widget_set_sensitive (item, empathy_contact_can_voip_video (contact)); gtk_widget_show (image); g_signal_connect (item, "activate", @@ -270,6 +357,29 @@ empathy_contact_file_transfer_menu_item_new (EmpathyContact *contact) return item; } +/* FIXME we should check if the contact supports vnc stream tube */ +GtkWidget * +empathy_contact_share_my_desktop_menu_item_new (EmpathyContact *contact) +{ + GtkWidget *item; + GtkWidget *image; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + + item = gtk_image_menu_item_new_with_mnemonic (_("Share my desktop")); + image = gtk_image_new_from_icon_name (GTK_STOCK_NETWORK, + GTK_ICON_SIZE_MENU); + gtk_widget_set_sensitive (item, empathy_contact_can_use_stream_tube (contact)); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); + gtk_widget_show (image); + + g_signal_connect_swapped (item, "activate", + G_CALLBACK (empathy_share_my_desktop_share_with_contact), + contact); + + return item; +} + static void contact_info_menu_item_activate_cb (EmpathyContact *contact) { @@ -306,17 +416,36 @@ contact_edit_menu_item_activate_cb (EmpathyContact *contact) GtkWidget * empathy_contact_edit_menu_item_new (EmpathyContact *contact) { + EmpathyContactManager *manager; GtkWidget *item; GtkWidget *image; + gboolean enable = FALSE; g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + if (empathy_contact_manager_initialized ()) { + TpConnection *connection; + EmpathyContactListFlags flags; + + manager = empathy_contact_manager_dup_singleton (); + connection = empathy_contact_get_connection (contact); + flags = empathy_contact_manager_get_flags_for_connection ( + manager, connection); + + enable = (flags & EMPATHY_CONTACT_LIST_CAN_ALIAS || + flags & EMPATHY_CONTACT_LIST_CAN_GROUP); + + g_object_unref (manager); + } + item = gtk_image_menu_item_new_with_mnemonic (_("_Edit")); image = gtk_image_new_from_icon_name (GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); gtk_widget_show (image); + gtk_widget_set_sensitive (item, enable); + g_signal_connect_swapped (item, "activate", G_CALLBACK (contact_edit_menu_item_activate_cb), contact); diff --git a/libempathy-gtk/empathy-contact-menu.h b/libempathy-gtk/empathy-contact-menu.h index 262ec9650..2c623e6ba 100644 --- a/libempathy-gtk/empathy-contact-menu.h +++ b/libempathy-gtk/empathy-contact-menu.h @@ -40,6 +40,7 @@ typedef enum { GtkWidget * empathy_contact_menu_new (EmpathyContact *contact, EmpathyContactFeatureFlags features); +GtkWidget * empathy_contact_add_menu_item_new (EmpathyContact *contact); GtkWidget * empathy_contact_chat_menu_item_new (EmpathyContact *contact); GtkWidget * empathy_contact_audio_call_menu_item_new (EmpathyContact *contact); GtkWidget * empathy_contact_video_call_menu_item_new (EmpathyContact *contact); @@ -48,6 +49,7 @@ GtkWidget * empathy_contact_info_menu_item_new (EmpathyContact *cont GtkWidget * empathy_contact_edit_menu_item_new (EmpathyContact *contact); GtkWidget * empathy_contact_invite_menu_item_new (EmpathyContact *contact); GtkWidget * empathy_contact_file_transfer_menu_item_new (EmpathyContact *contact); +GtkWidget * empathy_contact_share_my_desktop_menu_item_new (EmpathyContact *contact); G_END_DECLS diff --git a/libempathy-gtk/empathy-contact-widget.c b/libempathy-gtk/empathy-contact-widget.c index 7e80d0d65..a9a673c43 100644 --- a/libempathy-gtk/empathy-contact-widget.c +++ b/libempathy-gtk/empathy-contact-widget.c @@ -47,6 +47,7 @@ #include "empathy-avatar-chooser.h" #include "empathy-avatar-image.h" #include "empathy-ui-utils.h" +#include "empathy-kludge-label.h" #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT #include <libempathy/empathy-debug.h> @@ -219,7 +220,6 @@ empathy_contact_widget_new (EmpathyContact *contact, "hbox_presence", &information->hbox_presence, "label_alias", &information->label_alias, "image_state", &information->image_state, - "label_status", &information->label_status, "table_contact", &information->table_contact, "vbox_avatar", &information->vbox_avatar, "vbox_location", &information->vbox_location, @@ -400,6 +400,13 @@ contact_widget_set_contact (EmpathyContactWidget *information, information->factory = empathy_tp_contact_factory_dup_singleton (connection); } + /* set the selected account to be the account this contact came from */ + if (contact && EMPATHY_IS_ACCOUNT_CHOOSER (information->widget_account)) { + empathy_account_chooser_set_account ( + EMPATHY_ACCOUNT_CHOOSER (information->widget_account), + empathy_contact_get_account (contact)); + } + /* Update information for widgets */ contact_widget_contact_update (information); contact_widget_groups_update (information); @@ -587,6 +594,12 @@ update_avatar_chooser_account_cb (EmpathyAccountChooser *account_chooser, static void contact_widget_contact_setup (EmpathyContactWidget *information) { + /* Setup label_status as a KludgeLabel */ + information->label_status = empathy_kludge_label_new (""); + gtk_box_pack_start (GTK_BOX (information->hbox_presence), + information->label_status, TRUE, TRUE, 0); + gtk_widget_show (information->label_status); + /* Setup account label/chooser */ if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT) { diff --git a/libempathy-gtk/empathy-contact-widget.ui b/libempathy-gtk/empathy-contact-widget.ui index c5bbd5bbe..5737b7d71 100644 --- a/libempathy-gtk/empathy-contact-widget.ui +++ b/libempathy-gtk/empathy-contact-widget.ui @@ -112,17 +112,7 @@ </packing> </child> <child> - <object class="GtkLabel" id="label_status"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="xalign">0</property> - <property name="use_markup">True</property> - <property name="wrap">True</property> - <property name="selectable">True</property> - </object> - <packing> - <property name="position">1</property> - </packing> + <placeholder/> </child> </object> <packing> diff --git a/libempathy-gtk/empathy-geometry.c b/libempathy-gtk/empathy-geometry.c index 882e15aa9..14e794c44 100644 --- a/libempathy-gtk/empathy-geometry.c +++ b/libempathy-gtk/empathy-geometry.c @@ -49,7 +49,7 @@ geometry_get_filename (void) gchar *dir; gchar *filename; - dir = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, NULL); + dir = g_build_filename (g_get_user_config_dir (), PACKAGE_NAME, NULL); if (!g_file_test (dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { DEBUG ("Creating directory:'%s'", dir); g_mkdir_with_parents (dir, GEOMETRY_DIR_CREATE_MODE); @@ -77,9 +77,13 @@ empathy_geometry_save (const gchar *name, gchar *content; gsize length; gchar *str; + gchar *escaped_name; - DEBUG ("Saving window geometry: x:%d, y:%d, w:%d, h:%d\n", - x, y, w, h); + /* escape the name so that unwanted characters such as # are removed */ + escaped_name = g_uri_escape_string (name, NULL, TRUE); + + DEBUG ("Saving window geometry: name:%s x:%d, y:%d, w:%d, h:%d\n", + escaped_name, x, y, w, h); screen = gdk_screen_get_default (); max_width = gdk_screen_get_width (screen); @@ -98,7 +102,7 @@ empathy_geometry_save (const gchar *name, filename = geometry_get_filename (); g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL); - g_key_file_set_string (key_file, GEOMETRY_GROUP_NAME, name, str); + g_key_file_set_string (key_file, GEOMETRY_GROUP_NAME, escaped_name, str); g_free (str); @@ -111,6 +115,7 @@ empathy_geometry_save (const gchar *name, g_free (content); g_free (filename); + g_free (escaped_name); g_key_file_free (key_file); } @@ -124,6 +129,10 @@ empathy_geometry_load (const gchar *name, GKeyFile *key_file; gchar *filename; gchar *str = NULL; + gchar *escaped_name; + + /* escape the name so that unwanted characters such as # are removed */ + escaped_name = g_uri_escape_string (name, NULL, TRUE); if (x) { *x = -1; @@ -146,7 +155,7 @@ empathy_geometry_load (const gchar *name, filename = geometry_get_filename (); if (g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL)) { - str = g_key_file_get_string (key_file, GEOMETRY_GROUP_NAME, name, NULL); + str = g_key_file_get_string (key_file, GEOMETRY_GROUP_NAME, escaped_name, NULL); } if (str) { @@ -177,6 +186,7 @@ empathy_geometry_load (const gchar *name, x ? *x : -1, y ? *y : -1, w ? *w : -1, h ? *h : -1); g_free (filename); + g_free (escaped_name); g_key_file_free (key_file); } diff --git a/libempathy-gtk/empathy-kludge-label.c b/libempathy-gtk/empathy-kludge-label.c new file mode 100644 index 000000000..f4a29dec2 --- /dev/null +++ b/libempathy-gtk/empathy-kludge-label.c @@ -0,0 +1,89 @@ +/* vim: set ts=4 sts=4 sw=4 et: */ +/* + * 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 + * + * Authors: Davyd Madeley <davyd.madeley@collabora.co.uk> + */ + +#include "empathy-kludge-label.h" + +G_DEFINE_TYPE (EmpathyKludgeLabel, empathy_kludge_label, GTK_TYPE_LABEL); + +static void +empathy_kludge_label_size_allocate (GtkWidget *self, + GtkAllocation *allocation) +{ + PangoLayout *layout; + + GTK_WIDGET_CLASS (empathy_kludge_label_parent_class)->size_allocate ( + self, allocation); + + /* force the width of the PangoLayout to be the width of the allocation */ + layout = gtk_label_get_layout (GTK_LABEL (self)); + pango_layout_set_width (layout, allocation->width * PANGO_SCALE); +} + +static gboolean +empathy_kludge_label_expose_event (GtkWidget *self, + GdkEventExpose *event) +{ + PangoLayout *layout; + PangoRectangle rect; + GtkAllocation real_allocation; + gboolean r; + + layout = gtk_label_get_layout (GTK_LABEL (self)); + pango_layout_get_pixel_extents (layout, NULL, &rect); + + /* this is mind-bendingly evil: + * get_layout_location() is going to remove rect.x from the position of the + * layout when painting it. This really sucks. We're going to compensate by + * adding this value to the allocation. + */ + real_allocation = self->allocation; + self->allocation.x += rect.x; + + r = GTK_WIDGET_CLASS (empathy_kludge_label_parent_class)->expose_event ( + self, event); + + self->allocation = real_allocation; + + return r; +} + +static void +empathy_kludge_label_class_init (EmpathyKludgeLabelClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + widget_class->size_allocate = empathy_kludge_label_size_allocate; + widget_class->expose_event = empathy_kludge_label_expose_event; +} + +static void +empathy_kludge_label_init (EmpathyKludgeLabel *self) +{ +} + +GtkWidget * +empathy_kludge_label_new (const char *str) +{ + return g_object_new (EMPATHY_TYPE_KLUDGE_LABEL, + "label", str, + "xalign", 0., + NULL); +} diff --git a/libempathy-gtk/empathy-kludge-label.h b/libempathy-gtk/empathy-kludge-label.h new file mode 100644 index 000000000..f2ea1e938 --- /dev/null +++ b/libempathy-gtk/empathy-kludge-label.h @@ -0,0 +1,53 @@ +/* + * 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 + * + * Authors: Davyd Madeley <davyd.madeley@collabora.co.uk> + */ + +#ifndef __EMPATHY_KLUDGE_LABEL_H__ +#define __EMPATHY_KLUDGE_LABEL_H__ + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_KLUDGE_LABEL (empathy_kludge_label_get_type ()) +#define EMPATHY_KLUDGE_LABEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMPATHY_TYPE_KLUDGE_LABEL, EmpathyKludgeLabel)) +#define EMPATHY_KLUDGE_LABEL_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), EMPATHY_TYPE_KLUDGE_LABEL, EmpathyKludgeLabelClass)) +#define EMPATHY_IS_KLUDGE_LABEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMPATHY_TYPE_KLUDGE_LABEL)) +#define EMPATHY_IS_KLUDGE_LABEL_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), EMPATHY_TYPE_KLUDGE_LABEL)) +#define EMPATHY_KLUDGE_LABEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_KLUDGE_LABEL, EmpathyKludgeLabelClass)) + +typedef struct _EmpathyKludgeLabel EmpathyKludgeLabel; +typedef struct _EmpathyKludgeLabelClass EmpathyKludgeLabelClass; + +struct _EmpathyKludgeLabel +{ + GtkLabel parent; +}; + +struct _EmpathyKludgeLabelClass +{ + GtkLabelClass parent_class; +}; + +GType empathy_kludge_label_get_type (void); +GtkWidget *empathy_kludge_label_new (const char *str); + +G_END_DECLS + +#endif diff --git a/libempathy-gtk/empathy-new-message-dialog.ui b/libempathy-gtk/empathy-new-message-dialog.ui index e24095fba..a7b43818c 100644 --- a/libempathy-gtk/empathy-new-message-dialog.ui +++ b/libempathy-gtk/empathy-new-message-dialog.ui @@ -1,6 +1,14 @@ <?xml version="1.0"?> <!--*- mode: xml -*--> <interface> + <object class="GtkImage" id="call_image"> + <property name="icon_name">audio-input-microphone</property> + <property name="icon-size">4</property> + </object> + <object class="GtkImage" id="chat_image"> + <property name="icon_name">im-message-new</property> + <property name="icon-size">4</property> + </object> <object class="GtkDialog" id="new_message_dialog"> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="border_width">5</property> @@ -82,41 +90,9 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="can_default">True</property> - <child> - <object class="GtkAlignment" id="alignment1"> - <property name="visible">True</property> - <property name="xscale">0</property> - <property name="yscale">0</property> - <child> - <object class="GtkHBox" id="hbox1"> - <property name="visible">True</property> - <property name="spacing">2</property> - <child> - <object class="GtkImage" id="image1"> - <property name="visible">True</property> - <property name="icon_name">audio-input-microphone</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label3"> - <property name="visible">True</property> - <property name="label" translatable="yes">C_all</property> - <property name="use_underline">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> + <property name="image">call_image</property> + <property name="label" translatable="yes">C_all</property> + <property name="use_underline">True</property> </object> <packing> <property name="position">1</property> @@ -128,41 +104,9 @@ <property name="can_focus">True</property> <property name="can_default">True</property> <property name="has_default">True</property> - <child> - <object class="GtkAlignment" id="alignment2"> - <property name="visible">True</property> - <property name="xscale">0</property> - <property name="yscale">0</property> - <child> - <object class="GtkHBox" id="hbox2"> - <property name="visible">True</property> - <property name="spacing">2</property> - <child> - <object class="GtkImage" id="image2"> - <property name="visible">True</property> - <property name="icon_name">im-message-new</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label4"> - <property name="visible">True</property> - <property name="label" translatable="yes">C_hat</property> - <property name="use_underline">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> + <property name="image">chat_image</property> + <property name="label" translatable="yes">C_hat</property> + <property name="use_underline">True</property> </object> <packing> <property name="position">2</property> diff --git a/libempathy-gtk/empathy-presence-chooser.c b/libempathy-gtk/empathy-presence-chooser.c index 8fba26ff7..69b031c05 100644 --- a/libempathy-gtk/empathy-presence-chooser.c +++ b/libempathy-gtk/empathy-presence-chooser.c @@ -79,9 +79,9 @@ enum { /* For combobox's model */ enum { + COL_STATUS_TEXT, COL_STATE_ICON_NAME, COL_STATE, - COL_STATUS_TEXT, COL_DISPLAY_MARKUP, COL_STATUS_CUSTOMISABLE, COL_TYPE, @@ -162,9 +162,9 @@ presence_chooser_create_model (EmpathyPresenceChooser *self) int i; store = gtk_list_store_new (N_COLUMNS, + G_TYPE_STRING, /* COL_STATUS_TEXT */ G_TYPE_STRING, /* COL_STATE_ICON_NAME */ G_TYPE_UINT, /* COL_STATE */ - G_TYPE_STRING, /* COL_STATUS_TEXT */ G_TYPE_STRING, /* COL_DISPLAY_MARKUP */ G_TYPE_BOOLEAN, /* COL_STATUS_CUSTOMISABLE */ G_TYPE_INT); /* COL_TYPE */ @@ -179,9 +179,9 @@ presence_chooser_create_model (EmpathyPresenceChooser *self) icon_name = empathy_icon_name_for_presence (states[i].state); gtk_list_store_insert_with_values (store, NULL, -1, + COL_STATUS_TEXT, status, COL_STATE_ICON_NAME, icon_name, COL_STATE, states[i].state, - COL_STATUS_TEXT, status, COL_DISPLAY_MARKUP, status, COL_STATUS_CUSTOMISABLE, states[i].customisable, COL_TYPE, ENTRY_TYPE_BUILTIN, @@ -194,9 +194,9 @@ presence_chooser_create_model (EmpathyPresenceChooser *self) for (l = list; l; l = l->next) { gtk_list_store_insert_with_values (store, NULL, -1, + COL_STATUS_TEXT, l->data, COL_STATE_ICON_NAME, icon_name, COL_STATE, states[i].state, - COL_STATUS_TEXT, l->data, COL_DISPLAY_MARKUP, l->data, COL_STATUS_CUSTOMISABLE, TRUE, COL_TYPE, ENTRY_TYPE_SAVED, @@ -205,9 +205,9 @@ presence_chooser_create_model (EmpathyPresenceChooser *self) g_list_free (list); gtk_list_store_insert_with_values (store, NULL, -1, + COL_STATUS_TEXT, _("Custom Message..."), COL_STATE_ICON_NAME, icon_name, COL_STATE, states[i].state, - COL_STATUS_TEXT, "", COL_DISPLAY_MARKUP, custom_message, COL_STATUS_CUSTOMISABLE, TRUE, COL_TYPE, ENTRY_TYPE_CUSTOM, @@ -222,8 +222,8 @@ presence_chooser_create_model (EmpathyPresenceChooser *self) -1); gtk_list_store_insert_with_values (store, NULL, -1, + COL_STATUS_TEXT, _("Edit Custom Messages..."), COL_STATE_ICON_NAME, GTK_STOCK_EDIT, - COL_STATUS_TEXT, "", COL_DISPLAY_MARKUP, _("Edit Custom Messages..."), COL_TYPE, ENTRY_TYPE_EDIT_CUSTOM, -1); diff --git a/libempathy-gtk/empathy-share-my-desktop.c b/libempathy-gtk/empathy-share-my-desktop.c new file mode 100644 index 000000000..4a5fce916 --- /dev/null +++ b/libempathy-gtk/empathy-share-my-desktop.c @@ -0,0 +1,245 @@ +/* + * © 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: Arnaud Maillet <arnaud.maillet@collabora.co.uk> + */ + +#include <gtk/gtk.h> + +#include <dbus/dbus-glib.h> +#include <telepathy-glib/util.h> +#include <telepathy-glib/contact.h> +#define DEBUG_FLAG EMPATHY_DEBUG_SHARE_DESKTOP +#include <libempathy/empathy-debug.h> + +#include "empathy-share-my-desktop.h" + +#define DBUS_SERVICE "org.gnome.Vino" +#define DBUS_INTERFACE "org.gnome.VinoScreen" + +typedef struct { + TpContact *contact; + TpChannel *channel; + gulong signal_invalidated_id; +} EmpathyShareMyDesktopPrivate; + + +static void +empathy_share_my_desktop_tube_invalidated (TpProxy *channel, + guint domain, + gint code, + gchar *message, + gpointer object) +{ + EmpathyShareMyDesktopPrivate *data = (EmpathyShareMyDesktopPrivate *) object; + + DEBUG ("Tube is invalidated"); + + g_signal_handler_disconnect (G_OBJECT (data->channel), + data->signal_invalidated_id); + + if (data->channel != NULL) + { + g_object_unref (data->channel); + data->channel = NULL; + } + + g_slice_free (EmpathyShareMyDesktopPrivate, data); +} + +static void +empathy_share_my_desktop_channel_ready (TpChannel *channel, + const GError *error_failed, + gpointer object) +{ + EmpathyShareMyDesktopPrivate *data = (EmpathyShareMyDesktopPrivate *) object; + TpConnection *connection; + gchar * connection_path; + gchar * tube_path; + DBusGConnection *dbus_g_connection; + GHashTable *channel_properties; + DBusGProxy *proxy; + GError *error = NULL; + GdkScreen *screen; + gchar *obj_path; + GtkWidget *window; + + if (channel == NULL) + { + DEBUG ("The channel is not ready: %s", error_failed->message); + return; + } + + data->channel = channel; + + data->signal_invalidated_id = g_signal_connect (G_OBJECT (channel), + "invalidated", G_CALLBACK (empathy_share_my_desktop_tube_invalidated), + data); + + dbus_g_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); + + if (dbus_g_connection == NULL) + { + DEBUG ("Failed to open connection to bus: %s", error->message); + g_clear_error (&error); + return; + } + + screen = gdk_screen_get_default (); + obj_path = g_strdup_printf ("/org/gnome/vino/screens/%d", + gdk_screen_get_number (screen)); + + proxy = dbus_g_proxy_new_for_name (dbus_g_connection, DBUS_SERVICE, + obj_path, DBUS_INTERFACE); + + connection = tp_channel_borrow_connection (channel); + + g_object_get (connection, "object-path", &connection_path, NULL); + + DEBUG ("connection path : %s", connection_path); + + g_object_get (channel, "object-path", &tube_path, "channel-properties", + &channel_properties, NULL); + + DEBUG ("tube path : %s", tube_path); + + if (!dbus_g_proxy_call (proxy, "ShareWithTube", &error, + DBUS_TYPE_G_OBJECT_PATH, connection_path, + DBUS_TYPE_G_OBJECT_PATH, tube_path, + dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), + channel_properties, + G_TYPE_INVALID, G_TYPE_INVALID)) + { + window = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, + "Vino doesn't support telepathy"); + gtk_dialog_run (GTK_DIALOG (window)); + gtk_widget_destroy (window); + DEBUG ("Failed to request name: %s", + error ? error->message : "No error given"); + g_clear_error (&error); + } + + g_hash_table_unref (channel_properties); + g_free (connection_path); + g_free (tube_path); + g_free (obj_path); + g_object_unref (proxy); +} + +static void +empathy_share_my_desktop_create_channel_cb (TpConnection *connection, + const gchar *object_path, + GHashTable *channel_properties, + const GError *error_failed, + gpointer user_data, + GObject *object) +{ + EmpathyShareMyDesktopPrivate *data = (EmpathyShareMyDesktopPrivate *) + user_data; + + TpChannel *channel; + GError *error = NULL; + + if (object_path == NULL) + { + DEBUG ("CreateChannel failed: %s", error_failed->message); + return; + } + + DEBUG ("Offering a new stream tube"); + + channel = tp_channel_new_from_properties (connection, object_path, + channel_properties, &error); + + if (channel == NULL) + { + DEBUG ("Error requesting channel: %s", error->message); + g_clear_error (&error); + return; + } + + tp_channel_call_when_ready (channel, + empathy_share_my_desktop_channel_ready, data); +} + +static void +empathy_share_my_desktop_connection_ready (TpConnection *connection, + const GError *error, + gpointer object) +{ + EmpathyShareMyDesktopPrivate *data = (EmpathyShareMyDesktopPrivate *) object; + GHashTable *request; + GValue *value; + + if (connection == NULL) + { + DEBUG ("The connection is not ready: %s", error->message); + return; + } + + request = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, + (GDestroyNotify) tp_g_value_slice_free); + + /* org.freedesktop.Telepathy.Channel.ChannelType */ + value = tp_g_value_slice_new_static_string + (TP_IFACE_CHANNEL_TYPE_STREAM_TUBE); + g_hash_table_insert (request, TP_IFACE_CHANNEL ".ChannelType", value); + + /* org.freedesktop.Telepathy.Channel.TargetHandleType */ + value = tp_g_value_slice_new_uint (TP_HANDLE_TYPE_CONTACT); + g_hash_table_insert (request, TP_IFACE_CHANNEL ".TargetHandleType", value); + + /* org.freedesktop.Telepathy.Channel.TargetHandleType */ + value = tp_g_value_slice_new_uint (tp_contact_get_handle + (data->contact)); + g_hash_table_insert (request, TP_IFACE_CHANNEL ".TargetHandle", value); + + /* org.freedesktop.Telepathy.Channel.Type.StreamTube.Service */ + value = tp_g_value_slice_new_static_string ("x_vnc"); + g_hash_table_insert (request, + TP_IFACE_CHANNEL_TYPE_STREAM_TUBE ".Service", + value); + + tp_cli_connection_interface_requests_call_create_channel + (connection, -1, request, empathy_share_my_desktop_create_channel_cb, + data, NULL, NULL); + + g_hash_table_destroy (request); +} + +void +empathy_share_my_desktop_share_with_contact (EmpathyContact *contact) +{ + TpConnection *connection; + EmpathyShareMyDesktopPrivate *data; + data = g_slice_new (EmpathyShareMyDesktopPrivate); + data->contact = empathy_contact_get_tp_contact (contact); + + DEBUG ("Creation of ShareMyDesktop"); + + if (!TP_IS_CONTACT (data->contact)) + { + DEBUG ("It's not a tp contact"); + return; + } + + connection = tp_contact_get_connection (data->contact); + + tp_connection_call_when_ready (connection, + empathy_share_my_desktop_connection_ready, data); +} diff --git a/libempathy-gtk/empathy-share-my-desktop.h b/libempathy-gtk/empathy-share-my-desktop.h new file mode 100644 index 000000000..3efeecc14 --- /dev/null +++ b/libempathy-gtk/empathy-share-my-desktop.h @@ -0,0 +1,28 @@ +/* + * © 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: Arnaud Maillet <arnaud.maillet@collabora.co.uk> + */ + +#ifndef __EMPATHY_SHARE_MY_DESKTOP_H__ +#define __EMPATHY_SHARE_MY_DESKTOP_H__ + +#include <libempathy/empathy-contact.h> + +void empathy_share_my_desktop_share_with_contact (EmpathyContact *contact); + +#endif
\ No newline at end of file diff --git a/libempathy-gtk/empathy-status-preset-dialog.c b/libempathy-gtk/empathy-status-preset-dialog.c index 7ac13ad38..802d116e7 100644 --- a/libempathy-gtk/empathy-status-preset-dialog.c +++ b/libempathy-gtk/empathy-status-preset-dialog.c @@ -559,8 +559,8 @@ empathy_status_preset_dialog_init (EmpathyStatusPresetDialog *self) status_preset_dialog_setup_presets_treeview (self); status_preset_dialog_setup_add_combobox (self); - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (self)->vbox), toplevel_vbox, - TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), + toplevel_vbox, TRUE, TRUE, 0); g_object_unref (gui); } diff --git a/libempathy-gtk/empathy-theme-adium.c b/libempathy-gtk/empathy-theme-adium.c index 0cc2c034d..e04771597 100644 --- a/libempathy-gtk/empathy-theme-adium.c +++ b/libempathy-gtk/empathy-theme-adium.c @@ -51,8 +51,12 @@ typedef struct { EmpathySmileyManager *smiley_manager; EmpathyContact *last_contact; time_t last_timestamp; + gboolean last_is_backlog; gboolean page_loaded; GList *message_queue; + gchar *hovered_uri; + guint notify_enable_webkit_developer_tools_id; + GtkWidget *inspector_window; } EmpathyThemeAdiumPriv; struct _EmpathyAdiumData { @@ -65,12 +69,20 @@ struct _EmpathyAdiumData { gchar *template_html; gchar *in_content_html; gsize in_content_len; + gchar *in_context_html; + gsize in_context_len; gchar *in_nextcontent_html; gsize in_nextcontent_len; + gchar *in_nextcontext_html; + gsize in_nextcontext_len; gchar *out_content_html; gsize out_content_len; + gchar *out_context_html; + gsize out_context_len; gchar *out_nextcontent_html; gsize out_nextcontent_len; + gchar *out_nextcontext_html; + gsize out_nextcontext_len; gchar *status_html; gsize status_len; GHashTable *info; @@ -88,6 +100,31 @@ G_DEFINE_TYPE_WITH_CODE (EmpathyThemeAdium, empathy_theme_adium, G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CHAT_VIEW, theme_adium_iface_init)); +static void +theme_adium_update_enable_webkit_developer_tools (EmpathyThemeAdium *theme) +{ + WebKitWebView *web_view = WEBKIT_WEB_VIEW (theme); + gboolean enable_webkit_developer_tools; + + if (empathy_conf_get_bool (empathy_conf_get (), "/apps/empathy/conversation/enable_webkit_developer_tools", &enable_webkit_developer_tools) == FALSE) + return; + + g_object_set (G_OBJECT (webkit_web_view_get_settings (web_view)), + "enable-developer-extras", + enable_webkit_developer_tools, + NULL); +} + +static void +theme_adium_notify_enable_webkit_developer_tools_cb (EmpathyConf *conf, + const gchar *key, + gpointer user_data) +{ + EmpathyThemeAdium *theme = user_data; + + theme_adium_update_enable_webkit_developer_tools (theme); +} + static WebKitNavigationResponse theme_adium_navigation_requested_cb (WebKitWebView *view, WebKitWebFrame *frame, @@ -103,15 +140,81 @@ theme_adium_navigation_requested_cb (WebKitWebView *view, } static void +theme_adium_hovering_over_link_cb (EmpathyThemeAdium *theme, + gchar *title, + gchar *uri, + gpointer user_data) +{ + EmpathyThemeAdiumPriv *priv = GET_PRIV (theme); + + if (tp_strdiff (uri, priv->hovered_uri)) { + g_free (priv->hovered_uri); + priv->hovered_uri = g_strdup (uri); + } +} + +static void +theme_adium_copy_address_cb (GtkMenuItem *menuitem, + gpointer user_data) +{ + EmpathyThemeAdium *theme = EMPATHY_THEME_ADIUM (user_data); + EmpathyThemeAdiumPriv *priv = GET_PRIV (theme); + GtkClipboard *clipboard; + + clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); + gtk_clipboard_set_text (clipboard, priv->hovered_uri, -1); + + clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY); + gtk_clipboard_set_text (clipboard, priv->hovered_uri, -1); +} + +static void +theme_adium_open_address_cb (GtkMenuItem *menuitem, + gpointer user_data) +{ + EmpathyThemeAdium *theme = EMPATHY_THEME_ADIUM (user_data); + EmpathyThemeAdiumPriv *priv = GET_PRIV (theme); + + empathy_url_show (GTK_WIDGET (menuitem), priv->hovered_uri); +} + +static void theme_adium_populate_popup_cb (WebKitWebView *view, GtkMenu *menu, gpointer user_data) { - GtkWidget *item; + EmpathyThemeAdium *theme = EMPATHY_THEME_ADIUM (view); + EmpathyThemeAdiumPriv *priv = GET_PRIV (theme); + GtkWidget *item; + GList *items; + GtkWidget *icon; + gchar *stock_id; + gboolean is_link = FALSE; + gboolean developer_tools_enabled; + + /* FIXME: WebKitGTK+'s context menu API clearly needs an + * overhaul. There is currently no way to know what is being + * clicked, to decide what features to provide. You either + * take what it gives you as a menu, or use hacks to figure + * out what to display. */ + items = gtk_container_get_children (GTK_CONTAINER (menu)); + item = GTK_WIDGET (g_list_nth_data (items, 0)); + g_list_free (items); + + if (GTK_IS_IMAGE_MENU_ITEM (item)) { + icon = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (item)); + gtk_image_get_stock (GTK_IMAGE (icon), &stock_id, NULL); + + if ((!strcmp (stock_id, GTK_STOCK_OPEN)) && priv->hovered_uri) + is_link = TRUE; + } /* Remove default menu items */ - gtk_container_foreach (GTK_CONTAINER (menu), - (GtkCallback) gtk_widget_destroy, NULL); + g_object_get (G_OBJECT (webkit_web_view_get_settings (view)), + "enable-developer-extras", &developer_tools_enabled, NULL); + if (!developer_tools_enabled) + gtk_container_foreach (GTK_CONTAINER (menu), + (GtkCallback) gtk_widget_destroy, NULL); /* Select all item */ item = gtk_image_menu_item_new_from_stock (GTK_STOCK_SELECT_ALL, NULL); @@ -146,10 +249,31 @@ theme_adium_populate_popup_cb (WebKitWebView *view, G_CALLBACK (empathy_chat_view_clear), view); - /* FIXME: Add open_link and copy_link when those bugs are fixed: - * https://bugs.webkit.org/show_bug.cgi?id=16092 - * https://bugs.webkit.org/show_bug.cgi?id=16562 - */ + /* We will only add the following menu items if we are + * right-clicking a link */ + if (!is_link) + return; + + /* Separator */ + item = gtk_separator_menu_item_new (); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + + /* Copy Link Address menu item */ + item = gtk_menu_item_new_with_mnemonic (_("_Copy Link Address")); + g_signal_connect (item, "activate", + G_CALLBACK (theme_adium_copy_address_cb), + view); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + + /* Open Link menu item */ + item = gtk_menu_item_new_with_mnemonic (_("_Open Link")); + g_signal_connect (item, "activate", + G_CALLBACK (theme_adium_open_address_cb), + view); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); } static gchar * @@ -402,7 +526,8 @@ theme_adium_append_message (EmpathyChatView *view, gsize len = 0; const gchar *func; const gchar *service_name; - const gchar *message_classes = NULL; + GString *message_classes = NULL; + gboolean is_backlog; if (!priv->page_loaded) { priv->message_queue = g_list_prepend (priv->message_queue, @@ -455,45 +580,102 @@ theme_adium_append_message (EmpathyChatView *view, } } + is_backlog = empathy_message_is_backlog (msg); + /* Get the right html/func to add the message */ func = "appendMessage"; + + message_classes = g_string_new ("message"); + + /* eventually append the "history" class */ + if (is_backlog) { + g_string_append (message_classes, " history"); + } + + /* check the sender of the message and append the appropriate class */ + if (empathy_contact_is_user (sender)) { + g_string_append (message_classes, " outgoing"); + } + else { + g_string_append (message_classes, " incoming"); + } + /* * To mimick Adium's behavior, we only want to join messages - * sent within a 5 minute time frame. + * sent by the same contact within a 5 minute time frame. */ if (empathy_contact_equal (priv->last_contact, sender) && - (timestamp - priv->last_timestamp < MESSAGE_JOIN_PERIOD)) { + (timestamp - priv->last_timestamp < MESSAGE_JOIN_PERIOD) && + (is_backlog == priv->last_is_backlog)) { + /* the messages can be appended */ func = "appendNextMessage"; + g_string_append (message_classes, " consecutive"); + + /* check who is the sender of the message to use the correct html file */ if (empathy_contact_is_user (sender)) { - message_classes = "consecutive incoming message"; - html = priv->data->out_nextcontent_html; - len = priv->data->out_nextcontent_len; + /* check if this is a backlog message and use NextContext.html */ + if (is_backlog) { + html = priv->data->out_nextcontext_html; + len = priv->data->out_nextcontext_len; + } + + /* + * html is null if this is not a backlog message or + * if we have to fallback (NextContext.html missing). + * use NextContent.html + */ + if (html == NULL) { + html = priv->data->out_nextcontent_html; + len = priv->data->out_nextcontent_len; + } } - if (!html) { - message_classes = "consecutive message outgoing"; - html = priv->data->in_nextcontent_html; - len = priv->data->in_nextcontent_len; + else { + if (is_backlog) { + html = priv->data->in_nextcontext_html; + len = priv->data->in_nextcontext_len; + } + + if (html == NULL) { + html = priv->data->in_nextcontent_html; + len = priv->data->in_nextcontent_len; + } } } - if (!html) { + + /* + * we have html == NULL here if: + * 1. the message didn't have to be appended because + * the sender was different or the timestamp was too far + * 2. NextContent.html file does not exist, so we must + * not forget to fallback to the correct Content.html + */ + if (html == NULL) { if (empathy_contact_is_user (sender)) { - if (!message_classes) { - message_classes = "incoming message"; + if (is_backlog) { + html = priv->data->out_context_html; + len = priv->data->out_context_len; + } + + if (html == NULL) { + html = priv->data->out_content_html; + len = priv->data->out_content_len; } - html = priv->data->out_content_html; - len = priv->data->out_content_len; } - if (!html) { - if (!message_classes) { - message_classes = "message outgoing"; + else { + if (is_backlog) { + html = priv->data->in_context_html; + len = priv->data->in_context_len; + } + + if (html == NULL) { + html = priv->data->in_content_html; + len = priv->data->in_content_len; } - html = priv->data->in_content_html; - len = priv->data->in_content_len; } } theme_adium_append_html (theme, func, html, len, body, avatar_filename, - name, contact_id, service_name, message_classes, + name, contact_id, service_name, message_classes->str, timestamp); /* Keep the sender of the last displayed message */ @@ -502,8 +684,10 @@ theme_adium_append_message (EmpathyChatView *view, } priv->last_contact = g_object_ref (sender); priv->last_timestamp = timestamp; + priv->last_is_backlog = is_backlog; g_free (dup_body); + g_string_free (message_classes, TRUE); } static void @@ -560,6 +744,13 @@ theme_adium_clear (EmpathyChatView *view) priv->data->template_html, basedir_uri); g_free (basedir_uri); + + /* Clear last contact to avoid trying to add a 'joined' + * message when we don't have an insertion point. */ + if (priv->last_contact) { + g_object_unref (priv->last_contact); + priv->last_contact = NULL; + } } static gboolean @@ -657,6 +848,10 @@ theme_adium_finalize (GObject *object) EmpathyThemeAdiumPriv *priv = GET_PRIV (object); empathy_adium_data_unref (priv->data); + g_free (priv->hovered_uri); + + empathy_conf_notify_remove (empathy_conf_get (), + priv->notify_enable_webkit_developer_tools_id); G_OBJECT_CLASS (empathy_theme_adium_parent_class)->finalize (object); } @@ -676,9 +871,77 @@ theme_adium_dispose (GObject *object) priv->last_contact = NULL; } + if (priv->inspector_window) { + gtk_widget_destroy (priv->inspector_window); + priv->inspector_window = NULL; + } + G_OBJECT_CLASS (empathy_theme_adium_parent_class)->dispose (object); } +static gboolean +theme_adium_inspector_show_window_cb (WebKitWebInspector *inspector, + gpointer user_data) +{ + EmpathyThemeAdium *theme = user_data; + EmpathyThemeAdiumPriv *priv = GET_PRIV (theme); + + gtk_widget_show_all (priv->inspector_window); + + return TRUE; +} + +static gboolean +theme_adium_inspector_close_window_cb (WebKitWebInspector *inspector, + gpointer user_data) +{ + EmpathyThemeAdium *theme = user_data; + EmpathyThemeAdiumPriv *priv; + + /* We may be called too late - when the theme has already been + * destroyed */ + if (!theme) + return FALSE; + + priv = GET_PRIV (theme); + + if (priv->inspector_window) { + gtk_widget_hide (priv->inspector_window); + } + + return TRUE; +} + +static WebKitWebView * +theme_adium_inspect_web_view_cb (WebKitWebInspector *inspector, + WebKitWebView *web_view, + gpointer data) +{ + EmpathyThemeAdiumPriv *priv = GET_PRIV (EMPATHY_THEME_ADIUM (web_view)); + GtkWidget *scrolled_window; + GtkWidget *inspector_web_view; + + if (!priv->inspector_window) { + priv->inspector_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size (GTK_WINDOW (priv->inspector_window), + 800, 600); + + g_signal_connect (priv->inspector_window, "delete-event", + G_CALLBACK (gtk_widget_hide_on_delete), NULL); + + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_container_add (GTK_CONTAINER (priv->inspector_window), scrolled_window); + + inspector_web_view = webkit_web_view_new (); + gtk_container_add (GTK_CONTAINER (scrolled_window), inspector_web_view); + + return WEBKIT_WEB_VIEW (inspector_web_view); + } + + return NULL; +} + static void theme_adium_constructed (GObject *object) { @@ -698,7 +961,15 @@ theme_adium_constructed (GObject *object) if (font_size) { g_object_set (G_OBJECT (webkit_settings), "default-font-size", font_size, NULL); } - webkit_web_view_set_settings (WEBKIT_WEB_VIEW (object), webkit_settings); + + g_signal_connect (webkit_web_view_get_inspector (WEBKIT_WEB_VIEW (object)), "inspect-web-view", + G_CALLBACK (theme_adium_inspect_web_view_cb), NULL); + + g_signal_connect (webkit_web_view_get_inspector (WEBKIT_WEB_VIEW (object)), "show-window", + G_CALLBACK (theme_adium_inspector_show_window_cb), object); + + g_signal_connect (webkit_web_view_get_inspector (WEBKIT_WEB_VIEW (object)), "close-window", + G_CALLBACK (theme_adium_inspector_close_window_cb), NULL); /* Load template */ basedir_uri = g_strconcat ("file://", priv->data->basedir, NULL); @@ -768,7 +1039,6 @@ empathy_theme_adium_class_init (EmpathyThemeAdiumClass *klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_type_class_add_private (object_class, sizeof (EmpathyThemeAdiumPriv)); } @@ -791,6 +1061,17 @@ empathy_theme_adium_init (EmpathyThemeAdium *theme) g_signal_connect (theme, "populate-popup", G_CALLBACK (theme_adium_populate_popup_cb), NULL); + g_signal_connect (theme, "hovering-over-link", + G_CALLBACK (theme_adium_hovering_over_link_cb), + NULL); + + priv->notify_enable_webkit_developer_tools_id = + empathy_conf_notify_add (empathy_conf_get (), + "/apps/empathy/conversation/enable_webkit_developer_tools", + theme_adium_notify_enable_webkit_developer_tools_cb, + theme); + + theme_adium_update_enable_webkit_developer_tools (theme); } EmpathyThemeAdium * @@ -809,6 +1090,15 @@ empathy_adium_path_is_valid (const gchar *path) gboolean ret; gchar *file; + /* The theme is not valid if there is no Info.plist */ + file = g_build_filename (path, "Contents", "Info.plist", + NULL); + ret = g_file_test (file, G_FILE_TEST_EXISTS); + g_free (file); + + if (ret == FALSE) + return ret; + /* We ship a default Template.html as fallback if there is any problem * with the one inside the theme. The only other required file is * Content.html for incoming messages (outgoing fallback to use @@ -834,10 +1124,15 @@ empathy_adium_info_new (const gchar *path) value = empathy_plist_parse_from_file (file); g_free (file); - if (value) { - info = g_value_dup_boxed (value); - tp_g_value_slice_free (value); - } + if (value == NULL) + return NULL; + + info = g_value_dup_boxed (value); + tp_g_value_slice_free (value); + + /* Insert the theme's path into the hash table, + * keys have to be dupped */ + tp_asv_set_string (info, g_strdup ("path"), path); return info; } @@ -890,6 +1185,14 @@ empathy_adium_data_new_with_info (const gchar *path, GHashTable *info) g_file_get_contents (file, &data->in_nextcontent_html, &data->in_nextcontent_len, NULL); g_free (file); + file = g_build_filename (data->basedir, "Incoming", "Context.html", NULL); + g_file_get_contents (file, &data->in_context_html, &data->in_context_len, NULL); + g_free (file); + + file = g_build_filename (data->basedir, "Incoming", "NextContext.html", NULL); + g_file_get_contents (file, &data->in_nextcontext_html, &data->in_nextcontext_len, NULL); + g_free (file); + file = g_build_filename (data->basedir, "Outgoing", "Content.html", NULL); g_file_get_contents (file, &data->out_content_html, &data->out_content_len, NULL); g_free (file); @@ -898,6 +1201,14 @@ empathy_adium_data_new_with_info (const gchar *path, GHashTable *info) g_file_get_contents (file, &data->out_nextcontent_html, &data->out_nextcontent_len, NULL); g_free (file); + file = g_build_filename (data->basedir, "Outgoing", "Context.html", NULL); + g_file_get_contents (file, &data->out_context_html, &data->out_context_len, NULL); + g_free (file); + + file = g_build_filename (data->basedir, "Outgoing", "NextContext.html", NULL); + g_file_get_contents (file, &data->out_nextcontext_html, &data->out_nextcontext_len, NULL); + g_free (file); + file = g_build_filename (data->basedir, "Status.html", NULL); g_file_get_contents (file, &data->status_html, &data->status_len, NULL); g_free (file); @@ -1001,7 +1312,7 @@ empathy_adium_data_ref (EmpathyAdiumData *data) { g_return_val_if_fail (data != NULL, NULL); - data->ref_count++; + g_atomic_int_inc (&data->ref_count); return data; } @@ -1011,15 +1322,18 @@ empathy_adium_data_unref (EmpathyAdiumData *data) { g_return_if_fail (data != NULL); - data->ref_count--; - if (data->ref_count == 0) { + if (g_atomic_int_dec_and_test (&data->ref_count)) { g_free (data->path); g_free (data->basedir); g_free (data->template_html); g_free (data->in_content_html); g_free (data->in_nextcontent_html); + g_free (data->in_context_html); + g_free (data->in_nextcontext_html); g_free (data->out_content_html); g_free (data->out_nextcontent_html); + g_free (data->out_context_html); + g_free (data->out_nextcontext_html); g_free (data->default_avatar_filename); g_free (data->default_incoming_avatar_filename); g_free (data->default_outgoing_avatar_filename); diff --git a/libempathy-gtk/empathy-theme-manager.c b/libempathy-gtk/empathy-theme-manager.c index ba3d48e68..fea2eca51 100644 --- a/libempathy-gtk/empathy-theme-manager.c +++ b/libempathy-gtk/empathy-theme-manager.c @@ -26,6 +26,7 @@ #include <string.h> #include <glib/gi18n-lib.h> +#include <telepathy-glib/dbus.h> #include <gtk/gtk.h> #include <telepathy-glib/util.h> @@ -67,9 +68,6 @@ static const gchar *themes[] = { "simple", N_("Simple"), "clean", N_("Clean"), "blue", N_("Blue"), -#ifdef HAVE_WEBKIT - "adium", N_("Adium"), -#endif NULL }; @@ -378,6 +376,10 @@ theme_manager_ensure_theme_exists (const gchar *name) return FALSE; } + if (strcmp ("adium", name) == 0) { + return TRUE; + } + for (i = 0; themes[i]; i += 2) { if (strcmp (themes[i], name) == 0) { return TRUE; @@ -534,3 +536,62 @@ empathy_theme_manager_get_themes (void) return themes; } +#ifdef HAVE_WEBKIT +static void +find_themes (GList **list, const gchar *dirpath) +{ + GDir *dir; + GError *error = NULL; + const gchar *name = NULL; + GHashTable *info = NULL; + + dir = g_dir_open (dirpath, 0, &error); + if (dir != NULL) { + name = g_dir_read_name (dir); + while (name != NULL) { + gchar *path; + + path = g_build_path (G_DIR_SEPARATOR_S, dirpath, name, NULL); + if (empathy_adium_path_is_valid (path)) { + info = empathy_adium_info_new (path); + if (info != NULL) { + *list = g_list_prepend (*list, info); + } + } + g_free (path); + name = g_dir_read_name (dir); + } + g_dir_close (dir); + } else { + DEBUG ("Error opening %s: %s\n", dirpath, error->message); + g_error_free (error); + } +} +#endif /* HAVE_WEBKIT */ + +GList * +empathy_theme_manager_get_adium_themes (void) +{ +#ifdef HAVE_WEBKIT + GList *themes = NULL; + gchar *userpath = NULL; + const gchar *const *paths = NULL; + gint i = 0; + + userpath = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (), "adium/message-styles", NULL); + find_themes (&themes, userpath); + g_free (userpath); + + paths = g_get_system_data_dirs (); + for (i = 0; paths[i] != NULL; i++) { + userpath = g_build_path (G_DIR_SEPARATOR_S, paths[i], + "adium/message-styles", NULL); + find_themes (&themes, userpath); + g_free (userpath); + } + + return themes; +#else + return NULL; +#endif /* HAVE_WEBKIT */ +} diff --git a/libempathy-gtk/empathy-theme-manager.h b/libempathy-gtk/empathy-theme-manager.h index 99c96d784..a459b43cb 100644 --- a/libempathy-gtk/empathy-theme-manager.h +++ b/libempathy-gtk/empathy-theme-manager.h @@ -51,6 +51,7 @@ struct _EmpathyThemeManagerClass { GType empathy_theme_manager_get_type (void) G_GNUC_CONST; EmpathyThemeManager * empathy_theme_manager_get (void); const gchar ** empathy_theme_manager_get_themes (void); +GList * empathy_theme_manager_get_adium_themes (void); EmpathyChatView * empathy_theme_manager_create_view (EmpathyThemeManager *manager); G_END_DECLS diff --git a/libempathy-gtk/empathy-ui-utils.c b/libempathy-gtk/empathy-ui-utils.c index 7b4cc1d43..b697b4d0b 100644 --- a/libempathy-gtk/empathy-ui-utils.c +++ b/libempathy-gtk/empathy-ui-utils.c @@ -1238,7 +1238,7 @@ empathy_window_get_is_visible (GtkWindow *window) g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE); - gdk_window = GTK_WIDGET (window)->window; + gdk_window = gtk_widget_get_window (GTK_WIDGET (window)); if (!gdk_window) { return FALSE; } @@ -1260,7 +1260,7 @@ empathy_window_iconify (GtkWindow *window, GtkStatusIcon *status_icon) GdkWindow *gdk_window; gtk_status_icon_get_geometry (status_icon, NULL, &icon_location, NULL); - gdk_window = GTK_WIDGET (window)->window; + gdk_window = gtk_widget_get_window (GTK_WIDGET (window)); dpy = gdk_x11_drawable_get_xdisplay (gdk_window); data[0] = icon_location.x; @@ -1329,6 +1329,8 @@ empathy_get_toplevel_window (GtkWidget *widget) static gchar * fixup_url (const gchar *url) { + g_return_val_if_fail (url != NULL, NULL); + if (g_str_has_prefix (url, "ghelp:") || g_str_has_prefix (url, "mailto:") || strstr (url, ":/")) { @@ -1349,6 +1351,9 @@ empathy_url_show (GtkWidget *parent, gchar *real_url; GError *error = NULL; + g_return_if_fail (GTK_IS_WIDGET (parent)); + g_return_if_fail (url != NULL); + real_url = fixup_url (url); if (real_url) { url = real_url; diff --git a/libempathy-gtk/empathy-video-widget.c b/libempathy-gtk/empathy-video-widget.c index 79f27814f..0f62496de 100644 --- a/libempathy-gtk/empathy-video-widget.c +++ b/libempathy-gtk/empathy-video-widget.c @@ -403,7 +403,7 @@ empathy_video_widget_sync_message_cb (GstBus *bus, GstMessage *message, { g_assert (GTK_WIDGET_REALIZED (GTK_WIDGET (self))); gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (priv->overlay), - GDK_WINDOW_XID (GTK_WIDGET (self)->window)); + GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (self)))); } } @@ -418,13 +418,13 @@ empathy_video_widget_expose_event (GtkWidget *widget, GdkEventExpose *event) if (priv->overlay == NULL) { - gdk_window_clear_area (widget->window, 0, 0, + gdk_window_clear_area (gtk_widget_get_window (widget), 0, 0, widget->allocation.width, widget->allocation.height); return TRUE; } gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (priv->overlay), - GDK_WINDOW_XID (widget->window)); + GDK_WINDOW_XID (gtk_widget_get_window (widget))); gst_x_overlay_expose (GST_X_OVERLAY (priv->overlay)); |