/*
 ******************************************************************************
 *
 *	ParcPlace Systems, Inc.
 *	Copyright (c) 1992, ParcPlace Systems, Inc. USA   All rights reserved.
 *
 ****************************************************************************
 *
 *	File:	dragdrop.H
 *
 *	Functions(s):
 *
 *	Description:
 *		Drag and Drop data structures
 *
 *	RCSid = "$Id: dragdrop.H,v 4.12.1.3 1993/06/14 21:04:29 toml Exp $"
 *
 ****************************************************************************
 */

#ifndef OI_dragdrop_H
#define OI_dragdrop_H

	class OI_connection;
	class OI_d_tech;
	class OI_long_array;
	class OI_atom_array;
	class OI_callback;
	class OI_drop;

#define	OI_dnd_enumeration_count	OI_DND_ENUMERATION_COUNT
#define	OI_dnd_enumeration_item		OI_DND_ENUMERATION_ITEM
#define	OI_dnd_enumeration_end		OI_DND_ENUMERATION_END
#define	OI_dnd_current_item		OI_DND_CURRENT_ITEM
#define	OI_dnd_targets			OI_DND_TARGETS
#define	OI_dnd_multiple			OI_DND_MULTIPLE
#define	OI_dnd_file_name		OI_DND_FILE_NAME
#define	OI_dnd_string			OI_DND_STRING
#define	OI_dnd_file_host_name		OI_DND_FILE_HOST_NAME
#define	OI_dnd_host_name		OI_DND_HOST_NAME
#define	OI_dnd_available_types		OI_DND_AVAILABLE_TYPES
#define	OI_dnd_length			OI_DND_LENGTH
#define	OI_dnd_timestamp		OI_DND_TIMESTAMP

#define	OI_DND_TYPE_STRING		OI_str_STRING
#define	OI_dnd_type_string		OI_str_STRING
#define	OI_DND_TYPE_INTEGER		OI_str_INTEGER
#define	OI_dnd_type_integer		OI_str_INTEGER
		
	enum OI_dnd_sun_area_type {OI_dnd_sun_area_rect=0, OI_dnd_sun_area_window=1};

enum OI_dnd_operation {
	OI_dnd_noop = 0,
	OI_dnd_move,
	OI_dnd_copy,
	OI_dnd_enter,
	OI_dnd_leave,
	OI_dnd_motion,
	OI_dnd_start,
	OI_dnd_done
};

#define OI_dnd_sun_dragdrop_trigger_delete	0x01
#define OI_dnd_sun_dragdrop_trigger_ack		0x02
#define OI_dnd_sun_dragdrop_trigger_transient	0x04
#define OI_dnd_sun_dragdrop_trigger_forward	0x08

#define	OI_dnd_site_none			0,
#define	OI_dnd_site_crossing			0x01	/* site requests enter and leave events */
#define	OI_dnd_site_motion			0x02	/* site requests motion events */
#define	OI_dnd_site_default			0x04	/* this is the default site for the window */
#define	OI_dnd_site_forward			0x08	/* this site exists as a proxy for another site */
#define	OI_dnd_site_insensitive			0x10	/* this site is currently inactive */

	// the sun DSDM returns an array of these data structures
	struct OI_dnd_sun_dsdm_rect {
		unsigned long		screen_number;
		unsigned long		site_id;
		unsigned long		event_window_id;
		long			x;
		long			y;
		unsigned long		width;
		unsigned long		height;
		unsigned long		flags;
	};
 // macro to see if a coordinate is in a dsdm rectangle
