/*
   Copyright 2008 Jeffrey Lee
   This file is part of WOUM.
   WOUM 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 3 of the License, or
   (at your option) any later version.
   WOUM 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 General Public License for more details.
   You should have received a copy of the GNU General Public License
   along with WOUM.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef __LIMPX_C
#define __LIMPX_C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "kernel.h"
#include "swis.h"

/* LimpX Version 1.14 */

/* To-do list...
   * Fix other (menu?) get commands to use up to date data
   * Improve user message events - custom handlers for common events
   * Validation string manipulation
   * Add any other handy functions
   * Perhaps make menu code automatically update RO block?
   * Make settext not shrink text for rot_size objects?
   * Fix null string bugs
*/

/* Include header so that there is only one set of defines to look after */
#include "limpx.h"

#define __LIMPX_MEMTHRESHOLD 64

/*

				GENERIC STRUCTURES

*/


/* #define DEBUG */

#ifdef DEBUG
extern FILE *debuglog;
#endif

typedef struct {
	int minx;
	int miny;
	int maxx;
	int maxy;
} obj_size;

typedef struct {
	char title_for,title_back,work_for,work_back;
} obj_cols;

typedef struct {
	char width0,width1,height0,height1;
} obj_min_size;

static void oms_setwidth(obj_min_size *s,int w)
{
	s->width0 = w & 0xFF;
	s->width1 = (w & 0xFF00) >> 8;
}

static void oms_setheight(obj_min_size *s,int h)
{
	s->height0 = h & 0xFF;
	s->height1 = (h & 0xFF00) >> 8;
}

static int oms_getwidth(obj_min_size *s)
{
	return s->width0+(s->width1 << 8);
}

static int oms_getheight(obj_min_size *s)
{
	return s->height0+(s->height1 << 8);
}

typedef union {
	char c[12]; /* Easier than having lots of different types unioned */
	int i[3];
	char *p[3];
} icon_data;

/*

				LIMPX STRUCTURES

*/

struct _limpx_window;

typedef struct _limpx_icon {
	int ro_window; /* RISC OS window handle */
	struct _limpx_window *lx_window; /* LimpX window object ptr */
	struct _limpx_icon *next,*prev; /* Stored in linked lists */
	char *text; /* Pointers and buffer sizes for use with indirected data */
	int t_size;
	int rot_size; /* size we pass to RISC OS - max length the user can enter */
	char *validation;
	int v_size;
	int spriteblock; /* Make indirected sprite icons easier to handle */
	int spriteptr; /* For ones without sprite ptr, use the text as if it's non indirected */
	int pos,priority; /* For iconbar icons */
	int ro_handle;
} limpx_icon;

typedef struct _limpx_window {
	limpx_icon *icons;
	int ro_handle; /* RISC OS window handle */
	int numicons; /* Our count of how many icons */
	struct _limpx_window *next,*prev; /* Linked list */
	char *text; /* Title text */
	int t_size;
	char *validation; /* Title validation */
	int v_size;
	int spriteblock;
	int spriteptr;
	char *fonts; /* Font array */
} limpx_window;

struct _limpx_menu_item;

typedef struct _limpx_menu {
	int *ro_block; /* RISC OS menu block ptr */
	int b_size; /* Size allocated for block */
	int numitems;
	char *text; /* Indirected data... */
	int t_size;
	char *validation;
	int v_size;
	obj_cols cols;
	int width,height,gap;
	int flags;
	struct _limpx_menu *next,*prev;
	struct _limpx_menu_item *items;
} limpx_menu;

typedef struct _limpx_menu_item {
	char *text; /* Indirected data... */
	int t_size;
	int rot_size;
	char *validation;
	int v_size;
	int spriteblock;
	int spriteptr;
	int itemf,iconf; /* Flags */
	limpx_menu *submenu; /* If null, use subwindow */
	limpx_window *subwindow;
	limpx_menu *lx_menu; /* Our owner */
	struct _limpx_menu_item *next,*prev;
} limpx_menu_item;

typedef struct {
	int code;
	int block[64];
} limpx_pollblock;

struct _limpx_window_state;
struct _limpx_mouse_obj;
struct _limpx_caret_obj;

typedef union {
	int (*null_code) (void);
	int (*redraw_window) (limpx_window *win);
	int (*open_window) (limpx_window *win,struct _limpx_window_state *pos);
	int (*close_window) (limpx_window *win);
	int (*pointer_leave) (limpx_window *win);
	int (*pointer_enter) (limpx_window *win);
	int (*mouse_click) (struct _limpx_mouse_obj *mouse,limpx_window *win,limpx_icon *icon);
	int (*drag_box) (int minx,int miny,int maxx,int maxy); /* Add task,window,icon info? */
	int (*key_pressed) (struct _limpx_caret_obj *c,int key);
	int (*menu_selection) (int *selections); /* Add menu object ptr! */
	int (*scroll_request) (limpx_window *win,struct _limpx_window_state *pos,int xdir,int ydir);
	int (*lose_caret) (struct _limpx_caret_obj *c);
	int (*gain_caret) (struct _limpx_caret_obj *c);
	int (*poll_nonzero) (void);
	int (*user_message) (int code,int *block);
	int (*other_event) (int code,int *block);
	int foo_event;
} limpx_event_func;

typedef struct _limpx_event {
	int code;
	int flags;
	int criteria[8]; /* Should be enough */
	struct _limpx_event *next,*prev;
	limpx_event_func func;
} limpx_event;

static struct {
	limpx_menu *menus;
	limpx_window *windows;
	limpx_icon *icons; /* For icons not bound to a limpx window */
	limpx_event *events;
	_kernel_swi_regs r;
	limpx_pollblock block;
	int abflag; /* Set to non-zero to abort a wimp poll cycle */
	int task; /* Task handle */
	int sb[64];
	/* blah blah blah */
} limpx;

/*

				USER STRUCTURES

*/

typedef struct
{
	int ro_handle; /* Window */
	obj_size vis;
	int scrollx,scrolly;
	obj_size redraw;
} limpx_redraw_obj;

typedef struct _limpx_mouse_obj
{
	int x,y;
	int buttons;
	int window; /* Need to also add lx object pointers */
	int icon;
} limpx_mouse_obj;

typedef struct _limpx_caret_obj
{
	int window;
	int icon;
	int x,y;
	int height;
	int index;
} limpx_caret_obj;

typedef struct
{
	int col[16];
	int border;
	int mouse[3];
} limpx_pal;

typedef struct
{
	int xmul;
	int ymul;
	int xdiv;
	int ydiv;
} limpx_scalefact;

typedef struct
{
	char col[16];
} limpx_coltran;

typedef struct _limpx_window_state
{
	obj_size vis;
	int scrollx,scrolly;
	int behind;
	int flags;
} limpx_window_state;

typedef struct {
	obj_size vis; /* RISC OS data block */
	int scrollx;
	int scrolly;
	int behind;
	int flags;
	obj_cols col;
	char scroll_outer,scroll_inner,title_focus,zero;
	obj_size work;
	int title_flags;
	int work_flags;
	int sprite_block;
	obj_min_size mins;
	icon_data title;
	int numicons;
} limpx_window_header;

typedef struct {
	obj_size size;
	int flags;
	icon_data data;
} limpx_icon_block;

typedef struct {
	char fonts[256];
	limpx_window_header *window;
} limpx_window_fheader;

/*

				LIMPX FUNCTIONS

*/

static void jstrcpy(char *str1,char *str2)
{
	/* Copy string, accepting terminators as anything below 32
	   Also handle 0 & -1 pointers */
	int i;
	i = 0;
	if (((int) str2 == 0) || ((int) str2 == -1))
	{
		str1[0] = 0;
		return;
	}
	while (str2[i] >= 32)
	{
		str1[i] = str2[i];
		i++;
	}
	str1[i] = 0;
}

static void jstrncpy(char *str1,char *str2,int n)
{
	int i;
	i = 0;
	if (((int) str2 != 0) && ((int) str2 != -1))
		while (str2[i] >= 32)
		{
			str1[i] = str2[i];
			i++;
			if (n == i)
				return;
		}
	while (i < n)
	{
		str1[i] = 0;
		i++;
	}
}

static int jstrlen(char *str)
{
	/* Return string length, 0=null */
	int n;
	n = 0;
	if (((int) str == 0) || ((int) str == -1))
		return 0;
	while (str[n] >= 32)
		n++;
	return n;
}

static limpx_window *_LimpX_NewWindow()
{
	limpx_window *w;
	int i;
	w = (limpx_window *) malloc(sizeof(limpx_window));
	w->icons = (limpx_icon *) NULL;
	w->ro_handle = 0;
	w->numicons = 0;
	w->next = limpx.windows;
	w->prev = (limpx_window *) NULL;
	limpx.windows = w;
	if (w->next != NULL)
		w->next->prev = w;
	w->text = (char *) NULL;
	w->t_size = 0;
	w->validation = (char *) NULL;
	w->v_size = 0;
	w->spriteblock = 1; /* ** different from sprite_block! ** */
	w->spriteptr = (int) NULL;
	w->fonts = (char*) malloc(sizeof(char)*256);
	for (i=0;i<256;i++)
		w->fonts[i] = 0;
	return w;
}

static limpx_icon *_LimpX_NewIcon()
{
	/* Create new icon, but don't link to anything */
	limpx_icon *i;
	i = (limpx_icon *) malloc(sizeof(limpx_icon));
	i->ro_window = 0;
	i->lx_window = (limpx_window *) NULL;
	i->next = i->prev = (limpx_icon *) NULL;
	i->text = (char *) NULL;
	i->t_size = i->rot_size = 0;
	i->validation = (char *) NULL;
	i->v_size = 0;
	i->spriteblock = 1;
	i->spriteptr = (int) NULL;
	i->pos = i->priority = 0;
	i->ro_handle = -1; /* Icon handle of -1 is the work area, .'. icon hasn't been created yet */
	return i;
}

static limpx_menu *_LimpX_NewMenu()
{
	limpx_menu *m;
	m = (limpx_menu*) malloc(sizeof(limpx_menu));
	m->ro_block = NULL; /* Have no block if there are no items */
	m->b_size = 0;
	m->numitems = 0;
	m->next = limpx.menus;
	m->prev = (limpx_menu *) NULL;
	m->text = m->validation = (char *) NULL;
	m->t_size = m->v_size = 0;
	m->cols.title_for = 7;
	m->cols.title_back = 2;
	m->cols.work_for = 7;
	m->cols.work_back = 0;
	m->width = 0;
	m->height = 44;
	m->gap = 0;
	m->flags = 0;
	limpx.menus = m;
	m->items = (limpx_menu_item *) NULL;
	if (m->next != NULL)
		m->next->prev = m;
	return m;
}

static limpx_menu_item *_LimpX_NewMenuItem(limpx_menu *m)
{
	limpx_menu_item *i,*p;
	i = (limpx_menu_item*) malloc(sizeof(limpx_menu_item));
	/* Need to create item at end of list... */
	i->prev = i->next = (limpx_menu_item *) NULL;
	p = m->items;
	if (p != NULL)
		while (p->next != NULL)
			p = p->next;
	i->prev = p;
	if (p != NULL)
		p->next = i;
	else
		m->items = i;
	m->numitems++;
	i->lx_menu = m;
	i->submenu = (limpx_menu *) NULL;
	i->subwindow = (limpx_window *) NULL;
	i->itemf = i->iconf = 0;
	i->t_size = i->rot_size = i->v_size = 0;
	i->text = i->validation = (char *) NULL;
	i->spriteblock = 1;
	i->spriteptr = (int) NULL;
	return i;
}

static limpx_menu_item *_LimpX_GetMenuItem(limpx_menu *m,int i)
{
	limpx_menu_item *it;
	it = m->items;
	while (i > 0)
	{
		i--;
		it = it->next;
	}
	return it;
}

static limpx_event *_LimpX_NewEvent()
{
	limpx_event *e;
	e = (limpx_event*) malloc(sizeof(limpx_event));
	e->next = limpx.events;
	e->prev = (limpx_event *) NULL;
	if (e->next != NULL)
		e->next->prev = e;
	e->code = 0;
	e->flags = 0;
	e->func.foo_event = (int) NULL;
	limpx.events = e;
	return e;
}

int LimpX_GetWindow_Icons(limpx_window *w);

static int *_LimpX_GetWindow(limpx_window *w)
{
	int *block;
	int i,c;
	i = 23+LimpX_GetWindow_Icons(w)*8;
	block = (int*) malloc(sizeof(int)*i);
	limpx.r.r[1] = (int) block;
	block[0] = w->ro_handle;
	_kernel_swi(Wimp_GetWindowInfo,&limpx.r,&limpx.r);
	for (c=1;c<i;c++)
		block[c-1] = block[c]; /* Shift down 1 to remove window header */
#ifdef DEBUG
	fprintf(debuglog,"_limpx_getwindow(%x)->%x: I say %d, wimp says %d\n",(int) w,(int) block,(i-23)/8,block[21]);
#endif
	return block;
}

static void _LimpX_RecreateWindow(limpx_window *w,int *block)
{
	limpx_icon *ic;
	int h;
/* #ifdef DEBUG
	int *tb;
	tb = _LimpX_GetWindow(w);
	fprintf(debuglog,"_limpx_recreatewindow: Before:\n");
	for (h=0;h<22+tb[21]*8;h++)
		fprintf(debuglog,"  block[%d]=%x\n",h,tb[h]);
	free(tb);
	fprintf(debuglog,"_limpx_recreatewindow: Desired (%x):\n",(int) block);
	for (h=0;h<22+block[21]*8;h++)
		fprintf(debuglog,"  block[%d]=%x\n",h,block[h]);
#endif */
	limpx.sb[0] = w->ro_handle;
	limpx.r.r[1] = (int) limpx.sb;
	_kernel_swi(Wimp_DeleteWindow,&limpx.r,&limpx.r);
	limpx.r.r[1] = (int) block;
	_kernel_swi(Wimp_CreateWindow,&limpx.r,&limpx.r);
	h = limpx.r.r[0];
	if (h != w->ro_handle)
	{
		ic = w->icons;
		while (ic != NULL)
		{
			ic->ro_window = h;
			ic = ic->next;
		}
		w->ro_handle = h;
		/* ** change other stuff? ** */
	}
	/* Check if window should be reopened */
	if (block[7] & LIMPX_WINFLAG_ISOPEN)
	{
		memcpy(&limpx.sb[1],block,28);
		limpx.sb[0] = w->ro_handle;
		limpx.r.r[1] = (int) limpx.sb;
		_kernel_swi(Wimp_OpenWindow,&limpx.r,&limpx.r);
	}
	free(block);
/* #ifdef DEBUG
	tb = _LimpX_GetWindow(w);
	fprintf(debuglog,"_limpx_recreatewindow: After:\n");
	for (h=0;h<22+tb[21]*8;h++)
		fprintf(debuglog,"  block[%d]=%x\n",h,tb[h]);
	free(tb);
#endif */
}

