changeset 11359:9480e0d0f563

[gaim-migrate @ 13581] Search results notification extended so that any column can be added. committer: Tailor Script <tailor@pidgin.im>
author Bartoz Oler <bartosz@pidgin.im>
date Sun, 28 Aug 2005 22:21:24 +0000
parents fb702c34794b
children cf15c1cdcfbd
files src/gtknotify.c src/notify.c src/notify.h src/protocols/oscar/oscar.c
diffstat 4 files changed, 460 insertions(+), 89 deletions(-) [+]
line wrap: on
line diff
--- a/src/gtknotify.c	Sun Aug 28 22:18:08 2005 +0000
+++ b/src/gtknotify.c	Sun Aug 28 22:21:24 2005 +0000
@@ -56,12 +56,12 @@
 
 } GaimNotifySearchResultsData;
 
-enum
+typedef struct
 {
-	COLUMN_ICON,
-	COLUMN_SCREENNAME,
-	NUM_COLUMNS
-};
+	GaimNotifySearchButton *button;
+	GaimNotifySearchResultsData *data;
+
+} GaimNotifySearchResultsButtonData;
 
 static void *gaim_gtk_notify_emails(size_t count, gboolean detailed,
 									const char **subjects,
@@ -97,12 +97,17 @@
 }
 
 static void
-add_buddy_helper_cb(GtkWidget *widget, GaimNotifySearchResultsData *data)
+searchresults_callback_wrapper_cb(GtkWidget *widget, GaimNotifySearchResultsButtonData *bd)
 {
+	GaimNotifySearchResultsData *data = bd->data;
+
 	GtkTreeSelection *selection;
 	GtkTreeModel *model;
 	GtkTreeIter iter;
-	gchar *buddy;
+	GaimNotifySearchButton *button;
+	GList *row = NULL;
+	gchar *str;
+	int i;
 
 	g_return_if_fail(data != NULL);
 
@@ -110,11 +115,14 @@
 
 	if (gtk_tree_selection_get_selected(selection, &model, &iter))
 	{
-		gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
-						   COLUMN_SCREENNAME, &buddy, -1);
-		gaim_blist_request_add_buddy(data->account, buddy, NULL, NULL);
-		g_free(buddy);
+		for (i = 1; i < gtk_tree_model_get_n_columns(GTK_TREE_MODEL(model)); i++) {
+			gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, i, &str, -1);
+			row = g_list_append(row, str);
+		}
 	}
+
+	button = bd->button;
+	button->callback(gaim_account_get_connection(data->account), row);
 }
 
 static void *
@@ -426,26 +434,64 @@
 	return window;
 }
 