#define OI_DND_IN_SUN_SITE(s, xx, yy)		((xx) >= (s)->x && \
						(xx) <= (long) ((s)->x + (s)->width) && \
						(yy) >= (s)->y && \
						(yy) <= (long) ((s)->y + (s)->height))

	class OI_dnd_sun_rect {
			int				_x;
			int				_y;
			unsigned long			_width;
			unsigned long			_height;
	public:
							OI_dnd_sun_rect(int x, int y, unsigned long w, unsigned long h)	{ _x=x; _y=y; _width=w; _height=h; }
			int				x()		{ return (_x); }
			int				y()		{ return (_y); }
			unsigned long			width()		{ return (_width); }
			unsigned long			height()	{ return (_height); }
	};

	class OI_dnd_sun_list {
			unsigned long			_count;
		public:
							OI_dnd_sun_list() { _count = 0; }
		virtual	void				append_window(Window);
		virtual	void				append_rect(int, int, unsigned long, unsigned long);
		virtual void				apply(OI_long_array *, int, int, unsigned long, unsigned long);
			unsigned long			count()		{ return (_count); }
			void				inc_count()	{ _count++; }
	};

	class OI_dnd_sun_window_list : public OI_dnd_sun_list {
			Window				*_list;
		public:
							OI_dnd_sun_window_list();
		virtual					~OI_dnd_sun_window_list();
		virtual	void				append_window(Window);
		virtual void				apply(OI_long_array *, int, int, unsigned long, unsigned long);
	};

	class OI_dnd_sun_rect_list : public OI_dnd_sun_list {
			OI_dnd_sun_rect			**_list;
		public:
							OI_dnd_sun_rect_list();
		virtual					~OI_dnd_sun_rect_list();
		virtual	void				append_rect(int, int, unsigned long, unsigned long);
		virtual void				apply(OI_long_array *, int, int, unsigned long, unsigned long);
			OI_dnd_sun_rect			**list()						{ return (_list); }
	};

	class OI_dnd_sun_area_list {
			OI_dnd_sun_area_type		_type;
			OI_dnd_sun_list			*_list;
		public:
							OI_dnd_sun_area_list(OI_dnd_sun_area_type);
							~OI_dnd_sun_area_list()					{ delete _list; }
			void				append(int x, int y, unsigned long w, unsigned long h)	{ _list->append_rect(x, y, w, h); }
			void				append(Window win)					{ _list->append_window(win); }
			void				apply(OI_long_array *, int, int, unsigned long, unsigned long);
			OI_dnd_sun_list			*list()							{ return (_list); }
			OI_dnd_sun_area_type		type()							{ return (_type); }
	};

	class OI_dnd_sun_site_description {
			Window				_event_window_id;
			unsigned long			_site_id;
			unsigned long			_flags;
			OI_dnd_sun_area_list		*_area_list;
		public:
							OI_dnd_sun_site_description(Window, unsigned long, unsigned long, OI_dnd_clip_rectangle*, OI_number);
							~OI_dnd_sun_site_description()		{ delete _area_list; }
			void				apply(OI_long_array *, int, int, unsigned long, unsigned long);
			OI_dnd_sun_area_list		*area_list()			{ return (_area_list); }
			void				set_event_window(Window w)	{ _event_window_id = w; }
	};

	class OI_dnd_sun {
			unsigned long			_version_number;
			unsigned long			_site_count;
			OI_drop				**_sites;
		public:
							OI_dnd_sun()	 { _version_number = 0; _site_count = 0; _sites = NULL; }
							~OI_dnd_sun();
			void				append(OI_drop*);
			void				apply(OI_d_tech*);
	};

	class OI_dnd_motif {
		public:
			void				append(OI_drop*)		{}
			void				apply(OI_d_tech*);
	};

	class OI_dnd_drop_sites {
			unsigned long			_site_count;
			OI_drop				**_sites;
			OI_dnd_sun			*_sundd;
			OI_dnd_motif			*_motifdd;
	public:
							OI_dnd_drop_sites();
							~OI_dnd_drop_sites()	{ delete _sundd; delete _motifdd; /* don't delete _sites */}
			void				append(OI_drop *);
			void				apply(OI_d_tech *d)	{ _sundd->apply(d); _motifdd->apply(d); }
			OI_drop				**sites()		{ return (_sites); }
			OI_dnd_sun*			sundd()			{ return(_sundd); }
			OI_dnd_motif*			motifdd()		{ return(_motifdd); }
	};