static void _LimpX_GetIcon(limpx_icon *i,limpx_icon_block *block)
{
	limpx.sb[0]=i->ro_window;
	limpx.sb[1]=i->ro_handle;
	limpx.r.r[1]=(int) limpx.sb;
	_kernel_swi(Wimp_GetIconState,&limpx.r,&limpx.r);
	memcpy(block,&limpx.sb[2],32);
}

static void _LimpX_RecreateIcon(limpx_icon *i,limpx_icon_block *ic) /* ** can also be used for first time creation ** */
{
	int block[9];
	int *win;
	if (i->pos == 0)
	{
/*#ifdef DEBUG
		fprintf(debuglog,"_limpx_recreateicon: %x of %x is bound to window\n",(int) i,(int) i->lx_window);
		fprintf(debuglog,"Passing handle %d\n",i->ro_handle);
#endif */
		/* Bound to a window... */
/*		block[0] = i->ro_window;
		limpx.r.r[0] = i->ro_handle;
		limpx.r.r[1] = (int) block;
		_kernel_swi(Wimp_CreateIcon,&limpx.r,&limpx.r);
		i->ro_handle = limpx.r.r[0]; */
		/* Need to get the window block then add the icon manually */
		/* w->numicons should be the correct number of icons, so just use _limpx_getwindow */
		win = _LimpX_GetWindow(i->lx_window);
		/* Now stick the definition into it */
		win[21] = i->lx_window->numicons;
		memcpy(&win[22+(i->ro_handle*8)],ic,32);
		/* And update window */
		_LimpX_RecreateWindow(i->lx_window,win);
/* #ifdef DEBUG
		fprintf(debuglog,"Got back handle %d\n",i->ro_handle);
#endif */
	}
	else
	{
		/* On the iconbar */
		memcpy(&block[1],ic,32); /* Copy icon block */
		if (i->ro_handle == -1) /* Not created yet */
		{
/* #ifdef DEBUG
			fprintf(debuglog,"_limpx_recreateicon: %x is on iconbar, not created yet\n",(int) i);
#endif */
			block[0] = i->pos;
			limpx.r.r[0] = i->priority;
			limpx.r.r[1] = (int) block;
			_kernel_swi(Wimp_CreateIcon,&limpx.r,&limpx.r);
			i->ro_handle = limpx.r.r[0];
		}
		else
		{
/* #ifdef DEBUG
			fprintf(debuglog,"_limpx_recreateicon: %x is on iconbar, been created\n",(int) i);
#endif */
			if (i->pos & 1)
				block[0] = -4;
			else
				block[0] = -3;
			limpx.r.r[0] = i->ro_handle;
			limpx.r.r[1] = (int) block;
			_kernel_swi(Wimp_CreateIcon,&limpx.r,&limpx.r);
			i->ro_handle = limpx.r.r[0];
		}
	}
}

static int _LimpX_EventHandler();
static void _LimpX_DeleteWindowEvents(limpx_window *w);
static void _LimpX_DeleteIconEvents(limpx_icon *i);

/*

				USER FUNCTIONS

*/

int LimpX_Initialise(char *name)
{
	_kernel_oserror *err;
	limpx.r.r[0]=310;
	limpx.r.r[1]=0x4B534154;
	limpx.r.r[2]=(int) name;
	limpx.abflag = 0;
	limpx.r.r[3]= (int) &limpx.abflag; /* Accept all messages */
	err = _kernel_swi(Wimp_Initialise,&limpx.r,&limpx.r);
	if (err)
	{
		_kernel_raise_error(err);
		exit(1);
	}
	limpx.task = limpx.r.r[1];
	limpx.menus = (limpx_menu *) NULL;
	limpx.windows = (limpx_window *) NULL;
	limpx.icons = (limpx_icon *) NULL;
	limpx.events = (limpx_event *) NULL;
	return limpx.r.r[1];
}

void LimpX_OpenTemplate(char *name)
{
	limpx.r.r[1] = (int) name;
	_kernel_swi(Wimp_OpenTemplate,&limpx.r,&limpx.r);
}

limpx_window_header *LimpX_LoadTemplate(char *name)
{
	/* Need to: */
	/* Load template into memory */
	/* Return pointer to data */
	/* Ignore fonts for now */
	char *buff;
	int winsize,indsize;
	char n[13];
	jstrcpy(n,name);
	limpx.r.r[1]=0;
	limpx.r.r[4]=-1;
	limpx.r.r[5]=(int) n;
	limpx.r.r[6]=0;
	_kernel_swi(Wimp_LoadTemplate,&limpx.r,&limpx.r);
	winsize=limpx.r.r[1];
	indsize=limpx.r.r[2];
	buff=(char*) malloc(sizeof(char)*(winsize+indsize));
	jstrcpy(n,name);
	limpx.r.r[1]=(int) buff;
	limpx.r.r[2]=limpx.r.r[1] + winsize; /* Stick indirected data onto the end of the block */
	limpx.r.r[3]=limpx.r.r[2] + indsize;
	limpx.r.r[5]=(int) n;
	limpx.r.r[6]=0;
	_kernel_swi(Wimp_LoadTemplate,&limpx.r,&limpx.r);
	return (limpx_window_header *) buff;
}

limpx_window_fheader *LimpX_LoadTemplateWithFonts(char *name)
{
	/* Need to: */
	/* Load template into memory */
	/* Return pointer to data */
	/* Ignore fonts for now */
	char *buff;
	int winsize,indsize;
	char n[13];
	limpx_window_fheader *h;
	h = (limpx_window_fheader*) malloc(sizeof(limpx_window_fheader));
	jstrcpy(n,name);
	limpx.r.r[1]=0;
	limpx.r.r[4]=-1;
	limpx.r.r[5]=(int) &h->fonts;
	limpx.r.r[6]=0;
	_kernel_swi(Wimp_LoadTemplate,&limpx.r,&limpx.r);
	winsize=limpx.r.r[1];
	indsize=limpx.r.r[2];
	buff=(char*) malloc(sizeof(char)*(winsize+indsize));
	jstrcpy(n,name);
	limpx.r.r[1]=(int) buff;
	limpx.r.r[2]=limpx.r.r[1] + winsize; /* Stick indirected data onto the end of the block */
	limpx.r.r[3]=limpx.r.r[2] + indsize;
	limpx.r.r[5]=(int) n;
	limpx.r.r[6]=0;
	_kernel_swi(Wimp_LoadTemplate,&limpx.r,&limpx.r);
	h->window = (limpx_window_header *) buff;
	return h;
}

void LimpX_KillTemplate(limpx_window_header *h)
{
	free(h);
}

void LimpX_KillTemplateWithFonts(limpx_window_fheader *h)
{
	free(h->window);
	free(h);
}

void LimpX_CloseTemplate()
{
	_kernel_swi(Wimp_CloseTemplate,&limpx.r,&limpx.r);
}

limpx_icon *LimpX_NewIcon(limpx_window *w,limpx_icon_block *block);

limpx_window *LimpX_CreateWindow(limpx_window_header *origblock) /* Taken as header * here, but can include icons too */
{
	limpx_window *w;
	int *ib;
	int icons;
	limpx_window_header *block;
	/* Make copy of window block */
	block = (limpx_window_header *) malloc(4*(23+origblock->numicons*8));
	memcpy(block,origblock,4*(23+origblock->numicons*8));
	w = _LimpX_NewWindow();
	/* Set up data... */
	/* First title data */
	switch (block->title_flags & 259)
	{
		case 1:
		case 2:
		case 3:
			w->text = (char*) malloc(sizeof(char)*13);
			w->t_size = 12;
			jstrncpy(w->text,block->title.c,12);
			w->text[12] = 0;
			break;
		case 257:
		case 259:
			w->text = (char *) malloc(sizeof(char)*(block->title.i[2]+1));
			w->t_size = block->title.i[2];
			jstrcpy(w->text,block->title.p[0]);
			block->title.p[0] = w->text;
			w->validation = (char*) malloc(sizeof(char)*(jstrlen(block->title.p[1])+1));
			w->v_size = jstrlen(block->title.p[1]);
			jstrcpy(w->validation,block->title.p[1]);
			block->title.p[1] = w->validation;
			break;
		case 258:
			if (block->title.i[2] == 0)
				w->spriteptr = block->title.i[0];
			else
			{
				w->text = (char*) malloc(sizeof(char)*(block->title.i[2]+1));
				w->t_size = block->title.i[2];
				jstrcpy(w->text,block->title.p[0]);
				block->title.p[0] = w->text;
			}
			w->spriteblock = block->title.i[1];
	}
	icons = block->numicons;
	block->numicons = 0; /* Allow icons to be created by us */
	limpx.r.r[1] = (int) block;
	_kernel_swi(Wimp_CreateWindow,&limpx.r,&limpx.r);
	w->ro_handle = limpx.r.r[0];
	while (icons > 0)
	{
		ib = &(((int *) block)[22+(w->numicons*8)]); /* Go by current number of icons in window */
		LimpX_NewIcon(w,(limpx_icon_block *) ib);
		icons--;
	}
	free(block);
	return w;
}

limpx_window *LimpX_CreateWindowWithFonts(limpx_window_fheader *h)
{
	limpx_window *w;
	int n;
	w = LimpX_CreateWindow(h->window);
	for (n=0;n<256;n++)
		w->fonts[n] = h->fonts[n];
	return w;
}

limpx_icon *LimpX_NewIcon(limpx_window *w,limpx_icon_block *origblock)
{
	/* Create icon bound to LX window */
	limpx_icon *i,*p;
	limpx_icon_block *block;
	block = (limpx_icon_block*) malloc(sizeof(limpx_icon_block));
	memcpy(block,origblock,32);
	i = w->icons;
	p = NULL;
	while (i != NULL)
	{
		p = i;
		i=i->next; /* Find end of chain */
	}
	i = _LimpX_NewIcon();
	if (p != NULL)
	{
		p->next = i;
		i->prev = p;
	}
	else
		w->icons = i;
	i->ro_handle = w->numicons;
	w->numicons++;
	i->lx_window = w;
	i->ro_window = w->ro_handle;
	/* Now copy icon data, and copy text/validation into own area - is likely to change the users icon block!! */
	switch (block->flags & 259)
	{
		case 1:
		case 2:
		case 3:
			i->text = (char*) malloc(sizeof(char)*13);
			i->t_size = i->rot_size = 12;
			jstrncpy(i->text,block->data.c,12);
			i->text[12] = 0;
			break;
		case 257:
		case 259:
			i->text = (char*) malloc(sizeof(char)*(block->data.i[2]+1));
			i->t_size = i->rot_size = block->data.i[2];
			jstrcpy(i->text,block->data.p[0]);
			block->data.p[0] = i->text;
			i->validation = (char*) malloc(sizeof(char)*(jstrlen(block->data.p[1])+1));
			i->v_size = jstrlen(block->data.p[1]);
			jstrcpy(i->validation,block->data.p[1]);
			block->data.p[1] = i->validation;
			break;
		case 258:
			if (block->data.i[2] == 0)
				i->spriteptr = block->data.i[0];
			else
			{
				i->text = (char*) malloc(sizeof(char)*(block->data.i[2]+1));
				i->t_size = i->rot_size = block->data.i[2];
				jstrcpy(i->text,block->data.p[0]);
				block->data.p[0] = i->text;
			}
			i->spriteblock = block->data.i[1];
	}
	_LimpX_RecreateIcon(i,block);
	free(block);
	return i;
}

limpx_icon *LimpX_NewIconBarIcon(int pos,int priority,limpx_icon_block *origblock)
{
	/* Create new iconbar icon */
	limpx_icon *i;
	limpx_icon_block *block;
	block = (limpx_icon_block*) malloc(sizeof(limpx_icon_block));
	memcpy(block,origblock,32);
	i = _LimpX_NewIcon();
	i->next = limpx.icons;
	limpx.icons = i;
	if (i->next != NULL)
		i->next->prev = i;
	i->pos = pos;
	i->priority = priority;
	i->ro_window = -2; /* Iconbar! */
	/* Now copy icon data, and copy text/validation into own area - is likely to change the users icon block!! */
	switch (block->flags & 259)
	{
		case 1:
		case 2:
		case 3:
			i->text = (char*) malloc(sizeof(char)*13);
			i->t_size = i->rot_size = 12;
			jstrncpy(i->text,block->data.c,12);
			i->text[12] = 0;
			break;
		case 257:
		case 259:
			i->text = (char*) malloc(sizeof(char)*(block->data.i[2]+1));
			i->t_size = i->rot_size = block->data.i[2];
			jstrcpy(i->text,block->data.p[0]);
			block->data.p[0] = i->text;
			i->validation = (char*) malloc(sizeof(char)*(jstrlen(block->data.p[1])+1));
			i->v_size = jstrlen(block->data.p[1]);
			jstrcpy(i->validation,block->data.p[1]);
			block->data.p[1] = i->validation;
			break;
		case 258:
			if (block->data.i[2] == 0)
				i->spriteptr = block->data.i[0];
			else
			{
				i->text = (char*) malloc(sizeof(char)*(block->data.i[2]+1));
				i->t_size = i->rot_size = block->data.i[2];
				jstrcpy(i->text,block->data.p[0]);
				block->data.p[0] = i->text;
			}
			i->spriteblock = block->data.i[1];
	}
	_LimpX_RecreateIcon(i,block);
	free(block);
	return i;
}

void LimpX_DeleteWindow(limpx_window *w)
{
	limpx_icon *i,*next;
	int n;
	_LimpX_DeleteWindowEvents(w);
	/* Delete window, from LX and RO */
	if (w->ro_handle != 0)
	{
		limpx.sb[0]=w->ro_handle;
		limpx.r.r[1]=(int) limpx.sb;
		_kernel_swi(Wimp_DeleteWindow,&limpx.r,&limpx.r);
	}
	i = w->icons;
	while (i != NULL)
	{
		next = i->next;
		if (i->text != NULL)
			free(i->text);
		if (i->validation != NULL)
			free(i->validation);
		free(i);
		i = next;
	}
	if (w->text != NULL)
		free(w->text);
	if (w->validation != NULL)
		free(w->validation);
	/* Free fonts */
	if (w->fonts != NULL)
	{
		for(n=0;n<256;n++)
		{
			while (w->fonts[n] > 0)
			{
				limpx.r.r[0] = n;
				_kernel_swi(Font_LoseFont,&limpx.r,&limpx.r);
				w->fonts[n]--;
			}
		}
		free(w->fonts);
	}
	if (w->next != NULL)
		w->next->prev = w->prev;
	if (w->prev != NULL)
		w->prev->next = w->next;
	else
		limpx.windows = w->next;
	free(w);
}