+static void
+gaim_gtk_notify_searchresults_new_rows(GaimConnection *gc, GaimNotifySearchResults *results,
+									   void *data_, void *user_data)
+{
+	GaimNotifySearchResultsData *data = data_;
+	GtkListStore *model = data->model;
+	GtkTreeIter iter;
+	GdkPixbuf *icon, *scaled;
+	int col_num;
+	int i, j;
+	
+	gtk_list_store_clear(data->model);
+
+	icon = gaim_gtk_create_prpl_icon(gaim_connection_get_account(gc));
+	scaled = gdk_pixbuf_scale_simple(icon, 16, 16, GDK_INTERP_BILINEAR);
+
+	/* +1 is for the automagically created Status column. */
+	col_num = gaim_notify_searchresults_get_columns_count(results) + 1;
+
+	for (i = 0; i < gaim_notify_searchresults_get_rows_count(results); i++) {
+		GList *row = gaim_notify_searchresults_row_get(results, i);
+
+		gtk_list_store_append(model, &iter);
+		gtk_list_store_set(model, &iter, 0, scaled, -1);
+
+		for (j = 1; j < col_num; j++) {
+			GValue v = {0, };
+			char *escaped = g_markup_escape_text(g_list_nth_data(row, j - 1), -1);
+
+			g_value_init(&v, G_TYPE_STRING);
+			g_value_set_string(&v, escaped);
+			gtk_list_store_set_value(model, &iter, j, &v);
+			g_free(escaped);
+		}
+	}
+}
+
 static void *
 gaim_gtk_notify_searchresults(GaimConnection *gc, const char *title,
 							  const char *primary, const char *secondary,
-							  const char **results, GCallback cb,
+							  GaimNotifySearchResults *results, GCallback cb,
 							  void *user_data)
 {
 	GtkWidget *window;
+	GtkWidget *treeview;
+	GtkWidget *button, *close_button;
+	GType *col_types;
+	GtkListStore *model;
+	GtkCellRenderer *renderer;
+	int col_num;
+	int i;
+	GList *buttons = NULL;
+
 	GtkWidget *vbox;
 	GtkWidget *button_area;
 	GtkWidget *label;
-	GtkWidget *close_button;
-	GtkWidget *add_button;
 	GtkWidget *sw;
-	GtkWidget *treeview;
-	GdkPixbuf *icon, *scaled;
 	GaimNotifySearchResultsData *data;
-	GtkListStore *model;
-	GtkCellRenderer *renderer;
-	GtkTreeIter iter;
-	int i;
 	char *label_text;
 	char *primary_esc, *secondary_esc;
 
@@ -483,8 +529,18 @@
 	gtk_widget_show(label);
 	g_free(label_text);
 
+	/* +1 is for the automagically created Status column. */
+	col_num = gaim_notify_searchresults_get_columns_count(results) + 1;
+
 	/* Setup the list model */
-	model = gtk_list_store_new(NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING);
+	col_types = g_new0(GType, col_num);
+
+	/* There always is this first column. */
+	col_types[0] = GDK_TYPE_PIXBUF;
+	for (i = 1; i < col_num; i++) {
+		col_types[i] = G_TYPE_STRING;
+	}
+	model = gtk_list_store_newv(col_num, col_types);
 
 	/* Setup the scrolled window containing the treeview */
 	sw = gtk_scrolled_window_new(NULL, NULL);
@@ -498,27 +554,25 @@
 	/* Setup the treeview */
 	treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
 	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
-	gtk_widget_set_size_request(treeview, 250, 150);
+	gtk_widget_set_size_request(treeview, 500, 400);
 	gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)),
 								GTK_SELECTION_SINGLE);
-	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
+	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE);
 	gtk_container_add(GTK_CONTAINER(sw), treeview);
 	gtk_widget_show(treeview);
 
-	/* icon column */
-	renderer = gtk_cell_renderer_pixbuf_new ();
+	renderer = gtk_cell_renderer_pixbuf_new();
 	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview),
-					-1, "Icon", renderer,
-					"pixbuf", COLUMN_ICON,
-					NULL);
+					-1, "", renderer, "pixbuf", 0, NULL);
 
-	/* screenname column */
-	renderer = gtk_cell_renderer_text_new();
-	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview),
-					-1, "Screenname", renderer,
-					"text", COLUMN_SCREENNAME,
-					NULL);
+	for (i = 1; i < col_num; i++) {
+		renderer = gtk_cell_renderer_text_new();
 
+		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), -1,
+				gaim_notify_searchresults_column_get_title(results, i-1),
+				renderer, "text", i, NULL);
+	}
+	
 	/* Setup the button area */
 	button_area = gtk_hbutton_box_new();
 	gtk_box_pack_start(GTK_BOX(vbox), button_area, FALSE, FALSE, 0);
@@ -526,39 +580,48 @@
 	gtk_box_set_spacing(GTK_BOX(button_area), GAIM_HIG_BORDER);
 	gtk_widget_show(button_area);
 
-	/* Add the Add button */
-	add_button = gtk_button_new_from_stock(GTK_STOCK_ADD);
-	gtk_box_pack_start(GTK_BOX(button_area), add_button, FALSE, FALSE, 0);
-	gtk_widget_show(add_button);
+	for (i = 0; i < g_list_length(results->buttons); i++) {
+		GaimNotifySearchButton *b = g_list_nth_data(results->buttons, i);
+		button = NULL;
+		switch (b->type) {
+			case GAIM_NOTIFY_BUTTON_CONTINUE:
+				button = gtk_button_new_from_stock(GTK_STOCK_GO_FORWARD);
+				break;
+			case GAIM_NOTIFY_BUTTON_ADD_BUDDY:
+				button = gtk_button_new_from_stock(GTK_STOCK_ADD);
+				break;
+			default:
+				gaim_debug_warning("gtknotify", "Incorrect button type: %d\n", b->type);
+		}
+		if (button != NULL) {
+			gtk_box_pack_start(GTK_BOX(button_area), button, FALSE, FALSE, 0);
+			gtk_widget_show(button);
+			buttons = g_list_append(buttons, button);
+		}
+	}
 
 	/* Add the Close button */
 	close_button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
 	gtk_box_pack_start(GTK_BOX(button_area), close_button, FALSE, FALSE, 0);
 	gtk_widget_show(close_button);
 
-	/* Add the buddies to the tree view */
-	icon = gaim_gtk_create_prpl_icon(gc->account);
-	scaled = gdk_pixbuf_scale_simple(icon, 16, 16, GDK_INTERP_BILINEAR);
-
-	for (i = 0; results[i] != NULL; i++)
-	{
-		char *escaped = g_markup_escape_text(results[i], -1);
-		gtk_list_store_append(model, &iter);
-		gtk_list_store_set(model, &iter,
-						   COLUMN_ICON, scaled,
-						   COLUMN_SCREENNAME, escaped,
-						   -1);
-		g_free(escaped);
-	}
-
 	data->account = gc->account;
 	data->model = model;
 	data->treeview = treeview;
 	data->window = window;
 
+	/* Insert rows. */
+	gaim_gtk_notify_searchresults_new_rows(gc, results, data, NULL);
+
 	/* Connect Signals */
-	g_signal_connect(G_OBJECT(add_button), "clicked",
-					 G_CALLBACK(add_buddy_helper_cb), data);
+	for (i = 0; i < g_list_length(results->buttons); i++) {
+		GaimNotifySearchResultsButtonData *bd = g_new0(GaimNotifySearchResultsButtonData, 1);
+		bd->button = g_list_nth_data(results->buttons, i);
+		bd->data = data;
+		g_signal_connect(G_OBJECT(g_list_nth_data(buttons, i)), "clicked",
+						 G_CALLBACK(searchresults_callback_wrapper_cb), bd);
+	}
+
 	g_signal_connect_swapped(G_OBJECT(close_button), "clicked",
 							 G_CALLBACK(searchresults_close_cb), data);
 
@@ -811,6 +874,7 @@
 	gaim_gtk_notify_emails,
 	gaim_gtk_notify_formatted,
 	gaim_gtk_notify_searchresults,
+	gaim_gtk_notify_searchresults_new_rows,
 	gaim_gtk_notify_userinfo,
 	gaim_gtk_notify_uri,
 	gaim_gtk_close_notify
--- a/src/notify.c	Sun Aug 28 22:18:08 2005 +0000
+++ b/src/notify.c	Sun Aug 28 22:21:24 2005 +0000
@@ -158,7 +158,7 @@
 void *
 gaim_notify_searchresults(GaimConnection *gc, const char *title,
 						  const char *primary, const char *secondary,
-						  const char **results, GCallback cb, void *user_data)
+						  GaimNotifySearchResults *results, GCallback cb, void *user_data)
 {
 	GaimNotifyUiOps *ops;
 
@@ -182,6 +182,151 @@
 	return NULL;
 }
 
