/*
 *	(c) Copyright 1991 Sun Microsystems, Inc.  All rights reserved.
 *	See LEGAL_NOTICE file for terms and restrictions.
 */

#ifndef lint
#ifdef sccs
static char     sccsid[] = "@(#)drag.c 1.9 91/05/06";
#endif
#endif

#include <X11/X.h>
#include <X11/Xatom.h>
#include <xview/win_input.h>
#include <xview/fullscreen.h>
#include <xview/cursor.h>
#include <sspkg/canshell.h>
#include "canshell_impl.h"

/*
 * At the up event of a drag, the following evaluation occurs:
 * 
 *	on root?
 *		yes:	call (*root_window_drop_proc)() and return
 * 
 *	on canvas_shell?
 *		no:	do nothing, just return
 * 
 *	on rectobj that accepts drop?  (RECTOBJ_ACCEPTS_DROP == TRUE)
 *		no:	do nothing, just return
 *
 *	on rectobj that accepts drop?  (RECTOBJ_ACCEPTS_DROP == TRUE)
 *	and has a drop proc?  (RECTOBJ_DROP_PROC != 0) 
 *		yes:	call RECTOBJ_DROP_PROC and return
 *  
 *	does the rectobj's parent act as proxy for the drop proxy? 
 *	RECTOBJ_PARENT has (RECTOBJ_ACCEPTS_CHILD_DROP == TRUE)
 *	and has a drop proc (RECTOBJ_CHILD_DROP_PROC != 0) 
 * 
 *		yes:	call parent's RECTOBJ_CHILD_DROP_PROC and return
 *  
 *	do nothing, return
 */


void	(*root_window_drop_proc)();

XID
do_fullscreen_drag(canvas_shell, cursor, drop_event)
	Canvas_shell	canvas_shell;
	Xv_cursor	cursor;
	Event		*drop_event;
{
	Fullscreen	fullscreen;
	XID		dest_win_xid;
	Inputmask	im;
	XID		win_pointer_under();
	Window		child;
	int 		x,y;

	fullscreen = xv_create(0, FULLSCREEN,
			FULLSCREEN_INPUT_WINDOW, 	canvas_shell,
			FULLSCREEN_SYNC,		FALSE,
			WIN_CONSUME_EVENTS,		WIN_MOUSE_BUTTONS, 
							XV_NULL,
			XV_NULL);
	if(!cursor)
	  {
	    /* if no drag cursor specified, use a default one */

	    static Cursor default_cursor;

	    if(!default_cursor)
	      default_cursor = xv_create(XV_NULL, CURSOR,
					 CURSOR_SRC_CHAR, OLC_COPY_PTR,
					 CURSOR_MASK_CHAR, OLC_COPY_MASK_PTR,
					 XV_NULL);
	    cursor = default_cursor;
	  }
	
	xv_set(fullscreen, WIN_CURSOR, cursor, XV_NULL);
	
	input_imnull(&im);
	win_setinputcodebit(&im, MS_LEFT);
	win_setinputcodebit(&im, LOC_DRAG);
	im.im_flags = IM_NEGEVENT;

/* this isn't needed, just haven't tested it without it being used */
	XAllowEvents(xv_get(canvas_shell, XV_DISPLAY), 
	 		SyncPointer, CurrentTime);

	do {
		xv_input_readevent(canvas_shell, drop_event, TRUE, TRUE, &im);
	} while (	!( win_inputnegevent(drop_event) 
			&& event_action(drop_event) == ACTION_SELECT));

	xv_destroy(fullscreen);

	dest_win_xid = win_pointer_under(canvas_shell, 
					 event_x(drop_event),event_y(drop_event));

	if(XTranslateCoordinates(
				 (Display *) xv_get(canvas_shell, XV_DISPLAY),
				 xv_get(canvas_shell, XV_XID),
				 (dest_win_xid? dest_win_xid:
	    /* should use xv_get(xv_get(XV_ROOT,canvas_shell), XV_XID) here */
				 DefaultRootWindow((Display *) xv_get(canvas_shell, XV_DISPLAY))),
				 event_x(drop_event), event_y(drop_event),
				 &x, &y,
				 &child) == 0)
	  return (XID) -1;

	event_x(drop_event) = x;
	event_y(drop_event) = y;

	return(dest_win_xid);
}