void LimpX_DeleteIcon(limpx_icon *i)
{
	limpx_icon *ic;
	int c;
	_LimpX_DeleteIconEvents(i);
	if (i->ro_handle != -1)
	{
		if (i->pos == 0)
			limpx.sb[0]=i->ro_window;
		else
			limpx.sb[0]=-2;
		limpx.sb[1]=i->ro_handle;
		limpx.r.r[1]=(int) limpx.sb;
		_kernel_swi(Wimp_DeleteIcon,&limpx.r,&limpx.r);
	}
	if (i->prev != NULL)
		i->prev->next = i->next; /* Middle of a list */
	else if (i->lx_window != NULL)
		i->lx_window->icons = i->next; /* Start of window icon list */
	else
		limpx.icons = i->next; /* Misc icon list */
	if (i->next != NULL)
		i->next->prev = i;
	if (i->lx_window != NULL)
	{
		i->lx_window->numicons--;
		ic = i->lx_window->icons; /* Renumber other icons */
		c=0;
		while (ic != NULL)
		{
			ic->ro_handle = c;
			c++;
			ic=ic->next;
		}
	}
	/* Now delete indirected data */
	if (i->text != NULL)
		free(i->text);
	if (i->validation != NULL)
		free(i->validation);
	free(i);
}

limpx_window_state LimpX_GetWindowState(limpx_window *w);

void LimpX_OpenWindow(limpx_window *w)
{
	/* Plain open window at current pos */
	limpx_window_state p;
	p = LimpX_GetWindowState(w);
#ifdef DEBUG
	fprintf(debuglog,"LimpX_OpenWindow: %X",w->ro_handle);
	fprintf(debuglog," (%d,%d),(%d,%d)",p.vis.minx,p.vis.miny,p.vis.maxx,p.vis.maxy);
	fprintf(debuglog," (%d,%d),%X\n",p.scrollx,p.scrolly,p.behind);
#endif
	limpx.sb[0]=w->ro_handle;
	limpx.sb[1]=p.vis.minx;
	limpx.sb[2]=p.vis.miny;
	limpx.sb[3]=p.vis.maxx;
	limpx.sb[4]=p.vis.maxy;
	limpx.sb[5]=p.scrollx;
	limpx.sb[6]=p.scrolly;
	limpx.sb[7]=p.behind;
	limpx.r.r[1]=(int) limpx.sb;
	_kernel_swi(Wimp_OpenWindow,&limpx.r,&limpx.r);
}

void LimpX_OpenWindowAt(limpx_window *w,limpx_window_state p)
{
	limpx.sb[0]=w->ro_handle;
	limpx.sb[1]=p.vis.minx;
	limpx.sb[2]=p.vis.miny;
	limpx.sb[3]=p.vis.maxx;
	limpx.sb[4]=p.vis.maxy;
	limpx.sb[5]=p.scrollx;
	limpx.sb[6]=p.scrolly;
	limpx.sb[7]=p.behind;
	limpx.r.r[1]=(int) &limpx.sb;
	_kernel_swi(Wimp_OpenWindow,&limpx.r,&limpx.r);
}

void LimpX_CloseWindow(limpx_window *w)
{
	limpx.sb[0]=w->ro_handle;
	limpx.r.r[1]=(int) limpx.sb;
	_kernel_swi(Wimp_CloseWindow,&limpx.r,&limpx.r);
}

int LimpX_RedrawWindow(limpx_redraw_obj *r)
{
	limpx.r.r[1] = (int) r;
	_kernel_swi(Wimp_RedrawWindow,&limpx.r,&limpx.r);
	return limpx.r.r[0];
}

int LimpX_UpdateWindow(limpx_redraw_obj *r)
{
	limpx.r.r[1] = (int) r;
	_kernel_swi(Wimp_UpdateWindow,&limpx.r,&limpx.r);
	return limpx.r.r[0];
}

int LimpX_GetRectangle(limpx_redraw_obj *r)
{
	limpx.r.r[1] = (int) r;
	_kernel_swi(Wimp_GetRectangle,&limpx.r,&limpx.r);
	return limpx.r.r[0];
}

limpx_window_state LimpX_GetWindowState(limpx_window *w)
{
	struct {int i; limpx_window_state s;} s;
	/* Update window block */
	s.i = w->ro_handle;
	limpx.r.r[1] = (int) &s;
	_kernel_swi(Wimp_GetWindowState,&limpx.r,&limpx.r);
	return s.s;
}

limpx_window_header *LimpX_GetWindowInfo(limpx_window *w,int f)
{
	/* Get window info, if f=1 then dont get icons */
	/* If f=0, then call with f=1 to get how many icons there are so that correct memory can be allocated */
	int *block;
	int t;
	limpx_window_header *h;
	block = (int*) malloc(sizeof(limpx_window_header)+4);
	if (f != 0)
	{
		limpx.r.r[1]=((int) block) | f;
		block[0]=w->ro_handle;
		_kernel_swi(Wimp_GetWindowInfo,&limpx.r,&limpx.r);
		h = malloc(sizeof(limpx_window_header));
		memcpy(h,block+1,sizeof(limpx_window_header));
		free(block);
		return h;
	}
	limpx.r.r[1]=((int) block) | 1;
	block[0]=w->ro_handle;
	_kernel_swi(Wimp_GetWindowInfo,&limpx.r,&limpx.r);
	t = block[22];
	free(block);
	block = (int*) malloc(sizeof(limpx_window_header)+4 + 32*t);
	limpx.r.r[1]=(int) block;
	block[0]=w->ro_handle;
	_kernel_swi(Wimp_GetWindowInfo,&limpx.r,&limpx.r);
	h = malloc(sizeof(limpx_window_header)+32*t);
	memcpy(h,block+1,sizeof(limpx_window_header)+32*t);
	free(block);
	return h;
}

void LimpX_SetIconState(limpx_icon *i,int e,int c)
{
	limpx.sb[0]=i->ro_window;
	limpx.sb[1]=i->ro_handle;
	limpx.sb[2]=e;
	limpx.sb[3]=c;
	limpx.r.r[1]=(int) limpx.sb;
	_kernel_swi(Wimp_SetIconState,&limpx.r,&limpx.r);
}

void LimpX_GetIconState(limpx_icon *i,limpx_icon_block *b)
{
	_LimpX_GetIcon(i,b);
}

void LimpX_GetPointerInfo(limpx_mouse_obj *m)
{
	limpx.r.r[1] = (int) m;
	_kernel_swi(Wimp_GetPointerInfo,&limpx.r,&limpx.r);
}

void LimpX_DragBox(limpx_window *w,int type,int minx,int miny,int maxx,int maxy,int pminx,int pminy,int pmaxx,int pmaxy,int r12,int drawbox,int rembox,int movebox)
{
	int block[14];
	if (w != NULL)
		block[0] = w->ro_handle;
	block[1] = type;
	block[2] = minx;
	block[3] = miny;
	block[4] = maxx;
	block[5] = maxy;
	block[6] = pminx;
	block[7] = pminy;
	block[8] = pmaxx;
	block[9] = pmaxy;
	block[10] = r12;
	block[11] = drawbox;
	block[12] = rembox;
	block[13] = movebox;
	limpx.r.r[1]=(int) block;
	_kernel_swi(Wimp_DragBox,&limpx.r,&limpx.r);
}

void LimpX_DragBoxBlk(int *block)
{
	limpx.r.r[1]=(int) block;
	_kernel_swi(Wimp_DragBox,&limpx.r,&limpx.r);
}

void LimpX_ForceRedraw(limpx_window *w,int minx,int miny,int maxx,int maxy)
{
	if (w == NULL)
		limpx.r.r[0]=-1;
	else
		limpx.r.r[0]=w->ro_handle;
	limpx.r.r[1]=minx;
	limpx.r.r[2]=miny;
	limpx.r.r[3]=maxx;
	limpx.r.r[4]=maxy;
	_kernel_swi(Wimp_ForceRedraw,&limpx.r,&limpx.r);
}

void LimpX_SetCaretPosition(limpx_window *w,limpx_icon *i,int x,int y,int h,int p)
{
	if (w == NULL)
		limpx.r.r[0] = -1;
	else
		limpx.r.r[0]=w->ro_handle;
	if (i == NULL)
		limpx.r.r[1] = -1;
	else
		limpx.r.r[1]=i->ro_handle;
	limpx.r.r[2]=x;
	limpx.r.r[3]=y;
	limpx.r.r[4]=h;
	limpx.r.r[5]=p;
	_kernel_swi(Wimp_SetCaretPosition,&limpx.r,&limpx.r);
}

void LimpX_SetCaretPositionBlk(limpx_caret_obj *c)
{
	_kernel_swi(Wimp_SetCaretPosition,(_kernel_swi_regs *) c,&limpx.r);
}

void LimpX_GetCaretPosition(limpx_caret_obj *c)
{
	limpx.r.r[1] = (int) c;
	_kernel_swi(Wimp_GetCaretPosition,&limpx.r,&limpx.r);
}

limpx_menu *LimpX_NewMenu()
{
	limpx_menu *m;
	m = _LimpX_NewMenu();
	return m;
}

void LimpX_KillMenuItem(limpx_menu *m,int n)
{
	limpx_menu_item *i;
	i = _LimpX_GetMenuItem(m,n);
	/* Delete data */
	if (i->text != NULL)
		free(i->text);
	if (i->validation != NULL)
		free(i->validation);
	/* Now delink */
	if (i->next != NULL)
		i->next->prev = i->prev;
	if (i->prev != NULL)
		i->prev->next = i->next;
	else
		m->items = i->next;
	m->numitems--;
	free(i);
}

void LimpX_KillMenu(limpx_menu *m)
{
	/* Delete menu and contents... */
	while (m->items != NULL)
		LimpX_KillMenuItem(m,0); /* 0 is 1st item */
	if (m->text != NULL)
		free(m->text);
	if (m->validation != NULL)
		free(m->validation);
	/* Delete RO block */
	if (m->ro_block != NULL)
		free(m->ro_block);
	/* De-link */
	if (m->next != NULL)
		m->next->prev = m->prev;
	if (m->prev != NULL)
		m->prev->next = m->next;
	else
		limpx.menus = m->next;
	free(m);
}

void LimpX_UpdateMenuBlock(limpx_menu *m)
{
	/* Update menu block... */
	int bsize;
	int n,i;
	limpx_menu_item *cur;
	if (m->numitems == 0)
		bsize = 28 + 24; /* Stick a dummy item in */
	else
		bsize = 28 + (24*m->numitems);
	if ((m->b_size < bsize) || ((m->b_size - __LIMPX_MEMTHRESHOLD) > bsize))
	{
		if (m->ro_block != NULL)
			free(m->ro_block);
		m->b_size = bsize;
		m->ro_block = (int*) malloc(bsize);
	}
	/* Now fill in block... */
	/* Start with header */
	if (m->flags & 256)
	{
		m->ro_block[0] = (int) m->text;
		m->ro_block[1] = (int) m->validation;
		m->ro_block[2] = m->t_size;
	}
	else
		jstrncpy((char *) m->ro_block,m->text,12);
	memcpy(&m->ro_block[3],&m->cols.title_for,16);
/*	m->ro_block[3] = m->cols.title_for + (256*m->cols.title_back + (256*m->cols.work_for + (256*m->cols.work_back)));
	m->ro_block[4] = m->width;
	m->ro_block[5] = m->height;
	m->ro_block[6] = m->gap; */
	if (m->numitems == 0)
	{
		m->ro_block[7] = 128 + (m->flags & 256);
		m->ro_block[8] = -1;
		m->ro_block[9] = 0;
		m->ro_block[10] = 0;
		m->ro_block[11] = 0;
		m->ro_block[12] = 0;
		return;
	}
	i = 7;
	cur = m->items;
	for (n=0;n<m->numitems;n++)
	{
		m->ro_block[i] = cur->itemf;
		if (n == 0)
			m->ro_block[i] = m->ro_block[i] | (m->flags & 256);
		if (n == (m->numitems - 1))
			m->ro_block[i] = m->ro_block[i] | 128;
		if (cur->submenu == NULL)
		{
			if (cur->subwindow == NULL)
				m->ro_block[i+1] = -1;
			else
				m->ro_block[i+1] = cur->subwindow->ro_handle;
		}
		else
			m->ro_block[i+1] = (int) cur->submenu->ro_block;
		m->ro_block[i+2] = cur->iconf;
		/* icon data... */
		switch (cur->iconf & 259)
		{
		case 257: /* Indirected text */
		case 259: /* Indirected text & sprite */
			m->ro_block[i+3] = (int) cur->text;
			m->ro_block[i+4] = (int) cur->validation;
			m->ro_block[i+5] = cur->rot_size;
			break;
		case 258: /* Indirected sprite */
			if (cur->spriteptr != NULL)
			{
				m->ro_block[i+3] = (int) cur->text;
				m->ro_block[i+4] = cur->spriteblock;
				m->ro_block[i+5] = jstrlen(cur->text);
			}
			else
			{
				m->ro_block[i+3] = cur->spriteptr;
				m->ro_block[i+4] = cur->spriteblock;
				m->ro_block[i+5] = 0;
			}
			break;
		default:
			jstrncpy((char *) &m->ro_block[i+3],cur->text,12);
		}
		i=i+6;
		cur = cur->next;
	}
}

void LimpX_CreateMenu(limpx_menu *m,int x,int y)
{
	if (m == NULL)
		limpx.r.r[1] = -1;
	else
		limpx.r.r[1]=(int) m->ro_block;
	limpx.r.r[2]=x;
	limpx.r.r[3]=y;
	_kernel_swi(Wimp_CreateMenu,&limpx.r,&limpx.r);
}

void LimpX_CreateWindowAsMenu(limpx_window *w,int x,int y)
{
	if (w == NULL)
		limpx.r.r[1] = -1;
	else
		limpx.r.r[1]=(int) w->ro_handle;
	limpx.r.r[2]=x;
	limpx.r.r[3]=y;
	_kernel_swi(Wimp_CreateMenu,&limpx.r,&limpx.r);
}

