/* $Revision Header *** Header built automatically - do not edit! ***********
 *
 *	(C) Copyright 1992 by Torsten Jürgeleit
 *
 *	Name .....: pointer.c
 *	Created ..: Wednesday 08-Jan-92 22:34:41
 *	Revision .: 2
 *
 *	Date        Author                 Comment
 *	=========   ====================   ====================
 *	11-Jul-92   Torsten Jürgeleit      now visible gadgets can be removed
 *					   by changing mouse pointer to
 *					   busy pointer
 *	13-Apr-92   Torsten Jürgeleit      remove menu for busy pointer
 *	08-Jan-92   Torsten Jürgeleit      Created this file!
 *
 ****************************************************************************
 *
 *	Support routines for mouse pointer
 *
 * $Revision Header ********************************************************/

	/* Includes */

#include <exec/types.h>
#include <exec/memory.h>
#include <devices/input.h>
#include <devices/inputevent.h>
#include <intuition/intuition.h>
#include <intuition/screens.h>
#ifdef AZTEC_C
#include <functions.h>   /* needed for Aztec C - prototypes and pragmas for all Amiga system functions */
#endif
#include <libraries/memwatch.h>   /* header file for memory debug link library (Fish 240) - AFTER functions.h */
#include "/render/render.h"
#include "/gadgets/gadgets.h"   /* needed for "/gadgets/imports.h" */
#include "/gadgets/imports.h"   /* protos for remove/display_visible_gadget_lists() */
#include "pointer.h"

	/* Defines for for workbench busy ballon */

#define BUSY_POINTER_WIDTH	15
#define BUSY_POINTER_HEIGHT	22
#define BUSY_POINTER_XOFFSET	-7
#define BUSY_POINTER_YOFFSET	-8

	/* Statics for for workbench busy ballon */

STATIC UWORD busy_pointer_image[] = {
	0x0000, 0x0000,

	0x0600, 0x0600,
	0x0f40, 0x0f40,
	0x3fe0, 0x3fe0,
	0x7fe0, 0x7fe0,
	0x61f0, 0x7ff0,
	0x7bf8, 0x7ff8,
	0xf7f8, 0xfff8,
	0x61fc, 0x7ffc,
	0x7f0c, 0x7ffc,
	0x3fde, 0x3ffe,
	0x7fbc, 0x7ffc,
	0x3f0c, 0x3ffc,
	0x1ff8, 0x1ff8,
	0x07f0, 0x07f0,
	0x01c0, 0x01c0,
	0x0700, 0x0700,
	0x0fc0, 0x0fc0,
	0x0680, 0x0680,
	0x0000, 0x0000,
	0x00c0, 0x00c0,
	0x00e0, 0x00e0,
	0x0040, 0x0040,

	0x0000, 0x0000
};
STATIC struct PointerData  busy_pointer_data = {
	BUSY_POINTER_WIDTH,
	BUSY_POINTER_HEIGHT,
	BUSY_POINTER_XOFFSET,
	BUSY_POINTER_YOFFSET,
	&busy_pointer_image[0]
};
	/* Change mouse pointer for given window - save old one in singly linked list */

   VOID
change_mouse_pointer(struct Window  *win, struct PointerData  *pd,
						        BOOL remove_gadgets)
{
   if (win) {
      struct PointerList  *pl;

      if (pl = AllocMem((LONG)sizeof(struct PointerList),
					  (LONG)MEMF_PUBLIC | MEMF_CLEAR)) {
	 struct Menu  *menu = NULL;

	 /* List for visible gadget lists MUST be initialized */
	 NewList((struct List *)&pl->pl_GadgetList);

	 /* If no pointer data given then use busy pointer */
	 if (!pd) {
	    pd = &busy_pointer_data;

	    /* Remove menu for busy pointer */
	    if (menu = win->MenuStrip) {
	       ClearMenuStrip(win);
	    }

	    /* Remove visible gadget lists too if requested */
	    if (remove_gadgets == TRUE) {
	       remove_visible_gadget_lists(win, &pl->pl_GadgetList);
	    }
	 }

	 /* Allocate chipmem buffer for pointer data if necessary */
	 if (!(TypeOfMem((BYTE *)pd->pd_Data) & MEMF_CHIP) &&
	     !(pl->pl_Buffer = AllocMem(pl->pl_BufferSize = (pd->pd_Height +
				  2) * 4, (LONG)MEMF_PUBLIC | MEMF_CHIP))) {
	    FreeMem(pl, (LONG)sizeof(struct PointerList));
	 } else {
	    UWORD *data;

	    /* Init pointer list */
	    pl->pl_ID   = ISUP_ID;
	    pl->pl_Menu = menu;
	    if (!pl->pl_Buffer) {
	       data = pd->pd_Data;
	    } else {
	       data = pl->pl_Buffer;
	       CopyMem((BYTE *)pd->pd_Data, (BYTE *)data, pl->pl_BufferSize);
	    }

	    /* Save old pointer data in pointer list */
	    Forbid();
	    pl->pl_Width   = win->PtrWidth;
	    pl->pl_Height  = win->PtrHeight;
	    pl->pl_XOffset = win->XOffset;
	    pl->pl_YOffset = win->YOffset;
	    pl->pl_Data    = win->Pointer;

	    /* Append old window user data ptr and set new one */
	    pl->pl_Next   = (struct PointerList *)win->UserData;
	    win->UserData = (BYTE *)pl;
	    Permit();

	    /* Install new pointer image */
	    SetPointer(win, data, (LONG)pd->pd_Height, (LONG)pd->pd_Width,
				(LONG)pd->pd_XOffset, (LONG)pd->pd_YOffset);
	 }
      }
   }
}
	/* Restore saved mouse pointer for given window - use first entry from singly linked list */

   VOID
