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 Sat Mar 13 14:55:52 2004 for WvStreams by doxygen 1.3.6-20040222