Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

wvqtstreamclone.cc

Go to the documentation of this file.
00001 /* 00002 * Worldvisions Weaver Software: 00003 * Copyright (C) 1997-2002 Net Integration Technologies, Inc. 00004 * 00005 * Wraps another WvStream and attaches it to the normal Qt 00006 * event loop. If you are using this object to manage all of your 00007 * streams, then you do not need to have a normal WvStreams 00008 * select()/callback() loop in your application at all. 00009 * 00010 * However, should you leave the Qt event loop and wish to continue 00011 * using this WvStream, call qt_detach() first, then run a normal 00012 * WvStreams event loop. If you do not do this, events may be 00013 * lost!! You may resume the Qt event loop at any time after the 00014 * WvStreams event loop has exited by calling qt_attach(). 00015 * 00016 * Note: You do not need to add all of the WvStreams used in a Qt 00017 * application to a single WvStreamList wrapped by a 00018 * WvQtStreamClone so long as each top-level stream is wrapped 00019 * by a WvQtStreamClone to take care of calling select() 00020 * and callback() from within the Qt event loop. 00021 */ 00022 #include "wvqtstreamclone.moc" 00023 00024 // number of slots used by the separate chaining hashtable 00025 // note: can store more than this number of elements in the table 00026 #define NUM_SLOTS 41 // must be prime 00027 00028 WvQtStreamClone::WvQtStreamClone(WvStream* _cloned, int msec_timeout) : 00029 WvStreamClone(_cloned), msec_timeout(msec_timeout), 00030 pending_callback(false), first_time(true), select_in_progress(false), 00031 last_max_fd(-1), 00032 notify_readable(NUM_SLOTS), 00033 notify_writable(NUM_SLOTS), 00034 notify_exception(NUM_SLOTS) 00035 { 00036 notify_readable.setAutoDelete(true); 00037 notify_writable.setAutoDelete(true); 00038 notify_exception.setAutoDelete(true); 00039 qt_attach(); 00040 } 00041 00042 00043 WvQtStreamClone::~WvQtStreamClone() 00044 { 00045 } 00046 00047 00048 void WvQtStreamClone::pre_poll() 00049 { 00050 // prepare lists of file descriptors 00051 bool sure = _build_selectinfo(si, msec_timeout, 00052 false, false, false, true); 00053 if (sure) 00054 { 00055 pending_callback = true; 00056 si.msec_timeout = 0; 00057 } 00058 00059 // set up a timer to wake us up to poll again (for alarms) 00060 // we don't try to catch the timer signal; we use it only to force 00061 // Qt's event loop to restart so our hook gets called again 00062 select_timer.stop(); 00063 if (si.msec_timeout >= 0) 00064 select_timer.start(si.msec_timeout, true /*singleshot*/); 00065 00066 // set up necessary QSocketNotifiers, unfortunately there is no 00067 // better way to iterate over the set of file descriptors 00068 for (int fd = 0; fd <= si.max_fd; ++fd) 00069 { 00070 if (FD_ISSET(fd, &si.read)) 00071 { 00072 QSocketNotifier *n = notify_readable.find(fd); 00073 if (! n) 00074 { 00075 n = new QSocketNotifier(fd, QSocketNotifier::Read); 00076 notify_readable.insert(fd, n); 00077 QObject::connect(n, SIGNAL(activated(int)), 00078 this, SLOT(fd_readable(int))); 00079 } 00080 } else 00081 notify_readable.remove(fd); 00082 00083 if (FD_ISSET(fd, &si.write)) 00084 { 00085 QSocketNotifier *n = notify_writable.find(fd); 00086 if (! n) 00087 { 00088 n = new QSocketNotifier(fd, QSocketNotifier::Write); 00089 notify_writable.insert(fd, n); 00090 QObject::connect(n, SIGNAL(activated(int)), 00091 this, SLOT(fd_writable(int))); 00092 } 00093 } else 00094 notify_writable.remove(fd); 00095 00096 if (FD_ISSET(fd, &si.except)) 00097 { 00098 QSocketNotifier *n = notify_exception.find(fd); 00099 if (! n) 00100 { 00101 n = new QSocketNotifier(fd, QSocketNotifier::Exception); 00102 notify_exception.insert(fd, n); 00103 QObject::connect(n, SIGNAL(activated(int)), 00104 this, SLOT(fd_exception(int))); 00105 } 00106 } else 00107 notify_exception.remove(fd); 00108 } 00109 00110 // remove stale notifiers 00111 for (int fd = si.max_fd + 1; fd <= last_max_fd; ++fd) 00112 { 00113 notify_readable.remove(fd); 00114 notify_writable.remove(fd); 00115 notify_exception.remove(fd); 00116 } 00117 last_max_fd = si.max_fd; 00118 00119 // clear select lists 00120 FD_ZERO(&si.read); 00121 FD_ZERO(&si.write); 00122 FD_ZERO(&si.except); 00123 } 00124 00125 00126 void WvQtStreamClone::post_poll() 00127 { 00128 // cleanup and invoke callbacks 00129 bool sure = _process_selectinfo(si, true); 00130 if (sure || pending_callback) 00131 { 00132 pending_callback = false; 00133 callback(); 00134 if (globalstream) globalstream->callback(); 00135 } 00136 } 00137 00138 00139 void WvQtStreamClone::set_timeout(int msec_timeout) 00140 { 00141 this->msec_timeout = msec_timeout; 00142 } 00143 00144 00145 void WvQtStreamClone::qt_begin_event_loop_hook() 00146 { 00147 // select not done yet? 00148 if (select_in_progress) return; 00149 00150 // finish the last polling stage 00151 if (! first_time) 00152 post_poll(); 00153 else 00154 first_time = false; 00155 // start the next polling stage 00156 pre_poll(); 00157 select_in_progress = true; 00158 } 00159 00160 00161 void WvQtStreamClone::qt_detach() 00162 { 00163 // finish the last polling stage 00164 if (! first_time) 00165 { 00166 select_in_progress = false; 00167 post_poll(); 00168 last_max_fd = -1; 00169 first_time = true; 00170 } 00171 // remove any remaining Qt objects 00172 select_timer.stop(); 00173 notify_readable.clear(); 00174 notify_writable.clear(); 00175 notify_exception.clear(); 00176 QObject::disconnect(qApp, SIGNAL(guiThreadAwake()), 00177 this, SLOT(qt_begin_event_loop_hook())); 00178 QObject::disconnect(& select_timer, SIGNAL(timeout()), 00179 this, SLOT(select_timer_expired())); 00180 } 00181 00182 00183 void WvQtStreamClone::qt_attach() 00184 { 00185 // hook into the Qt event loop before each iteration 00186 QObject::connect(qApp, SIGNAL(guiThreadAwake()), 00187 this, SLOT(qt_begin_event_loop_hook())); 00188 QObject::connect(& select_timer, SIGNAL(timeout()), 00189 this, SLOT(select_timer_expired())); 00190 } 00191 00192 00193 void WvQtStreamClone::select_timer_expired() 00194 { 00195 select_in_progress = false; 00196 } 00197 00198 00199 void WvQtStreamClone::fd_readable(int fd) 00200 { 00201 FD_SET(fd, &si.read); 00202 pending_callback = true; 00203 select_in_progress = false; 00204 } 00205 00206 00207 void WvQtStreamClone::fd_writable(int fd) 00208 { 00209 FD_SET(fd, &si.write); 00210 pending_callback = true; 00211 select_in_progress = false; 00212 } 00213 00214 00215 void WvQtStreamClone::fd_exception(int fd) 00216 { 00217 FD_SET(fd, &si.except); 00218 pending_callback = true; 00219 select_in_progress = false; 00220 } 00221 00222 void WvQtStreamClone::execute() 00223 { 00224 WvStreamClone::execute(); 00225 }

Generated on Tue Oct 5 01:09:20 2004 for WvStreams by doxygen 1.3.7