// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
/*
* Copyright (C) 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authored by: Marco Trevisan (TreviƱo) <3v1n0@ubuntu.com>
*/
#ifndef UNITY_GLIB_SOURCE_H
#define UNITY_GLIB_SOURCE_H
#include
#include
#include
#include
#include
namespace unity
{
namespace glib
{
/**
* glib::Source is a wrapper class made to handle GSource based events at C++
* level.
*
* The class is basically to be intended abstract and is currently implemented
* by glib::Timeout() and glib::Idle() that are the higher-level wrappers for
* g_timeout and g_idle respectively.
*
* As this is meant to be mostly a wrapper, I've mostly kept the same logic of
* the glib sources, and so, for example, a source can't be ran more than once.
*
* Sources should define a callback function that will be called every time that
* the source is dispatched. If the callback function returns false, then the
* source will be removed, otherwise it will continue.
*
* Pointer types have been defined and should be used to handle dynamically
* allocated sources. They also implicitly allow to remove running Sources
* by setting their value to nullptr.
*/
class Source : public boost::noncopyable
{
public:
typedef std::shared_ptr Ptr;
typedef std::unique_ptr UniquePtr;
typedef std::function Callback;
/**
* This is an enum used for convenience, you can actually cast to this
* any integer: the bigger it is, the lower priority we have.
*/
enum Priority
{
HIGH = G_PRIORITY_HIGH, // -100
DEFAULT = G_PRIORITY_DEFAULT, // 0
HIGH_IDLE = G_PRIORITY_HIGH_IDLE, // 100
DEFAULT_IDLE = G_PRIORITY_DEFAULT_IDLE, // 200
LOW = G_PRIORITY_LOW // 300
};
virtual ~Source();
unsigned int Id() const;
/**
* This Run a source using the @callback function as Source's callback.
* The method will return false if the source is already running, true otherwise.
*/
bool Run(Callback const& callback);
bool IsRunning() const;
/**
* This removes a source, and stop it from being executed.
* After that a source has been removed, it can't be ran again.
*/
void Remove();
void SetPriority(Priority prio);
Priority GetPriority() const;
/**
* The removed signal is emitted when the Source has been removed and so it
* can happen both when the Remove() method is called and when the callback
* function returns false.
*/
sigc::signal removed;
protected:
Source();
GSource* source_;
private:
struct CallBackData
{
CallBackData(Source* src, Callback const& callback)
: self(src)
, callback_fn_(callback)
{}
Source* self;
Callback callback_fn_;
};
static gboolean SourceCallback(gpointer data);
static void DestroyCallback(gpointer data);
unsigned int source_id_;
CallBackData* callback_data_;
};
/**
* glib::Timeout is a wrapper to g_timeout and must be used to initialize a
* timeout that will be executed every @milliseconds milliseconds, whenever
* there are no higher priority events pending to the default main loop.
*
* If the Callback is defined on construction, then the Timeout is ran as soon
* as it is created, otherwise you must manually call the Run() method with the
* appropriate parameters.
*/
class Timeout : public Source
{
public:
Timeout(unsigned int milliseconds, Priority prio = Priority::DEFAULT);
Timeout(unsigned int milliseconds, Callback const& cb, Priority prio = Priority::DEFAULT);
private:
void Init(unsigned int milliseconds, Priority prio);
};
/**
* glib::TimeoutSeconds is a wrapper to g_timeout and must be used to initialize
* a timeout that will be executed every @seconds seconds, whenever
* there are no higher priority events pending to the default main loop.
*
* If the Callback is defined on construction, then the Timeout is ran as soon
* as it is created, otherwise you must manually call the Run() method with the
* appropriate parameters.
*/
class TimeoutSeconds : public Source
{
public:
TimeoutSeconds(unsigned int seconds, Priority prio = Priority::DEFAULT);
TimeoutSeconds(unsigned int seconds, Callback const& cb, Priority prio = Priority::DEFAULT);
private:
void Init(unsigned int seconds, Priority prio);
};
/**
* glib::Idle is a wrapper to g_idle and must be used to initialize an idle
* that will be executed whenever there are no higher priority events pending to
* the default main loop.
*
* If the Callback is defined on construction, then the Idle is ran as soon as
* it is created, otherwise you must manually call the Run() method with the
* appropriate parameters.
*/
class Idle : public Source
{
public:
Idle(Priority prio = Priority::DEFAULT_IDLE);
Idle(Callback const& cb, Priority prio = Priority::DEFAULT_IDLE);
private:
void Init(Priority prio);
};
/**
* glib::SourceManager is a container for the glib::Source pointers.
* It can be used to store multiple Sources pointers, possibly defining a
* "nick" name to reference them.
*
* This is meant to be an utility class that ensures that all the Sources
* are removed and destructed when the container itself is destructed.
*/
class SourceManager : public boost::noncopyable
{
public:
SourceManager();
~SourceManager();
/**
* Adds a new Source to the manager.
* Only new valid sources can be added to the manager.
*
* The developer may define a nickname for a Source, when adding a new Source
* with an already known nickname, the old Source will be removed, and the
* new one will replace it.
*/
bool Add(Source* source, std::string const& nick = "");
bool Add(Source::Ptr const& source, std::string const& nick = "");
Source::Ptr AddTimeout(unsigned int milliseconds, std::string const& nick = "");
Source::Ptr AddTimeout(unsigned int milliseconds, Source::Callback const& cb, std::string const& nick = "");
Source::Ptr AddTimeoutSeconds(unsigned int seconds, std::string const& nick = "");
Source::Ptr AddTimeoutSeconds(unsigned int seconds, Source::Callback const& cb, std::string const& nick = "");
Source::Ptr AddIdle(std::string const& nick = "");
Source::Ptr AddIdle(Source::Callback const& cb, std::string const& nick = "");
bool Remove(std::string const& nick);
bool Remove(unsigned int id);
void RemoveAll();
Source::Ptr GetSource(std::string const& nick) const;
Source::Ptr GetSource(unsigned int id) const;
protected: // For testing purposes
typedef std::map SourcesMap;
SourcesMap sources_;
private:
void OnSourceRemoved(unsigned int id);
void RemoveItem(SourcesMap::iterator it);
};
} // glib namespace
} // unity namespace
#endif