void LimpX_DecodeMenu(limpx_menu *m,void *sel,int *out)
{
	limpx.r.r[1]=(int) m->ro_block;
	limpx.r.r[2]=(int) sel;
	limpx.r.r[3]=(int) out;
	_kernel_swi(Wimp_DecodeMenu,&limpx.r,&limpx.r);
}

void LimpX_WhichIcon(limpx_window *w,int *block,int mask,int settings)
{
	limpx.r.r[0]=w->ro_handle;
	limpx.r.r[1]=(int) block;
	limpx.r.r[2]=mask;
	limpx.r.r[3]=settings;
	_kernel_swi(Wimp_WhichIcon,&limpx.r,&limpx.r);
}

void LimpX_SetExtent(limpx_window *w,int minx,int miny,int maxx,int maxy)
{
	limpx.r.r[0]=w->ro_handle;
	limpx.r.r[1]=(int) limpx.sb;
	limpx.sb[0]=minx;
	limpx.sb[1]=miny;
	limpx.sb[2]=maxx;
	limpx.sb[3]=maxy;
	_kernel_swi(Wimp_SetExtent,&limpx.r,&limpx.r);
}

void LimpX_SetPointerShape(int n,void *d,int w,int h,int x,int y)
{
	if (d == NULL)
		limpx.r.r[1]=-1;
	else
		limpx.r.r[1]=(int) d;
	limpx.r.r[0]=n;
	limpx.r.r[2]=w;
	limpx.r.r[3]=h;
	limpx.r.r[4]=x;
	limpx.r.r[5]=y;
	_kernel_swi(Wimp_SetPointerShape,&limpx.r,&limpx.r);
}

void LimpX_ProcessKey(int c)
{
	limpx.r.r[0]=c;
	_kernel_swi(Wimp_ProcessKey,&limpx.r,&limpx.r);
}

void LimpX_CloseDown()
{
	limpx.r.r[0]=limpx.task;
	limpx.r.r[1]=0x4B534154;
	_kernel_swi(Wimp_CloseDown,&limpx.r,&limpx.r);
}

void LimpX_DeleteEvent(limpx_event *e);

void LimpX_KillAll() /* Delete all data */
{
#ifdef DEBUG
	fprintf(debuglog,"Deleteing icons\n");
#endif
	while (limpx.icons != NULL)
		LimpX_DeleteIcon(limpx.icons);
#ifdef DEBUG
	fprintf(debuglog,"Deleteing windows\n");
#endif
	while (limpx.windows != NULL)
		LimpX_DeleteWindow(limpx.windows);
#ifdef DEBUG
	fprintf(debuglog,"Deleteing menus\n");
#endif
	while (limpx.menus != NULL)
		LimpX_KillMenu(limpx.menus);
#ifdef DEBUG
	fprintf(debuglog,"Deleteing events\n");
#endif
	while (limpx.events != NULL)
		LimpX_DeleteEvent(limpx.events);
#ifdef DEBUG
	fprintf(debuglog,"Done\n");
#endif
}

int LimpX_StartTask(char *cmd)
{
	limpx.r.r[0]=(int) cmd;
	_kernel_swi(Wimp_StartTask,&limpx.r,&limpx.r);
	return limpx.r.r[0];
}

int LimpX_ReportError(int num,char *msg,int flags,char *title,char *spr,int blk,char *extra)
{
	union {char c[1024];int i[256];} e;
	e.i[0]=num;
	strcpy(&e.c[4],msg);
	limpx.r.r[0]=(int) &e;
	limpx.r.r[1]=flags;
	limpx.r.r[2]=(int) title;
	limpx.r.r[3]=(int) spr;
	limpx.r.r[4]=blk;
	limpx.r.r[5]=(int) extra;
	_kernel_swi(Wimp_ReportError,&limpx.r,&limpx.r);
	return limpx.r.r[1];
}

limpx_window_state LimpX_GetWindowOutline(limpx_window *w)
{
	limpx_window_state s;
	limpx.sb[0] = w->ro_handle;
	limpx.r.r[1]=(int) limpx.sb;
	_kernel_swi(Wimp_GetWindowOutline,&limpx.r,&limpx.r);
	memcpy(&s,&limpx.sb[1],16);
	return s;
}

void LimpX_PlotIcon(limpx_icon_block *i)
{
	limpx.r.r[1]=(int) i;
	_kernel_swi(Wimp_PlotIcon,&limpx.r,&limpx.r);
}

void LimpX_SetMode(int m)
{
	limpx.r.r[0]=m;
	_kernel_swi(Wimp_SetMode,&limpx.r,&limpx.r);
}

void LimpX_SetPalette(limpx_pal *p)
{
	limpx.r.r[1]=(int) p;
	_kernel_swi(Wimp_SetPalette,&limpx.r,&limpx.r);
}

void LimpX_ReadPalette(limpx_pal *p)
{
	limpx.r.r[1]=(int) p;
	_kernel_swi(Wimp_ReadPalette,&limpx.r,&limpx.r);
}

void LimpX_SetColour(int c)
{
	limpx.r.r[0]=c;
	_kernel_swi(Wimp_SetColour,&limpx.r,&limpx.r);
}

void LimpX_SendMessage(int code,void *b,int h,int i) /* Could do with improving... */
{
	limpx.r.r[0]=code;
	limpx.r.r[1]=(int) b;
	limpx.r.r[2]=h;
	limpx.r.r[3]=i;
	_kernel_swi(Wimp_SendMessage,&limpx.r,&limpx.r);
}

void LimpX_CreateSubMenu(limpx_menu *m,limpx_window *w,int x,int y)
{
	if (m != NULL)
		limpx.r.r[1]=(int) m->ro_block;
	else
		limpx.r.r[1]=w->ro_handle;
	limpx.r.r[2]=x;
	limpx.r.r[3]=y;
	_kernel_swi(Wimp_CreateSubMenu,&limpx.r,&limpx.r);
}

/* SpriteOp needs investigating... */

int LimpX_ROMBaseOfSprites()
{
	_kernel_swi(Wimp_BaseOfSprites,&limpx.r,&limpx.r);
	return limpx.r.r[0];
}

int LimpX_RMABaseOfSprites()
{
	_kernel_swi(Wimp_BaseOfSprites,&limpx.r,&limpx.r);
	return limpx.r.r[1];
}

void LimpX_BlockCopy(limpx_window *w,int minx,int miny,int maxx,int maxy,int dx,int dy)
{
	limpx.r.r[0]=w->ro_handle;
	limpx.r.r[1]=minx;
	limpx.r.r[2]=miny;
	limpx.r.r[3]=maxx;
	limpx.r.r[4]=maxy;
	limpx.r.r[5]=dx;
	limpx.r.r[6]=dy;
	_kernel_swi(Wimp_BlockCopy,&limpx.r,&limpx.r);
}

int LimpX_SlotSize(int op,int val)
{
	switch (op)
	{
		case LIMPX_SLOTSIZE_SETCURRENT:
			limpx.r.r[0] = val;
			limpx.r.r[1] = -1;
			_kernel_swi(Wimp_SlotSize,&limpx.r,&limpx.r);
			return limpx.r.r[0];
		case LIMPX_SLOTSIZE_SETNEXT:
			limpx.r.r[0] = -1;
			limpx.r.r[1] = val;
			_kernel_swi(Wimp_SlotSize,&limpx.r,&limpx.r);
			return limpx.r.r[1];
		case LIMPX_SLOTSIZE_READCURRENT:
			limpx.r.r[0] = -1;
			limpx.r.r[1] = -1;
			_kernel_swi(Wimp_SlotSize,&limpx.r,&limpx.r);
			return limpx.r.r[0];
		case LIMPX_SLOTSIZE_READNEXT:
			limpx.r.r[0] = -1;
			limpx.r.r[1] = -1;
			_kernel_swi(Wimp_SlotSize,&limpx.r,&limpx.r);
			return limpx.r.r[1];
		case LIMPX_SLOTSIZE_READFREE:
			limpx.r.r[0] = -1;
			limpx.r.r[1] = -1;
			_kernel_swi(Wimp_SlotSize,&limpx.r,&limpx.r);
			return limpx.r.r[2];
	}
	return 0;
}

void LimpX_ReadPixTrans(int flags,int area,int spr,limpx_scalefact *s,limpx_coltran *c)
{
	limpx.r.r[0]=flags;
	limpx.r.r[1]=area;
	limpx.r.r[2]=spr;
	limpx.r.r[6]=(int) s;
	limpx.r.r[7]=(int) c;
	_kernel_swi(Wimp_ReadPixTrans,&limpx.r,&limpx.r);
}

/* ClaimFreeMemory needs block too... but it's a bit of a dodgy call to make so I'll just forget about it */

void LimpX_CommandWindow(int o)
{
	limpx.r.r[0]=o;
	_kernel_swi(Wimp_CommandWindow,&limpx.r,&limpx.r);
}

void LimpX_TextColour(int c)
{
	limpx.r.r[0]=c;
	_kernel_swi(Wimp_TextColour,&limpx.r,&limpx.r);
}

void LimpX_TextOp_Colour(int f,int b)
{
	limpx.r.r[0] = 0;
	limpx.r.r[1] = f;
	limpx.r.r[2] = b;
	_kernel_swi(Wimp_TextOp,&limpx.r,&limpx.r);
}

int LimpX_TextOp_Width(char *str,int chars)
{
	limpx.r.r[0] = 1;
	limpx.r.r[1] = (int) str;
	limpx.r.r[2] = chars;
	_kernel_swi(Wimp_TextOp,&limpx.r,&limpx.r);
	return limpx.r.r[0];
}

void LimpX_TextOp_Plot(int flags,char *str,int x,int y)
{
	limpx.r.r[0] = 2+flags;
	limpx.r.r[1] = (int) str;
	limpx.r.r[2] = -1;
	limpx.r.r[3] = -1;
	limpx.r.r[4] = x;
	limpx.r.r[5] = y;
	_kernel_swi(Wimp_TextOp,&limpx.r,&limpx.r);
}

void LimpX_TransferBlock(int sh,void *sb,int dh,void *db,int l)
{
	limpx.r.r[0]=sh;
	limpx.r.r[1]=(int) sb;
	limpx.r.r[2]=dh;
	limpx.r.r[3]=(int) db;
	limpx.r.r[4]=l;
	_kernel_swi(Wimp_TransferBlock,&limpx.r,&limpx.r);
}

int LimpX_ReadSysInfo(int i,int *s)
{
	limpx.r.r[0]=i;
	_kernel_swi(Wimp_ReadSysInfo,&limpx.r,&limpx.r);
	if (s != NULL)
		*s = limpx.r.r[1]; /* second value for i=5,i=8 */
	return limpx.r.r[0];
}

void LimpX_SetFontColours(int b,int f)
{
	limpx.r.r[1]=b;
	limpx.r.r[2]=f;
	_kernel_swi(Wimp_SetFontColours,&limpx.r,&limpx.r);
}

void LimpX_GetMenuState(int t,int *b,int w,int i)
{
	limpx.r.r[0]=t;
	limpx.r.r[1]=(int) b;
	limpx.r.r[2]=w;
	limpx.r.r[3]=i;
	_kernel_swi(Wimp_GetMenuState,&limpx.r,&limpx.r);
}

/* RegisterFilter is a no-no call now */

void LimpX_AddMessages(void *b)
{
	limpx.r.r[0]=(int) b;
	_kernel_swi(Wimp_AddMessages,&limpx.r,&limpx.r);
}

void LimpX_RemoveMessages(void *b)
{
	limpx.r.r[0]=(int) b;
	_kernel_swi(Wimp_RemoveMessages,&limpx.r,&limpx.r);
}

void LimpX_SetColourMapping(limpx_pal *p,char *two,char *four,char *sixteen)
{
	limpx.r.r[1]=(int) p;
	limpx.r.r[2]=(int) two;
	limpx.r.r[3]=(int) four;
	limpx.r.r[4]=(int) sixteen;
	limpx.r.r[5]=limpx.r.r[6]=limpx.r.r[7]=0;
	_kernel_swi(Wimp_SetColourMapping,&limpx.r,&limpx.r);
}

/* Handy functions.... */

limpx_pollblock *LimpX_Poll(int mask,void *w)
{
	limpx.abflag = 0; /* Clear previous code */
	while (limpx.abflag == 0)
	{
		limpx.r.r[0] = mask;
		limpx.r.r[1] = (int) limpx.block.block;
		limpx.r.r[3] = (int) w;
		_kernel_swi(Wimp_Poll,&limpx.r,&limpx.r);
		limpx.block.code = limpx.r.r[0];
		if (_LimpX_EventHandler() == 0)
			return &limpx.block; /* Pass block on to user */
	}
	return &limpx.block; /* User should check the abort code whenever LimpX_Poll returns */
}

limpx_pollblock *LimpX_PollIdle(int mask,void *w,int time)
{
	limpx.abflag = 0;
	while (limpx.abflag == 0)
	{
		limpx.r.r[0] = mask;
		limpx.r.r[1] = (int) limpx.block.block;
		limpx.r.r[2] = time;
		limpx.r.r[3] = (int) w;
		_kernel_swi(Wimp_PollIdle,&limpx.r,&limpx.r);
		limpx.block.code = limpx.r.r[0];
		if (_LimpX_EventHandler() == 0)
			return &limpx.block;
	}
	return &limpx.block;
}

void LimpX_SetAbortFlag(int i)
{
	limpx.abflag = i;
}

int LimpX_GetAbortFlag()
{
	return limpx.abflag;
}

limpx_window *LimpX_WindowFromHandle(int h)
{
	/* Return a limpx window for a window handle */
	limpx_window *cur;
	cur = limpx.windows;
	while (cur != NULL)
	{
		if (cur->ro_handle == h)
			return cur;
		cur = cur->next;
	}
	return cur;
}

limpx_icon *LimpX_IconFromHandle(int h,int i)
{
	limpx_window *w;
	limpx_icon *ic;
	w = LimpX_WindowFromHandle(h);
	if (w != NULL)
	{
		ic = w->icons;
		while (ic != NULL)
		{
			if (ic->ro_handle == i)
				return ic;
			ic = ic->next;
		}
	}
	ic = limpx.icons;
	while (ic != NULL)
	{
		if ((ic->ro_handle == i) && (ic->ro_window == h))
			return ic;
		ic = ic->next;
	}
	return ic;
}

limpx_menu *LimpX_MenuFromHandle(void *h) /* Really a pointer */
{
	limpx_menu *m;
	m = limpx.menus;
	while (m != NULL)
	{
		if (m->ro_block == h)
			return m;
		m = m->next;
	}
	return m;
}

