/*  XFC: Xfce Foundation Classes (User Interface Library)
 *  Copyright (C) 2004 The XFC Development Team.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  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 Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/// @file xfc/gdk/input.hh
/// @brief A GdkDevice C++ wrapper interface.
///
/// Provides Device, an object for handling extended input devices.

#ifndef XFC_GDK_INPUT_HH
#define XFC_GDK_INPUT_HH

#ifndef XFC_G_OBJECT_HH
#include <xfc/glib/object.hh>
#endif

#ifndef XFC_GDK_TYPES_HH
#include <xfc/gdk/types.hh>
#endif

#ifndef _CPP_VECTOR
#include <vector>
#endif

namespace Xfc {

namespace Gdk {

class Device;
class Display;
class Window;

/// @enum InputSource
/// An enumeration describing the type of an input device in general terms.

enum InputSource
{
	SOURCE_MOUSE = GDK_SOURCE_MOUSE,
	///< The device is a mouse (this will be reported for the core pointer,
	///< even if it is something else, such as a trackball).
	
	SOURCE_PEN = GDK_SOURCE_PEN,
	///< The device is a stylus of a graphics tablet or similar device.

	SOURCE_ERASER = GDK_SOURCE_ERASER,
	///< The device is an eraser; typically, this would be the other end
	///< of a stylus on a graphics tablet.

	SOURCE_CURSOR = GDK_SOURCE_CURSOR
	///< The device is a graphics tablet "puck" or similar device.
};

/// @enum InputMode
/// An enumeration that describes the mode of an input device.

enum InputMode
{
	MODE_DISABLED = GDK_MODE_DISABLED,
	///< The device is disabled and will not report any events.
	
	MODE_SCREEN = GDK_MODE_SCREEN,
	///< The device is enabled; the device's coordinate space maps to the entire screen.

	MODE_WINDOW = GDK_MODE_WINDOW
	///< The device is enabled; the device's coordinate space is mapped to a single window
	///< (the manner in which this window is chosen is undefined, but it will typically be
	///< the same way in which the focus window for key events is determined).
};

/// @name Device Methods
/// @{

bool devices_list(std::vector<Device*>& devices);
///< Returns the list of available input devices attached to the default display.
///< @param devices A reference to a vector of Device* to hold the list of devices.
///< @return <EM>true</EM> if the vector is not empty.
///<
///< The devices in this list are statically allocated and will be freed by GTK+.
///< See also Gdk::Display::list_devcies.

/// @}

/// @class Device input.hh xfc/gdk/input.hh
/// @brief A GdkDevice C++ wrapper class.
///
/// In addition to the normal keyboard and mouse input devices, GTK+ also contains support for
/// extended input devices. In particular, this support is targeted at graphics tablets. Graphics
/// tablets typically return sub-pixel positioning information and possibly information about the
/// pressure and tilt of the stylus. Under X, the support for extended devices is done through the
/// XInput extension.
///
/// Because handling extended input devices may involve considerable overhead, they need to be
/// turned on for each Gdk::Window individually using set_extension_events(). (Or, more typically,
/// for Gtk::Widgets, using Gtk::Widget::set_extension_events()). As an additional complication,
/// depending on the support from the windowing system, its possible that a normal mouse cursor
/// will not be displayed for a particular extension device. If an application does not want to
/// deal with displaying a cursor itself, it can ask only to get extension events from devices
/// that will display a cursor, by passing the EXTENSION_EVENTS_CURSOR value to 
/// set_extension_events(). Otherwise, the application must retrieve the device information using
/// list_devices(), check the has_cursor() accessor, and, if it returns false, draw a cursor 
/// itself when it receives motion events.
///
/// Each pointing device is assigned a unique integer ID; events from a particular device can be
/// identified by the deviceid field in the event structure. The events generated by pointer 
/// devices have also been extended to contain pressure, xtilt and ytilt fields which contain the
/// extended information reported as additional valuators from the device. The pressure field is
/// a double value ranging from 0.0 to 1.0, while the tilt fields are double values ranging
/// from -1.0 to 1.0. (With -1.0 representing the maximum tilt to the left or up, and 1.0 
/// representing the maximum tilt to the right or down.)
///
/// One additional field in each event is the source field, which contains an enumeration value
/// describing the type of device; this currently can be one of SOURCE_MOUSE, SOURCE_PEN, 
/// SOURCE_ERASER, or SOURCE_CURSOR. This field is present to allow simple applications to
/// (for instance) delete when they detect eraser devices without having to keep track of
/// complicated per-device settings.
///
/// Various aspects of each device may be configured. The easiest way of creating a GUI to
/// allow the user to configure such a device is to use the GtkInputDialog widget in GTK+.
/// XFC doesn't wrap GtkInputDialog because it is considered too specialized and will 
/// eventually be moved out of GTK+. If you use this widget, application writers will need
/// to directly query and set the configuration parameters in order to save the state between
/// invocations of the application. The configuration of devices is queried using 
/// list_devices(). Each device must be activated using set_mode(), which also controls 
/// whether the device's range is mapped to the entire screen or to a single window. The 
/// mapping of the valuators of the device onto the predefined valuator types is set using
/// set_axis_use(). And the source type for each device can be set with set_source().
///
/// Devices may also have associated keys or macro buttons. Such keys can be globally set to
/// map into normal X keyboard events. The mapping is set using set_key(). The interfaces in
/// this section will most likely be considerably modified in the future to accomodate devices
/// that may have different sets of additional valuators than the pressure xtilt and ytilt.

class Device : public G::Object
{
	friend class G::Object;

	Device(const Device&);
	Device& operator=(const Device&);
	
protected:
/// @name Constructors
/// @{

	explicit Device(GdkDevice *device, bool owns_reference = true);
	///< Construct a new Device from an existing GdkDevice.
	///< @param device A pointer to a GdkDevice.
	///< @param owns_reference Set false if the initial reference count is floating, set true if it's not.
	///<
	///< The <EM>device</EM> can be a newly created GdkDevice or an existing
	///< GdkDevice. (see G::Object::Object).

/// @}

public:
	typedef GdkDevice CObjectType;

/// @name Constructors
/// @{

	virtual ~Device();
	///< Destructor.

/// @}
/// @name Accessors
/// @{

	GdkDevice* gdk_device() const;
	///< Get a pointer to the GdkDevice structure.

	operator GdkDevice* () const;
	///< Conversion operator; safely converts a Device to a GdkDevice pointer.

 	String name() const;
	///< Returns the name of the device.

	InputSource source() const;
	///< Returns the type of the device.

	InputMode mode() const;
	///< Returns the mode of the device.

	bool has_cursor() const;
	///< Returns true if the X pointer follows device motion

	void get_state(Window& window, double *axes, ModifierTypeField *mask) const;
	///< Gets the current state of the device.
	///< @param window A Gdk::Window.
	///< @param axes An array of doubles to store the values of the axes of device in, or null.
 	///< @param mask The location to store the modifiers, or null.

	bool get_history(Window& window, unsigned long start, unsigned long stop, GdkTimeCoord ***events, int *n_events) const;
	///< Obtains the motion history for a device, given a starting and ending timestamp,
	///< and returns all events in the motion history for the given time range.
	///< @param window The window with respect to which which the event coordinates will be reported.
	///< @param start The starting timestamp for range of events to return.
	///< @param stop The ending timestamp for the range of events to return.
	///< @param events The location to store a newly-allocated array of GdkTimeCoord, or null.
	///< @param n_events The location to store the length of events, or null.
	///< @return <EM>true</EM> if the windowing system supports motion history
	///< and at least one event was found.
	///<
	///< Some windowing systems do not support motion history, in which case, false
	///< will be returned. This is not distinguishable from the case where motion history
	///< is supported and no events were found. If successful, the vector contents must be
	///< freed by calling free_history();

	bool get_axis(double *axes, AxisUse use, double *value) const;
	///< Interprets an array of double as axis values for a given device, 
	///< and locates the value in the array for a given axis use.
	///< @param axes The pointer to an array of axes.
	///< @param use The use to look for.
	///< @param value The location to store the found value.
	///< @return <EM>true</EM> if the given axis use was found, otherwise <EM>false</EM>.

/// @}
/// @name Accessors
/// @{

	static Device* get_core_pointer(const Display *display = 0);
	///< Returns the core pointer device for <EM>display</EM>.
	///< @param display The Display, or null for the default display.
	///<
	///< This device is owned by the display and should not be unreferenced.

/// @}
/// @name Methods
/// @{
	
	void set_source(InputSource source);
	///< Sets the source type for the input device.
	///< @param source The source type.

	bool set_mode(InputMode mode);
	///< Sets the mode of an input device.
	///< @param mode The input mode.
	///< @return <EM>true</EM> if the mode was successfully changed.
	///<
	///< The mode controls if the device is active and whether the device's range
	///< is mapped to the entire screen or to a single window.

	void set_key(unsigned int index, unsigned int keyval, ModifierTypeField modifiers);
	///< Specifies the X key event to generate when a macro button of a device is pressed.
	///< @param index The index of the macro button to set.
	///< @param keyval The keyval to generate.
	///< @param modifiers The modifiers to set.

	void set_axis_use(unsigned int index, AxisUse use);
	///< Specifies how an axis of a device is used.
	///< @param index The index of the axis.
	///< @param use Specifies how the axis is used.

/// @}
/// @name Accessors
/// @{

	static void free_history(GdkTimeCoord **events, int n_events);
	///< Frees the array of GdkTimeCoord that was returned by get_history().
	///< @param events An array of GdkTimeCoord.
	///< @param n_events The length of the array.	

/// @}
};

} // namespace Gdk

} // namespace Xfc

#include <xfc/gdk/inline/input.inl>

#endif // XFC_GDK_INPUT_HH

