Code

moving trunk for module inkscape
[inkscape.git] / src / extension / timer.cpp
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  */
15 #include "extension.h"
16 #include "timer.h"
18 namespace Inkscape {
19 namespace Extension {
21 #define TIMER_SCALE_VALUE  20
23 ExpirationTimer * ExpirationTimer::timer_list = NULL;
24 ExpirationTimer * ExpirationTimer::idle_start = NULL;
25 long ExpirationTimer::timeout = 240;
26 bool ExpirationTimer::timer_started = false;
28 /** \brief  Create a new expiration timer
29     \param  in_extension  Which extension this timer is related to
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;
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     }
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     }
58     return;
59 }
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;
79         if (idle_start == this)
80             idle_start = next;
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     }
94     return;
95 }
97 /** \brief  Touches the timer to extend the length before it expires
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)
109     Glib::TimeVal current;
110     current.assign_current_time();
112     long time_left = (long)(expiration.as_double() - current.as_double());
113     if (time_left < 0) time_left = 0;
114     time_left /= 2;
116     expiration = current + timeout + time_left;
117     return;
120 /** \brief  Check to see if the timer has expired
122     Checks the time against the current time.
123 */
124 bool
125 ExpirationTimer::expired (void) const
127     if (locked) return false;
129     Glib::TimeVal current;
130     current.assign_current_time();
131     return expiration < current;
134 // int idle_cnt = 0;
136 /** \brief  This function goes in the idle loop to find expired extensions
137     \return Whether the function should be requeued or not
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)
152     // std::cout << "Idle func pass: " << idle_cnt++ << "  timer list: " << timer_list << std::endl;
154     /* see if this is the last */
155     if (timer_list == NULL) {
156         timer_started = false;
157         return false;
158     }
160     /* evalutate current */
161     if (timer_list->expired()) {
162         timer_list->extension->set_state(Extension::STATE_UNLOADED);
163     }
165     /* see if this is the last */
166     if (timer_list == NULL) {
167         timer_started = false;
168         return false;
169     }
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     }
182     /* If nothing else, continue on */
183     timer_list = timer_list->next;
184     return true;
187 /** \brief  A timer function to set up the idle function
188     \return Always false -- to disable the timer
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)
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;
203 }; }; /* namespace Inkscape, Extension */
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 :