int LimpX_HandleFromWindow(limpx_window *w)
{
	return w->ro_handle;
}

limpx_window *LimpX_WindowFromIcon(limpx_icon *i)
{
	return i->lx_window;
}

int LimpX_HandleFromIcon(limpx_icon *i)
{
	return i->ro_handle;
}

int LimpX_HandleFromMenu(limpx_menu *m)
{
	return (int) m->ro_block;
}

limpx_icon *LimpX_IconFromWindow(limpx_window *w,int i)
{
	limpx_icon *ic;
	ic = w->icons;
	while (i > 0)
	{
		ic = ic->next;
		i--;
	}
	return ic;
}

/* window editing commands... */

void LimpX_GetWindowHeader(limpx_window *w,limpx_window_header *h)
{
	limpx.sb[0] = w->ro_handle;
	limpx.r.r[1]=((int) limpx.sb) | 1;
	_kernel_swi(Wimp_GetWindowInfo,&limpx.r,&limpx.r);
	memcpy(h,&limpx.sb[1],sizeof(limpx_window_header)); /* Bah! */
}

int LimpX_GetWindow_TitleFor(limpx_window *w) {limpx_window_header h;LimpX_GetWindowHeader(w,&h);return h.col.title_for;}
int LimpX_GetWindow_TitleBack(limpx_window *w) {limpx_window_header h;LimpX_GetWindowHeader(w,&h);return h.col.title_back;}
int LimpX_GetWindow_WorkFor(limpx_window *w) {limpx_window_header h;LimpX_GetWindowHeader(w,&h);return h.col.work_for;}
int LimpX_GetWindow_WorkBack(limpx_window *w) {limpx_window_header h;LimpX_GetWindowHeader(w,&h);return h.col.work_back;}
int LimpX_GetWindow_ScrollOuter(limpx_window *w) {limpx_window_header h;LimpX_GetWindowHeader(w,&h);return h.scroll_outer;}
int LimpX_GetWindow_ScrollInner(limpx_window *w) {limpx_window_header h;LimpX_GetWindowHeader(w,&h);return h.scroll_inner;}
int LimpX_GetWindow_TitleFocus(limpx_window *w) {limpx_window_header h;LimpX_GetWindowHeader(w,&h);return h.title_focus;}
int LimpX_GetWindow_WorkMinX(limpx_window *w) {limpx_window_header h;LimpX_GetWindowHeader(w,&h);return h.work.minx;}
int LimpX_GetWindow_WorkMinY(limpx_window *w) {limpx_window_header h;LimpX_GetWindowHeader(w,&h);return h.work.miny;}
int LimpX_GetWindow_WorkMaxX(limpx_window *w) {limpx_window_header h;LimpX_GetWindowHeader(w,&h);return h.work.maxx;}
int LimpX_GetWindow_WorkMaxY(limpx_window *w) {limpx_window_header h;LimpX_GetWindowHeader(w,&h);return h.work.maxy;}
int LimpX_GetWindow_TitleFlags(limpx_window *w) {limpx_window_header h;LimpX_GetWindowHeader(w,&h);return h.title_flags;}
int LimpX_GetWindow_WorkFlags(limpx_window *w) {limpx_window_header h;LimpX_GetWindowHeader(w,&h);return h.work_flags;}
int LimpX_GetWindow_SpriteBlock(limpx_window *w) {limpx_window_header h;LimpX_GetWindowHeader(w,&h);return h.sprite_block;}
int LimpX_GetWindow_MinX(limpx_window *w) {limpx_window_header h;LimpX_GetWindowHeader(w,&h);return oms_getwidth(&h.mins);}
int LimpX_GetWindow_MinY(limpx_window *w) {limpx_window_header h;LimpX_GetWindowHeader(w,&h);return oms_getheight(&h.mins);}
char *LimpX_GetWindow_Title(limpx_window *w) {return w->text;}
char *LimpX_GetWindow_Validation(limpx_window *w) {return w->validation;}
int LimpX_GetWindow_TitleSpriteBlock(limpx_window *w) {return w->spriteblock;}
int LimpX_GetWindow_TitleSpritePtr(limpx_window *w) {return w->spriteptr;}
int LimpX_GetWindow_Icons(limpx_window *w) {
#ifdef DEBUG
	fprintf(debuglog,"getwindowicons: %x is %d\n",(int) w,w->numicons);
#endif
return w->numicons;}

/* Now set data... */

void LimpX_SetWindow_TitleFor(limpx_window *w,int i) {int *block;block = _LimpX_GetWindow(w);((limpx_window_header *) block)->col.title_for = i;_LimpX_RecreateWindow(w,block);}
void LimpX_SetWindow_TitleBack(limpx_window *w,int i) {int *block;block = _LimpX_GetWindow(w);((limpx_window_header *) block)->col.title_back = i;_LimpX_RecreateWindow(w,block);}
void LimpX_SetWindow_WorkFor(limpx_window *w,int i) {int *block;block = _LimpX_GetWindow(w);((limpx_window_header *) block)->col.work_for = i;_LimpX_RecreateWindow(w,block);}
void LimpX_SetWindow_WorkBack(limpx_window *w,int i) {int *block;block = _LimpX_GetWindow(w);((limpx_window_header *) block)->col.work_back = i;_LimpX_RecreateWindow(w,block);}
void LimpX_SetWindow_ScrollOuter(limpx_window *w,int i) {int *block;block = _LimpX_GetWindow(w);((limpx_window_header *) block)->scroll_outer = i;_LimpX_RecreateWindow(w,block);}
void LimpX_SetWindow_ScrollInner(limpx_window *w,int i) {int *block;block = _LimpX_GetWindow(w);((limpx_window_header *) block)->scroll_inner = i;_LimpX_RecreateWindow(w,block);}
void LimpX_SetWindow_TitleFocus(limpx_window *w,int i) {int *block;block = _LimpX_GetWindow(w);((limpx_window_header *) block)->title_focus = i;_LimpX_RecreateWindow(w,block);}
void LimpX_SetWindow_TitleFlags(limpx_window *w,int i) {int *block;block = _LimpX_GetWindow(w);((limpx_window_header *) block)->title_flags = i;_LimpX_RecreateWindow(w,block);}
void LimpX_SetWindow_WorkFlags(limpx_window *w,int i) {int *block;block = _LimpX_GetWindow(w);((limpx_window_header *) block)->work_flags = i;_LimpX_RecreateWindow(w,block);}
void LimpX_SetWindow_SpriteBlock(limpx_window *w,int i) {int *block;block = _LimpX_GetWindow(w);((limpx_window_header *) block)->sprite_block = i;_LimpX_RecreateWindow(w,block);}
void LimpX_SetWindow_MinX(limpx_window *w,int i) {int *block;block = _LimpX_GetWindow(w);oms_setwidth(&((limpx_window_header *) block)->mins,i);_LimpX_RecreateWindow(w,block);}
void LimpX_SetWindow_MinY(limpx_window *w,int i) {int *block;block = _LimpX_GetWindow(w);oms_setheight(&((limpx_window_header *) block)->mins,i);_LimpX_RecreateWindow(w,block);}
void LimpX_SetWindow_Title(limpx_window *w,char *c)
{
	int tsize;
	int *block;
	tsize = jstrlen(c);
	block = _LimpX_GetWindow(w);
#ifdef DEBUG
	fprintf(debuglog,"limpx_setwindow_title: getwindow returns %x\n",(int) block);
#endif
	switch (((limpx_window_header *) block)->title_flags & 259)
	{
	case 1:
	case 2:
	case 3:
		/* Copy into buffer */
		if (w->t_size != 12)
		{
			if (w->text != NULL)
				free(w->text);
			w->text = (char*) malloc(sizeof(char)*13); /* Extra space for terminator */
			w->t_size = 12;
		}
		jstrncpy(w->text,c,12);
		w->text[12] = 0;
		jstrncpy(((limpx_window_header *) block)->title.c,c,12);
		/* Remove validation string & sprite stuff */
		if (w->validation != NULL)
		{
			free(w->validation);
			w->validation = (char *) NULL;
			w->v_size = 0;
		}
		w->spriteblock = 1;
		w->spriteptr = (int) NULL;
		_LimpX_RecreateWindow(w,block);
		return;
	case 258:
		if (w->spriteptr != NULL) /* Has sprite ptr, therefore can't have name */
			break;
	case 257:
	case 259:
#ifdef DEBUG
		fprintf(debuglog,"limpx_setwindow_title: type 257/258/259, new title '%s', data is:\n",c);
		fprintf(debuglog,"title.i[0]=%x\n",((limpx_window_header *) block)->title.i[0]);
		fprintf(debuglog,"title.i[1]=%x\n",((limpx_window_header *) block)->title.i[1]);
		fprintf(debuglog,"title.i[2]=%x\n",((limpx_window_header *) block)->title.i[2]);
		fprintf(debuglog,"w->t_size=%d\nw->text=%x\n",w->t_size,(int) w->text);
#endif
		if ((w->t_size < tsize) || ((w->t_size - __LIMPX_MEMTHRESHOLD) > tsize) || (w->text == NULL))
		{
#ifdef DEBUG
			fprintf(debuglog,"Going to rebuild window\n");
#endif
			tsize += __LIMPX_MEMTHRESHOLD >> 2; /* Add some extra space to allow the string to expand a bit */
			if (w->text != NULL)
				free(w->text);
			w->t_size = tsize;
			w->text = (char*) malloc(sizeof(char)*(tsize+1));
			((limpx_window_header *) block)->title.p[0] = w->text;
			((limpx_window_header *) block)->title.i[2] = tsize+1; /* Is this right? */
			jstrcpy(w->text,c);
			_LimpX_RecreateWindow(w,block); /* Only if needed */
			return;
		}
		jstrcpy(w->text,c);
	}
	free(block);
}
void LimpX_SetWindow_Validation(limpx_window *w,char *c)
{
	int vsize;
	int *block;
	vsize = jstrlen(c);
	block = _LimpX_GetWindow(w);
	switch (((limpx_window_header *) block)->title_flags & 259)
	{
		case 257:
		case 259:
			if ((w->v_size < vsize) || ((w->v_size - __LIMPX_MEMTHRESHOLD) > vsize) || (w->validation == NULL))
		{
			vsize += __LIMPX_MEMTHRESHOLD >> 2;
			if (w->validation != NULL)
				free(w->validation);
			w->v_size = vsize;
			w->validation = (char*) malloc(sizeof(char)*(vsize+1));
			((limpx_window_header *) block)->title.p[1] = w->validation;
			jstrcpy(w->validation,c);
			_LimpX_RecreateWindow(w,block); /* Only if needed */
			return;
		}
		jstrcpy(w->validation,c);
	}
	free(block);
}
void LimpX_SetWindow_TitleSpriteBlock(limpx_window *w,int i)
{
	int *block;
	block = _LimpX_GetWindow(w);
	switch (((limpx_window_header *) block)->title_flags & 259)
	{
		case 258:
			((limpx_window_header *) block)->title.i[1] = i;
			w->spriteblock = i;
			_LimpX_RecreateWindow(w,block); /* Only if needed */
			return;
	}
	free(block);
}
void LimpX_SetWindow_TitleSpritePtr(limpx_window *w,int i)
{
	int *block;
	block = _LimpX_GetWindow(w);
	switch (((limpx_window_header *) block)->title_flags & 259)
	{
		case 258:
			/* If i is null, switch to text */
			/* Else switch to ptr */
			w->spriteptr = i;
			if (i == NULL)
			{
				if (((limpx_window_header *) block)->title.i[2] == 0)
				{
					((limpx_window_header *) block)->title.p[0] = w->text;
					((limpx_window_header *) block)->title.i[2] = w->t_size;
					_LimpX_RecreateWindow(w,block);
					return;
				}
			}
			else
			{
				/* Change to ptr */
				if (((limpx_window_header *) block)->title.i[2] != 0)
					((limpx_window_header *) block)->title.i[2] = 0;
				((limpx_window_header *) block)->title.i[0] = i;
				_LimpX_RecreateWindow(w,block);
				return;
			}
	}
	free(block);
}

void LimpX_RebuildTitleData(limpx_window *w)
{
	/* Rebuilds the title block, based on the IST settings */
	int *block;
	block = _LimpX_GetWindow(w);
	switch (((limpx_window_header *) block)->title_flags & 259)
	{
		case 0:
		case 256:
			((limpx_window_header *) block)->title.i[0] = ((limpx_window_header *) block)->title.i[1] = ((limpx_window_header *) block)->title.i[2] = 0;
			break;
		case 1:
		case 2:
		case 3:
			jstrncpy(((limpx_window_header *) block)->title.c,w->text,12);
			break;
		case 257:
		case 259:
			((limpx_window_header *) block)->title.p[0] = w->text;
			((limpx_window_header *) block)->title.p[1] = w->validation;
			((limpx_window_header *) block)->title.i[2] = w->t_size;
			break;
		case 258:
			if (w->spriteptr == NULL)
			{
				((limpx_window_header *) block)->title.p[0] = w->text;
				((limpx_window_header *) block)->title.i[2] = w->t_size;
			}
			else
			{
				((limpx_window_header *) block)->title.i[0] = w->spriteptr;
				((limpx_window_header *) block)->title.i[2] = 0;
			}
			((limpx_window_header *) block)->title.i[1] = w->spriteblock;
	}
	_LimpX_RecreateWindow(w,block);
}
/* Now icon manipulation... */
int LimpX_GetIcon_MinX(limpx_icon *i) {limpx_icon_block b;_LimpX_GetIcon(i,&b);return b.size.minx;}
int LimpX_GetIcon_MinY(limpx_icon *i) {limpx_icon_block b;_LimpX_GetIcon(i,&b);return b.size.miny;}
int LimpX_GetIcon_MaxX(limpx_icon *i) {limpx_icon_block b;_LimpX_GetIcon(i,&b);return b.size.maxx;}
int LimpX_GetIcon_MaxY(limpx_icon *i) {limpx_icon_block b;_LimpX_GetIcon(i,&b);return b.size.maxy;}
int LimpX_GetIcon_Flags(limpx_icon *i) {limpx_icon_block b;_LimpX_GetIcon(i,&b);return b.flags;}
char *LimpX_GetIcon_Text(limpx_icon *i)
{
	limpx_icon_block b;
	_LimpX_GetIcon(i,&b);
	/* Check IST */
	switch (b.flags & 259)
	{
		case 1:
		case 2:
		case 3:
			/* Re-read icon text */
			if (i->t_size != 12)
			{
				if (i->text != NULL)
					free(i->text);
				i->text = (char*) malloc(sizeof(char)*13);
				i->t_size = 12;
			}
			jstrncpy(i->text,b.data.c,12);
			i->text[12] = 0;
		break;
	}
	return i->text;
}
char *LimpX_GetIcon_Validation(limpx_icon *i) {return i->validation;}
int LimpX_GetIcon_SpriteBlock(limpx_icon *i) {return i->spriteblock;}
int LimpX_GetIcon_SpritePtr(limpx_icon *i) {return i->spriteptr;}
int LimpX_GetIcon_Pos(limpx_icon *i) {return i->pos;}
int LimpX_GetIcon_Priority(limpx_icon *i) {return i->priority;}
int LimpX_GetIcon_TextLength(limpx_icon *i) {return i->rot_size;}