+void
+gaim_notify_searchresults_free(GaimNotifySearchResults *results)
+{
+	GList *l, *m;
+
+	g_return_if_fail(results != NULL);
+
+	for (l = results->buttons; l != NULL; l = l->next) {
+		GaimNotifySearchButton *button = l->data;
+
+		results->buttons = g_list_remove(results->buttons, button);
+		g_free(button);
+	}
+	g_list_free(results->buttons);
+
+	for (l = results->rows; l != NULL; l = l->next) {
+		GList *row = l->data;
+
+		for (m = row; m != NULL; m = m->next) {
+			gchar *str = m->data;
+
+			m = g_list_remove(m, str);
+			g_free(str);
+		}
+
+		results->rows = g_list_remove(results->rows, row);
+		g_list_free(row);
+	}
+	g_list_free(results->rows);
+
+	for (l = results->columns; l != NULL; l = l->next) {
+		GaimNotifySearchColumn *column = l->data;
+
+		results->columns = g_list_remove(results->columns, column);
+		g_free(column->title);
+		g_free(column);
+	}
+	g_list_free(results->columns);
+}
+
+void
+gaim_notify_searchresults_new_rows(GaimConnection *gc,
+		GaimNotifySearchResults *results,
+		void *data, void *user_data)
+{
+	GaimNotifyUiOps *ops;
+
+	ops = gaim_notify_get_ui_ops();
+
+	if (ops != NULL && ops->notify_searchresults != NULL) {
+		ops->notify_searchresults_new_rows(gc, results, data, user_data);
+	}
+}
+
+void
+gaim_notify_searchresults_button_add(GaimNotifySearchResults *results,
+									 GaimNotifySearchButtonType type,
+									 GaimNotifySearchResultsCallback cb)
+{
+	GaimNotifySearchButton *button;
+
+	g_return_if_fail(results != NULL);
+	g_return_if_fail(cb != NULL);
+
+	button = g_new0(GaimNotifySearchButton, 1);
+	button->callback = cb;
+	button->type = type;
+
+	results->buttons = g_list_append(results->buttons, button);
+}
+
+GaimNotifySearchResults *
+gaim_notify_searchresults_new()
+{
+	GaimNotifySearchResults *rs = g_new0(GaimNotifySearchResults, 1);
+
+	return rs;
+}
+
+void
+gaim_notify_searchresults_column_add(GaimNotifySearchResults *results,
+									 GaimNotifySearchColumn *column)
+{
+	g_return_if_fail(results != NULL);
+	g_return_if_fail(column  != NULL);
+
+	results->columns = g_list_append(results->columns, column);
+}
+
+void gaim_notify_searchresults_row_add(GaimNotifySearchResults *results,
+									   GList *row)
+{
+	g_return_if_fail(results != NULL);
+	g_return_if_fail(row     != NULL);
+
+	results->rows = g_list_append(results->rows, row);
+}
+
+GaimNotifySearchColumn *
+gaim_notify_searchresults_column_new(const char *title)
+{
+	GaimNotifySearchColumn *sc;
+
+	g_return_val_if_fail(title != NULL, NULL);
+
+	sc = g_new0(GaimNotifySearchColumn, 1);
+	sc->title = g_strdup(title);
+
+	return sc;
+}
+
+int
+gaim_notify_searchresults_get_columns_count(GaimNotifySearchResults *results)
+{
+	g_return_val_if_fail(results != NULL, -1);
+
+	return g_list_length(results->columns);
+}
+
+int
+gaim_notify_searchresults_get_rows_count(GaimNotifySearchResults *results)
+{
+	g_return_val_if_fail(results != NULL, -1);
+
+	return g_list_length(results->rows);
+}
+
+char *
+gaim_notify_searchresults_column_get_title(GaimNotifySearchResults *results,
+										   unsigned int column_id)
+{
+	g_return_val_if_fail(results != NULL, NULL);
+
+	return ((GaimNotifySearchColumn *)g_list_nth_data(results->columns, column_id))->title;
+}
+
+GList *
+gaim_notify_searchresults_row_get(GaimNotifySearchResults *results,
+								  unsigned int row_id)
+{
+	g_return_val_if_fail(results != NULL, NULL);
+
+	return g_list_nth_data(results->rows, row_id);
+}
+
 void *
 gaim_notify_userinfo(GaimConnection *gc, const char *who, const char *title,
 						   const char *primary, const char *secondary,
--- a/src/notify.h	Sun Aug 28 22:18:08 2005 +0000
+++ b/src/notify.h	Sun Aug 28 22:21:24 2005 +0000
@@ -58,6 +58,49 @@
 } GaimNotifyMsgType;
 
 /**
+ * The types of buttons
+ */
+typedef enum
+{
+	GAIM_NOTIFY_BUTTON_CONTINUE = 0,
+	GAIM_NOTIFY_BUTTON_ADD_BUDDY
+
+} GaimNotifySearchButtonType;
+
+/**
+ * Search results object.
+ */
+typedef struct
+{
+	GList *columns;        /**< List of the search column objects. */
+	GList *rows;           /**< List of rows in the result. */
+	GList *buttons;        /**< List of buttons to display. */
+
+} GaimNotifySearchResults;
+
+/**
+ * Single column of a search result.
+ */
+typedef struct
+{
+	char *title; /**< Title of the column. */
+
+} GaimNotifySearchColumn;
+
+typedef void (*GaimNotifySearchResultsCallback)(GaimConnection *, GList *);
+
+
+/**
+ * Definition of a button.
+ */
+typedef struct
+{
+	GaimNotifySearchButtonType type;
+	GaimNotifySearchResultsCallback callback; /**< Function to be called when clicked. */
+
+} GaimNotifySearchButton;
+
+/**
  * Notification UI operations.
  */
 typedef struct
