diff options
author | Sam Spilsbury <smspillaz@gmail.com> | 2011-01-04 16:42:10 +0800 |
---|---|---|
committer | Sam Spilsbury <smspillaz@gmail.com> | 2011-01-04 16:42:10 +0800 |
commit | 0d81dcc38a6fcc54568e60de366ae99e2b53f7e6 (patch) | |
tree | 2399c44ce4be0c323b513ad28f0fe6e95b5f3719 | |
parent | 3f18c469842cdad1317fd6d1dfd33a77ffe177da (diff) | |
download | compiz-with-glib-mainloop-0d81dcc38a6fcc54568e60de366ae99e2b53f7e6.tar.gz compiz-with-glib-mainloop-0d81dcc38a6fcc54568e60de366ae99e2b53f7e6.tar.bz2 |
Re-write timers to be a regular Glib::Source
We previously used Glib::TimeoutSource but this one is broken
for a number of usecases that we need, so create our own timeout
source which is similar to the stock one, except that we only insert
one source into the glib stack with grouped timeout times for the rest
of our timers.
Allows the use of setTimes () and setCallback () without glib
becoming a disaster-zone. Also fixes a number of crashes related
to the buggy glibmm implementation.
-rw-r--r-- | include/core/screen.h | 1 | ||||
-rw-r--r-- | include/core/timer.h | 15 | ||||
-rw-r--r-- | src/privatescreen.h | 32 | ||||
-rw-r--r-- | src/screen.cpp | 174 | ||||
-rw-r--r-- | src/timer.cpp | 34 |
5 files changed, 168 insertions, 88 deletions
diff --git a/include/core/screen.h b/include/core/screen.h index aa6ab5a..49ca46f 100644 --- a/include/core/screen.h +++ b/include/core/screen.h @@ -402,6 +402,7 @@ class CompScreen : friend class PrivateWindow; friend class ModifierHandler; friend class CompEventSource; + friend class CompTimeoutSource; friend class CompManager; friend class CompWatchFd; diff --git a/include/core/timer.h b/include/core/timer.h index 3119178..98d0c12 100644 --- a/include/core/timer.h +++ b/include/core/timer.h @@ -29,9 +29,9 @@ #include <boost/function.hpp> #include <sys/time.h> #include <core/core.h> - #include <glibmm/main.h> +class CompTimeoutSource; /** * A simple timer for use with invoking a CallBack during a timed duration. */ @@ -97,12 +97,9 @@ class CompTimer { */ void stop (); - void tick (); - - const struct timeval & tickInfo () const; - friend class CompScreen; friend class PrivateScreen; + friend class CompTimeoutSource; private: bool mActive; @@ -112,13 +109,7 @@ class CompTimer { int mMaxLeft; private: - CallBack mCallBack; - bool mForceFail; - bool mExecuting; - struct timeval tickStart; - - bool internalCallback (unsigned int); - Glib::RefPtr <Glib::TimeoutSource> mSource; + CallBack mCallBack; }; diff --git a/src/privatescreen.h b/src/privatescreen.h index f6b9bb9..44d0b04 100644 --- a/src/privatescreen.h +++ b/src/privatescreen.h @@ -70,6 +70,33 @@ class CompWatchFd : friend class CompScreen; }; +class CompTimeoutSource : + public Glib::Source +{ + public: + + static Glib::RefPtr <CompTimeoutSource> create (); + sigc::connection connect (const sigc::slot <bool> &slot); + + protected: + + bool prepare (int &timeout); + bool check (); + bool dispatch (sigc::slot_base *slot); + bool callback (); + + explicit CompTimeoutSource (); + virtual ~CompTimeoutSource (); + + private: + + struct timeval mLastTimeout; + Glib::PollFD pfd; + + friend class CompTimer; + friend class PrivateScreen; +}; + extern CompWindow *lastFoundWindow; extern bool useDesktopHints; @@ -356,13 +383,14 @@ class PrivateScreen : public CoreOptions { Glib::RefPtr <Glib::MainLoop> mainloop; Glib::RefPtr <CompEventSource> source; + Glib::RefPtr <CompTimeoutSource> timeout; Glib::RefPtr <Glib::MainContext> ctx; CompFileWatchList fileWatch; CompFileWatchHandle lastFileWatchHandle; - std::list <int> removedTimers; - struct timeval lastTimeout; + std::list <CompTimer *> timers; + struct timeval lastTimeout; std::list<Glib::RefPtr <CompWatchFd> > watchFds; CompWatchFdHandle lastWatchFdHandle; diff --git a/src/screen.cpp b/src/screen.cpp index e296b03..5c74795 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -182,6 +182,7 @@ CompScreen::eventLoop () priv->ctx = Glib::MainContext::get_default (); priv->mainloop = Glib::MainLoop::create (priv->ctx, false); priv->source = CompEventSource::create (); + priv->timeout = CompTimeoutSource::create (); priv->source->attach (priv->ctx); @@ -190,7 +191,6 @@ CompScreen::eventLoop () priv->mainloop->run (); } - CompFileWatchHandle CompScreen::addFileWatch (const char *path, int mask, @@ -242,87 +242,165 @@ CompScreen::getFileWatches () const return priv->fileWatch; } -/* TODO: move this code to timer.cpp */ +CompTimeoutSource::CompTimeoutSource () : + Glib::Source () +{ + struct timeval tv; + + gettimeofday (&tv, 0); + mLastTimeout = tv; + + pfd.set_fd (ConnectionNumber (screen->dpy ())); + pfd.set_events (Glib::IO_IN); + + set_priority (G_PRIORITY_HIGH); + attach (screen->priv->ctx); + connect (sigc::mem_fun <bool, CompTimeoutSource> (this, &CompTimeoutSource::callback)); +} + +CompTimeoutSource::~CompTimeoutSource () +{ +} + +sigc::connection +CompTimeoutSource::connect (const sigc::slot <bool> &slot) +{ + return connect_generic (slot); +} + +Glib::RefPtr <CompTimeoutSource> +CompTimeoutSource::create () +{ + return Glib::RefPtr <CompTimeoutSource> (new CompTimeoutSource ()); +} bool -CompTimer::internalCallback (unsigned int id) +CompTimeoutSource::prepare (int &timeout) { - bool result; + struct timeval tv; - /* Detect when the timer is still going and the internal - * object has been freed */ - if (!screen->priv->removedTimers.empty ()) + gettimeofday (&tv, 0); + + /* Determine time to wait */ + + if (screen->priv->timers.empty ()) { - if (std::find (screen->priv->removedTimers.begin (), - screen->priv->removedTimers.end (), - id) != screen->priv->removedTimers.end ()) - { - screen->priv->removedTimers.remove (id); - return false; - } + add_poll (pfd); + timeout = -1; + return false; } + else + remove_poll (pfd); - if (!mActive) - return false; + if (screen->priv->timers.front ()->mMinLeft > 0) + { + std::list<CompTimer *>::iterator it = screen->priv->timers.begin (); - mForceFail = false; - mExecuting = true; + CompTimer *t = (*it); + timeout = t->mMaxLeft; + while (it != screen->priv->timers.end ()) + { + t = (*it); + if (t->mMinLeft >= timeout) + break; + if (t->mMaxLeft < timeout) + timeout = t->mMaxLeft; + it++; + } - result = mCallBack (); + mLastTimeout = tv; + return false; + } + else + { + mLastTimeout = tv; + timeout = 0; + return true; + } +} - mExecuting = false; +bool +CompTimeoutSource::check () +{ + struct timeval tv; + int timeDiff; - if (mForceFail) - return false; + gettimeofday (&tv, 0); + timeDiff = TIMEVALDIFF (&tv, &mLastTimeout); + + if (timeDiff < 0) + timeDiff = 0; - if (result) + foreach (CompTimer *t, screen->priv->timers) { - tick (); - return true; + t->mMinLeft -= timeDiff; + t->mMaxLeft -= timeDiff; } - else + + return screen->priv->timers.front ()->mMinLeft <= 0; +} + +bool +CompTimeoutSource::dispatch (sigc::slot_base *slot) +{ + (*static_cast <sigc::slot <bool> *> (slot)) (); + + return true; +} + +bool +CompTimeoutSource::callback () +{ + while (screen->priv->timers.begin () != screen->priv->timers.end () && + screen->priv->timers.front ()->mMinLeft <= 0) { - if (mSource) - mSource.reset (); - return false; + CompTimer *t = screen->priv->timers.front (); + screen->priv->timers.pop_front (); + + t->mActive = false; + if (t->mCallBack ()) + { + screen->priv->addTimer (t); + t->mActive = true; + } } + + return !screen->priv->timers.empty (); } void PrivateScreen::addTimer (CompTimer *timer) { - unsigned int time = timer->mMinTime; - unsigned int id; + std::list<CompTimer *>::iterator it; - if (timer->mSource) - return; + it = std::find (timers.begin (), timers.end (), timer); - timer->mSource = Glib::TimeoutSource::create (time); + if (it != timers.end ()) + return; - if (timer->mSource) + for (it = timers.begin (); it != timers.end (); it++) { - timer->mSource->attach (priv->ctx); - id = g_source_get_id (timer->mSource->gobj ()); - removedTimers.remove (id); - timer->mSource->connect (sigc::bind <unsigned int>(sigc::mem_fun (timer, &CompTimer::internalCallback), id)); - timer->tick (); + if ((int) timer->mMinTime < (*it)->mMinLeft) + break; } - else - timer->mActive = false; + + timer->mMinLeft = timer->mMinTime; + timer->mMaxLeft = timer->mMaxTime; + + timers.insert (it, timer); } void PrivateScreen::removeTimer (CompTimer *timer) { - if (!timer->mSource) - return; + std::list<CompTimer *>::iterator it; - if (timer->mExecuting) - timer->mForceFail = true; + it = std::find (timers.begin (), timers.end (), timer); - removedTimers.push_back (g_source_get_id (timer->mSource->gobj ())); + if (it == timers.end ()) + return; - timer->mSource.reset (); /* This will NULL the pointer */ + timers.erase (it); } CompWatchFd::CompWatchFd (int fd, diff --git a/src/timer.cpp b/src/timer.cpp index 793dad4..4a05c27 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -33,17 +33,13 @@ CompTimer::CompTimer () : mMaxTime (0), mMinLeft (0), mMaxLeft (0), - mCallBack (NULL), - mForceFail (false), - mExecuting (false), - mSource (NULL) + mCallBack (NULL) { } CompTimer::~CompTimer () { - if (mActive) - screen->priv->removeTimer (this); + screen->priv->removeTimer (this); } void @@ -65,12 +61,14 @@ CompTimer::setCallback (CompTimer::CallBack callback) bool wasActive = mActive; if (mActive) stop (); + mCallBack = callback; if (wasActive) start (); } + void CompTimer::start () { @@ -83,10 +81,8 @@ CompTimer::start () return; } - if (!mActive) - screen->priv->addTimer (this); - mActive = true; + screen->priv->addTimer (this); } void @@ -110,10 +106,8 @@ CompTimer::start (CompTimer::CallBack callback, void CompTimer::stop () { - if (mActive) - screen->priv->removeTimer (this); - mActive = false; + screen->priv->removeTimer (this); } unsigned int @@ -131,25 +125,13 @@ CompTimer::maxTime () unsigned int CompTimer::minLeft () { - struct timeval current; - int left; - - gettimeofday (¤t, 0); - left = mMinTime - TIMEVALDIFF (¤t, &tickStart); - - return (left < 0)? 0 : (unsigned int) left; + return (mMinLeft < 0)? 0 : mMinLeft; } unsigned int CompTimer::maxLeft () { - struct timeval current; - int left; - - gettimeofday (¤t, 0); - left = mMaxTime - TIMEVALDIFF (¤t, &tickStart); - - return (left < 0)? 0 : (unsigned int) left; + return (mMaxLeft < 0)? 0 : mMaxLeft; } bool |