summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Spilsbury <smspillaz@gmail.com>2011-01-04 16:42:10 +0800
committerSam Spilsbury <smspillaz@gmail.com>2011-01-04 16:42:10 +0800
commit0d81dcc38a6fcc54568e60de366ae99e2b53f7e6 (patch)
tree2399c44ce4be0c323b513ad28f0fe6e95b5f3719
parent3f18c469842cdad1317fd6d1dfd33a77ffe177da (diff)
downloadcompiz-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.h1
-rw-r--r--include/core/timer.h15
-rw-r--r--src/privatescreen.h32
-rw-r--r--src/screen.cpp174
-rw-r--r--src/timer.cpp34
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 (&current, 0);
- left = mMinTime - TIMEVALDIFF (&current, &tickStart);
-
- return (left < 0)? 0 : (unsigned int) left;
+ return (mMinLeft < 0)? 0 : mMinLeft;
}
unsigned int
CompTimer::maxLeft ()
{
- struct timeval current;
- int left;
-
- gettimeofday (&current, 0);
- left = mMaxTime - TIMEVALDIFF (&current, &tickStart);
-
- return (left < 0)? 0 : (unsigned int) left;
+ return (mMaxLeft < 0)? 0 : mMaxLeft;
}
bool