#define OI_DRAG_DRAGGING		0x01		/* we are currently dragging */
#define OI_DRAG_OVER_SITE		0x02		/* is the pointer over a site?  (used only for motif) */
#define OI_DRAG_TMP_CURSORS		0x04		/* temporary cursors can be deleted when drag is finished */
#define OI_DRAG_EVENTS_INSTALLED	0x08		/* events have been installed */

	class OI_drag : public OI_callback {
			OI_d_tech		*objp;
			Cursor			_cursor;
			Cursor			_accept_cursor;
			Cursor			current_cursor;
			OI_dnd_sun_dsdm_rect	*sun_rects;
			OI_dnd_sun_dsdm_rect	*sun_current_site;
			int			sun_rect_count;
			short unsigned		flags;
			Atom			sel;
			OI_dnd_operation	op;
		static	int			root_x;			// when a drag starts, get the root location of the object
		static	int			root_y;
		static	Window			last_subwindow;
		static	Window			top_level;		// current top-level window we're over
		public:
						OI_drag(OI_d_tech *, Cursor, Cursor);
		virtual				~OI_drag();
			void			allow_events_installed()	{ flags |= OI_DRAG_EVENTS_INSTALLED; }
			Cursor			accept_cursor()			{ return (_accept_cursor); }
			void			allow_dragging()		{ flags |= OI_DRAG_DRAGGING; }
			void			allow_over_site()		{ flags |= OI_DRAG_OVER_SITE; }
			void			allow_tmp_cursors()		{ flags |= OI_DRAG_TMP_CURSORS; }
			OI_dnd_sun_dsdm_rect	*construct_site_list(int, int, long*, unsigned int*);
			Cursor			cursor()			{ return (_cursor); }
			void			disallow_dragging()		{ flags &= ~OI_DRAG_DRAGGING; }
			void			disallow_events_installed()	{ flags &= ~OI_DRAG_EVENTS_INSTALLED; }
			void			disallow_over_site()		{ flags &= ~OI_DRAG_OVER_SITE; }
			void			disallow_tmp_cursors()		{ flags &= ~OI_DRAG_TMP_CURSORS; }
			Atom			get_transient_selection();
			OI_bool			is_dragging()			{ return ((flags&OI_DRAG_DRAGGING)?OI_YES:OI_NO); }
			OI_bool			is_events_installed()		{ return ((flags&OI_DRAG_EVENTS_INSTALLED)?OI_yes:OI_no); }
			OI_bool			is_tmp_cursors()		{ return ((flags&OI_DRAG_TMP_CURSORS)?OI_YES:OI_NO); }
			void			handle_client_message(const XEvent *,void*) ;		/* ClientMessage event handler */
			void			handle_motion(const XEvent *, void*);
			void			handle_release(const XEvent *, void*);
			void			handle_selection(const XEvent *, void*);
			void			install_events();
			OI_bool			is_over_site()			{ return ((flags & OI_DRAG_OVER_SITE)?OI_yes:OI_no); }
			OI_dnd_operation	operation()			{ return (op); }
			Atom			selection()			{ return (sel); }
			OI_bool			send_select_data(Window, Atom, Atom, Atom);
			OI_bool			start(OI_dnd_operation, int, int, Cursor = None, Cursor = None, OI_number = 0);
 			void			sun_send_crossing_event(OI_dnd_sun_dsdm_rect*, int, int, int, Time);
			void			verify(int, int);
	};