@@ -77,8 +120,11 @@
 							  GCallback cb, void *user_data);
 	void *(*notify_searchresults)(GaimConnection *gc, const char *title,
 								  const char *primary, const char *secondary,
-								  const char **results, GCallback cb,
+								  GaimNotifySearchResults *results, GCallback cb,
 								  void *user_data);
+	void (*notify_searchresults_new_rows)(GaimConnection *gc,
+										  GaimNotifySearchResults *results,
+										  void *data, void *user_data);
 	void *(*notify_userinfo)(GaimConnection *gc, const char *who,
 							  const char *title, const char *primary,
 							  const char *secondary, const char *text,
@@ -89,12 +135,139 @@
 
 } GaimNotifyUiOps;
 
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /**************************************************************************/
+/** Search results notification API                                       */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Displays results from a buddy search.  This can be, for example,
+ * a window with a list of all found buddies, where you are given the
+ * option of adding buddies to your buddy list.
+ *
+ * @param gc        The GaimConnection handle associated with the information.
+ * @param title     The title of the message.  If this is NULL, the title
+ *                  will be "Search	Results."
+ * @param primary   The main point of the message.
+ * @param secondary The secondary information.
+ * @param results   The GaimNotifySearchResults instance.
+ * @param cb        The callback to call when the user closes
+ *                  the notification.
+ * @param user_data The data to pass to the callback.
+ *
+ * @return A UI-specific handle.
+ */
+void *gaim_notify_searchresults(GaimConnection *gc, const char *title,
+								const char *primary, const char *secondary,
+								GaimNotifySearchResults *results, GCallback cb,
+								void *user_data);
+
+void gaim_notify_searchresults_free(GaimNotifySearchResults *results);
+
+/**
+ * Replace old rows with the new. Reuse an existing window.
+ *
+ * @param gc        The GaimConnection structure.
+ * @param results   The GaimNotifySearchResults structure.
+ * @param data      Data returned by the gaim_notify_searchresults().
+ * @param user_data User defined data.
+ */
+void gaim_notify_searchresults_new_rows(GaimConnection *gc,
+										GaimNotifySearchResults *results,
+										void *data, void *user_data);
+
+/**
+ * Adds a button that will be displayed in the search results dialog.
+ *
+ * @param results The search results object.
+ * @param type    Type of the button. (TODO: Only one button of a given type can be displayed.)
+ * @param cb      Function that will be called on the click event.
+ */
+void gaim_notify_searchresults_button_add(GaimNotifySearchResults *results,
+										  GaimNotifySearchButtonType type,
+										  GaimNotifySearchResultsCallback cb);
+
+/**
+ * Returns a newly created search results object.
+ *
+ * @return The new search results object.
+ */
+GaimNotifySearchResults *gaim_notify_searchresults_new();
+
+/**
+ * Returns a newly created search result column object.
+ *
+ * @param title Title of the column. NOTE: Title will get g_strdup()ed.
+ * 
+ * @return The new search column object.
+ */
+GaimNotifySearchColumn *gaim_notify_searchresults_column_new(const char *title);
+
+/**
+ * Adds a new column to the search result object.
+ *
+ * @param results The result object to which the column will be added.
+ * @param columnt The column that will be added to the result object.
+ */
+void gaim_notify_searchresults_column_add(GaimNotifySearchResults *results,
+										  GaimNotifySearchColumn *column);
+
+/**
+ * Adds a new row of the results to the search results object.
+ *
+ * @param results The search results object.
+ * @param row     The row of the results.
+ */
+void gaim_notify_searchresults_row_add(GaimNotifySearchResults *results,
+									   GList *row);
+
+/**
+ * Returns a number of the rows in the search results object.
+ * 
+ * @param results The search results object.
+ *
+ * @return Number of the result rows. Or -1 if an error occurrs.
+ */
+int gaim_notify_searchresults_get_rows_count(GaimNotifySearchResults *results);
+
+/**
+ * Returns a number of the columns in the search results object.
+ *
+ * @param results The search results object.
+ *
+ * @return Number of the columns. Or -1 if an error occurrs.
+ */
+int gaim_notify_searchresults_get_columns_count(GaimNotifySearchResults *results);
+
+/**
+ * Returns a row of the results from the search results object.
+ *
+ * @param results The search results object.
+ * @param row_id  Index of the row to be returned.
+ *
+ * @return Row of the results.
+ */
+GList *gaim_notify_searchresults_row_get(GaimNotifySearchResults *results,
+										 unsigned int row_id);
+
+/**
+ * Returns a title of the search results object's column.
+ * 
+ * @param results   The search results object.
+ * @param column_id Index of the column.
+ *
+ * @return Title of the column.
+ */
+char *gaim_notify_searchresults_column_get_title(GaimNotifySearchResults *results,
+												 unsigned int column_id);
+
+/*@}*/
+
+/**************************************************************************/
 /** @name Notification API                                                */
 /**************************************************************************/
 /*@{*/
