1 /*
2  * wmslib/src/but/timer.c, part of wmslib (Library functions)
3  * Copyright (C) 1994 William Shubert.
4  * See "configure.h.in" for more copyright information.
5  */
6 
7 #include <configure.h>
8 
9 #ifdef  X11_DISP
10 
11 #include <X11/Xlib.h>
12 #include <X11/Xutil.h>
13 #include <X11/cursorfont.h>
14 #include <X11/Xatom.h>
15 #include <X11/keysym.h>
16 #include <sys/time.h>
17 #include <wms.h>
18 #include <but/but.h>
19 #include <but/timer.h>
20 
21 
butTimer_create(void * packet,But * but,struct timeval delay,struct timeval period,bool winOnly,ButOut (* timerFunc)(ButTimer * timer))22 ButTimer  *butTimer_create(void *packet, But *but, struct timeval delay,
23 			   struct timeval period, bool winOnly,
24 			   ButOut (*timerFunc)(ButTimer *timer))  {
25   ButTimer *bt;
26   struct timeval  now;
27   struct timezone  tzone;
28 
29   bt = wms_malloc(sizeof(ButTimer));
30   MAGIC_SET(bt);
31   bt->packet = packet;
32   bt->eventNum = 0;
33   bt->period = period;
34   bt->state = butTimer_on;
35   gettimeofday(&now, &tzone);
36   bt->nextFiring = but_timerAdd(now, delay);
37   if (but)
38     bt->win = but->win;
39   else
40     bt->win = NULL;
41   bt->but = but;
42   bt->timerFunc = timerFunc;
43   bt->winOnly = winOnly;
44   bt->next = but_timerList;
45   bt->freqCounter = FALSE;
46   bt->ticksLeft = 0;
47   but_timerList = bt;
48   return(bt);
49 }
50 
51 
butTimer_fCreate(void * packet,But * but,struct timeval delay,int frequency,bool winOnly,ButOut (* timerFunc)(ButTimer * timer))52 ButTimer  *butTimer_fCreate(void *packet, But *but, struct timeval delay,
53 			    int frequency, bool winOnly,
54 			    ButOut (*timerFunc)(ButTimer *timer))  {
55   ButTimer  *bt;
56   struct timeval  now;
57   struct timezone  tzone;
58   int  i;
59 
60   bt = wms_malloc(sizeof(ButTimer));
61   MAGIC_SET(bt);
62   bt->packet = packet;
63   bt->eventNum = 0;
64   bt->period.tv_sec = 0;
65   bt->winOnly = winOnly;
66   if (frequency < BUTTIMER_MAXFREQ)  {
67     bt->period.tv_usec = 1000000 / frequency;
68     bt->ticksPerPeriod = 1;
69   } else  {
70     bt->period.tv_usec = 1000000 / BUTTIMER_STDFREQ;
71     bt->ticksPerPeriod = (frequency + BUTTIMER_STDFREQ/2) /
72       BUTTIMER_STDFREQ;
73   }
74   bt->state = butTimer_on;
75   gettimeofday(&now, &tzone);
76   bt->nextFiring = but_timerAdd(now, delay);
77   if (but)
78     bt->win = but->win;
79   else
80     bt->win = NULL;
81   bt->but = but;
82   bt->timerFunc = timerFunc;
83   bt->next = but_timerList;
84   bt->freqCounter = TRUE;
85   for (i = 0;  i < BUTTIMER_HIST;  ++i)
86     bt->lastRes[i] = 1;
87   bt->resnum = 0;
88   bt->ticksLeft = 0;
89   but_timerList = bt;
90   return(bt);
91 }
92 
93 
butTimer_destroy(ButTimer * timer)94 void  butTimer_destroy(ButTimer *timer)  {
95   assert(MAGIC(timer));
96   timer->state = butTimer_dead;
97 }
98 
99 
butTimer_reset(ButTimer * timer)100 void  butTimer_reset(ButTimer *timer)  {
101   struct timeval  now;
102   struct timezone  tzone;
103 
104   assert(MAGIC(timer));
105   timer->eventNum = 0;
106   gettimeofday(&now, &tzone);
107   timer->nextFiring = but_timerAdd(now, timer->period);
108 }
109 
110 
but_timerAdd(struct timeval t1,struct timeval t2)111 struct timeval  but_timerAdd(struct timeval t1, struct timeval t2)  {
112   struct timeval  r;
113 
114   r.tv_sec = t1.tv_sec + t2.tv_sec;
115   if ((r.tv_usec = t1.tv_usec + t2.tv_usec) > 1000000)  {
116     r.tv_usec -= 1000000;
117     ++r.tv_sec;
118   }
119   return(r);
120 }
121 
122 
but_timerSub(struct timeval t1,struct timeval t2)123 struct timeval  but_timerSub(struct timeval t1, struct timeval t2)  {
124   struct timeval r;
125 
126   r.tv_sec = t1.tv_sec - t2.tv_sec;
127   if ((r.tv_usec = t1.tv_usec - t2.tv_usec) < 0)  {
128     r.tv_usec += 1000000;
129     --r.tv_sec;
130   }
131   if (r.tv_sec < 0)
132     r.tv_sec += 60*60*24;
133   return(r);
134 }
135 
136 
but_timerDiv(struct timeval t1,struct timeval t2,struct timeval * remainder)137 int  but_timerDiv(struct timeval t1, struct timeval t2,
138 		     struct timeval *remainder)  {
139   int  result;
140   long it1, it2, irem;
141 
142   it1 = (t1.tv_sec*1000000L) + t1.tv_usec;
143   it2 = (t2.tv_sec*1000000L) + t2.tv_usec;
144   result = it1 / it2;
145   if (remainder != NULL)  {
146     irem = it1 % it2;
147     remainder->tv_usec = irem % 1000000;
148     remainder->tv_sec = irem / 1000000;
149   }
150   return(result);
151 }
152 
153 
butEnv_checkTimers(ButEnv * env,struct timeval * timeout)154 int  butEnv_checkTimers(ButEnv *env, struct timeval *timeout)  {
155   struct timeval  current_time, next_timer, timerem;
156   struct timezone  tzone;
157   bool  take_timer, timer_set = FALSE;
158   ButTimer  *bt, *bt2;
159   int  ticks, i, orig_ticks;
160   int  result = 0;
161 
162   /* First, kill off all the dead timers. */
163   for (bt = but_timerList;  bt != NULL;)  {
164     if (bt->state == butTimer_dead)  {
165       if (bt == but_timerList)
166 	but_timerList = bt->next;
167       else  {
168 	for (bt2 = but_timerList;  bt2->next != bt;  bt2 = bt2->next);
169 	bt2->next = bt->next;
170       }
171       bt2 = bt->next;
172       MAGIC_UNSET(bt);
173       wms_free(bt);
174       bt = bt2;
175     } else  {
176       bt = bt->next;
177     }
178   }
179   gettimeofday(&current_time, &tzone);
180   for (bt = but_timerList;  bt != NULL;  bt = bt->next)  {
181     if (bt->state == butTimer_on)  {
182       if (timercmp(&bt->nextFiring, &current_time, <))  {
183 	take_timer = TRUE;
184 	ticks = but_timerDiv(but_timerSub(current_time, bt->nextFiring),
185 			     bt->period, &timerem) + 1 + bt->ticksLeft;
186 	take_timer = TRUE;
187 	orig_ticks = ticks;
188 	if (bt->freqCounter)  {
189 	  for (i = 0;  i < BUTTIMER_HIST;  ++i)  {
190 	    if (bt->lastRes[i] > ticks)  {
191 	      take_timer = FALSE;
192 	    }
193 	  }
194 	  if (!bt->ticksLeft)  {
195 	    bt->lastRes[bt->resnum] = ticks;
196 	    bt->resnum = (bt->resnum + 1) & (BUTTIMER_HIST - 1);
197 	  }
198 	  ticks *= bt->ticksPerPeriod;
199 	}
200 	bt->nextFiring = but_timerSub(but_timerAdd(current_time, bt->period),
201 				       timerem);
202 	if (take_timer)  {
203 	  bt->eventNum += ticks;
204 	  result |= bt->timerFunc(bt);
205 	  XSync(env->dpy, False);
206 	  bt->ticksLeft = 0;
207 	} else
208 	  bt->ticksLeft += orig_ticks;
209       }
210       if (!timer_set || timercmp(&bt->nextFiring, &next_timer, <))  {
211 	timer_set = TRUE;
212 	next_timer = bt->nextFiring;
213       }
214     }
215   }
216   if (timer_set)
217     *timeout = but_timerSub(next_timer, current_time);
218   else  {
219     timeout->tv_usec = 0;
220     timeout->tv_sec = 365*24*60*60;  /* 1 spurious interrupt per year. */
221   }
222   return(result);
223 }
224 
225 #endif  /* X11_DISP */
226