-1.4
+1.4 Fri Jan 16 23:03:22 CET 2004
- fix stupid segfault on esc-c.
- small font tunings.
+ - much better io manager, less bugs, higher speed.
1.3 2003-12-26
- fix a bug in font height selection
-# $Id: Makefile.in,v 1.6 2003-12-18 00:56:51 pcg Exp $
+# $Id: Makefile.in,v 1.7 2004-01-16 22:11:09 pcg Exp $
@MCOMMON@
LINT = lint -DNARROWPROTO=1 $(XINC) -chapbxz
thisdir = src
MKDIR = @top_srcdir@/autoconf/mkinstalldirs
-SUPLIB = -lsupc++
+SUPLIB = -fno-exceptions -lsupc++ # TODO: only for g++
# for developers: the following debug options may be used
# -DDEBUG_CMD -DDEBUG_MAIN -DDEBUG_MENU -DDEBUG_MENUARROWS
/*--------------------------------*-C-*---------------------------------*
* File: command.c
*----------------------------------------------------------------------*
- * $Id: command.C,v 1.27 2003-12-30 01:35:58 pcg Exp $
+ * $Id: command.C,v 1.28 2004-01-16 22:11:09 pcg Exp $
*
* All portions of code are copyright by their respective author/s.
* Copyright (c) 1992 John Bovey, University of Kent at Canterbury <jdb@ukc.ac.uk>
void
rxvt_term::blink_cb (time_watcher &w)
{
- w.at += BLINK_INTERVAL;
hidden_cursor = !hidden_cursor;
want_refresh = 1;
+
+ w.start (w.at + BLINK_INTERVAL);
}
#endif
void
rxvt_term::pointer_blank ()
{
- pointer_ev.stop ();
-
if (!(Options & Opt_pointerBlank))
return;
#include "../config.h"
#include <cstdio>
+#include <cstdlib>
+#include <cerrno>
#include <sys/select.h>
#include <sys/time.h>
#include "iom.h"
+// TSTAMP_MAX must still fit into a positive struct timeval
+#define TSTAMP_MAX (double)(1UL<<31)
+
tstamp NOW;
-bool iom_valid;
+static bool iom_valid;
io_manager iom;
template<class watcher>
void io_manager::reg (watcher *w, simplevec<watcher *> &queue)
{
- if (find (queue.begin (), queue.end (), w) == queue.end ())
- queue.push_back (w);
+ if (!iom_valid)
+ abort ();
+
+ if (!w->active)
+ {
+ queue.push_back (w);
+ w->active = queue.size ();
+ }
}
template<class watcher>
void io_manager::unreg (watcher *w, simplevec<watcher *> &queue)
{
- queue.erase (find (queue.begin (), queue.end (), w));
-}
-
-#if IOM_IO
-io_watcher::~io_watcher ()
-{
- if (iom_valid)
- iom.unreg (this);
-}
-
-void io_manager::reg (io_watcher *w)
-{
- reg (w, iow);
-}
+ if (!iom_valid)
+ return;
-void io_manager::unreg (io_watcher *w)
-{
- unreg (w, iow);
+ if (w->active)
+ {
+ queue [w->active - 1] = 0;
+ w->active = 0;
+ }
}
-#endif
-
#if IOM_TIME
void time_watcher::trigger ()
{
iom.reg (this);
}
-time_watcher::~time_watcher ()
-{
- if (iom_valid)
- iom.unreg (this);
-
- at = TSTAMP_CANCEL;
-}
-
-void io_manager::reg (time_watcher *w)
-{
- reg (w, tw);
-}
+void io_manager::reg (time_watcher *w) { reg (w, tw); }
+void io_manager::unreg (time_watcher *w) { unreg (w, tw); }
+#endif
-void io_manager::unreg (time_watcher *w)
-{
- unreg (w, tw);
-}
+#if IOM_IO
+void io_manager::reg (io_watcher *w) { reg (w, iow); }
+void io_manager::unreg (io_watcher *w) { unreg (w, iow); }
#endif
#if IOM_CHECK
-check_watcher::~check_watcher ()
-{
- if (iom_valid)
- iom.unreg (this);
-}
-
-void io_manager::reg (check_watcher *w)
-{
- reg (w, cw);
-}
-
-void io_manager::unreg (check_watcher *w)
-{
- unreg (w, cw);
-}
+void io_manager::reg (check_watcher *w) { reg (w, cw); }
+void io_manager::unreg (check_watcher *w) { unreg (w, cw); }
#endif
#if IOM_IDLE
-idle_watcher::~idle_watcher ()
-{
- if (iom_valid)
- iom.unreg (this);
-}
-
-void io_manager::reg (idle_watcher *w)
-{
- reg (w, iw);
-}
-
-void io_manager::unreg (idle_watcher *w)
-{
- unreg (w, iw);
-}
+void io_manager::reg (idle_watcher *w) { reg (w, iw); }
+void io_manager::unreg (idle_watcher *w) { unreg (w, iw); }
#endif
#if IOM_TIME
#endif
{
#if IOM_TIME
- time_watcher *w;
+ time_watcher *next;
- for (;tw.size ();)
+ for (;;)
{
- w = tw[0];
+ next = tw[0]; // the first time-watcher must exist at ALL times
- for (time_watcher **i = tw.begin (); i < tw.end (); ++i)
- if ((*i)->at < w->at)
- w = *i;
+ for (int i = tw.size (); i--; )
+ if (!tw[i])
+ tw.erase_unordered (i);
+ else if (tw[i]->at < next->at)
+ next = tw[i];
- if (w->at > NOW)
+ if (next->at > NOW)
{
- double diff = w->at - NOW;
- tval.tv_sec = (int)diff;
- tval.tv_usec = (int)((diff - tval.tv_sec) * 1000000);
- to = &tval;
+ if (next != tw[0])
+ {
+ double diff = next->at - NOW;
+ tval.tv_sec = (int)diff;
+ tval.tv_usec = (int)((diff - tval.tv_sec) * 1000000);
+ to = &tval;
+ }
break;
}
- else if (w->at >= 0)
- w->call (*w);
- else
- unreg (w);
+ else if (next->at >= 0)
+ {
+ unreg (next);
+ next->call (*next);
+ }
}
#endif
}
#if IOM_CHECK
- for (int i = 0; i < cw.size (); ++i)
- cw[i]->call (*cw[i]);
+ for (int i = cw.size (); i--; )
+ if (!cw[i])
+ cw.erase_unordered (i);
+ else
+ cw[i]->call (*cw[i]);
#endif
#if IOM_IO
- fd_set rfd, wfd;
+ fd_set rfd, wfd, efd;
FD_ZERO (&rfd);
FD_ZERO (&wfd);
int fds = 0;
- for (io_watcher **w = iow.begin (); w < iow.end (); ++w)
- {
- if ((*w)->events & EVENT_READ ) FD_SET ((*w)->fd, &rfd);
- if ((*w)->events & EVENT_WRITE) FD_SET ((*w)->fd, &wfd);
+ for (io_watcher **i = iow.end (); i-- > iow.begin (); )
+ if (*i)
+ {
+ if ((*i)->events & EVENT_READ ) FD_SET ((*i)->fd, &rfd);
+ if ((*i)->events & EVENT_WRITE) FD_SET ((*i)->fd, &wfd);
- if ((*w)->fd >= fds) fds = (*w)->fd + 1;
- }
+ if ((*i)->fd >= fds) fds = (*i)->fd + 1;
+ }
- if (!to && !fds)
+ if (!to && !fds) //TODO: also check idle_watchers and check_watchers
break; // no events
- fds = select (fds, &rfd, &wfd, 0, to);
+ fds = select (fds, &rfd, &wfd, &efd, to);
# if IOM_TIME
set_now ();
# endif
if (fds > 0)
- for (int i = 0; i < iow.size (); ++i)
- {
- io_watcher *w = iow[i];
-
- short revents = w->events;
+ for (int i = iow.size (); i--; )
+ if (!iow[i])
+ iow.erase_unordered (i);
+ else
+ {
+ short revents = iow[i]->events;
- if (!FD_ISSET (w->fd, &rfd)) revents &= ~EVENT_READ;
- if (!FD_ISSET (w->fd, &wfd)) revents &= ~EVENT_WRITE;
+ if (!FD_ISSET (iow[i]->fd, &rfd)) revents &= ~EVENT_READ;
+ if (!FD_ISSET (iow[i]->fd, &wfd)) revents &= ~EVENT_WRITE;
- if (revents)
- w->call (*w, revents);
- }
+ if (revents)
+ iow[i]->call (*iow[i], revents);
+ }
+ else if (fds < 0 && errno != EINTR)
+ {
+ perror ("Error while waiting for I/O or time event");
+ abort ();
+ }
#if IOM_IDLE
- else if (iw.size ())
- for (int i = 0; i < iw.size (); ++i)
- iw[i]->call (*iw[i]);
+ else
+ for (int i = iw.size (); i--; )
+ if (!iw[i])
+ iw.erase_unordered (i);
+ else
+ iw[i]->call (*iw[i]);
#endif
#elif IOM_TIME
}
}
+// this is a dummy time watcher to ensure that the first
+// time watcher is _always_ valid, this gets rid of a lot
+// of null-pointer-checks
+static struct tw0 : time_watcher {
+ void cb (time_watcher &w)
+ {
+ // should never get called
+ // reached end-of-time, or tstamp has a bogus definition :)
+ abort ();
+ }
+
+ tw0()
+ : time_watcher (this, &tw0::cb)
+ { }
+} tw0;
+
io_manager::io_manager ()
{
+ iom_valid = true;
+
#if IOM_TIME
set_now ();
-#endif
- iom_valid = true;
+ tw0.start (TSTAMP_MAX);
+#endif
}
io_manager::~io_manager ()
#include <cassert>
-#include "rxvtvec.h"
#include "callback.h"
+#include "rxvtvec.h"
+
+#ifndef IOM_IO
+# define IOM_IO 1
+#endif
+#ifndef IOM_TIME
+# define IOM_TIME 1
+#endif
+#ifndef IOM_CHECK
+# define IOM_CHECK 1
+#endif
+#ifndef IOM_IDLE
+# define IOM_IDLE 0
+#endif
-#define IOM_IO 1
-#define IOM_TIME 1
-#define IOM_CHECK 1
-#define IOM_IDLE 0
+typedef double tstamp;
+extern tstamp NOW;
#if IOM_IO
- typedef double tstamp;
- extern tstamp NOW;
-
struct io_watcher;
#endif
#if IOM_TIME
struct idle_watcher;
#endif
+template<class watcher>
+struct io_manager_vec : protected simplevec<watcher *> {
+ friend class io_manager;
+protected:
+ void erase_unordered (unsigned int pos)
+ {
+ watcher *w = (*this)[size () - 1];
+ pop_back ();
+
+ if (size ())
+ if ((*this)[pos] = w)
+ w->active = pos + 1;
+ }
+};
+
class io_manager {
#if IOM_IO
- simplevec<io_watcher *> iow;
+ io_manager_vec<io_watcher> iow;
#endif
#if IOM_CHECK
- simplevec<check_watcher *> cw;
+ io_manager_vec<check_watcher> cw;
#endif
#if IOM_TIME
- simplevec<time_watcher *> tw;
+ io_manager_vec<time_watcher> tw;
#endif
#if IOM_IDLE
- simplevec<idle_watcher *> iw;
+ io_manager_vec<idle_watcher> iw;
#endif
template<class watcher>
extern io_manager iom; // a singleton, together with it's construction/destruction problems.
+struct watcher {
+ int active; /* 0 == inactive, else index into respective vector */
+
+ watcher() : active(0) { }
+};
+
#if IOM_IO
enum { EVENT_READ = 1, EVENT_WRITE = 2 };
-struct io_watcher : callback2<void, io_watcher &, short> {
+struct io_watcher : watcher, callback2<void, io_watcher &, short> {
int fd;
short events;
- template<class O1, class O2>
- io_watcher (O1 *object, void (O2::*method)(io_watcher &, short))
- : callback2<void, io_watcher &, short>(object,method)
- { }
-
- ~io_watcher ();
-
void set (int fd_, short events_) { fd = fd_; events = events_; }
void set (short events_) { set (fd, events_); }
void start () { iom.reg (this); }
void start (int fd_, short events_) { set (fd_, events_); iom.reg (this); }
void stop () { iom.unreg (this); }
+
+ template<class O1, class O2>
+ io_watcher (O1 *object, void (O2::*method)(io_watcher &, short))
+ : callback2<void, io_watcher &, short>(object,method)
+ { }
+ ~io_watcher () { stop (); }
};
#endif
#if IOM_TIME
-enum { TSTAMP_CANCEL = -1 };
-
-struct time_watcher : callback1<void, time_watcher &> {
+struct time_watcher : watcher, callback1<void, time_watcher &> {
tstamp at;
- template<class O1, class O2>
- time_watcher (O1 *object, void (O2::*method)(time_watcher &))
- : callback1<void, time_watcher &>(object,method)
- { }
-
- ~time_watcher ();
-
void trigger ();
void set (tstamp when) { at = when; }
void start (tstamp when) { set (when); iom.reg (this); }
void stop () { iom.unreg (this); }
- void reset (tstamp when = TSTAMP_CANCEL)
- {
- stop ();
- at = when;
- }
+ template<class O1, class O2>
+ time_watcher (O1 *object, void (O2::*method)(time_watcher &))
+ : callback1<void, time_watcher &>(object,method)
+ { }
+ ~time_watcher () { stop (); }
};
#endif
#if IOM_CHECK
// run before checking for new events
-struct check_watcher : callback1<void, check_watcher &> {
- template<class O1, class O2>
- check_watcher (O1 *object, void (O2::*method)(check_watcher &))
- : callback1<void, check_watcher &>(object,method)
- { }
-
- ~check_watcher ();
-
+struct check_watcher : watcher, callback1<void, check_watcher &> {
void start () { iom.reg (this); }
void stop () { iom.unreg (this); }
+
+ template<class O1, class O2>
+ check_watcher (O1 *object, void (O2::*method)(check_watcher &))
+ : callback1<void, check_watcher &>(object,method)
+ { }
+ ~check_watcher () { stop (); }
};
#endif
#if IOM_IDLE
// run after checking for any i/o, but before waiting
-struct idle_watcher : callback1<void, idle_watcher &> {
+struct idle_watcher : watcher, callback1<void, idle_watcher &> {
+ void start () { iom.reg (this); }
+ void stop () { iom.unreg (this); }
+
template<class O1, class O2>
idle_watcher (O1 *object, void (O2::*method)(idle_watcher &))
: callback1<void, idle_watcher &>(object,method)
{ }
-
- ~idle_watcher ();
-
- void start () { iom.reg (this); }
- void stop () { iom.unreg (this); }
+ ~idle_watcher () { stop (); }
};
#endif
#endif
return EXIT_SUCCESS;
}
+
/*--------------------------------*-C-*--------------------------------------*
* File: screen.c
*---------------------------------------------------------------------------*
- * $Id: screen.C,v 1.15 2004-01-16 16:34:56 pcg Exp $
+ * $Id: screen.C,v 1.16 2004-01-16 22:11:09 pcg Exp $
*
* Copyright (c) 1997-2001 Geoff Wing <gcw@pobox.com>
*
void
rxvt_term::incr_cb (time_watcher &w)
{
- w.stop ();
selection_wait = Sel_none;
- rxvt_print_error("data loss: timeout on INCR selection paste");
+ rxvt_print_error ("data loss: timeout on INCR selection paste");
}
/*