X-Git-Url: https://git.0d.be/?p=empathy.git;a=blobdiff_plain;f=libempathy-gtk%2Fempathy-contact-list-view.c;h=05823435a04727f9b9d42f501b5477156e38a733;hp=c19ad32df2edcd59c49cff016d1eac44c9b6fd92;hb=940d0e9778828657a6ffbcadd35a8a84d706ac70;hpb=8c4fe70aad3622138957c49732fa612b1e2e9eb7 diff --git a/libempathy-gtk/empathy-contact-list-view.c b/libempathy-gtk/empathy-contact-list-view.c index c19ad32d..05823435 100644 --- a/libempathy-gtk/empathy-contact-list-view.c +++ b/libempathy-gtk/empathy-contact-list-view.c @@ -65,6 +65,7 @@ typedef struct { EmpathyContactListFeatureFlags list_features; EmpathyContactFeatureFlags contact_features; GtkWidget *tooltip_widget; + GtkTargetList *file_targets; } EmpathyContactListViewPriv; typedef struct { @@ -88,17 +89,23 @@ enum { enum DndDragType { DND_DRAG_TYPE_CONTACT_ID, - DND_DRAG_TYPE_URL, + DND_DRAG_TYPE_URI_LIST, DND_DRAG_TYPE_STRING, }; static const GtkTargetEntry drag_types_dest[] = { + { "text/path-list", 0, DND_DRAG_TYPE_URI_LIST }, + { "text/uri-list", 0, DND_DRAG_TYPE_URI_LIST }, { "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID }, - { "text/uri-list", 0, DND_DRAG_TYPE_URL }, { "text/plain", 0, DND_DRAG_TYPE_STRING }, { "STRING", 0, DND_DRAG_TYPE_STRING }, }; +static const GtkTargetEntry drag_types_dest_file[] = { + { "text/path-list", 0, DND_DRAG_TYPE_URI_LIST }, + { "text/uri-list", 0, DND_DRAG_TYPE_URI_LIST }, +}; + static const GtkTargetEntry drag_types_source[] = { { "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID }, }; @@ -150,6 +157,11 @@ contact_list_view_query_tooltip_cb (EmpathyContactListView *view, } running++; + /* Don't show the tooltip if there's already a popup menu */ + if (gtk_menu_get_for_attach_widget (GTK_WIDGET (view)) != NULL) { + goto OUT; + } + if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (view), &x, &y, keyboard_mode, &model, &path, &iter)) { @@ -170,6 +182,8 @@ contact_list_view_query_tooltip_cb (EmpathyContactListView *view, priv->tooltip_widget = empathy_contact_widget_new (contact, EMPATHY_CONTACT_WIDGET_FOR_TOOLTIP | EMPATHY_CONTACT_WIDGET_SHOW_LOCATION); + gtk_container_set_border_width ( + GTK_CONTAINER (priv->tooltip_widget), 8); g_object_ref (priv->tooltip_widget); g_signal_connect (priv->tooltip_widget, "destroy", G_CALLBACK (contact_list_view_tooltip_destroy_cb), @@ -226,6 +240,21 @@ contact_list_view_drag_got_contact (EmpathyTpContactFactory *factory, data->old_group, data->new_group); list = empathy_contact_list_store_get_list_iface (priv->store); + + if (!tp_strdiff (data->new_group, EMPATHY_CONTACT_LIST_STORE_FAVORITE)) { + /* Mark contact as favourite */ + empathy_contact_list_add_to_favourites (list, contact); + return; + } + + if (!tp_strdiff (data->old_group, EMPATHY_CONTACT_LIST_STORE_FAVORITE)) { + /* Remove contact as favourite */ + empathy_contact_list_remove_from_favourites (list, contact); + /* Don't try to remove it */ + g_free (data->old_group); + data->old_group = NULL; + } + if (data->new_group) { empathy_contact_list_add_to_group (list, contact, data->new_group); } @@ -234,74 +263,79 @@ contact_list_view_drag_got_contact (EmpathyTpContactFactory *factory, } } -static void -contact_list_view_drag_data_received (GtkWidget *view, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection, - guint info, - guint time_) +static gboolean +group_can_be_modified (const gchar *name, + gboolean is_fake_group, + gboolean adding) +{ + /* Real groups can always be modified */ + if (!is_fake_group) + return TRUE; + + /* The favorite fake group can be modified so users can + * add/remove favorites using DnD */ + if (!tp_strdiff (name, EMPATHY_CONTACT_LIST_STORE_FAVORITE)) + return TRUE; + + /* We can remove contacts from the 'ungrouped' fake group */ + if (!adding && !tp_strdiff (name, EMPATHY_CONTACT_LIST_STORE_UNGROUPED)) + return TRUE; + + return FALSE; +} + +static gboolean +contact_list_view_contact_drag_received (GtkWidget *view, + GdkDragContext *context, + GtkTreeModel *model, + GtkTreePath *path, + GtkSelectionData *selection) { EmpathyContactListViewPriv *priv; TpAccountManager *account_manager; EmpathyTpContactFactory *factory = NULL; - TpAccount *account = NULL; - GtkTreeModel *model; - GtkTreeViewDropPosition position; - GtkTreePath *path; - const gchar *id; - gchar **strv = NULL; - const gchar *account_id = NULL; - const gchar *contact_id = NULL; - gchar *new_group = NULL; - gchar *old_group = NULL; + TpAccount *account; DndGetContactData *data; - gboolean is_row; - gboolean success = TRUE; + GtkTreePath *source_path; + const gchar *sel_data; + gchar **strv = NULL; + const gchar *account_id = NULL; + const gchar *contact_id = NULL; + gchar *new_group = NULL; + gchar *old_group = NULL; + gboolean success = TRUE; + gboolean new_group_is_fake, old_group_is_fake = TRUE; priv = GET_PRIV (view); - model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); - /* Get destination group information. */ - is_row = gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (view), - x, - y, - &path, - &position); + sel_data = (const gchar *) gtk_selection_data_get_data (selection); + new_group = empathy_contact_list_store_get_parent_group (model, + path, NULL, &new_group_is_fake); - if (is_row) { - new_group = empathy_contact_list_store_get_parent_group (model, - path, NULL); - gtk_tree_path_free (path); - } + if (!group_can_be_modified (new_group, new_group_is_fake, TRUE)) + return FALSE; /* Get source group information. */ if (priv->drag_row) { - path = gtk_tree_row_reference_get_path (priv->drag_row); - if (path) { + source_path = gtk_tree_row_reference_get_path (priv->drag_row); + if (source_path) { old_group = empathy_contact_list_store_get_parent_group ( - model, path, NULL); - gtk_tree_path_free (path); + model, source_path, NULL, &old_group_is_fake); + gtk_tree_path_free (source_path); } } + if (!group_can_be_modified (old_group, old_group_is_fake, FALSE)) + return FALSE; + if (!tp_strdiff (old_group, new_group)) { g_free (new_group); g_free (old_group); - goto OUT; + return FALSE; } - 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" : "", - id); - - /* FIXME: should probably make sure the account manager is prepared - * before calling _ensure_account on it. See bug 600115. */ account_manager = tp_account_manager_dup (); - strv = g_strsplit (id, ":", 2); + strv = g_strsplit (sel_data, ":", 2); if (g_strv_length (strv) == 2) { account_id = strv[0]; contact_id = strv[1]; @@ -322,7 +356,7 @@ contact_list_view_drag_data_received (GtkWidget *view, success = FALSE; g_free (new_group); g_free (old_group); - goto OUT; + return FALSE; } data = g_slice_new0 (DndGetContactData); @@ -333,14 +367,85 @@ contact_list_view_drag_data_received (GtkWidget *view, /* FIXME: We should probably wait for the cb before calling * gtk_drag_finish */ empathy_tp_contact_factory_get_from_id (factory, contact_id, - contact_list_view_drag_got_contact, - data, (GDestroyNotify) contact_list_view_dnd_get_contact_free, - G_OBJECT (view)); - + contact_list_view_drag_got_contact, + data, (GDestroyNotify) contact_list_view_dnd_get_contact_free, + G_OBJECT (view)); + g_strfreev (strv); g_object_unref (factory); -OUT: - g_strfreev (strv); + return TRUE; +} + +static gboolean +contact_list_view_file_drag_received (GtkWidget *view, + GdkDragContext *context, + GtkTreeModel *model, + GtkTreePath *path, + GtkSelectionData *selection) +{ + GtkTreeIter iter; + const gchar *sel_data; + EmpathyContact *contact; + + sel_data = (const gchar *) gtk_selection_data_get_data (selection); + + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get (model, &iter, + EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact, + -1); + if (!contact) { + return FALSE; + } + + empathy_send_file_from_uri_list (contact, sel_data); + + g_object_unref (contact); + + return TRUE; +} + +static void +contact_list_view_drag_data_received (GtkWidget *view, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection, + guint info, + guint time_) +{ + GtkTreeModel *model; + gboolean is_row; + GtkTreeViewDropPosition position; + GtkTreePath *path; + gboolean success = TRUE; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); + + /* Get destination group information. */ + is_row = gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (view), + x, + y, + &path, + &position); + if (!is_row) { + success = FALSE; + } + else if (info == DND_DRAG_TYPE_CONTACT_ID || info == DND_DRAG_TYPE_STRING) { + success = contact_list_view_contact_drag_received (view, + context, + model, + path, + selection); + } + else if (info == DND_DRAG_TYPE_URI_LIST) { + success = contact_list_view_file_drag_received (view, + context, + model, + path, + selection); + } + + gtk_tree_path_free (path); gtk_drag_finish (context, success, FALSE, GDK_CURRENT_TIME); } @@ -363,12 +468,19 @@ contact_list_view_drag_motion (GtkWidget *widget, gint y, guint time_) { + EmpathyContactListViewPriv *priv; + GtkTreeModel *model; + GdkAtom target; + GtkTreeIter iter; static DragMotionData *dm = NULL; GtkTreePath *path; gboolean is_row; gboolean is_different = FALSE; gboolean cleanup = TRUE; - int action = 0; + gboolean retval = TRUE; + + priv = GET_PRIV (EMPATHY_CONTACT_LIST_VIEW (widget)); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); is_row = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), x, @@ -387,15 +499,82 @@ contact_list_view_drag_motion (GtkWidget *widget, cleanup &= FALSE; } - if (context->actions == GDK_ACTION_COPY) { - action = context->suggested_action; - } else if (context->actions & GDK_ACTION_MOVE) { - action = GDK_ACTION_MOVE; + if (path == NULL) { + /* Coordinates don't point to an actual row, so make sure the pointer + and highlighting don't indicate that a drag is possible. + */ + gdk_drag_status (context, GDK_ACTION_DEFAULT, time_); + gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), NULL, 0); + return FALSE; + } + target = gtk_drag_dest_find_target (widget, context, priv->file_targets); + gtk_tree_model_get_iter (model, &iter, path); + + if (target == GDK_NONE) { + /* If target == GDK_NONE, then we don't have a target that can be + dropped on a contact. This means a contact drag. If we're + pointing to a group, highlight it. Otherwise, if the contact + we're pointing to is in a group, highlight that. Otherwise, + set the drag position to before the first row for a drag into + the "non-group" at the top. + */ + GtkTreeIter group_iter; + gboolean is_group; + GtkTreePath *group_path; + gtk_tree_model_get (model, &iter, + EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, &is_group, + -1); + if (is_group) { + group_iter = iter; + } + else { + if (gtk_tree_model_iter_parent (model, &group_iter, &iter)) + gtk_tree_model_get (model, &group_iter, + EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, &is_group, + -1); + } + if (is_group) { + gdk_drag_status (context, GDK_ACTION_MOVE, time_); + group_path = gtk_tree_model_get_path (model, &group_iter); + gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), + group_path, + GTK_TREE_VIEW_DROP_INTO_OR_BEFORE); + gtk_tree_path_free (group_path); + } + else { + group_path = gtk_tree_path_new_first (); + gdk_drag_status (context, GDK_ACTION_MOVE, time_); + gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), + group_path, + GTK_TREE_VIEW_DROP_BEFORE); + } + } + else { + /* This is a file drag, and it can only be dropped on contacts, + not groups. + */ + EmpathyContact *contact; + gtk_tree_model_get (model, &iter, + EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact, + -1); + if (contact != NULL && + empathy_contact_is_online (contact) && + (empathy_contact_get_capabilities (contact) & EMPATHY_CAPABILITIES_FT)) { + gdk_drag_status (context, GDK_ACTION_COPY, time_); + gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), + path, + GTK_TREE_VIEW_DROP_INTO_OR_BEFORE); + g_object_unref (contact); + } + else { + gdk_drag_status (context, 0, time_); + gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), NULL, 0); + retval = FALSE; + } } - gdk_drag_status (context, action, time_); if (!is_different && !cleanup) { - return TRUE; + return retval; } if (dm) { @@ -420,7 +599,7 @@ contact_list_view_drag_motion (GtkWidget *widget, dm); } - return TRUE; + return retval; } static void @@ -550,10 +729,16 @@ contact_list_view_popup_menu_idle_cb (gpointer user_data) } if (menu) { + g_signal_connect (menu, "deactivate", + G_CALLBACK (gtk_menu_detach), NULL); + gtk_menu_attach_to_widget (GTK_MENU (menu), + GTK_WIDGET (data->view), NULL); gtk_widget_show (menu); gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, data->button, data->time); + g_object_ref_sink (menu); + g_object_unref (menu); } g_slice_free (MenuPopupData, data); @@ -625,54 +810,55 @@ contact_list_view_row_activated (GtkTreeView *view, } static void -contact_list_start_voip_call (EmpathyCellRendererActivatable *cell, +contact_list_view_call_activated_cb ( + EmpathyCellRendererActivatable *cell, const gchar *path_string, - EmpathyContactListView *view, - gboolean with_video) + EmpathyContactListView *view) { - EmpathyContactListViewPriv *priv = GET_PRIV (view); - GtkTreeModel *model; - GtkTreeIter iter; - EmpathyContact *contact; - - if (!(priv->contact_features & EMPATHY_CONTACT_FEATURE_CALL)) { - return; - } + GtkWidget *menu; + GtkTreeModel *model; + GtkTreeIter iter; + EmpathyContact *contact; + GdkEventButton *event; + GtkMenuShell *shell; + GtkWidget *item; model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); - if (!gtk_tree_model_get_iter_from_string (model, &iter, path_string)) { + if (!gtk_tree_model_get_iter_from_string (model, &iter, path_string)) return; - } gtk_tree_model_get (model, &iter, EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, &contact, -1); + if (contact == NULL) + return; - if (contact) { - EmpathyCallFactory *factory; - factory = empathy_call_factory_get (); - empathy_call_factory_new_call_with_streams (factory, contact, - TRUE, with_video); - g_object_unref (contact); - } -} - -static void -contact_list_view_video_call_activated_cb ( - EmpathyCellRendererActivatable *cell, - const gchar *path_string, - EmpathyContactListView *view) -{ - contact_list_start_voip_call (cell, path_string, view, TRUE); -} + event = (GdkEventButton *) gtk_get_current_event (); + menu = gtk_menu_new (); + shell = GTK_MENU_SHELL (menu); + + /* audio */ + item = empathy_contact_audio_call_menu_item_new (contact); + gtk_menu_shell_append (shell, item); + gtk_widget_show (item); + + /* video */ + item = empathy_contact_video_call_menu_item_new (contact); + gtk_menu_shell_append (shell, item); + gtk_widget_show (item); + + g_signal_connect (menu, "deactivate", + G_CALLBACK (gtk_menu_detach), NULL); + gtk_menu_attach_to_widget (GTK_MENU (menu), + GTK_WIDGET (view), NULL); + gtk_widget_show (menu); + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, + event->button, event->time); + g_object_ref_sink (menu); + g_object_unref (menu); -static void -contact_list_view_audio_call_activated_cb (EmpathyCellRendererActivatable *cell, - const gchar *path_string, - EmpathyContactListView *view) -{ - contact_list_start_voip_call (cell, path_string, view, FALSE); + g_object_unref (contact); } static void @@ -715,54 +901,70 @@ contact_list_view_pixbuf_cell_data_func (GtkTreeViewColumn *tree_column, GtkTreeIter *iter, EmpathyContactListView *view) { - gchar *icon_name; - gboolean is_group; - gboolean is_active; + GdkPixbuf *pixbuf; + gboolean is_group; + gboolean is_active; gtk_tree_model_get (model, iter, EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, &is_group, EMPATHY_CONTACT_LIST_STORE_COL_IS_ACTIVE, &is_active, - EMPATHY_CONTACT_LIST_STORE_COL_ICON_STATUS, &icon_name, + EMPATHY_CONTACT_LIST_STORE_COL_ICON_STATUS, &pixbuf, -1); g_object_set (cell, "visible", !is_group, - "icon-name", icon_name, + "pixbuf", pixbuf, NULL); - g_free (icon_name); + if (pixbuf != NULL) { + g_object_unref (pixbuf); + } contact_list_view_cell_set_background (view, cell, is_group, is_active); } static void -contact_list_view_audio_call_cell_data_func ( - GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - EmpathyContactListView *view) +contact_list_view_group_icon_cell_data_func (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + EmpathyContactListView *view) { + GdkPixbuf *pixbuf = NULL; gboolean is_group; - gboolean is_active; - gboolean can_voip; + 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_CAN_AUDIO_CALL, &can_voip, + EMPATHY_CONTACT_LIST_STORE_COL_NAME, &name, -1); + if (!is_group) + goto out; + + if (!tp_strdiff (name, EMPATHY_CONTACT_LIST_STORE_FAVORITE)) { + pixbuf = empathy_pixbuf_from_icon_name ("emblem-favorite", + GTK_ICON_SIZE_MENU); + } + else if (!tp_strdiff (name, EMPATHY_CONTACT_LIST_STORE_PEOPLE_NEARBY)) { + pixbuf = empathy_pixbuf_from_icon_name ("im-local-xmpp", + GTK_ICON_SIZE_MENU); + } + +out: g_object_set (cell, - "visible", !is_group && can_voip, - "icon-name", EMPATHY_IMAGE_VOIP, + "visible", pixbuf != NULL, + "pixbuf", pixbuf, NULL); - contact_list_view_cell_set_background (view, cell, is_group, is_active); + if (pixbuf != NULL) + g_object_unref (pixbuf); + + g_free (name); } static void -contact_list_view_video_call_cell_data_func ( +contact_list_view_audio_call_cell_data_func ( GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *model, @@ -771,23 +973,23 @@ contact_list_view_video_call_cell_data_func ( { gboolean is_group; gboolean is_active; - gboolean can_voip; + gboolean can_audio, can_video; gtk_tree_model_get (model, iter, EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, &is_group, EMPATHY_CONTACT_LIST_STORE_COL_IS_ACTIVE, &is_active, - EMPATHY_CONTACT_LIST_STORE_COL_CAN_VIDEO_CALL, &can_voip, + EMPATHY_CONTACT_LIST_STORE_COL_CAN_AUDIO_CALL, &can_audio, + EMPATHY_CONTACT_LIST_STORE_COL_CAN_VIDEO_CALL, &can_video, -1); g_object_set (cell, - "visible", !is_group && can_voip, - "icon-name", EMPATHY_IMAGE_VIDEO_CALL, + "visible", !is_group && (can_audio || can_video), + "icon-name", can_video? EMPATHY_IMAGE_VIDEO_CALL : EMPATHY_IMAGE_VOIP, NULL); contact_list_view_cell_set_background (view, cell, is_group, is_active); } - static void contact_list_view_avatar_cell_data_func (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, @@ -828,22 +1030,12 @@ 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); } @@ -971,6 +1163,11 @@ contact_list_view_setup (EmpathyContactListView *view) GTK_TREE_MODEL (priv->store)); /* Setup view */ + /* Setting reorderable is a hack that gets us row previews as drag icons + for free. We override all the drag handlers. It's tricky to get the + position of the drag icon right in drag_begin. GtkTreeView has special + voodoo for it, so we let it do the voodoo that he do. + */ g_object_set (view, "headers-visible", FALSE, "reorderable", TRUE, @@ -993,6 +1190,22 @@ contact_list_view_setup (EmpathyContactListView *view) "visible", FALSE, NULL); + /* Group icon */ + cell = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (col, cell, FALSE); + gtk_tree_view_column_set_cell_data_func ( + col, cell, + (GtkTreeCellDataFunc) contact_list_view_group_icon_cell_data_func, + view, NULL); + + g_object_set (cell, + "xpad", 0, + "ypad", 0, + "visible", FALSE, + "width", 16, + "height", 16, + NULL); + /* Name */ cell = empathy_cell_renderer_text_new (); gtk_tree_view_column_pack_start (col, cell, TRUE); @@ -1003,10 +1216,16 @@ contact_list_view_setup (EmpathyContactListView *view) gtk_tree_view_column_add_attribute (col, cell, "name", EMPATHY_CONTACT_LIST_STORE_COL_NAME); + gtk_tree_view_column_add_attribute (col, cell, + "text", EMPATHY_CONTACT_LIST_STORE_COL_NAME); + gtk_tree_view_column_add_attribute (col, cell, + "presence-type", EMPATHY_CONTACT_LIST_STORE_COL_PRESENCE_TYPE); gtk_tree_view_column_add_attribute (col, cell, "status", EMPATHY_CONTACT_LIST_STORE_COL_STATUS); gtk_tree_view_column_add_attribute (col, cell, "is_group", EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP); + gtk_tree_view_column_add_attribute (col, cell, + "compact", EMPATHY_CONTACT_LIST_STORE_COL_COMPACT); /* Audio Call Icon */ cell = empathy_cell_renderer_activatable_new (); @@ -1021,23 +1240,7 @@ contact_list_view_setup (EmpathyContactListView *view) NULL); g_signal_connect (cell, "path-activated", - G_CALLBACK (contact_list_view_audio_call_activated_cb), - view); - - /* Video Call Icon */ - cell = empathy_cell_renderer_activatable_new (); - gtk_tree_view_column_pack_start (col, cell, FALSE); - gtk_tree_view_column_set_cell_data_func ( - col, cell, - (GtkTreeCellDataFunc) contact_list_view_video_call_cell_data_func, - view, NULL); - - g_object_set (cell, - "visible", FALSE, - NULL); - - g_signal_connect (cell, "path-activated", - G_CALLBACK (contact_list_view_video_call_activated_cb), + G_CALLBACK (contact_list_view_call_activated_cb), view); /* Avatar */ @@ -1131,6 +1334,9 @@ contact_list_view_finalize (GObject *object) if (priv->tooltip_widget) { gtk_widget_destroy (priv->tooltip_widget); } + if (priv->file_targets) { + gtk_target_list_unref (priv->file_targets); + } G_OBJECT_CLASS (empathy_contact_list_view_parent_class)->finalize (object); } @@ -1261,6 +1467,10 @@ empathy_contact_list_view_init (EmpathyContactListView *view) empathy_contact_list_store_row_separator_func, NULL, NULL); + /* Set up drag target lists. */ + priv->file_targets = gtk_target_list_new (drag_types_dest_file, + G_N_ELEMENTS (drag_types_dest_file)); + /* Connect to tree view signals rather than override. */ g_signal_connect (view, "button-press-event", G_CALLBACK (contact_list_view_button_press_event_cb), @@ -1344,7 +1554,8 @@ empathy_contact_list_view_get_flags (EmpathyContactListView *view) } gchar * -empathy_contact_list_view_get_selected_group (EmpathyContactListView *view) +empathy_contact_list_view_get_selected_group (EmpathyContactListView *view, + gboolean *is_fake_group) { EmpathyContactListViewPriv *priv; GtkTreeSelection *selection; @@ -1352,6 +1563,7 @@ empathy_contact_list_view_get_selected_group (EmpathyContactListView *view) GtkTreeModel *model; gboolean is_group; gchar *name; + gboolean fake; g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view), NULL); @@ -1365,6 +1577,7 @@ empathy_contact_list_view_get_selected_group (EmpathyContactListView *view) gtk_tree_model_get (model, &iter, EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, &is_group, EMPATHY_CONTACT_LIST_STORE_COL_NAME, &name, + EMPATHY_CONTACT_LIST_STORE_COL_IS_FAKE_GROUP, &fake, -1); if (!is_group) { @@ -1372,6 +1585,9 @@ empathy_contact_list_view_get_selected_group (EmpathyContactListView *view) return NULL; } + if (is_fake_group != NULL) + *is_fake_group = fake; + return name; } @@ -1408,7 +1624,7 @@ contact_list_view_group_remove_activate_cb (GtkMenuItem *menuitem, EmpathyContactListViewPriv *priv = GET_PRIV (view); gchar *group; - group = empathy_contact_list_view_get_selected_group (view); + group = empathy_contact_list_view_get_selected_group (view, NULL); if (group) { gchar *text; GtkWindow *parent; @@ -1436,6 +1652,7 @@ empathy_contact_list_view_get_group_menu (EmpathyContactListView *view) GtkWidget *menu; GtkWidget *item; GtkWidget *image; + gboolean is_fake_group; g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view), NULL); @@ -1444,8 +1661,9 @@ empathy_contact_list_view_get_group_menu (EmpathyContactListView *view) return NULL; } - group = empathy_contact_list_view_get_selected_group (view); - if (!group) { + group = empathy_contact_list_view_get_selected_group (view, &is_fake_group); + if (!group || is_fake_group) { + /* We can't alter fake groups */ return NULL; }