void LimpX_ResizeIcon(limpx_icon *i,int minx,int miny,int maxx,int maxy)
{
	limpx.r.r[0] = i->ro_window;
	limpx.r.r[1] = i->ro_handle;
	limpx.r.r[2] = minx;
	limpx.r.r[3] = miny;
	limpx.r.r[4] = maxx;
	limpx.r.r[5] = maxy;
	_kernel_swi(Wimp_ResizeIcon,&limpx.r,&limpx.r);
}

void LimpX_SetIcon_MinX(limpx_icon *i,int x)
{
	limpx_icon_block b;
	_LimpX_GetIcon(i,&b);
	LimpX_ResizeIcon(i,x,b.size.miny,b.size.maxx,b.size.maxy);
}
void LimpX_SetIcon_MinY(limpx_icon *i,int x)
{
	limpx_icon_block b;
	_LimpX_GetIcon(i,&b);
	LimpX_ResizeIcon(i,b.size.minx,x,b.size.maxx,b.size.maxy);
}
void LimpX_SetIcon_MaxX(limpx_icon *i,int x)
{
	limpx_icon_block b;
	_LimpX_GetIcon(i,&b);
	LimpX_ResizeIcon(i,b.size.minx,b.size.miny,x,b.size.maxy);
}
void LimpX_SetIcon_MaxY(limpx_icon *i,int x)
{
	limpx_icon_block b;
	_LimpX_GetIcon(i,&b);
	LimpX_ResizeIcon(i,b.size.minx,b.size.miny,b.size.maxx,x);
}

void LimpX_SetIcon_Flags(limpx_icon *i,int x) {LimpX_SetIconState(i,x,-1);}

void LimpX_SetIcon_Text(limpx_icon *i,char *c)
{
	int tsize;
	limpx_icon_block block;
	tsize = jstrlen(c);
	_LimpX_GetIcon(i,&block);
	switch (block.flags & 259)
	{
	case 1:
	case 2:
	case 3:
		/* Copy into buffer */
		i->rot_size = tsize;
		if (i->t_size != 12)
		{
			if (i->text != NULL)
				free(i->text);
			i->text = (char*) malloc(sizeof(char)*13); /* Extra space for terminator */
			i->t_size = 12;
		}
		jstrncpy(i->text,c,12);
		i->text[12] = 0;
		jstrncpy(block.data.c,c,12);
		/* Remove validation string & sprite stuff */
		if (i->validation != NULL)
		{
			free(i->validation);
			i->validation = (char *) NULL;
			i->v_size = 0;
		}
		i->spriteblock = 1;
		i->spriteptr = (int) NULL;
		_LimpX_RecreateIcon(i,&block);
		return;
	case 258:
		if (i->spriteptr != NULL) /* Has sprite ptr, therefore can't have name */
			break;
	case 257:
	case 259:
		i->rot_size = tsize+1; /* Need to count the terminator */
		if ((i->t_size < tsize) || ((i->t_size - __LIMPX_MEMTHRESHOLD) > tsize) || (i->text == NULL))
		{
			tsize += __LIMPX_MEMTHRESHOLD >> 2;
			if (i->text != NULL)
				free(i->text);
			i->t_size = tsize; /* Hmm, should this be +1 as well? */
			i->text = (char*) malloc(sizeof(char)*(tsize+1));
			block.data.p[0] = i->text;
			block.data.i[2] = i->rot_size; /* Only update the size when needed to stop windows flickering :( */
			_LimpX_RecreateIcon(i,&block);
		}
		jstrcpy(i->text,c);
	}
}
void LimpX_SetIcon_Validation(limpx_icon *i,char *c)
{
	int vsize;
	limpx_icon_block block;
	vsize = jstrlen(c);
	_LimpX_GetIcon(i,&block);
	switch (block.flags & 259)
	{
		case 257:
		case 259:
			if ((i->v_size < vsize) || ((i->v_size - __LIMPX_MEMTHRESHOLD) > vsize) || (i->validation == NULL))
		{
			vsize += __LIMPX_MEMTHRESHOLD >> 2;
			if (i->validation != NULL)
				free(i->validation);
			i->v_size = vsize;
			i->validation = (char*) malloc(sizeof(char)*(vsize+1));
			block.data.p[1] = i->validation;
			jstrcpy(i->validation,c);
			_LimpX_RecreateIcon(i,&block); /* Only if needed */
			return;
		}
		jstrcpy(i->validation,c);
	}
}
void LimpX_SetIcon_SpriteBlock(limpx_icon *i,int x)
{
	limpx_icon_block block;
	_LimpX_GetIcon(i,&block);
	switch (block.flags & 259)
	{
		case 258:
			block.data.i[1] = x;
			i->spriteblock = x;
			_LimpX_RecreateIcon(i,&block); /* Only if needed */
			return;
	}
}
void LimpX_SetIcon_SpritePtr(limpx_icon *i,int x)
{
	limpx_icon_block block;
	_LimpX_GetIcon(i,&block);
	switch (block.flags & 259)
	{
		case 258:
			/* If x is null, switch to text */
			/* Else switch to ptr */
			i->spriteptr = x;
			if (x == NULL)
			{
				if (block.data.i[2] == 0)
				{
					block.data.p[0] = i->text;
					block.data.i[2] = i->t_size;
					_LimpX_RecreateIcon(i,&block);
					return;
				}
			}
			else
			{
				/* Change to ptr */
				if (block.data.i[2] != 0)
					block.data.i[2] = 0;
				block.data.i[0] = x;
				_LimpX_RecreateIcon(i,&block);
				return;
			}
	}
}

void LimpX_RebuildIconData(limpx_icon *i)
{
	/* Rebuilds the data block, based on the IST settings */
	limpx_icon_block block;
	_LimpX_GetIcon(i,&block);
	switch (block.flags & 259)
	{
		case 0:
		case 256:
			block.data.i[0] = block.data.i[1] = block.data.i[2] = 0;
			break;
		case 1:
		case 2:
		case 3:
			jstrncpy(block.data.c,i->text,12);
			break;
		case 257:
		case 259:
			block.data.p[0] = i->text;
			block.data.p[1] = i->validation;
			block.data.i[2] = i->rot_size;
			break;
		case 258:
			if (i->spriteptr == NULL)
			{
				block.data.p[0] = i->text;
				block.data.i[2] = i->t_size;
			}
			else
			{
				block.data.i[0] = i->spriteptr;
				block.data.i[2] = 0;
			}
			block.data.i[1] = i->spriteblock;
	}
	_LimpX_RecreateIcon(i,&block);
}
void LimpX_SetIcon_Pos(limpx_icon *i,int x)
{
	limpx_icon_block block;
	_LimpX_GetIcon(i,&block);
	i->pos = x;
	_LimpX_RecreateIcon(i,&block);
}
void LimpX_SetIcon_Priority(limpx_icon *i,int x)
{
	limpx_icon_block block;
	_LimpX_GetIcon(i,&block);
	i->priority = x;
	_LimpX_RecreateIcon(i,&block);
}
void LimpX_SetIcon_TextLength(limpx_icon *i,int x)
{
	limpx_icon_block block;
	char *n;
	_LimpX_GetIcon(i,&block);
	switch (block.flags & 259)
	{
	case 1:
	case 2:
	case 3:
		i->rot_size = x;
		return;
	case 258:
		if (block.data.i[2] == 0)
			break;
	case 257:
	case 259:
		if (i->t_size < x)
		{
			n = (char*) malloc(sizeof(char)*(x+1));
			jstrcpy(n,i->text);
			free(i->text);
			i->text = n;
			i->t_size = x;
			block.data.p[0] = n;
		}
		block.data.i[2] = x;
		i->rot_size = x;
		_LimpX_RecreateIcon(i,&block);
	}
}

void LimpX_RedrawIcon(limpx_icon *i)
{
	limpx_icon_block block;
	_LimpX_GetIcon(i,&block);
	limpx.r.r[0] = i->ro_window;
	limpx.r.r[1] = block.size.minx;
	limpx.r.r[2] = block.size.miny;
	limpx.r.r[3] = block.size.maxx;
	limpx.r.r[4] = block.size.maxy;
	_kernel_swi(Wimp_ForceRedraw,&limpx.r,&limpx.r);
}

/* Menus... */
char *LimpX_GetMenu_Text(limpx_menu *m) {return m->text;}
char *LimpX_GetMenu_Validation(limpx_menu *m) {return m->validation;}
int LimpX_GetMenu_TitleFor(limpx_menu *m) {return m->cols.title_for;}
int LimpX_GetMenu_TitleBack(limpx_menu *m) {return m->cols.title_back;}
int LimpX_GetMenu_WorkFor(limpx_menu *m) {return m->cols.work_for;}
int LimpX_GetMenu_WorkBack(limpx_menu *m) {return m->cols.work_back;}
int LimpX_GetMenu_Width(limpx_menu *m) {return m->width;}
int LimpX_GetMenu_Height(limpx_menu *m) {return m->height;}
int LimpX_GetMenu_Gap(limpx_menu *m) {return m->gap;}
int LimpX_GetMenu_Flags(limpx_menu *m) {return m->flags;} /* ** remove this? currently only contains indirected flag... ** */

void LimpX_SetMenu_Text(limpx_menu *m,char *c)
{
	int tsize;
	/* Copy text... */
	tsize = jstrlen(c);
	if (m->flags & 256)
	{
		if ((m->t_size < tsize) || ((m->t_size - __LIMPX_MEMTHRESHOLD) > tsize) || (m->text == NULL))
		{
			if (m->text != NULL)
				free(m->text);
			m->t_size = tsize;
			m->text = (char*) malloc(sizeof(char)*(tsize+1));
		}
		jstrcpy(m->text,c);
	}
	else
	{
		if (m->t_size != 12)
		{
			if (m->text != NULL)
				free(m->text);
			m->text = (char*) malloc(sizeof(char)*13); /* Extra space for terminator */
			m->t_size = 12;
		}
		jstrncpy(m->text,c,12);
		m->text[12] = 0;
		/* Remove validation string */
		if (m->validation != NULL)
		{
			free(m->validation);
			m->validation = (char *) NULL;
			m->v_size = 0;
		}
	}
}
void LimpX_SetMenu_Validation(limpx_menu *m,char *c)
{
	int vsize;
	/* Copy text... */
	if ((m->flags & 256) == 0)
		return;
	vsize = jstrlen(c);
	if ((m->v_size < vsize) || ((m->v_size - __LIMPX_MEMTHRESHOLD) > vsize) || (m->validation == NULL))
	{
		if (m->validation != NULL)
			free(m->validation);
		m->v_size = vsize; /* vsize + 1? */
		m->validation = (char*) malloc(sizeof(char)*(vsize)); /* vsize + 1? */
	}
	jstrcpy(m->validation,c);
}
void LimpX_SetMenu_TitleFor(limpx_menu *m,int i) {m->cols.title_for = i;}
void LimpX_SetMenu_TitleBack(limpx_menu *m,int i) {m->cols.title_back = i;}
void LimpX_SetMenu_WorkFor(limpx_menu *m,int i) {m->cols.work_for = i;}
void LimpX_SetMenu_WorkBack(limpx_menu *m,int i) {m->cols.work_back = i;}
void LimpX_SetMenu_Width(limpx_menu *m,int i) {m->width = i;}
void LimpX_SetMenu_Height(limpx_menu *m,int i) {m->height = i;}
void LimpX_SetMenu_Gap(limpx_menu *m,int i) {m->gap = i;}
void LimpX_SetMenu_Flags(limpx_menu *m,int i) {m->flags = i;}

/* menu items... */
char *LimpX_GetMenuItem_Text(limpx_menu *m,int i)
{
	limpx_menu_item *it;
	int x;
	it = _LimpX_GetMenuItem(m,i);
	switch (it->iconf & 259)
	{
		case 1:
		case 2:
		case 3:
			/* Non-indirected text */
			/* Read from the menu block then */
			if (m->ro_block != NULL)
			{
				x = 7+i*6;
				if ((m->ro_block[x+2] & 259) == (it->iconf & 259))
				{
					if (it->t_size != 12)
					{
						if (it->text != NULL)
							free(it->text);
						it->text = (char*) malloc(sizeof(char)*13);
						it->t_size = 12;
					}
					jstrncpy(it->text,(char *) &m->ro_block[x+3],12);
					it->text[12] = 0;
				}
			}
			break;
	}
	return it->text;
}
char *LimpX_GetMenuItem_Validation(limpx_menu *m,int i) {limpx_menu_item *it;it = _LimpX_GetMenuItem(m,i);return it->validation;}
int LimpX_GetMenuItem_SpriteBlock(limpx_menu *m,int i) {limpx_menu_item *it;it = _LimpX_GetMenuItem(m,i);return it->spriteblock;}
int LimpX_GetMenuItem_SpritePtr(limpx_menu *m,int i) {limpx_menu_item *it;it = _LimpX_GetMenuItem(m,i);return it->spriteptr;}
int LimpX_GetMenuItem_ItemFlags(limpx_menu *m,int i) {limpx_menu_item *it;it = _LimpX_GetMenuItem(m,i);return it->itemf;}
int LimpX_GetMenuItem_IconFlags(limpx_menu *m,int i) {limpx_menu_item *it;it = _LimpX_GetMenuItem(m,i);return it->iconf;}
int LimpX_GetMenuItem_TextLength(limpx_menu *m,int i) {limpx_menu_item *it;it = _LimpX_GetMenuItem(m,i);return it->rot_size;}