#define OI_DROP_DELETE			0x01		/* we should delete the selection when we're done */
#define OI_DROP_EVENTS_INSTALLED	0x02		/* events have already been installed */
#define OI_DROP_FAKE			0x04		/* this is a fake drop site */

	class OI_drop : public OI_callback {
			OI_d_tech		*objp;
			OI_dnd_sun_site_description *sun_site;
			unsigned long		trigger_flags;
			short			current_item;
			short			count;
			long			x;			// root coordinate of drop
			long			y;			// root coordinate of drop
			short unsigned		flags;
			Atom			sel;			// the selection we are working on
		public:
						OI_drop(OI_d_tech *, Window, unsigned long, unsigned long, OI_dnd_clip_rectangle *, OI_number);
		virtual				~OI_drop();
			void			allow_delete()			{ flags |= OI_DROP_DELETE; }
			void			allow_events_installed()	{ flags |= OI_DROP_EVENTS_INSTALLED; }
			void			allow_fake()			{ flags |= OI_DROP_FAKE; }
			void			disallow_delete()		{ flags &= ~OI_DROP_DELETE; }
			void			disallow_events_installed()	{ flags &= ~OI_DROP_EVENTS_INSTALLED; }
			void			disallow_fake()			{ flags &= ~OI_DROP_FAKE; }
 			void			*get_drop_data(const char *, const char* = NULL);
			void			handle_client_message(const XEvent *,void*) ;		/* ClientMessage event handler */
			void			handle_drop_selection(const XEvent *,void*) ;		/* SelectionNotify event handler */
			void			handle_drop_item(int, Atom, Time, Atom*, int);		/* handle one of many dropped items */
			void			install_events();
			OI_bool			is_events_installed()		{ return ((flags&OI_DROP_EVENTS_INSTALLED)?OI_yes:OI_no); }
			OI_bool			is_fake()			{ return ((flags&OI_DROP_FAKE)?OI_yes:OI_no); }
			OI_bool			is_within(OI_d_tech*, int, int);
			OI_bool			is_delete()			{ return ((flags&OI_DROP_DELETE)?OI_YES:OI_NO); }
			OI_d_tech		*object()			{ return (objp); }
			Atom			selection()			{ return (sel); }
// 			void			send_motif_enter(Window, short unsigned, Time, short unsigned, short unsigned);
// 			void			send_motif_leave(Window, short unsigned, Time);
// 			void			send_motif_motion(Window, short unsigned, Time, short unsigned, short unsigned);
			OI_dnd_sun_site_description *sun_drop_site()		{ return (sun_site); }
	};



struct OI_dnd_motif_drop_site_info {
	unsigned char	byte_order;
	unsigned char	protocol_version;
	unsigned char	drag_protocol_style;
	unsigned char	pad1;
	Window		proxy_window;
	unsigned short	num_drop_sites;
	unsigned short	pad2;
	unsigned long	heap_offset;
};

struct OI_dnd_motif_drag_initiator_info {
        unsigned char   byte_order;
        unsigned char   protocol_version;
	unsigned short	targets_index;
	Atom		icc_handle;
};

enum OI_dnd_motif_op {
	OI_dnd_motif_top_level_enter		=0,
	OI_dnd_motif_top_level_leave		=1,
	OI_dnd_motif_drag_motion		=2,
	OI_dnd_motif_drop_site_enter		=3,
	OI_dnd_motif_drop_site_leave		=4,
	OI_dnd_motif_drag_motion_reply		=2 | 0x80,
	OI_dnd_motif_drop_site_enter_reply	=3 | 0x80,
	OI_dnd_motif_drop_site_leave_reply	=4 | 0x80,
	OI_dnd_motif_drop_start			=5,
	OI_dnd_motif_drop_finish		=6,
	OI_dnd_motif_drag_drop_finish		=7,
	OI_dnd_motif_operation_changed		=8
};

// Since #$!&^%$^#! OSF won't let me look at all the header files, these
// are my best guesses at these things from looking at xscope output and
// watching events being sent to me.  I'm fairly confident that they're
// ok.

enum OI_dnd_motif_operations {
	OI_dnd_motif_noop		=0,
	OI_dnd_motif_move		=1,
	OI_dnd_motif_copy		=2,
	OI_dnd_motif_link		=4
};

enum OI_dnd_motif_drop_site_status {
	OI_dnd_motif_no_drop_site	=1,
	OI_dnd_motif_drop_site_invalid	=2,
	OI_dnd_motif_drop_site_valid	=3
};

#define OI_dnd_motif_set_operation(x)		(x)
#define OI_dnd_motif_set_drop_site_status(x)	(x<<4)
#define OI_dnd_motif_set_operations(x)		(x<<8)
#define OI_dnd_motif_set_completion_status(x)	(x<<12)

#define OI_dnd_motif_get_operation(x)		(x & 0x000f)
#define OI_dnd_motif_get_drop_site_status(x)	((x & 0x00f0) >> 4)
#define OI_dnd_motif_get_operations(x)		((x & 0x0f00) >> 8)
#define OI_dnd_motif_get_completion_status(x)	((x & 0xf000) >> 12)

struct OI_dnd_motif_event_any {
	unsigned char	message_type;
	unsigned char	byte_order;
/*
 * the flags field contains the following:
 *
 *      000F    operation
 *      00F0    drop_site_status
 *      0F00    operations
 *      F000    completion_status
 */
	short unsigned	flags;
	Time		time;
};

struct OI_dnd_motif_event_top_level_enter {
	unsigned char	message_type;
	unsigned char	byte_order;
	short unsigned	flags;
	Time		time;
	Window		src_window;
	Atom		icc_handle;
};

struct OI_dnd_motif_event_top_level_leave {
	unsigned char	message_type;
	unsigned char	byte_order;
	short unsigned	flags;
	Time		time;
	Window		src_window;
};

struct OI_dnd_motif_event_drag_motion {
	unsigned char	message_type;
	unsigned char	byte_order;
	short unsigned	flags;
	Time		time;
	short unsigned	x;
	short unsigned	y;
};

struct OI_dnd_motif_event_operation_changed {
	unsigned char	message_type;
	unsigned char	byte_order;
	short unsigned	flags;
	Time		time;
};

struct OI_dnd_motif_event_drop_site_enter {
	unsigned char	message_type;
	unsigned char	byte_order;
	short unsigned	flags;
	Time		time;
	short unsigned	x;
	short unsigned	y;
};

struct OI_dnd_motif_event_drop_site_leave {
	unsigned char	message_type;
	unsigned char	byte_order;
	short unsigned	flags;
	Time		time;
};

struct OI_dnd_motif_event_drop_message {
	unsigned char	message_type;
	unsigned char	byte_order;
	short unsigned	flags;
	Time		time;
	short unsigned	x;
	short unsigned	y;
	Atom		icc_handle;
	Window		src_window;
};

union OI_dnd_motif_event {
	OI_dnd_motif_event_any			any;
	OI_dnd_motif_event_top_level_enter	top_level_enter;
	OI_dnd_motif_event_top_level_leave	top_level_leave;
	OI_dnd_motif_event_drag_motion		drag_motion;
	OI_dnd_motif_event_operation_changed	operation_changed;
	OI_dnd_motif_event_drop_site_enter	drop_site_enter;
	OI_dnd_motif_event_drop_site_leave	drop_site_leave;
	OI_dnd_motif_event_drop_message		drop_message;
};

struct OI_dnd_motif_drag_targets {
	unsigned char	byte_order;
	unsigned char	protocol_version;
	unsigned short	num;
	unsigned long	heap_offset;
};


class OI_dnd_motif_targets : public OI_callback {
		static	XrmQuark		q_drop_targets;
			OI_number		_tcnt;			// how many are in the target list
			OI_atom_array		**_tlist;		// target list
			Window			_motif_window;
			OI_connection		*_conp;
	public:
						OI_dnd_motif_targets(OI_connection *);
		virtual				~OI_dnd_motif_targets();
		OI_number			append(Atom *);
		OI_number			count()			{ return (_tcnt); }
		OI_atom_array			*list(int i)		{ return (_tlist[i]); }
};

#endif /* OI_dragdrop_H */
