2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
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.
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().
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.
22 #include "wvqtstreamclone.moc"
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
28 WvQtStreamClone::WvQtStreamClone(IWvStream
*_cloned
, int msec_timeout
) :
29 WvStreamClone(_cloned
), msec_timeout(msec_timeout
),
30 pending_callback(false), first_time(true), select_in_progress(false),
32 notify_readable(NUM_SLOTS
),
33 notify_writable(NUM_SLOTS
),
34 notify_exception(NUM_SLOTS
)
38 notify_readable
.setAutoDelete(true);
39 notify_writable
.setAutoDelete(true);
40 notify_exception
.setAutoDelete(true);
45 WvQtStreamClone::~WvQtStreamClone()
50 void WvQtStreamClone::pre_poll()
52 // prepare lists of file descriptors
53 _build_selectinfo(si
, msec_timeout
,
54 false, false, false, true);
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
60 if (si
.msec_timeout
>= 0)
61 select_timer
.start(si
.msec_timeout
, true /*singleshot*/);
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
)
67 if (FD_ISSET(fd
, &si
.read
))
69 QSocketNotifier
*n
= notify_readable
.find(fd
);
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)));
78 notify_readable
.remove(fd
);
80 if (FD_ISSET(fd
, &si
.write
))
82 QSocketNotifier
*n
= notify_writable
.find(fd
);
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)));
91 notify_writable
.remove(fd
);
93 if (FD_ISSET(fd
, &si
.except
))
95 QSocketNotifier
*n
= notify_exception
.find(fd
);
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)));
104 notify_exception
.remove(fd
);
107 // remove stale notifiers
108 for (int fd
= si
.max_fd
+ 1; fd
<= last_max_fd
; ++fd
)
110 notify_readable
.remove(fd
);
111 notify_writable
.remove(fd
);
112 notify_exception
.remove(fd
);
114 last_max_fd
= si
.max_fd
;
116 // clear select lists
123 void WvQtStreamClone::post_poll()
125 // cleanup and invoke callbacks
126 bool sure
= _process_selectinfo(si
, true);
127 if (sure
|| pending_callback
)
129 pending_callback
= false;
131 if (globalstream
) globalstream
->callback();
136 void WvQtStreamClone::set_timeout(int msec_timeout
)
138 this->msec_timeout
= msec_timeout
;
142 void WvQtStreamClone::qt_begin_event_loop_hook()
144 // select not done yet?
145 if (select_in_progress
) return;
147 // finish the last polling stage
152 // start the next polling stage
154 select_in_progress
= true;
158 void WvQtStreamClone::qt_detach()
160 // finish the last polling stage
163 select_in_progress
= false;
168 // remove any remaining Qt objects
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()));
180 void WvQtStreamClone::qt_attach()
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()));
190 void WvQtStreamClone::select_timer_expired()
192 select_in_progress
= false;
196 void WvQtStreamClone::fd_readable(int fd
)
198 FD_SET(fd
, &si
.read
);
199 pending_callback
= true;
200 select_in_progress
= false;
204 void WvQtStreamClone::fd_writable(int fd
)
206 FD_SET(fd
, &si
.write
);
207 pending_callback
= true;
208 select_in_progress
= false;
212 void WvQtStreamClone::fd_exception(int fd
)
214 FD_SET(fd
, &si
.except
);
215 pending_callback
= true;
216 select_in_progress
= false;
219 void WvQtStreamClone::execute()
221 WvStreamClone::execute();
225 void WvQtStreamClone::setclone(IWvStream
*newclone
)
227 WvStreamClone::setclone(newclone
);
229 if (newclone
!= NULL
)
230 my_type
= WvString("WvQtStreamClone:%s", newclone
->wstype());
232 my_type
= "WvQtStreamClone:(none)";