dthelp: Change to ANSI function definitions
[oweals/cde.git] / cde / programs / dtmail / dtmail / Notifier.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*
24  *+SNOTICE
25  *
26  *      $XConsortium: Notifier.C /main/4 1996/04/21 19:42:47 drk $
27  *
28  *      RESTRICTED CONFIDENTIAL INFORMATION:
29  *      
30  *      The information in this document is subject to special
31  *      restrictions in a confidential disclosure agreement between
32  *      HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
33  *      document outside HP, IBM, Sun, USL, SCO, or Univel without
34  *      Sun's specific written approval.  This document and all copies
35  *      and derivative works thereof must be returned or destroyed at
36  *      Sun's request.
37  *
38  *      Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
39  *
40  *+ENOTICE
41  */
42
43 #include <assert.h>
44 #include <unistd.h>
45 #include <signal.h>
46 #include "Notifier.hh"
47
48 NotifyEvent::NotifyEvent(void)
49 {
50 }
51
52 NotifyEvent::~NotifyEvent(void)
53 {
54 }
55
56 void
57 NotifyEvent::eventTriggered(void)
58 {
59     assert(!"Pure virtual NotifyEvent::eventTriggered called");
60 }
61
62 Notifier::EventKey::EventKey(void * key)
63 : ObjectKey("Notifier::EventKey")
64 {
65     _key = key;
66 }
67
68 Notifier::EventKey::~EventKey(void)
69 {
70 }
71
72 Notifier::EventKey::operator==(ObjectKey & other)
73 {
74     EventKey * ok = (EventKey *)&other;
75
76     return(_key == ok->_key);
77 }
78
79 Notifier::EventKey::operator!=(ObjectKey & other)
80 {
81     EventKey * ok = (EventKey *)&other;
82
83     return(_key != ok->_key);
84 }
85
86 Notifier::EventKey::operator<(ObjectKey & other)
87 {
88     EventKey * ok = (EventKey *)&other;
89
90     return(_key < ok->_key);
91 }
92
93 Notifier::EventKey::operator>(ObjectKey & other)
94 {
95     EventKey * ok = (EventKey *)&other;
96
97     return(_key > ok->_key);
98 }
99
100 Notifier::EventKey::operator<=(ObjectKey & other)
101 {
102     EventKey * ok = (EventKey *)&other;
103
104     return(_key <= ok->_key);
105 }
106
107 Notifier::EventKey::operator>=(ObjectKey & other)
108 {
109     EventKey * ok = (EventKey *)&other;
110
111     return(_key >= ok->_key);
112 }
113
114 HashVal
115 Notifier::EventKey::hashValue(void)
116 {
117     unsigned long lkey = (unsigned long)_key;
118
119     return(((lkey >> 16) & 0xffff) ^ (lkey & 0xffff));
120 }
121
122 // These constants are used to keep the ends of the pipe straight.
123 //
124 static const int        READ = 0;
125 static const int        WRITE = 1;
126
127 Notifier::Notifier(XtAppContext context)
128 : _events(5), // Pending events that need to be sent.
129   _timer_events(8) // Events for timing.
130 {
131     // Create a pipe for sending events.
132     //
133     pipe(_event_fds);
134
135     // Register the input file descriptor for callback.
136     //
137     XtAppAddInput(context,
138                   _event_fds[READ],
139                   (XtPointer)(XtInputReadMask | XtInputExceptMask),
140                   eventProc,
141                   this);
142
143     _context = context;
144 }
145
146 int
147 Notifier::deleteTimerEvent(ObjectKey &, TimerEvent * event, void *)
148 {
149     XtRemoveTimeOut(event->id);
150     delete event->event;
151     delete event;
152     return(1);
153 }
154
155 Notifier::~Notifier(void)
156 {
157     XtRemoveInput(_id);
158
159     close(_event_fds[READ]);
160     close(_event_fds[WRITE]);
161
162     // We need to run through all of the pending events. They may
163     // be interesting to the recipient and should be delivered before
164     // we shutdown.
165     //
166     while (_events.length()) {
167         NotifyEvent * event = _events[0];
168         event->eventTriggered();
169         delete event;
170         _events.remove(0);
171     }
172
173     // Now we want to throw away all of the events we have laying about
174     // for timers and signals.
175     //
176     _timer_events.forEach(deleteTimerEvent, NULL);
177 }
178
179 void
180 Notifier::notify(NotifyEvent & event, DtMailBoolean fast_path)
181 {
182     // The fast path means use an immediate call. Really pretty
183     // simple. Fire the event and throw away the memory for it.
184     //
185     if (fast_path == DTM_TRUE) {
186         event.eventTriggered();
187         delete &event;
188     }
189
190     // A little more complex. We will add the event to the queue, and
191     // send a byte through the pipe. This will cause us to wake up
192     // later, after going through the queue.
193     //
194     _events.append(&event);
195
196     char bogus_buf = 0;
197     write(_event_fds[WRITE], &bogus_buf, 1);
198     return;
199 }
200
201 Notifier::IntervalId
202 Notifier::addInterval(int interval_ms,
203                       DtMailBoolean multi_shot,
204                       NotifyEvent & event)
205 {
206     TimerEvent * t_event = new TimerEvent;
207
208     t_event->interval = interval_ms;
209     t_event->multi_shot = multi_shot;
210     t_event->event = &event;
211
212     t_event->id = XtAppAddTimeOut(_context, interval_ms, timerProc, this);
213
214     EventKey * key = new EventKey((void *)t_event->id);
215     _timer_events.set(*key, t_event);
216
217     return(t_event);
218 }
219
220 void
221 Notifier::removeInterval(IntervalId id)
222 {
223     // The Id is really the TimerEvent structure pointer. We don't have
224     // a key for these objects so we will have to enumerate the entire
225     // list of timer events until we find the appropriate key.
226     //
227     TimerEvent * t_event = (TimerEvent *)id;
228
229     TimerSearch t_srch;
230     t_srch.srch_event = t_event;
231     t_srch.key = NULL;
232
233     _timer_events.forEach(searchTimer, &t_srch);
234
235     if (t_srch.key) {
236         _timer_events.remove(*t_srch.key);
237         delete t_event->event;
238         delete t_event;
239     }
240
241     return;
242 }
243
244 void
245 Notifier::eventProc(XtPointer client_data, int * fd, XtInputId *)
246 {
247     Notifier * self = (Notifier *)client_data;
248
249     // There was activity on the pipe. Read one byte, and fire one
250     // event. We don't want to fire more than that or we will run
251     // the risk of spending too much time in the callbacks.
252     //
253     char bogus_buf;
254     read(*fd, &bogus_buf, 1);
255
256     if (self->_events.length()) {
257         NotifyEvent * event = self->_events[0];
258         event->eventTriggered();
259         delete event;
260         self->_events.remove(0);
261     }
262
263     return;
264 }
265
266 void
267 Notifier::timerProc(XtPointer client_data, XtIntervalId *id)
268 {
269     Notifier * self = (Notifier *)client_data;
270     EventKey key((void *)*id);
271
272     TimerEvent * t_event = self->_timer_events.lookup(key);
273     if (!t_event) {
274         // Bogus event.
275         return;
276     }
277
278     t_event->event->eventTriggered();
279
280     // We remove the event from the list. We do this because the
281     // key will change because we will get a new interval id.
282     //
283     self->_timer_events.remove(key);
284
285     // If this is a multi-shot event we have to register it again.
286     //
287     if (t_event->multi_shot == DTM_TRUE) {
288         t_event->id = XtAppAddTimeOut(self->_context,
289                                       t_event->interval,
290                                       timerProc,
291                                       self);
292         EventKey * new_key = new EventKey((void *)t_event->id);
293         self->_timer_events.set(*new_key, t_event);
294     }
295     else {
296         delete t_event->event;
297         delete t_event;
298     }
299 }
300
301 int
302 Notifier::searchTimer(ObjectKey & key, TimerEvent * event, void * client_data)
303 {
304     TimerSearch * srch = (TimerSearch *)client_data;
305
306     if (event == srch->srch_event) {
307         srch->key = (EventKey *)&key;
308         return(0);
309     }
310
311     return(1);
312 }