2
/* Ekiga -- A VoIP and Video-Conferencing application
3
* Copyright (C) 2000-2006 Damien Sandras
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20
* Ekiga is licensed under the GPL license and as a special exception,
21
* you have permission to link or otherwise combine this program with the
22
* programs OPAL, OpenH323 and PWLIB, and distribute the combination,
23
* without applying the requirements of the GNU GPL to the OPAL, OpenH323
24
* and PWLIB programs, as long as you do follow the requirements of the
25
* GNU GPL for all the rest of the software thus combined.
30
* calls_history_window.cpp - description
31
* -----------------------
32
* begin : Sun Sep 1 2002
33
* copyright : (C) 2000-2006 by Damien Sandras
34
* description : This file defines functions to manage the
38
#include "../../config.h"
43
#include "addressbook.h"
46
#include "callshistory.h"
48
#include "callbacks.h"
49
#include "urlhandler.h"
52
#include "gmcontacts.h"
53
#include "gmmenuaddon.h"
55
#include "gmstockicons.h"
58
/* internal representation */
59
struct _GmCallsHistoryWindow
61
GtkWidget *chw_history_tree_view [3];
62
GtkWidget *chw_search_entry;
63
GtkWidget *chw_notebook;
65
typedef struct _GmCallsHistoryWindow GmCallsHistoryWindow;
78
#define GM_CALLS_HISTORY_WINDOW(x) (GmCallsHistoryWindow *) (x)
86
* BEHAVIOR : Frees a GmCallsHistoryWindow and its content.
87
* PRE : A non-NULL pointer to a GmCallsHistoryWindow.
89
static void gm_chw_destroy (gpointer data);
93
* BEHAVIOR : Returns a pointer to the private GmCallsHistoryWindow
94
* used by the calls history GMObject.
95
* PRE : The given GtkWidget pointer must be a calls history GMObject.
97
static GmCallsHistoryWindow *gm_chw_get_chw (GtkWidget *calls_history_window);
101
* BEHAVIOR : Returns a pointer to a newly allocated GmContact with
102
* all the info for the contact currently being selected
103
* in the calls history window given as argument. NULL if none
105
* PRE : The given GtkWidget pointer must point to the calls history
108
static GmContact *gm_chw_get_selected_contact (GtkWidget *calls_history_window);
112
* BEHAVIOR : Creates a calls history item menu and returns it.
113
* PRE : The given GtkWidget pointer must point to the calls history
116
static GtkWidget *gm_chw_contact_menu_new (GtkWidget *calls_history_window);
120
* BEHAVIOR : Populate the calls history with the stored history.
121
* PRE : The given GtkWidget pointer must point to the calls history
124
static void gm_chw_update (GtkWidget *calls_history_window);
128
* BEHAVIOR : Returns the config key associated with the given call type
132
static gchar *gm_chw_get_conf_key (int calltype);
135
/* DESCRIPTION : This function is called when the user drops the contact.
136
* BEHAVIOR : Returns the dragged contact
137
* PRE : Assumes data hides a calls history window (widget)
139
static GmContact *dnd_get_contact (GtkWidget *widget,
145
/* DESCRIPTION : This callback is called when the user has clicked the clear
147
* BEHAVIOR : Clears the corresponding calls list using the config DB.
148
* PRE : data = the calls history window GMObject.
150
static void clear_button_clicked_cb (GtkButton *widget,
154
/* DESCRIPTION : This callback is called when the user has clicked the find
156
* BEHAVIOR : Hides the rows that do not contain the text in the search
158
* PRE : data = the GtkNotebook containing the 3 lists of calls.
160
static void find_button_clicked_cb (GtkButton *widget,
165
* BEHAVIOR : This callback is called when the user clicks on a contact.
167
* PRE : A valid pointer to the calls history window GMObject.
169
static gint contact_clicked_cb (GtkWidget *widget,
170
GdkEventButton *event,
175
* BEHAVIOR : This callback is called when the user chooses to call
176
* a contact using the menu.
177
* PRE : The calls history window as argument.
179
static void call_contact1_cb (GtkWidget *widget,
184
* BEHAVIOR : This callback is called when the user chooses to call
185
* a contact by double-clicking on it.
186
* PRE : The calls history window as argument.
188
static void call_contact2_cb (GtkTreeView *tree_view,
190
GtkTreeViewColumn *arg2,
195
* BEHAVIOR : This callback is called when the user chooses to add the
196
* contact in the address book.
197
* It presents the dialog to edit a contact.
198
* PRE : The gpointer must point to the calls history window.
200
static void add_contact_cb (GtkWidget *widget,
204
/* DESCRIPTION : This function is called to compare 1 GmContact to an URL.
205
* BEHAVIOR : Returns 0 if both URLs are equal.
208
static gint contact_compare_cb (gconstpointer contact,
212
/* DESCRIPTION : This callback is called when one of the calls history * config value changes.
213
* BEHAVIOR : Rebuild its content, regenerate the cache of urls in
214
* the main and chat windows.
215
* PRE : A valid pointer to the calls history window GMObject.
218
calls_history_changed_nt (gpointer id,
225
gm_chw_destroy (gpointer data)
227
g_return_if_fail (data);
229
delete ((GmCallsHistoryWindow *) data);
233
static GmCallsHistoryWindow *
234
gm_chw_get_chw (GtkWidget *calls_history_window)
236
g_return_val_if_fail (calls_history_window != NULL, NULL);
238
return GM_CALLS_HISTORY_WINDOW (g_object_get_data (G_OBJECT (calls_history_window), "GMObject"));
243
gm_chw_get_selected_contact (GtkWidget *calls_history_window)
245
GmContact *contact = NULL;
247
GmCallsHistoryWindow *chw = NULL;
249
GtkTreeSelection *selection = NULL;
250
GtkTreeModel *model = NULL;
256
g_return_val_if_fail (calls_history_window != NULL, NULL);
258
chw = gm_chw_get_chw (calls_history_window);
260
g_return_val_if_fail (chw != NULL, NULL);
262
page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (chw->chw_notebook));
264
g_return_val_if_fail ((page_num == RECEIVED_CALL || page_num == PLACED_CALL || page_num == MISSED_CALL), NULL);
267
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (chw->chw_history_tree_view [page_num]));
268
model = gtk_tree_view_get_model (GTK_TREE_VIEW (chw->chw_history_tree_view [page_num]));
270
if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
272
contact = gmcontact_new ();
274
gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
275
COLUMN_NAME, &contact->fullname,
276
COLUMN_URL, &contact->url,
286
gm_chw_contact_menu_new (GtkWidget *calls_history_window)
288
GtkWidget *menu = NULL;
290
menu = gtk_menu_new ();
293
static MenuEntry contact_menu [] =
295
GTK_MENU_ENTRY("call", _("C_all Contact"), NULL,
297
GTK_SIGNAL_FUNC (call_contact1_cb),
298
calls_history_window, TRUE),
302
GTK_MENU_ENTRY("add", _("Add Contact to _Address Book"), NULL,
304
GTK_SIGNAL_FUNC (add_contact_cb),
305
calls_history_window, TRUE),
311
gtk_build_menu (menu, contact_menu, NULL, NULL);
319
gm_chw_update (GtkWidget *calls_history_window)
321
GmCallsHistoryWindow *chw = NULL;
324
GtkListStore *list_store = NULL;
326
gchar *conf_key = NULL;
327
gchar **call_data = NULL;
329
GSList *calls_list = NULL;
330
GSList *calls_list_iter = NULL;
332
chw = gm_chw_get_chw (calls_history_window);
334
for (int i = 0 ; i < MAX_VALUE_CALL ; i++) {
336
list_store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (chw->chw_history_tree_view [i])));
338
conf_key = gm_chw_get_conf_key (i);
340
gtk_list_store_clear (list_store);
342
calls_list = gm_conf_get_string_list (conf_key);
344
calls_list_iter = calls_list;
345
while (calls_list_iter && calls_list_iter->data) {
347
call_data = g_strsplit ((char *) calls_list_iter->data, "|", 0);
351
gtk_list_store_append (list_store, &iter);
352
gtk_list_store_set (list_store,
363
g_strfreev (call_data);
365
calls_list_iter = g_slist_next (calls_list_iter);
370
g_slist_foreach (calls_list, (GFunc) g_free, NULL);
371
g_slist_free (calls_list);
377
gm_chw_get_conf_key (int i)
379
gchar *conf_key = NULL;
381
g_return_val_if_fail ((i >= 0 && i < MAX_VALUE_CALL), NULL);
387
g_strdup (USER_INTERFACE_KEY "calls_history_window/received_calls_history");
391
g_strdup (USER_INTERFACE_KEY "calls_history_window/placed_calls_history");
395
g_strdup (USER_INTERFACE_KEY "calls_history_window/missed_calls_history");
405
dnd_get_contact (GtkWidget *widget,
408
GtkWidget *chw = NULL;
410
chw = GTK_WIDGET (data);
412
return gm_chw_get_selected_contact (chw);
417
clear_button_clicked_cb (GtkButton *widget,
420
GmCallsHistoryWindow *chw = NULL;
424
g_return_if_fail (data != NULL);
426
chw = gm_chw_get_chw (GTK_WIDGET (data));
428
g_return_if_fail (chw);
430
i = gtk_notebook_get_current_page (GTK_NOTEBOOK (chw->chw_notebook));
432
gm_calls_history_clear (i);
437
find_button_clicked_cb (GtkButton *widget,
440
GmCallsHistoryWindow *chw = NULL;
442
GtkListStore *list_store = NULL;
444
const char *entry_text = NULL;
446
gchar *software = NULL;
447
gchar *remote_user = NULL;
448
gchar *end_reason = NULL;
450
BOOL removed = FALSE;
456
g_return_if_fail (data != NULL);
458
/* Fill in the window */
459
gm_chw_update (GTK_WIDGET (data));
461
chw = gm_chw_get_chw (GTK_WIDGET (data));
463
g_return_if_fail (chw);
466
entry_text = gtk_entry_get_text (GTK_ENTRY (chw->chw_search_entry));
468
page = gtk_notebook_get_current_page (GTK_NOTEBOOK (chw->chw_notebook));
470
list_store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (chw->chw_history_tree_view [page])));
473
if (strcmp (entry_text, "")
474
&& gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store), &iter)) {
480
gtk_tree_model_get (GTK_TREE_MODEL (list_store),
483
COLUMN_NAME, &remote_user,
484
COLUMN_ENDREASON, &end_reason,
485
COLUMN_SOFTWARE, &software,
488
if (!(PString (date).Find (entry_text) != P_MAX_INDEX
489
|| PString (remote_user).Find (entry_text) != P_MAX_INDEX
490
|| PString (end_reason).Find (entry_text) != P_MAX_INDEX
491
|| PString (software).Find (entry_text) != P_MAX_INDEX)) {
493
ok = gtk_list_store_remove (GTK_LIST_STORE (list_store), &iter);
498
g_free (remote_user);
503
ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (list_store), &iter);
511
contact_clicked_cb (GtkWidget *widget,
512
GdkEventButton *event,
515
GtkWidget *menu = NULL;
517
g_return_val_if_fail (data != NULL, FALSE);
519
if (event->type == GDK_BUTTON_PRESS || event->type == GDK_KEY_PRESS) {
521
if (event->button == 3) {
523
menu = gm_chw_contact_menu_new (GTK_WIDGET (data));
524
gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
525
event->button, event->time);
526
g_signal_connect (G_OBJECT (menu), "hide",
527
GTK_SIGNAL_FUNC (g_object_unref), (gpointer) menu);
528
g_object_ref (G_OBJECT (menu));
529
gtk_object_sink (GTK_OBJECT (menu));
538
call_contact1_cb (GtkWidget *widget,
541
GmContact *contact = NULL;
543
GtkWidget *calls_history_window = NULL;
545
g_return_if_fail (data != NULL);
547
calls_history_window = GTK_WIDGET (data);
549
contact = gm_chw_get_selected_contact (calls_history_window);
553
GnomeMeeting::Process ()->Connect (contact->url);
554
gmcontact_delete (contact);
560
call_contact2_cb (GtkTreeView *tree_view,
562
GtkTreeViewColumn *arg2,
565
g_return_if_fail (data != NULL);
567
call_contact1_cb (NULL, data);
572
add_contact_cb (GtkWidget *widget,
575
GmContact *contact = NULL;
577
GtkWidget *calls_history_window = NULL;
578
GtkWidget *addressbook_window = NULL;
580
g_return_if_fail (data != NULL);
582
calls_history_window = GTK_WIDGET (data);
583
addressbook_window = GnomeMeeting::Process ()->GetAddressbookWindow ();
585
contact = gm_chw_get_selected_contact (calls_history_window);
589
gm_addressbook_window_edit_contact_dialog_run (addressbook_window,
593
calls_history_window);
594
gmcontact_delete (contact);
600
contact_compare_cb (gconstpointer contact,
603
GmContact *gmcontact = NULL;
605
if (!contact || !url)
608
gmcontact = GM_CONTACT (contact);
610
if (gmcontact->url && url) {
612
if (GMURL (gmcontact->url) == GMURL ((char *) url))
623
calls_history_changed_nt (gpointer id,
627
GtkWidget *main_window = NULL;
628
GtkWidget *chat_window = NULL;
630
g_return_if_fail (data != NULL);
631
g_return_if_fail (gm_conf_entry_get_type (entry) == GM_CONF_LIST);
633
main_window = GnomeMeeting::Process ()->GetMainWindow ();
634
chat_window = GnomeMeeting::Process ()->GetChatWindow ();
636
gdk_threads_enter ();
637
gm_chw_update (GTK_WIDGET (data));
638
gm_main_window_urls_history_update (main_window);
639
gm_text_chat_window_urls_history_update (chat_window);
640
gdk_threads_leave ();
646
gm_calls_history_window_new ()
648
GtkWidget *hbox = NULL;
649
GtkWidget *button = NULL;
650
GtkWidget *window = NULL;
651
GtkWidget *scr = NULL;
652
GtkWidget *label = NULL;
653
GdkPixbuf *icon = NULL;
655
GmCallsHistoryWindow *chw = NULL;
657
GtkTreeViewColumn *column = NULL;
658
GtkCellRenderer *renderer = NULL;
660
GtkListStore *list_store = NULL;
662
gchar *conf_key = NULL;
663
const gchar *label_text [3] =
664
{N_("Received Calls"), N_("Placed Calls"), N_("Missed Calls")};
665
label_text [0] = gettext (label_text [0]);
666
label_text [1] = gettext (label_text [1]);
667
label_text [2] = gettext (label_text [2]);
670
window = gtk_dialog_new ();
671
gtk_dialog_add_button (GTK_DIALOG (window), GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL);
673
g_object_set_data_full (G_OBJECT (window), "window_name",
674
g_strdup ("calls_history_window"), g_free);
676
gtk_window_set_title (GTK_WINDOW (window), _("Calls History"));
677
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
678
icon = gtk_widget_render_icon (GTK_WIDGET (window),
679
GM_STOCK_CALLS_HISTORY,
680
GTK_ICON_SIZE_MENU, NULL);
681
gtk_window_set_icon (GTK_WINDOW (window), icon);
682
g_object_unref (icon);
684
chw = new GmCallsHistoryWindow ();
685
g_object_set_data_full (G_OBJECT (window), "GMObject",
686
chw, gm_chw_destroy);
689
/* The notebook containing the 3 lists of calls */
690
chw->chw_notebook = gtk_notebook_new ();
691
gtk_container_set_border_width (GTK_CONTAINER (chw->chw_notebook), 6);
692
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
693
chw->chw_notebook, TRUE, TRUE, 0);
696
for (int i = 0 ; i < MAX_VALUE_CALL ; i++) {
698
label = gtk_label_new (N_(label_text [i]));
700
scr = gtk_scrolled_window_new (NULL, NULL);
701
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr),
702
GTK_POLICY_AUTOMATIC,
703
GTK_POLICY_AUTOMATIC);
706
gtk_list_store_new (6,
714
chw->chw_history_tree_view [i] =
715
gtk_tree_view_new_with_model (GTK_TREE_MODEL (list_store));
716
gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (chw->chw_history_tree_view [i]), TRUE);
718
renderer = gtk_cell_renderer_text_new ();
719
column = gtk_tree_view_column_new_with_attributes (_("Date"),
724
gtk_tree_view_append_column (GTK_TREE_VIEW (chw->chw_history_tree_view [i]), column);
726
renderer = gtk_cell_renderer_text_new ();
727
column = gtk_tree_view_column_new_with_attributes (_("Remote User"),
732
gtk_tree_view_append_column (GTK_TREE_VIEW (chw->chw_history_tree_view [i]), column);
733
g_object_set (G_OBJECT (renderer), "weight", "bold", NULL);
735
renderer = gtk_cell_renderer_text_new ();
736
column = gtk_tree_view_column_new_with_attributes (_("Call Duration"),
741
gtk_tree_view_append_column (GTK_TREE_VIEW (chw->chw_history_tree_view [i]), column);
743
gtk_tree_view_column_set_visible (column, false);
745
renderer = gtk_cell_renderer_text_new ();
746
column = gtk_tree_view_column_new_with_attributes (_("Call End Reason"),
751
gtk_tree_view_append_column (GTK_TREE_VIEW (chw->chw_history_tree_view [i]), column);
752
g_object_set (G_OBJECT (renderer), "style", PANGO_STYLE_ITALIC, NULL);
754
renderer = gtk_cell_renderer_text_new ();
755
column = gtk_tree_view_column_new_with_attributes (_("Software"),
760
gtk_tree_view_append_column (GTK_TREE_VIEW (chw->chw_history_tree_view [i]), column);
761
g_object_set (G_OBJECT (renderer), "style", PANGO_STYLE_ITALIC, NULL);
764
gtk_container_add (GTK_CONTAINER (scr), chw->chw_history_tree_view [i]);
765
gtk_notebook_append_page (GTK_NOTEBOOK (chw->chw_notebook), scr, label);
768
/* Signal to call the person on the double-clicked row */
769
g_signal_connect (G_OBJECT (chw->chw_history_tree_view [i]),
771
G_CALLBACK (call_contact2_cb),
774
/* The drag and drop information */
775
gmcontacts_dnd_set_source (GTK_WIDGET (chw->chw_history_tree_view [i]),
776
dnd_get_contact, window);
778
/* Right-click on a contact */
779
g_signal_connect (G_OBJECT (chw->chw_history_tree_view [i]), "event_after",
780
G_CALLBACK (contact_clicked_cb),
784
conf_key = gm_chw_get_conf_key (i);
785
gm_conf_notifier_add (conf_key,
786
calls_history_changed_nt, (gpointer) window);
792
/* The hbox added below the notebook that contains the Search field,
793
and the search and clear buttons */
794
hbox = gtk_hbox_new (FALSE, 0);
795
gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
796
chw->chw_search_entry = gtk_entry_new ();
797
gtk_box_pack_start (GTK_BOX (hbox), chw->chw_search_entry, TRUE, TRUE, 2);
798
g_signal_connect (G_OBJECT (chw->chw_search_entry), "activate",
799
G_CALLBACK (find_button_clicked_cb),
802
button = gtk_button_new_from_stock (GTK_STOCK_FIND);
803
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 2);
804
g_signal_connect (G_OBJECT (button), "clicked",
805
G_CALLBACK (find_button_clicked_cb),
808
button = gtk_button_new_from_stock (GTK_STOCK_CLEAR);
809
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 2);
810
g_signal_connect (G_OBJECT (button), "clicked",
811
G_CALLBACK (clear_button_clicked_cb),
814
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), hbox,
818
/* Generic signals */
819
g_signal_connect_swapped (GTK_OBJECT (window),
821
G_CALLBACK (gnomemeeting_window_hide),
824
g_signal_connect (GTK_OBJECT (window), "delete-event",
825
G_CALLBACK (delete_window_cb), NULL);
828
/* Fill in the window with old calls */
829
gm_chw_update (window);
832
gtk_widget_show_all (GTK_WIDGET (GTK_DIALOG (window)->vbox));
839
gm_calls_history_add_call (int calltype,
840
const char *remote_user,
842
const char *duration,
844
const char *software)
846
gchar *conf_key = NULL;
847
gchar *call_data = NULL;
849
GSList *calls_list = NULL;
853
time = PTime ().AsString ("yyyy/MM/dd hh:mm:ss");
857
g_strdup_printf ("%s|%s|%s|%s|%s|%s",
858
(const char *) time ? (const char *) time : "",
859
remote_user ? remote_user : "",
861
duration ? duration : "",
862
reason ? reason : "",
863
software ? software : "");
865
conf_key = gm_chw_get_conf_key (calltype);
867
calls_list = gm_conf_get_string_list (conf_key);
868
calls_list = g_slist_append (calls_list, (gpointer) call_data);
870
while (g_slist_length (calls_list) > 100)
871
calls_list = g_slist_delete_link (calls_list, calls_list);
873
gm_conf_set_string_list (conf_key, calls_list);
877
g_slist_foreach (calls_list, (GFunc) g_free, NULL);
878
g_slist_free (calls_list);
883
gm_calls_history_clear (int calltype)
885
gchar *conf_key = NULL;
887
g_return_if_fail ((calltype >= 0 && calltype < MAX_VALUE_CALL));
889
conf_key = gm_chw_get_conf_key (calltype);
890
gm_conf_set_string_list (conf_key, NULL);
896
gm_calls_history_get_calls (int calltype,
901
GmContact *contact = NULL;
903
GSList *calls_list = NULL;
904
GSList *calls_list_iter = NULL;
905
GSList *work_list = NULL;
906
GSList *work_list_iter = NULL;
907
GSList *result = NULL;
909
gchar **call_data = NULL;
910
gchar *conf_key = NULL;
912
gboolean found = FALSE;
914
for (int i = 0 ; i < MAX_VALUE_CALL ; i++) {
916
if (calltype == MAX_VALUE_CALL
919
conf_key = gm_chw_get_conf_key (i);
920
calls_list = gm_conf_get_string_list (conf_key);
922
if (reversed) calls_list = g_slist_reverse (calls_list);
924
calls_list_iter = calls_list;
925
while (calls_list_iter && calls_list_iter->data) {
927
if ((calltype == MAX_VALUE_CALL && at_most != -1)
928
|| (calltype == i)) {
930
call_data = g_strsplit ((char *) calls_list_iter->data, "|", 0);
934
contact = gmcontact_new ();
937
contact->fullname = g_strdup (call_data [1]);
940
contact->url = g_strdup (call_data [2]);
942
found = (g_slist_find_custom (work_list,
943
(gconstpointer) contact->url,
944
(GCompareFunc) contact_compare_cb)
947
if ((unique && !found) || (!unique)) {
949
work_list = g_slist_append (work_list, (gpointer) contact);
952
gmcontact_delete (contact);
956
g_strfreev (call_data);
959
calls_list_iter = g_slist_next (calls_list_iter);
962
g_slist_foreach (calls_list, (GFunc) g_free, NULL);
963
g_slist_free (calls_list);
970
/* #INV: work_list contains the result, with unique items or not */
971
if (at_most == -1 || calltype == MAX_VALUE_CALL) // Return all values
973
else { // Return the last at_most results
975
if (reversed) work_list = g_slist_reverse (work_list);
976
work_list_iter = work_list;
977
while (work_list_iter && work_list_iter->data) {
979
if (g_slist_position (work_list, work_list_iter) >=
980
(int) g_slist_length (work_list) - at_most) {
983
g_slist_append (result,
984
(gpointer) work_list_iter->data);
987
g_free (work_list_iter->data);
989
work_list_iter = g_slist_next (work_list_iter);
992
if (reversed) result = g_slist_reverse (result);
994
g_slist_free (work_list);