void
start_drag_drop(canvas_shell, rectobj)
	Canvas_shell	canvas_shell;
	Rectobj		rectobj;
{
	XID		drop_window;
	Event		drop_event;
	Xv_window	drop_paint_window;
	Canvas_shell	drop_canvas_shell;
	Rectobj		drop_rectobj;
	void		(*drop_proc)();
	Canvas_shell_info *csinfo;

	extern Attr_attribute canvas_shell_context_key;
	extern 		Rectobj event_to_rectobj();

	drop_window = do_fullscreen_drag(canvas_shell, 
			xv_get(rectobj, RECTOBJ_DRAG_CURSOR),
			&drop_event);

	if( drop_window == -1)
		return;	/* error condition */

	if( drop_window == 0 ) {
		/* this means the destination window is the root window */
		if( root_window_drop_proc != 0 )
			(*root_window_drop_proc)(canvas_shell, rectobj,
						/*destcanvas*/0, 
						/*destrectobj*/0,
						&drop_event);
		return ;
	}

	/*
	 * hack alert: 
	 *	win_number_to_object(canvas_shell, XID) is private to xview
	 *	it returns the paint window of the XID.
	 * 	V3.0 should have a public interface.
	 */
	drop_paint_window = win_number_to_object(canvas_shell, drop_window);
	if(drop_paint_window == 0)
		/*
		 * this means the destination window was in another 
		 * (because the context manager didn't know about it) 
		 * for now, ignore this.  later, when V3 is available, 
		 * we'll set up the drag and do-the-right-thing here 
		 */
		return;

	/* hack alert!
	 * this should be doable via a public interface!
	 */
	csinfo = (Canvas_shell_info*) xv_get(drop_paint_window,
				XV_KEY_DATA, canvas_shell_context_key);

	if(csinfo == 0)
		/* must not be a canvas shell */
		return;

	drop_canvas_shell = CANVAS_SHELL_PUBLIC(csinfo);
	drop_rectobj = event_to_rectobj(drop_canvas_shell, &drop_event);

	if(!xv_get(drop_rectobj, RECTOBJ_ACCEPTS_DROP)) 
		return;

	drop_proc = (void(*)()) xv_get(drop_rectobj, RECTOBJ_DROP_PROC);

	if(!drop_proc){
		Rectobj parent;
		parent = xv_get(drop_rectobj, RECTOBJ_PARENT);
		if(!parent)
			return;
		if(!xv_get(parent, RECTOBJ_ACCEPTS_CHILD_DROP))
			return;
		drop_proc = (void(*)()) xv_get(parent, RECTOBJ_CHILD_DROP_PROC);
	}

	if(drop_proc)
		(*drop_proc)(canvas_shell, rectobj,
			drop_canvas_shell, 
			drop_rectobj,
			&drop_event);

	return ;
}

#ifdef ORIGINAL_FULL_SCRN_CODE

xview_send_drag_event(src_win, cursor, fname)
    Xv_opaque	src_win, cursor;
    char *fname;

{
Xv_opaque	fullscreen, dest_win_xid;
Inputmask	im;
Event		event;
int		data[5];
Atom		drop_atom;

    fullscreen = xv_create(0, FULLSCREEN,
			FULLSCREEN_INPUT_WINDOW, 	src_win,
			FULLSCREEN_SYNC,		TRUE,
			WIN_CURSOR,			cursor,
			WIN_CONSUME_EVENTS,		WIN_MOUSE_BUTTONS, NULL,
			NULL);
    input_imnull(&im);
    win_setinputcodebit(&im, MS_LEFT);
    win_setinputcodebit(&im, LOC_DRAG);
    im.im_flags = IM_NEGEVENT;

    XAllowEvents(xv_get(src_win, XV_DISPLAY), SyncPointer, CurrentTime);
    do {
	xv_input_readevent(src_win, &event, TRUE, TRUE, &im);
    } while (!(win_inputnegevent(&event) && event_action(&event) == ACTION_SELECT));

    fullscreen_destroy(fullscreen);

    dest_win_xid = win_pointer_under(src_win, event_x(&event), event_y(&event));

    drop_atom = XInternAtom(xv_get(src_win, XV_DISPLAY), "FOOBAR", FALSE);
    XChangeProperty(xv_get(src_win, XV_DISPLAY),
		    xv_get(src_win, XV_XID), drop_atom,
		    XA_STRING, 8, PropModeReplace,
		    (Xv_opaque) fname, strlen(fname) + 1);
    data[0] = XV_POINTER_WINDOW;
    data[1] = event_x(&event);
    data[2] = event_y(&event);
    data[3] = xv_get(src_win, XV_XID);
    data[4] = drop_atom;

    xv_send_message(src_win, dest_win_xid, "XV_DO_DRAG_LOAD", 32, data, 20);
}


#endif
