WvStreams
wvqtstreamclone.cc
1/*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4 *
5 * Wraps another WvStream and attaches it to the normal Qt
6 * event loop. If you are using this object to manage all of your
7 * streams, then you do not need to have a normal WvStreams
8 * select()/callback() loop in your application at all.
9 *
10 * However, should you leave the Qt event loop and wish to continue
11 * using this WvStream, call qt_detach() first, then run a normal
12 * WvStreams event loop. If you do not do this, events may be
13 * lost!! You may resume the Qt event loop at any time after the
14 * WvStreams event loop has exited by calling qt_attach().
15 *
16 * Note: You do not need to add all of the WvStreams used in a Qt
17 * application to a single WvStreamList wrapped by a
18 * WvQtStreamClone so long as each top-level stream is wrapped
19 * by a WvQtStreamClone to take care of calling select()
20 * and callback() from within the Qt event loop.
21 */
22#include "wvqtstreamclone.moc"
23
24// number of slots used by the separate chaining hashtable
25// note: can store more than this number of elements in the table
26#define NUM_SLOTS 41 // must be prime
27
28WvQtStreamClone::WvQtStreamClone(IWvStream *_cloned, int msec_timeout) :
29 WvStreamClone(_cloned), msec_timeout(msec_timeout),
30 pending_callback(false), first_time(true), select_in_progress(false),
31 last_max_fd(-1),
32 notify_readable(NUM_SLOTS),
33 notify_writable(NUM_SLOTS),
34 notify_exception(NUM_SLOTS)
35{
36 _cloned->addRef();
37 setclone(_cloned);
38 notify_readable.setAutoDelete(true);
39 notify_writable.setAutoDelete(true);
40 notify_exception.setAutoDelete(true);
41 qt_attach();
42}
43
44
45WvQtStreamClone::~WvQtStreamClone()
46{
47}
48
49
50void WvQtStreamClone::pre_poll()
51{
52 // prepare lists of file descriptors
53 _build_selectinfo(si, msec_timeout,
54 false, false, false, true);
55
56 // set up a timer to wake us up to poll again (for alarms)
57 // we don't try to catch the timer signal; we use it only to force
58 // Qt's event loop to restart so our hook gets called again
59 select_timer.stop();
60 if (si.msec_timeout >= 0)
61 select_timer.start(si.msec_timeout, true /*singleshot*/);
62
63 // set up necessary QSocketNotifiers, unfortunately there is no
64 // better way to iterate over the set of file descriptors
65 for (int fd = 0; fd <= si.max_fd; ++fd)
66 {
67 if (FD_ISSET(fd, &si.read))
68 {
69 QSocketNotifier *n = notify_readable.find(fd);
70 if (! n)
71 {
72 n = new QSocketNotifier(fd, QSocketNotifier::Read);
73 notify_readable.insert(fd, n);
74 QObject::connect(n, SIGNAL(activated(int)),
75 this, SLOT(fd_readable(int)));
76 }
77 } else
78 notify_readable.remove(fd);
79
80 if (FD_ISSET(fd, &si.write))
81 {
82 QSocketNotifier *n = notify_writable.find(fd);
83 if (! n)
84 {
85 n = new QSocketNotifier(fd, QSocketNotifier::Write);
86 notify_writable.insert(fd, n);
87 QObject::connect(n, SIGNAL(activated(int)),
88 this, SLOT(fd_writable(int)));
89 }
90 } else
91 notify_writable.remove(fd);
92
93 if (FD_ISSET(fd, &si.except))
94 {
95 QSocketNotifier *n = notify_exception.find(fd);
96 if (! n)
97 {
98 n = new QSocketNotifier(fd, QSocketNotifier::Exception);
99 notify_exception.insert(fd, n);
100 QObject::connect(n, SIGNAL(activated(int)),
101 this, SLOT(fd_exception(int)));
102 }
103 } else
104 notify_exception.remove(fd);
105 }
106
107 // remove stale notifiers
108 for (int fd = si.max_fd + 1; fd <= last_max_fd; ++fd)
109 {
110 notify_readable.remove(fd);
111 notify_writable.remove(fd);
112 notify_exception.remove(fd);
113 }
114 last_max_fd = si.max_fd;
115
116 // clear select lists
117 FD_ZERO(&si.read);
118 FD_ZERO(&si.write);
119 FD_ZERO(&si.except);
120}
121
122
123void WvQtStreamClone::post_poll()
124{
125 // cleanup and invoke callbacks
126 bool sure = _process_selectinfo(si, true);
127 if (sure || pending_callback)
128 {
129 pending_callback = false;
130 callback();
131 if (globalstream) globalstream->callback();
132 }
133}
134
135
136void WvQtStreamClone::set_timeout(int msec_timeout)
137{
138 this->msec_timeout = msec_timeout;
139}
140
141
142void WvQtStreamClone::qt_begin_event_loop_hook()
143{
144 // select not done yet?
145 if (select_in_progress) return;
146
147 // finish the last polling stage
148 if (! first_time)
149 post_poll();
150 else
151 first_time = false;
152 // start the next polling stage
153 pre_poll();
154 select_in_progress = true;
155}
156
157
158void WvQtStreamClone::qt_detach()
159{
160 // finish the last polling stage
161 if (! first_time)
162 {
163 select_in_progress = false;
164 post_poll();
165 last_max_fd = -1;
166 first_time = true;
167 }
168 // remove any remaining Qt objects
169 select_timer.stop();
170 notify_readable.clear();
171 notify_writable.clear();
172 notify_exception.clear();
173 QObject::disconnect(qApp, SIGNAL(guiThreadAwake()),
174 this, SLOT(qt_begin_event_loop_hook()));
175 QObject::disconnect(& select_timer, SIGNAL(timeout()),
176 this, SLOT(select_timer_expired()));
177}
178
179
180void WvQtStreamClone::qt_attach()
181{
182 // hook into the Qt event loop before each iteration
183 QObject::connect(qApp, SIGNAL(guiThreadAwake()),
184 this, SLOT(qt_begin_event_loop_hook()));
185 QObject::connect(& select_timer, SIGNAL(timeout()),
186 this, SLOT(select_timer_expired()));
187}
188
189
190void WvQtStreamClone::select_timer_expired()
191{
192 select_in_progress = false;
193}
194
195
196void WvQtStreamClone::fd_readable(int fd)
197{
198 FD_SET(fd, &si.read);
199 pending_callback = true;
200 select_in_progress = false;
201}
202
203
204void WvQtStreamClone::fd_writable(int fd)
205{
206 FD_SET(fd, &si.write);
207 pending_callback = true;
208 select_in_progress = false;
209}
210
211
212void WvQtStreamClone::fd_exception(int fd)
213{
214 FD_SET(fd, &si.except);
215 pending_callback = true;
216 select_in_progress = false;
217}
218
219void WvQtStreamClone::execute()
220{
222}
223
224
226{
227 WvStreamClone::setclone(newclone);
228
229 if (newclone != NULL)
230 my_type = WvString("WvQtStreamClone:%s", newclone->wstype());
231 else
232 my_type = "WvQtStreamClone:(none)";
233}
virtual unsigned int addRef()=0
Indicate you are using this object.
WvQtStreamClone(IWvStream *_cloned=NULL, int msec_timeout=-1)
WvQtStreamClone takes ownership of the stream you give it just like WvStreamClone.
virtual void setclone(IWvStream *clone)
WvStreamClone takes ownership of the given stream; it will WVRELEASE() the stream when you setclone()...
WvStreamClone simply forwards all requests to the "cloned" stream.
virtual void setclone(IWvStream *clone)
WvStreamClone takes ownership of the given stream; it will WVRELEASE() the stream when you setclone()...
virtual void execute()
The callback() function calls execute(), and then calls the user- specified callback if one is define...
virtual void callback()
if the stream has a callback function defined, call it now.
Definition wvstream.cc:401
WvString is an implementation of a simple and efficient printable-string class.