These changes are reuired to make the Windows installer build.
[pidgin-git.git] / libpurple / notify.c
blob349521f76428387f21b453655c1f212f5812408a
1 /**
2 * @file notify.c Notification API
3 * @ingroup core
4 */
6 /* purple
8 * Purple is the legal property of its developers, whose names are too numerous
9 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * source distribution.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 #define _PURPLE_NOTIFY_C_
28 #include "internal.h"
29 #include "dbus-maybe.h"
30 #include "notify.h"
32 static PurpleNotifyUiOps *notify_ui_ops = NULL;
33 static GList *handles = NULL;
35 typedef struct
37 PurpleNotifyType type;
38 void *handle;
39 void *ui_handle;
40 PurpleNotifyCloseCallback cb;
41 gpointer cb_user_data;
42 } PurpleNotifyInfo;
44 /**
45 * Definition of a user info entry
47 struct _PurpleNotifyUserInfoEntry
49 char *label;
50 char *value;
51 PurpleNotifyUserInfoEntryType type;
54 struct _PurpleNotifyUserInfo
56 GList *user_info_entries;
59 void *
60 purple_notify_message(void *handle, PurpleNotifyMsgType type,
61 const char *title, const char *primary,
62 const char *secondary, PurpleNotifyCloseCallback cb, gpointer user_data)
64 PurpleNotifyUiOps *ops;
66 g_return_val_if_fail(primary != NULL, NULL);
68 ops = purple_notify_get_ui_ops();
70 if (ops != NULL && ops->notify_message != NULL) {
71 void *ui_handle = ops->notify_message(type, title, primary,
72 secondary);
73 if (ui_handle != NULL) {
75 PurpleNotifyInfo *info = g_new0(PurpleNotifyInfo, 1);
76 info->type = PURPLE_NOTIFY_MESSAGE;
77 info->handle = handle;
78 info->ui_handle = ui_handle;
79 info->cb = cb;
80 info->cb_user_data = user_data;
82 handles = g_list_append(handles, info);
84 return info->ui_handle;
89 if (cb != NULL)
90 cb(user_data);
92 return NULL;
95 void *
96 purple_notify_email(void *handle, const char *subject, const char *from,
97 const char *to, const char *url, PurpleNotifyCloseCallback cb,
98 gpointer user_data)
100 PurpleNotifyUiOps *ops;
102 ops = purple_notify_get_ui_ops();
104 if (ops != NULL && ops->notify_email != NULL) {
105 void *ui_handle;
107 purple_signal_emit(purple_notify_get_handle(), "displaying-email-notification",
108 subject, from, to, url);
110 ui_handle = ops->notify_email(handle, subject, from, to, url);
112 if (ui_handle != NULL) {
114 PurpleNotifyInfo *info = g_new0(PurpleNotifyInfo, 1);
115 info->type = PURPLE_NOTIFY_EMAIL;
116 info->handle = handle;
117 info->ui_handle = ui_handle;
118 info->cb = cb;
119 info->cb_user_data = user_data;
121 handles = g_list_append(handles, info);
123 return info->ui_handle;
127 if (cb != NULL)
128 cb(user_data);
130 return NULL;
133 void *
134 purple_notify_emails(void *handle, size_t count, gboolean detailed,
135 const char **subjects, const char **froms,
136 const char **tos, const char **urls,
137 PurpleNotifyCloseCallback cb, gpointer user_data)
139 PurpleNotifyUiOps *ops;
141 if (count == 1) {
142 return purple_notify_email(handle,
143 (subjects == NULL ? NULL : *subjects),
144 (froms == NULL ? NULL : *froms),
145 (tos == NULL ? NULL : *tos),
146 (urls == NULL ? NULL : *urls),
147 cb, user_data);
150 ops = purple_notify_get_ui_ops();
152 if (ops != NULL && ops->notify_emails != NULL) {
153 void *ui_handle;
155 purple_signal_emit(purple_notify_get_handle(), "displaying-emails-notification",
156 subjects, froms, tos, urls, count);
158 ui_handle = ops->notify_emails(handle, count, detailed, subjects,
159 froms, tos, urls);
161 if (ui_handle != NULL) {
162 PurpleNotifyInfo *info = g_new0(PurpleNotifyInfo, 1);
163 info->type = PURPLE_NOTIFY_EMAILS;
164 info->handle = handle;
165 info->ui_handle = ui_handle;
166 info->cb = cb;
167 info->cb_user_data = user_data;
169 handles = g_list_append(handles, info);
171 return info->ui_handle;
176 if (cb != NULL)
177 cb(user_data);
179 return NULL;
182 void *
183 purple_notify_formatted(void *handle, const char *title, const char *primary,
184 const char *secondary, const char *text,
185 PurpleNotifyCloseCallback cb, gpointer user_data)
187 PurpleNotifyUiOps *ops;
189 g_return_val_if_fail(primary != NULL, NULL);
191 ops = purple_notify_get_ui_ops();
193 if (ops != NULL && ops->notify_formatted != NULL) {
194 void *ui_handle = ops->notify_formatted(title, primary, secondary, text);
196 if (ui_handle != NULL) {
198 PurpleNotifyInfo *info = g_new0(PurpleNotifyInfo, 1);
199 info->type = PURPLE_NOTIFY_FORMATTED;
200 info->handle = handle;
201 info->ui_handle = ui_handle;
202 info->cb = cb;
203 info->cb_user_data = user_data;
205 handles = g_list_append(handles, info);
207 return info->ui_handle;
211 if (cb != NULL)
212 cb(user_data);
213 return NULL;
216 void *
217 purple_notify_searchresults(PurpleConnection *gc, const char *title,
218 const char *primary, const char *secondary,
219 PurpleNotifySearchResults *results, PurpleNotifyCloseCallback cb,
220 gpointer user_data)
222 PurpleNotifyUiOps *ops;
224 ops = purple_notify_get_ui_ops();
226 if (ops != NULL && ops->notify_searchresults != NULL) {
227 void *ui_handle = ops->notify_searchresults(gc, title, primary,
228 secondary, results, user_data);
229 if (ui_handle != NULL) {
231 PurpleNotifyInfo *info = g_new0(PurpleNotifyInfo, 1);
232 info->type = PURPLE_NOTIFY_SEARCHRESULTS;
233 info->handle = gc;
234 info->ui_handle = ui_handle;
235 info->cb = cb;
236 info->cb_user_data = user_data;
238 handles = g_list_append(handles, info);
240 return info->ui_handle;
244 if (cb != NULL)
245 cb(user_data);
247 return NULL;
250 void
251 purple_notify_searchresults_free(PurpleNotifySearchResults *results)
253 GList *l;
255 g_return_if_fail(results != NULL);
257 for (l = results->buttons; l; l = g_list_delete_link(l, l)) {
258 PurpleNotifySearchButton *button = l->data;
259 g_free(button->label);
260 g_free(button);
263 for (l = results->rows; l; l = g_list_delete_link(l, l)) {
264 GList *row = l->data;
265 g_list_foreach(row, (GFunc)g_free, NULL);
266 g_list_free(row);
269 for (l = results->columns; l; l = g_list_delete_link(l, l)) {
270 PurpleNotifySearchColumn *column = l->data;
271 g_free(column->title);
272 g_free(column);
275 g_free(results);
278 void
279 purple_notify_searchresults_new_rows(PurpleConnection *gc,
280 PurpleNotifySearchResults *results,
281 void *data)
283 PurpleNotifyUiOps *ops;
285 ops = purple_notify_get_ui_ops();
287 if (ops != NULL && ops->notify_searchresults != NULL) {
288 ops->notify_searchresults_new_rows(gc, results, data);
292 void
293 purple_notify_searchresults_button_add(PurpleNotifySearchResults *results,
294 PurpleNotifySearchButtonType type,
295 PurpleNotifySearchResultsCallback cb)
297 PurpleNotifySearchButton *button;
299 g_return_if_fail(results != NULL);
300 g_return_if_fail(cb != NULL);
302 button = g_new0(PurpleNotifySearchButton, 1);
303 button->callback = cb;
304 button->type = type;
306 results->buttons = g_list_append(results->buttons, button);
310 void
311 purple_notify_searchresults_button_add_labeled(PurpleNotifySearchResults *results,
312 const char *label,
313 PurpleNotifySearchResultsCallback cb) {
314 PurpleNotifySearchButton *button;
316 g_return_if_fail(results != NULL);
317 g_return_if_fail(cb != NULL);
318 g_return_if_fail(label != NULL);
319 g_return_if_fail(*label != '\0');
321 button = g_new0(PurpleNotifySearchButton, 1);
322 button->callback = cb;
323 button->type = PURPLE_NOTIFY_BUTTON_LABELED;
324 button->label = g_strdup(label);
326 results->buttons = g_list_append(results->buttons, button);
330 PurpleNotifySearchResults *
331 purple_notify_searchresults_new()
333 PurpleNotifySearchResults *rs = g_new0(PurpleNotifySearchResults, 1);
335 return rs;
338 void
339 purple_notify_searchresults_column_add(PurpleNotifySearchResults *results,
340 PurpleNotifySearchColumn *column)
342 g_return_if_fail(results != NULL);
343 g_return_if_fail(column != NULL);
345 results->columns = g_list_append(results->columns, column);
348 void purple_notify_searchresults_row_add(PurpleNotifySearchResults *results,
349 GList *row)
351 g_return_if_fail(results != NULL);
352 g_return_if_fail(row != NULL);
354 results->rows = g_list_append(results->rows, row);
357 PurpleNotifySearchColumn *
358 purple_notify_searchresults_column_new(const char *title)
360 PurpleNotifySearchColumn *sc;
362 g_return_val_if_fail(title != NULL, NULL);
364 sc = g_new0(PurpleNotifySearchColumn, 1);
365 sc->title = g_strdup(title);
367 return sc;
370 guint
371 purple_notify_searchresults_get_columns_count(PurpleNotifySearchResults *results)
373 g_return_val_if_fail(results != NULL, 0);
375 return g_list_length(results->columns);
378 guint
379 purple_notify_searchresults_get_rows_count(PurpleNotifySearchResults *results)
381 g_return_val_if_fail(results != NULL, 0);
383 return g_list_length(results->rows);
386 char *
387 purple_notify_searchresults_column_get_title(PurpleNotifySearchResults *results,
388 unsigned int column_id)
390 g_return_val_if_fail(results != NULL, NULL);
392 return ((PurpleNotifySearchColumn *)g_list_nth_data(results->columns, column_id))->title;
395 GList *
396 purple_notify_searchresults_row_get(PurpleNotifySearchResults *results,
397 unsigned int row_id)
399 g_return_val_if_fail(results != NULL, NULL);
401 return g_list_nth_data(results->rows, row_id);
404 void *
405 purple_notify_userinfo(PurpleConnection *gc, const char *who,
406 PurpleNotifyUserInfo *user_info, PurpleNotifyCloseCallback cb, gpointer user_data)
408 PurpleNotifyUiOps *ops;
410 g_return_val_if_fail(who != NULL, NULL);
412 ops = purple_notify_get_ui_ops();
414 if (ops != NULL && ops->notify_userinfo != NULL) {
415 void *ui_handle;
417 purple_signal_emit(purple_notify_get_handle(), "displaying-userinfo",
418 purple_connection_get_account(gc), who, user_info);
420 ui_handle = ops->notify_userinfo(gc, who, user_info);
422 if (ui_handle != NULL) {
424 PurpleNotifyInfo *info = g_new0(PurpleNotifyInfo, 1);
425 info->type = PURPLE_NOTIFY_USERINFO;
426 info->handle = gc;
427 info->ui_handle = ui_handle;
428 info->cb = cb;
429 info->cb_user_data = user_data;
431 handles = g_list_append(handles, info);
433 return info->ui_handle;
437 if (cb != NULL)
438 cb(user_data);
440 return NULL;
443 PurpleNotifyUserInfoEntry *
444 purple_notify_user_info_entry_new(const char *label, const char *value)
446 PurpleNotifyUserInfoEntry *user_info_entry;
448 user_info_entry = g_new0(PurpleNotifyUserInfoEntry, 1);
449 PURPLE_DBUS_REGISTER_POINTER(user_info_entry, PurpleNotifyUserInfoEntry);
450 user_info_entry->label = g_strdup(label);
451 user_info_entry->value = g_strdup(value);
452 user_info_entry->type = PURPLE_NOTIFY_USER_INFO_ENTRY_PAIR;
454 return user_info_entry;
457 static void
458 purple_notify_user_info_entry_destroy(PurpleNotifyUserInfoEntry *user_info_entry)
460 g_return_if_fail(user_info_entry != NULL);
462 g_free(user_info_entry->label);
463 g_free(user_info_entry->value);
464 PURPLE_DBUS_UNREGISTER_POINTER(user_info_entry);
465 g_free(user_info_entry);
468 PurpleNotifyUserInfo *
469 purple_notify_user_info_new()
471 PurpleNotifyUserInfo *user_info;
473 user_info = g_new0(PurpleNotifyUserInfo, 1);
474 PURPLE_DBUS_REGISTER_POINTER(user_info, PurpleNotifyUserInfo);
475 user_info->user_info_entries = NULL;
477 return user_info;
480 void
481 purple_notify_user_info_destroy(PurpleNotifyUserInfo *user_info)
483 GList *l;
485 for (l = user_info->user_info_entries; l != NULL; l = l->next) {
486 PurpleNotifyUserInfoEntry *user_info_entry = l->data;
488 purple_notify_user_info_entry_destroy(user_info_entry);
491 g_list_free(user_info->user_info_entries);
492 PURPLE_DBUS_UNREGISTER_POINTER(user_info);
493 g_free(user_info);
496 GList *
497 purple_notify_user_info_get_entries(PurpleNotifyUserInfo *user_info)
499 g_return_val_if_fail(user_info != NULL, NULL);
501 return user_info->user_info_entries;
504 char *
505 purple_notify_user_info_get_text_with_newline(PurpleNotifyUserInfo *user_info, const char *newline)
507 GList *l;
508 GString *text;
510 text = g_string_new("");
512 for (l = user_info->user_info_entries; l != NULL; l = l->next) {
513 PurpleNotifyUserInfoEntry *user_info_entry = l->data;
514 /* Add a newline before a section header */
515 if (user_info_entry->type == PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER)
516 g_string_append(text, newline);
518 /* Handle the label/value pair itself */
519 /* XXX Todo: Use a larger size for a section header? */
520 if (user_info_entry->label)
521 g_string_append_printf(text, "<b>%s</b>", user_info_entry->label);
522 if (user_info_entry->label && user_info_entry->value)
523 g_string_append(text, ": ");
524 if (user_info_entry->value)
525 g_string_append(text, user_info_entry->value);
527 /* Display a section break as a horizontal line */
528 if (user_info_entry->type == PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK)
529 g_string_append(text, "<HR>");
531 /* Don't insert a new line before or after a section break; <HR> does that for us */
532 if ((user_info_entry->type != PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK) &&
533 (l->next && ((((PurpleNotifyUserInfoEntry *)(l->next->data))->type != PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK))))
534 g_string_append(text, newline);
536 /* Add an extra newline after a section header */
537 if (user_info_entry->type == PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER)
538 g_string_append(text, newline);
541 return g_string_free(text, FALSE);
545 const gchar *
546 purple_notify_user_info_entry_get_label(PurpleNotifyUserInfoEntry *user_info_entry)
548 g_return_val_if_fail(user_info_entry != NULL, NULL);
550 return user_info_entry->label;
553 void
554 purple_notify_user_info_entry_set_label(PurpleNotifyUserInfoEntry *user_info_entry, const char *label)
556 g_return_if_fail(user_info_entry != NULL);
558 g_free(user_info_entry->label);
559 user_info_entry->label = g_strdup(label);
562 const gchar *
563 purple_notify_user_info_entry_get_value(PurpleNotifyUserInfoEntry *user_info_entry)
565 g_return_val_if_fail(user_info_entry != NULL, NULL);
567 return user_info_entry->value;
570 void
571 purple_notify_user_info_entry_set_value(PurpleNotifyUserInfoEntry *user_info_entry, const char *value)
573 g_return_if_fail(user_info_entry != NULL);
575 g_free(user_info_entry->value);
576 user_info_entry->value = g_strdup(value);
579 PurpleNotifyUserInfoEntryType
580 purple_notify_user_info_entry_get_type(PurpleNotifyUserInfoEntry *user_info_entry)
582 g_return_val_if_fail(user_info_entry != NULL, PURPLE_NOTIFY_USER_INFO_ENTRY_PAIR);
584 return user_info_entry->type;
587 void
588 purple_notify_user_info_entry_set_type(PurpleNotifyUserInfoEntry *user_info_entry, PurpleNotifyUserInfoEntryType type)
590 g_return_if_fail(user_info_entry != NULL);
592 user_info_entry->type = type;
595 void
596 purple_notify_user_info_add_pair(PurpleNotifyUserInfo *user_info, const char *label, const char *value)
598 PurpleNotifyUserInfoEntry *entry;
600 entry = purple_notify_user_info_entry_new(label, value);
601 user_info->user_info_entries = g_list_append(user_info->user_info_entries, entry);
604 void
605 purple_notify_user_info_prepend_pair(PurpleNotifyUserInfo *user_info, const char *label, const char *value)
607 PurpleNotifyUserInfoEntry *entry;
609 entry = purple_notify_user_info_entry_new(label, value);
610 user_info->user_info_entries = g_list_prepend(user_info->user_info_entries, entry);
613 void
614 purple_notify_user_info_remove_entry(PurpleNotifyUserInfo *user_info, PurpleNotifyUserInfoEntry *entry)
616 g_return_if_fail(user_info != NULL);
617 g_return_if_fail(entry != NULL);
619 user_info->user_info_entries = g_list_remove(user_info->user_info_entries, entry);
622 void
623 purple_notify_user_info_add_section_header(PurpleNotifyUserInfo *user_info, const char *label)
625 PurpleNotifyUserInfoEntry *entry;
627 entry = purple_notify_user_info_entry_new(label, NULL);
628 entry->type = PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER;
630 user_info->user_info_entries = g_list_append(user_info->user_info_entries, entry);
633 void
634 purple_notify_user_info_prepend_section_header(PurpleNotifyUserInfo *user_info, const char *label)
636 PurpleNotifyUserInfoEntry *entry;
638 entry = purple_notify_user_info_entry_new(label, NULL);
639 entry->type = PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER;
641 user_info->user_info_entries = g_list_prepend(user_info->user_info_entries, entry);
644 void
645 purple_notify_user_info_add_section_break(PurpleNotifyUserInfo *user_info)
647 PurpleNotifyUserInfoEntry *entry;
649 entry = purple_notify_user_info_entry_new(NULL, NULL);
650 entry->type = PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK;
652 user_info->user_info_entries = g_list_append(user_info->user_info_entries, entry);
655 void
656 purple_notify_user_info_prepend_section_break(PurpleNotifyUserInfo *user_info)
658 PurpleNotifyUserInfoEntry *entry;
660 entry = purple_notify_user_info_entry_new(NULL, NULL);
661 entry->type = PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK;
663 user_info->user_info_entries = g_list_prepend(user_info->user_info_entries, entry);
666 void
667 purple_notify_user_info_remove_last_item(PurpleNotifyUserInfo *user_info)
669 GList *last = g_list_last(user_info->user_info_entries);
670 if (last) {
671 purple_notify_user_info_entry_destroy(last->data);
672 user_info->user_info_entries = g_list_delete_link(user_info->user_info_entries, last);
676 void *
677 purple_notify_uri(void *handle, const char *uri)
679 PurpleNotifyUiOps *ops;
681 g_return_val_if_fail(uri != NULL, NULL);
683 ops = purple_notify_get_ui_ops();
685 if (ops != NULL && ops->notify_uri != NULL) {
687 void *ui_handle = ops->notify_uri(uri);
689 if (ui_handle != NULL) {
691 PurpleNotifyInfo *info = g_new0(PurpleNotifyInfo, 1);
692 info->type = PURPLE_NOTIFY_URI;
693 info->handle = handle;
694 info->ui_handle = ui_handle;
696 handles = g_list_append(handles, info);
698 return info->ui_handle;
702 return NULL;
705 void
706 purple_notify_close(PurpleNotifyType type, void *ui_handle)
708 GList *l;
709 PurpleNotifyUiOps *ops;
711 g_return_if_fail(ui_handle != NULL);
713 ops = purple_notify_get_ui_ops();
715 for (l = handles; l != NULL; l = l->next) {
716 PurpleNotifyInfo *info = l->data;
718 if (info->ui_handle == ui_handle) {
719 handles = g_list_remove(handles, info);
721 if (ops != NULL && ops->close_notify != NULL)
722 ops->close_notify(info->type, ui_handle);
724 if (info->cb != NULL)
725 info->cb(info->cb_user_data);
727 g_free(info);
729 break;
734 void
735 purple_notify_close_with_handle(void *handle)
737 GList *l, *prev = NULL;
738 PurpleNotifyUiOps *ops;
740 g_return_if_fail(handle != NULL);
742 ops = purple_notify_get_ui_ops();
744 for (l = handles; l != NULL; l = prev ? prev->next : handles) {
745 PurpleNotifyInfo *info = l->data;
747 if (info->handle == handle) {
748 handles = g_list_remove(handles, info);
750 if (ops != NULL && ops->close_notify != NULL)
751 ops->close_notify(info->type, info->ui_handle);
753 if (info->cb != NULL)
754 info->cb(info->cb_user_data);
756 g_free(info);
757 } else
758 prev = l;
762 void
763 purple_notify_set_ui_ops(PurpleNotifyUiOps *ops)
765 notify_ui_ops = ops;
768 PurpleNotifyUiOps *
769 purple_notify_get_ui_ops(void)
771 return notify_ui_ops;
774 void *
775 purple_notify_get_handle(void)
777 static int handle;
779 return &handle;
782 void
783 purple_notify_init(void)
785 gpointer handle = purple_notify_get_handle();
787 purple_signal_register(handle, "displaying-email-notification",
788 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER, NULL, 4,
789 purple_value_new(PURPLE_TYPE_STRING),
790 purple_value_new(PURPLE_TYPE_STRING),
791 purple_value_new(PURPLE_TYPE_STRING),
792 purple_value_new(PURPLE_TYPE_STRING));
794 purple_signal_register(handle, "displaying-emails-notification",
795 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT, NULL, 5,
796 purple_value_new(PURPLE_TYPE_POINTER),
797 purple_value_new(PURPLE_TYPE_POINTER),
798 purple_value_new(PURPLE_TYPE_POINTER),
799 purple_value_new(PURPLE_TYPE_POINTER),
800 purple_value_new(PURPLE_TYPE_UINT));
802 purple_signal_register(handle, "displaying-userinfo",
803 purple_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
804 purple_value_new(PURPLE_TYPE_SUBTYPE,
805 PURPLE_SUBTYPE_ACCOUNT),
806 purple_value_new(PURPLE_TYPE_STRING),
807 purple_value_new(PURPLE_TYPE_SUBTYPE,
808 PURPLE_SUBTYPE_USERINFO));
811 void
812 purple_notify_uninit(void)
814 purple_signals_unregister_by_instance(purple_notify_get_handle());