~mc.../inkscape/inkscape

« back to all changes in this revision

Viewing changes to src/extension/timer.cpp

  • Committer: mental
  • Date: 2006-01-16 02:36:01 UTC
  • Revision ID: mental@users.sourceforge.net-20060116023601-wkr0h7edl5veyudq
moving trunk for module inkscape

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Here is where the extensions can get timed on when they load and
 
3
 * unload.  All of the timing is done in here.
 
4
 *
 
5
 * Authors:
 
6
 *   Ted Gould <ted@gould.cx>
 
7
 *
 
8
 * Copyright (C) 2004 Authors
 
9
 *
 
10
 * Released under GNU GPL, read the file 'COPYING' for more information
 
11
 */
 
12
 
 
13
 
 
14
 
 
15
#include "extension.h"
 
16
#include "timer.h"
 
17
 
 
18
namespace Inkscape {
 
19
namespace Extension {
 
20
 
 
21
#define TIMER_SCALE_VALUE  20
 
22
 
 
23
ExpirationTimer * ExpirationTimer::timer_list = NULL;
 
24
ExpirationTimer * ExpirationTimer::idle_start = NULL;
 
25
long ExpirationTimer::timeout = 240;
 
26
bool ExpirationTimer::timer_started = false;
 
27
 
 
28
/** \brief  Create a new expiration timer
 
29
    \param  in_extension  Which extension this timer is related to
 
30
 
 
31
    This function creates the timer, and sets the time to the current
 
32
    time, plus what ever the current timeout is.  Also, if this is
 
33
    the first timer extension, the timer is kicked off.  This function
 
34
    also sets up teh circularly linked list of all the timers.
 
35
*/
 
36
ExpirationTimer::ExpirationTimer (Extension * in_extension)
 
37
{
 
38
    locked = false;
 
39
    extension = in_extension;
 
40
 
 
41
    /* Fix Me! */
 
42
    if (timer_list == NULL) {
 
43
        next = this;
 
44
        timer_list = this;
 
45
    } else {
 
46
        next = timer_list->next;
 
47
        timer_list->next = this;
 
48
    }
 
49
 
 
50
    expiration.assign_current_time();
 
51
    expiration += timeout;
 
52
    
 
53
    if (!timer_started) {
 
54
        Glib::signal_timeout().connect(sigc::ptr_fun(&timer_func), timeout * 1000 / TIMER_SCALE_VALUE);
 
55
        timer_started = true;
 
56
    }
 
57
 
 
58
    return;
 
59
}
 
60
 
 
61
/** \brief  Deletes a \c ExpirationTimer
 
62
    
 
63
    The most complex thing that this function does is remove the timer
 
64
    from the circularly linked list.  If this is the only entry in the
 
65
    list that is easy, otherwise all the entries must be found, and this
 
66
    one removed from the list.
 
67
*/
 
68
ExpirationTimer::~ExpirationTimer(void)
 
69
{
 
70
    if (this != next) {
 
71
        /* This will remove this entry from the circularly linked
 
72
           list. */
 
73
        ExpirationTimer * prev;
 
74
        for (prev = timer_list;
 
75
                prev->next != this;
 
76
                prev = prev->next);
 
77
        prev->next = next;
 
78
 
 
79
        if (idle_start == this)
 
80
            idle_start = next;
 
81
 
 
82
        /* This may occur more than you think, just because the guy
 
83
           doing most of the deletions is the idle function, who tracks
 
84
           where it is looking using the \c timer_list variable. */
 
85
        if (timer_list == this)
 
86
            timer_list = next;
 
87
    } else {
 
88
        /* If we're the only entry in the list, the list needs to go
 
89
           to NULL */
 
90
        timer_list = NULL;
 
91
        idle_start = NULL;
 
92
    }
 
93
 
 
94
    return;
 
95
}
 
96
 
 
97
/** \brief  Touches the timer to extend the length before it expires
 
98
 
 
99
    Basically it adds more time to the timer.  One thing that is kinda
 
100
    tricky is that it adds half the time remaining back into the timer.
 
101
    This allows for some extensions that are used regularly to having
 
102
    extended expiration times.  So, in the end, they stay loaded longer.
 
103
    Extensions that are only used once will expire at a standard rate
 
104
    set by \c timeout.
 
105
*/
 
106
void
 
107
ExpirationTimer::touch (void)
 
108
{
 
109
    Glib::TimeVal current;
 
110
    current.assign_current_time();
 
111
 
 
112
    long time_left = (long)(expiration.as_double() - current.as_double());
 
113
    if (time_left < 0) time_left = 0;
 
114
    time_left /= 2;
 
115
 
 
116
    expiration = current + timeout + time_left;
 
117
    return;
 
118
}
 
119
 
 
120
/** \brief  Check to see if the timer has expired
 
121
 
 
122
    Checks the time against the current time.
 
123
*/
 
124
bool
 
125
ExpirationTimer::expired (void) const
 
126
{
 
127
    if (locked) return false;
 
128
 
 
129
    Glib::TimeVal current;
 
130
    current.assign_current_time();
 
131
    return expiration < current;
 
132
}
 
133
 
 
134
// int idle_cnt = 0;
 
135
 
 
136
/** \brief  This function goes in the idle loop to find expired extensions
 
137
    \return Whether the function should be requeued or not
 
138
 
 
139
    This function first insures that there is a timer list, and then checks
 
140
    to see if the one on the top of the list has expired.  If it has
 
141
    expired it unloads the module.  By unloading the module, the timer
 
142
    gets deleted (happens in the unload function).  If the list is
 
143
    no empty, the function returns that it should be dequeued and sets
 
144
    the \c timer_started variable so that the timer will be reissued when
 
145
    a timer is added.  If there is entries left, but the next one is
 
146
    where this function started, then the timer is set up.  The timer
 
147
    will then re-add the idle loop function when it runs.
 
148
*/ 
 
149
bool
 
150
ExpirationTimer::idle_func (void)
 
151
{
 
152
    // std::cout << "Idle func pass: " << idle_cnt++ << "  timer list: " << timer_list << std::endl;
 
153
 
 
154
    /* see if this is the last */
 
155
    if (timer_list == NULL) {
 
156
        timer_started = false;
 
157
        return false;
 
158
    }
 
159
 
 
160
    /* evalutate current */
 
161
    if (timer_list->expired()) {
 
162
        timer_list->extension->set_state(Extension::STATE_UNLOADED);
 
163
    }
 
164
 
 
165
    /* see if this is the last */
 
166
    if (timer_list == NULL) {
 
167
        timer_started = false;
 
168
        return false;
 
169
    }
 
170
 
 
171
    if (timer_list->next == idle_start) {
 
172
        /* if so, set up the timer and return FALSE */
 
173
        /* Note: This may cause one to be missed on the evaluation if
 
174
                 the one before it expires and it is last in the list.
 
175
                 While this could be taken care of, it isn't worth the
 
176
                 complexity for this lazy removal that we're doing.  It
 
177
                 should get picked up next time */
 
178
        Glib::signal_timeout().connect(sigc::ptr_fun(&timer_func), timeout * 1000 / TIMER_SCALE_VALUE);
 
179
        return false;
 
180
    }
 
181
 
 
182
    /* If nothing else, continue on */
 
183
    timer_list = timer_list->next;
 
184
    return true;
 
185
}
 
186
 
 
187
/** \brief  A timer function to set up the idle function
 
188
    \return Always false -- to disable the timer
 
189
 
 
190
    This function sets up the idle loop when it runs.  The idle loop is
 
191
    the one that unloads all the extensions.
 
192
*/
 
193
bool
 
194
ExpirationTimer::timer_func (void)
 
195
{
 
196
    // std::cout << "Timer func" << std::endl;
 
197
    idle_start = timer_list;
 
198
    // idle_cnt = 0;
 
199
    Glib::signal_idle().connect(sigc::ptr_fun(&idle_func));
 
200
    return false;
 
201
}
 
202
 
 
203
}; }; /* namespace Inkscape, Extension */
 
204
 
 
205
/*
 
206
  Local Variables:
 
207
  mode:c++
 
208
  c-file-style:"stroustrup"
 
209
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
210
  indent-tabs-mode:nil
 
211
  fill-column:99
 
212
  End:
 
213
*/
 
214
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :