aboutsummaryrefslogtreecommitdiffstats
path: root/timer_group.c
blob: 0a72e84567e1250b5175207ebcf459971f7b3299 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/* $Id$
 * $URL$
 *
 * generic grouping of widget timers that have been set to the same
 * update interval, thus allowing synchronized updates
 *
 * Copyright (C) 2010 Martin Zuther <code@mzuther.de>
 *
 * Based on "timer.c" which is
 * Copyright (C) 2003, 2004 Michael Reinelt <michael@reinelt.co.at>
 * Copyright (C) 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

/* 
 * exported functions:
 *
 * int timer_add_group(void (*callback) (void *data), const int interval)
 *   make sure that generic timer exists for given update interval
 *
 * int timer_remove_group(void (*callback) (void *data), const int interval)
 *   remove generic timer for given update interval
 *
 * void timer_process_group(void *data)
 *   process all widgets of a given update interval (*data)
 *
 * void timer_exit_group(void)
 *   release all timers and free reserved memory
 *
 * int timer_add_widget(void (*callback) (void *data), void *data, const int interval, const int one_shot)
 *  add widget to group of the given update interval (creates a new group if
 *  necessary)
 *
 * int timer_remove_widget(void (*callback) (void *data), void *data)
 *  remove widget from group of the given update interval (als removes emtpy
 *  groups)
 *
 */


#include "config.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "debug.h"
#include "cfg.h"
#include "timer.h"
#include "timer_group.h"

#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif


/* contains the actual timers, one for each update interval */
typedef struct TIMER_GROUP {
    void (*callback) (void *data);
    int *interval;
    int active;
} TIMER_GROUP;

TIMER_GROUP *GroupTimers = NULL;
int nGroupTimers = 0;

/* contains callback and data for each widget */
typedef struct SINGLE_TIMER {
    void (*callback) (void *data);
    void *data;
    int interval;
    int one_shot;
    int active;
} SINGLE_TIMER;

SINGLE_TIMER *SingleTimers = NULL;
int nSingleTimers = 0;

int timer_add_group(void (*callback) (void *data), const int interval)
{
    int group;

    /* check whether timer exists for given update interval */
    for (group = 0; group < nGroupTimers; group++) {
	if (*GroupTimers[group].interval == interval)
	    return 0;
    }

    /* otherwise look for a free group */
    for (group = 0; group < nGroupTimers; group++) {
	if (GroupTimers[group].active == 0)
	    break;
    }

    /* none found, allocate a new group */
    if (group >= nGroupTimers) {
	nGroupTimers++;
	GroupTimers = realloc(GroupTimers, nGroupTimers * sizeof(*GroupTimers));

	/* also allocate memory for callback data */
	GroupTimers[group].interval = malloc(sizeof(int));
    }

    /* initialize group */
    info("Creating new timer group (%d ms)", interval);

    GroupTimers[group].callback = callback;
    *GroupTimers[group].interval = interval;
    GroupTimers[group].active = 1;

    /* finally, request a generic timer */
    return timer_add(GroupTimers[group].callback, GroupTimers[group].interval, interval, 0);
}

int timer_remove_group(void (*callback) (void *data), const int interval)
{
    int group;

    /* look for group with given callback function and update interval */
    for (group = 0; group < nGroupTimers; group++) {
	if (GroupTimers[group].callback == callback && *GroupTimers[group].interval == interval
	    && GroupTimers[group].active) {
	    /* inactivate group */
	    GroupTimers[group].active = 0;

	    /* remove generic timer */
	    return timer_remove(GroupTimers[group].callback, GroupTimers[group].interval);
	}
    }
    return -1;
}

void timer_process_group(void *data)
{
    int slot;
    int *interval = (int *) data;

    /* sanity check */
    if (nSingleTimers == 0) {
	error("huh? not even a single widget timer to process? dazed and confused...");
	return;
    }

    /* process every (active) widget associated with given update interval */
    for (slot = 0; slot < nSingleTimers; slot++) {
	if (SingleTimers[slot].active == 0)
	    continue;

	if (SingleTimers[slot].interval == *interval) {
	    /* call one-shot timers only once */
	    if (SingleTimers[slot].one_shot)
		SingleTimers[slot].active = 0;
	    /* execute callback function */
	    if (SingleTimers[slot].callback != NULL)
		SingleTimers[slot].callback(SingleTimers[slot].data);
	}
    }
}

int timer_add_widget(void (*callback) (void *data), void *data, const int interval, const int one_shot)
{
    int slot;

    /* make sure that group for update interval exists or can be created */
    if (timer_add_group(timer_process_group, interval) != 0)
	return -1;

    /* find a free slot for callback data */
    for (slot = 0; slot < nSingleTimers; slot++) {
	if (SingleTimers[slot].active == 0)
	    break;
    }

    /* none found, allocate a new slot */
    if (slot >= nSingleTimers) {
	nSingleTimers++;
	SingleTimers = realloc(SingleTimers, nSingleTimers * sizeof(*SingleTimers));
    }

    /* fill slot with callback data */
    SingleTimers[slot].callback = callback;
    SingleTimers[slot].data = data;
    SingleTimers[slot].interval = interval;
    SingleTimers[slot].one_shot = one_shot;
    SingleTimers[slot].active = 1;

    return 0;
}

int timer_remove_widget(void (*callback) (void *data), void *data)
{
    int slot, interval;

    interval = 0;
    /* look for (active) widget with given callback function and data */
    for (slot = 0; slot < nSingleTimers; slot++) {
	if (SingleTimers[slot].callback == callback && SingleTimers[slot].data == data && SingleTimers[slot].active) {
	    /* deactivate widget */
	    SingleTimers[slot].active = 0;
	    interval = SingleTimers[slot].interval;
	    break;
	}
    }

    /* signal an error if no matching widget was found */
    if (interval == 0)
	return -1;

    /* look for other widgets with given update interval */
    for (slot = 0; slot < nSingleTimers; slot++) {
	if (SingleTimers[slot].active == 0)
	    continue;
	/* at least one other widget with given update interval exists */
	if (SingleTimers[slot].interval == interval)
	    return 0;
    }

    /* remove group with given update interval */
    return timer_remove_group(timer_process_group, interval);
}

void timer_exit_group(void)
{
    int group;

    /* remove generic timer and free memory for callback data */
    for (group = 0; group < nGroupTimers; group++) {
	timer_remove(GroupTimers[group].callback, GroupTimers[group].interval);
	free(GroupTimers[group].interval);
    }

    /* free memory for groups */
    nGroupTimers = 0;

    if (GroupTimers != NULL) {
	free(GroupTimers);;
	GroupTimers = NULL;
    }

    /* free memory for widget callback data */
    nSingleTimers = 0;

    if (SingleTimers != NULL) {
	free(SingleTimers);;
	SingleTimers = NULL;
    }
}