@@ -181,28 +354,6 @@
 							const char *text, GCallback cb, void *user_data);
 
 /**
- * Displays results from a buddy search.  This can be, for example,
- * a window with a list of all found buddies, where you are given the
- * option of adding buddies to your buddy list.
- *
- * @param gc        The GaimConnection handle associated with the information.
- * @param title     The title of the message.  If this is NULL, the title
- *                  will be "Search	Results."
- * @param primary   The main point of the message.
- * @param secondary The secondary information.
- * @param results   An null-terminated array of null-terminated buddy names.
- * @param cb        The callback to call when the user closes
- *                  the notification.
- * @param user_data The data to pass to the callback.
- *
- * @return A UI-specific handle.
- */
-void *gaim_notify_searchresults(GaimConnection *gc, const char *title,
-								const char *primary, const char *secondary,
-								const char **results, GCallback cb,
-								void *user_data);
-
-/**
  * Displays user information with formatted text, passing information giving
  * the connection and username from which the user information came.
  *
--- a/src/protocols/oscar/oscar.c	Sun Aug 28 22:18:08 2005 +0000
+++ b/src/protocols/oscar/oscar.c	Sun Aug 28 22:21:24 2005 +0000
@@ -5449,11 +5449,18 @@
 	return 1;
 }
 
+static void oscar_searchresults_add_buddy_cb(GaimConnection *gc, GList *row)
+{
+	gaim_blist_request_add_buddy(gaim_connection_get_account(gc),
+								 g_list_nth_data(row, 0), NULL, NULL);
+}
+
 static int gaim_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...)
 {
 	GaimConnection *gc = sess->aux_data;
+	GaimNotifySearchResults *results;
+	GaimNotifySearchColumn *column;
 	gchar *secondary;
-	gchar **screennames;
 	int i, num;
 	va_list ap;
 	char *email, *SNs;
@@ -5467,16 +5474,20 @@
 	/* TODO: Need to use ngettext() here */
 	secondary = g_strdup_printf(_("The following screen names are associated with %s"), email);
 
-	screennames = g_malloc((num + 1) * sizeof(gchar *));
-	for (i = 0; i < num; i++)
-		screennames[i] = g_strdup(&SNs[i * (MAXSNLEN + 1)]);
-	screennames[num] = NULL;
-
-	gaim_notify_searchresults(gc, NULL, NULL, secondary,
-							  (const char **)screennames, NULL, NULL);
+	results = gaim_notify_searchresults_new();
+	column = gaim_notify_searchresults_column_new("Screen name");
+	gaim_notify_searchresults_column_add(results, column);
+
+	for (i = 0; i < num; i++) {
+		GList *row = NULL;
+		row = g_list_append(row, g_strdup(&SNs[i * (MAXSNLEN + 1)]));
+		gaim_notify_searchresults_row_add(results, row);
+	}
+	gaim_notify_searchresults_button_add(results, GAIM_NOTIFY_BUTTON_ADD_BUDDY,
+										 oscar_searchresults_add_buddy_cb);
+	gaim_notify_searchresults(gc, NULL, NULL, secondary, results, NULL, NULL);
 
 	g_free(secondary);
-	g_strfreev(screennames);
 
 	return 1;
 }