void LimpX_SetMenuItem_Text(limpx_menu *m,int i,char *c)
{
	limpx_menu_item *it;
	int tsize;
	it = _LimpX_GetMenuItem(m,i);
	/* Copy text... */
	tsize = jstrlen(c);
	switch (it->iconf & 259)
	{
	case 1:
	case 2:
	case 3:
		/* Copy into buffer */
		it->rot_size = tsize;
		if (it->t_size != 12)
		{
			if (it->text != NULL)
				free(it->text);
			it->text = (char*) malloc(sizeof(char)*13); /* Extra space for terminator */
			it->t_size = 12;
		}
		jstrncpy(it->text,c,12);
		it->text[12] = 0;
		/* Remove validation string & sprite stuff */
		if (it->validation != NULL)
		{
			free(it->validation);
			it->validation = (char *) NULL;
			it->v_size = 0;
		}
		it->spriteblock = 1;
		it->spriteptr = (int) NULL;
		break;
	case 258:
		if (it->spriteptr != NULL) /* Has sprite ptr, therefore can't have name */
			break;
	case 257:
	case 259:
		it->rot_size = tsize+1;
		if ((it->t_size < tsize) || ((it->t_size - __LIMPX_MEMTHRESHOLD) > tsize) || (it->text == NULL))
		{
			if (it->text != NULL)
				free(it->text);
			it->t_size = tsize;
			it->text = (char*) malloc(sizeof(char)*(tsize+1));
		}
		jstrcpy(it->text,c);
	}
}
void LimpX_SetMenuItem_Validation(limpx_menu *m,int i,char *c)
{
	limpx_menu_item *it;
	int vsize;
	it = _LimpX_GetMenuItem(m,i);
	/* Copy text... */
	vsize = jstrlen(c);
	switch (it->iconf & 259)
	{
		case 257:
		case 259:
			if ((it->v_size < vsize) || ((it->v_size - __LIMPX_MEMTHRESHOLD) > vsize) || (it->validation == NULL))
		{
			if (it->validation != NULL)
				free(it->validation);
			it->v_size = vsize;
			it->validation = (char*) malloc(sizeof(char)*(vsize+1));
		}
		jstrcpy(it->validation,c);
	}
}
void LimpX_SetMenuItem_SpriteBlock(limpx_menu *m,int i,int x)
{
	limpx_menu_item *it;
	it = _LimpX_GetMenuItem(m,i);
	if ((it->iconf & 259) == 258)
		it->spriteblock = x;
}
void LimpX_SetMenuItem_SpritePtr(limpx_menu *m,int i,int x)
{
	limpx_menu_item *it;
	it = _LimpX_GetMenuItem(m,i);
	if ((it->iconf & 259) != 258)
		return;
	it->spriteptr = x;
}
void LimpX_SetMenuItem_ItemFlags(limpx_menu *m,int i,int x) {limpx_menu_item *it;it = _LimpX_GetMenuItem(m,i);it->itemf = x;}
void LimpX_SetMenuItem_IconFlags(limpx_menu *m,int i,int x) {limpx_menu_item *it;it = _LimpX_GetMenuItem(m,i);it->iconf = x;}
void LimpX_SetMenuItem_TextLength(limpx_menu *m,int i,int x)
{
	limpx_menu_item *it;
	char *n;
	it = _LimpX_GetMenuItem(m,i);
	if (it->t_size < x)
	{
		n = (char*) malloc(sizeof(char)*(x+1));
		jstrcpy(n,it->text);
		free(it->text);
		it->text = n;
		it->t_size = x;
	}
	it->rot_size = x;
}
void LimpX_SetMenuItem_SubMenu(limpx_menu *m,int i,limpx_menu *s)
{
	limpx_menu_item *it;
	it = _LimpX_GetMenuItem(m,i);
	it->submenu = s;
	it->subwindow = (limpx_window *) NULL;
}
void LimpX_SetMenuItem_SubWindow(limpx_menu *m,int i,limpx_window *s)
{
	limpx_menu_item *it;
	it = _LimpX_GetMenuItem(m,i);
	it->subwindow = s;
	it->submenu = (limpx_menu *) NULL;
}
void LimpX_SetMenuItem_ClearSub(limpx_menu *m,int i)
{
	limpx_menu_item *it;
	it = _LimpX_GetMenuItem(m,i);
	it->subwindow = (limpx_window *) NULL;
	it->submenu = (limpx_menu *) NULL;
}

int LimpX_NewMenuItem(limpx_menu *m)
{
	/* Return item no. */
	_LimpX_NewMenuItem(m);
	return m->numitems-1; /* Starts at item 0 */
}

limpx_event *LimpX_NewEvent_Null_Code(int (*func) (void))
{
	limpx_event *e;
	e = _LimpX_NewEvent();
	e->func.null_code = func;
	e->code = 0;
	return e;
}

limpx_event *LimpX_NewEvent_Redraw_Window(int (*func) (limpx_window *win),limpx_window *w)
{
	limpx_event *e;
	e = _LimpX_NewEvent();
	e->func.redraw_window = func;
	e->code = 1;
	e->criteria[0] = (int) w;
	return e;
}

limpx_event *LimpX_NewEvent_Open_Window(int (*func) (limpx_window *win,limpx_window_state *pos),limpx_window *w)
{
	limpx_event *e;
	e = _LimpX_NewEvent();
	e->func.open_window = func;
	e->code = 2;
	e->criteria[0] = (int) w;
	return e;
}

limpx_event *LimpX_NewEvent_Close_Window(int (*func) (limpx_window *win),limpx_window *w)
{
	limpx_event *e;
	e = _LimpX_NewEvent();
	e->func.close_window = func;
	e->code = 3;
	e->criteria[0] = (int) w;
	return e;
}

limpx_event *LimpX_NewEvent_Pointer_Leave(int (*func) (limpx_window *win),limpx_window *w)
{
	limpx_event *e;
	e = _LimpX_NewEvent();
	e->func.pointer_leave = func;
	e->code = 4;
	e->criteria[0] = (int) w;
	return e;
}

limpx_event *LimpX_NewEvent_Pointer_Enter(int (*func) (limpx_window *win),limpx_window *w)
{
	limpx_event *e;
	e = _LimpX_NewEvent();
	e->func.pointer_enter = func;
	e->code = 5;
	e->criteria[0] = (int) w;
	return e;
}

limpx_event *LimpX_NewEvent_Mouse_Click(int (*func) (limpx_mouse_obj *mouse,limpx_window *win,limpx_icon *icon),limpx_window *win,limpx_icon *icon)
{
	limpx_event *e;
	e = _LimpX_NewEvent();
	e->func.mouse_click = func;
	e->code = 6;
	e->criteria[0] = (int) win;
	e->criteria[1] = (int) icon;
	return e;
}

limpx_event *LimpX_NewEvent_Drag_Box(int (*func) (int minx,int miny,int maxx,int maxy))
{
	limpx_event *e;
	e = _LimpX_NewEvent();
	e->func.drag_box = func;
	e->code = 7;
	return e;
}

limpx_event *LimpX_NewEvent_Key_Pressed(int (*func) (limpx_caret_obj *c,int key),limpx_window *win,limpx_icon *icon)
{
	limpx_event *e;
	e = _LimpX_NewEvent();
	e->func.key_pressed = func;
	e->code = 8;
	e->criteria[0] = (int) win;
	e->criteria[1] = (int) icon;
	return e;
}

limpx_event *LimpX_NewEvent_Menu_Selection(int (*func) (int *selections))
{
	limpx_event *e;
	e = _LimpX_NewEvent();
	e->func.menu_selection = func;
	e->code = 9;
	return e;
}

limpx_event *LimpX_NewEvent_Scroll_Request(int (*func) (limpx_window *win,limpx_window_state *pos,int xdir,int ydir),limpx_window *win)
{
	limpx_event *e;
	e = _LimpX_NewEvent();
	e->func.scroll_request = func;
	e->code = 10;
	e->criteria[0] = (int) win;
	return e;
}

limpx_event *LimpX_NewEvent_Lose_Caret(int (*func) (limpx_caret_obj *c),limpx_window *win,limpx_icon *icon)
{
	limpx_event *e;
	e = _LimpX_NewEvent();
	e->func.lose_caret = func;
	e->code = 11;
	e->criteria[0] = (int) win;
	e->criteria[1] = (int) icon;
	return e;
}

limpx_event *LimpX_NewEvent_Gain_Caret(int (*func) (limpx_caret_obj *c),limpx_window *win,limpx_icon *icon)
{
	limpx_event *e;
	e = _LimpX_NewEvent();
	e->func.gain_caret = func;
	e->code = 12;
	e->criteria[0] = (int) win;
	e->criteria[1] = (int) icon;
	return e;
}

limpx_event *LimpX_NewEvent_Poll_NonZero(int (*func) (void))
{
	limpx_event *e;
	e = _LimpX_NewEvent();
	e->func.poll_nonzero = func;
	e->code = 13;
	return e;
}

limpx_event *LimpX_NewEvent_User_Message(int (*func) (int code,int *block),int msg)
{
	limpx_event *e;
	e = _LimpX_NewEvent();
	e->func.user_message = func;
	e->code = 17;
	e->criteria[0] = msg;
	return e;
}

limpx_event *LimpX_NewEvent_Other_Event(int (*func) (int code,int *block))
{
	limpx_event *e;
	e = _LimpX_NewEvent();
	e->func.other_event = func;
	e->code = -1;
	return e;
}

void LimpX_DeleteEvent(limpx_event *e)
{
	if (e->prev != NULL)
		e->prev->next = e->next;
	else
		limpx.events = e->next;
	if (e->next != NULL)
		e->next->prev = e->prev;
	free(e);
}

void LimpX_SelectESGIcon(limpx_icon *i)
{
	/* Select only icon i from i->window */
	int *block,n;
	limpx_icon_block b;
	block = (int*) malloc(sizeof(int)*i->lx_window->numicons+1);
	LimpX_GetIconState(i,&b);
	LimpX_WhichIcon(i->lx_window,block,0x003F0000,(b.flags & 0x1F0000)+0x200000); /* Only get selected ones :) */
	n=0;
	while (block[n] != -1)
	{
		limpx.sb[0]=i->ro_window;
		limpx.sb[1]=block[n];
		limpx.sb[2]=0;
		limpx.sb[3]=0x200000;
		limpx.r.r[1]=(int) limpx.sb;
		_kernel_swi(Wimp_SetIconState,&limpx.r,&limpx.r);
		n++;
	}
	LimpX_SetIconState(i,0x200000,0x200000);
	free(block);
}

limpx_icon *LimpX_GetSelectedESGIcon(limpx_window *w,int esg)
{
	int *block,tmp;
	block = (int*) malloc(sizeof(int)*w->numicons+1);
	LimpX_WhichIcon(w,block,0x003F0000,(esg*0x10000)+0x200000);
	tmp = block[0];
	free(block);
	return LimpX_IconFromWindow(w,tmp);
}

void LimpX_DragASprite_Start(int flags,int area,char *name,int *box,int *bounds)
{
	limpx.r.r[0] = flags;
	limpx.r.r[1] = area;
	limpx.r.r[2] = (int) name;
	limpx.r.r[3] = (int) box;
	limpx.r.r[4] = (int) bounds;
	_kernel_swi(DragASprite_Start,&limpx.r,&limpx.r);
}

void LimpX_DragASprite_Stop()
{
	_kernel_swi(DragASprite_Stop,&limpx.r,&limpx.r);
}

void LimpX_UpdateCaret()
{
	/* Get cursor pos */
	/* If it's in one of our icons, make sure it isn't in a dodgy place */
	/* Always relocate it to ensure it gets drawn in the right pos */
	limpx_caret_obj c;
	limpx_icon *i;
	limpx_menu *m;
	limpx_menu_item *it;
	LimpX_GetCaretPosition(&c);
	if (c.index == -1)
		return; /* Only in strings */
	i = LimpX_IconFromHandle(c.window,c.icon);
	if (i != NULL)
	{
		if (c.index > i->rot_size)
			c.index = i->rot_size;
		LimpX_SetCaretPositionBlk(&c);
	}
	m = LimpX_MenuFromHandle((void *) c.window); /* Check for menus */
	if (m != NULL)
	{
		it = _LimpX_GetMenuItem(m,c.icon);
		if (it != NULL)
		{
			if (c.index > it->rot_size)
				c.index = it->rot_size;
			LimpX_SetCaretPositionBlk(&c);
		}
	}
}

/*

				EVENT HANDLERS

*/

static limpx_event *_LimpX_FindEvent(int code,limpx_event *start)
{
	/* Search for 'code' */
	/* If start==null, check the 1st event */
	/* Return null if none found */
	if (start == NULL)
		start = limpx.events;
	else
		start = start->next;
	while (start != NULL)
	{
		if (start->code == code)
			return start;
		start = start->next;
	}
	return start;
}

static int _LimpX_Event_Null()
{
	/* Search for null event handler */
	limpx_event *event;
	event = _LimpX_FindEvent(0,NULL);
	while (event != NULL)
	{
		if ((*event->func.null_code)() == 1)
			return 1;
		event = _LimpX_FindEvent(0,event);
	}
	return 0;
}

static int _LimpX_Event_Redraw_Window()
{
	/* First look for exact match, then for inexact  */
	limpx_event *event;
	event = _LimpX_FindEvent(1,NULL);
	while (event != NULL)
	{
		if (event->criteria[0] != (int) NULL)
			if (((limpx_window *) event->criteria[0])->ro_handle == limpx.block.block[0])
				if ((*event->func.redraw_window)((limpx_window *) event->criteria[0]) == 1)
					return 1;
		event = _LimpX_FindEvent(1,event);
	}
	event = _LimpX_FindEvent(1,NULL);
	while (event != NULL)
	{
		if (event->criteria[0] == (int) NULL)
			if ((*event->func.redraw_window)(LimpX_WindowFromHandle(limpx.block.block[0])) == 1)
				return 1;
		event = _LimpX_FindEvent(1,event);
	}
	return 0;
}

static int _LimpX_Event_Open_Window()
{
	/* Look for exact, then inexact */
	limpx_event *event;
	event = _LimpX_FindEvent(2,NULL);
	while (event != NULL)
	{
		if (event->criteria[0] != (int) NULL)
			if (((limpx_window *) event->criteria[0])->ro_handle == limpx.block.block[0])
				if ((*event->func.open_window)((limpx_window *) event->criteria[0],(limpx_window_state *) &limpx.block.block[1]) == 1)
					return 1;
		event = _LimpX_FindEvent(2,event);
	}
	event = _LimpX_FindEvent(2,NULL);
	while (event != NULL)
	{
		if (event->criteria[0] == (int) NULL)
			if ((*event->func.open_window)(LimpX_WindowFromHandle(limpx.block.block[0]),(limpx_window_state *) &limpx.block.block[1]) == 1)
				return 1;
		event = _LimpX_FindEvent(2,event);
	}
	return 0;
}