restore_mouse_pointer(struct Window  *win)
{
   if (win) {
      struct PointerList  *pl;

      /* Get saved pointer - if no data given then use default one */
      if ((pl = (struct PointerList *)win->UserData) &&
						     pl->pl_ID == ISUP_ID) {
	 struct Menu  *menu;

	 /* Remove first pointer from list */
	 win->UserData = (BYTE *)pl->pl_Next;

	 /* Restore menu - if any */
	 if (menu = pl->pl_Menu) {
	    SetMenuStrip(win, menu);
	 }

	 /* Display visible gadgets */
	 display_visible_gadget_lists(win, &pl->pl_GadgetList);

	 /* Restore pointer image and free pointer data */
	 SetPointer(win, pl->pl_Data, (LONG)pl->pl_Height,
	    (LONG)pl->pl_Width, (LONG)pl->pl_XOffset, (LONG)pl->pl_YOffset);
	 if (pl->pl_Buffer) {
	    FreeMem(pl->pl_Buffer, pl->pl_BufferSize);
	 }
	 FreeMem(pl, (LONG)sizeof(struct PointerList));
      } else {
	 ClearPointer(win);
      }
   }
}
	/* Move mouse pointer to given position relativ to specified window */

   VOID
move_mouse_pointer(struct Window  *win, SHORT x, SHORT y, BOOL button)
{
   struct MsgPort     *port;
   struct IOStdReq    *ior;
   struct InputEvent  *ie;

   if (win && (port = CreatePort((BYTE *)NULL, 0L))) {
      if (ior = CreateStdIO(port)) {
	 if (!OpenDevice("input.device", 0L, (struct IORequest *)ior, 0L)) {
	    if (ie = AllocMem((LONG)sizeof(struct InputEvent),
					  (LONG)MEMF_PUBLIC | MEMF_CLEAR)) {
	       struct Screen  *screen = win->WScreen;

	       /* Init IO request */
	       ior->io_Command = IND_WRITEEVENT;
	       ior->io_Flags   = 0;
	       ior->io_Data    = (APTR)ie;
	       ior->io_Length  = sizeof(struct InputEvent);

	       /* Convert mouse position */
	       x += win->LeftEdge;
	       y += win->TopEdge;
	       if (!(screen->ViewPort.Modes & HIRES)) {
		  x *= 2;
	       }
	       if (!(screen->ViewPort.Modes & LACE)) {
		  y *= 2;
	       }
	       y += 2 * screen->TopEdge;

	       /* Init input event */
	       ie->ie_Class = IECLASS_POINTERPOS;
	       ie->ie_X     = x;
	       ie->ie_Y     = y;

	       /* Send IO request - if button then first button down and then up event */
	       if (button) {
		  ie->ie_Code = IECODE_LBUTTON;
		  DoIO((struct IORequest *)ior);
		  ie->ie_Code = IECODE_LBUTTON | IECODE_UP_PREFIX;
	       } else {
		  ie->ie_Code = IECODE_NOBUTTON;
	       }
	       DoIO((struct IORequest *)ior);
	       FreeMem(ie, (LONG)sizeof(struct InputEvent));
	    }
	    CloseDevice((struct IORequest *)ior);
	 }
	 DeleteStdIO(ior);
      }
      DeletePort(port);
   }
}
