/*  Inti: Integrated Foundation Classes
 *  Copyright (C) 2002-2003 The Inti 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 inti/gdk/input.h
//! @brief A GdkDevice C++ wrapper interface.
//!
//! Provides Device, an object for handling extended input devices.

#ifndef INTI_GDK_INPUT_H
#define INTI_GDK_INPUT_H

#ifndef INTI_G_OBJECT_H
#include <inti/glib/object.h>
#endif

#ifndef INTI_GDK_TYPES
#include <inti/gdk/types.h>
#endif

#ifndef _CPP_VECTOR
#include <vector>
#endif

namespace Inti {

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.
//!<
//!< <BR>The devices in this list are statically allocated and will be freed by GTK+.
//!< See also Gdk::Display::list_devcies.

//! @}

//! @class Device input.h inti/gdk/input.h
//! @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+.
//! Inti 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 reference = true);
	//!< Construct a new Device from an existing GdkDevice.
	//!< @param device A pointer to a GdkDevice.
	//!< @param reference Set false if the initial reference count is floating, set true if it's not.
	//!<
	//!< <BR>The <EM>device</EM> can be a newly created GdkDevice or an existing
	//!< GdkDevice. (see G::Object::Object).

//! @}

public:
//! @name Constructors
//! @{

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

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

	GdkDevice* gdk_device() const { return (GdkDevice*)instance; }
	//!< Get a pointer to the GdkDevice structure.

	GdkDeviceClass* gdk_device_class() const;
	//!< Get a pointer to the GdkDeviceClass 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.
	//!<
	//!< <BR>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>.

//! @}

	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.	

	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.
	//!<
	//!< <BR>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.
	//!<
	//!< <BR>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.

//! @}
};

} // namespace Gdk

} // namespace Inti

#endif // INTI_GDK_INPUT_H