static int _LimpX_Event_Close_Window()
{
	/* First look for exact match, then for inexact  */
	limpx_event *event;
	event = _LimpX_FindEvent(3,NULL);
	while (event != NULL)
	{
		if (event->criteria[0] != (int) NULL)
			if (((limpx_window *) event->criteria[0])->ro_handle == limpx.block.block[0])
				if ((*event->func.close_window)((limpx_window *) event->criteria[0]) == 1)
					return 1;
		event = _LimpX_FindEvent(3,event);
	}
	event = _LimpX_FindEvent(3,NULL);
	while (event != NULL)
	{
		if (event->criteria[0] == (int) NULL)
			if ((*event->func.close_window)(LimpX_WindowFromHandle(limpx.block.block[0])) == 1)
				return 1;
		event = _LimpX_FindEvent(3,event);
	}
	return 0;
}

static int _LimpX_Event_Pointer_Leave()
{
	/* First look for exact match, then for inexact  */
	limpx_event *event;
	event = _LimpX_FindEvent(4,NULL);
	while (event != NULL)
	{
		if (event->criteria[0] != (int) NULL)
			if (((limpx_window *) event->criteria[0])->ro_handle == limpx.block.block[0])
				if ((*event->func.pointer_leave)((limpx_window *) event->criteria[0]) == 1)
					return 1;
		event = _LimpX_FindEvent(4,event);
	}
	event = _LimpX_FindEvent(4,NULL);
	while (event != NULL)
	{
		if (event->criteria[0] == (int) NULL)
			if ((*event->func.pointer_leave)(LimpX_WindowFromHandle(limpx.block.block[0])) == 1)
				return 1;
		event = _LimpX_FindEvent(4,event);
	}
	return 0;
}

static int _LimpX_Event_Pointer_Enter()
{
	/* First look for exact match, then for inexact  */
	limpx_event *event;
	event = _LimpX_FindEvent(5,NULL);
	while (event != NULL)
	{
		if (event->criteria[0] != (int) NULL)
			if (((limpx_window *) event->criteria[0])->ro_handle == limpx.block.block[0])
				if ((*event->func.pointer_enter)((limpx_window *) event->criteria[0]) == 1)
					return 1;
		event = _LimpX_FindEvent(5,event);
	}
	event = _LimpX_FindEvent(5,NULL);
	while (event != NULL)
	{
		if (event->criteria[0] == (int) NULL)
			if ((*event->func.pointer_enter)(LimpX_WindowFromHandle(limpx.block.block[0])) == 1)
				return 1;
		event = _LimpX_FindEvent(5,event);
	}
	return 0;
}

static int _LimpX_Event_Mouse_Click()
{
	/* First look for exact win,icon match */
	/* Then for win match */
	/* Then general func */
	limpx_event *event;
	limpx_window *win;
	limpx_icon *icon;
	event = _LimpX_FindEvent(6,NULL);
	win = LimpX_WindowFromHandle(limpx.block.block[3]);
	icon = LimpX_IconFromHandle(limpx.block.block[3],limpx.block.block[4]);
	while (event != NULL)
	{
		if ((event->criteria[0] == (int) win) && (event->criteria[1] == (int) icon))
			if ((*event->func.mouse_click)((limpx_mouse_obj *) limpx.block.block,win,icon) == 1)
				return 1;
		event = _LimpX_FindEvent(6,event);
	}
	event = _LimpX_FindEvent(6,NULL);
	while (event != NULL)
	{
		if ((event->criteria[0] == (int) win) && (event->criteria[1] == (int) NULL))
			if ((*event->func.mouse_click)((limpx_mouse_obj *) limpx.block.block,win,icon) == 1)
				return 1;
		event = _LimpX_FindEvent(6,event);
	}
	event = _LimpX_FindEvent(6,NULL);
	while (event != NULL)
	{ 
		if ((event->criteria[0] == (int) NULL) && (event->criteria[1] == (int) NULL))
			if ((*event->func.mouse_click)((limpx_mouse_obj *) limpx.block.block,win,icon) == 1)
				return 1;
		event = _LimpX_FindEvent(6,event);
	}
	return 0;
}

static int _LimpX_Event_Drag_Box()
{
	/* Look for any drag box handler that accepts it */
	limpx_event *event;
	event = _LimpX_FindEvent(7,NULL);
	while (event != NULL)
	{
		if ((*event->func.drag_box)(limpx.block.block[0],limpx.block.block[1],limpx.block.block[2],limpx.block.block[3]) == 1)
			return 1;
		event = _LimpX_FindEvent(7,event);
	}
	return 0;
}

static int _LimpX_Event_Key_Pressed()
{
	/* Search with same pattern as mouse_click... */
	limpx_event *event;
	limpx_window *win;
	limpx_icon *icon;
	event = _LimpX_FindEvent(8,NULL);
	win = LimpX_WindowFromHandle(limpx.block.block[0]);
	icon = LimpX_IconFromHandle(limpx.block.block[0],limpx.block.block[1]);
	while (event != NULL)
	{
		if ((event->criteria[0] == (int) win) && (event->criteria[1] == (int) icon))
			if ((*event->func.key_pressed)((limpx_caret_obj *) limpx.block.block,limpx.block.block[6]) == 1)
				return 1;
		event = _LimpX_FindEvent(8,event);
	}
	event = _LimpX_FindEvent(8,NULL);
	while (event != NULL)
	{
		if ((event->criteria[0] == (int) win) && (event->criteria[1] == (int) NULL))
			if ((*event->func.key_pressed)((limpx_caret_obj *) limpx.block.block,limpx.block.block[6]) == 1)
				return 1;
		event = _LimpX_FindEvent(8,event);
	}
	event = _LimpX_FindEvent(8,NULL);
	while (event != NULL)
	{ 
		if ((event->criteria[0] == (int) NULL) && (event->criteria[1] == (int) NULL))
			if ((*event->func.key_pressed)((limpx_caret_obj *) limpx.block.block,limpx.block.block[6]) == 1)
				return 1;
		event = _LimpX_FindEvent(8,event);
	}
	return 0;
}

static int _LimpX_Event_Menu_Selection()
{
	limpx_event *event;
	event = _LimpX_FindEvent(9,NULL);
	while (event != NULL)
	{
		if ((*event->func.menu_selection)(limpx.block.block) == 1)
			return 1;
		event = _LimpX_FindEvent(9,event);
	}
	return 0;
}

static int _LimpX_Event_Scroll_Request()
{
	/* Window match */
	limpx_event *event;
	event = _LimpX_FindEvent(10,NULL);
	while (event != NULL)
	{
		if (event->criteria[0] != (int) NULL)
			if (((limpx_window *) event->criteria[0])->ro_handle == limpx.block.block[0])
				if ((*event->func.scroll_request)((limpx_window *) event->criteria[0],(limpx_window_state *) &limpx.block.block[1],limpx.block.block[8],limpx.block.block[9]) == 1)
					return 1;
		event = _LimpX_FindEvent(10,event);
	}
	event = _LimpX_FindEvent(10,NULL);
	while (event != NULL)
	{
		if (event->criteria[0] == (int) NULL)
			if ((*event->func.scroll_request)(LimpX_WindowFromHandle(limpx.block.block[0]),(limpx_window_state *) &limpx.block.block[1],limpx.block.block[8],limpx.block.block[9]) == 1)
				return 1;
		event = _LimpX_FindEvent(10,event);
	}
	return 0;
}

static int _LimpX_Event_Lose_Caret()
{
	/* window,icon match */
	limpx_event *event;
	limpx_window *win;
	limpx_icon *icon;
	event = _LimpX_FindEvent(11,NULL);
	win = LimpX_WindowFromHandle(limpx.block.block[0]);
	icon = LimpX_IconFromHandle(limpx.block.block[0],limpx.block.block[1]);
	while (event != NULL)
	{
		if ((event->criteria[0] == (int) win) && (event->criteria[1] == (int) icon))
			if ((*event->func.lose_caret)((limpx_caret_obj *) limpx.block.block) == 1)
				return 1;
		event = _LimpX_FindEvent(11,event);
	}
	event = _LimpX_FindEvent(11,NULL);
	while (event != NULL)
	{
		if ((event->criteria[0] == (int) win) && (event->criteria[1] == (int) NULL))
			if ((*event->func.lose_caret)((limpx_caret_obj *) limpx.block.block) == 1)
				return 1;
		event = _LimpX_FindEvent(11,event);
	}
	event = _LimpX_FindEvent(11,NULL);
	while (event != NULL)
	{ 
		if ((event->criteria[0] == (int) NULL) && (event->criteria[1] == (int) NULL))
			if ((*event->func.lose_caret)((limpx_caret_obj *) limpx.block.block) == 1)
				return 1;
		event = _LimpX_FindEvent(11,event);
	}
	return 0;
}

static int _LimpX_Event_Gain_Caret()
{
	/* as above */
	limpx_event *event;
	limpx_window *win;
	limpx_icon *icon;
	event = _LimpX_FindEvent(12,NULL);
	win = LimpX_WindowFromHandle(limpx.block.block[0]);
	icon = LimpX_IconFromHandle(limpx.block.block[0],limpx.block.block[1]);
	while (event != NULL)
	{
		if ((event->criteria[0] == (int) win) && (event->criteria[1] == (int) icon))
			if ((*event->func.gain_caret)((limpx_caret_obj *) limpx.block.block) == 1)
				return 1;
		event = _LimpX_FindEvent(12,event);
	}
	event = _LimpX_FindEvent(12,NULL);
	while (event != NULL)
	{
		if ((event->criteria[0] == (int) win) && (event->criteria[1] == (int) NULL))
			if ((*event->func.gain_caret)((limpx_caret_obj *) limpx.block.block) == 1)
				return 1;
		event = _LimpX_FindEvent(12,event);
	}
	event = _LimpX_FindEvent(12,NULL);
	while (event != NULL)
	{ 
		if ((event->criteria[0] == (int) NULL) && (event->criteria[1] == (int) NULL))
			if ((*event->func.gain_caret)((limpx_caret_obj *) limpx.block.block) == 1)
				return 1;
		event = _LimpX_FindEvent(12,event);
	}
	return 0;
}

static int _LimpX_Event_Poll_NonZero()
{
	limpx_event *event;
	event = _LimpX_FindEvent(13,NULL);
	while (event != NULL)
	{
		if ((*event->func.poll_nonzero)() == 1)
			return 1;
		event = _LimpX_FindEvent(13,event);
	}
	return 0;
}

static int _LimpX_Event_User_Message()
{
	/* Look for exact event match, then inexact */
	limpx_event *event;
	event = _LimpX_FindEvent(17,NULL);
	while (event != NULL)
	{
		if (event->criteria[0] == limpx.block.block[4])
			if ((*event->func.user_message)(limpx.block.code,limpx.block.block) == 1)
				return 1;
		event = _LimpX_FindEvent(17,event);
	}
	event = _LimpX_FindEvent(17,NULL);
	while (event != NULL)
	{
		if (event->criteria[0] == -1)
			if ((*event->func.user_message)(limpx.block.code,limpx.block.block) == 1)
				return 1;
		event = _LimpX_FindEvent(17,event);
	}
	return 0;
}

static int _LimpX_Event_Other_Event()
{
	limpx_event *event;
	event = _LimpX_FindEvent(-1,NULL);
	while (event != NULL)
	{
		if ((*event->func.other_event)(limpx.block.code,limpx.block.block) == 1)
			return 1;
		event = _LimpX_FindEvent(-1,event);
	}
	return 0;
}

static int _LimpX_EventHandler()
{
	/* Branch to appropriate function... */
	switch (limpx.block.code)
	{
		case 0:
			return _LimpX_Event_Null();
		case 1:
			if (_LimpX_Event_Redraw_Window() == 1)
				return 1;
			break;
		case 2:
			if (_LimpX_Event_Open_Window() == 1)
				return 1;
			break;
		case 3:
			if (_LimpX_Event_Close_Window() == 1)
				return 1;
			break;
		case 4:
			if (_LimpX_Event_Pointer_Leave() == 1)
				return 1;
			break;
		case 5:
			if (_LimpX_Event_Pointer_Enter() == 1)
				return 1;
			break;
		case 6:
			if (_LimpX_Event_Mouse_Click() == 1)
				return 1;
			break;
		case 7:
			if (_LimpX_Event_Drag_Box() == 1)
				return 1;
			break;
		case 8:
			if (_LimpX_Event_Key_Pressed() == 1)
				return 1;
			break;
		case 9:
			if (_LimpX_Event_Menu_Selection() == 1)
				return 1;
			break;
		case 10:
			if (_LimpX_Event_Scroll_Request() == 1)
				return 1;
			break;
		case 11:
			if (_LimpX_Event_Lose_Caret() == 1)
				return 1;
			break;
		case 12:
			if (_LimpX_Event_Gain_Caret() == 1)
				return 1;
			break;
		case 13:
			return _LimpX_Event_Poll_NonZero(); /* Only one handler for this */
		case 17:
		case 18:
		case 19:
			if (_LimpX_Event_User_Message() == 1)
				return 1;
			break;
	}
	/* Otherwise, try the 'other' function */
	return _LimpX_Event_Other_Event();
}

static void _LimpX_DeleteWindowEvents(limpx_window *w)
{
	/* Delete all events to do with that window... */
	/* * Events that only link to window through its icon? * */
	limpx_event *next,*cur;
	cur = limpx.events;
	while (cur != NULL)
	{
		next = cur->next;
		switch (cur->code)
		{
			case 1: /* Redraw window */
			case 2: /* Open window */
			case 3: /* Close window */
			case 4: /* Pointer leave */
			case 5: /* Pointer enter */
			case 6: /* Mouse click */
			case 8: /* Key pressed */
			case 10: /* Scroll request */
			case 11: /* Lose caret */
			case 12: /* Gain caret */
				if (cur->criteria[0] == (int) w)
					LimpX_DeleteEvent(cur);
		}
		cur = next;
	}
}

static void _LimpX_DeleteIconEvents(limpx_icon *i)
{
	limpx_event *next,*cur;
	cur = limpx.events;
	while (cur != NULL)
	{
		next = cur->next;
		switch (cur->code)
		{
			case 6: /* Mouse click */
			case 8: /* Key pressed */
			case 11: /* Lose caret */
			case 12: /* Gain caret */
				if (cur->criteria[0] == (int) i)
					LimpX_DeleteEvent(cur);
		}
		cur = next;
	}
}

#endif
