// -*- c++ -*- #ifndef _GLIBMM_MAIN_H #define _GLIBMM_MAIN_H /* $Id$ */ /* Copyright (C) 2002 The gtkmm Development Team * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include GTKMM_USING_STD(vector) namespace Glib { class Cond; class Mutex; class IOChannel; /** @defgroup MainLoop The Main Event Loop * Manages all available sources of events. * @{ */ enum { /*! Use this for high priority event sources. It is not used within * GLib or GTK+.

*/ PRIORITY_HIGH = -100, /*! Use this for default priority event sources. In glibmm this * priority is used by default when installing timeout handlers with * SignalTimeout::connect(). In GDK this priority is used for events * from the X server.

*/ PRIORITY_DEFAULT = 0, /*! Use this for high priority idle functions. GTK+ uses * PRIORITY_HIGH_IDLE + 10 for resizing operations, and * PRIORITY_HIGH_IDLE + 20 for redrawing operations. * (This is done to ensure that any pending resizes are processed before * any pending redraws, so that widgets are not redrawn twice unnecessarily.) *

*/ PRIORITY_HIGH_IDLE = 100, /*! Use this for default priority idle functions. In glibmm this priority is * used by default when installing idle handlers with SignalIdle::connect(). *

*/ PRIORITY_DEFAULT_IDLE = 200, /*! Use this for very low priority background tasks. It is not used within * GLib or GTK+. */ PRIORITY_LOW = 300 }; /** A bitwise combination representing an I/O condition to watch for on an * event source. * The flags correspond to those used by the %poll() system call * on UNIX (see man 2 poll). To test for individual flags, do * something like this: * @code * if((condition & Glib::IO_OUT) != 0) * do_some_output(); * @endcode * @par Bitwise operators: * IOCondition operator|(IOCondition, IOCondition)
* IOCondition operator&(IOCondition, IOCondition)
* IOCondition operator^(IOCondition, IOCondition)
* IOCondition operator~(IOCondition)
* IOCondition& operator|=(IOCondition&, IOCondition)
* IOCondition& operator&=(IOCondition&, IOCondition)
* IOCondition& operator^=(IOCondition&, IOCondition)
*/ enum IOCondition { IO_IN = G_IO_IN, /*!< @hideinitializer There is data to read. */ IO_OUT = G_IO_OUT, /*!< @hideinitializer Data can be written (without blocking). */ IO_PRI = G_IO_PRI, /*!< @hideinitializer There is urgent data to read. */ IO_ERR = G_IO_ERR, /*!< @hideinitializer %Error condition. */ IO_HUP = G_IO_HUP, /*!< @hideinitializer Hung up (the connection has been broken, usually for pipes and sockets). */ IO_NVAL = G_IO_NVAL /*!< @hideinitializer Invalid request. The file descriptor is not open. */ }; inline IOCondition operator|(IOCondition lhs, IOCondition rhs) { return static_cast(static_cast(lhs) | static_cast(rhs)); } inline IOCondition operator&(IOCondition lhs, IOCondition rhs) { return static_cast(static_cast(lhs) & static_cast(rhs)); } inline IOCondition operator^(IOCondition lhs, IOCondition rhs) { return static_cast(static_cast(lhs) ^ static_cast(rhs)); } inline IOCondition operator~(IOCondition flags) { return static_cast(~static_cast(flags)); } inline IOCondition& operator|=(IOCondition& lhs, IOCondition rhs) { return (lhs = static_cast(static_cast(lhs) | static_cast(rhs))); } inline IOCondition& operator&=(IOCondition& lhs, IOCondition rhs) { return (lhs = static_cast(static_cast(lhs) & static_cast(rhs))); } inline IOCondition& operator^=(IOCondition& lhs, IOCondition rhs) { return (lhs = static_cast(static_cast(lhs) ^ static_cast(rhs))); } class PollFD { public: PollFD(); explicit PollFD(int fd); PollFD(int fd, IOCondition events); void set_fd(int fd) { gobject_.fd = fd; } int get_fd() const { return gobject_.fd; } void set_events(IOCondition events) { gobject_.events = events; } IOCondition get_events() const { return static_cast(gobject_.events); } void set_revents(IOCondition revents) { gobject_.revents = revents; } IOCondition get_revents() const { return static_cast(gobject_.revents); } GPollFD* gobj() { return &gobject_; } const GPollFD* gobj() const { return &gobject_; } private: GPollFD gobject_; }; class SignalTimeout { public: #ifndef DOXYGEN_SHOULD_SKIP_THIS explicit inline SignalTimeout(GMainContext* context); #endif /** Connects a timeout handler. * @code * Glib::signal_timeout().connect(SigC::slot(&timeout_handler), 1000); * @endcode * is equivalent to: * @code * const Glib::RefPtr timeout_source = Glib::TimeoutSource::create(1000); * timeout_source->connect(SigC::slot(&timeout_handler)); * timeout_source->attach(Glib::MainContext::get_default()); * @endcode * @param slot A slot to call when @a interval elapsed. * @param interval The timeout in milliseconds. * @param priority The priority of the new event source. * @return A connection handle, which can be used to disconnect the handler. */ SigC::Connection connect(const SigC::Slot0& slot, unsigned int interval, int priority = PRIORITY_DEFAULT); private: GMainContext* context_; // no copy assignment SignalTimeout& operator=(const SignalTimeout&); }; class SignalIdle { public: #ifndef DOXYGEN_SHOULD_SKIP_THIS explicit inline SignalIdle(GMainContext* context); #endif /** Connects an idle handler. * @code * Glib::signal_idle().connect(SigC::slot(&idle_handler)); * @endcode * is equivalent to: * @code * const Glib::RefPtr idle_source = Glib::IdleSource::create(); * idle_source->connect(SigC::slot(&idle_handler)); * idle_source->attach(Glib::MainContext::get_default()); * @endcode * @param slot A slot to call when the main loop is idle. * @param priority The priority of the new event source. * @return A connection handle, which can be used to disconnect the handler. */ SigC::Connection connect(const SigC::Slot0& slot, int priority = PRIORITY_DEFAULT_IDLE); private: GMainContext* context_; // no copy assignment SignalIdle& operator=(const SignalIdle&); }; class SignalIO { public: #ifndef DOXYGEN_SHOULD_SKIP_THIS explicit inline SignalIO(GMainContext* context); #endif /** Connects an I/O handler. * @code * Glib::signal_io().connect(SigC::slot(&io_handler), fd, Glib::IO_IN | Glib::IO_HUP); * @endcode * is equivalent to: * @code * const Glib::RefPtr io_source = Glib::IOSource::create(fd, Glib::IO_IN | Glib::IO_HUP); * io_source->connect(SigC::slot(&io_handler)); * io_source->attach(Glib::MainContext::get_default()); * @endcode * @param slot A slot to call when polling @a fd results in an event that matches @a condition. * The event will be passed as a parameter to @a slot. * If @a io_handler returns false the signal is disconnected. * @param fd The file descriptor (or a @c HANDLE on Win32 systems) to watch. * @param condition The conditions to watch for. * @param priority The priority of the new event source. * @return A connection handle, which can be used to disconnect the handler. */ SigC::Connection connect(const SigC::Slot1& slot, int fd, IOCondition condition, int priority = PRIORITY_DEFAULT); /** Connects an I/O channel. * @code * Glib::signal_io().connect(SigC::slot(&io_handler), channel, Glib::IO_IN | Glib::IO_HUP); * @endcode * is equivalent to: * @code * const Glib::RefPtr io_source = Glib::IOSource::create(channel, Glib::IO_IN | Glib::IO_HUP); * io_source->connect(SigC::slot(&io_handler)); * io_source->attach(Glib::MainContext::get_default()); * @endcode * @param slot A slot to call when polling @a fd results in an event that matches @a condition. * The event will be passed as a parameter to @a slot. * If @a io_handler returns false the signal is disconnected. * @param channel The IOChannel object to watch. * @param condition The conditions to watch for. * @param priority The priority of the new event source. * @return A connection handle, which can be used to disconnect the handler. */ SigC::Connection connect(const SigC::Slot1& slot, const Glib::RefPtr& channel, IOCondition condition, int priority = PRIORITY_DEFAULT); private: GMainContext* context_; // no copy assignment SignalIO& operator=(const SignalIO&); }; /** Convenience timeout signal. * @return A signal proxy; you want to use SignalTimeout::connect(). */ SignalTimeout signal_timeout(); /** Convenience idle signal. * @return A signal proxy; you want to use SignalIdle::connect(). */ SignalIdle signal_idle(); /** Convenience I/O signal. * @return A signal proxy; you want to use SignalIO::connect(). */ SignalIO signal_io(); /** Main context. */ class MainContext { public: typedef Glib::MainContext CppObjectType; typedef GMainContext BaseObjectType; static Glib::RefPtr create(); static Glib::RefPtr get_default(); bool iteration(bool may_block); bool pending(); void wakeup(); bool acquire(); bool wait(Glib::Cond& cond, Glib::Mutex& mutex); void release(); bool prepare(int& priority); bool prepare(); void query(int max_priority, int& timeout, std::vector& fds); bool check(int max_priority, std::vector& fds); void dispatch(); void set_poll_func(GPollFunc poll_func); GPollFunc get_poll_func(); void add_poll(PollFD& fd, int priority); void remove_poll(PollFD& fd); /** Timeout signal, attached to this MainContext. * @return A signal proxy; you want to use SignalTimeout::connect(). */ SignalTimeout signal_timeout(); /** Idle signal, attached to this MainContext. * @return A signal proxy; you want to use SignalIdle::connect(). */ SignalIdle signal_idle(); /** I/O signal, attached to this MainContext. * @return A signal proxy; you want to use SignalIO::connect(). */ SignalIO signal_io(); void reference() const; void unreference() const; GMainContext* gobj(); const GMainContext* gobj() const; GMainContext* gobj_copy() const; private: // Glib::MainContext can neither be constructed nor deleted. MainContext(); void operator delete(void*, size_t); // noncopyable MainContext(const MainContext& other); MainContext& operator=(const MainContext& other); }; /** @relates Glib::MainContext */ Glib::RefPtr wrap(GMainContext* gobject, bool take_copy = false); class MainLoop { public: typedef Glib::MainLoop CppObjectType; typedef GMainLoop BaseObjectType; static Glib::RefPtr create(bool is_running = false); static Glib::RefPtr create(const Glib::RefPtr& context, bool is_running = false); void run(); void quit(); bool is_running(); Glib::RefPtr get_context(); void reference() const; void unreference() const; GMainLoop* gobj(); const GMainLoop* gobj() const; GMainLoop* gobj_copy() const; private: // Glib::MainLoop can neither be constructed nor deleted. MainLoop(); void operator delete(void*, size_t); MainLoop(const MainLoop&); MainLoop& operator=(const MainLoop&); }; /** @relates Glib::MainLoop */ Glib::RefPtr wrap(GMainLoop* gobject, bool take_copy = false); class Source { public: typedef Glib::Source CppObjectType; typedef GSource BaseObjectType; static Glib::RefPtr create() /* = 0 */; unsigned int attach(const Glib::RefPtr& context); unsigned int attach(); void destroy(); void set_priority(int priority); int get_priority() const; void set_can_recurse(bool can_recurse); bool get_can_recurse() const; unsigned int get_id() const; Glib::RefPtr get_context(); GSource* gobj() { return gobject_; } const GSource* gobj() const { return gobject_; } GSource* gobj_copy() const; void reference() const; void unreference() const; protected: /** Construct an object that uses the virtual functions prepare(), check() and dispatch(). */ Source(); /** Wrap an existing GSource object and install the given callback function. * The constructed object doesn't use the virtual functions prepare(), check() and dispatch(). * This ctor is for use by derived types that need to wrap a GSource object. * The callback function can be a static member function. But beware! * Depending on the actual implementation of the GSource's virtual functions * the expected type of the callback function can differ from GSourceFunc. */ Source(GSource* cast_item, GSourceFunc callback_func); virtual ~Source(); SigC::Connection connect_generic(const SigC::SlotBase& slot); void add_poll (PollFD& poll_fd); void remove_poll(PollFD& poll_fd); void get_current_time(Glib::TimeVal& current_time); virtual bool prepare(int& timeout) = 0; virtual bool check() = 0; virtual bool dispatch(SigC::SlotNode* slot_data) = 0; private: GSource* gobject_; #ifndef DOXGEN_SHOULD_SKIP_THIS static inline Source* get_wrapper(GSource* source); static const GSourceFuncs vfunc_table_; static gboolean prepare_vfunc(GSource* source, int* timeout); static gboolean check_vfunc(GSource* source); static gboolean dispatch_vfunc(GSource* source, GSourceFunc callback, void* user_data); public: static void destroy_notify_callback(void* data); private: #endif /* DOXGEN_SHOULD_SKIP_THIS */ // noncopyable Source(const Source&); Source& operator=(const Source&); }; class TimeoutSource : public Glib::Source { public: typedef Glib::TimeoutSource CppObjectType; static Glib::RefPtr create(unsigned int interval); SigC::Connection connect(const SigC::Slot0& slot); protected: explicit TimeoutSource(unsigned int interval); virtual ~TimeoutSource(); virtual bool prepare(int& timeout); virtual bool check(); virtual bool dispatch(SigC::SlotNode* slot_data); private: Glib::TimeVal expiration_; unsigned int interval_; }; class IdleSource : public Glib::Source { public: typedef Glib::IdleSource CppObjectType; static Glib::RefPtr create(); SigC::Connection connect(const SigC::Slot0& slot); protected: IdleSource(); virtual ~IdleSource(); virtual bool prepare(int& timeout); virtual bool check(); virtual bool dispatch(SigC::SlotNode* slot_data); }; class IOSource : public Glib::Source { public: typedef Glib::IOSource CppObjectType; static Glib::RefPtr create(int fd, IOCondition condition); static Glib::RefPtr create(const Glib::RefPtr& channel, IOCondition condition); SigC::Connection connect(const SigC::Slot1& slot); protected: IOSource(int fd, IOCondition condition); IOSource(const Glib::RefPtr& channel, IOCondition condition); virtual ~IOSource(); virtual bool prepare(int& timeout); virtual bool check(); virtual bool dispatch(SigC::SlotNode* slot_data); private: PollFD poll_fd_; }; /** @} group MainLoop */ } // namespace Glib #endif /* _GLIBMM_MAIN_H */