changeset 0:f840ca9a1a98

Initial commit.
author Brian Smith <brian@dbsoft.org>
date Fri, 18 Feb 2011 02:50:18 -0600
parents
children 43def5d33575
files README decoder_plug.h decoder_plug.html dw.c dw.h filter_plug.h filter_plug.html format.h license.txt makefile nuclear.c nuclear.def ooura1d.lib ooura1d.txt output_plug.h output_plug.html plugin.h plugin.html visual_plug.html
diffstat 19 files changed, 12886 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README	Fri Feb 18 02:50:18 2011 -0600
@@ -0,0 +1,30 @@
+Currently to replace the default analyzer in PM123 we need to replace analyzer.dll.
+This will change in the future.  But for now back up the default analyzer.dll in the
+VISPLUG directory.  And put this one in it's place. 
+
+The DIVE renderer may not work on all systems, but it performs about 10x better than
+the standard GPI renderer.  So I would recommend having DIVE enabled unless you are
+experiencing problems with DIVE.
+
+
+Changes:
+
+Merged latest Dynamic Windows source, changes to deal with new features
+of Dynamic Windows.
+
+Added notebook to the preferences dialog, and a page called Visuals.
+
+Added 2 more rendering schemes (color patterns).
+
+Fixed maximum peaks not making it to the top.
+
+Added a build option to clear the entire area before blitting, solves problems
+with peaks getting "stuck".
+
+Build without debug information so CPPOM30.DLL is not required.
+
+Thanks!
+
+Please send any comments or suggestions to dbsoft@technologist.com
+
+Brian Smith
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decoder_plug.h	Fri Feb 18 02:50:18 2011 -0600
@@ -0,0 +1,164 @@
+#if __cplusplus
+extern "C" {
+#endif
+
+#define WM_PLAYSTOP           WM_USER+69
+#define WM_PLAYERROR          WM_USER+100
+#define WM_SEEKSTOP           WM_USER+666
+
+
+int  _System decoder_init(void **w);
+BOOL _System decoder_uninit(void *w);
+
+#define DECODER_PLAY    1 /* returns 101 -> already playing
+                                     102 -> error, decoder killed */
+#define DECODER_STOP    2 /* returns 101 -> already stopped
+                                     102 -> error, decoder killed (and stopped) */
+#define DECODER_FFWD    3
+#define DECODER_REW     4
+#define DECODER_JUMPTO  5
+#define DECODER_SETUP   6
+#define DECODER_EQ      7
+#define DECODER_BUFFER  8
+
+typedef struct {
+   int size;
+
+   /* --- DECODER_PLAY, STOP */
+
+   char *filename;
+   char *URL;
+   char *drive; /* for CD ie.: "X:" */
+   int  track;
+   int sectors[2];  /* play from sector x to sector y */
+   char *other;
+
+   /* --- DECODER_REW, FFWD and JUMPTO */
+
+   int jumpto;     /* absolute positioning in milliseconds */
+   int ffwd;       /* 1 = start ffwd, 0 = end ffwd */
+   int rew;        /* 1 = start rew, 0 = end rew */
+
+   /* --- DECODER_SETUP */
+
+   /* specify a function which the decoder should use for output */
+   int (* _System output_play_samples)(void *a, FORMAT_INFO *format, char *buf, int len, int posmarker);
+   void *a; /* only to be used with the precedent function */
+   int audio_buffersize;
+
+   char *proxyurl; /* NULL = none */
+   char *httpauth; /* NULL = none */
+
+   /* error message function the decoder should use */
+   void (* _System error_display)(char *);
+
+   HEV playsem;  /* this semaphore is reseted when DECODER_PLAY is requested
+                    and is posted on stop */
+
+   HWND hwnd; // commodity for PM interface, decoder must send a few messages to this handle
+
+   /* values used for streaming inputs by the decoder */
+   int buffersize; /* read ahead buffer in bytes, 0 = disabled */
+   int bufferwait; /* block the first read until the buffer is filled */
+
+   /* -- DECODER_BUFFER */
+
+   int bufferstatus; /* reports how many bytes there are available in the buffer */
+
+   /* --- DECODER_EQ */
+
+   /* usually only useful with MP3 decoder */
+   int equalizer;    /* TRUE or FALSE */
+   float *bandgain;  /* point to an array like this bandgain[#channels][10] */
+
+} DECODER_PARAMS;
+
+/* returns 0 -> ok
+           1 -> command unsupported
+           1xx -> msg specific */
+ULONG _System decoder_command(void *w, ULONG msg, DECODER_PARAMS *params);
+
+#define DECODER_STOPPED  0
+#define DECODER_PLAYING  1
+#define DECODER_STARTING 2
+ULONG _System decoder_status(void *w);
+
+/* WARNING!! this _can_ change in time!!! returns stream length in ms */
+/* the decoder should keep in memory a last valid length so the call  */
+/* remains valid even if decoder_status() == DECODER_STOPPED          */
+ULONG _System decoder_length(void *w);
+
+static char *modes[4] = { "Stereo", "Joint-Stereo", "Dual-Channel", "Single-Channel" };
+
+/* NOTE: the information returned is only based on the FIRST header */
+typedef struct {
+   int size;
+
+   FORMAT_INFO format; /* stream format after decoding */
+
+   int songlength; /* in milliseconds, smaller than 0 -> unknown */
+   int junklength; /* bytes of junk before stream start, if < 0 -> unknown */
+
+   /* mpeg stuff */
+   int mpeg; /* 25 = MPEG 2.5, 10 = MPEG 1.0, 20 = MPEG 2.0, 0 = not an MPEG */
+   int layer; /* 0 = unknown */
+   int mode; /* use it on modes[4] */
+   int modext; /* didn't check what this one does */
+   int bpf; /* bytes in the mpeg frame including header */
+   int bitrate; /* in kbit/s */
+   int extention; /* didn't check what this one does */
+
+   /* track stuff */
+   int startsector;
+   int endsector;
+
+   /* module stuff */
+   int numchannels;  /* 0 = not a MODule */
+   int numpatterns;
+   int numpositions;
+
+   /* general technical information string */
+   char tech_info[128];
+
+   /* song information */
+   char title[80];
+   char artist[80];
+   char album[80];
+   char year[80];
+   char comment[80];
+   char genre[80];
+
+} DECODER_INFO;
+
+/* returns
+      0 = everything's perfect, structure is set
+      100 = error reading file (too small?)
+      200 = decoder can't play that
+      1001 = http error occured, check http_strerror() for string;
+      other values = errno */
+ULONG _System decoder_fileinfo(char *filename, DECODER_INFO *info);
+ULONG _System decoder_trackinfo(char *drive, int track, DECODER_INFO *info);
+
+typedef struct
+{
+   int sectors;
+   int firsttrack;
+   int lasttrack;
+} DECODER_CDINFO;
+
+ULONG _System decoder_cdinfo(char *drive, DECODER_CDINFO *info);
+
+
+/* returns ORed values */
+#define DECODER_FILENAME  0x1
+#define DECODER_URL       0x2
+#define DECODER_TRACK     0x4
+#define DECODER_OTHER     0x8
+/* size is i/o and is the size of the array.
+   each ext should not be bigger than 8bytes */
+ULONG _System decoder_support(char *fileext[], int *size);
+
+
+#if __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decoder_plug.html	Fri Feb 18 02:50:18 2011 -0600
@@ -0,0 +1,156 @@
+<HTML>
+<HEAD>
+   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+   <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (OS/2; U) [Netscape]">
+   <TITLE>PM123 Decoder Plug-in Developer's Guide</TITLE>
+</HEAD>
+<BODY>
+
+<H3>Decoder plug-ins</H3>
+
+Decoder plug-ins must implement and export the functions defined in
+decoder_plug.h.<P>
+
+<TT>int  _System decoder_init(void **w)<BR>
+BOOL _System decoder_uninit(void *w)</TT>
+<UL>
+<LI>w : Allocate any chunk of memory necessary for the decoder's
+function.  This pointer will be passed to the other functions.</LI>
+<LI>return value : -1 means the decoder was not initialized
+successfully.</LI>
+</UL>
+
+Init function is called when pm123 needs the specified decoder
+to play the stream demanded by the user.  So only one decoder plug-in is
+active at any given time.  It should initialize the necessary semaphores
+and threads.  <TT>decoder_uninit</TT> is called when another decoder
+than yours is needed, and should destroy the decoder's thread,
+semaphores, other opened handles and free allocated memory for w.<P>
+
+<TT>ULONG _System decoder_command(void *w, ULONG msg, DECODER_PARAMS *params)</TT>
+
+<UL>
+<LI>msg: one of the following:<BR>
+DECODER_PLAY<BR>
+DECODER_STOP<BR>
+DECODER_FFWD<BR>
+DECODER_REW<BR>
+DECODER_JUMPTO<BR>
+DECODER_SETUP<BR>
+DECODER_EQ<BR>
+DECODER_BUFFER</LI>
+<LI>params: structure that contains the parameters needed by the preceding
+commands</LI>
+<LI>return value:<BR>
+0 -> ok<BR>
+1 -> command unsupported<BR>
+1xx -> msg specific <BR></LI>
+</UL>
+
+There is a lot of commands to implement for this function.  Parameters
+needed for each of the are described in the definition of the structure
+in the .h file.
+
+<UL>
+<LI>DECODER_PLAY start playing the given filename, URL or others.</LI>
+<LI>DECODER_STOP stop playing.</LI>
+<LI>DECODER_FFWD engage in ffwd mode (ie.: play faster or skip when playing)</LI>
+<LI>DECODER_REW  engage rewind mode</LI>
+<LI>DECODER_JUMPTO jump and start decoding at the given time position</LI>
+<LI>DECODER_SETUP setup various parameters such as the output plugin
+functions, hwnd where to send messages and an optional play semaphore.</LI>
+<LI>DECODER_EQ usually only useful for MPEG decoding where frequency
+equalization is cheap.</LI>
+<LI>DECODER_BUFFER reports the reader buffer status.</LI>
+</UL>
+
+The decoder MUST WinPostMsg() the following messages to <TT>hwnd</TT>:
+
+<UL>
+<LI>WM_PLAYSTOP when the stream has finished decoding.</LI>
+<LI>WM_PLAYERROR when a playback error occured so that pm123 should know to
+stop immediately.</LI>
+<LI>WM_SEEKSTOP when a JUMPTO operation is completed (ie.: when no buffers
+from before the seek is sent to the output plugin anymore).</LI>
+</UL>
+
+<TT>ULONG _System decoder_status(void *w)</TT>
+
+<UL>
+<LI>return value - One of the following: <BR>
+DECODER_STOPPED<BR>
+DECODER_PLAYING<BR>
+DECODER_STARTING<BR>
+</UL>
+
+<TT>ULONG _System decoder_length(void *w)</TT>
+<UL>
+<LI>return value - number of milliseconds the stream lasts (you can
+report -1 if unknown)</LI>
+</UL>
+
+The call to this function must be valid even if DECODER_STARTING or
+DECODER_STOPPED is reported (when the stream plays too fast for
+example).<P>
+
+<TT>
+ULONG _System decoder_fileinfo(char *filename, DECODER_INFO *info)<BR>
+ULONG _System decoder_trackinfo(char *drive, int track, DECODER_INFO *info)
+</TT>
+
+<UL>
+<LI>filename : full path or URL to the desired stream.</LI>
+<LI>drive : ie.: "X:"</LI>
+<LI>track : CD tracks start from 1.</LI>
+<LI>info : this structure must be filled with the required
+information.</LI>
+<LI> return value:<BR>
+0 = everything's perfect, structure is set<BR>
+100 = error reading file (too small?)<BR>
+200 = decoder can't play that<BR>
+1001 = http error occured<BR>
+other values = errno </LI>
+
+</UL>
+
+<TT>decoder_fileinfo</TT> and <TT>decoder_trackinfo</TT> (for CD
+decoders) must be independant from the current status of the decoder.
+It should always be functionnaly and give consistent results in any
+conditions.<P>
+
+<TT>ULONG _System decoder_cdinfo(char *drive, DECODER_CDINFO *info)</TT>
+
+<UL>
+<LI>drive: ...</LI>
+<LI>info: required info on the number of tracks available from the
+decoder.</LI>
+</UL>
+
+This is used by pm123 before calling <TT>decoder_trackinfo</TT>.<P>
+
+<TT>ULONG _System decoder_support(char *fileext[], int *size)</TT>
+
+<UL>
+<LI>fileext: fill this array with all the wildcard expression matching
+filenames this decoder can play (each element is a 8 bytes char array).
+</LI>
+<LI>size I/O: number of wildcard expressions returned (if this value is not
+big enough, ie.: 0, return the appropriate size without filling
+fileext)</LI>
+<LI>return value: return what kind of stream can the decoder play:<BR>
+DECODER_FILENAME<BR>
+DECODER_URL<BR>
+DECODER_TRACK<BR>
+DECODER_OTHER</LI>
+
+</UL>
+This is used by pm123 to suggest to the user what he can play with the
+decoder. Extentions can be for example "*.MOD".
+<P>
+
+<HR size=1><I><FONT SIZE=-1>Last revised May 20, 2000, Copyright &copy;
+Taneli Lepp&auml; &lt;rosmo@sektori.com>, Samuel Audet &lt;guardia@cam.org></FONT></I>
+</BODY>
+</HTML>
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dw.c	Fri Feb 18 02:50:18 2011 -0600
@@ -0,0 +1,9489 @@
+/*
+/*
+ * Dynamic Windows:
+ *          A GTK like implementation of the PM GUI
+ *
+ * (C) 2000-2004 Brian Smith <dbsoft@technologist.com>
+ * (C) 2003-2004 Mark Hessling <m.hessling@qut.edu.au>
+ * (C) 2000 Achim Hasenmueller <achimha@innotek.de>
+ * (C) 2000 Peter Nielsen <peter@pmview.com>
+ * (C) 1998 Sergey I. Yevtushenko (some code borrowed from cell toolkit)
+ *
+ */
+#define INCL_DOS
+#define INCL_DOSERRORS
+#define INCL_WIN
+#define INCL_GPI
+
+#include <os2.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <process.h>
+#include <time.h>
+#include <io.h>
+#ifndef __EMX__
+#include <direct.h>
+#endif
+#include <sys/time.h>
+#include "dw.h"
+
+#define QWP_USER 0
+
+/* The toolkit headers don't seem to have this */
+BOOL APIENTRY WinStretchPointer(HPS hps, LONG x, LONG y, LONG cx, LONG cy, HPOINTER hptr, ULONG fs);
+
+MRESULT EXPENTRY _run_event(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2);
+MRESULT EXPENTRY _wndproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2);
+void _do_resize(Box *thisbox, int x, int y);
+void _handle_splitbar_resize(HWND hwnd, float percent, int type, int x, int y);
+int _load_bitmap_file(char *file, HWND handle, HBITMAP *hbm, HDC *hdc, HPS *hps, unsigned long *width, unsigned long *height);
+void _dw_box_pack_start(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad, char *functionname);
+void _dw_box_pack_end(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad, char *functionname);
+void _free_menu_data(HWND menu);
+
+char ClassName[] = "dynamicwindows";
+char SplitbarClassName[] = "dwsplitbar";
+char *DefaultFont = "9.WarpSans";
+
+HAB dwhab = 0;
+HMQ dwhmq = 0;
+DWTID _dwtid = 0;
+LONG _foreground = 0xAAAAAA, _background = DW_CLR_DEFAULT;
+
+HWND hwndApp = NULLHANDLE, hwndBubble = NULLHANDLE, hwndBubbleLast = NULLHANDLE, hwndEmph = NULLHANDLE;
+PRECORDCORE pCoreEmph = NULL;
+ULONG aulBuffer[4], GlobalID = 10000;
+HWND lasthcnr = 0, lastitem = 0, popup = 0, desktop;
+HMOD wpconfig = 0;
+
+unsigned long _colors[] = {
+	CLR_BLACK,
+	CLR_DARKRED,
+	CLR_DARKGREEN,
+	CLR_BROWN,
+	CLR_DARKBLUE,
+	CLR_DARKPINK,
+	CLR_DARKCYAN,
+	CLR_PALEGRAY,
+	CLR_DARKGRAY,
+	CLR_RED,
+	CLR_GREEN,
+	CLR_YELLOW,
+	CLR_BLUE,
+	CLR_PINK,
+	CLR_CYAN,
+	CLR_WHITE
+};
+
+#define IS_WARP4() (aulBuffer[0] == 20 && aulBuffer[1] >= 40)
+
+#ifndef min
+#define min(a, b) (((a < b) ? a : b))
+#endif
+
+typedef struct _sighandler
+{
+	struct _sighandler	*next;
+	ULONG message;
+	HWND window;
+	int id;
+	void *signalfunction;
+	void *data;
+
+} SignalHandler;
+
+SignalHandler *Root = NULL;
+
+typedef struct
+{
+	ULONG message;
+	char name[30];
+
+} SignalList;
+
+/* List of signals and their equivilent OS/2 message */
+#define SIGNALMAX 16
+
+SignalList SignalTranslate[SIGNALMAX] = {
+	{ WM_SIZE,         DW_SIGNAL_CONFIGURE },
+	{ WM_CHAR,         DW_SIGNAL_KEY_PRESS },
+	{ WM_BUTTON1DOWN,  DW_SIGNAL_BUTTON_PRESS },
+	{ WM_BUTTON1UP,    DW_SIGNAL_BUTTON_RELEASE },
+	{ WM_MOUSEMOVE,    DW_SIGNAL_MOTION_NOTIFY },
+	{ WM_CLOSE,        DW_SIGNAL_DELETE },
+	{ WM_PAINT,        DW_SIGNAL_EXPOSE },
+	{ WM_COMMAND,      DW_SIGNAL_CLICKED },
+	{ CN_ENTER,        DW_SIGNAL_ITEM_ENTER },
+	{ CN_CONTEXTMENU,  DW_SIGNAL_ITEM_CONTEXT },
+	{ LN_SELECT,       DW_SIGNAL_LIST_SELECT },
+	{ CN_EMPHASIS,     DW_SIGNAL_ITEM_SELECT },
+	{ WM_SETFOCUS,     DW_SIGNAL_SET_FOCUS },
+	{ SLN_SLIDERTRACK, DW_SIGNAL_VALUE_CHANGED },
+	{ BKN_PAGESELECTED,DW_SIGNAL_SWITCH_PAGE },
+	{ CN_EXPANDTREE,   DW_SIGNAL_TREE_EXPAND }
+};
+
+/* This function adds a signal handler callback into the linked list.
+ */
+void _new_signal(ULONG message, HWND window, int id, void *signalfunction, void *data)
+{
+	SignalHandler *new = malloc(sizeof(SignalHandler));
+
+	new->message = message;
+	new->window = window;
+	new->id = id;
+	new->signalfunction = signalfunction;
+	new->data = data;
+	new->next = NULL;
+
+	if (!Root)
+		Root = new;
+	else
+	{
+		SignalHandler *prev = NULL, *tmp = Root;
+		while(tmp)
+		{
+			if(tmp->message == message &&
+			   tmp->window == window &&
+			   tmp->id == id &&
+			   tmp->signalfunction == signalfunction)
+			{
+				tmp->data = data;
+				free(new);
+				return;
+			}
+			prev = tmp;
+			tmp = tmp->next;
+		}
+		if(prev)
+			prev->next = new;
+		else
+			Root = new;
+	}
+}
+
+/* Finds the message number for a given signal name */
+ULONG _findsigmessage(char *signame)
+{
+	int z;
+
+	for(z=0;z<SIGNALMAX;z++)
+	{
+		if(stricmp(signame, SignalTranslate[z].name) == 0)
+			return SignalTranslate[z].message;
+	}
+	return 0L;
+}
+
+typedef struct _CNRITEM
+{
+	MINIRECORDCORE rc;
+	HPOINTER       hptrIcon;
+	PVOID          user;
+	HTREEITEM      parent;
+
+} CNRITEM, *PCNRITEM;
+
+
+int _null_key(HWND window, int key, void *data)
+{
+	window = window; /* keep compiler happy */
+	key = key; /* keep compiler happy */
+	data = data; /* keep compiler happy */
+	return TRUE;
+}
+
+/* Find the desktop window handle */
+HWND _toplevel_window(HWND handle)
+{
+	HWND box, lastbox = WinQueryWindow(handle, QW_PARENT);
+
+	/* Find the toplevel window */
+	while((box = WinQueryWindow(lastbox, QW_PARENT)) != desktop && box > 0)
+	{
+		lastbox = box;
+	}
+	if(box > 0)
+		return lastbox;
+	return handle;
+}
+
+
+/* Returns height of specified window. */
+int _get_height(HWND handle)
+{
+	unsigned long height;
+	dw_window_get_pos_size(handle, NULL, NULL, NULL, &height);
+	return (int)height;
+}
+
+/* Find the height of the frame a desktop style window is sitting on */
+int _get_frame_height(HWND handle)
+{
+	while(handle)
+	{
+		HWND client;
+		if((client = WinWindowFromID(handle, FID_CLIENT)) != NULLHANDLE)
+		{
+            return _get_height(WinQueryWindow(handle, QW_PARENT));
+		}
+        handle = WinQueryWindow(handle, QW_PARENT);
+	}
+	return dw_screen_height();
+}
+
+/* A "safe" WinSendMsg() that tries multiple times in case the
+ * queue is blocked for one reason or another.
+ */
+MRESULT _dw_send_msg(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2, int failure)
+{
+	MRESULT res;
+	int z = 0;
+
+	while((int)(res = WinSendMsg(hwnd, msg, mp1, mp2)) == failure)
+	{
+		z++;
+		if(z > 5000000)
+			return (MRESULT)failure;
+		dw_main_sleep(1);
+	}
+	return res;
+}
+
+/* Used in the slider and percent classes internally */
+unsigned int _dw_percent_get_range(HWND handle)
+{
+	return SHORT2FROMMP(WinSendMsg(handle, SLM_QUERYSLIDERINFO, MPFROM2SHORT(SMA_SLIDERARMPOSITION,SMA_RANGEVALUE), 0));
+}
+
+/* Return the entryfield child of a window */
+HWND _find_entryfield(HWND handle)
+{
+	HENUM henum;
+	HWND child, entry = 0;
+
+	henum = WinBeginEnumWindows(handle);
+	while((child = WinGetNextWindow(henum)) != NULLHANDLE)
+	{
+		char tmpbuf[100];
+
+		WinQueryClassName(child, 99, tmpbuf);
+
+		if(strncmp(tmpbuf, "#6", 3)==0)  /* Entryfield */
+		{
+			entry = child;
+			break;
+		}
+	}
+	WinEndEnumWindows(henum);
+	return entry;
+}
+
+/* This function changes the owner of buttons in to the
+ * dynamicwindows handle to fix a problem in notebooks.
+ */
+void _fix_button_owner(HWND handle, HWND dw)
+{
+	HENUM henum;
+	HWND child;
+
+	henum = WinBeginEnumWindows(handle);
+	while((child = WinGetNextWindow(henum)) != NULLHANDLE)
+	{
+		char tmpbuf[100];
+
+		WinQueryClassName(child, 99, tmpbuf);
+
+		if(strncmp(tmpbuf, "#3", 3)==0 && dw)  /* Button */
+			WinSetOwner(child, dw);
+		else if(strncmp(tmpbuf, "dynamicwindows", 14) == 0)
+			dw = child;
+
+		_fix_button_owner(child, dw);
+	}
+	WinEndEnumWindows(henum);
+	return;
+}
+
+/* Free bitmap data associated with a window */
+void _free_bitmap(HWND handle)
+{
+	HBITMAP hbm = (HBITMAP)dw_window_get_data(handle, "_dw_bitmap");
+	HPS hps = (HPS)dw_window_get_data(handle, "_dw_hps");
+	HDC hdc = (HDC)dw_window_get_data(handle, "_dw_hdc");
+	HPIXMAP pixmap = (HPIXMAP)dw_window_get_data(handle, "_dw_hpixmap");
+	HPIXMAP disable = (HPIXMAP)dw_window_get_data(handle, "_dw_hpixmap_disabled");
+	HPOINTER icon = (HPOINTER)dw_window_get_data(handle, "_dw_button_icon");
+
+	if(icon)
+		WinDestroyPointer(icon);
+
+	if(pixmap)
+		dw_pixmap_destroy(pixmap);
+
+	if(disable)
+		dw_pixmap_destroy(disable);
+
+	if(hps)
+	{
+		GpiSetBitmap(hps, NULLHANDLE);
+		GpiAssociate(hps, NULLHANDLE);
+		GpiDestroyPS(hps);
+	}
+
+	if(hdc)
+		DevCloseDC(hdc);
+
+	if(hbm)
+		GpiDeleteBitmap(hbm);
+}
+
+/* This function removes any handlers on windows and frees
+ * the user memory allocated to it.
+ */
+void _free_window_memory(HWND handle)
+{
+	HENUM henum;
+	HWND child;
+	void *ptr = (void *)WinQueryWindowPtr(handle, QWP_USER);
+
+	dw_signal_disconnect_by_window(handle);
+
+	if((child = WinWindowFromID(handle, FID_MENU)) != NULLHANDLE)
+		_free_menu_data(child);
+
+	if((child = WinWindowFromID(handle, FID_CLIENT)) != NULLHANDLE)
+	{
+		Box *box = (Box *)WinQueryWindowPtr(child, QWP_USER);
+
+		if(box)
+		{
+			if(box->count && box->items)
+				free(box->items);
+
+			WinSetWindowPtr(child, QWP_USER, 0);
+			free(box);
+		}
+	}
+
+	if(ptr)
+	{
+		WindowData *wd = (WindowData *)ptr;
+		char tmpbuf[100];
+
+		WinQueryClassName(handle, 99, tmpbuf);
+
+		if(strncmp(tmpbuf, "ColorSelectClass", 17)!=0)
+		{
+			/* If this window has an associate bitmap destroy it. */
+			_free_bitmap(handle);
+
+			if(strncmp(tmpbuf, "#1", 3)==0 && !WinWindowFromID(handle, FID_CLIENT))
+			{
+				Box *box = (Box *)ptr;
+
+				if(box->count && box->items)
+					free(box->items);
+			}
+			else if(strncmp(tmpbuf, SplitbarClassName, strlen(SplitbarClassName)+1)==0)
+			{
+				void *data = dw_window_get_data(handle, "_dw_percent");
+
+				if(data)
+					free(data);
+			}
+			else if(strncmp(tmpbuf, "#37", 4)==0)
+			{
+				dw_container_clear(handle, FALSE);
+				if(wd && dw_window_get_data(handle, "_dw_container"))
+				{
+					void *oldflags = wd->data;
+
+					wd->data = NULL;
+					free(oldflags);
+				}
+			}
+
+			if(wd->oldproc)
+				WinSubclassWindow(handle, wd->oldproc);
+
+			dw_window_set_data(handle, NULL, NULL);
+			WinSetWindowPtr(handle, QWP_USER, 0);
+			free(ptr);
+		}
+	}
+
+	henum = WinBeginEnumWindows(handle);
+	while((child = WinGetNextWindow(henum)) != NULLHANDLE)
+		_free_window_memory(child);
+
+	WinEndEnumWindows(henum);
+	return;
+}
+
+void _free_menu_data(HWND menu)
+{
+	int i, count = (int)WinSendMsg(menu, MM_QUERYITEMCOUNT, 0, 0);
+
+	dw_signal_disconnect_by_name(menu, DW_SIGNAL_CLICKED);
+	_free_window_memory(menu);
+
+	for(i=0;i<count;i++)
+	{
+		SHORT menuid = (SHORT)WinSendMsg(menu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(i), 0);
+		MENUITEM mi;
+
+		if(WinSendMsg(menu, MM_QUERYITEM, MPFROMSHORT(menuid), MPFROMP(&mi))
+		   && mi.hwndSubMenu)
+			_free_menu_data(mi.hwndSubMenu);
+	}
+}
+
+/* This function returns 1 if the window (widget) handle
+ * passed to it is a valid window that can gain input focus.
+ */
+int _validate_focus(HWND handle)
+{
+	char tmpbuf[100];
+
+	if(!handle)
+		return 0;
+
+	WinQueryClassName(handle, 99, tmpbuf);
+
+	if(!WinIsWindowEnabled(handle) ||
+	   (strncmp(tmpbuf, "ColorSelectClass", 17) && dw_window_get_data(handle, "_dw_disabled")))
+		return 0;
+
+	/* These are the window classes which can
+	 * obtain input focus.
+	 */
+	if(strncmp(tmpbuf, "#2", 3)==0 ||  /* Combobox */
+	   strncmp(tmpbuf, "#3", 3)==0 ||  /* Button */
+	   strncmp(tmpbuf, "#6", 3)==0 ||  /* Entryfield */
+	   strncmp(tmpbuf, "#7", 3)==0 ||  /* List box */
+	   strncmp(tmpbuf, "#10", 4)==0 || /* MLE */
+	   strncmp(tmpbuf, "#32", 4)==0 || /* Spinbutton */
+	   strncmp(tmpbuf, "#37", 4)==0 || /* Container */
+	   strncmp(tmpbuf, "#38", 4)== 0)  /* Slider */
+		return 1;
+	return 0;
+}
+
+int _focus_check_box(Box *box, HWND handle, int start, HWND defaultitem)
+{
+	int z;
+	static HWND lasthwnd, firsthwnd;
+    static int finish_searching;
+
+	/* Start is 2 when we have cycled completely and
+	 * need to set the focus to the last widget we found
+	 * that was valid.
+	 */
+	if(start == 2)
+	{
+		if(lasthwnd)
+			WinSetFocus(HWND_DESKTOP, lasthwnd);
+		return 0;
+	}
+
+	/* Start is 1 when we are entering the function
+	 * for the first time, it is zero when entering
+	 * the function recursively.
+	 */
+	if(start == 1)
+	{
+		lasthwnd = handle;
+		finish_searching = 0;
+		firsthwnd = 0;
+	}
+
+	for(z=box->count-1;z>-1;z--)
+	{
+		if(box->items[z].type == TYPEBOX)
+		{
+			Box *thisbox = WinQueryWindowPtr(box->items[z].hwnd, QWP_USER);
+
+			if(thisbox && _focus_check_box(thisbox, handle, start == 3 ? 3 : 0, defaultitem))
+				return 1;
+		}
+		else
+		{
+			if(box->items[z].hwnd == handle)
+			{
+				if(lasthwnd == handle && firsthwnd)
+					WinSetFocus(HWND_DESKTOP, firsthwnd);
+				else if(lasthwnd == handle && !firsthwnd)
+					finish_searching = 1;
+				else
+					WinSetFocus(HWND_DESKTOP, lasthwnd);
+
+				/* If we aren't looking for the last handle,
+				 * return immediately.
+				 */
+				if(!finish_searching)
+					return 1;
+			}
+			if(_validate_focus(box->items[z].hwnd))
+			{
+				/* Start is 3 when we are looking for the
+				 * first valid item in the layout.
+				 */
+				if(start == 3)
+				{
+					if(!defaultitem || (defaultitem && defaultitem == box->items[z].hwnd))
+					{
+						WinSetFocus(HWND_DESKTOP, box->items[z].hwnd);
+						return 1;
+					}
+				}
+
+				if(!firsthwnd)
+					firsthwnd = box->items[z].hwnd;
+
+				lasthwnd = box->items[z].hwnd;
+			}
+			else
+			{
+				char tmpbuf[100] = "";
+
+				WinQueryClassName(box->items[z].hwnd, 99, tmpbuf);
+				if(strncmp(tmpbuf, SplitbarClassName, strlen(SplitbarClassName)+1)==0)
+				{
+					/* Then try the bottom or right box */
+					HWND mybox = (HWND)dw_window_get_data(box->items[z].hwnd, "_dw_bottomright");
+
+					if(mybox)
+					{
+						Box *splitbox = (Box *)WinQueryWindowPtr(mybox, QWP_USER);
+
+						if(splitbox && _focus_check_box(splitbox, handle, start == 3 ? 3 : 0, defaultitem))
+							return 1;
+					}
+
+					/* Try the top or left box */
+					mybox = (HWND)dw_window_get_data(box->items[z].hwnd, "_dw_topleft");
+
+					if(mybox)
+					{
+						Box *splitbox = (Box *)WinQueryWindowPtr(mybox, QWP_USER);
+
+						if(splitbox && _focus_check_box(splitbox, handle, start == 3 ? 3 : 0, defaultitem))
+							return 1;
+					}
+				}
+				else if(strncmp(tmpbuf, "#40", 4)==0) /* Notebook */
+				{
+					Box *notebox;
+					HWND page = (HWND)WinSendMsg(box->items[z].hwnd, BKM_QUERYPAGEWINDOWHWND,
+												 (MPARAM)dw_notebook_page_get(box->items[z].hwnd), 0);
+
+					if(page)
+					{
+						notebox = (Box *)WinQueryWindowPtr(page, QWP_USER);
+
+						if(notebox && _focus_check_box(notebox, handle, start == 3 ? 3 : 0, defaultitem))
+							return 1;
+					}
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+int _focus_check_box_back(Box *box, HWND handle, int start, HWND defaultitem)
+{
+	int z;
+	static HWND lasthwnd, firsthwnd;
+    static int finish_searching;
+
+	/* Start is 2 when we have cycled completely and
+	 * need to set the focus to the last widget we found
+	 * that was valid.
+	 */
+	if(start == 2)
+	{
+		if(lasthwnd)
+			WinSetFocus(HWND_DESKTOP, lasthwnd);
+		return 0;
+	}
+
+	/* Start is 1 when we are entering the function
+	 * for the first time, it is zero when entering
+	 * the function recursively.
+	 */
+	if(start == 1)
+	{
+		lasthwnd = handle;
+		finish_searching = 0;
+		firsthwnd = 0;
+	}
+
+	for(z=0;z<box->count;z++)
+	{
+		if(box->items[z].type == TYPEBOX)
+		{
+			Box *thisbox = WinQueryWindowPtr(box->items[z].hwnd, QWP_USER);
+
+			if(thisbox && _focus_check_box_back(thisbox, handle, start == 3 ? 3 : 0, defaultitem))
+				return 1;
+		}
+		else
+		{
+			if(box->items[z].hwnd == handle)
+			{
+				if(lasthwnd == handle && firsthwnd)
+					WinSetFocus(HWND_DESKTOP, firsthwnd);
+				else if(lasthwnd == handle && !firsthwnd)
+					finish_searching = 1;
+				else
+					WinSetFocus(HWND_DESKTOP, lasthwnd);
+
+				/* If we aren't looking for the last handle,
+				 * return immediately.
+				 */
+				if(!finish_searching)
+					return 1;
+			}
+			if(_validate_focus(box->items[z].hwnd))
+			{
+				/* Start is 3 when we are looking for the
+				 * first valid item in the layout.
+				 */
+				if(start == 3)
+				{
+					if(!defaultitem || (defaultitem && defaultitem == box->items[z].hwnd))
+					{
+						WinSetFocus(HWND_DESKTOP, box->items[z].hwnd);
+						return 1;
+					}
+				}
+
+				if(!firsthwnd)
+					firsthwnd = box->items[z].hwnd;
+
+				lasthwnd = box->items[z].hwnd;
+			}
+			else
+			{
+				char tmpbuf[100] = "";
+
+				WinQueryClassName(box->items[z].hwnd, 99, tmpbuf);
+				if(strncmp(tmpbuf, SplitbarClassName, strlen(SplitbarClassName)+1)==0)
+				{
+					/* Try the top or left box */
+					HWND mybox = (HWND)dw_window_get_data(box->items[z].hwnd, "_dw_topleft");
+
+					if(mybox)
+					{
+						Box *splitbox = (Box *)WinQueryWindowPtr(mybox, QWP_USER);
+
+						if(splitbox && _focus_check_box_back(splitbox, handle, start == 3 ? 3 : 0, defaultitem))
+							return 1;
+					}
+
+					/* Then try the bottom or right box */
+					mybox = (HWND)dw_window_get_data(box->items[z].hwnd, "_dw_bottomright");
+
+					if(mybox)
+					{
+						Box *splitbox = (Box *)WinQueryWindowPtr(mybox, QWP_USER);
+
+						if(splitbox && _focus_check_box_back(splitbox, handle, start == 3 ? 3 : 0, defaultitem))
+							return 1;
+					}
+				}
+				else if(strncmp(tmpbuf, "#40", 4)==0) /* Notebook */
+				{
+					Box *notebox;
+					HWND page = (HWND)WinSendMsg(box->items[z].hwnd, BKM_QUERYPAGEWINDOWHWND,
+												 (MPARAM)dw_notebook_page_get(box->items[z].hwnd), 0);
+
+					if(page)
+					{
+						notebox = (Box *)WinQueryWindowPtr(page, QWP_USER);
+
+						if(notebox && _focus_check_box_back(notebox, handle, start == 3 ? 3 : 0, defaultitem))
+							return 1;
+					}
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+/* This function finds the first widget in the
+ * layout and moves the current focus to it.
+ */
+int _initial_focus(HWND handle)
+{
+	Box *thisbox = NULL;
+	HWND box;
+
+	box = WinWindowFromID(handle, FID_CLIENT);
+	if(box)
+		thisbox = WinQueryWindowPtr(box, QWP_USER);
+	else
+		return 1;
+
+	if(thisbox)
+		_focus_check_box(thisbox, handle, 3, thisbox->defaultitem);
+	return 0;
+}
+
+/* This function finds the current widget in the
+ * layout and moves the current focus to the next item.
+ */
+void _shift_focus(HWND handle)
+{
+	Box *thisbox;
+	HWND box, lastbox = _toplevel_window(handle);
+
+	box = WinWindowFromID(lastbox, FID_CLIENT);
+	if(box)
+		thisbox = WinQueryWindowPtr(box, QWP_USER);
+	else
+		thisbox = WinQueryWindowPtr(lastbox, QWP_USER);
+
+	if(thisbox)
+	{
+		if(_focus_check_box(thisbox, handle, 1, 0)  == 0)
+			_focus_check_box(thisbox, handle, 2, 0);
+	}
+}
+
+/* This function finds the current widget in the
+ * layout and moves the current focus to the next item.
+ */
+void _shift_focus_back(HWND handle)
+{
+	Box *thisbox;
+	HWND box, lastbox = _toplevel_window(handle);
+
+	box = WinWindowFromID(lastbox, FID_CLIENT);
+	if(box)
+		thisbox = WinQueryWindowPtr(box, QWP_USER);
+	else
+		thisbox = WinQueryWindowPtr(lastbox, QWP_USER);
+
+	if(thisbox)
+	{
+		if(_focus_check_box_back(thisbox, handle, 1, 0)  == 0)
+			_focus_check_box_back(thisbox, handle, 2, 0);
+	}
+}
+
+/* This function will recursively search a box and add up the total height of it */
+void _count_size(HWND box, int type, int *xsize, int *xorigsize)
+{
+	int size = 0, origsize = 0, z;
+	Box *tmp = WinQueryWindowPtr(box, QWP_USER);
+
+	if(!tmp)
+	{
+		*xsize = *xorigsize = 0;
+		return;
+	}
+
+	if(type == tmp->type)
+	{
+		/* If the box is going in the direction we want, then we
+		 * return the entire sum of the items.
+		 */
+		for(z=0;z<tmp->count;z++)
+		{
+			if(tmp->items[z].type == TYPEBOX)
+			{
+				int s, os;
+
+				_count_size(tmp->items[z].hwnd, type, &s, &os);
+				size += s;
+				origsize += os;
+			}
+			else
+			{
+				size += (type == DW_HORZ ? tmp->items[z].width : tmp->items[z].height);
+				origsize += (type == DW_HORZ ? tmp->items[z].origwidth : tmp->items[z].origheight);
+			}
+		}
+	}
+	else
+	{
+		/* If the box is not going in the direction we want, then we only
+		 * want to return the maximum value.
+		 */
+		int tmpsize = 0, tmporigsize = 0;
+
+		for(z=0;z<tmp->count;z++)
+		{
+			if(tmp->items[z].type == TYPEBOX)
+				_count_size(tmp->items[z].hwnd, type, &tmpsize, &tmporigsize);
+			else
+			{
+				tmpsize = (type == DW_HORZ ? tmp->items[z].width : tmp->items[z].height);
+				tmporigsize = (type == DW_HORZ ? tmp->items[z].origwidth : tmp->items[z].origheight);
+			}
+
+			if(tmpsize > size)
+				size = tmpsize;
+		}
+	}
+
+	*xsize = size;
+	*xorigsize = origsize;
+}
+
+
+/* Function: TrackRectangle
+ * Abstract: Tracks given rectangle.
+ *
+ * If rclBounds is NULL, then track rectangle on entire desktop.
+ * rclTrack is in window coorditates and will be mapped to
+ * desktop.
+ */
+
+BOOL _TrackRectangle(HWND hwndBase, RECTL* rclTrack, RECTL* rclBounds)
+{
+	TRACKINFO track;
+	APIRET rc;
+
+	track.cxBorder = 1;
+	track.cyBorder = 1;
+	track.cxGrid   = 1;
+	track.cyGrid   = 1;
+	track.cxKeyboard = 8;
+	track.cyKeyboard = 8;
+
+	if(!rclTrack)
+		return FALSE;
+
+	if(rclBounds)
+	{
+		track.rclBoundary = *rclBounds;
+	}
+	else
+	{
+		track.rclBoundary.yTop    =
+			track.rclBoundary.xRight  = 3000;
+		track.rclBoundary.yBottom =
+			track.rclBoundary.xLeft   = -3000;
+	}
+
+	track.rclTrack = *rclTrack;
+
+	WinMapWindowPoints(hwndBase,
+					   HWND_DESKTOP,
+					   (PPOINTL)&track.rclTrack,
+					   2);
+
+	track.ptlMinTrackSize.x = track.rclTrack.xRight
+		- track.rclTrack.xLeft;
+	track.ptlMinTrackSize.y = track.rclTrack.yTop
+		- track.rclTrack.yBottom;
+	track.ptlMaxTrackSize.x = track.rclTrack.xRight
+		- track.rclTrack.xLeft;
+	track.ptlMaxTrackSize.y = track.rclTrack.yTop
+		- track.rclTrack.yBottom;
+
+	track.fs = TF_MOVE | TF_ALLINBOUNDARY;
+
+	rc = WinTrackRect(HWND_DESKTOP, 0, &track);
+
+	if(rc)
+		*rclTrack = track.rclTrack;
+
+	return rc;
+}
+
+void _check_resize_notebook(HWND hwnd)
+{
+	char tmpbuf[100];
+
+	WinQueryClassName(hwnd, 99, tmpbuf);
+
+	/* If we have a notebook we resize the page again. */
+	if(strncmp(tmpbuf, "#40", 4)==0)
+	{
+		unsigned long x, y, width, height;
+		ULONG page = (ULONG)WinSendMsg(hwnd, BKM_QUERYPAGEID, 0, MPFROM2SHORT(BKA_FIRST, BKA_MAJOR));
+
+		while(page)
+		{
+			HWND pagehwnd = (HWND)WinSendMsg(hwnd, BKM_QUERYPAGEWINDOWHWND, MPFROMLONG(page), 0);
+			RECTL rc;
+
+			Box *pagebox = (Box *)WinQueryWindowPtr(pagehwnd, QWP_USER);
+			if(pagebox)
+			{
+				dw_window_get_pos_size(hwnd, &x, &y, &width, &height);
+
+				rc.xLeft = x;
+				rc.yBottom = y;
+				rc.xRight = x + width;
+				rc.yTop = y + height;
+
+				WinSendMsg(hwnd, BKM_CALCPAGERECT, (MPARAM)&rc, (MPARAM)TRUE);
+
+				_do_resize(pagebox, rc.xRight - rc.xLeft, rc.yTop - rc.yBottom);
+			}
+			page = (ULONG)WinSendMsg(hwnd, BKM_QUERYPAGEID, (MPARAM)page, MPFROM2SHORT(BKA_NEXT, BKA_MAJOR));
+		}
+
+	}
+}
+
+/* Return the OS/2 color from the DW color */
+unsigned long _internal_color(unsigned long color)
+{
+	if(color < 16)
+		return _colors[color];
+	return color;
+}
+
+unsigned long _os2_color(unsigned long color)
+{
+	return DW_RED_VALUE(color) << 16 | DW_GREEN_VALUE(color) << 8 | DW_BLUE_VALUE(color);
+}
+
+BOOL _MySetWindowPos(HWND hwnd, HWND parent, HWND behind, LONG x, LONG y, LONG cx, LONG cy, ULONG fl)
+{
+	int height = _get_height(parent);
+
+	return WinSetWindowPos(hwnd, behind, x, height - y - cy, cx, cy, fl);
+}
+
+/* This function calculates how much space the widgets and boxes require
+ * and does expansion as necessary.
+ */
+int _resize_box(Box *thisbox, int *depth, int x, int y, int *usedx, int *usedy,
+				int pass, int *usedpadx, int *usedpady)
+{
+	int z, currentx = 0, currenty = 0;
+	int uymax = 0, uxmax = 0;
+	int upymax = 0, upxmax = 0;
+	/* Used for the SIZEEXPAND */
+	int nux = *usedx, nuy = *usedy;
+	int nupx = *usedpadx, nupy = *usedpady;
+
+	(*usedx) += (thisbox->pad * 2);
+	(*usedy) += (thisbox->pad * 2);
+
+	if(thisbox->grouphwnd)
+	{
+		char *text = dw_window_get_text(thisbox->grouphwnd);
+
+		thisbox->grouppady = 0;
+
+		if(text)
+		{
+			dw_font_text_extents_get(thisbox->grouphwnd, 0, text, NULL, &thisbox->grouppady);
+			dw_free(text);
+		}
+
+		if(thisbox->grouppady)
+			thisbox->grouppady += 3;
+		else
+			thisbox->grouppady = 6;
+
+		thisbox->grouppadx = 6;
+
+		(*usedx) += thisbox->grouppadx;
+		(*usedpadx) += thisbox->grouppadx;
+		(*usedy) += thisbox->grouppady;
+		(*usedpady) += thisbox->grouppady;
+	}
+
+	for(z=0;z<thisbox->count;z++)
+	{
+		if(thisbox->items[z].type == TYPEBOX)
+		{
+			int initialx, initialy;
+			Box *tmp = WinQueryWindowPtr(thisbox->items[z].hwnd, QWP_USER);
+
+			initialx = x - (*usedx);
+			initialy = y - (*usedy);
+
+			if(tmp)
+			{
+				int newx, newy;
+				int nux = *usedx, nuy = *usedy;
+				int upx = *usedpadx + (tmp->pad*2), upy = *usedpady + (tmp->pad*2);
+
+				/* On the second pass we know how big the box needs to be and how
+				 * much space we have, so we can calculate a ratio for the new box.
+				 */
+				if(pass == 2)
+				{
+					int deep = *depth + 1;
+
+					_resize_box(tmp, &deep, x, y, &nux, &nuy, 1, &upx, &upy);
+
+					tmp->upx = upx - *usedpadx;
+					tmp->upy = upy - *usedpady;
+
+					newx = x - nux;
+					newy = y - nuy;
+
+					tmp->width = thisbox->items[z].width = initialx - newx;
+					tmp->height = thisbox->items[z].height = initialy - newy;
+
+					tmp->parentxratio = thisbox->xratio;
+					tmp->parentyratio = thisbox->yratio;
+
+					tmp->parentpad = tmp->pad;
+
+					/* Just in case */
+					tmp->xratio = thisbox->xratio;
+					tmp->yratio = thisbox->yratio;
+
+					if(thisbox->type == DW_VERT)
+					{
+						int tmppad = (thisbox->items[z].pad*2)+(tmp->pad*2)+tmp->grouppady;
+
+						if((thisbox->items[z].width - tmppad)!=0)
+							tmp->xratio = ((float)((thisbox->items[z].width * thisbox->xratio)-tmppad))/((float)(thisbox->items[z].width-tmppad));
+					}
+					else
+					{
+						if((thisbox->items[z].width-tmp->upx)!=0)
+							tmp->xratio = ((float)((thisbox->items[z].width * thisbox->xratio)-tmp->upx))/((float)(thisbox->items[z].width-tmp->upx));
+					}
+					if(thisbox->type == DW_HORZ)
+					{
+						int tmppad = (thisbox->items[z].pad*2)+(tmp->pad*2)+tmp->grouppadx;
+
+						if((thisbox->items[z].height-tmppad)!=0)
+							tmp->yratio = ((float)((thisbox->items[z].height * thisbox->yratio)-tmppad))/((float)(thisbox->items[z].height-tmppad));
+					}
+					else
+					{
+						if((thisbox->items[z].height-tmp->upy)!=0)
+							tmp->yratio = ((float)((thisbox->items[z].height * thisbox->yratio)-tmp->upy))/((float)(thisbox->items[z].height-tmp->upy));
+					}
+
+					nux = *usedx; nuy = *usedy;
+					upx = *usedpadx + (tmp->pad*2); upy = *usedpady + (tmp->pad*2);
+				}
+
+				(*depth)++;
+
+				_resize_box(tmp, depth, x, y, &nux, &nuy, pass, &upx, &upy);
+
+				(*depth)--;
+
+				newx = x - nux;
+				newy = y - nuy;
+
+				tmp->minwidth = thisbox->items[z].width = initialx - newx;
+				tmp->minheight = thisbox->items[z].height = initialy - newy;
+			}
+		}
+
+		if(pass > 1 && *depth > 0)
+		{
+			if(thisbox->type == DW_VERT)
+			{
+				int tmppad = (thisbox->items[z].pad*2)+(thisbox->parentpad*2)+thisbox->grouppadx;
+
+				if((thisbox->minwidth-tmppad) == 0)
+					thisbox->items[z].xratio = 1.0;
+				else
+					thisbox->items[z].xratio = ((float)((thisbox->width * thisbox->parentxratio)-tmppad))/((float)(thisbox->minwidth-tmppad));
+			}
+			else
+			{
+				if(thisbox->minwidth-thisbox->upx == 0)
+					thisbox->items[z].xratio = 1.0;
+				else
+					thisbox->items[z].xratio = ((float)((thisbox->width * thisbox->parentxratio)-thisbox->upx))/((float)(thisbox->minwidth-thisbox->upx));
+			}
+
+			if(thisbox->type == DW_HORZ)
+			{
+				int tmppad = (thisbox->items[z].pad*2)+(thisbox->parentpad*2)+thisbox->grouppady;
+
+				if((thisbox->minheight-tmppad) == 0)
+					thisbox->items[z].yratio = 1.0;
+				else
+					thisbox->items[z].yratio = ((float)((thisbox->height * thisbox->parentyratio)-tmppad))/((float)(thisbox->minheight-tmppad));
+			}
+			else
+			{
+				if(thisbox->minheight-thisbox->upy == 0)
+					thisbox->items[z].yratio = 1.0;
+				else
+					thisbox->items[z].yratio = ((float)((thisbox->height * thisbox->parentyratio)-thisbox->upy))/((float)(thisbox->minheight-thisbox->upy));
+			}
+
+			if(thisbox->items[z].type == TYPEBOX)
+			{
+				Box *tmp = WinQueryWindowPtr(thisbox->items[z].hwnd, QWP_USER);
+
+				if(tmp)
+				{
+					tmp->parentxratio = thisbox->items[z].xratio;
+					tmp->parentyratio = thisbox->items[z].yratio;
+				}
+			}
+		}
+		else
+		{
+			thisbox->items[z].xratio = thisbox->xratio;
+			thisbox->items[z].yratio = thisbox->yratio;
+		}
+
+		if(thisbox->type == DW_VERT)
+		{
+			int itemwidth = thisbox->items[z].width + (thisbox->items[z].pad*2);
+
+			if(itemwidth > uxmax)
+				uxmax = itemwidth;
+			if(thisbox->items[z].hsize != SIZEEXPAND)
+			{
+				if(itemwidth > upxmax)
+					upxmax = itemwidth;
+			}
+			else
+			{
+				if(thisbox->items[z].pad*2 > upxmax)
+					upxmax = thisbox->items[z].pad*2;
+			}
+		}
+		else
+		{
+			if(thisbox->items[z].width == -1)
+			{
+				/* figure out how much space this item requires */
+				/* thisbox->items[z].width = */
+			}
+			else
+			{
+				(*usedx) += thisbox->items[z].width + (thisbox->items[z].pad*2);
+				if(thisbox->items[z].hsize != SIZEEXPAND)
+					(*usedpadx) += (thisbox->items[z].pad*2) + thisbox->items[z].width;
+				else
+					(*usedpadx) += thisbox->items[z].pad*2;
+			}
+		}
+		if(thisbox->type == DW_HORZ)
+		{
+			int itemheight = thisbox->items[z].height + (thisbox->items[z].pad*2);
+
+			if(itemheight > uymax)
+				uymax = itemheight;
+			if(thisbox->items[z].vsize != SIZEEXPAND)
+			{
+				if(itemheight > upymax)
+					upymax = itemheight;
+			}
+			else
+			{
+				if(thisbox->items[z].pad*2 > upymax)
+					upymax = thisbox->items[z].pad*2;
+			}
+		}
+		else
+		{
+			if(thisbox->items[z].height == -1)
+			{
+				/* figure out how much space this item requires */
+				/* thisbox->items[z].height = */
+			}
+			else
+			{
+				(*usedy) += thisbox->items[z].height + (thisbox->items[z].pad*2);
+				if(thisbox->items[z].vsize != SIZEEXPAND)
+					(*usedpady) += (thisbox->items[z].pad*2) + thisbox->items[z].height;
+				else
+					(*usedpady) += thisbox->items[z].pad*2;
+			}
+		}
+	}
+
+	(*usedx) += uxmax;
+	(*usedy) += uymax;
+	(*usedpadx) += upxmax;
+	(*usedpady) += upymax;
+
+	currentx += thisbox->pad;
+	currenty += thisbox->pad;
+
+	if(thisbox->grouphwnd)
+	{
+		currentx += 3;
+		currenty += thisbox->grouppady - 3;
+	}
+
+	/* The second pass is for expansion and actual placement. */
+	if(pass > 1)
+	{
+		/* Any SIZEEXPAND items should be set to uxmax/uymax */
+		for(z=0;z<thisbox->count;z++)
+		{
+			if(thisbox->items[z].hsize == SIZEEXPAND && thisbox->type == DW_VERT)
+				thisbox->items[z].width = uxmax-(thisbox->items[z].pad*2);
+			if(thisbox->items[z].vsize == SIZEEXPAND && thisbox->type == DW_HORZ)
+				thisbox->items[z].height = uymax-(thisbox->items[z].pad*2);
+			/* Run this code segment again to finalize the sized after setting uxmax/uymax values. */
+			if(thisbox->items[z].type == TYPEBOX)
+			{
+				Box *tmp = WinQueryWindowPtr(thisbox->items[z].hwnd, QWP_USER);
+
+				if(tmp)
+				{
+					if(*depth > 0)
+					{
+						float calcval;
+
+						if(thisbox->type == DW_VERT)
+						{
+							calcval = (float)(tmp->minwidth-((thisbox->items[z].pad*2)+(thisbox->pad*2)));
+							if(calcval == 0.0)
+								tmp->xratio = thisbox->xratio;
+							else
+								tmp->xratio = ((float)((thisbox->items[z].width * thisbox->xratio)-((thisbox->items[z].pad*2)+(thisbox->pad*2))))/calcval;
+							tmp->width = thisbox->items[z].width;
+						}
+						if(thisbox->type == DW_HORZ)
+						{
+							calcval = (float)(tmp->minheight-((thisbox->items[z].pad*2)+(thisbox->pad*2)));
+							if(calcval == 0.0)
+								tmp->yratio = thisbox->yratio;
+							else
+								tmp->yratio = ((float)((thisbox->items[z].height * thisbox->yratio)-((thisbox->items[z].pad*2)+(thisbox->pad*2))))/calcval;
+							tmp->height = thisbox->items[z].height;
+						}
+					}
+
+					(*depth)++;
+
+					_resize_box(tmp, depth, x, y, &nux, &nuy, 3, &nupx, &nupy);
+
+					(*depth)--;
+
+				}
+			}
+		}
+
+		for(z=0;z<(thisbox->count);z++)
+		{
+			int height = thisbox->items[z].height;
+			int width = thisbox->items[z].width;
+			int pad = thisbox->items[z].pad;
+			HWND handle = thisbox->items[z].hwnd;
+			int vectorx, vectory;
+
+			/* When upxmax != pad*2 then ratios are incorrect. */
+			vectorx = (int)((width*thisbox->items[z].xratio)-width);
+			vectory = (int)((height*thisbox->items[z].yratio)-height);
+
+			if(width > 0 && height > 0)
+			{
+				char tmpbuf[100];
+				/* This is a hack to fix rounding of the sizing */
+				if(*depth == 0)
+				{
+					vectorx++;
+					vectory++;
+				}
+
+				/* If this item isn't going to expand... reset the vectors to 0 */
+				if(thisbox->items[z].vsize != SIZEEXPAND)
+					vectory = 0;
+				if(thisbox->items[z].hsize != SIZEEXPAND)
+					vectorx = 0;
+
+				WinQueryClassName(handle, 99, tmpbuf);
+
+				if(strncmp(tmpbuf, "#2", 3)==0)
+				{
+					HWND frame = (HWND)dw_window_get_data(handle, "_dw_combo_box");
+					/* Make the combobox big enough to drop down. :) */
+					WinSetWindowPos(handle, HWND_TOP, 0, -100,
+									width + vectorx, (height + vectory) + 100, SWP_MOVE | SWP_SIZE | SWP_ZORDER);
+					_MySetWindowPos(frame, thisbox->hwnd, HWND_TOP, currentx + pad, currenty + pad,
+									width + vectorx, height + vectory, SWP_MOVE | SWP_SIZE | SWP_ZORDER);
+				}
+				else if(strncmp(tmpbuf, "#6", 3)==0)
+				{
+					/* Entryfields on OS/2 have a thick border that isn't on Windows and GTK */
+					_MySetWindowPos(handle, thisbox->hwnd, HWND_TOP, (currentx + pad) + 3, (currenty + pad) + 3,
+									(width + vectorx) - 6, (height + vectory) - 6, SWP_MOVE | SWP_SIZE | SWP_ZORDER);
+				}
+				else if(strncmp(tmpbuf, "#40", 5)==0)
+				{
+					_MySetWindowPos(handle, thisbox->hwnd, HWND_TOP, currentx + pad, currenty + pad,
+									width + vectorx, height + vectory, SWP_MOVE | SWP_SIZE | SWP_ZORDER);
+					_check_resize_notebook(handle);
+				}
+				else if(strncmp(tmpbuf, SplitbarClassName, strlen(SplitbarClassName)+1)==0)
+				{
+					/* Then try the bottom or right box */
+					float *percent = (float *)dw_window_get_data(handle, "_dw_percent");
+					int type = (int)dw_window_get_data(handle, "_dw_type");
+					int cx = width + vectorx;
+					int cy = height + vectory;
+
+					_MySetWindowPos(handle, thisbox->hwnd, HWND_TOP, currentx + pad, currenty + pad,
+									cx, cy, SWP_MOVE | SWP_SIZE | SWP_ZORDER);
+
+					if(cx > 0 && cy > 0 && percent)
+						_handle_splitbar_resize(handle, *percent, type, cx, cy);
+				}
+				else
+				{
+					_MySetWindowPos(handle, thisbox->hwnd, HWND_TOP, currentx + pad, currenty + pad,
+									width + vectorx, height + vectory, SWP_MOVE | SWP_SIZE | SWP_ZORDER);
+					if(thisbox->items[z].type == TYPEBOX)
+					{
+						Box *boxinfo = WinQueryWindowPtr(handle, QWP_USER);
+
+						if(boxinfo && boxinfo->grouphwnd)
+							WinSetWindowPos(boxinfo->grouphwnd, HWND_TOP, 0, 0,
+											width + vectorx, height + vectory, SWP_MOVE | SWP_SIZE);
+
+					}
+
+				}
+
+				if(thisbox->type == DW_HORZ)
+					currentx += width + vectorx + (pad * 2);
+				if(thisbox->type == DW_VERT)
+					currenty += height + vectory + (pad * 2);
+			}
+		}
+	}
+	return 0;
+}
+
+void _do_resize(Box *thisbox, int x, int y)
+{
+	if(x != 0 && y != 0)
+	{
+		if(thisbox)
+		{
+			int usedx = 0, usedy = 0, usedpadx = 0, usedpady = 0, depth = 0;
+
+			_resize_box(thisbox, &depth, x, y, &usedx, &usedy, 1, &usedpadx, &usedpady);
+
+			if(usedx-usedpadx == 0 || usedy-usedpady == 0)
+				return;
+
+			thisbox->xratio = ((float)(x-usedpadx))/((float)(usedx-usedpadx));
+			thisbox->yratio = ((float)(y-usedpady))/((float)(usedy-usedpady));
+
+			usedx = usedy = usedpadx = usedpady = depth = 0;
+
+			_resize_box(thisbox, &depth, x, y, &usedx, &usedy, 2, &usedpadx, &usedpady);
+		}
+	}
+}
+
+/* This procedure handles WM_QUERYTRACKINFO requests from the frame */
+MRESULT EXPENTRY _sizeproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+	PFNWP *blah = WinQueryWindowPtr(hWnd, QWP_USER);
+	Box *thisbox = NULL;
+	HWND box;
+
+	box = WinWindowFromID(hWnd, FID_CLIENT);
+	if(box)
+		thisbox = WinQueryWindowPtr(box, QWP_USER);
+
+	if(thisbox && !thisbox->titlebar)
+	{
+		switch(msg)
+		{
+		case WM_QUERYTRACKINFO:
+			{
+				if(blah && *blah)
+				{
+					PTRACKINFO ptInfo;
+					int res;
+					PFNWP myfunc = *blah;
+					res = (int)myfunc(hWnd, msg, mp1, mp2);
+
+					ptInfo = (PTRACKINFO)(mp2);
+
+					ptInfo->ptlMinTrackSize.y = 8;
+					ptInfo->ptlMinTrackSize.x = 8;
+
+					return (MRESULT)res;
+				}
+			}
+		}
+	}
+
+	if(blah && *blah)
+	{
+		PFNWP myfunc = *blah;
+		return myfunc(hWnd, msg, mp1, mp2);
+	}
+
+	return WinDefWindowProc(hWnd, msg, mp1, mp2);
+}
+
+void _Top(HPS hpsPaint, RECTL rclPaint)
+{
+	POINTL ptl1, ptl2;
+
+	ptl1.x = rclPaint.xLeft;
+	ptl2.y = ptl1.y = rclPaint.yTop - 1;
+	ptl2.x = rclPaint.xRight - 1;
+	GpiMove(hpsPaint, &ptl1);
+	GpiLine(hpsPaint, &ptl2);
+}
+
+/* Left hits the bottom */
+void _Left(HPS hpsPaint, RECTL rclPaint)
+{
+	POINTL ptl1, ptl2;
+
+	ptl2.x = ptl1.x = rclPaint.xLeft;
+	ptl1.y = rclPaint.yTop - 1;
+	ptl2.y = rclPaint.yBottom;
+	GpiMove(hpsPaint, &ptl1);
+	GpiLine(hpsPaint, &ptl2);
+}
+
+void _Bottom(HPS hpsPaint, RECTL rclPaint)
+{
+	POINTL ptl1, ptl2;
+
+	ptl1.x = rclPaint.xRight - 1;
+	ptl1.y = ptl2.y = rclPaint.yBottom;
+	ptl2.x = rclPaint.xLeft;
+	GpiMove(hpsPaint, &ptl1);
+	GpiLine(hpsPaint, &ptl2);
+}
+
+/* Right hits the top */
+void _Right(HPS hpsPaint, RECTL rclPaint)
+{
+	POINTL ptl1, ptl2;
+
+	ptl2.x = ptl1.x = rclPaint.xRight - 1;
+	ptl1.y = rclPaint.yBottom + 1;
+	ptl2.y = rclPaint.yTop - 1;
+	GpiMove(hpsPaint, &ptl1);
+	GpiLine(hpsPaint, &ptl2);
+}
+
+/* This procedure handles drawing of a status border */
+MRESULT EXPENTRY _statusproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+	PFNWP *blah = WinQueryWindowPtr(hWnd, QWP_USER);
+
+	if(msg == WM_MOUSEMOVE && _wndproc(hWnd, msg, mp1, mp2))
+		return MPFROMSHORT(FALSE);
+
+	if(blah && *blah)
+	{
+		PFNWP myfunc = *blah;
+
+		switch(msg)
+		{
+		case WM_PAINT:
+			{
+				HPS hpsPaint;
+				RECTL rclPaint;
+				char buf[1024];
+
+				hpsPaint = WinBeginPaint(hWnd, 0, 0);
+				WinQueryWindowRect(hWnd, &rclPaint);
+				WinFillRect(hpsPaint, &rclPaint, CLR_PALEGRAY);
+
+				GpiSetColor(hpsPaint, CLR_DARKGRAY);
+				_Top(hpsPaint, rclPaint);
+				_Left(hpsPaint, rclPaint);
+
+				GpiSetColor(hpsPaint, CLR_WHITE);
+				_Right(hpsPaint, rclPaint);
+				_Bottom(hpsPaint, rclPaint);
+
+				WinQueryWindowText(hWnd, 1024, buf);
+				rclPaint.xLeft += 3;
+				rclPaint.xRight--;
+				rclPaint.yTop--;
+				rclPaint.yBottom++;
+
+				GpiSetColor(hpsPaint, CLR_BLACK);
+				WinDrawText(hpsPaint, -1, buf, &rclPaint, DT_TEXTATTRS, DT_TEXTATTRS, DT_VCENTER | DT_LEFT | DT_TEXTATTRS);
+				WinEndPaint(hpsPaint);
+
+				return (MRESULT)TRUE;
+			}
+		}
+		return myfunc(hWnd, msg, mp1, mp2);
+	}
+
+	return WinDefWindowProc(hWnd, msg, mp1, mp2);
+}
+
+/* This procedure handles pointer changes */
+MRESULT EXPENTRY _textproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+	PFNWP *blah = WinQueryWindowPtr(hWnd, QWP_USER);
+
+	if(msg == WM_MOUSEMOVE &&_wndproc(hWnd, msg, mp1, mp2))
+		return MPFROMSHORT(FALSE);
+
+	if(blah && *blah)
+	{
+		PFNWP myfunc = *blah;
+
+		return myfunc(hWnd, msg, mp1, mp2);
+	}
+
+	return WinDefWindowProc(hWnd, msg, mp1, mp2);
+}
+
+void _click_default(HWND handle)
+{
+	char tmpbuf[100];
+
+	WinQueryClassName(handle, 99, tmpbuf);
+
+	/* These are the window classes which can
+	 * obtain input focus.
+	 */
+	if(strncmp(tmpbuf, "#3", 3)==0)
+	{
+		/* Generate click on default item */
+		SignalHandler *tmp = Root;
+
+		/* Find any callbacks for this function */
+		while(tmp)
+		{
+			if(tmp->message == WM_COMMAND)
+			{
+				int (* API clickfunc)(HWND, void *) = (int (* API)(HWND, void *))tmp->signalfunction;
+
+				/* Make sure it's the right window, and the right ID */
+				if(tmp->window == handle)
+				{
+					clickfunc(tmp->window, tmp->data);
+					tmp = NULL;
+				}
+			}
+			if(tmp)
+				tmp= tmp->next;
+		}
+	}
+	else
+		WinSetFocus(HWND_DESKTOP, handle);
+}
+
+#define ENTRY_CUT   1001
+#define ENTRY_COPY  1002
+#define ENTRY_PASTE 1003
+#define ENTRY_UNDO  1004
+#define ENTRY_SALL  1005
+
+/* Originally just intended for entryfields, it now serves as a generic
+ * procedure for handling TAB presses to change input focus on controls.
+ */
+MRESULT EXPENTRY _entryproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+	WindowData *blah = (WindowData *)WinQueryWindowPtr(hWnd, QWP_USER);
+	PFNWP oldproc = 0;
+	char tmpbuf[100];
+
+	if(blah)
+		oldproc = blah->oldproc;
+
+	WinQueryClassName(hWnd, 99, tmpbuf);
+
+	/* These are the window classes which should get a menu */
+	if(strncmp(tmpbuf, "#2", 3)==0 ||  /* Combobox */
+	   strncmp(tmpbuf, "#6", 3)==0 ||  /* Entryfield */
+	   strncmp(tmpbuf, "#10", 4)==0 || /* MLE */
+	   strncmp(tmpbuf, "#32", 4)==0)   /* Spinbutton */
+	{
+		switch(msg)
+		{
+		case WM_CONTEXTMENU:
+			{
+				HMENUI hwndMenu = dw_menu_new(0L);
+				long x, y;
+
+				if(strncmp(tmpbuf, "#10", 4)==0 && !WinSendMsg(hWnd, MLM_QUERYREADONLY, 0, 0))
+				{
+					dw_menu_append_item(hwndMenu, "Undo", ENTRY_UNDO, 0L, TRUE, FALSE, 0L);
+					dw_menu_append_item(hwndMenu, "", 0L, 0L, TRUE, FALSE, 0L);
+				}
+				dw_menu_append_item(hwndMenu, "Copy", ENTRY_COPY, 0L, TRUE, FALSE, 0L);
+				if((strncmp(tmpbuf, "#10", 4)!=0  && !dw_window_get_data(hWnd, "_dw_disabled")) || (strncmp(tmpbuf, "#10", 4)==0 && !WinSendMsg(hWnd, MLM_QUERYREADONLY, 0, 0)))
+				{
+					dw_menu_append_item(hwndMenu, "Cut", ENTRY_CUT, 0L, TRUE, FALSE, 0L);
+					dw_menu_append_item(hwndMenu, "Paste", ENTRY_PASTE, 0L, TRUE, FALSE, 0L);
+				}
+				dw_menu_append_item(hwndMenu, "", 0L, 0L, TRUE, FALSE, 0L);
+				dw_menu_append_item(hwndMenu, "Select All", ENTRY_SALL, 0L, TRUE, FALSE, 0L);
+
+				WinSetFocus(HWND_DESKTOP, hWnd);
+				dw_pointer_query_pos(&x, &y);
+				dw_menu_popup(&hwndMenu, hWnd, x, y);
+			}
+			break;
+		case WM_COMMAND:
+			{
+				ULONG command = COMMANDMSG(&msg)->cmd;
+
+				/* MLE */
+				if(strncmp(tmpbuf, "#10", 4)==0)
+				{
+					switch(command)
+					{
+					case ENTRY_CUT:
+						return WinSendMsg(hWnd, MLM_CUT, 0, 0);
+					case ENTRY_COPY:
+						return WinSendMsg(hWnd, MLM_COPY, 0, 0);
+					case ENTRY_PASTE:
+						return WinSendMsg(hWnd, MLM_PASTE, 0, 0);
+					case ENTRY_UNDO:
+						return WinSendMsg(hWnd, MLM_UNDO, 0, 0);
+					case ENTRY_SALL:
+						{
+							ULONG len = (ULONG)WinSendMsg(hWnd, MLM_QUERYTEXTLENGTH, 0, 0);
+							return WinSendMsg(hWnd, MLM_SETSEL, 0, (MPARAM)len);
+						}
+					}
+				}
+				else /* Other */
+				{
+					HWND handle = hWnd;
+
+					/* Get the entryfield handle from multi window controls */
+					if(strncmp(tmpbuf, "#2", 3)==0)
+						handle = WinWindowFromID(hWnd, 667);
+
+					if(handle)
+					{
+						switch(command)
+						{
+						case ENTRY_CUT:
+							return WinSendMsg(handle, EM_CUT, 0, 0);
+						case ENTRY_COPY:
+							return WinSendMsg(handle, EM_COPY, 0, 0);
+						case ENTRY_PASTE:
+							return WinSendMsg(handle, EM_PASTE, 0, 0);
+						case ENTRY_SALL:
+							{
+								LONG len = WinQueryWindowTextLength(hWnd);
+								return WinSendMsg(hWnd, EM_SETSEL, MPFROM2SHORT(0, (SHORT)len), 0);
+							}
+						}
+					}
+				}
+			}
+			break;
+		}
+	}
+
+	switch(msg)
+	{
+	case WM_BUTTON1DOWN:
+	case WM_BUTTON2DOWN:
+	case WM_BUTTON3DOWN:
+		{
+			if(strncmp(tmpbuf, "#32", 4)==0)
+				_run_event(hWnd, WM_SETFOCUS, (MPARAM)FALSE, (MPARAM)TRUE);
+		}
+		break;
+	case WM_CONTROL:
+		{
+			if(strncmp(tmpbuf, "#38", 4)==0)
+				_run_event(hWnd, msg, mp1, mp2);
+		}
+		break;
+	case WM_SETFOCUS:
+		_run_event(hWnd, msg, mp1, mp2);
+		break;
+	case WM_CHAR:
+		if(_run_event(hWnd, msg, mp1, mp2) == (MRESULT)TRUE)
+			return (MRESULT)TRUE;
+		if(SHORT1FROMMP(mp2) == '\t')
+		{
+			if(CHARMSG(&msg)->fs & KC_SHIFT)
+				_shift_focus_back(hWnd);
+			else
+				_shift_focus(hWnd);
+			return FALSE;
+		}
+		else if(SHORT1FROMMP(mp2) == '\r' && blah && blah->clickdefault)
+			_click_default(blah->clickdefault);
+		/* When you hit escape we get this value and the
+		 * window hangs for reasons unknown. (in an MLE)
+		 */
+		else if(SHORT1FROMMP(mp2) == 283)
+			return (MRESULT)TRUE;
+
+		break;
+	case WM_SIZE:
+		{
+			/* If it's a slider... make sure it shows the correct value */
+			if(strncmp(tmpbuf, "#38", 4)==0)
+				WinPostMsg(hWnd, WM_USER+7, 0, 0);
+		}
+		break;
+	case WM_USER+7:
+		{
+			int pos = (int)dw_window_get_data(hWnd, "_dw_slider_value");
+			WinSendMsg(hWnd, SLM_SETSLIDERINFO, MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_INCREMENTVALUE), (MPARAM)pos);
+		}
+		break;
+	case WM_MOUSEMOVE:
+		if(_wndproc(hWnd, msg, mp1, mp2))
+			return MPFROMSHORT(FALSE);
+		break;
+	}
+
+	if(oldproc)
+		return oldproc(hWnd, msg, mp1, mp2);
+
+	return WinDefWindowProc(hWnd, msg, mp1, mp2);
+}
+
+/*  Deal with combobox specifics and enhancements */
+MRESULT EXPENTRY _comboentryproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+	WindowData *blah = (WindowData *)WinQueryWindowPtr(hWnd, QWP_USER);
+
+	switch(msg)
+	{
+	case WM_MOUSEMOVE:
+		if(_wndproc(hWnd, msg, mp1, mp2))
+			return MPFROMSHORT(FALSE);
+		break;
+	case WM_CONTEXTMENU:
+	case WM_COMMAND:
+		return _entryproc(hWnd, msg, mp1, mp2);
+	case WM_SETFOCUS:
+		_run_event(hWnd, msg, mp1, mp2);
+		break;
+	case WM_CHAR:
+		if(_run_event(hWnd, msg, mp1, mp2) == (MRESULT)TRUE)
+			return (MRESULT)TRUE;
+		/* A Similar problem to the MLE, if ESC just return */
+		if(SHORT1FROMMP(mp2) == 283)
+			return (MRESULT)TRUE;
+		break;
+	}
+
+	if(blah && blah->oldproc)
+		return blah->oldproc(hWnd, msg, mp1, mp2);
+
+	return WinDefWindowProc(hWnd, msg, mp1, mp2);
+}
+
+/* Enhance the standard OS/2 MLE control */
+MRESULT EXPENTRY _mleproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+	switch(msg)
+	{
+	case WM_VSCROLL:
+		if(SHORT2FROMMP(mp2) == SB_SLIDERTRACK)
+		{
+			USHORT pos = SHORT1FROMMP(mp2);
+
+			WinSendMsg(hWnd, msg, mp1, MPFROM2SHORT(pos, SB_SLIDERPOSITION));
+		}
+		break;
+	}
+	return _entryproc(hWnd, msg, mp1, mp2);
+}
+
+/* Handle special messages for the spinbutton's entryfield */
+MRESULT EXPENTRY _spinentryproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+	WindowData *blah = (WindowData *)WinQueryWindowPtr(hWnd, QWP_USER);
+	PFNWP oldproc = 0;
+
+	if(blah)
+		oldproc = blah->oldproc;
+
+	switch(msg)
+	{
+	case WM_MOUSEMOVE:
+		if(_wndproc(hWnd, msg, mp1, mp2))
+			return MPFROMSHORT(FALSE);
+		break;
+	case WM_CONTEXTMENU:
+	case WM_COMMAND:
+		return _entryproc(hWnd, msg, mp1, mp2);
+	}
+
+	if(oldproc)
+		return oldproc(hWnd, msg, mp1, mp2);
+
+	return WinDefWindowProc(hWnd, msg, mp1, mp2);
+}
+
+int _dw_int_pos(HWND hwnd)
+{
+	int pos = (int)dw_window_get_data(hwnd, "_dw_percent_value");
+	int range = _dw_percent_get_range(hwnd);
+	float fpos = (float)pos;
+	float frange = (float)range;
+	float fnew = (fpos/1000.0)*frange;
+	return (int)fnew;
+}
+
+void _dw_int_set(HWND hwnd, int pos)
+{
+	int inew, range = _dw_percent_get_range(hwnd);
+	if(range)
+	{
+		float fpos = (float)pos;
+		float frange = (float)range;
+		float fnew = (fpos/frange)*1000.0;
+		inew = (int)fnew;
+		dw_window_set_data(hwnd, "_dw_percent_value", (void *)inew);
+	}
+}
+
+/* Handle size changes in the percent class */
+MRESULT EXPENTRY _percentproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+	WindowData *blah = (WindowData *)WinQueryWindowPtr(hWnd, QWP_USER);
+	PFNWP oldproc = 0;
+
+	if(blah)
+		oldproc = blah->oldproc;
+
+	switch(msg)
+	{
+	case WM_MOUSEMOVE:
+		if(_wndproc(hWnd, msg, mp1, mp2))
+			return MPFROMSHORT(FALSE);
+		break;
+	case WM_SIZE:
+		WinPostMsg(hWnd, WM_USER+7, 0, 0);
+		break;
+	case WM_USER+7:
+		WinSendMsg(hWnd, SLM_SETSLIDERINFO, MPFROM2SHORT(SMA_SLIDERARMPOSITION,SMA_RANGEVALUE), (MPARAM)_dw_int_pos(hWnd));
+		break;
+	}
+
+	if(oldproc)
+		return oldproc(hWnd, msg, mp1, mp2);
+
+	return WinDefWindowProc(hWnd, msg, mp1, mp2);
+}
+
+/* Handle correct painting of a combobox with the WS_CLIPCHILDREN
+ * flag enabled, and also handle TABs to switch input focus.
+ */
+MRESULT EXPENTRY _comboproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+	WindowData *blah = WinQueryWindowPtr(hWnd, QWP_USER);
+	PFNWP oldproc = 0;
+
+	if(blah)
+		oldproc = blah->oldproc;
+
+	switch(msg)
+	{
+	case WM_MOUSEMOVE:
+		if(_wndproc(hWnd, msg, mp1, mp2))
+			return MPFROMSHORT(FALSE);
+		break;
+	case WM_CHAR:
+		if(SHORT1FROMMP(mp2) == '\t')
+		{
+			if(CHARMSG(&msg)->fs & KC_SHIFT)
+				_shift_focus_back(hWnd);
+			else
+				_shift_focus(hWnd);
+			return FALSE;
+		}
+		else if(SHORT1FROMMP(mp2) == '\r' && blah && blah->clickdefault)
+			_click_default(blah->clickdefault);
+		break;
+	case WM_BUTTON1DBLCLK:
+	case WM_BUTTON2DBLCLK:
+	case WM_BUTTON3DBLCLK:
+		if(dw_window_get_data(hWnd, "_dw_disabled"))
+			return (MRESULT)TRUE;
+		break;
+	case WM_BUTTON1DOWN:
+	case WM_BUTTON2DOWN:
+	case WM_BUTTON3DOWN:
+		if(_run_event(hWnd, msg, mp1, mp2) == (MRESULT)TRUE)
+			return (MRESULT)TRUE;
+		_run_event(hWnd, WM_SETFOCUS, (MPARAM)FALSE, (MPARAM)TRUE);
+		break;
+	case WM_SETFOCUS:
+		_run_event(hWnd, msg, mp1, mp2);
+		break;
+	case WM_PAINT:
+		{
+			HWND entry, frame = (HWND)dw_window_get_data(hWnd, "_dw_combo_box"), parent = WinQueryWindow(frame, QW_PARENT);
+			HPS hpsPaint;
+			POINTL ptl;
+			unsigned long width, height, thumbheight = 0;
+			ULONG color;
+
+			if((entry = (HWND)dw_window_get_data(hWnd, "_dw_comboentry")) != NULLHANDLE)
+				dw_window_get_pos_size(entry, 0, 0, 0, &thumbheight);
+
+			if(!thumbheight)
+				thumbheight = WinQuerySysValue(HWND_DESKTOP, SV_CYVSCROLLARROW);
+
+			/* Add 6 because it has a thick border like the entryfield */
+			thumbheight += 6;
+
+			color = (ULONG)dw_window_get_data(parent, "_dw_fore");
+			dw_window_get_pos_size(hWnd, 0, 0, &width, &height);
+
+			if(height > thumbheight)
+			{
+				hpsPaint = WinGetPS(hWnd);
+				if(color)
+					GpiSetColor(hpsPaint, _internal_color(color-1));
+				else
+					GpiSetColor(hpsPaint, CLR_PALEGRAY);
+
+				ptl.x = ptl.y = 0;
+				GpiMove(hpsPaint, &ptl);
+
+				ptl.x = width;
+				ptl.y = height - thumbheight;
+				GpiBox(hpsPaint, DRO_FILL, &ptl, 0, 0);
+
+				WinReleasePS(hpsPaint);
+			}
+		}
+		break;
+	}
+	if(oldproc)
+		return oldproc(hWnd, msg, mp1, mp2);
+
+	return WinDefWindowProc(hWnd, msg, mp1, mp2);
+}
+
+void _GetPPFont(HWND hwnd, char *buff)
+{
+    ULONG AttrFound;
+    BYTE  AttrValue[128];
+    ULONG cbRetLen;
+
+    cbRetLen = WinQueryPresParam(hwnd,
+                                 PP_FONTNAMESIZE,
+                                 0,
+                                 &AttrFound,
+                                 sizeof(AttrValue),
+                                 &AttrValue,
+                                 QPF_NOINHERIT);
+
+    if(PP_FONTNAMESIZE == AttrFound && cbRetLen)
+    {
+        memcpy(buff, AttrValue, cbRetLen);
+    }
+}
+
+int _HandleScroller(HWND handle, int pos, int which)
+{
+	MPARAM res;
+	int min, max, page;
+
+	if(which == SB_SLIDERTRACK)
+		return pos;
+
+	pos = dw_scrollbar_get_pos(handle);
+	res = WinSendMsg(handle, SBM_QUERYRANGE, 0, 0);
+
+	min = SHORT1FROMMP(res);
+	max = SHORT2FROMMP(res);
+	page = (int)dw_window_get_data(handle, "_dw_scrollbar_visible");
+
+	switch(which)
+	{
+	case SB_LINEUP:
+		pos = pos - 1;
+		if(pos < min)
+			pos = min;
+		dw_scrollbar_set_pos(handle, pos);
+		return pos;
+	case SB_LINEDOWN:
+		pos = pos + 1;
+		if(pos > max)
+			pos = max;
+		dw_scrollbar_set_pos(handle, pos);
+		return pos;
+	case SB_PAGEUP:
+		pos = pos - page;
+		if(pos < min)
+			pos = min;
+		dw_scrollbar_set_pos(handle, pos);
+		return pos;
+	case SB_PAGEDOWN:
+		pos = pos + page;
+		if(pos > max)
+			pos = max;
+		dw_scrollbar_set_pos(handle, pos);
+		return pos;
+	}
+	return -1;
+}
+
+void _clear_emphasis(void)
+{
+	if(hwndEmph && WinIsWindow(dwhab, hwndEmph) && pCoreEmph)
+		WinSendMsg(hwndEmph, CM_SETRECORDEMPHASIS, pCoreEmph, MPFROM2SHORT(FALSE, CRA_SOURCE));
+	hwndEmph = NULLHANDLE;
+	pCoreEmph = NULL;
+}
+
+/* Find the desktop window handle */
+HWND _menu_owner(HWND handle)
+{
+	HWND menuowner = NULLHANDLE, lastowner = (HWND)dw_window_get_data(handle, "_dw_owner");
+	int menubar = (int)dw_window_get_data(handle, "_dw_menubar");
+
+	/* Find the toplevel window */
+	while(!menubar && (menuowner = (HWND)dw_window_get_data(lastowner, "_dw_owner")) != NULLHANDLE)
+	{
+		menubar = (int)dw_window_get_data(lastowner, "_dw_menubar");
+		lastowner = menuowner;
+	}
+	if(menuowner && menubar)
+	{
+		HWND client = WinWindowFromID(menuowner, FID_CLIENT);
+
+		return client ? client : menuowner;
+	}
+	return NULLHANDLE;
+}
+
+MRESULT EXPENTRY _run_event(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+	int result = -1;
+	SignalHandler *tmp = Root;
+	ULONG origmsg = msg;
+
+	if(msg == WM_BUTTON2DOWN || msg == WM_BUTTON3DOWN)
+		msg = WM_BUTTON1DOWN;
+	if(msg == WM_BUTTON2UP || msg == WM_BUTTON3UP)
+		msg = WM_BUTTON1UP;
+	if(msg == WM_VSCROLL || msg == WM_HSCROLL)
+		msg = WM_CONTROL;
+
+	/* Find any callbacks for this function */
+	while(tmp)
+	{
+		if(tmp->message == msg || msg == WM_CONTROL || tmp->message == WM_USER+1)
+		{
+			switch(msg)
+			{
+			case WM_SETFOCUS:
+				{
+					if((mp2 && tmp->message == WM_SETFOCUS) || (!mp2 && tmp->message == WM_USER+1))
+					{
+						int (* API setfocusfunc)(HWND, void *) = (int (* API)(HWND, void *))tmp->signalfunction;
+
+						if(hWnd == tmp->window || WinWindowFromID(tmp->window, FID_CLIENT) == hWnd)
+						{
+							result = setfocusfunc(tmp->window, tmp->data);
+							tmp = NULL;
+						}
+					}
+				}
+				break;
+			case WM_TIMER:
+				{
+					int (* API timerfunc)(void *) = (int (* API)(void *))tmp->signalfunction;
+					if(tmp->id == (int)mp1)
+					{
+						if(!timerfunc(tmp->data))
+							dw_timer_disconnect(tmp->id);
+						tmp = NULL;
+					}
+					result = 0;
+				}
+				break;
+			case WM_SIZE:
+				{
+					int (* API sizefunc)(HWND, int, int, void *) = (int (* API)(HWND, int, int, void *))tmp->signalfunction;
+
+					if((hWnd == tmp->window || WinWindowFromID(tmp->window, FID_CLIENT) == hWnd) && SHORT1FROMMP(mp2) && SHORT2FROMMP(mp2))
+					{
+						result = sizefunc(tmp->window, SHORT1FROMMP(mp2), SHORT2FROMMP(mp2), tmp->data);
+						tmp = NULL;
+					}
+				}
+				break;
+			case WM_BUTTON1DOWN:
+				{
+					POINTS pts = (*((POINTS*)&mp1));
+					int (* API buttonfunc)(HWND, int, int, int, void *) = (int (* API)(HWND, int, int, int, void *))tmp->signalfunction;
+
+					if(hWnd == tmp->window || WinWindowFromID(tmp->window, FID_CLIENT) == hWnd || WinQueryCapture(HWND_DESKTOP) == tmp->window)
+					{
+						int button = 0;
+
+						switch(origmsg)
+						{
+						case WM_BUTTON1DOWN:
+							button = 1;
+							break;
+						case WM_BUTTON2DOWN:
+							button = 2;
+							break;
+						case WM_BUTTON3DOWN:
+							button = 3;
+							break;
+						}
+
+						result = buttonfunc(tmp->window, pts.x, _get_frame_height(tmp->window) - pts.y, button, tmp->data);
+						tmp = NULL;
+					}
+				}
+				break;
+			case WM_BUTTON1UP:
+				{
+					POINTS pts = (*((POINTS*)&mp1));
+					int (* API buttonfunc)(HWND, int, int, int, void *) = (int (* API)(HWND, int, int, int, void *))tmp->signalfunction;
+
+					if(hWnd == tmp->window || WinWindowFromID(tmp->window, FID_CLIENT) == hWnd || WinQueryCapture(HWND_DESKTOP) == tmp->window)
+					{
+						int button = 0;
+
+						switch(origmsg)
+						{
+						case WM_BUTTON1UP:
+							button = 1;
+							break;
+						case WM_BUTTON2UP:
+							button = 2;
+							break;
+						case WM_BUTTON3UP:
+							button = 3;
+							break;
+						}
+
+						result = buttonfunc(tmp->window, pts.x, WinQueryWindow(tmp->window, QW_PARENT) == HWND_DESKTOP ? dw_screen_height() - pts.y : _get_height(tmp->window) - pts.y, button, tmp->data);
+						tmp = NULL;
+					}
+				}
+				break;
+			case WM_MOUSEMOVE:
+				{
+					int (* API motionfunc)(HWND, int, int, int, void *) = (int (* API)(HWND, int, int, int, void *))tmp->signalfunction;
+
+					if(hWnd == tmp->window || WinWindowFromID(tmp->window, FID_CLIENT) == hWnd || WinQueryCapture(HWND_DESKTOP) == tmp->window)
+					{
+						int keys = 0;
+						SHORT x = SHORT1FROMMP(mp1), y = SHORT2FROMMP(mp1);
+
+						if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) & 0x8000)
+							keys = DW_BUTTON1_MASK;
+						if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000)
+							keys |= DW_BUTTON2_MASK;
+						if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON3) & 0x8000)
+							keys |= DW_BUTTON3_MASK;
+
+						result = motionfunc(tmp->window, x, _get_frame_height(tmp->window) - y, keys, tmp->data);
+						tmp = NULL;
+					}
+				}
+				break;
+			case WM_CHAR:
+				{
+					int (* API keypressfunc)(HWND, char, int, int, void *) = (int (* API)(HWND, char, int, int, void *))tmp->signalfunction;
+
+					if((hWnd == tmp->window || _toplevel_window(hWnd) == tmp->window) && !(SHORT1FROMMP(mp1) & KC_KEYUP))
+					{
+						int vk;
+						char ch = 0;
+
+						if(SHORT1FROMMP(mp1) & KC_CHAR)
+							ch = (char)SHORT1FROMMP(mp2);
+						if(SHORT1FROMMP(mp1) & KC_VIRTUALKEY)
+							vk = SHORT2FROMMP(mp2);
+						else
+							vk = SHORT1FROMMP(mp2) + 128;
+
+						/* This is a hack to fix shift presses showing
+						 * up as tabs!
+						 */
+						if(ch == '\t' && !(SHORT1FROMMP(mp1) & KC_CHAR))
+						{
+							ch = 0;
+							vk = VK_SHIFT;
+						}
+
+						result = keypressfunc(tmp->window, ch, vk,
+											  SHORT1FROMMP(mp1) & (KC_ALT | KC_SHIFT | KC_CTRL), tmp->data);
+						tmp = NULL;
+					}
+				}
+				break;
+			case WM_CLOSE:
+				{
+					int (* API closefunc)(HWND, void *) = (int (* API)(HWND, void *))tmp->signalfunction;
+
+					if(hWnd == tmp->window || hWnd == WinWindowFromID(tmp->window, FID_CLIENT))
+					{
+						result = closefunc(tmp->window, tmp->data);
+						if(result)
+							result = FALSE;
+						tmp = NULL;
+					}
+				}
+				break;
+			case WM_PAINT:
+				{
+					HPS hps;
+					DWExpose exp;
+					int (* API exposefunc)(HWND, DWExpose *, void *) = (int (* API)(HWND, DWExpose *, void *))tmp->signalfunction;
+					RECTL  rc;
+
+					if(hWnd == tmp->window)
+					{
+						int height = _get_height(hWnd);
+
+						hps = WinBeginPaint(hWnd, 0L, &rc);
+						exp.x = rc.xLeft;
+						exp.y = height - rc.yTop - 1;
+						exp.width = rc.xRight - rc. xLeft;
+						exp.height = rc.yTop - rc.yBottom;
+						result = exposefunc(hWnd, &exp, tmp->data);
+						WinEndPaint(hps);
+					}
+				}
+				break;
+			case WM_COMMAND:
+				{
+					int (* API clickfunc)(HWND, void *) = (int (* API)(HWND, void *))tmp->signalfunction;
+					ULONG command = COMMANDMSG(&msg)->cmd;
+
+					if(tmp->id && command == tmp->id)
+					{
+						HWND menuowner = _menu_owner(tmp->window);
+
+						if(menuowner == hWnd || menuowner == NULLHANDLE)
+						{
+							result = clickfunc(tmp->window, tmp->data);
+							tmp = NULL;
+						}
+					}
+					else if(tmp->window < 65536 && command == tmp->window)
+					{
+						result = clickfunc(popup ?  popup : tmp->window, tmp->data);
+						tmp = NULL;
+					}
+				}
+				break;
+			case WM_CONTROL:
+				if(origmsg == WM_VSCROLL || origmsg == WM_HSCROLL || tmp->message == SHORT2FROMMP(mp1) ||
+				   (tmp->message == SLN_SLIDERTRACK && SHORT2FROMMP(mp1) == SLN_CHANGE))
+				{
+					int svar = SLN_SLIDERTRACK;
+					if(origmsg == WM_CONTROL)
+						svar = SHORT2FROMMP(mp1);
+
+					switch(svar)
+					{
+					case CN_ENTER:
+						{
+							int (* API containerselectfunc)(HWND, char *, void *) = (int (* API)(HWND, char *, void *))tmp->signalfunction;
+							int id = SHORT1FROMMP(mp1);
+							HWND conthwnd = dw_window_from_id(hWnd, id);
+							char *text = NULL;
+
+							if(mp2)
+							{
+								PRECORDCORE pre;
+
+								pre = ((PNOTIFYRECORDENTER)mp2)->pRecord;
+								if(pre)
+									text = pre->pszIcon;
+							}
+
+							if(tmp->window == conthwnd)
+							{
+								result = containerselectfunc(tmp->window, text, tmp->data);
+								tmp = NULL;
+							}
+						}
+						break;
+					case CN_EXPANDTREE:
+						{
+							int (* API treeexpandfunc)(HWND, HTREEITEM, void *) = (int (* API)(HWND, HTREEITEM, void *))tmp->signalfunction;
+							int id = SHORT1FROMMP(mp1);
+							HWND conthwnd = dw_window_from_id(hWnd, id);
+
+							if(tmp->window == conthwnd)
+							{
+								result = treeexpandfunc(tmp->window, (HTREEITEM)mp2, tmp->data);
+								tmp = NULL;
+							}
+						}
+						break;
+					case CN_CONTEXTMENU:
+						{
+							int (* API containercontextfunc)(HWND, char *, int, int, void *, void *) = (int (* API)(HWND, char *, int, int, void *, void *))tmp->signalfunction;
+							int id = SHORT1FROMMP(mp1);
+							HWND conthwnd = dw_window_from_id(hWnd, id);
+							char *text = NULL;
+							void *user = NULL;
+							LONG x,y;
+
+							if(mp2)
+							{
+								PCNRITEM pci;
+
+								pci = (PCNRITEM)mp2;
+
+								text = pci->rc.pszIcon;
+								user = pci->user;
+							}
+
+							dw_pointer_query_pos(&x, &y);
+
+							if(tmp->window == conthwnd)
+							{
+								int container = (int)dw_window_get_data(tmp->window, "_dw_container");
+
+								if(mp2)
+								{
+									if(!container)
+									{
+										NOTIFYRECORDEMPHASIS pre;
+
+										dw_tree_item_select(tmp->window, (HTREEITEM)mp2);
+										pre.pRecord = mp2;
+										pre.fEmphasisMask = CRA_CURSORED;
+										pre.hwndCnr = tmp->window;
+										_run_event(hWnd, WM_CONTROL, MPFROM2SHORT(0, CN_EMPHASIS), (MPARAM)&pre);
+										pre.pRecord->flRecordAttr |= CRA_CURSORED;
+									}
+									else
+									{
+										if(pCoreEmph)
+											_clear_emphasis();
+										hwndEmph = tmp->window;
+										pCoreEmph = mp2;
+										WinSendMsg(tmp->window, CM_SETRECORDEMPHASIS, mp2, MPFROM2SHORT(TRUE, CRA_SOURCE));
+									}
+								}
+								result = containercontextfunc(tmp->window, text, x, y, tmp->data, user);
+								tmp = NULL;
+							}
+						}
+						break;
+					case CN_EMPHASIS:
+						{
+							PNOTIFYRECORDEMPHASIS pre = (PNOTIFYRECORDEMPHASIS)mp2;
+							static int emph_recurse = 0;
+
+							if(!emph_recurse)
+							{
+								emph_recurse = 1;
+
+								if(mp2)
+								{
+									if(tmp->window == pre->hwndCnr)
+									{
+										PCNRITEM pci = (PCNRITEM)pre->pRecord;
+
+										if(pci && pre->fEmphasisMask & CRA_CURSORED && (pci->rc.flRecordAttr & CRA_CURSORED))
+										{
+											int (* API treeselectfunc)(HWND, HTREEITEM, char *, void *, void *) = (int (* API)(HWND, HTREEITEM, char *, void *, void *))tmp->signalfunction;
+
+											if(dw_window_get_data(tmp->window, "_dw_container"))
+												result = treeselectfunc(tmp->window, 0, pci->rc.pszIcon, tmp->data, 0);
+											else
+											{
+												if(lasthcnr == tmp->window && lastitem == (HWND)pci)
+												{
+													lasthcnr = 0;
+													lastitem = 0;
+												}
+												else
+												{
+													lasthcnr = tmp->window;
+													lastitem = (HWND)pci;
+													result = treeselectfunc(tmp->window, (HTREEITEM)pci, pci->rc.pszIcon, tmp->data, pci->user);
+												}
+											}
+											tmp = NULL;
+										}
+									}
+								}
+								emph_recurse = 0;
+							}
+						}
+						break;
+					case LN_SELECT:
+						{
+							char classbuf[100];
+
+							WinQueryClassName(tmp->window, 99, classbuf);
+
+							if(strncmp(classbuf, "#38", 4) == 0)
+							{
+								int (* API valuechangedfunc)(HWND, int, void *) = (int (* API)(HWND, int, void *))tmp->signalfunction;
+
+								if(tmp->window == hWnd || WinQueryWindow(tmp->window, QW_PARENT) == hWnd)
+								{
+									static int lastvalue = -1;
+									static HWND lasthwnd = NULLHANDLE;
+									int ulValue = (int)WinSendMsg(tmp->window, SLM_QUERYSLIDERINFO, MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_INCREMENTVALUE), 0);
+									if(lastvalue != ulValue || lasthwnd != tmp->window)
+									{
+										result = valuechangedfunc(tmp->window, ulValue, tmp->data);
+										lastvalue = ulValue;
+										lasthwnd = tmp->window;
+									}
+									tmp = NULL;
+								}
+							}
+							else
+							{
+								int (* API listboxselectfunc)(HWND, int, void *) = (int (* API )(HWND, int, void *))tmp->signalfunction;
+								int id = SHORT1FROMMP(mp1);
+								HWND conthwnd = dw_window_from_id(hWnd, id);
+								static int _recursing = 0;
+
+								if(_recursing == 0 && (tmp->window == conthwnd || (!id && tmp->window == (HWND)mp2)))
+								{
+									char buf1[500];
+									unsigned int index = dw_listbox_selected(tmp->window);
+
+									dw_listbox_get_text(tmp->window, index, buf1, 500);
+
+									_recursing = 1;
+
+									if(id && strncmp(classbuf, "#2", 3)==0)
+									{
+										char *buf2;
+
+										buf2 = dw_window_get_text(tmp->window);
+
+										/* This is to make sure the listboxselect function doesn't
+										 * get called if the user is modifying the entry text.
+										 */
+										if(buf2 && *buf2 && *buf1 && strncmp(buf1, buf2, 500) == 0)
+											result = listboxselectfunc(tmp->window, index, tmp->data);
+
+										if(buf2)
+											free(buf2);
+									}
+									else
+										result = listboxselectfunc(tmp->window, index, tmp->data);
+
+									_recursing = 0;
+									tmp = NULL;
+								}
+							}
+						}
+						break;
+					case SLN_SLIDERTRACK:
+						{
+							int (* API valuechangedfunc)(HWND, int, void *) = (int (* API)(HWND, int, void *))tmp->signalfunction;
+
+							if(origmsg == WM_CONTROL)
+							{
+								/* Handle Slider control */
+								if(tmp->window == hWnd || WinQueryWindow(tmp->window, QW_PARENT) == hWnd)
+								{
+									static int lastvalue = -1;
+									static HWND lasthwnd = NULLHANDLE;
+									int ulValue = (int)WinSendMsg(tmp->window, SLM_QUERYSLIDERINFO, MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_INCREMENTVALUE), 0);
+									if(lastvalue != ulValue || lasthwnd != tmp->window)
+									{
+										dw_window_set_data(tmp->window, "_dw_slider_value", (void *)ulValue);
+										result = valuechangedfunc(tmp->window, ulValue, tmp->data);
+										lastvalue = ulValue;
+										lasthwnd = tmp->window;
+									}
+									tmp = NULL;
+								}
+							}
+							else
+							{
+								/* Handle scrollbar control */
+								if(tmp->window > 65535 && tmp->window == WinWindowFromID(hWnd, (ULONG)mp1))
+								{
+									int pos = _HandleScroller(tmp->window, (int)SHORT1FROMMP(mp2), (int)SHORT2FROMMP(mp2));;
+
+									if(pos > -1)
+									{
+										dw_window_set_data(tmp->window, "_dw_scrollbar_value", (void *)pos);
+										result = valuechangedfunc(tmp->window, pos, tmp->data);
+									}
+									result = 0;
+									tmp = NULL;
+								}
+							}
+						}
+						break;
+					case BKN_PAGESELECTED:
+						{
+							PAGESELECTNOTIFY *psn = (PAGESELECTNOTIFY *)mp2;
+
+							if(psn && tmp->window == psn->hwndBook)
+							{
+								int (* API switchpagefunc)(HWND, unsigned long, void *) = (int (* API)(HWND, unsigned long, void *))tmp->signalfunction;
+
+								result = switchpagefunc(tmp->window, psn->ulPageIdNew, tmp->data);
+								tmp = NULL;
+							}
+						}
+						break;
+					}
+				}
+				break;
+			}
+		}
+
+		if(tmp)
+			tmp = tmp->next;
+
+	}
+	return (MRESULT)result;
+}
+
+/* Gets a DW_RGB value from the three spinbuttons */
+unsigned long _dw_color_spin_get(HWND window)
+{
+	HWND button = (HWND)dw_window_get_data(window, "_dw_red_spin");
+	long red, green, blue;
+
+	red = dw_spinbutton_get_pos(button);
+	button = (HWND)dw_window_get_data(window, "_dw_green_spin");
+	green = dw_spinbutton_get_pos(button);
+	button = (HWND)dw_window_get_data(window, "_dw_blue_spin");
+	blue = dw_spinbutton_get_pos(button);
+
+	return DW_RGB(red, green, blue);
+}
+
+/* Set the three spinbuttons from a DW_RGB value */
+void _dw_color_spin_set(HWND window, unsigned long value)
+{
+	HWND button = (HWND)dw_window_get_data(window, "_dw_red_spin");
+	dw_window_set_data(window, "_dw_updating", (void *)1);
+	dw_spinbutton_set_pos(button, DW_RED_VALUE(value));
+	button = (HWND)dw_window_get_data(window, "_dw_green_spin");
+	dw_spinbutton_set_pos(button, DW_GREEN_VALUE(value));
+	button = (HWND)dw_window_get_data(window, "_dw_blue_spin");
+	dw_spinbutton_set_pos(button, DW_BLUE_VALUE(value));
+	dw_window_set_data(window, "_dw_updating", NULL);
+}
+
+/* Sets the color selection control to be a DW_RGB value */
+void _dw_col_set(HWND col, unsigned long value)
+{
+	WinSendMsg(col, 0x0602, MPFROMLONG(_os2_color(value)), 0);
+	if(!IS_WARP4())
+		WinSendMsg(col, 0x1384, MPFROMLONG(_os2_color(value)), 0);
+}
+
+/* Handles control messages sent to the box (owner). */
+MRESULT EXPENTRY _controlproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+	Box *blah = WinQueryWindowPtr(hWnd, QWP_USER);
+
+	switch(msg)
+	{
+	case WM_MOUSEMOVE:
+		if(_wndproc(hWnd, msg, mp1, mp2))
+			return MPFROMSHORT(FALSE);
+		break;
+	case WM_VSCROLL:
+	case WM_HSCROLL:
+		if(_run_event(hWnd, msg, mp1, mp2))
+		{
+			HWND window = WinWindowFromID(hWnd, (ULONG)mp1);
+			_HandleScroller(window, (int)SHORT1FROMMP(mp2), (int)SHORT2FROMMP(mp2));
+		}
+		break;
+		/* Handles Color Selection control messages */
+	case 0x0601:
+	case 0x130C:
+		{
+			HWND window = (HWND)dw_window_get_data(hWnd, "_dw_window");
+			unsigned long val = (unsigned long)mp1;
+
+			if(window)
+				_dw_color_spin_set(window, DW_RGB((val & 0xFF0000) >> 16, (val & 0xFF00) >> 8, val & 0xFF));
+		}
+		break;
+	case WM_CONTROL:
+		if((SHORT2FROMMP(mp1) == SPBN_CHANGE || SHORT2FROMMP(mp1) == SPBN_ENDSPIN))
+		{
+			HWND window = (HWND)dw_window_get_data(hWnd, "_dw_window");
+
+			if(window && !dw_window_get_data(window, "_dw_updating"))
+			{
+				unsigned long val = _dw_color_spin_get(window);
+				HWND col = (HWND)dw_window_get_data(window, "_dw_col");
+
+				_dw_col_set(col, val);
+			}
+		}
+		_run_event(hWnd, msg, mp1, mp2);
+		break;
+	}
+
+	if(blah && blah->oldproc)
+		return blah->oldproc(hWnd, msg, mp1, mp2);
+
+	return WinDefWindowProc(hWnd, msg, mp1, mp2);
+}
+
+/* The main window procedure for Dynamic Windows, all the resizing code is done here. */
+MRESULT EXPENTRY _wndproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+	int result = -1;
+	static int command_active = 0;
+	void (* API windowfunc)(PVOID) = 0L;
+
+	if(!command_active)
+	{
+        /* Make sure we don't end up in infinite recursion */
+		command_active = 1;
+
+		result = (int)_run_event(hWnd, msg, mp1, mp2);
+
+		command_active = 0;
+	}
+
+	/* Now that any handlers are done... do normal processing */
+	switch( msg )
+	{
+   case WM_ERASEBACKGROUND:
+      return 0;
+
+	case WM_PAINT:
+		{
+		HPS    hps;
+		RECTL  rc;
+
+		hps = WinBeginPaint( hWnd, 0L, &rc );
+		WinEndPaint( hps );
+		break;
+		}
+
+	case WM_SIZE:
+		{
+			Box *mybox = (Box *)WinQueryWindowPtr(hWnd, QWP_USER);
+
+			if(!SHORT1FROMMP(mp2) && !SHORT2FROMMP(mp2))
+				return (MPARAM)TRUE;
+
+			if(mybox && mybox->flags != DW_MINIMIZED)
+			{
+				/* Hide the window when recalculating to reduce
+				 * CPU load.
+				 */
+				WinShowWindow(hWnd, FALSE);
+
+                if(mybox->items)
+					WinSetWindowPos(mybox->items[0].hwnd, HWND_TOP, 0, 0, SHORT1FROMMP(mp2), SHORT2FROMMP(mp2), SWP_MOVE | SWP_SIZE);
+
+				_do_resize(mybox, SHORT1FROMMP(mp2), SHORT2FROMMP(mp2));
+
+				WinShowWindow(hWnd, TRUE);
+			}
+		}
+		break;
+	case WM_MINMAXFRAME:
+		{
+			Box *mybox = (Box *)WinQueryWindowPtr(hWnd, QWP_USER);
+			SWP *swp = (SWP *)mp1;
+
+			if(mybox && (swp->fl & SWP_MINIMIZE))
+				mybox->flags = DW_MINIMIZED;
+
+			if(mybox && (swp->fl & SWP_RESTORE))
+			{
+				if(!mybox->titlebar && mybox->hwndtitle)
+					WinSetParent(mybox->hwndtitle, HWND_OBJECT, FALSE);
+				mybox->flags = 0;
+			}
+
+			if(mybox && (swp->fl & (SWP_MAXIMIZE | SWP_RESTORE)))
+			{
+				int z;
+				SWP swp2;
+
+				WinQueryWindowPos(swp->hwnd, &swp2);
+
+				if(swp2.cx == swp->cx && swp2.cy == swp->cy)
+					return FALSE;
+
+				mybox->flags = 0;
+
+				/* Hide the window when recalculating to reduce
+				 * CPU load.
+				 */
+				WinShowWindow(hWnd, FALSE);
+
+				_do_resize(mybox, swp->cx, swp->cy);
+
+				if(mybox->count == 1 && mybox->items[0].type == TYPEBOX)
+				{
+					mybox = (Box *)WinQueryWindowPtr(mybox->items[0].hwnd, QWP_USER);
+
+					for(z=0;z<mybox->count;z++)
+						_check_resize_notebook(mybox->items[z].hwnd);
+
+				}
+
+				WinShowWindow(hWnd, TRUE);
+			}
+		}
+		break;
+	case WM_CONTROL:
+		switch(SHORT2FROMMP(mp1))
+		{
+		case BKN_PAGESELECTEDPENDING:
+			{
+				PAGESELECTNOTIFY *psn = (PAGESELECTNOTIFY *)mp2;
+				HWND pagehwnd = (HWND)WinSendMsg(psn->hwndBook, BKM_QUERYPAGEWINDOWHWND, MPFROMLONG(psn->ulPageIdNew), 0);
+				Box *pagebox = (Box *)WinQueryWindowPtr(pagehwnd, QWP_USER);
+				unsigned long x, y, width, height;
+				RECTL rc;
+
+				if(pagebox && psn->ulPageIdNew != psn->ulPageIdCur)
+				{
+					dw_window_get_pos_size(psn->hwndBook, &x, &y, &width, &height);
+
+					rc.xLeft = x;
+					rc.yBottom = y;
+					rc.xRight = x + width;
+					rc.yTop = y + height;
+
+					WinSendMsg(psn->hwndBook, BKM_CALCPAGERECT, (MPARAM)&rc, (MPARAM)TRUE);
+
+					_do_resize(pagebox, rc.xRight - rc.xLeft, rc.yTop - rc.yBottom);
+				}
+			}
+			break;
+		}
+		break;
+	case WM_CLOSE:
+		if(result == -1)
+		{
+			dw_window_destroy(WinQueryWindow(hWnd, QW_PARENT));
+			return (MRESULT)TRUE;
+		}
+		break;
+	case WM_MOUSEMOVE:
+		{
+			HPOINTER pointer;
+
+			if((pointer = (HPOINTER)dw_window_get_data(hWnd, "_dw_pointer")) ||
+			   (pointer = (HPOINTER)dw_window_get_data(_toplevel_window(hWnd), "_dw_pointer")))
+			{
+				WinSetPointer(HWND_DESKTOP, pointer);
+				return MRFROMSHORT(TRUE);
+			}
+		}
+		return MRFROMSHORT(FALSE);
+	case WM_USER:
+		windowfunc = (void (* API)(void *))mp1;
+
+		if(windowfunc)
+			windowfunc((void *)mp2);
+		break;
+	case WM_CHAR:
+		if(SHORT1FROMMP(mp2) == '\t')
+		{
+			if(CHARMSG(&msg)->fs & KC_SHIFT)
+				_shift_focus_back(hWnd);
+			else
+				_shift_focus(hWnd);
+			return FALSE;
+		}
+		break;
+	case WM_DESTROY:
+		{
+			HWND parent = WinQueryWindow(hWnd, QW_PARENT);
+
+			/* Free memory before destroying */
+			if(parent && WinWindowFromID(parent, FID_CLIENT) == hWnd)
+				_free_window_memory(parent);
+			else
+				_free_window_memory(hWnd);
+		}
+		break;
+	case WM_MENUEND:
+		/* Delay removing the signal until we've executed
+		 * the signal handler.
+		 */
+		WinPostMsg(hWnd, WM_USER+2, mp1, mp2);
+		break;
+	case WM_USER+2:
+		_clear_emphasis();
+		if(dw_window_get_data((HWND)mp2, "_dw_popup"))
+			_free_menu_data((HWND)mp2);
+		break;
+	}
+
+	if(result != -1)
+		return (MRESULT)result;
+	else
+		return WinDefWindowProc(hWnd, msg, mp1, mp2);
+}
+
+void _changebox(Box *thisbox, int percent, int type)
+{
+	int z;
+
+	for(z=0;z<thisbox->count;z++)
+	{
+		if(thisbox->items[z].type == TYPEBOX)
+		{
+			Box *tmp = WinQueryWindowPtr(thisbox->items[z].hwnd, QWP_USER);
+			_changebox(tmp, percent, type);
+		}
+		else
+		{
+			if(type == DW_HORZ)
+			{
+				if(thisbox->items[z].hsize == SIZEEXPAND)
+					thisbox->items[z].width = (int)(((float)thisbox->items[z].origwidth) * (((float)percent)/((float)100.0)));
+			}
+			else
+			{
+				if(thisbox->items[z].vsize == SIZEEXPAND)
+					thisbox->items[z].height = (int)(((float)thisbox->items[z].origheight) * (((float)percent)/((float)100.0)));
+			}
+		}
+	}
+}
+
+void _handle_splitbar_resize(HWND hwnd, float percent, int type, int x, int y)
+{
+	float ratio = (float)percent/(float)100.0;
+	HWND handle1 = (HWND)dw_window_get_data(hwnd, "_dw_topleft");
+	HWND handle2 = (HWND)dw_window_get_data(hwnd, "_dw_bottomright");
+	Box *tmp = WinQueryWindowPtr(handle1, QWP_USER);
+
+	WinShowWindow(handle1, FALSE);
+	WinShowWindow(handle2, FALSE);
+
+	if(type == DW_HORZ)
+	{
+		int newx = (int)((float)x * ratio) - (SPLITBAR_WIDTH/2);
+
+		WinSetWindowPos(handle1, NULLHANDLE, 0, 0, newx, y, SWP_MOVE | SWP_SIZE);
+		_do_resize(tmp, newx - 1, y - 1);
+
+		dw_window_set_data(hwnd, "_dw_start", (void *)newx);
+
+		tmp = WinQueryWindowPtr(handle2, QWP_USER);
+
+		newx = x - newx - SPLITBAR_WIDTH;
+
+		WinSetWindowPos(handle2, NULLHANDLE, x - newx, 0, newx, y, SWP_MOVE | SWP_SIZE);
+		_do_resize(tmp, newx - 1, y - 1);
+	}
+	else
+	{
+		int newy = (int)((float)y * ratio) - (SPLITBAR_WIDTH/2);
+
+		WinSetWindowPos(handle1, NULLHANDLE, 0, y - newy, x, newy, SWP_MOVE | SWP_SIZE);
+		_do_resize(tmp, x - 1, newy - 1);
+
+		tmp = WinQueryWindowPtr(handle2, QWP_USER);
+
+		newy = y - newy - SPLITBAR_WIDTH;
+
+		WinSetWindowPos(handle2, NULLHANDLE, 0, 0, x, newy, SWP_MOVE | SWP_SIZE);
+		_do_resize(tmp, x - 1, newy - 1);
+
+		dw_window_set_data(hwnd, "_dw_start", (void *)newy);
+	}
+
+	WinShowWindow(handle1, TRUE);
+	WinShowWindow(handle2, TRUE);
+}
+
+
+/* This handles any activity on the splitbars (sizers) */
+MRESULT EXPENTRY _splitwndproc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+	switch (msg)
+	{
+	case WM_ACTIVATE:
+	case WM_SETFOCUS:
+		return (MRESULT)(FALSE);
+
+	case WM_PAINT:
+		{
+			HPS hps;
+			POINTL ptl[2];
+			RECTL rcl;
+			int type = (int)dw_window_get_data(hwnd, "_dw_type");
+			int start = (int)dw_window_get_data(hwnd, "_dw_start");
+
+			hps = WinBeginPaint(hwnd, 0, 0);
+
+			WinQueryWindowRect(hwnd, &rcl);
+
+			if(type == DW_HORZ)
+			{
+				ptl[0].x = rcl.xLeft + start;
+				ptl[0].y = rcl.yBottom;
+				ptl[1].x = rcl.xRight + start + 3;
+				ptl[1].y = rcl.yTop;
+			}
+			else
+			{
+				ptl[0].x = rcl.xLeft;
+				ptl[0].y = rcl.yBottom + start;
+				ptl[1].x = rcl.xRight;
+				ptl[1].y = rcl.yTop + start + 3;
+			}
+
+
+			GpiSetColor(hps, CLR_PALEGRAY);
+			GpiMove(hps, &ptl[0]);
+			GpiBox(hps, DRO_OUTLINEFILL, &ptl[1], 0, 0);
+			WinEndPaint(hps);
+		}
+		return MRFROMSHORT(FALSE);
+
+	case WM_MOUSEMOVE:
+		{
+			int type = (int)dw_window_get_data(hwnd, "_dw_type");
+
+			if(type == DW_HORZ)
+				WinSetPointer(HWND_DESKTOP,
+							  WinQuerySysPointer(HWND_DESKTOP,
+												 SPTR_SIZEWE,
+												 FALSE));
+			else
+				WinSetPointer(HWND_DESKTOP,
+							  WinQuerySysPointer(HWND_DESKTOP,
+												 SPTR_SIZENS,
+												 FALSE));
+		}
+		return MRFROMSHORT(FALSE);
+	case WM_BUTTON1DOWN:
+		{
+			APIRET rc;
+			RECTL  rclFrame;
+			RECTL  rclBounds;
+			float *percent = (float *)dw_window_get_data(hwnd, "_dw_percent");
+			int type = (int)dw_window_get_data(hwnd, "_dw_type");
+			int start = (int)dw_window_get_data(hwnd, "_dw_start");
+
+			WinQueryWindowRect(hwnd, &rclFrame);
+			WinQueryWindowRect(hwnd, &rclBounds);
+
+			WinMapWindowPoints(hwnd, HWND_DESKTOP,
+							   (PPOINTL)&rclBounds, 2);
+
+
+			if(type == DW_HORZ)
+			{
+				rclFrame.xLeft = start;
+				rclFrame.xRight = start + SPLITBAR_WIDTH;
+			}
+			else
+			{
+				rclFrame.yBottom = start;
+				rclFrame.yTop = start + SPLITBAR_WIDTH;
+			}
+
+			if(percent)
+			{
+				rc = _TrackRectangle(hwnd, &rclFrame, &rclBounds);
+
+				if(rc == TRUE)
+				{
+					int width = (rclBounds.xRight - rclBounds.xLeft);
+					int height = (rclBounds.yTop - rclBounds.yBottom);
+
+					if(type == DW_HORZ)
+					{
+						start = rclFrame.xLeft - rclBounds.xLeft;
+						if(width - SPLITBAR_WIDTH > 1 && start < width - SPLITBAR_WIDTH)
+							*percent = ((float)start / (float)(width - SPLITBAR_WIDTH)) * 100.0;
+					}
+					else
+					{
+						start = rclFrame.yBottom - rclBounds.yBottom;
+						if(height - SPLITBAR_WIDTH > 1 && start < height - SPLITBAR_WIDTH)
+							*percent = 100.0 - (((float)start / (float)(height - SPLITBAR_WIDTH)) * 100.0);
+					}
+					_handle_splitbar_resize(hwnd, *percent, type, width, height);
+					_handle_splitbar_resize(hwnd, *percent, type, width, height);
+				}
+			}
+		}
+		return MRFROMSHORT(FALSE);
+	}
+	return WinDefWindowProc(hwnd, msg, mp1, mp2);
+}
+
+/* Function: BubbleProc
+ * Abstract: Subclass procedure for bubble help
+ */
+MRESULT EXPENTRY _BubbleProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+	MRESULT res;
+	PFNWP proc = (PFNWP)WinQueryWindowPtr(hwnd, QWL_USER);
+
+	if(proc)
+		res = proc(hwnd, msg, mp1, mp2);
+	else
+		res = WinDefWindowProc(hwnd, msg, mp1, mp2);
+
+	if(msg == WM_PAINT)
+	{
+		POINTL ptl;
+		HPS hpsTemp;
+		RECTL rcl;
+		int height, width;
+
+		WinQueryWindowRect(hwnd, &rcl);
+		height = rcl.yTop - rcl.yBottom - 1;
+		width = rcl.xRight - rcl.xLeft - 1;
+
+		/* Draw a border around the bubble help */
+		hpsTemp = WinGetPS(hwnd);
+		GpiSetColor(hpsTemp, CLR_BLACK);
+		ptl.x = ptl.y = 0;
+		GpiMove(hpsTemp, &ptl);
+		ptl.x = 0;
+		ptl.y = height;
+		GpiLine(hpsTemp, &ptl);
+		ptl.x = ptl.y = 0;
+		GpiMove(hpsTemp, &ptl);
+		ptl.y = 0;
+		ptl.x = width;
+		GpiLine(hpsTemp, &ptl);
+		ptl.x = width;
+		ptl.y = height;
+		GpiMove(hpsTemp, &ptl);
+		ptl.x = 0;
+		ptl.y = height;
+		GpiLine(hpsTemp, &ptl);
+		ptl.x = width;
+		ptl.y = height;
+		GpiMove(hpsTemp, &ptl);
+		ptl.y = 0;
+		ptl.x = width;
+		GpiLine(hpsTemp, &ptl);
+		WinReleasePS(hpsTemp);
+	}
+	return res;
+}
+
+MRESULT EXPENTRY _button_draw(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2, PFNWP oldproc, int indent)
+{
+	HPIXMAP pixmap = (HPIXMAP)dw_window_get_data(hwnd, "_dw_hpixmap");
+	HPIXMAP disable = (HPIXMAP)dw_window_get_data(hwnd, "_dw_hpixmap_disabled");
+	HPOINTER icon = (HPOINTER)dw_window_get_data(hwnd, "_dw_button_icon");
+	MRESULT res;
+	unsigned long width, height;
+	int x = 5, y = 5;
+
+	dw_window_get_pos_size(hwnd, NULL, NULL, &width, &height);
+
+	if(!oldproc)
+		res = WinDefWindowProc(hwnd, msg, mp1, mp2);
+	res = oldproc(hwnd, msg, mp1, mp2);
+
+	if(icon)
+	{
+		ULONG halftone = DP_NORMAL;
+		HPS hps = WinGetPS(hwnd);
+		POINTERINFO pi;
+		int cx, cy;
+
+		if(dw_window_get_data(hwnd, "_dw_disabled"))
+			halftone = DP_HALFTONED;
+
+		cx = width - 10;
+		cy = height - 10;
+
+		if(WinQueryPointerInfo(icon, &pi))
+		{
+			BITMAPINFOHEADER sl;
+			int newcx = cx, newcy = cy;
+
+			/* Check the mini icon first */
+			if(GpiQueryBitmapParameters(pi.hbmMiniColor, &sl))
+			{
+				if(sl.cx && sl.cy && cx > sl.cx && cy > sl.cy)
+				{
+					newcx = sl.cx;
+					newcy = sl.cy;
+				}
+			}
+			/* Check the normal icon second */
+			if(GpiQueryBitmapParameters(pi.hbmColor, &sl))
+			{
+				if(sl.cx && sl.cy && cx > sl.cx && cy > sl.cy)
+				{
+					newcx = sl.cx;
+					newcy = sl.cy;
+				}
+			}
+			cx = newcx; cy = newcy;
+			x = (width - cx)/2;
+			y = (height - cy)/2;
+		}
+		WinStretchPointer(hps, x + indent, y - indent, cx, cy, icon, halftone);
+		WinReleasePS(hps);
+	}
+	else if(pixmap)
+	{
+		x = (width - pixmap->width)/2;
+		y = (height - pixmap->height)/2;
+
+		if(disable && dw_window_get_data(hwnd, "_dw_disabled"))
+			dw_pixmap_bitblt(hwnd, 0, x + indent, y + indent, pixmap->width, pixmap->height, 0, disable, 0, 0);
+		else
+			dw_pixmap_bitblt(hwnd, 0, x + indent, y + indent, pixmap->width, pixmap->height, 0, pixmap, 0, 0);
+	}
+	return res;
+}
+
+/* Function: BtProc
+ * Abstract: Subclass procedure for buttons
+ */
+
+MRESULT EXPENTRY _BtProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+	BubbleButton *bubble;
+	PFNWP oldproc;
+
+	bubble = (BubbleButton *)WinQueryWindowPtr(hwnd, QWL_USER);
+
+	if(!bubble)
+		return WinDefWindowProc(hwnd, msg, mp1, mp2);
+
+	oldproc = bubble->pOldProc;
+
+	switch(msg)
+	{
+	case WM_MOUSEMOVE:
+		if(_wndproc(hwnd, msg, mp1, mp2))
+			return MPFROMSHORT(FALSE);
+		break;
+	case WM_PAINT:
+		return _button_draw(hwnd, msg, mp1, mp2, oldproc, 0);
+	case BM_SETHILITE:
+		return _button_draw(hwnd, msg, mp1, mp2, oldproc, (int)mp1);
+	case WM_SETFOCUS:
+		if(mp2)
+			_run_event(hwnd, msg, mp1, mp2);
+		else
+			WinSendMsg(hwnd, BM_SETDEFAULT, 0, 0);
+		break;
+	case WM_BUTTON1DOWN:
+	case WM_BUTTON2DOWN:
+	case WM_BUTTON3DOWN:
+	case WM_BUTTON1DBLCLK:
+	case WM_BUTTON2DBLCLK:
+	case WM_BUTTON3DBLCLK:
+		if(dw_window_get_data(hwnd, "_dw_disabled"))
+			return (MRESULT)FALSE;
+		break;
+	case WM_BUTTON1UP:
+		{
+			SignalHandler *tmp = Root;
+
+			if(WinIsWindowEnabled(hwnd) && !dw_window_get_data(hwnd, "_dw_disabled"))
+			{
+				/* Find any callbacks for this function */
+				while(tmp)
+				{
+					if(tmp->message == WM_COMMAND)
+					{
+						/* Make sure it's the right window, and the right ID */
+						if(tmp->window == hwnd)
+						{
+							/* Due to the fact that if we run the function
+							 * here, finishing actions on the button will occur
+							 * after we run the signal handler.  So we post the
+							 * message so the button can finish what it needs to
+							 * do before we run our handler.
+							 */
+							WinPostMsg(hwnd, WM_USER, (MPARAM)tmp, 0);
+							tmp = NULL;
+						}
+					}
+					if(tmp)
+						tmp= tmp->next;
+				}
+			}
+		}
+		break;
+	case WM_USER:
+		{
+            SignalHandler *tmp = (SignalHandler *)mp1;
+			int (* API clickfunc)(HWND, void *) = NULL;
+
+			if(tmp)
+			{
+				clickfunc = (int (* API)(HWND, void *))tmp->signalfunction;
+
+				clickfunc(tmp->window, tmp->data);
+			}
+		}
+        break;
+	case WM_CHAR:
+		{
+			/* A button press should also occur for an ENTER or SPACE press
+			 * while the button has the active input focus.
+			 */
+			if(SHORT1FROMMP(mp2) == '\r' || SHORT1FROMMP(mp2) == ' ')
+			{
+				SignalHandler *tmp = Root;
+
+				/* Find any callbacks for this function */
+				while(tmp)
+				{
+					if(tmp->message == WM_COMMAND)
+					{
+						/* Make sure it's the right window, and the right ID */
+						if(tmp->window == hwnd)
+						{
+							WinPostMsg(hwnd, WM_USER, (MPARAM)tmp, 0);
+							tmp = NULL;
+						}
+					}
+					if(tmp)
+						tmp= tmp->next;
+				}
+			}
+			if(SHORT1FROMMP(mp2) == '\t')
+			{
+				if(CHARMSG(&msg)->fs & KC_SHIFT)
+					_shift_focus_back(hwnd);
+				else
+					_shift_focus(hwnd);
+				WinSendMsg(hwnd, BM_SETDEFAULT, 0, 0);
+				return FALSE;
+			}
+			else if(!(CHARMSG(&msg)->fs & KC_KEYUP) && (CHARMSG(&msg)->vkey == VK_LEFT || CHARMSG(&msg)->vkey == VK_UP))
+			{
+				_shift_focus_back(hwnd);
+				return FALSE;
+			}
+			else if(!(CHARMSG(&msg)->fs & KC_KEYUP) && (CHARMSG(&msg)->vkey == VK_RIGHT || CHARMSG(&msg)->vkey == VK_DOWN))
+			{
+				_shift_focus(hwnd);
+				return FALSE;
+			}
+		}
+		break;
+	case 0x041f:
+		if (hwndBubble)
+		{
+			WinDestroyWindow(hwndBubble);
+			hwndBubble = 0;
+		}
+		break;
+
+	case 0x041e:
+
+		if(!*bubble->bubbletext)
+			break;
+
+		if(hwndBubble)
+		{
+			WinDestroyWindow(hwndBubble);
+			hwndBubble = 0;
+		}
+
+		if(!hwndBubble)
+		{
+			HPS   hpsTemp = 0;
+			LONG  lHight;
+			LONG  lWidth;
+			POINTL txtPointl[TXTBOX_COUNT];
+			POINTL ptlWork = {0,0};
+			ULONG ulColor = CLR_YELLOW;
+			void *blah;
+
+			hwndBubbleLast   = hwnd;
+			hwndBubble = WinCreateWindow(HWND_DESKTOP,
+										 WC_STATIC,
+										 "",
+										 SS_TEXT |
+										 DT_CENTER |
+										 DT_VCENTER,
+                                         0,0,0,0,
+										 HWND_DESKTOP,
+										 HWND_TOP,
+										 0,
+										 NULL,
+										 NULL);
+
+			WinSetPresParam(hwndBubble,
+							PP_FONTNAMESIZE,
+							strlen(DefaultFont)+1,
+							DefaultFont);
+
+
+			WinSetPresParam(hwndBubble,
+							PP_BACKGROUNDCOLORINDEX,
+							sizeof(ulColor),
+							&ulColor);
+
+			WinSetWindowText(hwndBubble,
+							 bubble->bubbletext);
+
+			WinMapWindowPoints(hwnd, HWND_DESKTOP, &ptlWork, 1);
+
+			hpsTemp = WinGetPS(hwndBubble);
+			GpiQueryTextBox(hpsTemp,
+							strlen(bubble->bubbletext),
+							bubble->bubbletext,
+							TXTBOX_COUNT,
+							txtPointl);
+			WinReleasePS(hpsTemp);
+
+			lWidth = txtPointl[TXTBOX_TOPRIGHT].x -
+				txtPointl[TXTBOX_TOPLEFT ].x + 8;
+
+			lHight = txtPointl[TXTBOX_TOPLEFT].y -
+				txtPointl[TXTBOX_BOTTOMLEFT].y + 8;
+
+			ptlWork.y -= lHight;
+
+			blah = (void *)WinSubclassWindow(hwndBubble, _BubbleProc);
+
+			if(blah)
+				WinSetWindowPtr(hwndBubble, QWP_USER, blah);
+
+			WinSetWindowPos(hwndBubble,
+							HWND_TOP,
+							ptlWork.x,
+							ptlWork.y,
+							lWidth,
+							lHight,
+							SWP_SIZE | SWP_MOVE | SWP_SHOW);
+		}
+		break;
+	}
+
+	if(!oldproc)
+		return WinDefWindowProc(hwnd, msg, mp1, mp2);
+	return oldproc(hwnd, msg, mp1, mp2);
+}
+
+MRESULT EXPENTRY _RendProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+	int res = 0;
+	res = (int)_run_event(hwnd, msg, mp1, mp2);
+	switch(msg)
+	{
+	case WM_MOUSEMOVE:
+		if(_wndproc(hwnd, msg, mp1, mp2))
+			return MPFROMSHORT(FALSE);
+		break;
+	case WM_BUTTON1DOWN:
+	case WM_BUTTON2DOWN:
+	case WM_BUTTON3DOWN:
+		if(res == -1)
+			WinSetFocus(HWND_DESKTOP, hwnd);
+		else if(res)
+			return (MPARAM)TRUE;
+	}
+	return WinDefWindowProc(hwnd, msg, mp1, mp2);
+}
+
+MRESULT EXPENTRY _TreeProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+	WindowData *blah = (WindowData *)WinQueryWindowPtr(hwnd, QWP_USER);
+	PFNWP oldproc = 0;
+
+	if(blah)
+		oldproc = blah->oldproc;
+
+	switch(msg)
+	{
+	case WM_MOUSEMOVE:
+		if(_wndproc(hwnd, msg, mp1, mp2))
+			return MPFROMSHORT(FALSE);
+		break;
+	case WM_PAINT:
+		{
+			HPS hps;
+			RECTL rcl;
+			POINTL ptl[2];
+
+			if(oldproc)
+				oldproc(hwnd, msg, mp1, mp2);
+
+			hps = WinBeginPaint(hwnd, 0, 0);
+			WinQueryWindowRect(hwnd, &rcl);
+			ptl[0].x = rcl.xLeft + 1;
+			ptl[0].y = rcl.yBottom + 1;
+			ptl[1].x = rcl.xRight - 1;
+			ptl[1].y = rcl.yTop - 1;
+
+			GpiSetColor(hps, CLR_BLACK);
+			GpiMove(hps, &ptl[0]);
+			GpiBox(hps, DRO_OUTLINE, &ptl[1], 0, 0);
+			WinEndPaint(hps);
+		}
+		return MRFROMSHORT(FALSE);
+	case WM_SETFOCUS:
+		_run_event(hwnd, msg, mp1, mp2);
+		break;
+	case WM_CHAR:
+		if(SHORT1FROMMP(mp2) == '\t')
+		{
+			if(CHARMSG(&msg)->fs & KC_SHIFT)
+				_shift_focus_back(hwnd);
+			else
+				_shift_focus(hwnd);
+			return FALSE;
+		}
+		break;
+	}
+
+	_run_event(hwnd, msg, mp1, mp2);
+
+	if(oldproc)
+		return oldproc(hwnd, msg, mp1, mp2);
+
+	return WinDefWindowProc(hwnd, msg, mp1, mp2);
+}
+
+/*
+ * Initializes the Dynamic Windows engine.
+ * Parameters:
+ *           newthread: True if this is the only thread.
+ *                      False if there is already a message loop running.
+ */
+int API dw_init(int newthread, int argc, char *argv[])
+{
+	APIRET rc;
+	char objnamebuf[300] = "";
+
+	argc = argc; /* keep compiler happy */
+	argv = argv; /* keep compiler happy */
+	if(newthread)
+	{
+		dwhab = WinInitialize(0);
+		dwhmq = WinCreateMsgQueue(dwhab, 0);
+	}
+
+	rc = WinRegisterClass(dwhab, ClassName, _wndproc, CS_SIZEREDRAW | CS_CLIPCHILDREN, 32);
+	rc = WinRegisterClass(dwhab, SplitbarClassName, _splitwndproc, 0L, 32);
+
+	/* Get the OS/2 version. */
+	DosQuerySysInfo(QSV_VERSION_MAJOR, QSV_MS_COUNT,(void *)aulBuffer, 4*sizeof(ULONG));
+
+	desktop = WinQueryDesktopWindow(dwhab, NULLHANDLE);
+
+	if(!IS_WARP4())
+		DefaultFont = "8.Helv";
+
+	/* This is a window that hangs around as long as the
+	 * application does and handles menu messages.
+	 */
+	hwndApp = dw_window_new(HWND_OBJECT, "", 0);
+	DosLoadModule(objnamebuf, sizeof(objnamebuf), "WPCONFIG", &wpconfig);
+
+	return rc;
+}
+
+/*
+ * Runs a message loop for Dynamic Windows.
+ */
+void API dw_main(void)
+{
+	QMSG qmsg;
+
+	_dwtid = dw_thread_id();
+
+	while(WinGetMsg(dwhab, &qmsg, 0, 0, 0))
+	{
+		if(qmsg.msg == WM_TIMER && qmsg.hwnd == NULLHANDLE)
+			_run_event(qmsg.hwnd, qmsg.msg, qmsg.mp1, qmsg.mp2);
+		WinDispatchMsg(dwhab, &qmsg);
+	}
+
+	WinDestroyMsgQueue(dwhmq);
+	WinTerminate(dwhab);
+}
+
+/*
+ * Runs a message loop for Dynamic Windows, for a period of milliseconds.
+ * Parameters:
+ *           milliseconds: Number of milliseconds to run the loop for.
+ */
+void API dw_main_sleep(int milliseconds)
+{
+	QMSG qmsg;
+#ifdef __EMX__
+	struct timeval tv, start;
+
+	gettimeofday(&start, NULL);
+	gettimeofday(&tv, NULL);
+
+	while(((tv.tv_sec - start.tv_sec)*1000) + ((tv.tv_usec - start.tv_usec)/1000) <= milliseconds)
+	{
+		if(WinPeekMsg(dwhab, &qmsg, 0, 0, 0, PM_NOREMOVE))
+		{
+			WinGetMsg(dwhab, &qmsg, 0, 0, 0);
+			if(qmsg.msg == WM_TIMER && qmsg.hwnd == NULLHANDLE)
+				_run_event(qmsg.hwnd, qmsg.msg, qmsg.mp1, qmsg.mp2);
+			WinDispatchMsg(dwhab, &qmsg);
+		}
+		else
+			DosSleep(1);
+		gettimeofday(&tv, NULL);
+	}
+#else
+	double start = (double)clock();
+
+	while(((clock() - start) / (CLOCKS_PER_SEC/1000)) <= milliseconds)
+	{
+		if(WinPeekMsg(dwhab, &qmsg, 0, 0, 0, PM_NOREMOVE))
+		{
+			WinGetMsg(dwhab, &qmsg, 0, 0, 0);
+			if(qmsg.msg == WM_TIMER && qmsg.hwnd == NULLHANDLE)
+				_run_event(qmsg.hwnd, qmsg.msg, qmsg.mp1, qmsg.mp2);
+			WinDispatchMsg(dwhab, &qmsg);
+		}
+		else
+			DosSleep(1);
+	}
+#endif
+}
+
+/*
+ * Processes a single message iteration and returns.
+ */
+void API dw_main_iteration(void)
+{
+	QMSG qmsg;
+
+	_dwtid = dw_thread_id();
+
+	if(WinGetMsg(dwhab, &qmsg, 0, 0, 0))
+	{
+		if(qmsg.msg == WM_TIMER && qmsg.hwnd == NULLHANDLE)
+			_run_event(qmsg.hwnd, qmsg.msg, qmsg.mp1, qmsg.mp2);
+		WinDispatchMsg(dwhab, &qmsg);
+	}
+}
+
+/*
+ * Free's memory allocated by dynamic windows.
+ * Parameters:
+ *           ptr: Pointer to dynamic windows allocated
+ *                memory to be free()'d.
+ */
+void API dw_free(void *ptr)
+{
+	free(ptr);
+}
+
+/*
+ * Allocates and initializes a dialog struct.
+ * Parameters:
+ *           data: User defined data to be passed to functions.
+ */
+DWDialog * API dw_dialog_new(void *data)
+{
+	DWDialog *tmp = malloc(sizeof(DWDialog));
+
+	tmp->eve = dw_event_new();
+	dw_event_reset(tmp->eve);
+	tmp->data = data;
+	tmp->done = FALSE;
+	tmp->result = NULL;
+
+    return tmp;
+}
+
+/*
+ * Accepts a dialog struct and returns the given data to the
+ * initial called of dw_dialog_wait().
+ * Parameters:
+ *           dialog: Pointer to a dialog struct aquired by dw_dialog_new).
+ *           result: Data to be returned by dw_dialog_wait().
+ */
+int API dw_dialog_dismiss(DWDialog *dialog, void *result)
+{
+	dialog->result = result;
+	dw_event_post(dialog->eve);
+	dialog->done = TRUE;
+	return 0;
+}
+
+/*
+ * Accepts a dialog struct waits for dw_dialog_dismiss() to be
+ * called by a signal handler with the given dialog struct.
+ * Parameters:
+ *           dialog: Pointer to a dialog struct aquired by dw_dialog_new).
+ */
+void * API dw_dialog_wait(DWDialog *dialog)
+{
+	QMSG qmsg;
+	void *tmp;
+
+	while (WinGetMsg(dwhab, &qmsg, 0, 0, 0))
+	{
+		if(qmsg.msg == WM_TIMER && qmsg.hwnd == NULLHANDLE)
+			_run_event(qmsg.hwnd, qmsg.msg, qmsg.mp1, qmsg.mp2);
+		WinDispatchMsg(dwhab, &qmsg);
+		if(dialog->done)
+			break;
+	}
+	dw_event_close(&dialog->eve);
+	tmp = dialog->result;
+	free(dialog);
+	return tmp;
+}
+
+
+/*
+ * Displays a Message Box with given text and title..
+ * Parameters:
+ *           title: The title of the message box.
+ *           flags: flags to indicate buttons and icon
+ *           format: printf style format string.
+ *           ...: Additional variables for use in the format.
+ */
+int API dw_messagebox(char *title, int flags, char *format, ...)
+{
+	va_list args;
+	char outbuf[1024];
+	int rc;
+
+	va_start(args, format);
+	vsprintf(outbuf, format, args);
+	va_end(args);
+
+	rc = WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, outbuf, title, 0, flags | MB_MOVEABLE);
+	if(rc == MBID_OK)
+		return DW_MB_RETURN_OK;
+	else if(rc == MBID_YES)
+		return DW_MB_RETURN_YES;
+	else if(rc == MBID_NO)
+		return DW_MB_RETURN_NO;
+	else if(rc == MBID_CANCEL)
+		return DW_MB_RETURN_CANCEL;
+	else return 0;
+}
+
+/*
+ * Makes the window topmost.
+ * Parameters:
+ *           handle: The window handle to make topmost.
+ */
+int API dw_window_raise(HWND handle)
+{
+	return WinSetWindowPos(handle, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER);
+}
+
+/*
+ * Makes the window bottommost.
+ * Parameters:
+ *           handle: The window handle to make bottommost.
+ */
+int API dw_window_lower(HWND handle)
+{
+	return WinSetWindowPos(handle, HWND_BOTTOM, 0, 0, 0, 0, SWP_ZORDER);
+}
+
+/*
+ * Makes the window visible.
+ * Parameters:
+ *           handle: The window handle to make visible.
+ */
+int API dw_window_show(HWND handle)
+{
+	int rc = WinSetWindowPos(handle, NULLHANDLE, 0, 0, 0, 0, SWP_SHOW);
+	HSWITCH hswitch;
+	SWCNTRL swcntrl;
+
+	_fix_button_owner(_toplevel_window(handle), 0);
+	WinSetFocus(HWND_DESKTOP, handle);
+	_initial_focus(handle);
+
+	/* If this window has a  switch list entry make sure it is visible */
+	hswitch = WinQuerySwitchHandle(handle, 0);
+	if(hswitch)
+	{
+		WinQuerySwitchEntry(hswitch, &swcntrl);
+		swcntrl.uchVisibility = SWL_VISIBLE;
+		WinChangeSwitchEntry(hswitch, &swcntrl);
+	}
+	if(WinWindowFromID(handle, FID_CLIENT))
+	{
+		WindowData *blah = WinQueryWindowPtr(handle, QWP_USER);
+
+		if(blah && !(blah->flags & DW_OS2_NEW_WINDOW))
+		{
+			ULONG cx = dw_screen_width(), cy = dw_screen_height();
+			int newx, newy, changed = 0;
+			SWP swp;
+
+			blah->flags |= DW_OS2_NEW_WINDOW;
+
+			WinQueryWindowPos(handle, &swp);
+
+			newx = swp.x;
+			newy = swp.y;
+
+			if((swp.x+swp.cx) > cx)
+			{
+				newx = (cx - swp.cx)/2;
+				changed = 1;
+			}
+			if((swp.y+swp.cy) > cy)
+			{
+				newy = (cy - swp.cy)/2;
+				changed = 1;
+			}
+			if(changed)
+				WinSetWindowPos(handle, NULLHANDLE, newx, newy, 0, 0, SWP_MOVE);
+		}
+	}
+	return rc;
+}
+
+/*
+ * Minimizes or Iconifies a top-level window.
+ * Parameters:
+ *           handle: The window handle to minimize.
+ */
+int API dw_window_minimize(HWND handle)
+{
+	HWND hwndclient = WinWindowFromID(handle, FID_CLIENT);
+
+	if(hwndclient)
+	{
+		Box *box = (Box *)WinQueryWindowPtr(hwndclient, QWP_USER);
+
+		if(box)
+		{
+			if(!box->titlebar && box->hwndtitle)
+				WinSetParent(box->hwndtitle, handle, FALSE);
+		}
+	}
+
+	return WinSetWindowPos(handle, NULLHANDLE, 0, 0, 0, 0, SWP_MINIMIZE);
+}
+
+/*
+ * Makes the window invisible.
+ * Parameters:
+ *           handle: The window handle to make visible.
+ */
+int API dw_window_hide(HWND handle)
+{
+	HSWITCH hswitch;
+	SWCNTRL swcntrl;
+
+	/* If this window has a  switch list entry make sure it is invisible */
+	hswitch = WinQuerySwitchHandle(handle, 0);
+	if(hswitch)
+	{
+		WinQuerySwitchEntry(hswitch, &swcntrl);
+		swcntrl.uchVisibility = SWL_INVISIBLE;
+		WinChangeSwitchEntry(hswitch, &swcntrl);
+	}
+	return WinShowWindow(handle, FALSE);
+}
+
+/*
+ * Destroys a window and all of it's children.
+ * Parameters:
+ *           handle: The window handle to destroy.
+ */
+int API dw_window_destroy(HWND handle)
+{
+	HWND frame, menu, parent = WinQueryWindow(handle, QW_PARENT);
+	Box *thisbox = WinQueryWindowPtr(parent, QWP_USER);
+
+	if(!handle)
+		return -1;
+
+	frame = (HWND)dw_window_get_data(handle, "_dw_combo_box");
+
+	if((menu = WinWindowFromID(handle, FID_MENU)) != NULLHANDLE)
+		_free_menu_data(menu);
+
+	if(parent != desktop && thisbox && thisbox->count)
+	{
+		int z, index = -1;
+		Item *tmpitem, *thisitem = thisbox->items;
+
+		for(z=0;z<thisbox->count;z++)
+		{
+			if(thisitem[z].hwnd == handle)
+				index = z;
+		}
+
+		if(index == -1)
+			return 0;
+
+		tmpitem = malloc(sizeof(Item)*(thisbox->count-1));
+
+		/* Copy all but the current entry to the new list */
+		for(z=0;z<index;z++)
+		{
+			tmpitem[z] = thisitem[z];
+		}
+		for(z=index+1;z<thisbox->count;z++)
+		{
+			tmpitem[z-1] = thisitem[z];
+		}
+
+		thisbox->items = tmpitem;
+		free(thisitem);
+		thisbox->count--;
+		_free_window_memory(frame ? frame : handle);
+	}
+	return WinDestroyWindow(frame ? frame : handle);
+}
+
+/* Causes entire window to be invalidated and redrawn.
+ * Parameters:
+ *           handle: Toplevel window handle to be redrawn.
+ */
+void API dw_window_redraw(HWND handle)
+{
+	HWND client = WinWindowFromID(handle, FID_CLIENT);
+	HWND window = client ? client : handle;
+	Box *mybox = (Box *)WinQueryWindowPtr(window, QWP_USER);
+
+	_fix_button_owner(_toplevel_window(handle), 0);
+	if(window && mybox)
+	{
+		unsigned long width, height;
+
+		dw_window_get_pos_size(window, NULL, NULL, &width, &height);
+
+		WinShowWindow(client ? mybox->items[0].hwnd : handle, FALSE);
+		_do_resize(mybox, width, height);
+		WinShowWindow(client ? mybox->items[0].hwnd : handle, TRUE);
+	}
+}
+
+/*
+ * Changes a window's parent to newparent.
+ * Parameters:
+ *           handle: The window handle to destroy.
+ *           newparent: The window's new parent window.
+ */
+void API dw_window_reparent(HWND handle, HWND newparent)
+{
+	HWND blah = WinWindowFromID(newparent, FID_CLIENT);
+	WinSetParent(handle, blah ? blah : newparent, TRUE);
+}
+
+/*
+ * Sets the font used by a specified window (widget) handle.
+ * Parameters:
+ *          handle: The window (widget) handle.
+ *          fontname: Name and size of the font in the form "size.fontname"
+ */
+int API dw_window_set_font(HWND handle, char *fontname)
+{
+	return WinSetPresParam(handle, PP_FONTNAMESIZE, strlen(fontname)+1, fontname);
+}
+
+/* Internal version */
+int _dw_window_set_color(HWND handle, ULONG fore, ULONG back)
+{
+	if((fore & DW_RGB_COLOR) == DW_RGB_COLOR)
+	{
+		RGB2 rgb2;
+
+		rgb2.bBlue = DW_BLUE_VALUE(fore);
+		rgb2.bGreen = DW_GREEN_VALUE(fore);
+		rgb2.bRed = DW_RED_VALUE(fore);
+		rgb2.fcOptions = 0;
+
+		WinSetPresParam(handle, PP_FOREGROUNDCOLOR, sizeof(RGB2), &rgb2);
+
+	}
+	else if(fore != DW_CLR_DEFAULT)
+	{
+		fore = _internal_color(fore);
+
+		WinSetPresParam(handle, PP_FOREGROUNDCOLORINDEX, sizeof(ULONG), &fore);
+	}
+	if((back & DW_RGB_COLOR) == DW_RGB_COLOR)
+	{
+		RGB2 rgb2;
+
+		rgb2.bBlue = DW_BLUE_VALUE(back);
+		rgb2.bGreen = DW_GREEN_VALUE(back);
+		rgb2.bRed = DW_RED_VALUE(back);
+		rgb2.fcOptions = 0;
+
+		WinSetPresParam(handle, PP_BACKGROUNDCOLOR, sizeof(RGB2), &rgb2);
+		return 0;
+	}
+	else if(back != DW_CLR_DEFAULT)
+	{
+		back = _internal_color(back);
+
+		WinSetPresParam(handle, PP_BACKGROUNDCOLORINDEX, sizeof(ULONG), &back);
+	}
+	return 0;
+}
+/*
+ * Sets the colors used by a specified window (widget) handle.
+ * Parameters:
+ *          handle: The window (widget) handle.
+ *          fore: Foreground color in DW_RGB format or a default color index.
+ *          back: Background color in DW_RGB format or a default color index.
+ */
+int API dw_window_set_color(HWND handle, ULONG fore, ULONG back)
+{
+	dw_window_set_data(handle, "_dw_fore", (void *)(fore+1));
+	dw_window_set_data(handle, "_dw_back", (void *)(back+1));
+
+	return _dw_window_set_color(handle, fore, back);
+}
+
+/*
+ * Sets the font used by a specified window (widget) handle.
+ * Parameters:
+ *          handle: The window (widget) handle.
+ *          border: Size of the window border in pixels.
+ */
+int API dw_window_set_border(HWND handle, int border)
+{
+	WinSendMsg(handle, WM_SETBORDERSIZE, MPFROMSHORT(border), MPFROMSHORT(border));
+	return 0;
+}
+
+/*
+ * Captures the mouse input to this window.
+ * Parameters:
+ *       handle: Handle to receive mouse input.
+ */
+void API dw_window_capture(HWND handle)
+{
+	WinSetCapture(HWND_DESKTOP, handle);
+}
+
+/*
+ * Releases previous mouse capture.
+ */
+void API dw_window_release(void)
+{
+	WinSetCapture(HWND_DESKTOP, NULLHANDLE);
+}
+
+/*
+ * Tracks this window movement.
+ * Parameters:
+ *       handle: Handle to frame to be tracked.
+ */
+void API dw_window_track(HWND handle)
+{
+	WinSendMsg(handle, WM_TRACKFRAME, MPFROMSHORT(TF_MOVE), 0);
+}
+
+/*
+ * Changes the appearance of the mouse pointer.
+ * Parameters:
+ *       handle: Handle to widget for which to change.
+ *       cursortype: ID of the pointer you want.
+ */
+void API dw_window_set_pointer(HWND handle, int pointertype)
+{
+	HPOINTER pointer = pointertype < 65535 ?
+		WinQuerySysPointer(HWND_DESKTOP, pointertype, FALSE)
+		: (HPOINTER)pointertype;
+
+	if(!pointertype)
+		dw_window_set_data(handle, "_dw_pointer", 0);
+	else
+	{
+		WinSetPointer(HWND_DESKTOP, pointer);
+
+		if(handle != HWND_DESKTOP)
+			dw_window_set_data(handle, "_dw_pointer", (void *)pointer);
+	}
+}
+
+/*
+ * Create a new Window Frame.
+ * Parameters:
+ *       owner: The Owner's window handle or HWND_DESKTOP.
+ *       title: The Window title.
+ *       flStyle: Style flags, see the PM reference.
+ */
+HWND API dw_window_new(HWND hwndOwner, char *title, ULONG flStyle)
+{
+	HWND hwndframe;
+	Box *newbox = calloc(1, sizeof(Box));
+	WindowData *blah = calloc(1, sizeof(WindowData));
+	ULONG winStyle = 0L;
+
+	newbox->pad = 0;
+	newbox->type = DW_VERT;
+	newbox->count = 0;
+
+	flStyle |= FCF_NOBYTEALIGN;
+
+	if(flStyle & DW_FCF_TITLEBAR)
+		newbox->titlebar = 1;
+	else
+		flStyle |= FCF_TITLEBAR;
+
+	if(!(flStyle & FCF_SHELLPOSITION))
+		blah->flags |= DW_OS2_NEW_WINDOW;
+
+	if(flStyle & WS_MAXIMIZED)
+	{
+		winStyle |= WS_MAXIMIZED;
+		flStyle &= ~WS_MAXIMIZED;
+	}
+	if(flStyle & WS_MINIMIZED)
+	{
+		winStyle |= WS_MINIMIZED;
+		flStyle &= ~WS_MINIMIZED;
+	}
+
+	hwndframe = WinCreateStdWindow(hwndOwner, winStyle, &flStyle, ClassName, title, 0L, NULLHANDLE, 0L, &newbox->hwnd);
+	newbox->hwndtitle = WinWindowFromID(hwndframe, FID_TITLEBAR);
+	if(!newbox->titlebar && newbox->hwndtitle)
+		WinSetParent(newbox->hwndtitle, HWND_OBJECT, FALSE);
+	blah->oldproc = WinSubclassWindow(hwndframe, _sizeproc);
+	WinSetWindowPtr(hwndframe, QWP_USER, blah);
+	WinSetWindowPtr(newbox->hwnd, QWP_USER, newbox);
+
+	return hwndframe;
+}
+
+/*
+ * Create a new Box to be packed.
+ * Parameters:
+ *       type: Either DW_VERT (vertical) or DW_HORZ (horizontal).
+ *       pad: Number of pixels to pad around the box.
+ */
+HWND API dw_box_new(int type, int pad)
+{
+	Box *newbox = calloc(1, sizeof(Box));
+
+	newbox->pad = pad;
+	newbox->type = type;
+	newbox->count = 0;
+    newbox->grouphwnd = NULLHANDLE;
+
+	newbox->hwnd = WinCreateWindow(HWND_OBJECT,
+								   WC_FRAME,
+								   NULL,
+								   WS_VISIBLE | WS_CLIPCHILDREN |
+								   FS_NOBYTEALIGN,
+								   0,0,2000,1000,
+								   NULLHANDLE,
+								   HWND_TOP,
+								   0L,
+								   NULL,
+								   NULL);
+
+	newbox->oldproc = WinSubclassWindow(newbox->hwnd, _controlproc);
+	WinSetWindowPtr(newbox->hwnd, QWP_USER, newbox);
+	dw_window_set_color(newbox->hwnd, DW_CLR_PALEGRAY, DW_CLR_PALEGRAY);
+	return newbox->hwnd;
+}
+
+/*
+ * Create a new Group Box to be packed.
+ * Parameters:
+ *       type: Either DW_VERT (vertical) or DW_HORZ (horizontal).
+ *       pad: Number of pixels to pad around the box.
+ *       title: Text to be displayined in the group outline.
+ */
+HWND API dw_groupbox_new(int type, int pad, char *title)
+{
+	Box *newbox = calloc(1, sizeof(Box));
+	newbox->pad = pad;
+	newbox->type = type;
+	newbox->count = 0;
+
+	newbox->hwnd = WinCreateWindow(HWND_OBJECT,
+								   WC_FRAME,
+								   NULL,
+								   WS_VISIBLE |
+								   FS_NOBYTEALIGN,
+								   0,0,2000,1000,
+								   NULLHANDLE,
+								   HWND_TOP,
+								   0L,
+								   NULL,
+								   NULL);
+
+	newbox->grouphwnd = WinCreateWindow(newbox->hwnd,
+										WC_STATIC,
+										title,
+										WS_VISIBLE | SS_GROUPBOX |
+										WS_GROUP,
+										0,0,2000,1000,
+										NULLHANDLE,
+										HWND_TOP,
+										0L,
+										NULL,
+										NULL);
+
+	WinSetWindowPtr(newbox->hwnd, QWP_USER, newbox);
+	dw_window_set_color(newbox->hwnd, DW_CLR_PALEGRAY, DW_CLR_PALEGRAY);
+	dw_window_set_color(newbox->grouphwnd, DW_CLR_BLACK, DW_CLR_PALEGRAY);
+	dw_window_set_font(newbox->grouphwnd, DefaultFont);
+	return newbox->hwnd;
+}
+
+/*
+ * Create a new MDI Frame to be packed.
+ * Parameters:
+ *       id: An ID to be used with dw_window_from_id or 0L.
+ */
+HWND API dw_mdi_new(unsigned long id)
+{
+	HWND hwndframe;
+	ULONG back = CLR_DARKGRAY;
+
+	hwndframe = WinCreateWindow(HWND_OBJECT,
+								WC_FRAME,
+								NULL,
+								WS_VISIBLE | WS_CLIPCHILDREN |
+								FS_NOBYTEALIGN,
+								0,0,2000,1000,
+								NULLHANDLE,
+								HWND_TOP,
+								id,
+								NULL,
+								NULL);
+	/* Make the MDI Client area the same color as Windows and Unix */
+	WinSetPresParam(hwndframe, PP_BACKGROUNDCOLORINDEX, sizeof(ULONG), &back);
+	return hwndframe;
+}
+
+/*
+ * Create a bitmap object to be packed.
+ * Parameters:
+ *       id: An ID to be used with dw_window_from_id() or 0L.
+ */
+HWND API dw_bitmap_new(ULONG id)
+{
+	return WinCreateWindow(HWND_OBJECT,
+						   WC_STATIC,
+						   NULL,
+						   WS_VISIBLE | SS_TEXT,
+						   0,0,2000,1000,
+						   NULLHANDLE,
+						   HWND_TOP,
+						   id,
+						   NULL,
+						   NULL);
+}
+
+/*
+ * Create a notebook object to be packed.
+ * Parameters:
+ *       id: An ID to be used for getting the resource from the
+ *           resource file.
+ */
+HWND API dw_notebook_new(ULONG id, int top)
+{
+	ULONG flags;
+	HWND tmp;
+
+	if(top)
+		flags = BKS_MAJORTABTOP;
+	else
+		flags = BKS_MAJORTABBOTTOM;
+
+	tmp = WinCreateWindow(HWND_OBJECT,
+						  WC_NOTEBOOK,
+						  NULL,
+						  WS_VISIBLE |
+#ifdef BKS_TABBEDDIALOG
+						  BKS_TABBEDDIALOG |
+#endif
+						  flags,
+						  0,0,2000,1000,
+						  NULLHANDLE,
+						  HWND_TOP,
+						  id,
+						  NULL,
+						  NULL);
+
+	/* Fix tab sizes on Warp 3 */
+	if(!IS_WARP4())
+	{
+		/* best sizes to be determined by trial and error */
+		WinSendMsg(tmp, BKM_SETDIMENSIONS,MPFROM2SHORT(102, 28), MPFROMSHORT( BKA_MAJORTAB));
+	}
+
+	dw_window_set_font(tmp, DefaultFont);
+	return tmp;
+}
+
+/*
+ * Create a menu object to be popped up.
+ * Parameters:
+ *       id: An ID to be used for getting the resource from the
+ *           resource file.
+ */
+HMENUI API dw_menu_new(ULONG id)
+{
+	HMENUI tmp = WinCreateWindow(HWND_OBJECT,
+								 WC_MENU,
+								 NULL,
+								 WS_VISIBLE,
+								 0,0,2000,1000,
+								 NULLHANDLE,
+								 HWND_TOP,
+								 id,
+								 NULL,
+								 NULL);
+	return tmp;
+}
+
+/*
+ * Create a menubar on a window.
+ * Parameters:
+ *       location: Handle of a window frame to be attached to.
+ */
+HMENUI API dw_menubar_new(HWND location)
+{
+	HMENUI tmp = WinCreateWindow(location,
+								 WC_MENU,
+								 NULL,
+								 WS_VISIBLE | MS_ACTIONBAR,
+								 0,0,2000,1000,
+								 location,
+								 HWND_TOP,
+								 FID_MENU,
+								 NULL,
+								 NULL);
+	dw_window_set_data(tmp, "_dw_owner", (void *)location);
+	dw_window_set_data(tmp, "_dw_menubar", (void *)location);
+	return tmp;
+}
+
+/*
+ * Destroys a menu created with dw_menubar_new or dw_menu_new.
+ * Parameters:
+ *       menu: Handle of a menu.
+ */
+void API dw_menu_destroy(HMENUI *menu)
+{
+	if(menu)
+		WinDestroyWindow(*menu);
+}
+
+/*
+ * Adds a menuitem or submenu to an existing menu.
+ * Parameters:
+ *       menu: The handle the the existing menu.
+ *       title: The title text on the menu item to be added.
+ *       id: An ID to be used for message passing.
+ *       flags: Extended attributes to set on the menu.
+ *       end: If TRUE memu is positioned at the end of the menu.
+ *       check: If TRUE menu is "check"able.
+ *       submenu: Handle to an existing menu to be a submenu or NULL.
+ */
+HWND API dw_menu_append_item(HMENUI menux, char *title, ULONG id, ULONG flags, int end, int check, HMENUI submenu)
+{
+	MENUITEM miSubMenu;
+	char buffer[15];
+
+	check = check; /* keep compiler happy */
+	if(!menux || id > 65536)
+		return NULLHANDLE;
+
+	if(end)
+		miSubMenu.iPosition=MIT_END;
+	else
+		miSubMenu.iPosition=0;
+
+	if(strlen(title) == 0)
+		miSubMenu.afStyle=MIS_SEPARATOR | flags;
+	else
+		miSubMenu.afStyle=MIS_TEXT | flags;
+	miSubMenu.afAttribute=0;
+	miSubMenu.id=id;
+	miSubMenu.hwndSubMenu = submenu;
+	miSubMenu.hItem=NULLHANDLE;
+
+	WinSendMsg(menux,
+			   MM_INSERTITEM,
+			   MPFROMP(&miSubMenu),
+			   MPFROMP(title));
+
+	sprintf(buffer, "_dw_id%d", (int)id);
+	dw_window_set_data(hwndApp, buffer, (void *)menux);
+
+	if(submenu)
+		dw_window_set_data(submenu, "_dw_owner", (void *)menux);
+	return (HWND)id;
+}
+
+/*
+ * Sets the state of a menu item check.
+ * Parameters:
+ *       menu: The handle the the existing menu.
+ *       id: Menuitem id.
+ *       check: TRUE for checked FALSE for not checked.
+ */
+void API dw_menu_item_set_check(HMENUI menux, unsigned long id, int check)
+{
+	if(check)
+		WinSendMsg(menux, MM_SETITEMATTR, MPFROM2SHORT(id, TRUE),
+				   MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED));
+	else
+		WinSendMsg(menux, MM_SETITEMATTR, MPFROM2SHORT(id, TRUE),
+				   MPFROM2SHORT(MIA_CHECKED, 0));
+}
+
+/*
+ * Pops up a context menu at given x and y coordinates.
+ * Parameters:
+ *       menu: The handle the the existing menu.
+ *       parent: Handle to the window initiating the popup.
+ *       x: X coordinate.
+ *       y: Y coordinate.
+ */
+void API dw_menu_popup(HMENUI *menu, HWND parent, int x, int y)
+{
+	if(menu)
+	{
+		popup = parent;
+		dw_window_set_data(*menu, "_dw_popup", (void *)1);
+		WinPopupMenu(HWND_DESKTOP, parent, *menu, x, dw_screen_height() - y, 0, PU_KEYBOARD | PU_MOUSEBUTTON1 | PU_VCONSTRAIN | PU_HCONSTRAIN);
+	}
+}
+
+/*
+ * Returns the current X and Y coordinates of the mouse pointer.
+ * Parameters:
+ *       x: Pointer to variable to store X coordinate.
+ *       y: Pointer to variable to store Y coordinate.
+ */
+void API dw_pointer_query_pos(long *x, long *y)
+{
+	POINTL ptl;
+
+	WinQueryPointerPos(HWND_DESKTOP, &ptl);
+	if(x && y)
+	{
+		*x = ptl.x;
+		*y = dw_screen_height() - ptl.y;
+	}
+}
+
+/*
+ * Sets the X and Y coordinates of the mouse pointer.
+ * Parameters:
+ *       x: X coordinate.
+ *       y: Y coordinate.
+ */
+void API dw_pointer_set_pos(long x, long y)
+{
+	WinSetPointerPos(HWND_DESKTOP, x, dw_screen_height() - y);
+}
+
+
+/*
+ * Create a container object to be packed.
+ * Parameters:
+ *       id: An ID to be used for getting the resource from the
+ *           resource file.
+ */
+HWND API dw_container_new(ULONG id, int multi)
+{
+	WindowData *blah = calloc(1, sizeof(WindowData));
+	HWND tmp = WinCreateWindow(HWND_OBJECT,
+							   WC_CONTAINER,
+							   NULL,
+							   WS_VISIBLE | CCS_READONLY |
+							   (multi ? CCS_EXTENDSEL : CCS_SINGLESEL) |
+							   CCS_AUTOPOSITION,
+							   0,0,2000,1000,
+							   NULLHANDLE,
+							   HWND_TOP,
+							   id ? id : (GlobalID++),
+							   NULL,
+							   NULL);
+	blah->oldproc = WinSubclassWindow(tmp, _TreeProc);
+	WinSetWindowPtr(tmp, QWP_USER, blah);
+	dw_window_set_font(tmp, DefaultFont);
+	dw_window_set_data(tmp, "_dw_container", (void *)1);
+	return tmp;
+}
+
+/*
+ * Create a tree object to be packed.
+ * Parameters:
+ *       id: An ID to be used for getting the resource from the
+ *           resource file.
+ */
+HWND API dw_tree_new(ULONG id)
+{
+	CNRINFO cnrinfo;
+	WindowData *blah = calloc(1, sizeof(WindowData));
+	HWND tmp = WinCreateWindow(HWND_OBJECT,
+							   WC_CONTAINER,
+							   NULL,
+							   WS_VISIBLE | CCS_READONLY |
+							   CCS_SINGLESEL | CCS_AUTOPOSITION,
+							   0,0,2000,1000,
+							   NULLHANDLE,
+							   HWND_TOP,
+							   id ? id : (GlobalID++),
+							   NULL,
+							   NULL);
+
+	cnrinfo.flWindowAttr = CV_TREE | CA_TREELINE;
+	cnrinfo.slBitmapOrIcon.cx = 16;
+	cnrinfo.slBitmapOrIcon.cy = 16;
+	cnrinfo.cyLineSpacing = 0;
+	cnrinfo.cxTreeIndent = 16;
+	cnrinfo.cxTreeLine = 1;
+
+	WinSendMsg(tmp, CM_SETCNRINFO, &cnrinfo, MPFROMLONG(CMA_FLWINDOWATTR | CMA_SLBITMAPORICON |
+														CMA_LINESPACING | CMA_CXTREEINDENT | CMA_CXTREELINE));
+	blah->oldproc = WinSubclassWindow(tmp, _TreeProc);
+	WinSetWindowPtr(tmp, QWP_USER, blah);
+	dw_window_set_font(tmp, DefaultFont);
+	return tmp;
+}
+
+/*
+ * Create a new static text window (widget) to be packed.
+ * Parameters:
+ *       text: The text to be display by the static text widget.
+ *       id: An ID to be used with dw_window_from_id() or 0L.
+ */
+HWND API dw_text_new(char *text, ULONG id)
+{
+	WindowData *blah = calloc(sizeof(WindowData), 1);
+	HWND tmp = WinCreateWindow(HWND_OBJECT,
+							   WC_STATIC,
+							   text,
+							   WS_VISIBLE | SS_TEXT,
+							   0,0,2000,1000,
+							   NULLHANDLE,
+							   HWND_TOP,
+							   id,
+							   NULL,
+							   NULL);
+	blah->oldproc = WinSubclassWindow(tmp, _textproc);
+	WinSetWindowPtr(tmp, QWP_USER, blah);
+	dw_window_set_font(tmp, DefaultFont);
+	dw_window_set_color(tmp, DW_CLR_BLACK, DW_CLR_PALEGRAY);
+	return tmp;
+}
+
+/*
+ * Create a new status text window (widget) to be packed.
+ * Parameters:
+ *       text: The text to be display by the static text widget.
+ *       id: An ID to be used with dw_window_from_id() or 0L.
+ */
+HWND API dw_status_text_new(char *text, ULONG id)
+{
+	WindowData *blah = calloc(sizeof(WindowData), 1);
+	HWND tmp = WinCreateWindow(HWND_OBJECT,
+							   WC_STATIC,
+							   text,
+							   WS_VISIBLE | SS_TEXT,
+							   0,0,2000,1000,
+							   NULLHANDLE,
+							   HWND_TOP,
+							   id,
+							   NULL,
+							   NULL);
+	blah->oldproc = WinSubclassWindow(tmp, _statusproc);
+	WinSetWindowPtr(tmp, QWP_USER, blah);
+	dw_window_set_font(tmp, DefaultFont);
+	dw_window_set_color(tmp, DW_CLR_BLACK, DW_CLR_PALEGRAY);
+	return tmp;
+}
+
+#ifndef MLS_LIMITVSCROLL
+#define MLS_LIMITVSCROLL           0x00000080L
+#endif
+
+/*
+ * Create a new Multiline Editbox window (widget) to be packed.
+ * Parameters:
+ *       id: An ID to be used with dw_window_from_id() or 0L.
+ */
+HWND API dw_mle_new(ULONG id)
+{
+	WindowData *blah = calloc(1, sizeof(WindowData));
+	HWND tmp = WinCreateWindow(HWND_OBJECT,
+							   WC_MLE,
+							   "",
+							   WS_VISIBLE |
+							   MLS_BORDER | MLS_IGNORETAB |
+							   MLS_READONLY | MLS_VSCROLL |
+							   MLS_LIMITVSCROLL,
+							   0,0,2000,1000,
+							   NULLHANDLE,
+							   HWND_TOP,
+							   id,
+							   NULL,
+							   NULL);
+	blah->oldproc = WinSubclassWindow(tmp, _mleproc);
+	WinSetWindowPtr(tmp, QWP_USER, blah);
+	dw_window_set_font(tmp, DefaultFont);
+	return tmp;
+}
+
+/*
+ * Create a new Entryfield window (widget) to be packed.
+ * Parameters:
+ *       text: The default text to be in the entryfield widget.
+ *       id: An ID to be used with dw_window_from_id() or 0L.
+ */
+HWND API dw_entryfield_new(char *text, ULONG id)
+{
+
+	WindowData *blah = calloc(1, sizeof(WindowData));
+	HWND tmp = WinCreateWindow(HWND_OBJECT,
+							   WC_ENTRYFIELD,
+							   text,
+							   WS_VISIBLE | ES_MARGIN |
+							   ES_AUTOSCROLL | WS_TABSTOP,
+							   0,0,2000,1000,
+							   NULLHANDLE,
+							   HWND_TOP,
+							   id,
+							   NULL,
+							   NULL);
+	blah->oldproc = WinSubclassWindow(tmp, _entryproc);
+	WinSetWindowPtr(tmp, QWP_USER, blah);
+	dw_window_set_font(tmp, DefaultFont);
+	dw_window_set_color(tmp, DW_CLR_BLACK, DW_CLR_WHITE);
+	return tmp;
+}
+
+/*
+ * Create a new Entryfield (password) window (widget) to be packed.
+ * Parameters:
+ *       text: The default text to be in the entryfield widget.
+ *       id: An ID to be used with dw_window_from_id() or 0L.
+ */
+HWND API dw_entryfield_password_new(char *text, ULONG id)
+{
+	WindowData *blah = calloc(1, sizeof(WindowData));
+	HWND tmp = WinCreateWindow(HWND_OBJECT,
+							   WC_ENTRYFIELD,
+							   text,
+							   WS_VISIBLE | ES_MARGIN | ES_UNREADABLE |
+							   ES_AUTOSCROLL | WS_TABSTOP,
+							   0,0,2000,1000,
+							   NULLHANDLE,
+							   HWND_TOP,
+							   id,
+							   NULL,
+							   NULL);
+	blah->oldproc = WinSubclassWindow(tmp, _entryproc);
+	WinSetWindowPtr(tmp, QWP_USER, blah);
+	dw_window_set_font(tmp, DefaultFont);
+	dw_window_set_color(tmp, DW_CLR_BLACK, DW_CLR_WHITE);
+	return tmp;
+}
+
+/*
+ * Create a new Combobox window (widget) to be packed.
+ * Parameters:
+ *       text: The default text to be in the combpbox widget.
+ *       id: An ID to be used with dw_window_from_id() or 0L.
+ */
+HWND API dw_combobox_new(char *text, ULONG id)
+{
+	WindowData *blah = calloc(1, sizeof(WindowData));
+	HWND frame = dw_box_new(DW_HORZ, 0);
+	HWND tmp = WinCreateWindow(frame,
+							   WC_COMBOBOX,
+							   text,
+							   WS_VISIBLE | CBS_DROPDOWN | WS_GROUP,
+							   0,0,2000,1000,
+							   NULLHANDLE,
+							   HWND_TOP,
+							   id,
+							   NULL,
+							   NULL);
+	HENUM henum = WinBeginEnumWindows(tmp);
+	HWND child, last = NULLHANDLE;
+	
+	while((child = WinGetNextWindow(henum)) != NULLHANDLE)
+	{
+		WindowData *moreblah = calloc(1, sizeof(WindowData));
+		moreblah->oldproc = WinSubclassWindow(child, _comboentryproc);
+		WinSetWindowPtr(child, QWP_USER, moreblah);
+		dw_window_set_color(child, DW_CLR_BLACK, DW_CLR_WHITE);
+		last = child;
+	}
+	WinEndEnumWindows(henum);
+	blah->oldproc = WinSubclassWindow(tmp, _comboproc);
+	WinSetWindowPtr(tmp, QWP_USER, blah);
+	dw_window_set_font(tmp, DefaultFont);
+	dw_window_set_color(tmp, DW_CLR_BLACK, DW_CLR_WHITE);
+	dw_window_set_data(tmp, "_dw_comboentry", (void *)last);
+	dw_window_set_data(tmp, "_dw_combo_box", (void *)frame);
+	WinSetOwner(tmp, frame);
+	return tmp;
+}
+
+/*
+ * Create a new button window (widget) to be packed.
+ * Parameters:
+ *       text: The text to be display by the static text widget.
+ *       id: An ID to be used with dw_window_from_id() or 0L.
+ */
+HWND API dw_button_new(char *text, ULONG id)
+{
+	BubbleButton *bubble = calloc(sizeof(BubbleButton), 1);
+
+	HWND tmp = WinCreateWindow(HWND_OBJECT,
+							   WC_BUTTON,
+							   text,
+							   WS_VISIBLE,
+							   0,0,2000,1000,
+							   NULLHANDLE,
+							   HWND_TOP,
+							   id,
+							   NULL,
+							   NULL);
+
+	bubble->id = id;
+	bubble->bubbletext[0] = '\0';
+	bubble->pOldProc = WinSubclassWindow(tmp, _BtProc);
+
+	WinSetWindowPtr(tmp, QWP_USER, bubble);
+	dw_window_set_font(tmp, DefaultFont);
+	dw_window_set_color(tmp, DW_CLR_BLACK, DW_CLR_PALEGRAY);
+	return tmp;
+}
+
+/* Function: GenResIDStr
+** Abstract: Generate string '#nnnn' for a given ID for using with Button
+**           controls
+*/
+
+void _GenResIDStr(CHAR *buff, ULONG ulID)
+{
+	char *str;
+	int  slen = 0;
+
+	*buff++ = '#';
+
+	str = buff;
+
+	do
+	{
+		*str++ = (ulID % 10) + '0';
+		ulID /= 10;
+		slen++;
+	}
+	while(ulID);
+
+	*str-- = 0;
+
+	for(; str > buff; str--, buff++)
+	{
+		*buff ^= *str;
+		*str  ^= *buff;
+		*buff ^= *str;
+	}
+}
+
+
+/*
+ * Create a new bitmap button window (widget) to be packed.
+ * Parameters:
+ *       text: Bubble help text to be displayed.
+ *       id: An ID of a bitmap in the resource file.
+ */
+HWND API dw_bitmapbutton_new(char *text, ULONG id)
+{
+	char idbuf[256], *name = NULL;
+	HWND tmp;
+	BubbleButton *bubble = calloc(sizeof(BubbleButton), 1);
+	HPOINTER icon = WinLoadPointer(HWND_DESKTOP, 0L, id);
+
+	if(!icon)
+	{
+		name = idbuf;
+		_GenResIDStr(idbuf, id);
+	}
+
+	tmp = WinCreateWindow(HWND_OBJECT,
+						  WC_BUTTON,
+						  name,
+						  WS_VISIBLE | BS_PUSHBUTTON |
+						  BS_NOPOINTERFOCUS | BS_AUTOSIZE |
+						  (icon ? 0 : BS_BITMAP),
+						  0,0,2000,1000,
+						  NULLHANDLE,
+						  HWND_TOP,
+						  id,
+						  NULL,
+						  NULL);
+
+	bubble->id = id;
+	strncpy(bubble->bubbletext, text, BUBBLE_HELP_MAX - 1);
+	bubble->bubbletext[BUBBLE_HELP_MAX - 1] = '\0';
+	bubble->pOldProc = WinSubclassWindow(tmp, _BtProc);
+
+	WinSetWindowPtr(tmp, QWP_USER, bubble);
+
+	if(icon)
+		dw_window_set_data(tmp, "_dw_button_icon", (void *)icon);
+	dw_window_set_data(tmp, "_dw_bitmapbutton", (void *)1);
+	return tmp;
+}
+
+/*
+ * Create a new bitmap button window (widget) to be packed from a file.
+ * Parameters:
+ *       text: Bubble help text to be displayed.
+ *       id: An ID to be used with dw_window_from_id() or 0L.
+ *       filename: Name of the file, omit extention to have
+ *                 DW pick the appropriate file extension.
+ *                 (BMP on OS/2 or Windows, XPM on Unix)
+ */
+HWND API dw_bitmapbutton_new_from_file(char *text, unsigned long id, char *filename)
+{
+	BubbleButton *bubble = calloc(sizeof(BubbleButton), 1);
+	HWND tmp = WinCreateWindow(HWND_OBJECT,
+							   WC_BUTTON,
+							   "",
+							   WS_VISIBLE | BS_PUSHBUTTON |
+							   BS_AUTOSIZE | BS_NOPOINTERFOCUS,
+							   0,0,2000,1000,
+							   NULLHANDLE,
+							   HWND_TOP,
+							   id,
+							   NULL,
+							   NULL);
+	char *file = alloca(strlen(filename) + 5);
+	HPIXMAP pixmap = NULL, disabled = NULL;
+	HPOINTER icon = 0;
+
+	if(file && (pixmap = calloc(1,sizeof(struct _hpixmap))))
+	{
+		int z, j, lim, len;
+		LONG fore;
+
+		strcpy(file, filename);
+
+		/* check if we can read from this file (it exists and read permission) */
+		if(access(file, 04) == 0)
+		{
+			len = strlen( file );
+			if(len > 4)
+			{
+				if(stricmp(file + len - 4, ".ico") == 0)
+					icon = WinLoadFileIcon(file, FALSE);
+				else
+					_load_bitmap_file(file, tmp, &pixmap->hbm, &pixmap->hdc, &pixmap->hps, &pixmap->width, &pixmap->height);
+			}
+		}
+		else
+		{
+			/* Try with .ico extension first...*/
+			strcat(file, ".ico");
+			if(access(file, 04) == 0)
+				icon = WinLoadFileIcon(file, FALSE);
+			else
+			{
+				strcpy(file, filename);
+				strcat(file, ".bmp");
+				if(access(file, 04) == 0)
+					_load_bitmap_file(file, tmp, &pixmap->hbm, &pixmap->hdc, &pixmap->hps, &pixmap->width, &pixmap->height);
+			}
+		}
+
+		if(icon)
+		{
+			free(pixmap);
+			pixmap = NULL;
+		}
+		else
+		{
+			/* Create a disabled style pixmap */
+			disabled = dw_pixmap_new(tmp, pixmap->width, pixmap->height, dw_color_depth_get());
+			dw_pixmap_bitblt(0, disabled, 0, 0, pixmap->width, pixmap->height, 0, pixmap, 0, 0);
+
+			fore = _foreground;
+			dw_color_foreground_set(DW_CLR_PALEGRAY);
+			lim = pixmap->width/2;
+			for(j=0;j<pixmap->height;j++)
+			{
+				int mod = j%2;
+
+				for(z=0;z<lim;z++)
+					dw_draw_point(0, disabled, (z*2)+mod, j);
+			}
+			_foreground = fore;
+		}
+	}
+
+	bubble->id = id;
+	strncpy(bubble->bubbletext, text, BUBBLE_HELP_MAX - 1);
+	bubble->bubbletext[BUBBLE_HELP_MAX - 1] = '\0';
+	bubble->pOldProc = WinSubclassWindow(tmp, _BtProc);
+
+	WinSetWindowPtr(tmp, QWP_USER, bubble);
+
+	if(icon)
+		dw_window_set_data(tmp, "_dw_button_icon", (void *)icon);
+	else
+	{
+		dw_window_set_data(tmp, "_dw_hpixmap", (void *)pixmap);
+		dw_window_set_data(tmp, "_dw_hpixmap_disabled", (void *)disabled);
+	}
+	dw_window_set_data(tmp, "_dw_bitmapbutton", (void *)1);
+	return tmp;
+}
+
+/*
+ * Create a new spinbutton window (widget) to be packed.
+ * Parameters:
+ *       text: The text to be display by the static text widget.
+ *       id: An ID to be used with dw_window_from_id() or 0L.
+ */
+HWND API dw_spinbutton_new(char *text, ULONG id)
+{
+	WindowData *blah = calloc(sizeof(WindowData), 1);
+	HWND tmp = WinCreateWindow(HWND_OBJECT,
+							   WC_SPINBUTTON,
+							   text,
+							   WS_VISIBLE | SPBS_MASTER,
+							   0,0,2000,1000,
+							   NULLHANDLE,
+							   HWND_TOP,
+							   id,
+							   NULL,
+							   NULL);
+	HWND entry = _find_entryfield(tmp);
+	blah->oldproc = WinSubclassWindow(tmp, _entryproc);
+	WinSetWindowPtr(tmp, QWP_USER, blah);
+	blah = calloc(sizeof(WindowData), 1);
+	blah->oldproc = WinSubclassWindow(entry, _spinentryproc);
+	WinSetWindowPtr(entry, QWP_USER, blah);
+	dw_window_set_font(tmp, DefaultFont);
+	dw_window_set_color(entry, DW_CLR_BLACK, DW_CLR_WHITE);
+	return tmp;
+}
+
+/*
+ * Create a new radiobutton window (widget) to be packed.
+ * Parameters:
+ *       text: The text to be display by the static text widget.
+ *       id: An ID to be used with dw_window_from_id() or 0L.
+ */
+HWND API dw_radiobutton_new(char *text, ULONG id)
+{
+	WindowData *blah = calloc(sizeof(WindowData), 1);
+	HWND tmp = WinCreateWindow(HWND_OBJECT,
+							   WC_BUTTON,
+							   text,
+							   WS_VISIBLE |
+							   BS_AUTORADIOBUTTON,
+							   0,0,2000,1000,
+							   NULLHANDLE,
+							   HWND_TOP,
+							   id,
+							   NULL,
+							   NULL);
+	blah->oldproc = WinSubclassWindow(tmp, _entryproc);
+	WinSetWindowPtr(tmp, QWP_USER, blah);
+	dw_window_set_font(tmp, DefaultFont);
+	dw_window_set_color(tmp, DW_CLR_BLACK, DW_CLR_PALEGRAY);
+	return tmp;
+}
+
+
+/*
+ * Create a new slider window (widget) to be packed.
+ * Parameters:
+ *       vertical: TRUE or FALSE if slider is vertical.
+ *       increments: Number of increments available.
+ *       id: An ID to be used with dw_window_from_id() or 0L.
+ */
+HWND API dw_slider_new(int vertical, int increments, ULONG id)
+{
+	WindowData *blah = calloc(1, sizeof(WindowData));
+	SLDCDATA sldcData = { 0, 0, 0, 0, 0 };
+	HWND tmp;
+
+	sldcData.cbSize = sizeof(SLDCDATA);
+    sldcData.usScale1Increments = increments;
+
+	tmp = WinCreateWindow(HWND_OBJECT,
+						  WC_SLIDER,
+						  "",
+						  WS_VISIBLE | SLS_SNAPTOINCREMENT |
+						  (vertical ? SLS_VERTICAL : SLS_HORIZONTAL),
+						  0,0,2000,1000,
+						  NULLHANDLE,
+						  HWND_TOP,
+						  id,
+						  &sldcData,
+						  NULL);
+
+	blah->oldproc = WinSubclassWindow(tmp, _entryproc);
+	WinSetWindowPtr(tmp, QWP_USER, blah);
+	return tmp;
+}
+
+/*
+ * Create a new scrollbar window (widget) to be packed.
+ * Parameters:
+ *       vertical: TRUE or FALSE if scrollbar is vertical.
+ *       increments: Number of increments available.
+ *       id: An ID to be used with dw_window_from_id() or 0L.
+ */
+HWND API dw_scrollbar_new(int vertical, ULONG id)
+{
+	return WinCreateWindow(HWND_OBJECT,
+						   WC_SCROLLBAR,
+						   "",
+						   WS_VISIBLE | SBS_AUTOTRACK |
+						   (vertical ? SBS_VERT : SBS_HORZ),
+						   0,0,2000,1000,
+						   NULLHANDLE,
+						   HWND_TOP,
+						   id ? id : (GlobalID++),
+						   NULL,
+						   NULL);
+}
+
+/*
+ * Create a new percent bar window (widget) to be packed.
+ * Parameters:
+ *       id: An ID to be used with dw_window_from_id() or 0L.
+ */
+HWND API dw_percent_new(ULONG id)
+{
+	WindowData *blah = calloc(1, sizeof(WindowData));
+	HWND tmp = WinCreateWindow(HWND_OBJECT,
+							   WC_SLIDER,
+							   "",
+							   WS_VISIBLE | SLS_READONLY
+							   | SLS_RIBBONSTRIP,
+							   0,0,2000,1000,
+							   NULLHANDLE,
+							   HWND_TOP,
+							   id,
+							   NULL,
+							   NULL);
+	blah->oldproc = WinSubclassWindow(tmp, _percentproc);
+	WinSetWindowPtr(tmp, QWP_USER, blah);
+	dw_window_disable(tmp);
+	return tmp;
+}
+
+/*
+ * Create a new checkbox window (widget) to be packed.
+ * Parameters:
+ *       text: The text to be display by the static text widget.
+ *       id: An ID to be used with dw_window_from_id() or 0L.
+ */
+HWND API dw_checkbox_new(char *text, ULONG id)
+{
+	BubbleButton *bubble = calloc(sizeof(BubbleButton), 1);
+	HWND tmp = WinCreateWindow(HWND_OBJECT,
+							   WC_BUTTON,
+							   text,
+							   WS_VISIBLE | BS_AUTOCHECKBOX,
+							   0,0,2000,1000,
+							   NULLHANDLE,
+							   HWND_TOP,
+							   id,
+							   NULL,
+							   NULL);
+	bubble->id = id;
+	bubble->bubbletext[0] = '\0';
+	bubble->pOldProc = WinSubclassWindow(tmp, _BtProc);
+	WinSetWindowPtr(tmp, QWP_USER, bubble);
+	dw_window_set_font(tmp, DefaultFont);
+	dw_window_set_color(tmp, DW_CLR_BLACK, DW_CLR_PALEGRAY);
+	return tmp;
+}
+
+/*
+ * Create a new listbox window (widget) to be packed.
+ * Parameters:
+ *       id: An ID to be used with dw_window_from_id() or 0L.
+ *       multi: Multiple select TRUE or FALSE.
+ */
+HWND API dw_listbox_new(ULONG id, int multi)
+{
+	WindowData *blah = calloc(sizeof(WindowData), 1);
+	HWND tmp = WinCreateWindow(HWND_OBJECT,
+							   WC_LISTBOX,
+							   NULL,
+							   WS_VISIBLE | LS_NOADJUSTPOS |
+							   (multi ? LS_MULTIPLESEL : 0),
+							   0,0,2000,1000,
+							   NULLHANDLE,
+							   HWND_TOP,
+							   id ? id : (GlobalID++),
+							   NULL,
+							   NULL);
+	blah->oldproc = WinSubclassWindow(tmp, _entryproc);
+	WinSetWindowPtr(tmp, QWP_USER, blah);
+	dw_window_set_font(tmp, DefaultFont);
+	dw_window_set_color(tmp, DW_CLR_BLACK, DW_CLR_WHITE);
+	return tmp;
+}
+
+/*
+ * Sets the icon used for a given window.
+ * Parameters:
+ *       handle: Handle to the window.
+ *       id: An ID to be used to specify the icon.
+ */
+void API dw_window_set_icon(HWND handle, ULONG id)
+{
+	HPOINTER icon = id < 65536 ? WinLoadPointer(HWND_DESKTOP,NULLHANDLE,id) : (HPOINTER)id;
+	WinSendMsg(handle, WM_SETICON, (MPARAM)icon, 0);
+}
+
+/* Internal function to load a bitmap from a file and return handles
+ * to the bitmap, presentation space etc.
+ */
+int _load_bitmap_file(char *file, HWND handle, HBITMAP *hbm, HDC *hdc, HPS *hps, unsigned long *width, unsigned long *height)
+{
+	HFILE BitmapFileHandle = NULLHANDLE; /* handle for the file */
+	ULONG OpenAction = 0;
+	PBYTE BitmapFileBegin; /* pointer to the first byte of bitmap data  */
+	FILESTATUS BitmapStatus;
+	ULONG cbRead;
+	PBITMAPFILEHEADER2 pBitmapFileHeader;
+	PBITMAPINFOHEADER2 pBitmapInfoHeader;
+	ULONG ScanLines, ulFlags;
+	HPS hps1;
+	HDC hdc1;
+	SIZEL sizl = { 0, 0 };
+
+	/* open bitmap file */
+	DosOpen(file, &BitmapFileHandle, &OpenAction, 0L,
+			FILE_ARCHIVED | FILE_NORMAL | FILE_READONLY,
+			OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
+			OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY |
+			OPEN_FLAGS_NOINHERIT, 0L);
+
+	if(!BitmapFileHandle)
+		return 0;
+
+	/* find out how big the file is  */
+	DosQueryFileInfo(BitmapFileHandle, 1, &BitmapStatus,
+					 sizeof(BitmapStatus));
+
+	/* allocate memory to load the bitmap */
+	DosAllocMem((PPVOID)&BitmapFileBegin, (ULONG)BitmapStatus.cbFile,
+				PAG_READ | PAG_WRITE | PAG_COMMIT);
+
+	/* read bitmap file into memory buffer */
+	DosRead(BitmapFileHandle, (PVOID)BitmapFileBegin,
+			BitmapStatus.cbFile, &cbRead);
+
+	/* access first bytes as bitmap header */
+	pBitmapFileHeader = (PBITMAPFILEHEADER2)BitmapFileBegin;
+
+	/* check if it's a valid bitmap data file */
+	if((pBitmapFileHeader->usType != BFT_BITMAPARRAY) &&
+	   (pBitmapFileHeader->usType != BFT_BMAP))
+	{
+		/* free memory of bitmap file buffer */
+		DosFreeMem(BitmapFileBegin);
+		/* close the bitmap file */
+		DosClose(BitmapFileHandle);
+		return 0;
+	}
+
+	/* check if it's a file with multiple bitmaps */
+	if(pBitmapFileHeader->usType == BFT_BITMAPARRAY)
+	{
+		/* we'll just use the first bitmap and ignore the others */
+		pBitmapFileHeader = &(((PBITMAPARRAYFILEHEADER2)BitmapFileBegin)->bfh2);
+	}
+
+	/* set pointer to bitmap information block */
+	pBitmapInfoHeader = &pBitmapFileHeader->bmp2;
+
+	/* find out if it's the new 2.0 format or the old format */
+	/* and query number of lines */
+	if(pBitmapInfoHeader->cbFix == sizeof(BITMAPINFOHEADER))
+	{
+		*height = ScanLines = (ULONG)((PBITMAPINFOHEADER)pBitmapInfoHeader)->cy;
+		*width = (ULONG)((PBITMAPINFOHEADER)pBitmapInfoHeader)->cx;
+	}
+	else
+	{
+		*height = ScanLines = pBitmapInfoHeader->cy;
+		*width = pBitmapInfoHeader->cx;
+	}
+
+	/* now we need a presentation space, get it from static control */
+	hps1 = WinGetPS(handle);
+
+	hdc1    = GpiQueryDevice(hps1);
+	ulFlags = GpiQueryPS(hps1, &sizl);
+
+	*hdc = DevOpenDC(dwhab, OD_MEMORY, "*", 0L, NULL, hdc1);
+	*hps = GpiCreatePS (dwhab, *hdc, &sizl, ulFlags | GPIA_ASSOC);
+
+	/* create bitmap now using the parameters from the info block */
+	*hbm = GpiCreateBitmap(*hps, pBitmapInfoHeader, 0L, NULL, NULL);
+
+	/* select the new bitmap into presentation space */
+	GpiSetBitmap(*hps, *hbm);
+
+	/* now copy the bitmap data into the bitmap */
+	GpiSetBitmapBits(*hps, 0L, ScanLines,
+					 BitmapFileBegin + pBitmapFileHeader->offBits,
+					 (PBITMAPINFO2)pBitmapInfoHeader);
+
+	WinReleasePS(hps1);
+
+	/* free memory of bitmap file buffer */
+	DosFreeMem(BitmapFileBegin);
+	/* close the bitmap file */
+	DosClose(BitmapFileHandle);
+	return 1;
+}
+
+/*
+ * Sets the bitmap used for a given static window.
+ * Parameters:
+ *       handle: Handle to the window.
+ *       id: An ID to be used to specify the icon,
+ *           (pass 0 if you use the filename param)
+ *       filename: a path to a file (Bitmap on OS/2 or
+ *                 Windows and a pixmap on Unix, pass
+ *                 NULL if you use the id param)
+ */
+void API dw_window_set_bitmap(HWND handle, unsigned long id, char *filename)
+{
+	HBITMAP hbm;
+	HPS     hps;
+
+	/* Destroy any old bitmap data */
+	_free_bitmap(handle);
+
+	/* If id is non-zero use the resource */
+	if(id)
+	{
+		hps = WinGetPS(handle);
+
+		hbm = GpiLoadBitmap(hps, NULLHANDLE, id, 0, 0);
+	}
+	else if(filename)
+	{
+		HDC hdc;
+		unsigned long width, height;
+		char *file = alloca(strlen(filename) + 5);
+
+		if(!file)
+			return;
+
+		strcpy(file, filename);
+
+		/* check if we can read from this file (it exists and read permission) */
+		if(access(file, 04) != 0)
+		{
+			/* Try with .bmp extention */
+			strcat(file, ".bmp");
+			if(access(file, 04) != 0)
+				return;
+		}
+
+		if(!_load_bitmap_file(file, handle, &hbm, &hdc, &hps, &width, &height))
+			return;
+
+		dw_window_set_data(handle, "_dw_hps", (void *)hps);
+		dw_window_set_data(handle, "_dw_hdc", (void *)hdc);
+		dw_window_set_data(handle, "_dw_width", (void *)width);
+		dw_window_set_data(handle, "_dw_height", (void *)height);
+	}
+	else
+		return;
+
+	WinSetWindowBits(handle,QWL_STYLE,SS_BITMAP,SS_BITMAP | 0x7f);
+	WinSendMsg( handle, SM_SETHANDLE, MPFROMP(hbm), NULL );
+	if(id)
+		WinReleasePS(hps);
+	dw_window_set_data(handle, "_dw_bitmap", (void *)hbm);
+}
+
+/*
+ * Sets the text used for a given window.
+ * Parameters:
+ *       handle: Handle to the window.
+ *       text: The text associsated with a given window.
+ */
+void API dw_window_set_text(HWND handle, char *text)
+{
+	WinSetWindowText(handle, text);
+}
+
+/*
+ * Gets the text used for a given window.
+ * Parameters:
+ *       handle: Handle to the window.
+ * Returns:
+ *       text: The text associsated with a given window.
+ */
+char * API dw_window_get_text(HWND handle)
+{
+	int len = WinQueryWindowTextLength(handle);
+	char *tempbuf = calloc(1, len + 2);
+
+	WinQueryWindowText(handle, len + 1, tempbuf);
+
+	return tempbuf;
+}
+
+/*
+ * Disables given window (widget).
+ * Parameters:
+ *       handle: Handle to the window.
+ */
+void API dw_window_disable(HWND handle)
+{
+	char tmpbuf[100];
+
+	if(dw_window_get_data(handle, "_dw_disabled"))
+		return;
+
+	WinQueryClassName(handle, 99, tmpbuf);
+	dw_window_set_data(handle, "_dw_disabled", (void *)1);
+
+	if(tmpbuf[0] == '#')
+	{
+		int val = atoi(&tmpbuf[1]);
+		HWND hwnd;
+
+		switch(val)
+		{
+		case 2:
+		case 6:
+		case 10:
+		case 32:
+		case 7:
+			hwnd = _find_entryfield(handle);
+			_dw_window_set_color(hwnd ? hwnd : handle, DW_CLR_BLACK, DW_CLR_PALEGRAY);
+			dw_signal_connect(hwnd ? hwnd : handle, DW_SIGNAL_KEY_PRESS, DW_SIGNAL_FUNC(_null_key), (void *)100);
+            if(val == 2)
+				dw_signal_connect(handle, DW_SIGNAL_BUTTON_PRESS, DW_SIGNAL_FUNC(_null_key), (void *)100);
+			if(hwnd)
+				dw_window_set_data(hwnd, "_dw_disabled", (void *)1);
+			return;
+		case 3:
+			if(dw_window_get_data(handle, "_dw_bitmapbutton") && !dw_window_get_data(handle, "_dw_hpixmap"))
+				WinEnableWindow(handle, FALSE);
+			else if(dw_window_get_data(handle, "_dw_bitmapbutton") && dw_window_get_data(handle, "_dw_hpixmap_disabled"))
+				WinInvalidateRect(handle, NULL, FALSE);
+			else
+				_dw_window_set_color(handle, DW_CLR_DARKGRAY, DW_CLR_PALEGRAY);
+			dw_signal_connect(handle, DW_SIGNAL_KEY_PRESS, DW_SIGNAL_FUNC(_null_key), (void *)100);
+			dw_signal_connect(handle, DW_SIGNAL_BUTTON_PRESS, DW_SIGNAL_FUNC(_null_key), (void *)100);
+			return;
+		}
+	}
+	WinEnableWindow(handle, FALSE);
+}
+
+/*
+ * Enables given window (widget).
+ * Parameters:
+ *       handle: Handle to the window.
+ */
+void API dw_window_enable(HWND handle)
+{
+	ULONG fore = (ULONG)dw_window_get_data(handle, "_dw_fore");
+	ULONG back = (ULONG)dw_window_get_data(handle, "_dw_back");
+	HWND hwnd = _find_entryfield(handle);
+
+	dw_window_set_data(handle, "_dw_disabled", 0);
+	if(hwnd)
+		dw_window_set_data(hwnd, "_dw_disabled", 0);
+	if(fore && back)
+		_dw_window_set_color(hwnd ? hwnd : handle, fore-1, back-1);
+	dw_signal_disconnect_by_data(handle, (void *)100);
+	WinEnableWindow(handle, TRUE);
+	if(dw_window_get_data(handle, "_dw_bitmapbutton") && dw_window_get_data(handle, "_dw_hpixmap_disabled"))
+		WinInvalidateRect(handle, NULL, FALSE);
+}
+
+/*
+ * Gets the child window handle with specified ID.
+ * Parameters:
+ *       handle: Handle to the parent window.
+ *       id: Integer ID of the child.
+ */
+HWND API dw_window_from_id(HWND handle, int id)
+{
+	HENUM henum;
+	HWND child;
+	char tmpbuf[100];
+
+	henum = WinBeginEnumWindows(handle);
+	while((child = WinGetNextWindow(henum)) != NULLHANDLE)
+	{
+		int windowid = WinQueryWindowUShort(child, QWS_ID);
+		HWND found;
+
+		WinQueryClassName(child, 99, tmpbuf);
+
+		/* If the child is a box (frame) then recurse into it */
+		if(strncmp(tmpbuf, "#1", 3)==0)
+			if((found = dw_window_from_id(child, id)) != NULLHANDLE)
+				return found;
+
+		if(windowid && windowid == id)
+		{
+			WinEndEnumWindows(henum);
+			return child;
+		}
+	}
+	WinEndEnumWindows(henum);
+	return NULLHANDLE;
+}
+
+/*
+ * Pack windows (widgets) into a box from the end (or bottom).
+ * Parameters:
+ *       box: Window handle of the box to be packed into.
+ *       item: Window handle of the item to be back.
+ *       width: Width in pixels of the item or -1 to be self determined.
+ *       height: Height in pixels of the item or -1 to be self determined.
+ *       hsize: TRUE if the window (widget) should expand horizontally to fill space given.
+ *       vsize: TRUE if the window (widget) should expand vertically to fill space given.
+ *       pad: Number of pixels of padding around the item.
+ */
+void API dw_box_pack_end(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad)
+{
+	char *funcname = "dw_box_pack_end()";
+
+		/*
+		 * If you try and pack an item into itself VERY bad things can happen; like at least an
+		 * infinite loop on GTK! Lets be safe!
+		 */
+	if(box == item)
+	{
+		dw_messagebox(funcname, DW_MB_OK|DW_MB_ERROR, "Danger! Danger! Will Robinson; box and item are the same!");
+		return;
+	}
+
+	if(WinWindowFromID(box, FID_CLIENT))
+	{
+		box = WinWindowFromID(box, FID_CLIENT);
+		hsize = TRUE;
+		vsize = TRUE;
+	}
+	_dw_box_pack_end(box, item, width, height, hsize, vsize, pad, funcname);
+}
+
+void _dw_box_pack_end(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad, char *functionname)
+{
+	Box *thisbox = WinQueryWindowPtr(box, QWP_USER);
+
+	if(thisbox)
+	{
+		int z;
+		Item *tmpitem, *thisitem = thisbox->items;
+		char tmpbuf[100];
+		HWND frame = (HWND)dw_window_get_data(item, "_dw_combo_box");
+
+		tmpitem = malloc(sizeof(Item)*(thisbox->count+1));
+
+		for(z=0;z<thisbox->count;z++)
+		{
+			tmpitem[z+1] = thisitem[z];
+		}
+
+		WinQueryClassName(item, 99, tmpbuf);
+
+		if(vsize && !height)
+			height = 1;
+		if(hsize && !width)
+			width = 1;
+
+		if(strncmp(tmpbuf, "#1", 3)==0)
+			tmpitem[0].type = TYPEBOX;
+		else
+		{
+			if ( width == 0 && hsize == FALSE )
+				dw_messagebox(functionname, DW_MB_OK|DW_MB_ERROR, "Width and expand Horizonal both unset for box: %x item: %x",box,item);
+			if ( height == 0 && vsize == FALSE )
+				dw_messagebox(functionname, DW_MB_OK|DW_MB_ERROR, "Height and expand Vertical both unset for box: %x item: %x",box,item);
+
+			tmpitem[0].type = TYPEITEM;
+		}
+
+		tmpitem[0].hwnd = item;
+		tmpitem[0].origwidth = tmpitem[0].width = width;
+		tmpitem[0].origheight = tmpitem[0].height = height;
+		tmpitem[0].pad = pad;
+		if(hsize)
+			tmpitem[0].hsize = SIZEEXPAND;
+		else
+			tmpitem[0].hsize = SIZESTATIC;
+
+		if(vsize)
+			tmpitem[0].vsize = SIZEEXPAND;
+		else
+			tmpitem[0].vsize = SIZESTATIC;
+
+		thisbox->items = tmpitem;
+
+		if(thisbox->count)
+			free(thisitem);
+
+		thisbox->count++;
+
+		WinQueryClassName(item, 99, tmpbuf);
+		/* Don't set the ownership if it's an entryfield or spinbutton */
+		if(strncmp(tmpbuf, "#6", 3)!=0 && strncmp(tmpbuf, "#32", 4)!=0 && strncmp(tmpbuf, "#2", 3)!=0)
+			WinSetOwner(item, box);
+		WinSetParent(frame ? frame : item, box, FALSE);
+	}
+}
+
+/*
+ * Sets the size of a given window (widget).
+ * Parameters:
+ *          handle: Window (widget) handle.
+ *          width: New width in pixels.
+ *          height: New height in pixels.
+ */
+void API dw_window_set_size(HWND handle, ULONG width, ULONG height)
+{
+	WinSetWindowPos(handle, NULLHANDLE, 0, 0, width, height, SWP_SHOW | SWP_SIZE);
+}
+
+/*
+ * Returns the width of the screen.
+ */
+int API dw_screen_width(void)
+{
+	return WinQuerySysValue(HWND_DESKTOP,SV_CXSCREEN);
+}
+
+/*
+ * Returns the height of the screen.
+ */
+int API dw_screen_height(void)
+{
+	return WinQuerySysValue(HWND_DESKTOP,SV_CYSCREEN);
+}
+
+/* This should return the current color depth */
+unsigned long API dw_color_depth_get(void)
+{
+	HDC hdc = WinOpenWindowDC(HWND_DESKTOP);
+	long colors;
+
+	DevQueryCaps(hdc, CAPS_COLOR_BITCOUNT, 1, &colors);
+	DevCloseDC(hdc);
+	return colors;
+}
+
+
+/*
+ * Sets the position of a given window (widget).
+ * Parameters:
+ *          handle: Window (widget) handle.
+ *          x: X location from the bottom left.
+ *          y: Y location from the bottom left.
+ */
+void API dw_window_set_pos(HWND handle, ULONG x, ULONG y)
+{
+	int myy = _get_frame_height(handle) - (y + _get_height(handle));
+
+	WinSetWindowPos(handle, NULLHANDLE, x, myy, 0, 0, SWP_MOVE);
+}
+
+/*
+ * Sets the position and size of a given window (widget).
+ * Parameters:
+ *          handle: Window (widget) handle.
+ *          x: X location from the bottom left.
+ *          y: Y location from the bottom left.
+ *          width: Width of the widget.
+ *          height: Height of the widget.
+ */
+void API dw_window_set_pos_size(HWND handle, ULONG x, ULONG y, ULONG width, ULONG height)
+{
+	int myy = _get_frame_height(handle) - (y + height);
+
+	WinSetWindowPos(handle, NULLHANDLE, x, myy, width, height, SWP_MOVE | SWP_SIZE | SWP_SHOW);
+}
+
+/*
+ * Gets the position and size of a given window (widget).
+ * Parameters:
+ *          handle: Window (widget) handle.
+ *          x: X location from the bottom left.
+ *          y: Y location from the bottom left.
+ *          width: Width of the widget.
+ *          height: Height of the widget.
+ */
+void API dw_window_get_pos_size(HWND handle, ULONG *x, ULONG *y, ULONG *width, ULONG *height)
+{
+	SWP swp;
+	WinQueryWindowPos(handle, &swp);
+	if(x)
+		*x = swp.x;
+	if(y)
+		*y = _get_frame_height(handle) - (swp.y + swp.cy);
+	if(width)
+		*width = swp.cx;
+	if(height)
+		*height = swp.cy;
+}
+
+/*
+ * Sets the style of a given window (widget).
+ * Parameters:
+ *          handle: Window (widget) handle.
+ *          width: New width in pixels.
+ *          height: New height in pixels.
+ */
+void API dw_window_set_style(HWND handle, ULONG style, ULONG mask)
+{
+	WinSetWindowBits(handle, QWL_STYLE, style, mask);
+}
+
+/*
+ * Adds a new page to specified notebook.
+ * Parameters:
+ *          handle: Window (widget) handle.
+ *          flags: Any additional page creation flags.
+ *          front: If TRUE page is added at the beginning.
+ */
+unsigned long API dw_notebook_page_new(HWND handle, ULONG flags, int front)
+{
+	return (ULONG)WinSendMsg(handle, BKM_INSERTPAGE, 0L,
+							 MPFROM2SHORT((BKA_STATUSTEXTON | BKA_AUTOPAGESIZE | BKA_MAJOR | flags), front ? BKA_FIRST : BKA_LAST));
+}
+
+/*
+ * Remove a page from a notebook.
+ * Parameters:
+ *          handle: Handle to the notebook widget.
+ *          pageid: ID of the page to be destroyed.
+ */
+void API dw_notebook_page_destroy(HWND handle, unsigned int pageid)
+{
+	WinSendMsg(handle, BKM_DELETEPAGE,
+			   MPFROMLONG(pageid),	(MPARAM)BKA_SINGLE);
+}
+
+/*
+ * Queries the currently visible page ID.
+ * Parameters:
+ *          handle: Handle to the notebook widget.
+ */
+unsigned long API dw_notebook_page_get(HWND handle)
+{
+	return (unsigned long)WinSendMsg(handle, BKM_QUERYPAGEID,0L, MPFROM2SHORT(BKA_TOP, BKA_MAJOR));
+}
+
+/*
+ * Sets the currently visibale page ID.
+ * Parameters:
+ *          handle: Handle to the notebook widget.
+ *          pageid: ID of the page to be made visible.
+ */
+void API dw_notebook_page_set(HWND handle, unsigned int pageid)
+{
+	WinSendMsg(handle, BKM_TURNTOPAGE, MPFROMLONG(pageid), 0L);
+}
+
+/*
+ * Sets the text on the specified notebook tab.
+ * Parameters:
+ *          handle: Notebook handle.
+ *          pageid: Page ID of the tab to set.
+ *          text: Pointer to the text to set.
+ */
+void API dw_notebook_page_set_text(HWND handle, ULONG pageid, char *text)
+{
+	WinSendMsg(handle, BKM_SETTABTEXT,
+			   MPFROMLONG(pageid),	MPFROMP(text));
+}
+
+/*
+ * Sets the text on the specified notebook tab status area.
+ * Parameters:
+ *          handle: Notebook handle.
+ *          pageid: Page ID of the tab to set.
+ *          text: Pointer to the text to set.
+ */
+void API dw_notebook_page_set_status_text(HWND handle, ULONG pageid, char *text)
+{
+	WinSendMsg(handle, BKM_SETSTATUSLINETEXT,
+			   MPFROMLONG(pageid),	MPFROMP(text));
+}
+
+/*
+ * Packs the specified box into the notebook page.
+ * Parameters:
+ *          handle: Handle to the notebook to be packed.
+ *          pageid: Page ID in the notebook which is being packed.
+ *          page: Box handle to be packed.
+ */
+void API dw_notebook_pack(HWND handle, ULONG pageid, HWND page)
+{
+	HWND tmpbox = dw_box_new(DW_VERT, 0);
+
+	dw_box_pack_start(tmpbox, page, 0, 0, TRUE, TRUE, 0);
+	WinSubclassWindow(tmpbox, _wndproc);
+	WinSendMsg(handle, BKM_SETPAGEWINDOWHWND,
+			   MPFROMLONG(pageid),	MPFROMHWND(tmpbox));
+}
+
+/*
+ * Appends the specified text to the listbox's (or combobox) entry list.
+ * Parameters:
+ *          handle: Handle to the listbox to be appended to.
+ *          text: Text to append into listbox.
+ */
+void API dw_listbox_append(HWND handle, char *text)
+{
+	WinSendMsg(handle,
+			   LM_INSERTITEM,
+			   MPFROMSHORT(LIT_END),
+			   MPFROMP(text));
+}
+
+/*
+ * Appends the specified text items to the listbox's (or combobox) entry list.
+ * Parameters:
+ *          handle: Handle to the listbox to be appended to.
+ *          text: Text strings to append into listbox.
+ *          count: Number of text strings to append
+ */
+void API dw_listbox_list_append(HWND handle, char **text, int count)
+{
+	int i;
+	for(i=0;i<count;i++)
+		WinSendMsg(handle,
+				   LM_INSERTITEM,
+				   MPFROMSHORT(LIT_END),
+				   MPFROMP(text[i]));
+}
+
+/*
+ * Clears the listbox's (or combobox) list of all entries.
+ * Parameters:
+ *          handle: Handle to the listbox to be cleared.
+ */
+void API dw_listbox_clear(HWND handle)
+{
+	WinSendMsg(handle,
+			   LM_DELETEALL, 0L, 0L);
+}
+
+/*
+ * Returns the listbox's item count.
+ * Parameters:
+ *          handle: Handle to the listbox to be cleared.
+ */
+int API dw_listbox_count(HWND handle)
+{
+	return (int)WinSendMsg(handle,
+						   LM_QUERYITEMCOUNT,0L, 0L);
+}
+
+/*
+ * Sets the topmost item in the viewport.
+ * Parameters:
+ *          handle: Handle to the listbox to be cleared.
+ *          top: Index to the top item.
+ */
+void API dw_listbox_set_top(HWND handle, int top)
+{
+	WinSendMsg(handle,
+			   LM_SETTOPINDEX,
+			   MPFROMSHORT(top),
+			   0L);
+}
+
+/*
+ * Copies the given index item's text into buffer.
+ * Parameters:
+ *          handle: Handle to the listbox to be queried.
+ *          index: Index into the list to be queried.
+ *          buffer: Buffer where text will be copied.
+ *          length: Length of the buffer (including NULL).
+ */
+void API dw_listbox_get_text(HWND handle, unsigned int index, char *buffer, unsigned int length)
+{
+	WinSendMsg(handle, LM_QUERYITEMTEXT, MPFROM2SHORT(index, length), (MPARAM)buffer);
+}
+
+/*
+ * Sets the text of a given listbox entry.
+ * Parameters:
+ *          handle: Handle to the listbox to be queried.
+ *          index: Index into the list to be queried.
+ *          buffer: Buffer where text will be copied.
+ */
+void API dw_listbox_set_text(HWND handle, unsigned int index, char *buffer)
+{
+	WinSendMsg(handle, LM_SETITEMTEXT, MPFROMSHORT(index), (MPARAM)buffer);
+}
+
+/*
+ * Returns the index to the item in the list currently selected.
+ * Parameters:
+ *          handle: Handle to the listbox to be queried.
+ */
+unsigned int API dw_listbox_selected(HWND handle)
+{
+		return (unsigned int)WinSendMsg(handle,
+										LM_QUERYSELECTION,
+										MPFROMSHORT(LIT_CURSOR),
+										0);
+}
+
+/*
+ * Returns the index to the current selected item or -1 when done.
+ * Parameters:
+ *          handle: Handle to the listbox to be queried.
+ *          where: Either the previous return or -1 to restart.
+ */
+int API dw_listbox_selected_multi(HWND handle, int where)
+{
+	int place = where;
+
+	if(where == -1)
+		place = LIT_FIRST;
+
+	place = (int)WinSendMsg(handle,
+							LM_QUERYSELECTION,
+							MPFROMSHORT(place),0L);
+	if(place == LIT_NONE)
+		return -1;
+	return place;
+}
+
+/*
+ * Sets the selection state of a given index.
+ * Parameters:
+ *          handle: Handle to the listbox to be set.
+ *          index: Item index.
+ *          state: TRUE if selected FALSE if unselected.
+ */
+void API dw_listbox_select(HWND handle, int index, int state)
+{
+	char tmpbuf[100];
+
+	WinSendMsg(handle, LM_SELECTITEM, MPFROMSHORT(index), (MPARAM)state);
+
+	WinQueryClassName(handle, 99, tmpbuf);
+
+	/* If we are setting a combobox call the event handler manually */
+	if(strncmp(tmpbuf, "#6", 3)==0)
+		_run_event(handle, WM_CONTROL, MPFROM2SHORT(0, LN_SELECT), (MPARAM)handle);
+}
+
+/*
+ * Deletes the item with given index from the list.
+ * Parameters:
+ *          handle: Handle to the listbox to be set.
+ *          index: Item index.
+ */
+void API dw_listbox_delete(HWND handle, int index)
+{
+	WinSendMsg(handle, LM_DELETEITEM, MPFROMSHORT(index), 0);
+}
+
+/*
+ * Adds text to an MLE box and returns the current point.
+ * Parameters:
+ *          handle: Handle to the MLE to be queried.
+ *          buffer: Text buffer to be imported.
+ *          startpoint: Point to start entering text.
+ */
+unsigned int API dw_mle_import(HWND handle, char *buffer, int startpoint)
+{
+	unsigned long point = startpoint;
+	PBYTE mlebuf;
+
+	/* Work around 64K limit */
+	if(!DosAllocMem((PPVOID) &mlebuf, 65536, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_TILE))
+	{
+		int amount, len = strlen(buffer), written = 0;
+
+		while(written < len)
+		{
+			if((len - written) > 65535)
+				amount = 65535;
+			else
+				amount = len - written;
+
+			memcpy(mlebuf, &buffer[written], amount);
+			mlebuf[amount] = '\0';
+
+			WinSendMsg(handle, MLM_SETIMPORTEXPORT, MPFROMP(mlebuf), MPFROMLONG(amount+1));
+			WinSendMsg(handle, MLM_IMPORT, MPFROMP(&point), MPFROMLONG(amount + 1));
+			dw_mle_delete(handle, point, 1);
+
+			written += amount;
+		}
+		DosFreeMem(mlebuf);
+	}
+	return point - 1;
+}
+
+/*
+ * Grabs text from an MLE box.
+ * Parameters:
+ *          handle: Handle to the MLE to be queried.
+ *          buffer: Text buffer to be exported.
+ *          startpoint: Point to start grabbing text.
+ *          length: Amount of text to be grabbed.
+ */
+void API dw_mle_export(HWND handle, char *buffer, int startpoint, int length)
+{
+	PBYTE mlebuf;
+
+	/* Work around 64K limit */
+	if(!DosAllocMem((PPVOID) &mlebuf, 65535, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_TILE))
+	{
+		int amount, copied, written = 0;
+
+		while(written < length)
+		{
+			if((length - written) > 65535)
+				amount = 65535;
+			else
+				amount = length - written;
+
+			WinSendMsg(handle, MLM_SETIMPORTEXPORT, MPFROMP(mlebuf), MPFROMLONG(amount));
+			copied = (int)WinSendMsg(handle, MLM_EXPORT, MPFROMP(&startpoint), MPFROMLONG(&amount));
+
+			if(copied)
+			{
+				memcpy(&buffer[written], mlebuf, copied);
+
+				written += copied;
+			}
+			else
+				break;
+		}
+		DosFreeMem(mlebuf);
+	}
+}
+
+/*
+ * Obtains information about an MLE box.
+ * Parameters:
+ *          handle: Handle to the MLE to be queried.
+ *          bytes: A pointer to a variable to return the total bytes.
+ *          lines: A pointer to a variable to return the number of lines.
+ */
+void API dw_mle_get_size(HWND handle, unsigned long *bytes, unsigned long *lines)
+{
+	if(bytes)
+		*bytes = (unsigned long)WinSendMsg(handle, MLM_QUERYTEXTLENGTH, 0, 0);
+	if(lines)
+		*lines = (unsigned long)WinSendMsg(handle, MLM_QUERYLINECOUNT, 0, 0);
+}
+
+/*
+ * Deletes text from an MLE box.
+ * Parameters:
+ *          handle: Handle to the MLE to be deleted from.
+ *          startpoint: Point to start deleting text.
+ *          length: Amount of text to be deleted.
+ */
+void API dw_mle_delete(HWND handle, int startpoint, int length)
+{
+	char *buf = malloc(length+1);
+	int z, dellen = length;
+
+	dw_mle_export(handle, buf, startpoint, length);
+
+	for(z=0;z<length-1;z++)
+	{
+		if(strncmp(&buf[z], "\r\n", 2) == 0)
+			dellen--;
+	}
+	WinSendMsg(handle, MLM_DELETE, MPFROMLONG(startpoint), MPFROMLONG(dellen));
+	free(buf);
+}
+
+/*
+ * Clears all text from an MLE box.
+ * Parameters:
+ *          handle: Handle to the MLE to be cleared.
+ */
+void API dw_mle_clear(HWND handle)
+{
+	unsigned long bytes;
+
+	dw_mle_get_size(handle, &bytes, NULL);
+
+	WinSendMsg(handle, MLM_DELETE, MPFROMLONG(0), MPFROMLONG(bytes));
+}
+
+/*
+ * Sets the visible line of an MLE box.
+ * Parameters:
+ *          handle: Handle to the MLE to be positioned.
+ *          line: Line to be visible.
+ */
+void API dw_mle_set_visible(HWND handle, int line)
+{
+	int tmppnt = (int)WinSendMsg(handle, MLM_CHARFROMLINE, MPFROMLONG(line), 0);
+	WinSendMsg(handle, MLM_SETSEL, MPFROMLONG(tmppnt), MPFROMLONG(tmppnt));
+}
+
+/*
+ * Sets the editablity of an MLE box.
+ * Parameters:
+ *          handle: Handle to the MLE.
+ *          state: TRUE if it can be edited, FALSE for readonly.
+ */
+void API dw_mle_set_editable(HWND handle, int state)
+{
+	WinSendMsg(handle, MLM_SETREADONLY, MPFROMLONG(state ? FALSE : TRUE), 0);
+}
+
+/*
+ * Sets the word wrap state of an MLE box.
+ * Parameters:
+ *          handle: Handle to the MLE.
+ *          state: TRUE if it wraps, FALSE if it doesn't.
+ */
+void API dw_mle_set_word_wrap(HWND handle, int state)
+{
+	WinSendMsg(handle, MLM_SETWRAP, MPFROMLONG(state), 0);
+}
+
+/*
+ * Sets the current cursor position of an MLE box.
+ * Parameters:
+ *          handle: Handle to the MLE to be positioned.
+ *          point: Point to position cursor.
+ */
+void API dw_mle_set_cursor(HWND handle, int point)
+{
+	WinSendMsg(handle, MLM_SETSEL, MPFROMLONG(point), MPFROMLONG(point));
+}
+
+/*
+ * Finds text in an MLE box.
+ * Parameters:
+ *          handle: Handle to the MLE to be cleared.
+ *          text: Text to search for.
+ *          point: Start point of search.
+ *          flags: Search specific flags.
+ */
+int API dw_mle_search(HWND handle, char *text, int point, unsigned long flags)
+{
+	MLE_SEARCHDATA msd;
+
+	/* This code breaks with structure packing set to 1 (/Sp1 in VAC)
+	 * if this is needed we need to add a pragma here.
+	 */
+	msd.cb = sizeof(msd);
+	msd.pchFind = text;
+	msd.pchReplace = NULL;
+	msd.cchFind = strlen(text);
+	msd.cchReplace = 0;
+	msd.iptStart = point;
+	msd.iptStop = -1;
+
+	if(WinSendMsg(handle, MLM_SEARCH, MPFROMLONG(MLFSEARCH_SELECTMATCH | flags), (MPARAM)&msd))
+		return (int)WinSendMsg(handle, MLM_QUERYSEL,(MPARAM)MLFQS_MAXSEL, 0);
+	return 0;
+}
+
+/*
+ * Stops redrawing of an MLE box.
+ * Parameters:
+ *          handle: Handle to the MLE to freeze.
+ */
+void API dw_mle_freeze(HWND handle)
+{
+	WinSendMsg(handle, MLM_DISABLEREFRESH, 0, 0);
+}
+
+/*
+ * Resumes redrawing of an MLE box.
+ * Parameters:
+ *          handle: Handle to the MLE to thaw.
+ */
+void API dw_mle_thaw(HWND handle)
+{
+	WinSendMsg(handle, MLM_ENABLEREFRESH, 0, 0);
+}
+
+/*
+ * Sets the percent bar position.
+ * Parameters:
+ *          handle: Handle to the percent bar to be set.
+ *          position: Position of the percent bar withing the range.
+ */
+void API dw_percent_set_pos(HWND handle, unsigned int position)
+{
+	int range = _dw_percent_get_range(handle);
+	int mypos = ((float)position/100)*range;
+
+	if(range)
+	{
+		_dw_int_set(handle, mypos);
+		WinSendMsg(handle, SLM_SETSLIDERINFO, MPFROM2SHORT(SMA_SLIDERARMPOSITION,SMA_RANGEVALUE), (MPARAM)mypos);
+	}
+}
+
+/*
+ * Returns the position of the slider.
+ * Parameters:
+ *          handle: Handle to the slider to be queried.
+ */
+unsigned int API dw_slider_get_pos(HWND handle)
+{
+	return (unsigned int)WinSendMsg(handle, SLM_QUERYSLIDERINFO, MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_INCREMENTVALUE), 0);
+}
+
+/*
+ * Sets the slider position.
+ * Parameters:
+ *          handle: Handle to the slider to be set.
+ *          position: Position of the slider withing the range.
+ */
+void API dw_slider_set_pos(HWND handle, unsigned int position)
+{
+	dw_window_set_data(handle, "_dw_slider_value", (void *)position);
+	WinSendMsg(handle, SLM_SETSLIDERINFO, MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_INCREMENTVALUE), (MPARAM)position);
+}
+
+/*
+ * Returns the position of the scrollbar.
+ * Parameters:
+ *          handle: Handle to the scrollbar to be queried.
+ */
+unsigned int API dw_scrollbar_get_pos(HWND handle)
+{
+	return (unsigned int)WinSendMsg(handle, SBM_QUERYPOS, 0, 0);
+}
+
+/*
+ * Sets the scrollbar position.
+ * Parameters:
+ *          handle: Handle to the scrollbar to be set.
+ *          position: Position of the scrollbar withing the range.
+ */
+void API dw_scrollbar_set_pos(HWND handle, unsigned int position)
+{
+	dw_window_set_data(handle, "_dw_scrollbar_value", (void *)position);
+	WinSendMsg(handle, SBM_SETPOS, (MPARAM)position, 0);
+}
+
+/*
+ * Sets the scrollbar range.
+ * Parameters:
+ *          handle: Handle to the scrollbar to be set.
+ *          range: Maximum range value.
+ *          visible: Visible area relative to the range.
+ */
+void API dw_scrollbar_set_range(HWND handle, unsigned int range, unsigned int visible)
+{
+	unsigned int pos = (unsigned int)dw_window_get_data(handle, "_dw_scrollbar_value");
+	WinSendMsg(handle, SBM_SETSCROLLBAR, (MPARAM)pos, MPFROM2SHORT(0, (unsigned short)range - visible));
+	WinSendMsg(handle, SBM_SETTHUMBSIZE, MPFROM2SHORT((unsigned short)visible, range), 0);
+	dw_window_set_data(handle, "_dw_scrollbar_visible", (void *)visible);
+}
+
+/*
+ * Sets the spinbutton value.
+ * Parameters:
+ *          handle: Handle to the spinbutton to be set.
+ *          position: Current value of the spinbutton.
+ */
+void API dw_spinbutton_set_pos(HWND handle, long position)
+{
+	WinSendMsg(handle, SPBM_SETCURRENTVALUE, MPFROMLONG((long)position), 0L);
+}
+
+/*
+ * Sets the spinbutton limits.
+ * Parameters:
+ *          handle: Handle to the spinbutton to be set.
+ *          upper: Upper limit.
+ *          lower: Lower limit.
+ */
+void API dw_spinbutton_set_limits(HWND handle, long upper, long lower)
+{
+	WinSendMsg(handle, SPBM_SETLIMITS, MPFROMLONG(upper), MPFROMLONG(lower));
+}
+
+/*
+ * Sets the entryfield character limit.
+ * Parameters:
+ *          handle: Handle to the spinbutton to be set.
+ *          limit: Number of characters the entryfield will take.
+ */
+void API dw_entryfield_set_limit(HWND handle, ULONG limit)
+{
+	WinSendMsg(handle, EM_SETTEXTLIMIT, (MPARAM)limit, (MPARAM)0);
+}
+
+
+/*
+ * Returns the current value of the spinbutton.
+ * Parameters:
+ *          handle: Handle to the spinbutton to be queried.
+ */
+long API dw_spinbutton_get_pos(HWND handle)
+{
+	long tmpval = 0L;
+
+	WinSendMsg(handle, SPBM_QUERYVALUE, (MPARAM)&tmpval,0L);
+    return tmpval;
+}
+
+/*
+ * Returns the state of the checkbox.
+ * Parameters:
+ *          handle: Handle to the checkbox to be queried.
+ */
+int API dw_checkbox_get(HWND handle)
+{
+	return (int)WinSendMsg(handle,BM_QUERYCHECK,0,0);
+}
+
+/*
+ * Sets the state of the checkbox.
+ * Parameters:
+ *          handle: Handle to the checkbox to be queried.
+ *          value: TRUE for checked, FALSE for unchecked.
+ */
+void API dw_checkbox_set(HWND handle, int value)
+{
+	WinSendMsg(handle,BM_SETCHECK,MPFROMSHORT(value),0);
+}
+
+/*
+ * Inserts an item into a tree window (widget) after another item.
+ * Parameters:
+ *          handle: Handle to the tree to be inserted.
+ *          item: Handle to the item to be positioned after.
+ *          title: The text title of the entry.
+ *          icon: Handle to coresponding icon.
+ *          parent: Parent handle or 0 if root.
+ *          itemdata: Item specific data.
+ */
+HTREEITEM API dw_tree_insert_after(HWND handle, HTREEITEM item, char *title, unsigned long icon, HTREEITEM parent, void *itemdata)
+{
+	ULONG        cbExtra;
+	PCNRITEM     pci;
+	RECORDINSERT ri;
+
+	if(!item)
+		item = (HTREEITEM)CMA_FIRST;
+
+	/* Calculate extra bytes needed for each record besides that needed for the
+	 * MINIRECORDCORE structure
+	 */
+
+	cbExtra = sizeof(CNRITEM) - sizeof(MINIRECORDCORE);
+
+	/* Allocate memory for the parent record */
+
+	if((pci = (PCNRITEM)_dw_send_msg(handle, CM_ALLOCRECORD, MPFROMLONG(cbExtra), MPFROMSHORT(1), 0)) == 0)
+		return 0;
+
+	/* Fill in the parent record data */
+
+	pci->rc.cb          = sizeof(MINIRECORDCORE);
+	pci->rc.pszIcon     = strdup(title);
+	pci->rc.hptrIcon    = icon;
+
+	pci->hptrIcon       = icon;
+	pci->user           = itemdata;
+	pci->parent         = parent;
+
+	memset(&ri, 0, sizeof(RECORDINSERT));
+
+	ri.cb                 = sizeof(RECORDINSERT);
+	ri.pRecordOrder       = (PRECORDCORE)item;
+	ri.zOrder             = (USHORT)CMA_TOP;
+	ri.cRecordsInsert     = 1;
+	ri.fInvalidateRecord  = TRUE;
+
+	/* We are about to insert the child records. Set the parent record to be
+	 * the one we just inserted.
+	 */
+	ri.pRecordParent = (PRECORDCORE)parent;
+
+	/* Insert the record */
+	WinSendMsg(handle, CM_INSERTRECORD, MPFROMP(pci), MPFROMP(&ri));
+
+	return (HTREEITEM)pci;
+}
+
+/*
+ * Inserts an item into a tree window (widget).
+ * Parameters:
+ *          handle: Handle to the tree to be inserted.
+ *          title: The text title of the entry.
+ *          icon: Handle to coresponding icon.
+ *          parent: Parent handle or 0 if root.
+ *          itemdata: Item specific data.
+ */
+HTREEITEM API dw_tree_insert(HWND handle, char *title, unsigned long icon, HTREEITEM parent, void *itemdata)
+{
+	return dw_tree_insert_after(handle, (HTREEITEM)CMA_END, title, icon, parent, itemdata);
+}
+
+/*
+ * Sets the text and icon of an item in a tree window (widget).
+ * Parameters:
+ *          handle: Handle to the tree containing the item.
+ *          item: Handle of the item to be modified.
+ *          title: The text title of the entry.
+ *          icon: Handle to coresponding icon.
+ */
+void API dw_tree_item_change(HWND handle, HTREEITEM item, char *title, unsigned long icon)
+{
+	PCNRITEM pci = (PCNRITEM)item;
+
+	if(!pci)
+		return;
+
+	if(pci->rc.pszIcon)
+		free(pci->rc.pszIcon);
+
+	pci->rc.pszIcon     = strdup(title);
+	pci->rc.hptrIcon    = icon;
+
+	pci->hptrIcon       = icon;
+
+	WinSendMsg(handle, CM_INVALIDATERECORD, (MPARAM)&pci, MPFROM2SHORT(1, CMA_TEXTCHANGED));
+}
+
+/*
+ * Gets the text an item in a tree window (widget).
+ * Parameters:
+ *          handle: Handle to the tree containing the item.
+ *          item: Handle of the item to be modified.
+ */
+char * API dw_tree_get_title(HWND handle, HTREEITEM item)
+{
+	PCNRITEM pci = (PCNRITEM)item;
+
+	handle = handle; /* keep compiler happy */
+	if(pci)
+		return pci->rc.pszIcon;
+	return NULL;
+}
+
+/*
+ * Gets the text an item in a tree window (widget).
+ * Parameters:
+ *          handle: Handle to the tree containing the item.
+ *          item: Handle of the item to be modified.
+ */
+HTREEITEM API dw_tree_get_parent(HWND handle, HTREEITEM item)
+{
+	PCNRITEM pci = (PCNRITEM)item;
+
+	handle = handle; /* keep compiler happy */
+	if(pci)
+		return pci->parent;
+	return (HTREEITEM)0;
+}
+
+/*
+ * Sets the item data of a tree item.
+ * Parameters:
+ *          handle: Handle to the tree containing the item.
+ *          item: Handle of the item to be modified.
+ *          itemdata: User defined data to be associated with item.
+ */
+void API dw_tree_item_set_data(HWND handle, HTREEITEM item, void *itemdata)
+{
+	PCNRITEM pci = (PCNRITEM)item;
+
+	handle = handle; /* keep compiler happy */
+	if(!pci)
+		return;
+
+	pci->user = itemdata;
+}
+
+/*
+ * Gets the item data of a tree item.
+ * Parameters:
+ *          handle: Handle to the tree containing the item.
+ *          item: Handle of the item to be modified.
+ */
+void * API dw_tree_item_get_data(HWND handle, HTREEITEM item)
+{
+	PCNRITEM pci = (PCNRITEM)item;
+
+	handle = handle; /* keep compiler happy */
+	if(!pci)
+		return NULL;
+	return pci->user;
+}
+
+/*
+ * Sets this item as the active selection.
+ * Parameters:
+ *       handle: Handle to the tree window (widget) to be selected.
+ *       item: Handle to the item to be selected.
+ */
+void API dw_tree_item_select(HWND handle, HTREEITEM item)
+{
+	PRECORDCORE pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)0L, MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
+
+	while(pCore)
+	{
+		if(pCore->flRecordAttr & CRA_SELECTED)
+			WinSendMsg(handle, CM_SETRECORDEMPHASIS, (MPARAM)pCore, MPFROM2SHORT(FALSE, CRA_SELECTED | CRA_CURSORED));
+		pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)pCore, MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
+	}
+	WinSendMsg(handle, CM_SETRECORDEMPHASIS, (MPARAM)item, MPFROM2SHORT(TRUE, CRA_SELECTED | CRA_CURSORED));
+	lastitem = 0;
+	lasthcnr = 0;
+}
+
+/*
+ * Removes all nodes from a tree.
+ * Parameters:
+ *       handle: Handle to the window (widget) to be cleared.
+ */
+void API dw_tree_clear(HWND handle)
+{
+	dw_container_clear(handle, TRUE);
+}
+
+/*
+ * Expands a node on a tree.
+ * Parameters:
+ *       handle: Handle to the tree window (widget).
+ *       item: Handle to node to be expanded.
+ */
+void API dw_tree_item_expand(HWND handle, HTREEITEM item)
+{
+	WinSendMsg(handle, CM_EXPANDTREE, MPFROMP(item), 0);
+}
+
+/*
+ * Collapses a node on a tree.
+ * Parameters:
+ *       handle: Handle to the tree window (widget).
+ *       item: Handle to node to be collapsed.
+ */
+void API dw_tree_item_collapse(HWND handle, HTREEITEM item)
+{
+	WinSendMsg(handle, CM_COLLAPSETREE, MPFROMP(item), 0);
+}
+
+/*
+ * Removes a node from a tree.
+ * Parameters:
+ *       handle: Handle to the window (widget) to be cleared.
+ *       item: Handle to node to be deleted.
+ */
+void API dw_tree_item_delete(HWND handle, HTREEITEM item)
+{
+	PCNRITEM     pci = (PCNRITEM)item;
+
+	if(!item)
+		return;
+
+	if(pci->rc.pszIcon)
+	{
+		free(pci->rc.pszIcon);
+		pci->rc.pszIcon = 0;
+	}
+
+	WinSendMsg(handle, CM_REMOVERECORD, (MPARAM)&pci, MPFROM2SHORT(1, CMA_INVALIDATE | CMA_FREE));
+}
+
+/* Some OS/2 specific container structs */
+typedef struct _containerinfo {
+	int count;
+	void *data;
+	HWND handle;
+} ContainerInfo;
+
+/*
+ * Sets up the container columns.
+ * Parameters:
+ *          handle: Handle to the container to be configured.
+ *          flags: An array of unsigned longs with column flags.
+ *          titles: An array of strings with column text titles.
+ *          count: The number of columns (this should match the arrays).
+ *          separator: The column number that contains the main separator.
+ *                     (this item may only be used in OS/2)
+ */
+int API dw_container_setup(HWND handle, unsigned long *flags, char **titles, int count, int separator)
+{
+	PFIELDINFO details, first, left = NULL;
+	FIELDINFOINSERT detin;
+	CNRINFO cnri;
+	int z;
+	ULONG size = sizeof(RECORDCORE);
+	ULONG *offStruct = malloc(count * sizeof(ULONG));
+	ULONG *tempflags = malloc((count+1) * sizeof(ULONG));
+	WindowData *blah = (WindowData *)WinQueryWindowPtr(handle, QWP_USER);
+	ULONG *oldflags = blah ? blah->data : 0;
+
+	if(!offStruct || !tempflags)
+		return FALSE;
+
+	memcpy(tempflags, flags, count * sizeof(ULONG));
+	tempflags[count] = 0;
+
+	blah->data = tempflags;
+	blah->flags = separator;
+
+	if(oldflags)
+		free(oldflags);
+
+	while((first = (PFIELDINFO)WinSendMsg(handle, CM_QUERYDETAILFIELDINFO,  0, MPFROMSHORT(CMA_FIRST))) != NULL)
+	{
+		WinSendMsg(handle, CM_REMOVEDETAILFIELDINFO, (MPARAM)&first, MPFROM2SHORT(1, CMA_FREE));
+	}
+
+	/* Figure out the offsets to the items in the struct */
+	for(z=0;z<count;z++)
+	{
+		offStruct[z] = size;
+		if(flags[z] & DW_CFA_BITMAPORICON)
+			size += sizeof(HPOINTER);
+		else if(flags[z] & DW_CFA_STRING)
+			size += sizeof(char *);
+		else if(flags[z] & DW_CFA_ULONG)
+			size += sizeof(ULONG);
+		else if(flags[z] & DW_CFA_DATE)
+			size += sizeof(CDATE);
+		else if(flags[z] & DW_CFA_TIME)
+			size += sizeof(CTIME);
+	}
+
+	first = details = (PFIELDINFO)WinSendMsg(handle, CM_ALLOCDETAILFIELDINFO, MPFROMLONG(count), 0L);
+
+	if(!first)
+	{
+		free(offStruct);
+		return FALSE;
+	}
+
+	for(z=0;z<count;z++)
+	{
+		if(z==separator-1)
+			left=details;
+		details->cb = sizeof(FIELDINFO);
+		details->flData = flags[z];
+		details->flTitle = CFA_FITITLEREADONLY;
+		details->pTitleData = titles[z];
+		details->offStruct = offStruct[z];
+		details = details->pNextFieldInfo;
+	}
+
+	detin.cb = sizeof(FIELDINFOINSERT);
+	detin.fInvalidateFieldInfo = FALSE;
+	detin.pFieldInfoOrder = (PFIELDINFO) CMA_FIRST;
+	detin.cFieldInfoInsert = (ULONG)count;
+
+	WinSendMsg(handle, CM_INSERTDETAILFIELDINFO, MPFROMP(first), MPFROMP(&detin));
+
+	if(count > separator && separator > 0)
+	{
+		cnri.cb = sizeof(CNRINFO);
+		cnri.pFieldInfoLast = left;
+		cnri.xVertSplitbar  = 150;
+
+		WinSendMsg(handle, CM_SETCNRINFO, MPFROMP(&cnri),  MPFROMLONG(CMA_PFIELDINFOLAST | CMA_XVERTSPLITBAR));
+	}
+
+	cnri.flWindowAttr = CV_DETAIL | CV_MINI | CA_DETAILSVIEWTITLES;
+	cnri.slBitmapOrIcon.cx = 16;
+	cnri.slBitmapOrIcon.cy = 16;
+
+	WinSendMsg(handle, CM_SETCNRINFO, &cnri, MPFROMLONG(CMA_FLWINDOWATTR | CMA_SLBITMAPORICON));
+
+	free(offStruct);
+	return TRUE;
+}
+
+/*
+ * Sets up the filesystem columns, note: filesystem always has an icon/filename field.
+ * Parameters:
+ *          handle: Handle to the container to be configured.
+ *          flags: An array of unsigned longs with column flags.
+ *          titles: An array of strings with column text titles.
+ *          count: The number of columns (this should match the arrays).
+ */
+int API dw_filesystem_setup(HWND handle, unsigned long *flags, char **titles, int count)
+{
+	char **newtitles = malloc(sizeof(char *) * (count + 2));
+	unsigned long *newflags = malloc(sizeof(unsigned long) * (count + 2));
+
+	newtitles[0] = "Icon";
+	newtitles[1] = "Filename";
+
+	newflags[0] = DW_CFA_BITMAPORICON | DW_CFA_CENTER | DW_CFA_HORZSEPARATOR | DW_CFA_SEPARATOR;
+	newflags[1] = DW_CFA_STRING | DW_CFA_LEFT | DW_CFA_HORZSEPARATOR;
+
+	memcpy(&newtitles[2], titles, sizeof(char *) * count);
+	memcpy(&newflags[2], flags, sizeof(unsigned long) * count);
+
+	dw_container_setup(handle, newflags, newtitles, count + 2, count ? 2 : 0);
+
+	free(newtitles);
+	free(newflags);
+	return TRUE;
+}
+
+/*
+ * Obtains an icon from a module (or header in GTK).
+ * Parameters:
+ *          module: Handle to module (DLL) in OS/2 and Windows.
+ *          id: A unsigned long id int the resources on OS/2 and
+ *              Windows, on GTK this is converted to a pointer
+ *              to an embedded XPM.
+ */
+unsigned long API dw_icon_load(unsigned long module, unsigned long id)
+{
+	return WinLoadPointer(HWND_DESKTOP,module,id);
+}
+
+/*
+ * Obtains an icon from a file.
+ * Parameters:
+ *       filename: Name of the file, omit extention to have
+ *                 DW pick the appropriate file extension.
+ *                 (ICO on OS/2 or Windows, XPM on Unix)
+ */
+unsigned long API dw_icon_load_from_file(char *filename)
+{
+	char *file = alloca(strlen(filename) + 5);
+
+	if(!file)
+		return 0;
+
+	strcpy(file, filename);
+
+	/* check if we can read from this file (it exists and read permission) */
+	if(access(file, 04) != 0)
+	{
+		/* Try with .bmp extention */
+		strcat(file, ".ico");
+		if(access(file, 04) != 0)
+			return 0;
+	}
+	return WinLoadFileIcon(file, FALSE);
+}
+
+/*
+ * Frees a loaded resource in OS/2 and Windows.
+ * Parameters:
+ *          handle: Handle to icon returned by dw_icon_load().
+ */
+void API dw_icon_free(unsigned long handle)
+{
+	WinDestroyPointer(handle);
+}
+
+/*
+ * Allocates memory used to populate a container.
+ * Parameters:
+ *          handle: Handle to the container window (widget).
+ *          rowcount: The number of items to be populated.
+ */
+void * API dw_container_alloc(HWND handle, int rowcount)
+{
+	WindowData *wd = (WindowData *)WinQueryWindowPtr(handle, QWP_USER);
+	ULONG *flags = wd ? wd->data : 0;
+	int z, size = 0, totalsize, count = 0;
+	PRECORDCORE temp;
+	ContainerInfo *ci;
+	void *blah = NULL;
+
+	if(!flags || rowcount < 1)
+		return NULL;
+
+	while(flags[count])
+		count++;
+
+	/* Figure out the offsets to the items in the struct */
+	for(z=0;z<count;z++)
+	{
+		if(flags[z] & DW_CFA_BITMAPORICON)
+			size += sizeof(HPOINTER);
+		else if(flags[z] & DW_CFA_STRING)
+			size += sizeof(char *);
+		else if(flags[z] & DW_CFA_ULONG)
+			size += sizeof(ULONG);
+		else if(flags[z] & DW_CFA_DATE)
+			size += sizeof(CDATE);
+		else if(flags[z] & DW_CFA_TIME)
+			size += sizeof(CTIME);
+	}
+
+	totalsize = size + sizeof(RECORDCORE);
+
+	z = 0;
+
+	if(!(blah = (void *)_dw_send_msg(handle, CM_ALLOCRECORD, MPFROMLONG(size), MPFROMLONG(rowcount), 0)))
+		return NULL;
+
+	temp = (PRECORDCORE)blah;
+
+	for(z=0;z<rowcount;z++)
+	{
+		temp->cb = totalsize;
+		temp = temp->preccNextRecord;
+	}
+
+	ci = malloc(sizeof(struct _containerinfo));
+
+	ci->count = rowcount;
+	ci->data = blah;
+	ci->handle = handle;
+
+	return (void *)ci;
+}
+
+/* Internal function that does the work for set_item and change_item */
+void _dw_container_set_item(HWND handle, PRECORDCORE temp, int column, int row, void *data)
+{
+	WindowData *blah = (WindowData *)WinQueryWindowPtr(handle, QWP_USER);
+	ULONG totalsize, size = 0, *flags = blah ? blah->data : 0;
+	int z, currentcount;
+	CNRINFO cnr;
+    void *dest;
+
+	if(!flags)
+		return;
+
+	if(!_dw_send_msg(handle, CM_QUERYCNRINFO, (MPARAM)&cnr, MPFROMSHORT(sizeof(CNRINFO)), 0))
+		return;
+
+	currentcount = cnr.cRecords;
+
+	/* Figure out the offsets to the items in the struct */
+	for(z=0;z<column;z++)
+	{
+		if(flags[z] & DW_CFA_BITMAPORICON)
+			size += sizeof(HPOINTER);
+		else if(flags[z] & DW_CFA_STRING)
+			size += sizeof(char *);
+		else if(flags[z] & DW_CFA_ULONG)
+			size += sizeof(ULONG);
+		else if(flags[z] & DW_CFA_DATE)
+			size += sizeof(CDATE);
+		else if(flags[z] & DW_CFA_TIME)
+			size += sizeof(CTIME);
+	}
+
+	totalsize = size + sizeof(RECORDCORE);
+
+	for(z=0;z<(row-currentcount);z++)
+		temp = temp->preccNextRecord;
+
+	dest = (void *)(((ULONG)temp)+((ULONG)totalsize));
+
+	if(flags[column] & DW_CFA_BITMAPORICON)
+		memcpy(dest, data, sizeof(HPOINTER));
+	else if(flags[column] & DW_CFA_STRING)
+	{
+		char **newstr = (char **)data, **str = dest;
+
+		if(*str)
+			free(*str);
+
+		if(newstr && *newstr)
+			*str = strdup(*newstr);
+		else
+			*str = NULL;
+	}
+	else if(flags[column] & DW_CFA_ULONG)
+		memcpy(dest, data, sizeof(ULONG));
+	else if(flags[column] & DW_CFA_DATE)
+		memcpy(dest, data, sizeof(CDATE));
+	else if(flags[column] & DW_CFA_TIME)
+		memcpy(dest, data, sizeof(CTIME));
+}
+
+/* Internal function that free()s any strings allocated for a container item */
+void _dw_container_free_strings(HWND handle, PRECORDCORE temp)
+{
+	WindowData *blah = (WindowData *)WinQueryWindowPtr(handle, QWP_USER);
+	ULONG totalsize, size = 0, *flags = blah ? blah->data : 0;
+	int z, count = 0;
+
+	if(!flags)
+		return;
+
+	while(flags[count])
+		count++;
+
+	/* Figure out the offsets to the items in the struct */
+	for(z=0;z<count;z++)
+	{
+		if(flags[z] & DW_CFA_BITMAPORICON)
+			size += sizeof(HPOINTER);
+		else if(flags[z] & DW_CFA_STRING)
+		{
+			char **str;
+
+			totalsize = size + sizeof(RECORDCORE);
+
+			str = (char **)(((ULONG)temp)+((ULONG)totalsize));
+
+			if(*str)
+			{
+				free(*str);
+				*str = NULL;
+			}
+			size += sizeof(char *);
+		}
+		else if(flags[z] & DW_CFA_ULONG)
+			size += sizeof(ULONG);
+		else if(flags[z] & DW_CFA_DATE)
+			size += sizeof(CDATE);
+		else if(flags[z] & DW_CFA_TIME)
+			size += sizeof(CTIME);
+	}
+}
+
+/*
+ * Sets an item in specified row and column to the given data.
+ * Parameters:
+ *          handle: Handle to the container window (widget).
+ *          pointer: Pointer to the allocated memory in dw_container_alloc().
+ *          column: Zero based column of data being set.
+ *          row: Zero based row of data being set.
+ *          data: Pointer to the data to be added.
+ */
+void API dw_container_set_item(HWND handle, void *pointer, int column, int row, void *data)
+{
+	ContainerInfo *ci = (ContainerInfo *)pointer;
+
+	if(!ci)
+		return;
+
+	_dw_container_set_item(handle, (PRECORDCORE)ci->data, column, row, data);
+}
+
+/*
+ * Changes an existing item in specified row and column to the given data.
+ * Parameters:
+ *          handle: Handle to the container window (widget).
+ *          column: Zero based column of data being set.
+ *          row: Zero based row of data being set.
+ *          data: Pointer to the data to be added.
+ */
+void API dw_container_change_item(HWND handle, int column, int row, void *data)
+{
+	PRECORDCORE pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)0L, MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
+	int count = 0;
+
+	while(pCore)
+	{
+		if(count == row)
+		{
+			_dw_container_set_item(handle, pCore, column, 0, data);
+			WinSendMsg(handle, CM_INVALIDATERECORD, (MPARAM)&pCore, MPFROM2SHORT(1, CMA_NOREPOSITION | CMA_TEXTCHANGED));
+			return;
+		}
+		pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)pCore, MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
+		count++;
+	}
+}
+
+/*
+ * Changes an existing item in specified row and column to the given data.
+ * Parameters:
+ *          handle: Handle to the container window (widget).
+ *          column: Zero based column of data being set.
+ *          row: Zero based row of data being set.
+ *          data: Pointer to the data to be added.
+ */
+void API dw_filesystem_change_item(HWND handle, int column, int row, void *data)
+{
+	dw_container_change_item(handle, column + 2, row, data);
+}
+
+/*
+ * Changes an item in specified row and column to the given data.
+ * Parameters:
+ *          handle: Handle to the container window (widget).
+ *          pointer: Pointer to the allocated memory in dw_container_alloc().
+ *          column: Zero based column of data being set.
+ *          row: Zero based row of data being set.
+ *          data: Pointer to the data to be added.
+ */
+void API dw_filesystem_change_file(HWND handle, int row, char *filename, unsigned long icon)
+{
+	dw_container_change_item(handle, 0, row, (void *)&icon);
+	dw_container_change_item(handle, 1, row, (void *)&filename);
+}
+
+/*
+ * Sets an item in specified row and column to the given data.
+ * Parameters:
+ *          handle: Handle to the container window (widget).
+ *          pointer: Pointer to the allocated memory in dw_container_alloc().
+ *          column: Zero based column of data being set.
+ *          row: Zero based row of data being set.
+ *          data: Pointer to the data to be added.
+ */
+void API dw_filesystem_set_file(HWND handle, void *pointer, int row, char *filename, unsigned long icon)
+{
+	dw_container_set_item(handle, pointer, 0, row, (void *)&icon);
+	dw_container_set_item(handle, pointer, 1, row, (void *)&filename);
+}
+
+/*
+ * Sets an item in specified row and column to the given data.
+ * Parameters:
+ *          handle: Handle to the container window (widget).
+ *          pointer: Pointer to the allocated memory in dw_container_alloc().
+ *          column: Zero based column of data being set.
+ *          row: Zero based row of data being set.
+ *          data: Pointer to the data to be added.
+ */
+void API dw_filesystem_set_item(HWND handle, void *pointer, int column, int row, void *data)
+{
+	dw_container_set_item(handle, pointer, column + 2, row, data);
+}
+
+/*
+ * Gets column type for a container column
+ * Parameters:
+ *          handle: Handle to the container window (widget).
+ *          column: Zero based column.
+ */
+int API dw_container_get_column_type(HWND handle, int column)
+{
+	WindowData *blah = (WindowData *)WinQueryWindowPtr(handle, QWP_USER);
+	ULONG *flags = blah ? blah->data : 0;
+	int rc;
+
+	if(!flags)
+		return 0;
+
+	if(flags[column] & DW_CFA_BITMAPORICON)
+		rc = DW_CFA_BITMAPORICON;
+	else if(flags[column] & DW_CFA_STRING)
+		rc = DW_CFA_STRING;
+	else if(flags[column] & DW_CFA_ULONG)
+		rc = DW_CFA_ULONG;
+	else if(flags[column] & DW_CFA_DATE)
+		rc = DW_CFA_DATE;
+	else if(flags[column] & DW_CFA_TIME)
+		rc = DW_CFA_TIME;
+	else
+		rc = 0;
+	return rc;
+}
+
+/*
+ * Gets column type for a filesystem container column
+ * Parameters:
+ *          handle: Handle to the container window (widget).
+ *          column: Zero based column.
+ */
+int API dw_filesystem_get_column_type(HWND handle, int column)
+{
+	return dw_container_get_column_type( handle, column + 2 );
+}
+
+/*
+ * Sets the width of a column in the container.
+ * Parameters:
+ *          handle: Handle to window (widget) of container.
+ *          column: Zero based column of width being set.
+ *          width: Width of column in pixels.
+ */
+void API dw_container_set_column_width(HWND handle, int column, int width)
+{
+	handle = handle; /* keep compiler happy */
+	column = column; /* keep compiler happy */
+	width = width; /* keep compiler happy */
+}
+
+/*
+ * Sets the title of a row in the container.
+ * Parameters:
+ *          pointer: Pointer to the allocated memory in dw_container_alloc().
+ *          row: Zero based row of data being set.
+ *          title: String title of the item.
+ */
+void API dw_container_set_row_title(void *pointer, int row, char *title)
+{
+	ContainerInfo *ci = (ContainerInfo *)pointer;
+	PRECORDCORE temp;
+	int z, currentcount;
+	CNRINFO cnr;
+
+	if(!ci)
+		return;
+
+	temp = (PRECORDCORE)ci->data;
+
+	z = 0;
+
+	if(!_dw_send_msg(ci->handle, CM_QUERYCNRINFO, (MPARAM)&cnr, MPFROMSHORT(sizeof(CNRINFO)), 0))
+		return;
+
+	currentcount = cnr.cRecords;
+
+	for(z=0;z<(row-currentcount);z++)
+		temp = temp->preccNextRecord;
+
+	temp->pszIcon = title;
+	temp->pszName = title;
+	temp->pszText = title;
+}
+
+/*
+ * Sets the title of a row in the container.
+ * Parameters:
+ *          handle: Handle to the container window (widget).
+ *          pointer: Pointer to the allocated memory in dw_container_alloc().
+ *          rowcount: The number of rows to be inserted.
+ */
+void API dw_container_insert(HWND handle, void *pointer, int rowcount)
+{
+	RECORDINSERT recin;
+	ContainerInfo *ci = (ContainerInfo *)pointer;
+
+	if(!ci)
+		return;
+
+	recin.cb = sizeof(RECORDINSERT);
+	recin.pRecordOrder = (PRECORDCORE)CMA_END;
+	recin.pRecordParent = NULL;
+	recin.zOrder = CMA_TOP;
+	recin.fInvalidateRecord = TRUE;
+	recin.cRecordsInsert = rowcount;
+
+	_dw_send_msg(handle, CM_INSERTRECORD, MPFROMP(ci->data), MPFROMP(&recin), 0);
+
+	free(ci);
+}
+
+/*
+ * Removes all rows from a container.
+ * Parameters:
+ *       handle: Handle to the window (widget) to be cleared.
+ *       redraw: TRUE to cause the container to redraw immediately.
+ */
+void API dw_container_clear(HWND handle, int redraw)
+{
+	PCNRITEM pCore;
+	int container = (int)dw_window_get_data(handle, "_dw_container");
+
+	if(hwndEmph == handle)
+		_clear_emphasis();
+
+	pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)0L, MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
+
+	while(pCore)
+	{
+		if(container)
+			_dw_container_free_strings(handle, (PRECORDCORE)pCore);
+		else
+		{
+			/* Free icon text */
+			if(pCore->rc.pszIcon)
+			{
+				free(pCore->rc.pszIcon);
+				pCore->rc.pszIcon = 0;
+			}
+		}
+		pCore = (PCNRITEM)pCore->rc.preccNextRecord;/*WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)pCore, MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));*/
+	}
+	_dw_send_msg(handle, CM_REMOVERECORD, (MPARAM)0L, MPFROM2SHORT(0, (redraw ? CMA_INVALIDATE : 0) | CMA_FREE), -1);
+}
+
+/*
+ * Removes the first x rows from a container.
+ * Parameters:
+ *       handle: Handle to the window (widget) to be deleted from.
+ *       rowcount: The number of rows to be deleted.
+ */
+void API dw_container_delete(HWND handle, int rowcount)
+{
+	RECORDCORE *last, **prc = malloc(sizeof(RECORDCORE *) * rowcount);
+	int current = 1;
+
+	prc[0] = last = (RECORDCORE *)WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)0L, MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
+
+	while(last && current < rowcount)
+	{
+		_dw_container_free_strings(handle, last);
+		prc[current] = last = (RECORDCORE *)WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)last, MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
+		current++;
+	}
+
+	_dw_send_msg(handle, CM_REMOVERECORD, (MPARAM)prc, MPFROM2SHORT(current, CMA_INVALIDATE | CMA_FREE), -1);
+	
+	free(prc);
+}
+
+/*
+ * Scrolls container up or down.
+ * Parameters:
+ *       handle: Handle to the window (widget) to be scrolled.
+ *       direction: DW_SCROLL_UP, DW_SCROLL_DOWN, DW_SCROLL_TOP or
+ *                  DW_SCROLL_BOTTOM. (rows is ignored for last two)
+ *       rows: The number of rows to be scrolled.
+ */
+void API dw_container_scroll(HWND handle, int direction, long rows)
+{
+	rows = rows; /* keep compiler happy */
+	switch(direction)
+	{
+	case DW_SCROLL_TOP:
+		WinSendMsg(handle, CM_SCROLLWINDOW, MPFROMSHORT(CMA_VERTICAL), MPFROMLONG(-10000000));
+        break;
+	case DW_SCROLL_BOTTOM:
+		WinSendMsg(handle, CM_SCROLLWINDOW, MPFROMSHORT(CMA_VERTICAL), MPFROMLONG(10000000));
+		break;
+	}
+}
+
+/*
+ * Starts a new query of a container.
+ * Parameters:
+ *       handle: Handle to the window (widget) to be queried.
+ *       flags: If this parameter is DW_CRA_SELECTED it will only
+ *              return items that are currently selected.  Otherwise
+ *              it will return all records in the container.
+ */
+char * API dw_container_query_start(HWND handle, unsigned long flags)
+{
+	PRECORDCORE pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)0L, MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
+
+	if(pCore)
+	{
+		if(flags)
+		{
+			while(pCore)
+			{
+				if(pCore->flRecordAttr & flags)
+				{
+					dw_window_set_data(handle, "_dw_pcore", (void *)pCore);
+					return pCore->pszIcon;
+				}
+				pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)pCore, MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
+			}
+		}
+		else
+		{
+			dw_window_set_data(handle, "_dw_pcore", (void *)pCore);
+			return pCore->pszIcon;
+		}
+	}
+    return NULL;
+}
+
+/*
+ * Continues an existing query of a container.
+ * Parameters:
+ *       handle: Handle to the window (widget) to be queried.
+ *       flags: If this parameter is DW_CRA_SELECTED it will only
+ *              return items that are currently selected.  Otherwise
+ *              it will return all records in the container.
+ */
+char * API dw_container_query_next(HWND handle, unsigned long flags)
+{
+	PRECORDCORE pCore = (PRECORDCORE)dw_window_get_data(handle, "_dw_pcore");
+
+	pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)pCore, MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
+
+	if(pCore)
+	{
+		if(flags)
+		{
+			while(pCore)
+			{
+				if(pCore->flRecordAttr & flags)
+				{
+					dw_window_set_data(handle, "_dw_pcore", (void *)pCore);
+					return pCore->pszIcon;
+				}
+
+				pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)pCore, MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
+			}
+		}
+		else
+		{
+			dw_window_set_data(handle, "_dw_pcore", (void *)pCore);
+			return pCore->pszIcon;
+		}
+	}
+    return NULL;
+}
+
+/*
+ * Cursors the item with the text speficied, and scrolls to that item.
+ * Parameters:
+ *       handle: Handle to the window (widget) to be queried.
+ *       text:  Text usually returned by dw_container_query().
+ */
+void API dw_container_cursor(HWND handle, char *text)
+{
+	RECTL viewport, item;
+	PRECORDCORE pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)0L, MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
+
+	while(pCore)
+	{
+		if((char *)pCore->pszIcon == text)
+		{
+			QUERYRECORDRECT qrr;
+			int scrollpixels = 0, midway;
+
+			qrr.cb = sizeof(QUERYRECORDRECT);
+			qrr.pRecord = pCore;
+			qrr.fRightSplitWindow = 0;
+			qrr.fsExtent = CMA_TEXT;
+
+			WinSendMsg(handle, CM_SETRECORDEMPHASIS, (MPARAM)pCore, MPFROM2SHORT(TRUE, CRA_CURSORED));
+			WinSendMsg(handle, CM_QUERYVIEWPORTRECT, (MPARAM)&viewport, MPFROM2SHORT(CMA_WORKSPACE, FALSE));
+			WinSendMsg(handle, CM_QUERYRECORDRECT, (MPARAM)&item, (MPARAM)&qrr);
+
+			midway = (viewport.yTop - viewport.yBottom)/2;
+			scrollpixels = viewport.yTop - (item.yTop + midway);
+
+			WinSendMsg(handle, CM_SCROLLWINDOW, MPFROMSHORT(CMA_VERTICAL),  MPFROMLONG(scrollpixels));
+			return;
+		}
+
+		pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)pCore, MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
+	}
+}
+
+/*
+ * Deletes the item with the text speficied.
+ * Parameters:
+ *       handle: Handle to the window (widget).
+ *       text:  Text usually returned by dw_container_query().
+ */
+void API dw_container_delete_row(HWND handle, char *text)
+{
+	PRECORDCORE pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)0L, MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
+
+	while(pCore)
+	{
+		if((char *)pCore->pszIcon == text)
+		{
+			WinSendMsg(handle, CM_REMOVERECORD, (MPARAM)&pCore, MPFROM2SHORT(1, CMA_FREE | CMA_INVALIDATE));
+			return;
+		}
+		pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)pCore, MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
+	}
+}
+
+/*
+ * Optimizes the column widths so that all data is visible.
+ * Parameters:
+ *       handle: Handle to the window (widget) to be optimized.
+ */
+void API dw_container_optimize(HWND handle)
+{
+	WindowData *blah = (WindowData *)WinQueryWindowPtr(handle, QWP_USER);
+	RECTL item;
+	PRECORDCORE pCore = NULL;
+	int max = 0;
+
+	if(blah && !blah->flags)
+		return;
+
+	pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)0L, MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
+	while(pCore)
+	{
+		QUERYRECORDRECT qrr;
+		int vector;
+
+		qrr.cb = sizeof(QUERYRECORDRECT);
+		qrr.pRecord = pCore;
+		qrr.fRightSplitWindow = 0;
+		qrr.fsExtent = CMA_TEXT;
+
+		WinSendMsg(handle, CM_QUERYRECORDRECT, (MPARAM)&item, (MPARAM)&qrr);
+
+		vector = item.xRight - item.xLeft;
+
+		if(vector > max)
+			max = vector;
+
+		pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)pCore, MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
+	}
+
+	if(max)
+	{
+		CNRINFO cnri;
+
+		cnri.cb = sizeof(CNRINFO);
+		cnri.xVertSplitbar  = max;
+
+		WinSendMsg(handle, CM_SETCNRINFO, MPFROMP(&cnri),  MPFROMLONG(CMA_XVERTSPLITBAR));
+	}
+}
+
+/*
+ * Inserts an icon into the taskbar.
+ * Parameters:
+ *       handle: Window handle that will handle taskbar icon messages.
+ *       icon: Icon handle to display in the taskbar.
+ *       bubbletext: Text to show when the mouse is above the icon.
+ */
+void API dw_taskbar_insert(HWND handle, unsigned long icon, char *bubbletext)
+{
+	handle = handle;
+	icon = icon;
+	bubbletext = bubbletext;
+	/* TODO */
+}
+
+/*
+ * Deletes an icon from the taskbar.
+ * Parameters:
+ *       handle: Window handle that was used with dw_taskbar_insert().
+ *       icon: Icon handle that was used with dw_taskbar_insert().
+ */
+void API dw_taskbar_delete(HWND handle, unsigned long icon)
+{
+	handle = handle;
+	icon = icon;
+	/* TODO */
+}
+
+/*
+ * Creates a rendering context widget (window) to be packed.
+ * Parameters:
+ *       id: An id to be used with dw_window_from_id.
+ * Returns:
+ *       A handle to the widget or NULL on failure.
+ */
+HWND API dw_render_new(unsigned long id)
+{
+	HWND hwndframe = WinCreateWindow(HWND_OBJECT,
+									 WC_FRAME,
+									 NULL,
+									 WS_VISIBLE |
+									 FS_NOBYTEALIGN,
+									 0,0,2000,1000,
+									 NULLHANDLE,
+									 HWND_TOP,
+									 id,
+									 NULL,
+									 NULL);
+	WinSubclassWindow(hwndframe, _RendProc);
+	return hwndframe;
+}
+
+/* Sets the current foreground drawing color.
+ * Parameters:
+ *       red: red value.
+ *       green: green value.
+ *       blue: blue value.
+ */
+void API dw_color_foreground_set(unsigned long value)
+{
+	_foreground = value;
+}
+
+/* Sets the current background drawing color.
+ * Parameters:
+ *       red: red value.
+ *       green: green value.
+ *       blue: blue value.
+ */
+void API dw_color_background_set(unsigned long value)
+{
+	_background = value;
+}
+
+int DWSIGNAL _dw_color_cancel_func(HWND window, void *data)
+{
+	DWDialog *dwwait = (DWDialog *)data;
+	HMTX mtx = (HMTX)dw_window_get_data((HWND)dwwait->data, "_dw_mutex");
+	void *val;
+
+	window = (HWND)dwwait->data;
+	val = dw_window_get_data(window, "_dw_val");
+
+	dw_mutex_lock(mtx);
+	dw_mutex_close(mtx);
+	dw_window_destroy(window);
+	dw_dialog_dismiss((DWDialog *)data, val);
+	return FALSE;
+}
+
+int DWSIGNAL _dw_color_ok_func(HWND window, void *data)
+{
+	DWDialog *dwwait = (DWDialog *)data;
+	HMTX mtx = (HMTX)dw_window_get_data((HWND)dwwait->data, "_dw_mutex");
+	unsigned long val;
+
+	window = (HWND)dwwait->data;
+	val = _dw_color_spin_get(window);
+
+	dw_mutex_lock(mtx);
+	dw_mutex_close(mtx);
+	dw_window_destroy(window);
+	dw_dialog_dismiss((DWDialog *)data, (void *)val);
+	return FALSE;
+}
+
+/* Allows the user to choose a color using the system's color chooser dialog.
+ * Parameters:
+ *       value: current color
+ * Returns:
+ *       The selected color or the current color if cancelled.
+ */
+unsigned long API dw_color_choose(unsigned long value)
+{
+	HWND window, hbox, vbox, col, button, text;
+	DWDialog *dwwait;
+	HMTX mtx = dw_mutex_new();
+
+	window = dw_window_new( HWND_DESKTOP, "Choose Color", FCF_SHELLPOSITION | FCF_TITLEBAR | FCF_DLGBORDER | FCF_CLOSEBUTTON | FCF_SYSMENU);
+
+	vbox = dw_box_new(DW_VERT, 5);
+
+	dw_box_pack_start(window, vbox, 0, 0, TRUE, TRUE, 0);
+
+	hbox = dw_box_new(DW_HORZ, 0);
+
+	dw_box_pack_start(vbox, hbox, 0, 0, FALSE, FALSE, 0);
+	dw_window_set_style(hbox, 0, WS_CLIPCHILDREN);
+
+	col = WinCreateWindow(vbox, "ColorSelectClass", "", WS_VISIBLE | WS_GROUP, 0, 0, 390, 300, vbox, HWND_TOP, 266, NULL,NULL);
+	dw_box_pack_start(hbox, col, 390, 300, FALSE, FALSE, 0);
+
+	dw_window_set_data(hbox, "_dw_window", (void *)window);
+	dw_window_set_data(window, "_dw_mutex", (void *)mtx);
+	dw_window_set_data(window, "_dw_col", (void *)col);
+	dw_window_set_data(window, "_dw_val", (void *)value);
+
+	hbox = dw_box_new(DW_HORZ, 0);
+	dw_window_set_data(hbox, "_dw_window", (void *)window);
+
+	dw_box_pack_start(vbox, hbox, 0, 0, TRUE, FALSE, 0);
+
+	text = dw_text_new("Red:", 0);
+	dw_window_set_style(text, DW_DT_VCENTER, DW_DT_VCENTER);
+	dw_box_pack_start(hbox, text, 30, 20, FALSE, FALSE, 3);
+
+	button = dw_spinbutton_new("", 1001L);
+	dw_spinbutton_set_limits(button, 255, 0);
+	dw_box_pack_start(hbox, button, 20, 20, TRUE, FALSE, 3);
+	WinSetOwner(button, hbox);
+	dw_window_set_data(window, "_dw_red_spin", (void *)button);
+
+	text = dw_text_new("Green:", 0);
+	dw_window_set_style(text, DW_DT_VCENTER, DW_DT_VCENTER);
+	dw_box_pack_start(hbox, text, 30, 20, FALSE, FALSE, 3);
+
+	button = dw_spinbutton_new("", 1002L);
+	dw_spinbutton_set_limits(button, 255, 0);
+	dw_box_pack_start(hbox, button, 20, 20, TRUE, FALSE, 3);
+	WinSetOwner(button, hbox);
+	dw_window_set_data(window, "_dw_green_spin", (void *)button);
+
+	text = dw_text_new("Blue:", 0);
+	dw_window_set_style(text, DW_DT_VCENTER, DW_DT_VCENTER);
+	dw_box_pack_start(hbox, text, 30, 20, FALSE, FALSE, 3);
+
+	button = dw_spinbutton_new("", 1003L);
+	dw_spinbutton_set_limits(button, 255, 0);
+	dw_box_pack_start(hbox, button, 20, 20, TRUE, FALSE, 3);
+	WinSetOwner(button, hbox);
+	dw_window_set_data(window, "_dw_blue_spin", (void *)button);
+
+	hbox = dw_box_new(DW_HORZ, 0);
+
+	dw_box_pack_start(vbox, hbox, 0, 0, TRUE, FALSE, 0);
+	dw_box_pack_start(hbox, 0, 100, 1, TRUE, FALSE, 0);
+
+	button = dw_button_new("Ok", 1001L);
+	dw_box_pack_start(hbox, button, 50, 30, TRUE, FALSE, 3);
+
+	dwwait = dw_dialog_new((void *)window);
+
+	dw_signal_connect(button, DW_SIGNAL_CLICKED, DW_SIGNAL_FUNC(_dw_color_ok_func), (void *)dwwait);
+
+	button = dw_button_new("Cancel", 1002L);
+	dw_box_pack_start(hbox, button, 50, 30, TRUE, FALSE, 3);
+
+	dw_signal_connect(button, DW_SIGNAL_CLICKED, DW_SIGNAL_FUNC(_dw_color_cancel_func), (void *)dwwait);
+	dw_signal_connect(window, DW_SIGNAL_DELETE, DW_SIGNAL_FUNC(_dw_color_cancel_func), (void *)dwwait);
+
+	dw_window_set_size(window, 400, 400);
+
+	_dw_col_set(col, value);
+	_dw_color_spin_set(window, value);
+
+	dw_window_show(window);
+
+	return (unsigned long)dw_dialog_wait(dwwait);
+}
+
+HPS _set_hps(HPS hps)
+{
+	LONG alTable[2];
+
+	alTable[0] = DW_RED_VALUE(_foreground) << 16 | DW_GREEN_VALUE(_foreground) << 8 | DW_BLUE_VALUE(_foreground);
+	alTable[1] = DW_RED_VALUE(_background) << 16 | DW_GREEN_VALUE(_background) << 8 | DW_BLUE_VALUE(_background);
+
+	GpiCreateLogColorTable(hps,
+						   LCOL_RESET,
+						   LCOLF_CONSECRGB,
+						   16,
+						   2,
+						   alTable);
+	if(_foreground & DW_RGB_COLOR)
+		GpiSetColor(hps, 16);
+	else
+		GpiSetColor(hps, _internal_color(_foreground));
+	if(_background & DW_RGB_COLOR)
+		GpiSetBackColor(hps, 17);
+	else
+		GpiSetBackColor(hps, _internal_color(_background));
+	return hps;
+}
+
+HPS _set_colors(HWND handle)
+{
+	HPS hps = WinGetPS(handle);
+
+	_set_hps(hps);
+	return hps;
+}
+
+/* Draw a point on a window (preferably a render window).
+ * Parameters:
+ *       handle: Handle to the window.
+ *       pixmap: Handle to the pixmap. (choose only one of these)
+ *       x: X coordinate.
+ *       y: Y coordinate.
+ */
+void API dw_draw_point(HWND handle, HPIXMAP pixmap, int x, int y)
+{
+	HPS hps;
+	int height;
+	POINTL ptl;
+
+	if(handle)
+	{
+		hps = _set_colors(handle);
+        height = _get_height(handle);
+	}
+	else if(pixmap)
+	{
+		hps = _set_hps(pixmap->hps);
+		height = pixmap->height;
+	}
+	else
+		return;
+
+	ptl.x = x;
+	ptl.y = height - y - 1;
+
+	GpiSetPel(hps, &ptl);
+	if(!pixmap)
+		WinReleasePS(hps);
+}
+
+/* Draw a line on a window (preferably a render window).
+ * Parameters:
+ *       handle: Handle to the window.
+ *       pixmap: Handle to the pixmap. (choose only one of these)
+ *       x1: First X coordinate.
+ *       y1: First Y coordinate.
+ *       x2: Second X coordinate.
+ *       y2: Second Y coordinate.
+ */
+void API dw_draw_line(HWND handle, HPIXMAP pixmap, int x1, int y1, int x2, int y2)
+{
+	HPS hps;
+	int height;
+	POINTL ptl[2];
+
+	if(handle)
+	{
+		hps = _set_colors(handle);
+        height = _get_height(handle);
+	}
+	else if(pixmap)
+	{
+		hps = _set_hps(pixmap->hps);
+		height = pixmap->height;
+	}
+	else
+		return;
+
+	ptl[0].x = x1;
+	ptl[0].y = height - y1 - 1;
+	ptl[1].x = x2;
+	ptl[1].y = height - y2 - 1;
+
+	GpiMove(hps, &ptl[0]);
+	GpiLine(hps, &ptl[1]);
+	
+	if(!pixmap)
+		WinReleasePS(hps);
+}
+
+
+void _CopyFontSettings(HPS hpsSrc, HPS hpsDst)
+{
+	FONTMETRICS fm;
+	FATTRS fat;
+	SIZEF sizf;
+
+	GpiQueryFontMetrics(hpsSrc, sizeof(FONTMETRICS), &fm);
+
+    memset(&fat, 0, sizeof(fat));
+
+	fat.usRecordLength  = sizeof(FATTRS);
+	fat.lMatch          = fm.lMatch;
+	strcpy(fat.szFacename, fm.szFacename);
+
+	GpiCreateLogFont(hpsDst, 0, 1L, &fat);
+	GpiSetCharSet(hpsDst, 1L);
+
+	sizf.cx = MAKEFIXED(fm.lEmInc,0);
+	sizf.cy = MAKEFIXED(fm.lMaxBaselineExt,0);
+	GpiSetCharBox(hpsDst, &sizf );
+}
+
+/* Draw text on a window (preferably a render window).
+ * Parameters:
+ *       handle: Handle to the window.
+ *       pixmap: Handle to the pixmap. (choose only one of these)
+ *       x: X coordinate.
+ *       y: Y coordinate.
+ *       text: Text to be displayed.
+ */
+void API dw_draw_text(HWND handle, HPIXMAP pixmap, int x, int y, char *text)
+{
+	HPS hps;
+	int z, height;
+	RECTL rcl;
+	char fontname[128];
+	POINTL aptl[TXTBOX_COUNT];
+
+	if(handle)
+	{
+		hps = _set_colors(handle);
+		height = _get_height(handle);
+		_GetPPFont(handle, fontname);
+	}
+	else if(pixmap)
+	{
+		HPS pixmaphps = WinGetPS(pixmap->handle);
+
+		hps = _set_hps(pixmap->hps);
+		height = pixmap->height;
+		_GetPPFont(pixmap->handle, fontname);
+		_CopyFontSettings(pixmaphps, hps);
+		WinReleasePS(pixmaphps);
+	}
+	else
+		return;
+
+	for(z=0;z<strlen(fontname);z++)
+	{
+		if(fontname[z]=='.')
+			break;
+	}
+
+	GpiQueryTextBox(hps, strlen(text), text, TXTBOX_COUNT, aptl);
+
+	rcl.xLeft = x;
+	rcl.yTop = height - y;
+	rcl.yBottom = rcl.yTop - (aptl[TXTBOX_TOPLEFT].y - aptl[TXTBOX_BOTTOMLEFT].y);
+	rcl.xRight = rcl.xLeft + (aptl[TXTBOX_TOPRIGHT].x - aptl[TXTBOX_TOPLEFT].x);
+
+	if(_background == DW_CLR_DEFAULT)
+		WinDrawText(hps, -1, text, &rcl, DT_TEXTATTRS, DT_TEXTATTRS, DT_VCENTER | DT_LEFT | DT_TEXTATTRS);
+	else
+		WinDrawText(hps, -1, text, &rcl, _internal_color(_foreground), _internal_color(_background), DT_VCENTER | DT_LEFT | DT_ERASERECT);
+
+	if(!pixmap)
+		WinReleasePS(hps);
+}
+
+/* Query the width and height of a text string.
+ * Parameters:
+ *       handle: Handle to the window.
+ *       pixmap: Handle to the pixmap. (choose only one of these)
+ *       text: Text to be queried.
+ *       width: Pointer to a variable to be filled in with the width.
+ *       height Pointer to a variable to be filled in with the height.
+ */
+void API dw_font_text_extents_get(HWND handle, HPIXMAP pixmap, char *text, int *width, int *height)
+{
+	HPS hps;
+	POINTL aptl[TXTBOX_COUNT];
+
+	if(handle)
+	{
+		hps = _set_colors(handle);
+	}
+	else if(pixmap)
+	{
+		HPS pixmaphps = WinGetPS(pixmap->handle);
+
+		hps = _set_hps(pixmap->hps);
+		_CopyFontSettings(pixmaphps, hps);
+		WinReleasePS(pixmaphps);
+	}
+	else
+		return;
+
+	GpiQueryTextBox(hps, strlen(text), text, TXTBOX_COUNT, aptl);
+
+	if(width)
+		*width = aptl[TXTBOX_TOPRIGHT].x - aptl[TXTBOX_TOPLEFT].x;
+
+	if(height)
+		*height = aptl[TXTBOX_TOPLEFT].y - aptl[TXTBOX_BOTTOMLEFT].y;
+
+	if(!pixmap)
+		WinReleasePS(hps);
+}
+
+/* Draw a rectangle on a window (preferably a render window).
+ * Parameters:
+ *       handle: Handle to the window.
+ *       pixmap: Handle to the pixmap. (choose only one of these)
+ *       fill: Fill box TRUE or FALSE.
+ *       x: X coordinate.
+ *       y: Y coordinate.
+ *       width: Width of rectangle.
+ *       height: Height of rectangle.
+ */
+void API dw_draw_rect(HWND handle, HPIXMAP pixmap, int fill, int x, int y, int width, int height)
+{
+	HPS hps;
+	int thisheight;
+	POINTL ptl[2];
+
+	if(handle)
+	{
+		hps = _set_colors(handle);
+        thisheight = _get_height(handle);
+	}
+	else if(pixmap)
+	{
+		hps = _set_hps(pixmap->hps);
+		thisheight = pixmap->height;
+	}
+	else
+		return;
+
+	ptl[0].x = x;
+	ptl[0].y = thisheight - y - 1;
+	ptl[1].x = x + width - 1;
+	ptl[1].y = thisheight - y - height;
+
+	GpiMove(hps, &ptl[0]);
+	GpiBox(hps, fill ? DRO_OUTLINEFILL : DRO_OUTLINE, &ptl[1], 0, 0);
+	
+	if(!pixmap)
+		WinReleasePS(hps);
+}
+
+/* Call this after drawing to the screen to make sure
+ * anything you have drawn is visible.
+ */
+void API dw_flush(void)
+{
+}
+
+/*
+ * Creates a pixmap with given parameters.
+ * Parameters:
+ *       handle: Window handle the pixmap is associated with.
+ *       width: Width of the pixmap in pixels.
+ *       height: Height of the pixmap in pixels.
+ *       depth: Color depth of the pixmap.
+ * Returns:
+ *       A handle to a pixmap or NULL on failure.
+ */
+HPIXMAP API dw_pixmap_new(HWND handle, unsigned long width, unsigned long height, int depth)
+{
+	BITMAPINFOHEADER bmih;
+	SIZEL sizl = { 0, 0 };
+	HPIXMAP pixmap;
+	HDC hdc;
+	HPS hps;
+	ULONG ulFlags;
+    LONG cPlanes, cBitCount;
+
+	if (!(pixmap = calloc(1,sizeof(struct _hpixmap))))
+		return NULL;
+
+	hps = WinGetPS(handle);
+
+	hdc     = GpiQueryDevice(hps);
+	ulFlags = GpiQueryPS(hps, &sizl);
+
+	pixmap->handle = handle;
+	pixmap->hdc = DevOpenDC(dwhab, OD_MEMORY, "*", 0L, NULL, hdc);
+	pixmap->hps = GpiCreatePS (dwhab, pixmap->hdc, &sizl, ulFlags | GPIA_ASSOC);
+
+	DevQueryCaps(hdc, CAPS_COLOR_PLANES  , 1L, &cPlanes);
+	if (!depth)
+	{
+		DevQueryCaps(hdc, CAPS_COLOR_BITCOUNT, 1L, &cBitCount);
+		depth = cBitCount;
+	}
+
+	memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
+	bmih.cbFix     = sizeof(BITMAPINFOHEADER);
+	bmih.cx        = (SHORT)width;
+	bmih.cy        = (SHORT)height;
+	bmih.cPlanes   = (SHORT)cPlanes;
+	bmih.cBitCount = (SHORT)depth;
+
+	pixmap->width = width; pixmap->height = height;
+
+	pixmap->hbm = GpiCreateBitmap(pixmap->hps, (PBITMAPINFOHEADER2)&bmih, 0L, NULL, NULL);
+
+	GpiSetBitmap(pixmap->hps, pixmap->hbm);
+
+	if (depth>8)
+		GpiCreateLogColorTable(pixmap->hps, LCOL_PURECOLOR, LCOLF_RGB, 0, 0, NULL );
+
+	WinReleasePS(hps);
+
+	return pixmap;
+}
+
+/*
+ * Creates a pixmap from a file.
+ * Parameters:
+ *       handle: Window handle the pixmap is associated with.
+ *       filename: Name of the file, omit extention to have
+ *                 DW pick the appropriate file extension.
+ *                 (BMP on OS/2 or Windows, XPM on Unix)
+ * Returns:
+ *       A handle to a pixmap or NULL on failure.
+ */
+HPIXMAP API dw_pixmap_new_from_file(HWND handle, char *filename)
+{
+	HPIXMAP pixmap;
+	char *file = alloca(strlen(filename) + 5);
+
+	if(!file || !(pixmap = calloc(1,sizeof(struct _hpixmap))))
+		return NULL;
+
+	strcpy(file, filename);
+
+	/* check if we can read from this file (it exists and read permission) */
+	if(access(file, 04) != 0)
+	{
+		/* Try with .bmp extention */
+		strcat(file, ".bmp");
+		if(access(file, 04) != 0)
+		{
+			free(pixmap);
+			return NULL;
+		}
+	}
+
+	/* Try to load the bitmap from file */
+	if(!_load_bitmap_file(file, handle, &pixmap->hbm, &pixmap->hdc, &pixmap->hps, &pixmap->width, &pixmap->height))
+	{
+		free(pixmap);
+		return NULL;
+	}
+
+	/* Success fill in other values */
+	pixmap->handle = handle;
+
+	return pixmap;
+}
+
+/*
+ * Creates a pixmap from internal resource graphic specified by id.
+ * Parameters:
+ *       handle: Window handle the pixmap is associated with.
+ *       id: Resource ID associated with requested pixmap.
+ * Returns:
+ *       A handle to a pixmap or NULL on failure.
+ */
+HPIXMAP API dw_pixmap_grab(HWND handle, ULONG id)
+{
+	BITMAPINFOHEADER bmih;
+	SIZEL sizl = { 0, 0 };
+	HPIXMAP pixmap;
+	HDC hdc;
+	HPS hps;
+	ULONG ulFlags;
+
+	if (!(pixmap = calloc(1,sizeof(struct _hpixmap))))
+		return NULL;
+
+	hps = WinGetPS(handle);
+
+	hdc     = GpiQueryDevice(hps);
+	ulFlags = GpiQueryPS(hps, &sizl);
+
+	pixmap->hdc = DevOpenDC(dwhab, OD_MEMORY, "*", 0L, NULL, hdc);
+	pixmap->hps = GpiCreatePS (dwhab, pixmap->hdc, &sizl, ulFlags | GPIA_ASSOC);
+
+	pixmap->hbm = GpiLoadBitmap(pixmap->hps, NULLHANDLE, id, 0, 0);
+
+	GpiQueryBitmapParameters(pixmap->hbm, &bmih);
+
+	GpiSetBitmap(pixmap->hps, pixmap->hbm);
+
+	pixmap->width = bmih.cx; pixmap->height = bmih.cy;
+
+	WinReleasePS(hps);
+
+	return pixmap;
+}
+
+/*
+ * Destroys an allocated pixmap.
+ * Parameters:
+ *       pixmap: Handle to a pixmap returned by
+ *               dw_pixmap_new..
+ */
+void API dw_pixmap_destroy(HPIXMAP pixmap)
+{
+	GpiSetBitmap(pixmap->hps, NULLHANDLE);
+	GpiDeleteBitmap(pixmap->hbm);
+	GpiAssociate(pixmap->hps, NULLHANDLE);
+	GpiDestroyPS(pixmap->hps);
+	DevCloseDC(pixmap->hdc);
+	free(pixmap);
+}
+
+/*
+ * Copies from one item to another.
+ * Parameters:
+ *       dest: Destination window handle.
+ *       destp: Destination pixmap. (choose only one).
+ *       xdest: X coordinate of destination.
+ *       ydest: Y coordinate of destination.
+ *       width: Width of area to copy.
+ *       height: Height of area to copy.
+ *       src: Source window handle.
+ *       srcp: Source pixmap. (choose only one).
+ *       xsrc: X coordinate of source.
+ *       ysrc: Y coordinate of source.
+ */
+void API dw_pixmap_bitblt(HWND dest, HPIXMAP destp, int xdest, int ydest, int width, int height, HWND src, HPIXMAP srcp, int xsrc, int ysrc)
+{
+	HPS hpsdest;
+	HPS hpssrc;
+	POINTL ptl[4];
+    int destheight, srcheight;
+
+	if(dest)
+	{
+		hpsdest = WinGetPS(dest);
+		destheight = _get_height(dest);
+	}
+	else if(destp)
+	{
+		hpsdest = destp->hps;
+		destheight = destp->height;
+	}
+	else
+		return;
+
+	if(src)
+	{
+		hpssrc = WinGetPS(src);
+		srcheight = _get_height(src);
+	}
+	else if(srcp)
+	{
+		hpssrc = srcp->hps;
+		srcheight = srcp->height;
+	}
+	else
+	{
+		if(!destp)
+			WinReleasePS(hpsdest);
+		return;
+	}
+
+	ptl[0].x = xdest;
+	ptl[0].y = (destheight - ydest) - height;
+	ptl[1].x = ptl[0].x + width;
+	ptl[1].y = destheight - ydest;
+	ptl[2].x = xsrc;
+	ptl[2].y = srcheight - (ysrc + height);
+	ptl[3].x = ptl[2].x + width;
+	ptl[3].y = ptl[2].y + height;
+
+	GpiBitBlt(hpsdest, hpssrc, 4, ptl, ROP_SRCCOPY, BBO_IGNORE);
+
+	if(!destp)
+		WinReleasePS(hpsdest);
+	if(!srcp)
+		WinReleasePS(hpssrc);
+}
+
+/* Run DosBeep() in a separate thread so it doesn't block */
+void _beepthread(void *data)
+{
+	int *info = (int *)data;
+
+	if(data)
+	{
+		DosBeep(info[0], info[1]);
+		free(data);
+	}
+}
+
+/*
+ * Emits a beep.
+ * Parameters:
+ *       freq: Frequency.
+ *       dur: Duration.
+ */
+void API dw_beep(int freq, int dur)
+{
+	int *info = malloc(sizeof(int) * 2);
+
+	if(info)
+	{
+		info[0] = freq;
+		info[1] = dur;
+
+		_beginthread(_beepthread, NULL, 100, (void *)info);
+	}
+}
+
+/* Open a shared library and return a handle.
+ * Parameters:
+ *         name: Base name of the shared library.
+ *         handle: Pointer to a module handle,
+ *                 will be filled in with the handle.
+ */
+int API dw_module_load(char *name, HMOD *handle)
+{
+	char objnamebuf[300] = "";
+
+	return DosLoadModule(objnamebuf, sizeof(objnamebuf), name, handle);
+}
+
+/* Queries the address of a symbol within open handle.
+ * Parameters:
+ *         handle: Module handle returned by dw_module_load()
+ *         name: Name of the symbol you want the address of.
+ *         func: A pointer to a function pointer, to obtain
+ *               the address.
+ */
+int API dw_module_symbol(HMOD handle, char *name, void**func)
+{
+	return DosQueryProcAddr(handle, 0, name, (PFN*)func);
+}
+
+/* Frees the shared library previously opened.
+ * Parameters:
+ *         handle: Module handle returned by dw_module_load()
+ */
+int API dw_module_close(HMOD handle)
+{
+	DosFreeModule(handle);
+	return 0;
+}
+
+/*
+ * Returns the handle to an unnamed mutex semaphore.
+ */
+HMTX API dw_mutex_new(void)
+{
+	HMTX mutex;
+
+	DosCreateMutexSem(NULL, &mutex, 0, FALSE);
+	return mutex;
+}
+
+/*
+ * Closes a semaphore created by dw_mutex_new().
+ * Parameters:
+ *       mutex: The handle to the mutex returned by dw_mutex_new().
+ */
+void API dw_mutex_close(HMTX mutex)
+{
+	DosCloseMutexSem(mutex);
+}
+
+/*
+ * Tries to gain access to the semaphore, if it can't it blocks.
+ * If we are in a callback we must keep the message loop running
+ * while blocking.
+ * Parameters:
+ *       mutex: The handle to the mutex returned by dw_mutex_new().
+ */
+void API dw_mutex_lock(HMTX mutex)
+{
+	if(_dwtid == dw_thread_id())
+	{
+		int rc = DosRequestMutexSem(mutex, SEM_IMMEDIATE_RETURN);
+
+		while(rc == ERROR_TIMEOUT)
+		{
+			dw_main_sleep(10);
+			rc = DosRequestMutexSem(mutex, SEM_IMMEDIATE_RETURN);
+		}
+	}
+    else
+		DosRequestMutexSem(mutex, SEM_INDEFINITE_WAIT);
+}
+
+/*
+ * Reliquishes the access to the semaphore.
+ * Parameters:
+ *       mutex: The handle to the mutex returned by dw_mutex_new().
+ */
+void API dw_mutex_unlock(HMTX mutex)
+{
+	DosReleaseMutexSem(mutex);
+}
+
+/*
+ * Returns the handle to an unnamed event semaphore.
+ */
+HEV API dw_event_new(void)
+{
+	HEV blah;
+
+	if(DosCreateEventSem (NULL, &blah, 0L, FALSE))
+		return 0;
+
+	return blah;
+}
+
+/*
+ * Resets a semaphore created by dw_event_new().
+ * Parameters:
+ *       eve: The handle to the event returned by dw_event_new().
+ */
+int API dw_event_reset(HEV eve)
+{
+	ULONG count;
+
+	if(DosResetEventSem(eve, &count))
+		return FALSE;
+	return TRUE;
+}
+
+/*
+ * Posts a semaphore created by dw_event_new(). Causing all threads
+ * waiting on this event in dw_event_wait to continue.
+ * Parameters:
+ *       eve: The handle to the event returned by dw_event_new().
+ */
+int API dw_event_post(HEV eve)
+{
+	if(DosPostEventSem(eve))
+		return FALSE;
+	return TRUE;
+}
+
+
+/*
+ * Waits on a semaphore created by dw_event_new(), until the
+ * event gets posted or until the timeout expires.
+ * Parameters:
+ *       eve: The handle to the event returned by dw_event_new().
+ */
+int API dw_event_wait(HEV eve, unsigned long timeout)
+{
+	int rc = DosWaitEventSem(eve, timeout);
+	if(!rc)
+		return 1;
+	if(rc == ERROR_TIMEOUT)
+		return -1;
+	return 0;
+}
+
+/*
+ * Closes a semaphore created by dw_event_new().
+ * Parameters:
+ *       eve: The handle to the event returned by dw_event_new().
+ */
+int API dw_event_close(HEV *eve)
+{
+	if(!eve || ~DosCloseEventSem(*eve))
+		return FALSE;
+	return TRUE;
+}
+
+/* Create a named event semaphore which can be
+ * opened from other processes.
+ * Parameters:
+ *         eve: Pointer to an event handle to receive handle.
+ *         name: Name given to semaphore which can be opened
+ *               by other processes.
+ */
+HEV API dw_named_event_new(char *name)
+{
+	char *semname = malloc(strlen(name)+8);
+	HEV ev = 0;
+
+	if(!semname)
+		return 0;
+
+	strcpy(semname, "\\sem32\\");
+	strcat(semname, name);
+
+	DosCreateEventSem(semname, &ev, 0L, FALSE);
+
+	free(semname);
+	return ev;
+}
+
+/* Open an already existing named event semaphore.
+ * Parameters:
+ *         eve: Pointer to an event handle to receive handle.
+ *         name: Name given to semaphore which can be opened
+ *               by other processes.
+ */
+HEV API dw_named_event_get(char *name)
+{
+	char *semname = malloc(strlen(name)+8);
+	HEV ev;
+
+	if(!semname)
+		return 0;
+
+	strcpy(semname, "\\sem32\\");
+	strcat(semname, name);
+
+	DosOpenEventSem(semname, &ev);
+
+	free(semname);
+	return ev;
+}
+
+/* Resets the event semaphore so threads who call wait
+ * on this semaphore will block.
+ * Parameters:
+ *         eve: Handle to the semaphore obtained by
+ *              an open or create call.
+ */
+int API dw_named_event_reset(HEV eve)
+{
+	ULONG count;
+
+	return DosResetEventSem(eve, &count);
+}
+
+/* Sets the posted state of an event semaphore, any threads
+ * waiting on the semaphore will no longer block.
+ * Parameters:
+ *         eve: Handle to the semaphore obtained by
+ *              an open or create call.
+ */
+int API dw_named_event_post(HEV eve)
+{
+	return DosPostEventSem(eve);
+}
+
+
+/* Waits on the specified semaphore until it becomes
+ * posted, or returns immediately if it already is posted.
+ * Parameters:
+ *         eve: Handle to the semaphore obtained by
+ *              an open or create call.
+ *         timeout: Number of milliseconds before timing out
+ *                  or -1 if indefinite.
+ */
+int API dw_named_event_wait(HEV eve, unsigned long timeout)
+{
+	int rc;
+
+	rc = DosWaitEventSem(eve, timeout);
+	switch (rc)
+	{
+	case ERROR_INVALID_HANDLE:
+		rc = DW_ERROR_NON_INIT;
+		break;
+	case ERROR_NOT_ENOUGH_MEMORY:
+		rc = DW_ERROR_NO_MEM;
+		break;
+	case ERROR_INTERRUPT:
+		rc = DW_ERROR_INTERRUPT;
+		break;
+	case ERROR_TIMEOUT:
+		rc = DW_ERROR_TIMEOUT;
+		break;
+	}
+
+	return rc;
+}
+
+/* Release this semaphore, if there are no more open
+ * handles on this semaphore the semaphore will be destroyed.
+ * Parameters:
+ *         eve: Handle to the semaphore obtained by
+ *              an open or create call.
+ */
+int API dw_named_event_close(HEV eve)
+{
+	int rc;
+
+	rc = DosCloseEventSem(eve);
+	switch (rc)
+	{
+	case ERROR_INVALID_HANDLE:
+		rc = DW_ERROR_NON_INIT;
+		break;
+
+	case ERROR_SEM_BUSY:
+		rc = DW_ERROR_INTERRUPT;
+		break;
+	}
+
+	return rc;
+}
+
+/*
+ * Allocates a shared memory region with a name.
+ * Parameters:
+ *         handle: A pointer to receive a SHM identifier.
+ *         dest: A pointer to a pointer to receive the memory address.
+ *         size: Size in bytes of the shared memory region to allocate.
+ *         name: A string pointer to a unique memory name.
+ */
+HSHM API dw_named_memory_new(void **dest, int size, char *name)
+{
+	char namebuf[1024];
+
+	sprintf(namebuf, "\\sharemem\\%s", name);
+
+	if(DosAllocSharedMem((void *)dest, namebuf, size, PAG_COMMIT | PAG_WRITE | PAG_READ) != NO_ERROR)
+		return 0;
+
+	return 1;
+}
+
+/*
+ * Aquires shared memory region with a name.
+ * Parameters:
+ *         dest: A pointer to a pointer to receive the memory address.
+ *         size: Size in bytes of the shared memory region to requested.
+ *         name: A string pointer to a unique memory name.
+ */
+HSHM API dw_named_memory_get(void **dest, int size, char *name)
+{
+	char namebuf[1024];
+
+	size = size;
+	sprintf(namebuf, "\\sharemem\\%s", name);
+
+	if(DosGetNamedSharedMem((void *)dest, namebuf, PAG_READ | PAG_WRITE) != NO_ERROR)
+		return 0;
+
+	return 1;
+}
+
+/*
+ * Frees a shared memory region previously allocated.
+ * Parameters:
+ *         handle: Handle obtained from DB_named_memory_allocate.
+ *         ptr: The memory address aquired with DB_named_memory_allocate.
+ */
+int API dw_named_memory_free(HSHM handle, void *ptr)
+{
+	handle = handle;
+
+	if(DosFreeMem(ptr) != NO_ERROR)
+		return -1;
+	return 0;
+}
+
+/*
+ * Encapsulate the message queues on OS/2.
+ */
+void _dwthreadstart(void *data)
+{
+	HAB thishab = WinInitialize(0);
+	HMQ thishmq = WinCreateMsgQueue(dwhab, 0);
+	void (* API threadfunc)(void *) = NULL;
+	void **tmp = (void **)data;
+
+	threadfunc = (void (*)(void *))tmp[0];
+	threadfunc(tmp[1]);
+
+	free(tmp);
+
+	WinDestroyMsgQueue(thishmq);
+	WinTerminate(thishab);
+}
+
+/*
+ * Creates a new thread with a starting point of func.
+ * Parameters:
+ *       func: Function which will be run in the new thread.
+ *       data: Parameter(s) passed to the function.
+ *       stack: Stack size of new thread (OS/2 and Windows only).
+ */
+DWTID API dw_thread_new(void *func, void *data, int stack)
+{
+	void **tmp = malloc(sizeof(void *) * 2);
+
+	tmp[0] = func;
+	tmp[1] = data;
+
+	return (DWTID)_beginthread((void (*)(void *))_dwthreadstart, NULL, stack, (void *)tmp);
+}
+
+/*
+ * Ends execution of current thread immediately.
+ */
+void API dw_thread_end(void)
+{
+	_endthread();
+}
+
+/*
+ * Returns the current thread's ID.
+ */
+DWTID API dw_thread_id(void)
+{
+	return (DWTID)_threadid;
+}
+
+/*
+ * Cleanly terminates a DW session, should be signal handler safe.
+ * Parameters:
+ *       exitcode: Exit code reported to the operating system.
+ */
+void API dw_exit(int exitcode)
+{
+	/* Destroy the menu message window */
+	dw_window_destroy(hwndApp);
+
+	/* In case we are in a signal handler, don't
+	 * try to free memory that could possibly be
+	 * free()'d by the runtime already.
+	 */
+	Root = NULL;
+
+	DosFreeModule(wpconfig);
+	exit(exitcode);
+}
+
+/*
+ * Creates a splitbar window (widget) with given parameters.
+ * Parameters:
+ *       type: Value can be DW_VERT or DW_HORZ.
+ *       topleft: Handle to the window to be top or left.
+ *       bottomright:  Handle to the window to be bottom or right.
+ * Returns:
+ *       A handle to a splitbar window or NULL on failure.
+ */
+HWND API dw_splitbar_new(int type, HWND topleft, HWND bottomright, unsigned long id)
+{
+	HWND tmp = WinCreateWindow(HWND_OBJECT,
+							   SplitbarClassName,
+							   NULL,
+							   WS_VISIBLE | WS_CLIPCHILDREN,
+							   0,0,2000,1000,
+							   NULLHANDLE,
+							   HWND_TOP,
+							   id,
+							   NULL,
+							   NULL);
+	if(tmp)
+	{
+		HWND tmpbox = dw_box_new(DW_VERT, 0);
+        float *percent = malloc(sizeof(float));
+
+		dw_box_pack_start(tmpbox, topleft, 1, 1, TRUE, TRUE, 0);
+		WinSetParent(tmpbox, tmp, FALSE);
+		dw_window_set_data(tmp, "_dw_topleft", (void *)tmpbox);
+
+		tmpbox = dw_box_new(DW_VERT, 0);
+		dw_box_pack_start(tmpbox, bottomright, 1, 1, TRUE, TRUE, 0);
+		WinSetParent(tmpbox, tmp, FALSE);
+		*percent = 50.0;
+		dw_window_set_data(tmp, "_dw_bottomright", (void *)tmpbox);
+		dw_window_set_data(tmp, "_dw_percent", (void *)percent);
+		dw_window_set_data(tmp, "_dw_type", (void *)type);
+	}
+	return tmp;
+}
+
+/*
+ * Sets the position of a splitbar (pecentage).
+ * Parameters:
+ *       handle: The handle to the splitbar returned by dw_splitbar_new().
+ */
+void API dw_splitbar_set(HWND handle, float percent)
+{
+	float *mypercent = (float *)dw_window_get_data(handle, "_dw_percent");
+	int type = (int)dw_window_get_data(handle, "_dw_type");
+    unsigned long width, height;
+
+	if(mypercent)
+		*mypercent = percent;
+
+	dw_window_get_pos_size(handle, NULL, NULL, &width, &height);
+
+	_handle_splitbar_resize(handle, percent, type, width, height);
+}
+
+/*
+ * Gets the position of a splitbar (pecentage).
+ * Parameters:
+ *       handle: The handle to the splitbar returned by dw_splitbar_new().
+ */
+float API dw_splitbar_get(HWND handle)
+{
+	float *percent = (float *)dw_window_get_data(handle, "_dw_percent");
+
+	if(percent)
+		return *percent;
+	return 0.0;
+}
+
+/*
+ * Pack windows (widgets) into a box from the start (or top).
+ * Parameters:
+ *       box: Window handle of the box to be packed into.
+ *       item: Window handle of the item to be back.
+ *       width: Width in pixels of the item or -1 to be self determined.
+ *       height: Height in pixels of the item or -1 to be self determined.
+ *       hsize: TRUE if the window (widget) should expand horizontally to fill space given.
+ *       vsize: TRUE if the window (widget) should expand vertically to fill space given.
+ *       pad: Number of pixels of padding around the item.
+ */
+void API dw_box_pack_start(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad)
+{
+	char *funcname = "dw_box_pack_start()";
+
+	/*
+	 * If you try and pack an item into itself VERY bad things can happen; like at least an
+	 * infinite loop on GTK! Lets be safe!
+	 */
+	if(box == item)
+	{
+		dw_messagebox(funcname, DW_MB_OK|DW_MB_ERROR, "Danger! Danger! Will Robinson; box and item are the same!");
+		return;
+	}
+
+	if(WinWindowFromID(box, FID_CLIENT))
+	{
+		box = WinWindowFromID(box, FID_CLIENT);
+		hsize = TRUE;
+		vsize = TRUE;
+	}
+	_dw_box_pack_start(box, item, width, height, hsize, vsize, pad, funcname);
+}
+
+void _dw_box_pack_start(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad, char *functionname)
+{
+	Box *thisbox = WinQueryWindowPtr(box, QWP_USER);
+
+	if(thisbox)
+	{
+		int z;
+		Item *tmpitem, *thisitem = thisbox->items;
+		char tmpbuf[100];
+		HWND frame = (HWND)dw_window_get_data(item, "_dw_combo_box");
+
+		tmpitem = malloc(sizeof(Item)*(thisbox->count+1));
+
+		for(z=0;z<thisbox->count;z++)
+		{
+			tmpitem[z] = thisitem[z];
+		}
+
+		WinQueryClassName(item, 99, tmpbuf);
+
+		if(vsize && !height)
+			height = 1;
+		if(hsize && !width)
+			width = 1;
+
+		if(strncmp(tmpbuf, "#1", 3)==0)
+			tmpitem[thisbox->count].type = TYPEBOX;
+		else
+		{
+			if ( width == 0 && hsize == FALSE )
+				dw_messagebox(functionname, DW_MB_OK|DW_MB_ERROR, "Width and expand Horizonal both unset for box: %x item: %x",box,item);
+			if ( height == 0 && vsize == FALSE )
+				dw_messagebox(functionname, DW_MB_OK|DW_MB_ERROR, "Height and expand Vertical both unset for box: %x item: %x",box,item);
+
+			tmpitem[thisbox->count].type = TYPEITEM;
+		}
+
+		tmpitem[thisbox->count].hwnd = item;
+		tmpitem[thisbox->count].origwidth = tmpitem[thisbox->count].width = width;
+		tmpitem[thisbox->count].origheight = tmpitem[thisbox->count].height = height;
+		tmpitem[thisbox->count].pad = pad;
+		if(hsize)
+			tmpitem[thisbox->count].hsize = SIZEEXPAND;
+		else
+			tmpitem[thisbox->count].hsize = SIZESTATIC;
+
+		if(vsize)
+			tmpitem[thisbox->count].vsize = SIZEEXPAND;
+		else
+			tmpitem[thisbox->count].vsize = SIZESTATIC;
+
+		thisbox->items = tmpitem;
+
+		if(thisbox->count)
+			free(thisitem);
+
+		thisbox->count++;
+
+        /* Don't set the ownership if it's an entryfield  or spinbutton */
+		WinQueryClassName(item, 99, tmpbuf);
+		if(strncmp(tmpbuf, "#6", 3)!=0 && strncmp(tmpbuf, "#32", 4)!=0 && strncmp(tmpbuf, "#2", 3)!=0)
+			WinSetOwner(item, box);
+		WinSetParent(frame ? frame : item, box, FALSE);
+	}
+}
+
+/* The following two functions graciously contributed by Peter Nielsen. */
+static ULONG _ParseBuildLevel (char* pchBuffer, ULONG ulSize) {
+	char* pchStart = pchBuffer;
+	char* pchEnd = pchStart + ulSize - 2;
+
+	while (pchEnd >= pchStart)
+	{
+		if ((pchEnd[0] == '#') && (pchEnd[1] == '@'))
+		{
+			*pchEnd-- = '\0';
+			while (pchEnd >= pchStart)
+			{
+				if ((pchEnd[0] == '@') && (pchEnd[1] == '#'))
+				{
+					ULONG ulMajor = 0;
+					ULONG ulMinor = 0;
+
+					char* pch = pchEnd + 2;
+					while (!isdigit ((int)*pch) && *pch)
+						pch++;
+
+					while (isdigit ((int)*pch))
+						ulMajor = ulMajor * 10 + *pch++ - '0';
+
+					if (*pch == '.')
+					{
+						while (isdigit ((int)*++pch))
+							ulMinor = ulMinor * 10 + *pch - '0';
+					}
+					return ((ulMajor << 16) | ulMinor);
+				}
+				pchEnd--;
+			}
+		}
+		pchEnd--;
+	}
+	return (0);
+}
+
+ULONG _GetSystemBuildLevel(void) {
+	/* The build level info is normally available in the end of the OS2KRNL file. However, this is not the case in some beta versions of OS/2.
+	 * We first try to find the info in the 256 last bytes of the file. If that fails, we load the entire file and search it completely.
+	 */
+	ULONG ulBootDrive = 0;
+	ULONG ulBuild = 0;
+	if (DosQuerySysInfo (QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, &ulBootDrive, sizeof (ulBootDrive)) == NO_ERROR)
+	{
+		char achFileName[11] = "C:\\OS2KRNL";
+		HFILE hfile;
+		ULONG ulResult;
+
+        achFileName[0] = (char)('A'+ulBootDrive-1);
+
+		if (DosOpen (achFileName, &hfile, &ulResult, 0, 0, OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_SEQUENTIAL | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, NULL) == NO_ERROR)
+		{
+			ULONG ulFileSize = 0;
+			if (DosSetFilePtr (hfile, 0, FILE_END, &ulFileSize) == NO_ERROR)
+			{
+				const ULONG ulFirstTry = min (256, ulFileSize);
+				if (DosSetFilePtr (hfile, -(LONG)ulFirstTry, FILE_END, &ulResult) == NO_ERROR)
+				{
+					char *pchBuffer = malloc(ulFirstTry);
+					if (DosRead (hfile, pchBuffer, ulFirstTry, &ulResult) == NO_ERROR)
+					{
+						ulBuild = _ParseBuildLevel (pchBuffer, ulFirstTry);
+						if (ulBuild == 0)
+						{
+							if (DosSetFilePtr (hfile, 0, FILE_BEGIN, &ulResult) == NO_ERROR)
+							{
+								free(pchBuffer);
+								pchBuffer = malloc(ulFileSize);
+
+								if (DosRead (hfile, pchBuffer, ulFileSize, &ulResult) == NO_ERROR)
+									ulBuild = _ParseBuildLevel (pchBuffer, ulFileSize);
+							}
+						}
+					}
+					free(pchBuffer);
+				}
+			}
+			DosClose (hfile);
+		}
+	}
+	return (ulBuild);
+}
+
+/*
+ * Sets the default focus item for a window/dialog.
+ * Parameters:
+ *         window: Toplevel window or dialog.
+ *         defaultitem: Handle to the dialog item to be default.
+ */
+void API dw_window_default(HWND window, HWND defaultitem)
+{
+	Box *thisbox = NULL;
+	HWND box;
+
+	box = WinWindowFromID(window, FID_CLIENT);
+	if(box)
+		thisbox = WinQueryWindowPtr(box, QWP_USER);
+
+	if(thisbox)
+		thisbox->defaultitem = defaultitem;
+}
+
+/*
+ * Sets window to click the default dialog item when an ENTER is pressed.
+ * Parameters:
+ *         window: Window (widget) to look for the ENTER press.
+ *         next: Window (widget) to move to next (or click)
+ */
+void API dw_window_click_default(HWND window, HWND next)
+{
+	WindowData *blah = (WindowData *)WinQueryWindowPtr(window, QWP_USER);
+
+	if(blah)
+		blah->clickdefault = next;
+}
+
+/*
+ * Returns some information about the current operating environment.
+ * Parameters:
+ *       env: Pointer to a DWEnv struct.
+ */
+void API dw_environment_query(DWEnv *env)
+{
+	ULONG Build;
+
+	if(!env)
+		return;
+
+	/* The default is OS/2 2.0 */
+	strcpy(env->osName,"OS/2");
+	env->MajorVersion = 2;
+	env->MinorVersion = 0;
+
+	Build = _GetSystemBuildLevel();
+	env->MinorBuild =  Build & 0xFFFF;
+	env->MajorBuild =  Build >> 16;
+
+	if (aulBuffer[0] == 20)
+	{
+		int i = (unsigned int)aulBuffer[1];
+		if (i > 20)
+		{
+			strcpy(env->osName,"Warp");
+			env->MajorVersion = (int)i/10;
+			env->MinorVersion = i-(((int)i/10)*10);
+		}
+		else if (i == 10)
+			env->MinorVersion = 1;
+	}
+	strcpy(env->buildDate, __DATE__);
+	strcpy(env->buildTime, __TIME__);
+	env->DWMajorVersion = DW_MAJOR_VERSION;
+	env->DWMinorVersion = DW_MINOR_VERSION;
+	env->DWSubVersion = DW_SUB_VERSION;
+}
+
+/* The next few functions are support functions for the OS/2 folder browser */
+void _populate_directory(HWND tree, HTREEITEM parent, char *path)
+{
+	FILEFINDBUF3 ffbuf;
+	HTREEITEM item;
+	ULONG count = 1;
+	HDIR hdir = HDIR_CREATE;
+
+	if(DosFindFirst(path, &hdir, FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_ARCHIVED | MUST_HAVE_DIRECTORY,
+					&ffbuf, sizeof(FILEFINDBUF3), &count, FIL_STANDARD) == NO_ERROR)
+	{
+		while(DosFindNext(hdir, &ffbuf, sizeof(FILEFINDBUF3), &count) == NO_ERROR)
+		{
+			if(strcmp(ffbuf.achName, ".") && strcmp(ffbuf.achName, ".."))
+			{
+				int len = strlen(path);
+				char *folder = malloc(len + ffbuf.cchName + 2);
+				HTREEITEM tempitem;
+
+				strcpy(folder, path);
+				strcpy(&folder[len-1], ffbuf.achName);
+
+				item = dw_tree_insert(tree, ffbuf.achName, WinLoadFileIcon(folder, TRUE), parent, (void *)parent);
+				tempitem = dw_tree_insert(tree, "", 0, item, 0);
+				dw_tree_item_set_data(tree, item, (void *)tempitem);
+			}
+		}
+		DosFindClose(hdir);
+	}
+}
+
+void _populate_tree_thread(void *data)
+{
+	HWND window = (HWND)data, tree = (HWND)dw_window_get_data(window, "_dw_tree");
+	HMTX mtx = (HMTX)dw_window_get_data(window, "_dw_mutex");
+	int drive;
+	HTREEITEM items[26];
+	FSINFO  volinfo;
+
+	DosError(FERR_DISABLEHARDERR);
+
+	dw_mutex_lock(mtx);
+	for(drive=0;drive<26;drive++)
+	{
+		if(DosQueryFSInfo(drive+1, FSIL_VOLSER,(PVOID)&volinfo, sizeof(FSINFO)) == NO_ERROR)
+		{
+			char folder[5] = "C:\\", name[9] = "Drive C:";
+			HTREEITEM tempitem;
+
+			folder[0] = name[6] = 'A' + drive;
+
+			items[drive] = dw_tree_insert(tree, name, WinLoadFileIcon(folder, TRUE), NULL, 0);
+			tempitem = dw_tree_insert(tree, "", 0, items[drive], 0);
+			dw_tree_item_set_data(tree, items[drive], (void *)tempitem);
+		}
+		else
+			items[drive] = 0;
+	}
+	dw_mutex_unlock(mtx);
+
+	DosError(FERR_ENABLEHARDERR);
+}
+
+int DWSIGNAL _dw_ok_func(HWND window, void *data)
+{
+	DWDialog *dwwait = (DWDialog *)data;
+	HMTX mtx = (HMTX)dw_window_get_data((HWND)dwwait->data, "_dw_mutex");
+	void *treedata;
+
+	window = window;
+	if(!dwwait)
+		return FALSE;
+
+	dw_mutex_lock(mtx);
+	treedata = dw_window_get_data((HWND)dwwait->data, "_dw_tree_selected");
+	dw_mutex_close(mtx);
+	dw_window_destroy((HWND)dwwait->data);
+	dw_dialog_dismiss((DWDialog *)data, treedata);
+	return FALSE;
+}
+
+int DWSIGNAL _dw_cancel_func(HWND window, void *data)
+{
+	DWDialog *dwwait = (DWDialog *)data;
+	HMTX mtx = (HMTX)dw_window_get_data((HWND)dwwait->data, "_dw_mutex");
+
+	window = window;
+	if(!dwwait)
+		return FALSE;
+
+	dw_mutex_lock(mtx);
+	dw_mutex_close(mtx);
+	dw_window_destroy((HWND)dwwait->data);
+	dw_dialog_dismiss((DWDialog *)data, NULL);
+	return FALSE;
+}
+
+char *_tree_folder(HWND tree, HTREEITEM item)
+{
+	char *folder=strdup("");
+	HTREEITEM parent = item;
+
+	while(parent)
+	{
+		char *temp, *text = dw_tree_get_title(tree, parent);
+
+		if(text)
+		{
+			if(strncmp(text, "Drive ", 6) == 0)
+				text = &text[6];
+
+			temp = malloc(strlen(text) + strlen(folder) + 3);
+			strcpy(temp, text);
+			strcat(temp, "\\");
+			strcat(temp, folder);
+			free(folder);
+			folder = temp;
+		}
+		parent = dw_tree_get_parent(tree, parent);
+	}
+	return folder;
+}
+
+int DWSIGNAL _item_select(HWND window, HTREEITEM item, char *text, void *data, void *itemdata)
+{
+	DWDialog *dwwait = (DWDialog *)data;
+	char *treedata = (char *)dw_window_get_data((HWND)dwwait->data, "_dw_tree_selected");
+
+	text = text; itemdata = itemdata;
+	if(treedata)
+		free(treedata);
+
+	treedata = _tree_folder(window, item);
+	dw_window_set_data((HWND)dwwait->data, "_dw_tree_selected", (void *)treedata);
+
+	return FALSE;
+}
+
+int DWSIGNAL _tree_expand(HWND window, HTREEITEM item, void *data)
+{
+	HTREEITEM tempitem = (HTREEITEM)dw_tree_item_get_data(window, item);
+
+	data = data;
+	if(tempitem)
+	{
+		char *folder = _tree_folder(window, item);
+
+		dw_tree_item_set_data(window, item, 0);
+		dw_tree_item_delete(window, tempitem);
+
+		if(*folder)
+		{
+			strcat(folder, "*");
+			_populate_directory(window, item, folder);
+		}
+		free(folder);
+	}
+
+	return FALSE;
+}
+
+/*
+ * Opens a file dialog and queries user selection.
+ * Parameters:
+ *       title: Title bar text for dialog.
+ *       defpath: The default path of the open dialog.
+ *       ext: Default file extention.
+ *       flags: DW_FILE_OPEN or DW_FILE_SAVE.
+ * Returns:
+ *       NULL on error. A malloced buffer containing
+ *       the file path on success.
+ *
+ */
+char * API dw_file_browse(char *title, char *defpath, char *ext, int flags)
+{
+	if(flags == DW_DIRECTORY_OPEN)
+	{
+		HWND window, hbox, vbox, tree, button;
+		DWDialog *dwwait;
+		HMTX mtx = dw_mutex_new();
+
+		window = dw_window_new( HWND_DESKTOP, title, FCF_SHELLPOSITION | FCF_TITLEBAR | FCF_SIZEBORDER | FCF_MINMAX);
+
+		vbox = dw_box_new(DW_VERT, 5);
+
+		dw_box_pack_start(window, vbox, 0, 0, TRUE, TRUE, 0);
+
+		tree = dw_tree_new(60);
+
+		dw_box_pack_start(vbox, tree, 1, 1, TRUE, TRUE, 0);
+		dw_window_set_data(window, "_dw_mutex", (void *)mtx);
+		dw_window_set_data(window, "_dw_tree", (void *)tree);
+
+		hbox = dw_box_new(DW_HORZ, 0);
+
+		dw_box_pack_start(vbox, hbox, 0, 0, TRUE, FALSE, 0);
+
+		dwwait = dw_dialog_new((void *)window);
+
+		dw_signal_connect(tree, DW_SIGNAL_ITEM_SELECT, DW_SIGNAL_FUNC(_item_select), (void *)dwwait);
+		dw_signal_connect(tree, DW_SIGNAL_TREE_EXPAND, DW_SIGNAL_FUNC(_tree_expand), (void *)dwwait);
+
+		button = dw_button_new("Ok", 1001L);
+		dw_box_pack_start(hbox, button, 50, 30, TRUE, FALSE, 3);
+		dw_signal_connect(button, DW_SIGNAL_CLICKED, DW_SIGNAL_FUNC(_dw_ok_func), (void *)dwwait);
+
+		button = dw_button_new("Cancel", 1002L);
+		dw_box_pack_start(hbox, button, 50, 30, TRUE, FALSE, 3);
+		dw_signal_connect(button, DW_SIGNAL_CLICKED, DW_SIGNAL_FUNC(_dw_cancel_func), (void *)dwwait);
+		dw_signal_connect(window, DW_SIGNAL_DELETE, DW_SIGNAL_FUNC(_dw_cancel_func), (void *)dwwait);
+
+		dw_window_set_size(window, 225, 300);
+		dw_window_show(window);
+
+		dw_thread_new((void *)_populate_tree_thread, (void *)window, 0xff);
+		return (char *)dw_dialog_wait(dwwait);
+	}
+	else
+	{
+		FILEDLG fild;
+		HWND hwndFile;
+		int len;
+
+		if(defpath)
+			strcpy(fild.szFullFile, defpath);
+		else
+			strcpy(fild.szFullFile, "");
+
+		len = strlen(fild.szFullFile);
+
+		if(len)
+		{
+			if(fild.szFullFile[len-1] != '\\')
+				strcat(fild.szFullFile, "\\");
+		}
+		strcat(fild.szFullFile, "*");
+
+		if(ext)
+		{
+			strcat(fild.szFullFile, ".");
+			strcat(fild.szFullFile, ext);
+		}
+
+		memset(&fild, 0, sizeof(FILEDLG));
+		fild.cbSize = sizeof(FILEDLG);
+		fild.fl = FDS_CENTER | FDS_OPEN_DIALOG;
+		fild.pszTitle = title;
+		fild.pszOKButton = ((flags & DW_FILE_SAVE) ? "Save" : "Open");
+		fild.pfnDlgProc = (PFNWP)WinDefFileDlgProc;
+
+		hwndFile = WinFileDlg(HWND_DESKTOP, HWND_DESKTOP, &fild);
+		if(hwndFile)
+		{
+			switch(fild.lReturn)
+			{
+			case DID_OK:
+				return strdup(fild.szFullFile);
+			case DID_CANCEL:
+				return NULL;
+			}
+		}
+	}
+	return NULL;
+}
+
+/* Internal function to set drive and directory */
+int _SetPath(char *path)
+{
+#ifndef __WATCOMC__
+	if(strlen(path)	> 2)
+	{
+		if(path[1] == ':')
+		{
+			char drive = toupper(path[0]);
+			_chdrive((drive - 'A')+1);
+		}
+	}
+#endif
+	return chdir(path);
+}
+
+/*
+ * Execute and external program in a seperate session.
+ * Parameters:
+ *       program: Program name with optional path.
+ *       type: Either DW_EXEC_CON or DW_EXEC_GUI.
+ *       params: An array of pointers to string arguements.
+ * Returns:
+ *       -1 on error.
+ */
+int API dw_exec(char *program, int type, char **params)
+{
+	type = type; /* keep compiler happy */
+	return spawnvp(P_NOWAIT, program, (const char **)params);
+}
+
+/*
+ * Loads a web browser pointed at the given URL.
+ * Parameters:
+ *       url: Uniform resource locator.
+ */
+int API dw_browse(char *url)
+{
+	char *execargs[3], browser[1024], *olddir, *newurl = NULL;
+	int len, ret;
+
+	olddir = _getcwd(NULL, 1024);
+
+	PrfQueryProfileString(HINI_USERPROFILE, "WPURLDEFAULTSETTINGS",
+						  "DefaultWorkingDir", NULL, browser, 1024);
+
+	if(browser[0])
+		_SetPath(browser);
+
+	PrfQueryProfileString(HINI_USERPROFILE, "WPURLDEFAULTSETTINGS",
+						  "DefaultBrowserExe", NULL, browser, 1024);
+
+	len = strlen(browser) - strlen("explore.exe");
+
+	execargs[0] = browser;
+	execargs[1] = url;
+	execargs[2] = NULL;
+
+	/* Special case for Web Explorer, it requires file:/// instead
+	 * of file:// so I am handling it here.
+	 */
+	if(len > 0)
+	{
+		if(stricmp(&browser[len], "explore.exe") == 0 && stricmp(url, "file://") == 0)
+		{
+			int newlen, z;
+			newurl = malloc(strlen(url) + 2);
+			sprintf(newurl, "file:///%s", &url[7]);
+			newlen = strlen(newurl);
+			for(z=8;z<(newlen-8);z++)
+			{
+				if(newurl[z] == '|')
+					newurl[z] = ':';
+				if(newurl[z] == '/')
+					newurl[z] = '\\';
+			}
+			execargs[1] = newurl;
+		}
+	}
+
+	ret = dw_exec(browser, DW_EXEC_GUI, execargs);
+
+	if(olddir)
+	{
+		_SetPath(olddir);
+		free(olddir);
+	}
+	if(newurl)
+		free(newurl);
+	return ret;
+}
+
+/*
+ * Returns a pointer to a static buffer which containes the
+ * current user directory.  Or the root directory (C:\ on
+ * OS/2 and Windows).
+ */
+char * API dw_user_dir(void)
+{
+	static char _user_dir[1024] = "";
+
+	if(!_user_dir[0])
+	{
+		char *home = getenv("HOME");
+
+		if(home)
+			strcpy(_user_dir, home);
+		else
+			strcpy(_user_dir, "C:\\");
+	}
+	return _user_dir;
+}
+
+/*
+ * Call a function from the window (widget)'s context.
+ * Parameters:
+ *       handle: Window handle of the widget.
+ *       function: Function pointer to be called.
+ *       data: Pointer to the data to be passed to the function.
+ */
+void API dw_window_function(HWND handle, void *function, void *data)
+{
+	WinSendMsg(handle, WM_USER, (MPARAM)function, (MPARAM)data);
+}
+
+/* Functions for managing the user data lists that are associated with
+ * a given window handle.  Used in dw_window_set_data() and
+ * dw_window_get_data().
+ */
+UserData *_find_userdata(UserData **root, char *varname)
+{
+	UserData *tmp = *root;
+
+	while(tmp)
+	{
+		if(stricmp(tmp->varname, varname) == 0)
+			return tmp;
+		tmp = tmp->next;
+	}
+	return NULL;
+}
+
+int _new_userdata(UserData **root, char *varname, void *data)
+{
+	UserData *new = _find_userdata(root, varname);
+
+	if(new)
+	{
+		new->data = data;
+		return TRUE;
+	}
+	else
+	{
+		new = malloc(sizeof(UserData));
+		if(new)
+		{
+			new->varname = strdup(varname);
+			new->data = data;
+
+			new->next = NULL;
+
+			if (!*root)
+				*root = new;
+			else
+			{
+				UserData *prev = NULL, *tmp = *root;
+				while(tmp)
+				{
+					prev = tmp;
+					tmp = tmp->next;
+				}
+				if(prev)
+					prev->next = new;
+				else
+					*root = new;
+			}
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+int _remove_userdata(UserData **root, char *varname, int all)
+{
+	UserData *prev = NULL, *tmp = *root;
+
+	while(tmp)
+	{
+		if(all || stricmp(tmp->varname, varname) == 0)
+		{
+			if(!prev)
+			{
+				*root = tmp->next;
+				free(tmp->varname);
+				free(tmp);
+				if(!all)
+					return 0;
+				tmp = *root;
+			}
+			else
+			{
+				/* If all is true we should
+				 * never get here.
+				 */
+				prev->next = tmp->next;
+				free(tmp->varname);
+				free(tmp);
+				return 0;
+			}
+		}
+		else
+		{
+			prev = tmp;
+			tmp = tmp->next;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Add a named user data item to a window handle.
+ * Parameters:
+ *       window: Window handle of signal to be called back.
+ *       dataname: A string pointer identifying which signal to be hooked.
+ *       data: User data to be passed to the handler function.
+ */
+void API dw_window_set_data(HWND window, char *dataname, void *data)
+{
+	WindowData *blah = (WindowData *)WinQueryWindowPtr(window, QWP_USER);
+
+	if(!blah)
+	{
+		if(!dataname)
+			return;
+
+		blah = calloc(1, sizeof(WindowData));
+		WinSetWindowPtr(window, QWP_USER, blah);
+	}
+
+	if(data)
+		_new_userdata(&(blah->root), dataname, data);
+	else
+	{
+		if(dataname)
+			_remove_userdata(&(blah->root), dataname, FALSE);
+		else
+			_remove_userdata(&(blah->root), NULL, TRUE);
+	}
+}
+
+/*
+ * Gets a named user data item to a window handle.
+ * Parameters:
+ *       window: Window handle of signal to be called back.
+ *       dataname: A string pointer identifying which signal to be hooked.
+ *       data: User data to be passed to the handler function.
+ */
+void * API dw_window_get_data(HWND window, char *dataname)
+{
+	WindowData *blah = (WindowData *)WinQueryWindowPtr(window, QWP_USER);
+
+	if(blah && blah->root && dataname)
+	{
+		UserData *ud = _find_userdata(&(blah->root), dataname);
+		if(ud)
+			return ud->data;
+	}
+	return NULL;
+}
+
+/*
+ * Add a callback to a timer event.
+ * Parameters:
+ *       interval: Milliseconds to delay between calls.
+ *       sigfunc: The pointer to the function to be used as the callback.
+ *       data: User data to be passed to the handler function.
+ * Returns:
+ *       Timer ID for use with dw_timer_disconnect(), 0 on error.
+ */
+int API dw_timer_connect(int interval, void *sigfunc, void *data)
+{
+	if(sigfunc)
+	{
+		int timerid = WinStartTimer(dwhab, NULLHANDLE, 0, interval);
+
+		if(timerid)
+		{
+			_new_signal(WM_TIMER, NULLHANDLE, timerid, sigfunc, data);
+			return timerid;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Removes timer callback.
+ * Parameters:
+ *       id: Timer ID returned by dw_timer_connect().
+ */
+void API dw_timer_disconnect(int id)
+{
+	SignalHandler *prev = NULL, *tmp = Root;
+
+	/* 0 is an invalid timer ID */
+	if(!id)
+		return;
+
+	WinStopTimer(dwhab, NULLHANDLE, id);
+
+	while(tmp)
+	{
+		if(tmp->id == id)
+		{
+			if(prev)
+			{
+				prev->next = tmp->next;
+				free(tmp);
+				tmp = prev->next;
+			}
+			else
+			{
+				Root = tmp->next;
+				free(tmp);
+				tmp = Root;
+			}
+		}
+		else
+		{
+			prev = tmp;
+			tmp = tmp->next;
+		}
+	}
+}
+
+/*
+ * Add a callback to a window event.
+ * Parameters:
+ *       window: Window handle of signal to be called back.
+ *       signame: A string pointer identifying which signal to be hooked.
+ *       sigfunc: The pointer to the function to be used as the callback.
+ *       data: User data to be passed to the handler function.
+ */
+void API dw_signal_connect(HWND window, char *signame, void *sigfunc, void *data)
+{
+	ULONG message = 0, id = 0;
+
+	if(window && signame && sigfunc)
+	{
+		if((message = _findsigmessage(signame)) != 0)
+		{
+			/* Handle special case of the menu item */
+			if(message == WM_COMMAND && window < 65536)
+			{
+				char buffer[15];
+				HWND owner;
+
+				sprintf(buffer, "_dw_id%d", (int)window);
+				owner = (HWND)dw_window_get_data(hwndApp, buffer);
+
+				if(owner)
+				{
+					id = window;
+					window = owner;
+					dw_window_set_data(hwndApp, buffer, 0);
+				}
+				else
+				{
+					/* If it is a popup menu clear all entries */
+					dw_signal_disconnect_by_window(window);
+				}
+			}
+			_new_signal(message, window, id, sigfunc, data);
+		}
+	}
+}
+
+/*
+ * Removes callbacks for a given window with given name.
+ * Parameters:
+ *       window: Window handle of callback to be removed.
+ */
+void API dw_signal_disconnect_by_name(HWND window, char *signame)
+{
+	SignalHandler *prev = NULL, *tmp = Root;
+	ULONG message;
+
+	if(!window || !signame || (message = _findsigmessage(signame)) == 0)
+		return;
+
+	while(tmp)
+	{
+		if(tmp->window == window && tmp->message == message)
+		{
+			if(prev)
+			{
+				prev->next = tmp->next;
+				free(tmp);
+				tmp = prev->next;
+			}
+			else
+			{
+				Root = tmp->next;
+				free(tmp);
+				tmp = Root;
+			}
+		}
+		else
+		{
+			prev = tmp;
+			tmp = tmp->next;
+		}
+	}
+}
+
+/*
+ * Removes all callbacks for a given window.
+ * Parameters:
+ *       window: Window handle of callback to be removed.
+ */
+void API dw_signal_disconnect_by_window(HWND window)
+{
+	SignalHandler *prev = NULL, *tmp = Root;
+
+	while(tmp)
+	{
+		if(tmp->window == window)
+		{
+			if(prev)
+			{
+				prev->next = tmp->next;
+				free(tmp);
+				tmp = prev->next;
+			}
+			else
+			{
+				Root = tmp->next;
+				free(tmp);
+				tmp = Root;
+			}
+		}
+		else
+		{
+			prev = tmp;
+			tmp = tmp->next;
+		}
+	}
+}
+
+/*
+ * Removes all callbacks for a given window with specified data.
+ * Parameters:
+ *       window: Window handle of callback to be removed.
+ *       data: Pointer to the data to be compared against.
+ */
+void API dw_signal_disconnect_by_data(HWND window, void *data)
+{
+	SignalHandler *prev = NULL, *tmp = Root;
+
+	while(tmp)
+	{
+		if(tmp->window == window && tmp->data == data)
+		{
+			if(prev)
+			{
+				prev->next = tmp->next;
+				free(tmp);
+				tmp = prev->next;
+			}
+			else
+			{
+				Root = tmp->next;
+				free(tmp);
+				tmp = Root;
+			}
+		}
+		else
+		{
+			prev = tmp;
+			tmp = tmp->next;
+		}
+	}
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dw.h	Fri Feb 18 02:50:18 2011 -0600
@@ -0,0 +1,1125 @@
+/* $Id: dw.h,v 1.1 2005/05/09 19:21:08 nuke Exp $ */
+
+#ifndef _H_DW
+#define _H_DW
+
+/* Dynamic Windows version numbers */
+#define DW_MAJOR_VERSION 0
+#define DW_MINOR_VERSION 9
+#define DW_SUB_VERSION 0
+
+/* These corespond to the entries in the color
+ * arrays in the Win32 dw.c, they are also the
+ * same as DOS ANSI colors.
+ */
+#define DW_CLR_BLACK             0
+#define DW_CLR_DARKRED           1
+#define DW_CLR_DARKGREEN         2
+#define DW_CLR_BROWN             3
+#define DW_CLR_DARKBLUE          4
+#define DW_CLR_DARKPINK          5
+#define DW_CLR_DARKCYAN          6
+#define DW_CLR_PALEGRAY          7
+#define DW_CLR_DARKGRAY          8
+#define DW_CLR_RED               9
+#define DW_CLR_GREEN             10
+#define DW_CLR_YELLOW            11
+#define DW_CLR_BLUE              12
+#define DW_CLR_PINK              13
+#define DW_CLR_CYAN              14
+#define DW_CLR_WHITE             15
+#define DW_CLR_DEFAULT           16
+
+/* Signal handler defines */
+#define DW_SIGNAL_CONFIGURE      "configure_event"
+#define DW_SIGNAL_KEY_PRESS      "key_press_event"
+#define DW_SIGNAL_BUTTON_PRESS   "button_press_event"
+#define DW_SIGNAL_BUTTON_RELEASE "button_release_event"
+#define DW_SIGNAL_MOTION_NOTIFY  "motion_notify_event"
+#define DW_SIGNAL_DELETE         "delete_event"
+#define DW_SIGNAL_EXPOSE         "expose_event"
+#define DW_SIGNAL_CLICKED        "clicked"
+#define DW_SIGNAL_ITEM_ENTER     "container-select"
+#define DW_SIGNAL_ITEM_CONTEXT   "container-context"
+#define DW_SIGNAL_ITEM_SELECT    "tree-select"
+#define DW_SIGNAL_LIST_SELECT    "item-select"
+#define DW_SIGNAL_SET_FOCUS      "set-focus"
+#define DW_SIGNAL_VALUE_CHANGED  "value_changed"
+#define DW_SIGNAL_SWITCH_PAGE    "switch-page"
+#define DW_SIGNAL_COLUMN_CLICK   "click-column"
+#define DW_SIGNAL_TREE_EXPAND    "tree-expand"
+
+#if defined(__OS2__) || defined(__WIN32__) || defined(__MAC__) || defined(WINNT) || defined(__EMX__)
+/* OS/2, Windows or MacOS */
+
+#if (defined(__IBMC__) || defined(_System)) && !defined(API)
+#define API _System
+#endif
+
+/* Used internally */
+#define TYPEBOX  0
+#define TYPEITEM 1
+
+#define SIZESTATIC 0
+#define SIZEEXPAND 1
+
+#define SPLITBAR_WIDTH 4
+#define BUBBLE_HELP_MAX 256
+
+typedef struct _user_data
+{
+	struct _user_data *next;
+	void              *data;
+	char              *varname;
+} UserData;
+
+/* OS/2 Specific section */
+#if defined(__OS2__) || defined(__EMX__)
+#define INCL_DOS
+#define INCL_WIN
+#define INCL_GPI
+
+#include <os2.h>
+
+#define DW_DT_LEFT               DT_LEFT
+#define DW_DT_QUERYEXTENT        DT_QUERYEXTENT
+#define DW_DT_UNDERSCORE         DT_UNDERSCORE
+#define DW_DT_STRIKEOUT          DT_STRIKEOUT
+#define DW_DT_TEXTATTRS          DT_TEXTATTRS
+#define DW_DT_EXTERNALLEADING    DT_EXTERNALLEADING
+#define DW_DT_CENTER             DT_CENTER
+#define DW_DT_RIGHT              DT_RIGHT
+#define DW_DT_TOP                DT_TOP
+#define DW_DT_VCENTER            DT_VCENTER
+#define DW_DT_BOTTOM             DT_BOTTOM
+#define DW_DT_HALFTONE           DT_HALFTONE
+#define DW_DT_MNEMONIC           DT_MNEMONIC
+#define DW_DT_WORDBREAK          DT_WORDBREAK
+#define DW_DT_ERASERECT          DT_ERASERECT
+
+#ifndef FCF_CLOSEBUTTON
+#define FCF_CLOSEBUTTON            0x04000000L
+#endif
+
+#define DW_FCF_TITLEBAR          FCF_TITLEBAR
+#define DW_FCF_SYSMENU           (FCF_SYSMENU | FCF_CLOSEBUTTON)
+#define DW_FCF_MENU              FCF_MENU
+#define DW_FCF_SIZEBORDER        FCF_SIZEBORDER
+#define DW_FCF_MINBUTTON         FCF_MINBUTTON
+#define DW_FCF_MAXBUTTON         FCF_MAXBUTTON
+#define DW_FCF_MINMAX            FCF_MINMAX
+#define DW_FCF_VERTSCROLL        FCF_VERTSCROLL
+#define DW_FCF_HORZSCROLL        FCF_HORZSCROLL
+#define DW_FCF_DLGBORDER         FCF_DLGBORDER
+#define DW_FCF_BORDER            FCF_BORDER
+#define DW_FCF_SHELLPOSITION     FCF_SHELLPOSITION
+#define DW_FCF_TASKLIST          FCF_TASKLIST
+#define DW_FCF_NOBYTEALIGN       FCF_NOBYTEALIGN
+#define DW_FCF_NOMOVEWITHOWNER   FCF_NOMOVEWITHOWNER
+#define DW_FCF_SYSMODAL          FCF_SYSMODAL
+#define DW_FCF_HIDEBUTTON        FCF_HIDEBUTTON
+#define DW_FCF_HIDEMAX           FCF_HIDEMAX
+#define DW_FCF_AUTOICON          FCF_AUTOICON
+#define DW_FCF_MAXIMIZE          WS_MAXIMIZED
+#define DW_FCF_MINIMIZE          WS_MINIMIZED
+
+#define DW_CFA_BITMAPORICON      CFA_BITMAPORICON
+#define DW_CFA_STRING            CFA_STRING
+#define DW_CFA_ULONG             CFA_ULONG
+#define DW_CFA_TIME              CFA_TIME
+#define DW_CFA_DATE              CFA_DATE
+#define DW_CFA_CENTER            CFA_CENTER
+#define DW_CFA_LEFT              CFA_LEFT
+#define DW_CFA_RIGHT             CFA_RIGHT
+#define DW_CFA_HORZSEPARATOR     CFA_HORZSEPARATOR
+#define DW_CFA_SEPARATOR         CFA_SEPARATOR
+#define DW_CFA_STRINGANDICON     0
+
+#define DW_CRA_SELECTED          CRA_SELECTED
+#define DW_CRA_CURSORED          CRA_CURSORED
+
+#define DW_LS_MULTIPLESEL        LS_MULTIPLESEL
+
+#define DW_LIT_NONE              -1
+
+#define DW_MLE_CASESENSITIVE     MLFSEARCH_CASESENSITIVE
+
+#define DW_POINTER_DEFAULT       0
+#define DW_POINTER_ARROW         SPTR_ARROW
+#define DW_POINTER_CLOCK         SPTR_WAIT
+
+#define DW_OS2_NEW_WINDOW        1
+
+/* flag values for dw_messagebox() */
+#define DW_MB_OK                 MB_OK
+#define DW_MB_OKCANCEL           MB_OKCANCEL
+#define DW_MB_YESNO              MB_YESNO
+#define DW_MB_YESNOCANCEL        MB_YESNOCANCEL
+
+#define DW_MB_WARNING            MB_WARNING
+#define DW_MB_ERROR              MB_ERROR
+#define DW_MB_INFORMATION        MB_INFORMATION
+#define DW_MB_QUESTION           MB_QUERY
+
+/* Virtual Key Codes */
+#define VK_LBUTTON           VK_BUTTON1
+#define VK_RBUTTON           VK_BUTTON2
+#define VK_MBUTTON           VK_BUTTON3
+#define VK_RETURN            VK_NEWLINE
+#define VK_SNAPSHOT          VK_PRINTSCRN
+#define VK_CANCEL            VK_BREAK
+#define VK_CAPITAL           VK_CAPSLOCK
+#define VK_ESCAPE            VK_ESC
+#define VK_PRIOR             VK_PAGEUP
+#define VK_NEXT              VK_PAGEDOWN
+#define VK_SELECT            133
+#define VK_EXECUTE           134
+#define VK_PRINT             135
+#define VK_HELP              136
+#define VK_LWIN              137
+#define VK_RWIN              138
+#define VK_MULTIPLY          ('*' + 128)
+#define VK_ADD               ('+' + 128)
+#define VK_SEPARATOR         141
+#define VK_SUBTRACT          ('-' + 128)
+#define VK_DECIMAL           ('.' + 128)
+#define VK_DIVIDE            ('/' + 128)
+#define VK_SCROLL            VK_SCRLLOCK
+#define VK_LSHIFT            VK_SHIFT
+#define VK_RSHIFT            147
+#define VK_LCONTROL          VK_CTRL
+#define VK_RCONTROL          149
+#define VK_NUMPAD0           ('0' + 128)
+#define VK_NUMPAD1           ('1' + 128)
+#define VK_NUMPAD2           ('2' + 128)
+#define VK_NUMPAD3           ('3' + 128)
+#define VK_NUMPAD4           ('4' + 128)
+#define VK_NUMPAD5           ('5' + 128)
+#define VK_NUMPAD6           ('6' + 128)
+#define VK_NUMPAD7           ('7' + 128)
+#define VK_NUMPAD8           ('8' + 128)
+#define VK_NUMPAD9           ('9' + 128)
+#define VK_BACK              VK_BACKSPACE
+#define VK_LMENU             VK_MENU
+#define VK_RMENU             VK_MENU
+
+typedef struct _window_data {
+	PFNWP oldproc;
+	UserData *root;
+	HWND clickdefault;
+	ULONG flags;
+	void *data;
+} WindowData;
+
+typedef struct _hpixmap {
+	unsigned long width, height;
+	HDC hdc;
+	HPS hps;
+	HBITMAP hbm;
+	HWND handle;
+} *HPIXMAP;
+
+typedef void *HTREEITEM;
+typedef HWND HMENUI;
+typedef HMODULE HMOD;
+typedef unsigned short UWORD;
+typedef unsigned long HSHM;
+
+extern HAB dwhab;
+extern HMQ dwhmq;
+#endif
+
+#if defined(__MAC__)
+/* MacOS specific section */
+#include <Carbon/Carbon.h>
+
+typedef ControlRef HWND;
+typedef ThreadID DWTID;
+typedef unsigned long ULONG;
+typedef long LONG;
+typedef unsigned short USHORT;
+typedef short SHORT;
+typedef unsigned short UWORD;
+typedef short WORD ;
+typedef unsigned char UCHAR;
+typedef char CHAR;
+typedef unsigned UINT;
+typedef int INT;
+typedef void *HMTX;
+typedef void *HEV;
+typedef void *HSHM;
+typedef void *HMOD;
+typedef void *HPIXMAP;
+typedef void *HTREEITEM;
+typedef MenuRef HMENUI;
+
+typedef struct _window_data {
+	UserData *root;
+	HWND clickdefault;
+	ULONG flags;
+	void *data;
+} WindowData;
+
+#define DW_DT_LEFT               0
+#define DW_DT_QUERYEXTENT        0
+#define DW_DT_UNDERSCORE         0
+#define DW_DT_STRIKEOUT          0
+#define DW_DT_TEXTATTRS          0
+#define DW_DT_EXTERNALLEADING    0
+#define DW_DT_CENTER             0
+#define DW_DT_RIGHT              0
+#define DW_DT_TOP                0
+#define DW_DT_VCENTER            0
+#define DW_DT_BOTTOM             0
+#define DW_DT_HALFTONE           0
+#define DW_DT_MNEMONIC           0
+#define DW_DT_WORDBREAK          0
+#define DW_DT_ERASERECT          0
+
+#define DW_FCF_TITLEBAR          0
+#define DW_FCF_SYSMENU           kWindowCloseBoxAttribute
+#define DW_FCF_MENU              0
+#define DW_FCF_SIZEBORDER        (kWindowResizableAttribute|kWindowLiveResizeAttribute)
+#define DW_FCF_MINBUTTON         kWindowCollapseBoxAttribute
+#define DW_FCF_MAXBUTTON         kWindowFullZoomAttribute
+#define DW_FCF_MINMAX            (kWindowCollapseBoxAttribute|kWindowFullZoomAttribute)
+#define DW_FCF_VERTSCROLL        0
+#define DW_FCF_HORZSCROLL        0
+#define DW_FCF_DLGBORDER         0
+#define DW_FCF_BORDER            0
+#define DW_FCF_SHELLPOSITION     0
+#define DW_FCF_TASKLIST          0
+#define DW_FCF_NOBYTEALIGN       0
+#define DW_FCF_NOMOVEWITHOWNER   0
+#define DW_FCF_SYSMODAL          0
+#define DW_FCF_HIDEBUTTON        kWindowCollapseAttribute
+#define DW_FCF_HIDEMAX           0
+#define DW_FCF_AUTOICON          0
+#define DW_FCF_MAXIMIZE          0
+#define DW_FCF_MINIMIZE          0
+
+#define DW_CFA_BITMAPORICON      1
+#define DW_CFA_STRING            (1 << 1)
+#define DW_CFA_ULONG             (1 << 2)
+#define DW_CFA_TIME              (1 << 3)
+#define DW_CFA_DATE              (1 << 4)
+#define DW_CFA_CENTER            (1 << 5)
+#define DW_CFA_LEFT              (1 << 6)
+#define DW_CFA_RIGHT             (1 << 7)
+#define DW_CFA_STRINGANDICON     (1 << 8)
+#define DW_CFA_HORZSEPARATOR     0
+#define DW_CFA_SEPARATOR         0
+
+#define DW_CRA_SELECTED          1
+#define DW_CRA_CURSORED          (1 << 1)
+
+#define DW_LS_MULTIPLESEL        1
+
+#define DW_LIT_NONE              -1
+
+#define DW_MLE_CASESENSITIVE     MLFSEARCH_CASESENSITIVE
+
+#define DW_POINTER_DEFAULT       0
+#define DW_POINTER_ARROW         0
+#define DW_POINTER_CLOCK         watchCursor
+
+#define HWND_DESKTOP		 ((HWND)0)
+
+/* flag values for dw_messagebox() */
+#define DW_MB_OK                 (1 << 1)
+#define DW_MB_OKCANCEL           (1 << 2)
+#define DW_MB_YESNO              (1 << 3)
+#define DW_MB_YESNOCANCEL        (1 << 4)
+
+#define DW_MB_WARNING            (1 << 10)
+#define DW_MB_ERROR              (1 << 11)
+#define DW_MB_INFORMATION        (1 << 12)
+#define DW_MB_QUESTION           (1 << 13)
+
+
+#endif
+
+/* Windows specific section */
+#if defined(__WIN32__) || defined(WINNT)
+#include <windows.h>
+#include <commctrl.h>
+
+#if defined(MSVC) && !defined(API)
+# ifdef __MINGW32__
+#  ifdef BUILD_DLL
+#   define API APIENTRY __declspec(dllexport)
+#  else
+#   define API APIENTRY __declspec(dllimport)
+#  endif
+# else
+#  define API _cdecl
+#endif
+#endif
+
+#define DW_DT_LEFT               SS_LEFT
+#define DW_DT_QUERYEXTENT        0
+#define DW_DT_UNDERSCORE         0
+#define DW_DT_STRIKEOUT          0
+#define DW_DT_TEXTATTRS          0
+#define DW_DT_EXTERNALLEADING    0
+#define DW_DT_CENTER             SS_CENTER
+#define DW_DT_RIGHT              SS_RIGHT
+#define DW_DT_TOP                0
+#define DW_DT_VCENTER            SS_NOPREFIX
+#define DW_DT_BOTTOM             0
+#define DW_DT_HALFTONE           0
+#define DW_DT_MNEMONIC           0
+#define DW_DT_WORDBREAK          0
+#define DW_DT_ERASERECT          0
+
+#define DW_FCF_TITLEBAR          WS_CAPTION
+#define DW_FCF_SYSMENU           WS_SYSMENU
+#define DW_FCF_MENU              0
+#define DW_FCF_SIZEBORDER        WS_THICKFRAME
+#define DW_FCF_MINBUTTON         WS_MINIMIZEBOX
+#define DW_FCF_MAXBUTTON         WS_MAXIMIZEBOX
+#define DW_FCF_MINMAX            (WS_MINIMIZEBOX|WS_MAXIMIZEBOX)
+#define DW_FCF_VERTSCROLL        WS_VSCROLL
+#define DW_FCF_HORZSCROLL        WS_HSCROLL
+#define DW_FCF_DLGBORDER         WS_DLGFRAME
+#define DW_FCF_BORDER            WS_BORDER
+#define DW_FCF_SHELLPOSITION     0
+#define DW_FCF_TASKLIST          WS_VSCROLL
+#define DW_FCF_NOBYTEALIGN       0
+#define DW_FCF_NOMOVEWITHOWNER   0
+#define DW_FCF_SYSMODAL          0
+#define DW_FCF_HIDEBUTTON        WS_MINIMIZEBOX
+#define DW_FCF_HIDEMAX           0
+#define DW_FCF_AUTOICON          0
+#define DW_FCF_MAXIMIZE          WS_MAXIMIZE
+#define DW_FCF_MINIMIZE          WS_MINIMIZE
+
+#define DW_CFA_BITMAPORICON      1
+#define DW_CFA_STRING            (1 << 1)
+#define DW_CFA_ULONG             (1 << 2)
+#define DW_CFA_TIME              (1 << 3)
+#define DW_CFA_DATE              (1 << 4)
+#define DW_CFA_CENTER            (1 << 5)
+#define DW_CFA_LEFT              (1 << 6)
+#define DW_CFA_RIGHT             (1 << 7)
+#define DW_CFA_STRINGANDICON     (1 << 8)
+#define DW_CFA_HORZSEPARATOR     0
+#define DW_CFA_SEPARATOR         0
+
+#define DW_CRA_SELECTED          LVNI_SELECTED
+#define DW_CRA_CURSORED          LVNI_FOCUSED
+
+#define DW_LS_MULTIPLESEL        LBS_MULTIPLESEL
+
+#define DW_LIT_NONE              -1
+
+#define DW_MLE_CASESENSITIVE     1
+
+#define DW_POINTER_DEFAULT       0
+#define DW_POINTER_ARROW         32512
+#define DW_POINTER_CLOCK         32514
+
+/* flag values for dw_messagebox() */
+#define DW_MB_OK                 MB_OK
+#define DW_MB_OKCANCEL           MB_OKCANCEL
+#define DW_MB_YESNO              MB_YESNO
+#define DW_MB_YESNOCANCEL        MB_YESNOCANCEL
+
+#define DW_MB_WARNING            MB_ICONWARNING
+#define DW_MB_ERROR              MB_ICONERROR
+#define DW_MB_INFORMATION        MB_ICONINFORMATION
+#define DW_MB_QUESTION           MB_ICONQUESTION
+
+/* Key Modifiers */
+#define KC_CTRL                  (1)
+#define KC_SHIFT                 (1 << 1)
+#define KC_ALT                   (1 << 2)
+
+#define STATICCLASSNAME "STATIC"
+#define COMBOBOXCLASSNAME "COMBOBOX"
+#define LISTBOXCLASSNAME "LISTBOX"
+#define BUTTONCLASSNAME "BUTTON"
+#define POPUPMENUCLASSNAME "POPUPMENU"
+#define EDITCLASSNAME "EDIT"
+#define FRAMECLASSNAME "FRAME"
+#define SCROLLBARCLASSNAME "SCROLLBAR"
+
+#define ClassName "dynamicwindows"
+#define SplitbarClassName "dwsplitbar"
+#define ObjectClassName "dwobjectclass"
+#define DefaultFont NULL
+
+typedef struct _color {
+	int fore;
+	int back;
+	HWND combo, buddy;
+	int user;
+	int vcenter;
+	HWND clickdefault;
+	HBRUSH hbrush;
+	HFONT hfont;
+	char fontname[128];
+	WNDPROC pOldProc;
+	UserData *root;
+} ColorInfo;
+
+typedef struct _notebookpage {
+	ColorInfo cinfo;
+	TC_ITEM item;
+	HWND hwnd;
+	int realid;
+} NotebookPage;
+
+typedef HANDLE HMTX;
+typedef HANDLE HEV;
+typedef HANDLE HMOD;
+typedef HANDLE HSHM;
+
+typedef struct _container {
+	ColorInfo cinfo;
+	ULONG *flags;
+	WNDPROC pOldProc;
+	ULONG columns;
+} ContainerInfo;
+
+typedef struct _hpixmap {
+	unsigned long width, height;
+	HBITMAP hbm;
+	HDC hdc;
+	HWND handle;
+	void *bits;
+} *HPIXMAP;
+
+typedef HWND HMENUI;
+#endif
+
+typedef struct _item {
+	/* Item type - Box or Item */
+	int type;
+	/* Handle to Frame or Window */
+	HWND hwnd;
+	/* Width and Height of static size */
+	int width, height, origwidth, origheight;
+	/* Size Type - Static or Expand */
+	int hsize, vsize;
+	/* Padding */
+	int pad;
+	/* Ratio of current item */
+	float xratio, yratio;
+} Item;
+
+typedef struct _box {
+#if defined(__WIN32__) || defined(WINNT)
+	ColorInfo cinfo;
+#elif defined(__OS2__) || defined(__EMX__)
+	PFNWP oldproc;
+	UserData *root;
+	HWND hwndtitle, hwnd;
+	int titlebar;
+#endif
+	/* Number of items in the box */
+	int count;
+	/* Box type - horizontal or vertical */
+	int type;
+	/* Padding */
+	int pad, parentpad, grouppadx, grouppady;
+	/* Groupbox */
+	HWND grouphwnd;
+	/* Default item */
+	HWND defaultitem;
+	/* Used as temporary storage in the calculation stage */
+	int upx, upy, minheight, minwidth;
+	/* Ratio in this box */
+	float xratio, yratio, parentxratio, parentyratio;
+	/* Used for calculating individual item ratios */
+	int width, height;
+	/* Any combinations of flags describing the box */
+	unsigned long flags;
+	/* Array of item structures */
+	struct _item *items;
+} Box;
+
+typedef struct _bubblebutton {
+#if defined(__WIN32__) || defined(WINNT)
+	ColorInfo cinfo;
+	int checkbox;
+	WNDPROC pOldProc;
+#endif
+#if defined(__OS2__) || defined(__EMX__)
+	PFNWP pOldProc;
+	UserData *root;
+#endif
+	unsigned long id;
+	char bubbletext[BUBBLE_HELP_MAX];
+} BubbleButton;
+
+#else
+/* GTK Specific section */
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkprivate.h>
+#include <gdk/gdkkeysyms.h>
+#include <pthread.h>
+#include <dlfcn.h>
+
+#define DW_DT_LEFT               1
+#define DW_DT_UNDERSCORE         (1 << 1)
+#define DW_DT_STRIKEOUT          (1 << 2)
+#define DW_DT_CENTER             (1 << 3)
+#define DW_DT_RIGHT              (1 << 4)
+#define DW_DT_TOP                (1 << 5)
+#define DW_DT_VCENTER            (1 << 6)
+#define DW_DT_BOTTOM             (1 << 7)
+#define DW_DT_HALFTONE           (1 << 8)
+#define DW_DT_MNEMONIC           (1 << 9)
+#define DW_DT_WORDBREAK          (1 << 10)
+#define DW_DT_ERASERECT          (1 << 11)
+
+/* these don't exist under gtk, so make them dummy entries */
+#define DW_DT_QUERYEXTENT        0
+#define DW_DT_TEXTATTRS          0
+#define DW_DT_EXTERNALLEADING    0
+
+#define DW_FCF_TITLEBAR          1
+#define DW_FCF_SYSMENU           (1 << 1)
+#define DW_FCF_MENU              (1 << 2)
+#define DW_FCF_SIZEBORDER        (1 << 3)
+#define DW_FCF_MINBUTTON         (1 << 4)
+#define DW_FCF_MAXBUTTON         (1 << 5)
+#define DW_FCF_MINMAX            (1 << 6)
+#define DW_FCF_VERTSCROLL        (1 << 7)
+#define DW_FCF_HORZSCROLL        (1 << 8)
+#define DW_FCF_DLGBORDER         (1 << 9)
+#define DW_FCF_BORDER            (1 << 10)
+#define DW_FCF_SHELLPOSITION     (1 << 11)
+#define DW_FCF_TASKLIST          (1 << 12)
+#define DW_FCF_NOBYTEALIGN       (1 << 13)
+#define DW_FCF_NOMOVEWITHOWNER   (1 << 14)
+#define DW_FCF_SYSMODAL          (1 << 15)
+#define DW_FCF_HIDEBUTTON        (1 << 16)
+#define DW_FCF_HIDEMAX           (1 << 17)
+#define DW_FCF_AUTOICON          (1 << 18)
+#define DW_FCF_MAXIMIZE          (1 << 19)
+#define DW_FCF_MINIMIZE          (1 << 20)
+
+#define DW_CFA_BITMAPORICON      1
+#define DW_CFA_STRING            (1 << 1)
+#define DW_CFA_ULONG             (1 << 2)
+#define DW_CFA_TIME              (1 << 3)
+#define DW_CFA_DATE              (1 << 4)
+#define DW_CFA_CENTER            (1 << 5)
+#define DW_CFA_LEFT              (1 << 6)
+#define DW_CFA_RIGHT             (1 << 7)
+#define DW_CFA_HORZSEPARATOR     (1 << 8)
+#define DW_CFA_SEPARATOR         (1 << 9)
+#define DW_CFA_STRINGANDICON     (1 << 10)
+
+#define DW_CRA_SELECTED          1
+#define DW_CRA_CURSORED          (1 << 1)
+
+#define DW_LS_MULTIPLESEL        1
+
+#define DW_LIT_NONE              -1
+
+#define DW_MLE_CASESENSITIVE     1
+
+#define DW_POINTER_DEFAULT       0
+#define DW_POINTER_ARROW         GDK_TOP_LEFT_ARROW
+#define DW_POINTER_CLOCK         GDK_WATCH
+
+#define HWND_DESKTOP             ((HWND)0)
+
+/* flag values for dw_messagebox() */
+#define DW_MB_OK                 (1 << 1)
+#define DW_MB_OKCANCEL           (1 << 2)
+#define DW_MB_YESNO              (1 << 3)
+#define DW_MB_YESNOCANCEL        (1 << 4)
+
+#define DW_MB_WARNING            (1 << 10)
+#define DW_MB_ERROR              (1 << 11)
+#define DW_MB_INFORMATION        (1 << 12)
+#define DW_MB_QUESTION           (1 << 13)
+
+/* Virtual Key Codes */
+#define VK_LBUTTON           GDK_Pointer_Button1
+#define VK_RBUTTON           GDK_Pointer_Button3
+#define VK_CANCEL            GDK_Cancel
+#define VK_MBUTTON           GDK_Pointer_Button2
+#define VK_BACK              GDK_BackSpace
+#define VK_TAB               GDK_Tab
+#define VK_CLEAR             GDK_Clear
+#define VK_RETURN            GDK_Return
+#define VK_MENU              GDK_Menu
+#define VK_PAUSE             GDK_Pause
+#define VK_CAPITAL           GDK_Caps_Lock
+#define VK_ESCAPE            GDK_Escape
+#define VK_SPACE             GDK_space
+#define VK_PRIOR             GDK_Page_Up
+#define VK_NEXT              GDK_Page_Down
+#define VK_END               GDK_End
+#define VK_HOME              GDK_Home
+#define VK_LEFT              GDK_Left
+#define VK_UP                GDK_Up
+#define VK_RIGHT             GDK_Right
+#define VK_DOWN              GDK_Down
+#define VK_SELECT            GDK_Select
+#define VK_PRINT             GDK_Sys_Req
+#define VK_EXECUTE           GDK_Execute
+#define VK_SNAPSHOT          GDK_Print
+#define VK_INSERT            GDK_Insert
+#define VK_DELETE            GDK_Delete
+#define VK_HELP              GDK_Help
+#define VK_LWIN              GDK_Super_L
+#define VK_RWIN              GDK_Super_R
+#define VK_NUMPAD0           GDK_KP_0
+#define VK_NUMPAD1           GDK_KP_1
+#define VK_NUMPAD2           GDK_KP_2
+#define VK_NUMPAD3           GDK_KP_3
+#define VK_NUMPAD4           GDK_KP_4
+#define VK_NUMPAD5           GDK_KP_5
+#define VK_NUMPAD6           GDK_KP_6
+#define VK_NUMPAD7           GDK_KP_7
+#define VK_NUMPAD8           GDK_KP_8
+#define VK_NUMPAD9           GDK_KP_9
+#define VK_MULTIPLY          GDK_KP_Multiply
+#define VK_ADD               GDK_KP_Add
+#define VK_SEPARATOR         GDK_KP_Separator
+#define VK_SUBTRACT          GDK_KP_Subtract
+#define VK_DECIMAL           GDK_KP_Decimal
+#define VK_DIVIDE            GDK_KP_Divide
+#define VK_F1                GDK_F1
+#define VK_F2                GDK_F2
+#define VK_F3                GDK_F3
+#define VK_F4                GDK_F4
+#define VK_F5                GDK_F5
+#define VK_F6                GDK_F6
+#define VK_F7                GDK_F7
+#define VK_F8                GDK_F8
+#define VK_F9                GDK_F9
+#define VK_F10               GDK_F10
+#define VK_F11               GDK_F11
+#define VK_F12               GDK_F12
+#define VK_F13               GDK_F13
+#define VK_F14               GDK_F14
+#define VK_F15               GDK_F15
+#define VK_F16               GDK_F16
+#define VK_F17               GDK_F17
+#define VK_F18               GDK_F18
+#define VK_F19               GDK_F19
+#define VK_F20               GDK_F20
+#define VK_F21               GDK_F21
+#define VK_F22               GDK_F22
+#define VK_F23               GDK_F23
+#define VK_F24               GDK_F24
+#define VK_NUMLOCK           GDK_Num_Lock
+#define VK_SCROLL            GDK_Scroll_Lock
+#define VK_LSHIFT            GDK_Shift_L
+#define VK_RSHIFT            GDK_Shift_R
+#define VK_LCONTROL          GDK_Control_L
+#define VK_RCONTROL          GDK_Control_R
+#define VK_LMENU             GDK_Menu
+#define VK_RMENU             GDK_Menu
+
+/* Key Modifiers */
+#define KC_CTRL              GDK_CONTROL_MASK
+#define KC_SHIFT             GDK_SHIFT_MASK
+#define KC_ALT               GDK_MOD1_MASK
+
+typedef GtkWidget *HWND;
+#ifndef _ENVRNMNT_H
+typedef unsigned long ULONG;
+#endif
+typedef long LONG;
+typedef unsigned short USHORT;
+typedef short SHORT;
+typedef unsigned short UWORD;
+typedef short WORD ;
+typedef unsigned char UCHAR;
+typedef char CHAR;
+typedef unsigned UINT;
+typedef int INT;
+typedef pthread_mutex_t *HMTX;
+typedef struct _dw_unix_event {
+	pthread_mutex_t mutex;
+	pthread_cond_t event;
+	pthread_t thread;
+	int alive;
+	int posted;
+} *HEV;
+typedef pthread_t DWTID;
+typedef void * HMOD;
+struct _dw_unix_shm {
+	int fd;
+	char *path;
+	int sid;
+	int size;
+};
+
+typedef struct _hpixmap {
+	unsigned long width, height;
+	GdkPixmap *pixmap;
+	HWND handle;
+} *HPIXMAP;
+
+typedef GtkWidget *HMENUI;
+typedef void *HTREEITEM;
+typedef void *HSHM;
+
+typedef struct _resource_struct {
+	long resource_max, *resource_id;
+	char **resource_data;
+} DWResources;
+
+#if !defined(DW_RESOURCES) || defined(BUILD_DLL)
+static DWResources _resources = { 0, 0, 0 };
+#else
+extern DWResources _resources;
+#endif
+
+#endif
+
+#if !defined(__OS2__) && !defined(__EMX__)
+typedef struct _CDATE
+{
+	UCHAR  day;
+	UCHAR  month;
+	USHORT year;
+} CDATE;
+typedef CDATE *PCDATE;
+
+typedef struct _CTIME
+{
+	UCHAR hours;
+	UCHAR minutes;
+	UCHAR seconds;
+	UCHAR ucReserved;
+} CTIME;
+typedef CTIME *PCTIME;
+#endif
+
+#if defined(__OS2__) || defined(__WIN32__) || defined(WINNT) || defined(__EMX__)
+typedef unsigned long DWTID;
+#endif
+
+typedef struct _dwenv {
+	/* Operating System Name and DW Build Date/Time */
+	char osName[30], buildDate[30], buildTime[30];
+	/* Versions and builds */
+	short MajorVersion, MinorVersion, MajorBuild, MinorBuild;
+	/* Dynamic Window version */
+	short DWMajorVersion, DWMinorVersion, DWSubVersion;
+} DWEnv;
+
+
+typedef struct _dwexpose {
+	int x, y;
+	int width, height;
+} DWExpose;
+
+typedef struct _dwdialog {
+	HEV eve;
+	int done;
+	int method;
+	void *data, *result;
+} DWDialog;
+
+#define DW_SIGNAL_FUNC(a) ((void *)a)
+
+#define DW_DESKTOP               HWND_DESKTOP
+#define DW_MINIMIZED 1
+
+#define DW_BUTTON1_MASK 1
+#define DW_BUTTON2_MASK (1 << 1)
+#define DW_BUTTON3_MASK (1 << 2)
+
+#define DW_EXEC_CON 0
+#define DW_EXEC_GUI 1
+
+#define DW_FILE_OPEN      0
+#define DW_FILE_SAVE      1
+#define DW_DIRECTORY_OPEN 2
+
+#define DW_HORZ 0
+#define DW_VERT 1
+
+/* Obsolete, should disappear sometime */
+#define BOXHORZ DW_HORZ
+#define BOXVERT DW_VERT
+
+#define DW_SCROLL_UP 0
+#define DW_SCROLL_DOWN 1
+#define DW_SCROLL_TOP 2
+#define DW_SCROLL_BOTTOM 3
+
+/* return values for dw_messagebox() */
+#define DW_MB_RETURN_OK           0
+#define DW_MB_RETURN_YES          1
+#define DW_MB_RETURN_NO           0
+#define DW_MB_RETURN_CANCEL       2
+
+#define DW_PIXMAP_WIDTH(x) (x ? x->width : 0)
+#define DW_PIXMAP_HEIGHT(x) (x ? x->height : 0)
+
+#define DW_RGB_COLOR (0xF0000000)
+#define DW_RGB_TRANSPARENT (0x0F000000)
+#define DW_RGB_MASK (0x00FFFFFF)
+#define DW_RED_MASK (0x000000FF)
+#define DW_GREEN_MASK (0x0000FF00)
+#define DW_BLUE_MASK (0x00FF0000)
+#define DW_RED_VALUE(a) (a & DW_RED_MASK)
+#define DW_GREEN_VALUE(a) ((a & DW_GREEN_MASK) >> 8)
+#define DW_BLUE_VALUE(a) ((a & DW_BLUE_MASK) >> 16)
+#define DW_RGB(a, b, c) (0xF0000000 | a | b << 8 | c << 16)
+
+#define DW_MENU_SEPARATOR ""
+#define DW_NOMENU 0
+
+/* Return value error codes */
+#define DW_ERROR_NONE      0
+#define DW_ERROR_GENERAL   1
+#define DW_ERROR_TIMEOUT   2
+#define DW_ERROR_NON_INIT  3
+#define DW_ERROR_NO_MEM    4
+#define DW_ERROR_INTERRUPT 5
+
+#ifndef API
+#define API
+#endif
+
+#define DWSIGNAL API
+
+/* Let other APIs know what types we've defined,
+ * Regina REXX in particular, on Unix.
+ */
+#define ULONG_TYPEDEFED 1
+#define LONG_TYPEDEFED 1
+#define USHORT_TYPEDEFED 1
+#define SHORT_TYPEDEFED 1
+#define UWORD_TYPEDEFED 1
+#define WORD_TYPEDEFED 1
+#define UCHAR_TYPEDEFED 1
+#define CHAR_TYPEDEFED 1
+#define UINT_TYPEDEFED 1
+#define INT_TYPEDEFED 1
+
+/* Public function prototypes */
+void API dw_box_pack_start(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad);
+void API dw_box_pack_end(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad);
+#if !defined(__OS2__) && !defined(__WIN32__) && !defined(__EMX__) && !defined(__MAC__)
+int API dw_int_init(DWResources *res, int newthread, int *argc, char **argv[]);
+#define dw_init(a, b, c) dw_int_init(&_resources, a, &b, &c)
+#else
+int API dw_init(int newthread, int argc, char *argv[]);
+#endif
+void API dw_main(void);
+void API dw_main_sleep(int seconds);
+void API dw_main_iteration(void);
+void API dw_free(void *ptr);
+int API dw_window_show(HWND handle);
+int API dw_window_hide(HWND handle);
+int API dw_window_minimize(HWND handle);
+int API dw_window_raise(HWND handle);
+int API dw_window_lower(HWND handle);
+int API dw_window_destroy(HWND handle);
+void API dw_window_redraw(HWND handle);
+int API dw_window_set_font(HWND handle, char *fontname);
+int API dw_window_set_color(HWND handle, unsigned long fore, unsigned long back);
+HWND API dw_window_new(HWND hwndOwner, char *title, unsigned long flStyle);
+HWND API dw_box_new(int type, int pad);
+HWND API dw_groupbox_new(int type, int pad, char *title);
+HWND API dw_mdi_new(unsigned long id);
+HWND API dw_bitmap_new(unsigned long id);
+HWND API dw_bitmapbutton_new(char *text, unsigned long id);
+HWND API dw_bitmapbutton_new_from_file(char *text, unsigned long id, char *filename);
+HWND API dw_container_new(unsigned long id, int multi);
+HWND API dw_tree_new(unsigned long id);
+HWND API dw_text_new(char *text, unsigned long id);
+HWND API dw_status_text_new(char *text, unsigned long id);
+HWND API dw_mle_new(unsigned long id);
+HWND API dw_entryfield_new(char *text, unsigned long id);
+HWND API dw_entryfield_password_new(char *text, ULONG id);
+HWND API dw_combobox_new(char *text, unsigned long id);
+HWND API dw_button_new(char *text, unsigned long id);
+HWND API dw_spinbutton_new(char *text, unsigned long id);
+HWND API dw_radiobutton_new(char *text, ULONG id);
+HWND API dw_percent_new(unsigned long id);
+HWND API dw_slider_new(int vertical, int increments, ULONG id);
+HWND API dw_scrollbar_new(int vertical, ULONG id);
+HWND API dw_checkbox_new(char *text, unsigned long id);
+HWND API dw_listbox_new(unsigned long id, int multi);
+void API dw_listbox_append(HWND handle, char *text);
+void API dw_listbox_list_append(HWND handle, char **text, int count);
+void API dw_listbox_clear(HWND handle);
+int API dw_listbox_count(HWND handle);
+void API dw_listbox_set_top(HWND handle, int top);
+void API dw_listbox_select(HWND handle, int index, int state);
+void API dw_listbox_delete(HWND handle, int index);
+void API dw_listbox_get_text(HWND handle, unsigned int index, char *buffer, unsigned int length);
+void API dw_listbox_set_text(HWND handle, unsigned int index, char *buffer);
+unsigned int API dw_listbox_selected(HWND handle);
+int API dw_listbox_selected_multi(HWND handle, int where);
+void API dw_percent_set_pos(HWND handle, unsigned int position);
+unsigned int API dw_slider_get_pos(HWND handle);
+void API dw_slider_set_pos(HWND handle, unsigned int position);
+unsigned int API dw_scrollbar_get_pos(HWND handle);
+void API dw_scrollbar_set_pos(HWND handle, unsigned int position);
+void API dw_scrollbar_set_range(HWND handle, unsigned int range, unsigned int visible);
+void API dw_window_set_pos(HWND handle, unsigned long x, unsigned long y);
+void API dw_window_set_size(HWND handle, unsigned long width, unsigned long height);
+void API dw_window_set_pos_size(HWND handle, unsigned long x, unsigned long y, unsigned long width, unsigned long height);
+void API dw_window_get_pos_size(HWND handle, unsigned long *x, unsigned long *y, unsigned long *width, unsigned long *height);
+void API dw_window_set_style(HWND handle, unsigned long style, unsigned long mask);
+void API dw_window_set_icon(HWND handle, unsigned long id);
+void API dw_window_set_bitmap(HWND handle, unsigned long id, char *filename);
+char * API dw_window_get_text(HWND handle);
+void API dw_window_set_text(HWND handle, char *text);
+int API dw_window_set_border(HWND handle, int border);
+void API dw_window_disable(HWND handle);
+void API dw_window_enable(HWND handle);
+void API dw_window_capture(HWND handle);
+void API dw_window_release(void);
+void API dw_window_reparent(HWND handle, HWND newparent);
+void API dw_window_set_pointer(HWND handle, int pointertype);
+void API dw_window_default(HWND window, HWND defaultitem);
+void API dw_window_click_default(HWND window, HWND next);
+unsigned int API dw_mle_import(HWND handle, char *buffer, int startpoint);
+void API dw_mle_export(HWND handle, char *buffer, int startpoint, int length);
+void API dw_mle_get_size(HWND handle, unsigned long *bytes, unsigned long *lines);
+void API dw_mle_delete(HWND handle, int startpoint, int length);
+void API dw_mle_clear(HWND handle);
+void API dw_mle_freeze(HWND handle);
+void API dw_mle_thaw(HWND handle);
+void API dw_mle_set_cursor(HWND handle, int point);
+void API dw_mle_set_visible(HWND handle, int line);
+void API dw_mle_set_editable(HWND handle, int state);
+void API dw_mle_set_word_wrap(HWND handle, int state);
+int API dw_mle_search(HWND handle, char *text, int point, unsigned long flags);
+void API dw_spinbutton_set_pos(HWND handle, long position);
+void API dw_spinbutton_set_limits(HWND handle, long upper, long lower);
+void API dw_entryfield_set_limit(HWND handle, ULONG limit);
+long API dw_spinbutton_get_pos(HWND handle);
+int API dw_checkbox_get(HWND handle);
+void API dw_checkbox_set(HWND handle, int value);
+HTREEITEM API dw_tree_insert(HWND handle, char *title, unsigned long icon, HTREEITEM parent, void *itemdata);
+HTREEITEM API dw_tree_insert_after(HWND handle, HTREEITEM item, char *title, unsigned long icon, HTREEITEM parent, void *itemdata);
+void API dw_tree_clear(HWND handle);
+void API dw_tree_item_delete(HWND handle, HTREEITEM item);
+void API dw_tree_item_change(HWND handle, HTREEITEM item, char *title, unsigned long icon);
+void API dw_tree_item_expand(HWND handle, HTREEITEM item);
+void API dw_tree_item_collapse(HWND handle, HTREEITEM item);
+void API dw_tree_item_select(HWND handle, HTREEITEM item);
+void API dw_tree_item_set_data(HWND handle, HTREEITEM item, void *itemdata);
+void * API dw_tree_item_get_data(HWND handle, HTREEITEM item);
+char * API dw_tree_get_title(HWND handle, HTREEITEM item);
+HTREEITEM API dw_tree_get_parent(HWND handle, HTREEITEM item);
+int API dw_container_setup(HWND handle, unsigned long *flags, char **titles, int count, int separator);
+unsigned long API dw_icon_load(unsigned long module, unsigned long id);
+unsigned long API dw_icon_load_from_file(char *filename);
+void API dw_icon_free(unsigned long handle);
+void * API dw_container_alloc(HWND handle, int rowcount);
+void API dw_container_set_item(HWND handle, void *pointer, int column, int row, void *data);
+void API dw_container_change_item(HWND handle, int column, int row, void *data);
+void API dw_container_set_column_width(HWND handle, int column, int width);
+void API dw_container_set_row_title(void *pointer, int row, char *title);
+void API dw_container_insert(HWND handle, void *pointer, int rowcount);
+void API dw_container_clear(HWND handle, int redraw);
+void API dw_container_delete(HWND handle, int rowcount);
+char * API dw_container_query_start(HWND handle, unsigned long flags);
+char * API dw_container_query_next(HWND handle, unsigned long flags);
+void API dw_container_scroll(HWND handle, int direction, long rows);
+void API dw_container_cursor(HWND handle, char *text);
+void API dw_container_delete_row(HWND handle, char *text);
+void API dw_container_optimize(HWND handle);
+int API dw_filesystem_setup(HWND handle, unsigned long *flags, char **titles, int count);
+void API dw_filesystem_set_item(HWND handle, void *pointer, int column, int row, void *data);
+void API dw_filesystem_set_file(HWND handle, void *pointer, int row, char *filename, unsigned long icon);
+void API dw_filesystem_change_item(HWND handle, int column, int row, void *data);
+void API dw_filesystem_change_file(HWND handle, int row, char *filename, unsigned long icon);
+int API dw_container_get_column_type(HWND handle, int column);
+int API dw_filesystem_get_column_type(HWND handle, int column);
+void API dw_taskbar_insert(HWND handle, unsigned long icon, char *bubbletext);
+void API dw_taskbar_delete(HWND handle, unsigned long icon);
+int API dw_screen_width(void);
+int API dw_screen_height(void);
+unsigned long API dw_color_depth_get(void);
+HWND API dw_notebook_new(unsigned long id, int top);
+unsigned long API dw_notebook_page_new(HWND handle, unsigned long flags, int front);
+void API dw_notebook_page_destroy(HWND handle, unsigned int pageid);
+void API dw_notebook_page_set_text(HWND handle, unsigned long pageid, char *text);
+void API dw_notebook_page_set_status_text(HWND handle, unsigned long pageid, char *text);
+void API dw_notebook_page_set(HWND handle, unsigned int pageid);
+unsigned long API dw_notebook_page_get(HWND handle);
+void API dw_notebook_pack(HWND handle, unsigned long pageid, HWND page);
+HWND API dw_splitbar_new(int type, HWND topleft, HWND bottomright, unsigned long id);
+void API dw_splitbar_set(HWND handle, float percent);
+float API dw_splitbar_get(HWND handle);
+HMENUI API dw_menu_new(unsigned long id);
+HMENUI API dw_menubar_new(HWND location);
+HWND API dw_menu_append_item(HMENUI menu, char *title, unsigned long id, unsigned long flags, int end, int check, HMENUI submenu);
+void API dw_menu_item_set_check(HMENUI menu, unsigned long id, int check);
+void API dw_menu_popup(HMENUI *menu, HWND parent, int x, int y);
+void API dw_menu_destroy(HMENUI *menu);
+void API dw_pointer_query_pos(long *x, long *y);
+void API dw_pointer_set_pos(long x, long y);
+void API dw_window_function(HWND handle, void *function, void *data);
+HWND API dw_window_from_id(HWND handle, int id);
+HMTX API dw_mutex_new(void);
+void API dw_mutex_close(HMTX mutex);
+void API dw_mutex_lock(HMTX mutex);
+void API dw_mutex_unlock(HMTX mutex);
+HEV API dw_event_new(void);
+int API dw_event_reset(HEV eve);
+int API dw_event_post(HEV eve);
+int API dw_event_wait(HEV eve, unsigned long timeout);
+int API dw_event_close (HEV *eve);
+DWTID API dw_thread_new(void *func, void *data, int stack);
+void API dw_thread_end(void);
+DWTID API dw_thread_id(void);
+void API dw_exit(int exitcode);
+HWND API dw_render_new(unsigned long id);
+void API dw_color_foreground_set(unsigned long value);
+void API dw_color_background_set(unsigned long value);
+unsigned long API dw_color_choose(unsigned long value);
+void API dw_draw_point(HWND handle, HPIXMAP pixmap, int x, int y);
+void API dw_draw_line(HWND handle, HPIXMAP pixmap, int x1, int y1, int x2, int y2);
+void API dw_draw_rect(HWND handle, HPIXMAP pixmap, int fill, int x, int y, int width, int height);
+void API dw_draw_text(HWND handle, HPIXMAP pixmap, int x, int y, char *text);
+void API dw_font_text_extents_get(HWND handle, HPIXMAP pixmap, char *text, int *width, int *height);
+void API dw_flush(void);
+void API dw_pixmap_bitblt(HWND dest, HPIXMAP destp, int xdest, int ydest, int width, int height, HWND src, HPIXMAP srcp, int xsrc, int ysrc);
+HPIXMAP API dw_pixmap_new(HWND handle, unsigned long width, unsigned long height, int depth);
+HPIXMAP API dw_pixmap_new_from_file(HWND handle, char *filename);
+HPIXMAP API dw_pixmap_grab(HWND handle, ULONG id);
+void API dw_pixmap_destroy(HPIXMAP pixmap);
+void API dw_beep(int freq, int dur);
+int API dw_messagebox(char *title, int flags, char *format, ...);
+void API dw_environment_query(DWEnv *env);
+int API dw_exec(char *program, int type, char **params);
+int API dw_browse(char *url);
+char * API dw_file_browse(char *title, char *defpath, char *ext, int flags);
+char * API dw_user_dir(void);
+DWDialog * API dw_dialog_new(void *data);
+int API dw_dialog_dismiss(DWDialog *dialog, void *result);
+void * API dw_dialog_wait(DWDialog *dialog);
+void API dw_window_set_data(HWND window, char *dataname, void *data);
+void * API dw_window_get_data(HWND window, char *dataname);
+int API dw_module_load(char *name, HMOD *handle);
+int API dw_module_symbol(HMOD handle, char *name, void**func);
+int API dw_module_close(HMOD handle);
+int API dw_timer_connect(int interval, void *sigfunc, void *data);
+void API dw_timer_disconnect(int id);
+void API dw_signal_connect(HWND window, char *signame, void *sigfunc, void *data);
+void API dw_signal_disconnect_by_window(HWND window);
+void API dw_signal_disconnect_by_data(HWND window, void *data);
+void API dw_signal_disconnect_by_name(HWND window, char *signame);
+HEV API dw_named_event_new(char *name);
+HEV API dw_named_event_get(char *name);
+int API dw_named_event_reset(HEV eve);
+int API dw_named_event_post(HEV eve);
+int API dw_named_event_wait(HEV eve, unsigned long timeout);
+int API dw_named_event_close(HEV eve);
+HSHM API dw_named_memory_new(void **dest, int size, char *name);
+HSHM API dw_named_memory_get(void **dest, int size, char *name);
+int API dw_named_memory_free(HSHM handle, void *ptr);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/filter_plug.h	Fri Feb 18 02:50:18 2011 -0600
@@ -0,0 +1,33 @@
+#if __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+   int size;
+
+   /* specify a function which the filter should use for output */
+   int (* _System output_play_samples)(void *a, FORMAT_INFO *format, char *buf, int len, int posmarker);
+   void *a; /* only to be used with the precedent function */
+   int audio_buffersize;
+
+   /* error message function the filter plug-in should use */
+   void (* _System error_display)(char *);
+
+} FILTER_PARAMS;
+
+/* returns 0 -> ok */
+ULONG _System filter_init(void **f, FILTER_PARAMS *params);
+BOOL _System filter_uninit(void *f);
+
+
+/* Notice it is the same parameters as output_play_samples()  */
+/* this makes it possible to plug a decoder plug-in in either */
+/* a filter plug-in or directly in an output plug-in          */
+/* BUT you will have to pass void *a from above to the next   */
+/* stage which will be either a filter or output              */
+int _System filter_play_samples(void *f, FORMAT_INFO *format, char *buf,int len, int posmarker);
+
+
+#if __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/filter_plug.html	Fri Feb 18 02:50:18 2011 -0600
@@ -0,0 +1,58 @@
+<HTML>
+<HEAD>
+   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+   <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (OS/2; U) [Netscape]">
+   <TITLE>PM123 Filter Plug-in Developer's Guide</TITLE>
+</HEAD>
+<BODY>
+
+<H3>Filter plug-ins</H3>
+
+Filter plug-ins must implement and export the functions defined in
+filter_plug.h. The interface for the filter plug-in is simple compared
+to the other types of plug-ins.<P>
+
+<TT>
+ULONG _System filter_init(void **f, FILTER_PARAMS *params);<BR>
+BOOL _System filter_uninit(void *f);<BR>
+</TT>
+
+<UL>
+<LI>f : Allocate any chunk of memory necessary for the filter's
+function.  This pointer will be passed to the other filter_play_samples.
+At the very least, you need to allocate memory to keep the in memory
+the location of output_play_samples() and it's parameter "a". </LI>
+<LI>return value : 0 means the filter was initialized successfully.</LI>
+</UL>
+
+Init function is called when filter plug-in is about to be used.
+Multiple filter plug-ins are chained, so the pointers to
+output_play_samples() and it's parameter "a", might belong to another
+filter plug-in and not necessarily to the active output plug-in.
+
+
+<TT>int _System filter_play_samples(void *f, FORMAT_INFO *format, char *buf,int len, int posmarker);</TT>
+<UL>
+<LI>format - format of buf</LI>
+<LI>buf - data to play</LI>
+<LI>len - length of buf</LI>
+<LI>posmarker = position marker to return with output_playing_pos</LI>
+<LI>return value: the number of bytes from len processed. ie.: 0 == error
+</UL>
+
+This function is called by the decoder or a previous in chain filter plug-in
+to filter samples.  Note that this function's prototype is identical to
+output_play_samples.  This makes it possible to chain filter plug-ins.<P>
+
+Once you have modified the data in satisfactory way, call the
+output_play_samples() function with it's parameter "a" received from the
+init function, and use it with the modified samples of your filter
+plug-in. </LI>
+
+
+<HR size=1><I><FONT SIZE=-1>Last revised July 3, 2000, Copyright &copy;
+Taneli Lepp&auml; &lt;rosmo@sektori.com>, Samuel Audet &lt;guardia@cam.org></FONT></I>
+</BODY>
+</HTML>
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/format.h	Fri Feb 18 02:50:18 2011 -0600
@@ -0,0 +1,22 @@
+/* AFAIK, all of those also have BitsPerSample as format specific */
+#define WAVE_FORMAT_PCM       0x0001
+#define WAVE_FORMAT_ADPCM     0x0002
+#define WAVE_FORMAT_ALAW      0x0006
+#define WAVE_FORMAT_MULAW     0x0007
+#define WAVE_FORMAT_OKI_ADPCM 0x0010
+#define WAVE_FORMAT_DIGISTD   0x0015
+#define WAVE_FORMAT_DIGIFIX   0x0016
+#define IBM_FORMAT_MULAW      0x0101
+#define IBM_FORMAT_ALAW       0x0102
+#define IBM_FORMAT_ADPCM      0x0103
+
+typedef struct
+{
+  int size;
+
+  int samplerate;
+  int channels;
+  int bits;
+  int format; // PCM = 1
+} FORMAT_INFO;
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/license.txt	Fri Feb 18 02:50:18 2011 -0600
@@ -0,0 +1,20 @@
+Copyright Information About Nuclear Visuals.
+
+2000-2003 Brian Smith <dbsoft@technologist.com>
+2000 Achim Hasenmueller <achimha@innotek.de>
+2000 Peter Nielsen <peter@pmview.com>
+2003 Mark Hessling <m.hessling@qut.edu.au>
+1998 Sergey I. Yevtushenko
+
+This license allows you to use this source code in any way you wish, given the
+following restrictions:
+
+Source code must keep the copyrights.
+Entities using the source code must acknowledge Dynamic Windows contributors.
+(either passively when queried or actively by acknowledgements in the program)
+The following are not allowed to use Dynamic Windows in a commercial product:
+
+F/X Communications
+Any entity associated with Bjarne Jensen
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/makefile	Fri Feb 18 02:50:18 2011 -0600
@@ -0,0 +1,35 @@
+# Nuclear Visuals Makefile
+
+.SUFFIXES: \
+	.c .obj
+
+#CFLAGS = /Ti /DOS2 /DTCPV40HDRS /Sm /Ss /Q /Gm /Gt /Gd+ /C
+CFLAGS = /DOS2 /DTCPV40HDRS /Sm /Ss /Q /Gm /Gt /Gd- /Ge- /C
+#LDFLAGS = /DE /optfunc
+LDFLAGS = /optfunc
+
+
+OBJECTS = nuclear.obj dw.obj
+
+SOURCES = nuclear.c dw.c
+
+all: nuclear.dll
+
+$(OBJECTS):
+	icc $(CFLAGS) %s	
+
+nuclear.dll:  $(OBJECTS)
+	icc @<<
+	 /B" $(LDFLAGS)"
+	 /Feanalyzer.dll
+	 MMPM2.LIB
+	 $(OBJECTS)
+	 nuclear.def
+<<
+
+clean: 
+	rm $(OBJECTS) analyzer.dll
+
+
+nuclear.obj: nuclear.c plugin.h dw.c dw.h
+dw.obj: dw.c dw.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nuclear.c	Fri Feb 18 02:50:18 2011 -0600
@@ -0,0 +1,1311 @@
+#define INCL_DOS
+#define INCL_WIN
+#define INCL_GPI
+
+#include <os2.h>
+#include "dw.h"
+
+#define  _MEERROR_H_
+#include <mmioos2.h>
+#include <dive.h>
+#include <fourcc.h>
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include "format.h"
+#include "decoder_plug.h"
+#include "plugin.h"
+
+#define FULL_CLEAR
+
+HWND hwndClient, hwndPM123;
+
+#define strcasecmp stricmp
+
+PLUGIN_PROCS procs;
+int (* _System specana_init)(int setnumsamples);
+int (* _System specana_dobands)(float bands[]);
+
+void DiveInit(void);
+void DiveShutdown(void);
+
+HAB hab;
+
+/* So I can save/load this information */
+int blockwidth = 2;
+int falloff = 20;
+int updatefreq = 32;
+int spacing = 1;
+int percentage = 20;
+int boostval = 3;
+int fire = 2;
+int usedive = TRUE;
+int showpeaks = TRUE;
+int gradient = TRUE;
+int boost = TRUE;
+int barred = FALSE;
+int barblue = FALSE;
+int bargreen = TRUE;
+
+int bands, samples;
+int cx, cy;
+
+int *maxage;
+float *bmax;
+float *last;
+float *current;
+
+DIVE_CAPS DiveCaps = {0};
+FOURCC fccFormats[100] = {0};
+HDIVE hDive = NULLHANDLE;
+PBYTE fBuf;
+ULONG DiveBuffer = 0, fBufLen = 0, fBufScanLineBytes = 0, fBufScanLines = 0;
+RGB2 *DiveColors = NULL;
+RGB2 rgbBlack = { 0, 0, 0, 0};
+RGB2 rgbWhite = { 255, 255, 255, 0};
+HPAL hpalDive;
+HDC hdcClient;
+HPS hpsDive;
+
+int _System plugin_query(PPLUGIN_QUERYPARAM param)
+{
+	param->type         = PLUGIN_VISUAL; /* Identify the plugin as visual */
+
+	param->author       = "Brian Smith";
+	/* Author of the plugin */
+
+	param->desc         = "Nuclear Visuals";
+	/* A short description of the plugin */
+
+	param->configurable = TRUE;
+	/* Toggles plugin configurability via PM123 Properties dialog */
+
+	return 0;
+}
+
+/* Write the nuclear.ini file with all of the current settings */
+void saveconfig(void)
+{
+	FILE *f;
+
+	if((f=fopen("nuclear.ini", "w"))==NULL)
+	{
+		dw_messagebox("Nuclear Visuals", DW_MB_OK | DW_MB_ERROR, "Could not save settings.");
+		return;
+	}
+
+	if(showpeaks == TRUE)
+		fprintf(f, "SHOWPEAKS=TRUE\n");
+	else
+		fprintf(f, "SHOWPEAKS=FALSE\n");
+
+	if(gradient == TRUE)
+		fprintf(f, "GRADIENT=TRUE\n");
+	else
+		fprintf(f, "GRADIENT=FALSE\n");
+
+	if(boost == TRUE)
+		fprintf(f, "BOOST=TRUE\n");
+	else
+		fprintf(f, "BOOST=FALSE\n");
+
+	if(usedive == TRUE)
+		fprintf(f, "USEDIVE=TRUE\n");
+	else
+		fprintf(f, "USEDIVE=FALSE\n");
+
+	if(barred == TRUE)
+		fprintf(f, "BARRED=TRUE\n");
+	else
+		fprintf(f, "BARRED=FALSE\n");
+
+	if(bargreen == TRUE)
+		fprintf(f, "BARGREEN=TRUE\n");
+	else
+		fprintf(f, "BARGREEN=FALSE\n");
+
+	if(barblue == TRUE)
+		fprintf(f, "BARBLUE=TRUE\n");
+	else
+		fprintf(f, "BARBLUE=FALSE\n");
+
+	fprintf(f, "FALLOFF=%d\n", falloff);
+	fprintf(f, "UPDATEFREQ=%d\n", updatefreq);
+	fprintf(f, "BLOCKWIDTH=%d\n", blockwidth);
+	fprintf(f, "SPACING=%d\n", spacing);
+	fprintf(f, "PERCENTAGE=%d\n", percentage);
+	fprintf(f, "BOOSTVAL=%d\n", boostval);
+	fprintf(f, "FIRE=%d\n", fire);
+
+	fclose(f);
+}
+
+/* Generic function to parse information from a config file */
+void getline(FILE *f, char *entry, char *entrydata)
+{
+	char in[256];
+	int z;
+
+	memset(in, 0, 256);
+	fgets(in, 255, f);
+
+	if(in[strlen(in)-1] == '\n')
+		in[strlen(in)-1] = 0;
+
+	if(in[0] != '#')
+	{
+		for(z=0;z<strlen(in);z++)
+		{
+			if(in[z] == '=')
+			{
+				in[z] = 0;
+				strcpy(entry, in);
+				strcpy(entrydata, &in[z+1]);
+				return;
+			}
+		}
+	}
+	strcpy(entry, "");
+	strcpy(entrydata, "");
+}
+
+/* Load the nuclear.ini file from disk setting all the necessary flags */
+void loadconfig(void)
+{
+	char entry[256], entrydata[256];
+	FILE *f;
+
+	if((f = fopen("nuclear.ini", "r"))==NULL)
+		return;
+
+	while(!feof(f))
+	{
+		getline(f, entry, entrydata);
+		if(strcasecmp(entry, "showpeaks")==0 && strcasecmp(entrydata, "true") == 0)
+			showpeaks = TRUE;
+		if(strcasecmp(entry, "gradient")==0 && strcasecmp(entrydata, "true") == 0)
+			gradient = TRUE;
+		if(strcasecmp(entry, "boost")==0 && strcasecmp(entrydata, "true") == 0)
+			boost = TRUE;
+		if(strcasecmp(entry, "usedive")==0 && strcasecmp(entrydata, "true") == 0)
+			usedive = TRUE;
+		if(strcasecmp(entry, "barred")==0 && strcasecmp(entrydata, "true") == 0)
+			barred = TRUE;
+		if(strcasecmp(entry, "bargreen")==0 && strcasecmp(entrydata, "true") == 0)
+			bargreen = TRUE;
+		if(strcasecmp(entry, "barblue")==0 && strcasecmp(entrydata, "true") == 0)
+			barblue = TRUE;
+		if(strcasecmp(entry, "showpeaks")==0 && strcasecmp(entrydata, "false") == 0)
+			showpeaks = FALSE;
+		if(strcasecmp(entry, "gradient")==0 && strcasecmp(entrydata, "false") == 0)
+			gradient = FALSE;
+		if(strcasecmp(entry, "boost")==0 && strcasecmp(entrydata, "false") == 0)
+			boost = FALSE;
+		if(strcasecmp(entry, "usedive")==0 && strcasecmp(entrydata, "false") == 0)
+			usedive = FALSE;
+		if(strcasecmp(entry, "barred")==0 && strcasecmp(entrydata, "false") == 0)
+			barred = FALSE;
+		if(strcasecmp(entry, "bargreen")==0 && strcasecmp(entrydata, "false") == 0)
+			bargreen = FALSE;
+		if(strcasecmp(entry, "barblue")==0 && strcasecmp(entrydata, "false") == 0)
+			barblue = FALSE;
+		if(strcasecmp(entry, "falloff")==0)
+			falloff = atoi(entrydata);
+		if(strcasecmp(entry, "updatefreq")==0)
+			updatefreq = atoi(entrydata);
+		if(strcasecmp(entry, "blockwidth")==0)
+			blockwidth = atoi(entrydata);
+		if(strcasecmp(entry, "spacing")==0)
+			spacing = atoi(entrydata);
+		if(strcasecmp(entry, "percentage")==0)
+			percentage = atoi(entrydata);
+		if(strcasecmp(entry, "boostval")==0)
+			boostval = atoi(entrydata);
+		if(strcasecmp(entry, "fire")==0)
+			fire = atoi(entrydata);
+	}
+	fclose(f);
+}
+
+
+void DWSIGNAL generic_cancel(HWND window, void *data)
+{
+	HWND *handles = (HWND *)data;
+
+	if(handles)
+	{
+		dw_window_destroy(handles[0]);
+		free(handles);
+	}
+}
+
+/* Fills the analyzer area with black. */
+void clear_analyzer(void)
+{
+	if(usedive)
+	{
+		DiveBeginImageBufferAccess(hDive, DiveBuffer, &fBuf, &fBufScanLineBytes, &fBufScanLines);
+		fBufLen = fBufScanLineBytes * fBufScanLines;
+
+		memset(fBuf, 0, fBufLen);
+		DiveBlitImage(hDive,
+					  DiveBuffer,
+					  DIVE_BUFFER_SCREEN);
+		DiveEndImageBufferAccess(hDive, DiveBuffer);
+	}
+	else
+	{
+		HPS hps = WinGetPS(hwndClient);
+		POINTL ptl;
+
+		GpiSetColor(hps, CLR_BLACK);
+
+		ptl.x = 0;
+		ptl.y = 0;
+
+		GpiMove(hps, &ptl);
+
+		ptl.x = cx;
+		ptl.y = cy;
+
+		GpiBox(hps, DRO_FILL, &ptl, 0, 0);
+
+		WinReleasePS(hps);
+	}
+}
+
+/* Stops the analyzers, updates all the settings
+ * and then restarts it.
+ */
+void update_analyzer(HWND *handles)
+{
+	int z = 1, wantedsamples;
+
+	bands = 0;
+
+	WinStopTimer(hab, hwndClient, 449);
+
+	if(usedive)
+		DiveShutdown();
+
+	showpeaks = dw_checkbox_get(handles[1]);
+	gradient = dw_checkbox_get(handles[2]);
+	boost = dw_checkbox_get(handles[11]);
+	usedive = dw_checkbox_get(handles[13]);
+	barred = dw_checkbox_get(handles[3]);
+	bargreen = dw_checkbox_get(handles[4]);
+	barblue = dw_checkbox_get(handles[5]);
+	falloff = dw_spinbutton_get_pos(handles[6]);
+	updatefreq = dw_spinbutton_get_pos(handles[7]);
+	blockwidth = dw_spinbutton_get_pos(handles[8]);
+	spacing = dw_spinbutton_get_pos(handles[9]);
+	percentage = dw_spinbutton_get_pos(handles[10]);
+	boostval = dw_spinbutton_get_pos(handles[12]);
+
+	if(dw_checkbox_get(handles[15]))
+		fire = 1;
+	else if(dw_checkbox_get(handles[14]))
+		fire = 2;
+	else
+		fire = 0;
+
+	saveconfig();
+
+	/* Recalculate the sizes again */
+	wantedsamples = (int)((cx / (blockwidth+spacing))*(100/percentage));
+	samples = (int)(cx / (blockwidth+spacing));
+
+	/* Find the ideal number of bars (bands) for our analyzer */
+	while(bands < wantedsamples)
+	{
+		bands = specana_init(z);
+		z++;
+		if(z < 1 || z > 4097)
+		{
+			dw_messagebox("Nuclear Visuals", DW_MB_OK | DW_MB_ERROR, "Error getting spectrum analyzer");
+			samples = 0;
+			break;
+		}
+	}
+
+    /* Free the old arrays */
+	free(last);
+	free(bmax);
+	free(current);
+	free(maxage);
+	if(DiveColors)
+	{
+		free(DiveColors);
+		DiveColors = NULL;
+	}
+
+	/* Reallocate them with the new size */
+	maxage = (int *)calloc(bands, sizeof(int));
+	bmax = (float *)calloc(bands, sizeof(float));
+	last = (float *)calloc(bands, sizeof(float));
+	current = (float *)calloc(bands, sizeof(float));
+	if(usedive)
+		DiveColors = (RGB2 *)calloc(cy+2, sizeof(RGB2));
+
+	if(usedive)
+		DiveInit();
+
+	clear_analyzer();
+
+	WinStartTimer(hab, hwndClient, 449, updatefreq);
+}
+
+/* Callback to handle an OK press in the preferences dialog */
+void DWSIGNAL preferences_ok(HWND window, void *data)
+{
+	HWND *handles = (HWND *)data;
+
+	if(handles)
+	{
+		update_analyzer(handles);
+
+		dw_window_destroy(handles[0]);
+		free(handles);
+	}
+}
+
+/* Callback to handle an Apply press in the preferences dialog */
+void DWSIGNAL preferences_apply(HWND window, void *data)
+{
+	HWND *handles = (HWND *)data;
+
+	if(handles)
+		update_analyzer(handles);
+}
+
+int _System plugin_configure(HWND hwnd, HMODULE module)
+{
+	HWND entrywindow, mainbox, vbox, cancelbutton, okbutton, buttonbox,
+	applybutton, xbox, stext, winbox, groupbox, notebook,
+	*handles = malloc(17 * sizeof(HWND));
+	ULONG flStyle = DW_FCF_TITLEBAR | DW_FCF_SHELLPOSITION | DW_FCF_DLGBORDER;
+	int pageid, tmp;
+
+	handles[0] = entrywindow = dw_window_new(HWND_DESKTOP, "Nuclear Visuals Settings", flStyle);
+
+	winbox = dw_box_new(BOXVERT, 0);
+
+	dw_box_pack_start(entrywindow, winbox, 0, 0, TRUE, TRUE, 0);
+
+	notebook = dw_notebook_new(1050L, TRUE);
+
+	dw_box_pack_start(winbox, notebook, 150,300, TRUE, TRUE, 0);
+
+	xbox = dw_box_new(BOXVERT, 0);
+
+	mainbox = dw_box_new(BOXHORZ, 10);
+
+	dw_box_pack_start(xbox, mainbox, 0, 0, TRUE, TRUE, 0);
+
+	/* Checkboxes */
+	vbox = dw_box_new(BOXVERT, 0);
+
+	dw_box_pack_start(mainbox, vbox, 0, 0, TRUE, TRUE, 0);
+
+	handles[1] = dw_checkbox_new("Show Peaks", 0);
+	dw_checkbox_set(handles[1],showpeaks);
+
+
+	dw_box_pack_start(vbox, handles[1], 50, 20, TRUE, TRUE, 4);
+
+	handles[2] = dw_checkbox_new("Gradient", 0);
+	dw_checkbox_set(handles[2],gradient);
+
+	dw_box_pack_start(vbox, handles[2], 50, 20, TRUE, TRUE, 4);
+
+	handles[3] = dw_checkbox_new("Bar Red", 0);
+	dw_checkbox_set(handles[3],barred);
+
+	dw_box_pack_start(vbox, handles[3], 50, 20, TRUE, TRUE, 4);
+
+	handles[4] = dw_checkbox_new("Bar Green", 0);
+	dw_checkbox_set(handles[4],bargreen);
+
+	dw_box_pack_start(vbox, handles[4], 50, 20, TRUE, TRUE, 4);
+
+	handles[5] = dw_checkbox_new("Bar Blue", 0);
+	dw_checkbox_set(handles[5],barblue);
+
+	dw_box_pack_start(vbox, handles[5], 50, 20, TRUE, TRUE, 4);
+
+	handles[11] = dw_checkbox_new("Boost", 0);
+	dw_checkbox_set(handles[11],boost);
+
+	dw_box_pack_start(vbox, handles[11], 50, 20, TRUE, TRUE, 4);
+
+	handles[13] = dw_checkbox_new("Use DIVE", 0);
+	dw_checkbox_set(handles[13],usedive);
+
+	dw_box_pack_start(vbox, handles[13], 50, 20, TRUE, TRUE, 4);
+
+	/* Text */
+	vbox = dw_box_new(BOXVERT, 0);
+
+	dw_box_pack_start(mainbox, vbox, 0, 0, FALSE, TRUE, 0);
+
+	stext = dw_text_new("Falloff", 0);
+
+	dw_window_set_style(stext, DW_DT_VCENTER, DW_DT_VCENTER);
+
+	dw_box_pack_start(vbox, stext, 100, 20, FALSE, TRUE, 4);
+
+	stext = dw_text_new("Update Frequency", 0);
+
+	dw_window_set_style(stext, DW_DT_VCENTER, DW_DT_VCENTER);
+
+	dw_box_pack_start(vbox, stext, 100, 20, FALSE, TRUE, 4);
+
+	stext = dw_text_new("Block Width", 0);
+
+	dw_window_set_style(stext, DW_DT_VCENTER, DW_DT_VCENTER);
+
+	dw_box_pack_start(vbox, stext, 100, 20, FALSE, TRUE, 4);
+
+	stext = dw_text_new("Spacing", 0);
+
+	dw_window_set_style(stext, DW_DT_VCENTER, DW_DT_VCENTER);
+
+	dw_box_pack_start(vbox, stext, 100, 20, FALSE, TRUE, 4);
+
+	stext = dw_text_new("Spectrum %", 0);
+
+	dw_window_set_style(stext, DW_DT_VCENTER, DW_DT_VCENTER);
+
+	dw_box_pack_start(vbox, stext, 100, 20, FALSE, TRUE, 4);
+
+	stext = dw_text_new("Boost Value", 0);
+
+	dw_window_set_style(stext, DW_DT_VCENTER, DW_DT_VCENTER);
+
+	dw_box_pack_start(vbox, stext, 100, 20, FALSE, TRUE, 4);
+
+	dw_box_pack_start(vbox, 0, 100, 6, FALSE, TRUE, 0);
+
+	/* Spinbuttons */
+	vbox = dw_box_new(BOXVERT, 0);
+
+	dw_box_pack_start(mainbox, vbox, 0, 0, TRUE, TRUE, 0);
+
+	/* Falloff */
+	handles[6] = dw_spinbutton_new("", 100L);
+
+	dw_spinbutton_set_limits(handles[6], 60L, 0L);
+	dw_spinbutton_set_pos(handles[6], falloff);
+
+	dw_box_pack_start(vbox, handles[6], 25, 20, TRUE, TRUE, 8);
+
+	/* Update Frequency */
+	handles[7] = dw_spinbutton_new("", 100L);
+
+	dw_spinbutton_set_limits(handles[7], 1000L, 1L);
+	dw_spinbutton_set_pos(handles[7], updatefreq);
+
+	dw_box_pack_start(vbox, handles[7], 25, 20, TRUE, TRUE, 8);
+
+    /* Block Width */
+	handles[8] = dw_spinbutton_new("", 100L);
+
+	dw_spinbutton_set_limits(handles[8], 5L, 1L);
+	dw_spinbutton_set_pos(handles[8], blockwidth);
+
+	dw_box_pack_start(vbox, handles[8], 25, 20, TRUE, TRUE, 8);
+
+    /* Spacing */
+	handles[9] = dw_spinbutton_new("", 100L);
+
+	dw_spinbutton_set_limits(handles[9], 5L, 0L);
+	dw_spinbutton_set_pos(handles[9], spacing);
+
+	dw_box_pack_start(vbox, handles[9], 25, 20, TRUE, TRUE, 8);
+
+    /* Percentage */
+	handles[10] = dw_spinbutton_new("", 100L);
+
+	dw_spinbutton_set_limits(handles[10], 100L, 10L);
+	dw_spinbutton_set_pos(handles[10], percentage);
+
+	dw_box_pack_start(vbox, handles[10], 25, 20, TRUE, TRUE, 8);
+
+    /* Boost Value */
+	handles[12] = dw_spinbutton_new("", 100L);
+
+	dw_spinbutton_set_limits(handles[12], 5L, 1L);
+	dw_spinbutton_set_pos(handles[12], boostval);
+
+	dw_box_pack_start(vbox, handles[12], 25, 20, TRUE, TRUE, 8);
+
+	pageid = dw_notebook_page_new(notebook, 0L, FALSE);
+
+	dw_notebook_pack(notebook, pageid, xbox);
+
+	/* Due to a GTK limitiation the page text must be set after the page is packed */
+	dw_notebook_page_set_text(notebook, pageid, "General");
+	dw_notebook_page_set_status_text(notebook, pageid, "Page 1 of 2");
+
+	xbox = dw_box_new(BOXVERT, 5);
+
+	groupbox = dw_groupbox_new(BOXVERT, 10, "Fire Type");
+
+	dw_box_pack_start(xbox, groupbox, 150, 70, TRUE, TRUE, 0);
+
+	handles[14] = dw_radiobutton_new("Hot", 0);
+
+	dw_box_pack_start(groupbox, handles[14], 50, 20, TRUE, TRUE, 4);
+
+	handles[15] = dw_radiobutton_new("Cold", 0);
+
+	dw_box_pack_start(groupbox, handles[15], 50, 20, TRUE, TRUE, 4);
+
+	handles[16] = dw_radiobutton_new("Standard", 0);
+
+	dw_box_pack_start(groupbox, handles[16], 50, 20, TRUE, TRUE, 4);
+
+	pageid = dw_notebook_page_new(notebook, 0L, FALSE);
+
+	dw_notebook_pack(notebook, pageid, xbox);
+
+	/* Due to a GTK limitiation the page text must be set after the page is packed */
+	dw_notebook_page_set_text(notebook, pageid, "Visuals");
+	dw_notebook_page_set_status_text(notebook, pageid, "Page 2 of 2");
+
+	/* Buttons */
+	buttonbox = dw_box_new(BOXHORZ, 4);
+
+	dw_box_pack_start(winbox, buttonbox, 0, 0, TRUE, TRUE, 4);
+
+	okbutton = dw_button_new("Ok", 1001L);
+
+	dw_box_pack_start(buttonbox, okbutton, 50, 40, TRUE, TRUE, 4);
+
+	applybutton = dw_button_new("Apply", 1002L);
+
+	dw_box_pack_start(buttonbox, applybutton, 50, 40, TRUE, TRUE, 4);
+
+	cancelbutton = dw_button_new("Cancel", 1003L);
+
+	dw_box_pack_start(buttonbox, cancelbutton, 50, 40, TRUE, TRUE, 4);
+
+	dw_signal_connect(okbutton, "clicked", DW_SIGNAL_FUNC(preferences_ok), (void *)handles);
+	dw_signal_connect(applybutton, "clicked", DW_SIGNAL_FUNC(preferences_apply), (void *)handles);
+	dw_signal_connect(cancelbutton, "clicked", DW_SIGNAL_FUNC(generic_cancel), (void *)handles);
+
+	dw_window_set_size(entrywindow, 350, 350);
+
+	dw_window_show(entrywindow);
+
+	switch(fire)
+	{
+	case 1:
+		tmp = 15;
+		break;
+	case 2:
+		tmp = 14;
+		break;
+	default:
+		tmp = 16;
+		break;
+	}
+
+	dw_checkbox_set(handles[tmp], 1);
+
+    return 0;
+}
+
+int _System plugin_deinit(int unload)
+{
+	if(usedive)
+		DiveShutdown();
+
+	if(hpsDive  != NULLHANDLE)
+		GpiSelectPalette(hpsDive, NULLHANDLE);
+	if(hpalDive != NULLHANDLE)
+		GpiDeletePalette(hpalDive);
+	if(hpsDive != NULLHANDLE)
+		GpiDestroyPS(hpsDive);
+
+	WinDestroyWindow(hwndClient);
+
+	free(last);
+	free(bmax);
+	free(current);
+	free(maxage);
+	if(DiveColors)
+	{
+		free(DiveColors);
+		DiveColors = NULL;
+	}
+
+	return 0;
+}
+
+void CreateMonoColorTable(HPS hps, int r, int g, int b)
+{
+	short int red = 0, green = 0, blue = 100;
+	LONG alTable[17];
+
+	GpiQueryLogColorTable(hps, 0L, 0L, 17L, alTable);
+
+	if(r)
+		red = 255;
+	else
+		red = 0;
+
+	if(g)
+		green = 255;
+	else
+		green = 0;
+
+	if(b)
+		blue = 255;
+	else
+		blue = 0;
+
+	alTable[16] = (red * 65536) + (green * 256) + blue;
+
+	GpiCreateLogColorTable(hps, 0L, LCOLF_CONSECRGB, 0, 17, alTable);
+}
+
+void CreateColorTable(HPS hps, int maxcolors, int r, int g, int b)
+{
+	short int red = 0, green = 0, blue = 100;
+	LONG alTable[100];
+	/* We want to start 1/4 up the color scale
+	 * so we using 192 (256-64) instead of 256.
+	 */
+	float m = 192/maxcolors;
+	int z;
+
+	GpiQueryLogColorTable(hps, 0L, 0L, 100L, alTable);
+
+	for(z=0;z<maxcolors;z++)
+	{
+		if(r)
+			red = (BYTE)((z*m) + 63);
+		else
+			red = 0;
+
+		if(g)
+			green = (BYTE)((z*m) + 63);
+		else
+			green = 0;
+
+		if(b)
+			blue = (BYTE)((z*m) + 63);
+		else
+			blue = 0;
+
+		alTable[z+16] = (red * 65536) + (green * 256) + blue;
+	}
+
+	GpiCreateLogColorTable(hps, 0L, LCOLF_CONSECRGB, 0, 100, alTable);
+}
+
+void GpiDrawBlock(HPS hps, int x, int y, int width, int height, int color)
+{
+	POINTL ptl;
+	int newy = (cy - y) - 1;
+	int newcolor = color + 14;
+
+	if(color == 0)
+		newcolor = CLR_BLACK;
+	else if(color == 1)
+		newcolor = CLR_WHITE;
+
+	GpiSetColor(hps, newcolor);
+
+	ptl.x = x;
+	ptl.y = newy;
+
+	GpiMove(hps, &ptl);
+
+	ptl.x = (x + width) - 1;
+    ptl.y = (newy + height) - 1;
+
+	GpiBox(hps, DRO_FILL, &ptl, 0, 0);
+}
+
+/*
+ * GPI implementation of the analyzer renderer.
+ */
+void GpiRender(HWND hwnd)
+{
+	int z, max;
+	float scale;
+	HPS hps = WinGetPS(hwnd);
+
+	max = specana_dobands(current);
+
+	if(boost)
+		scale = (float)max/(cy*boostval);
+	else
+		scale = (float)max/cy;
+
+	/* We want a gradient */
+	if(gradient)
+		CreateColorTable(hps, cy, barred, bargreen, barblue);
+	else
+		CreateMonoColorTable(hps, barred, bargreen, barblue);
+
+
+#ifdef GPI_FULL_CLEAR
+	GpiDrawBlock(hps, 0, cy - 1, cx, cy, 0);
+#endif
+
+	for(z=0;z<samples;z++)
+	{
+		/* double check that we aren't off the screen */
+		int lastheight = last[z]/scale;
+		int thisheight = current[z]/scale;
+
+		if(lastheight > cy)
+			lastheight = cy;
+
+		if(thisheight > cy)
+			thisheight = cy;
+
+#ifndef GPI_FULL_CLEAR
+		/* Erase any old remnants if the current value
+		 * is lower than the last value.
+		 */
+		if(thisheight < lastheight)
+		{
+			GpiDrawBlock(hps, z * (blockwidth + spacing), cy - thisheight,
+						 blockwidth,  (lastheight - thisheight) + 1,
+						 0);
+		}
+#endif
+
+		/* Draw the bar */
+		if(gradient)
+		{
+			int t, start = cy - thisheight;
+
+			for(t=0;t<thisheight;t++)
+			{
+				if(fire == 1)
+					GpiDrawBlock(hps, z * (blockwidth + spacing), start + t,
+								  blockwidth, 1,
+								  (cy-t)+1);
+				else if(fire == 2)
+					GpiDrawBlock(hps, z * (blockwidth + spacing), start + t,
+								  blockwidth, 1,
+								  t+2);
+				else
+					GpiDrawBlock(hps, z * (blockwidth + spacing), start + t,
+								  blockwidth, 1,
+								  (thisheight-t)+1);
+
+			}
+		}
+		else
+		{
+			if(thisheight)
+			{
+				GpiDrawBlock(hps, z * (blockwidth + spacing), cy - 1,
+							  blockwidth, thisheight,
+							  2);
+			}
+		}
+
+		if(showpeaks)
+		{
+			int height;
+
+			/* If we have a new peak save it */
+			if(current[z] > bmax[z] || maxage[z] > falloff)
+			{
+#ifndef GPI_FULL_CLEAR
+				/* Erase the old peaks */
+				height = bmax[z]/scale;
+
+				/* double check that we aren't off the screen */
+				if(height > cy)
+					height = cy;
+
+				GpiDrawBlock(hps, z * (blockwidth + spacing), cy - height,
+							  blockwidth, 1,
+							  0);
+#endif
+
+				/* If we are over the falloff start
+				 * decreasing the max value exponentially.
+				 */
+				if(maxage[z] > falloff && current[z] < bmax[z])
+				{
+					bmax[z] -= (maxage[z]-falloff)*scale;
+					maxage[z]++;
+				}
+				else
+				{
+					/* Otherwise we reset the current peak to
+					 * the new peak, and reset the age.
+					 */
+					bmax[z] = current[z];
+					maxage[z] = 0;
+				}
+			}
+			else
+				maxage[z]++;
+
+			height = bmax[z]/scale;
+
+			/* Draw the peaks */
+			if(height)
+			{
+				/* double check that we aren't off the screen */
+				if(height > cy)
+					height = cy;
+
+				GpiDrawBlock(hps, z * (blockwidth + spacing), cy - height,
+							  blockwidth, 1,
+							  1);
+			}
+		}
+	}
+
+	WinReleasePS(hps);
+
+	memcpy(last, current, sizeof(float) * samples);
+}
+
+void DiveCreateColorTable(int maxcolors, int r, int g, int b)
+{
+	ULONG palcolors = maxcolors + 2;
+	/* We want to start 1/4 up the color scale
+	 * so we using 192 (256-64) instead of 256.
+	 */
+	float m = 192/maxcolors;
+	int z;
+
+	DiveColors[0] = rgbBlack;
+	DiveColors[1] = rgbWhite;
+
+	for(z=0;z<maxcolors;z++)
+	{
+		if(r)
+			DiveColors[z+2].bRed = (BYTE)((z*m) + 63);
+		else
+			DiveColors[z+2].bRed = 0;
+
+		if(g)
+			DiveColors[z+2].bGreen = (BYTE)((z*m) + 63);
+		else
+			DiveColors[z+2].bGreen = 0;
+
+		if(b)
+			DiveColors[z+2].bBlue = (BYTE)((z*m) + 63);
+		else
+			DiveColors[z+2].bBlue = 0;
+	}
+	hpalDive = GpiCreatePalette(hab,
+								LCOL_PURECOLOR,
+								LCOLF_CONSECRGB,
+								palcolors,
+								(PULONG)DiveColors);
+
+	GpiSelectPalette(hpsDive, hpalDive);
+	WinRealizePalette(hwndClient, hpsDive, &palcolors);
+}
+
+void DiveInit(void)
+{
+	APIRET rc = 0;
+
+	if(DiveOpen(&hDive, FALSE, 0))
+	{
+		dw_messagebox("Nuclear Visuals", DW_MB_OK | DW_MB_ERROR, "Error initializing DIVE.");
+		samples = 0;
+		return;
+	}
+
+#if 0
+	rc = DiveQueryCaps(&DiveCaps, DIVE_BUFFER_SCREEN);
+
+	if(rc || DiveCaps.ulDepth < 8)
+	{
+		dw_messagebox("Nuclear Visuals", DW_MB_OK | DW_MB_ERROR, "DIVE is present but cannot be used.");
+		DiveClose(hDive);
+		hDive = NULLHANDLE;
+		samples = 0;
+		return;
+	}
+#endif
+
+	DiveAllocImageBuffer(hDive, &DiveBuffer, FOURCC_LUT8,
+						 cx, cy, 0, NULL);
+
+	DiveCreateColorTable(cy, barred, bargreen, barblue);
+
+	DiveSetSourcePalette(hDive, 0, cy + 2, (PBYTE)DiveColors);
+	DiveSetDestinationPalette(hDive, 0, cy + 2, 0);
+
+	WinSetVisibleRegionNotify(hwndClient, TRUE);
+	WinPostMsg(hwndClient, WM_VRNENABLED, 0L, 0L);
+
+	/* This should be 1 bytes per pixel in LUT8 */
+	fBufLen = cx * cy;
+	fBufScanLineBytes = cx;
+	fBufScanLines = cy;
+}
+
+void DiveShutdown(void)
+{
+	WinSetVisibleRegionNotify(hwndClient, FALSE);
+
+	if(DiveBuffer)
+		DiveFreeImageBuffer(hDive, DiveBuffer);
+	if(hDive != NULLHANDLE)
+		DiveClose(hDive);
+
+	DiveBuffer = 0;
+	hDive = NULLHANDLE;
+}
+
+void DiveDrawBlock(int x, int y, int width, int height, int color)
+{
+	int b, s, offset;
+
+	for(b=0;b<width;b++)
+	{
+		for(s=0;s<height;s++)
+		{
+			offset = (x+b) + ((y + s) * fBufScanLineBytes);
+
+			/* Make sure we aren't going out of our buffer */
+			if(offset >= fBufLen)
+				return;
+
+			fBuf[offset] = (BYTE)color;
+		}
+	}
+}
+
+/*
+ * DIVE implementation of the analyzer renderer.
+ */
+void DiveRender(HWND hwnd)
+{
+	int z, max;
+	float scale;
+
+	max = specana_dobands(current);
+
+	if(boost)
+		scale = (float)max/(cy*boostval);
+	else
+		scale = (float)max/cy;
+
+	DiveBeginImageBufferAccess(hDive, DiveBuffer, &fBuf, &fBufScanLineBytes, &fBufScanLines);
+	fBufLen = fBufScanLineBytes * fBufScanLines;
+
+#ifdef FULL_CLEAR
+	memset(fBuf, 0, fBufLen);
+#endif
+
+	for(z=0;z<samples;z++)
+	{
+		/* double check that we aren't off the screen */
+		int lastheight = last[z]/scale;
+		int thisheight = current[z]/scale;
+
+		if(lastheight > cy)
+			lastheight = cy;
+
+		if(thisheight > cy)
+			thisheight = cy;
+
+#ifndef FULL_CLEAR
+		/* Erase any old remnants if the current value
+		 * is lower than the last value.
+		 */
+		if(thisheight < lastheight)
+		{
+			DiveDrawBlock(z * (blockwidth + spacing), cy - thisheight,
+						  blockwidth,  (lastheight - thisheight) + 1,
+						  0);
+		}
+#endif
+
+		/* Draw the bar */
+		if(gradient)
+		{
+			int t, start = cy - thisheight;
+
+			for(t=0;t<thisheight;t++)
+			{
+				if(fire == 1)
+					DiveDrawBlock(z * (blockwidth + spacing), start + t,
+								  blockwidth, 1,
+								  (cy-t)+1);
+				else if(fire == 2)
+					DiveDrawBlock(z * (blockwidth + spacing), start + t,
+								  blockwidth, 1,
+								  t+2);
+				else
+					DiveDrawBlock(z * (blockwidth + spacing), start + t,
+								  blockwidth, 1,
+								  (thisheight-t)+1);
+
+			}
+		}
+		else
+		{
+			if(thisheight)
+			{
+				DiveDrawBlock(z * (blockwidth + spacing), cy - thisheight,
+							  blockwidth, thisheight,
+							  cy);
+			}
+		}
+
+		if(showpeaks)
+		{
+			int height;
+
+			/* If we have a new peak save it */
+			if(current[z] > bmax[z] || maxage[z] > falloff)
+			{
+#ifndef FULL_CLEAR
+				/* Erase the old peaks */
+				height = bmax[z]/scale;
+
+				/* double check that we aren't off the screen */
+				if(height > cy)
+					height = cy;
+
+				DiveDrawBlock(z * (blockwidth + spacing), cy - height,
+							  blockwidth, 1,
+							  0);
+#endif
+
+				/* If we are over the falloff start
+				 * decreasing the max value exponentially.
+				 */
+				if(maxage[z] > falloff && current[z] < bmax[z])
+				{
+					bmax[z] -= (maxage[z]-falloff)*scale;
+					maxage[z]++;
+				}
+				else
+				{
+					/* Otherwise we reset the current peak to
+					 * the new peak, and reset the age.
+					 */
+					bmax[z] = current[z];
+					maxage[z] = 0;
+				}
+			}
+			else
+				maxage[z]++;
+
+			height = bmax[z]/scale;
+
+			/* Draw the peaks */
+			if(height)
+			{
+				/* double check that we aren't off the screen */
+				if(height > cy)
+					height = cy;
+
+				DiveDrawBlock(z * (blockwidth + spacing), cy - height,
+							  blockwidth, 1,
+							  1);
+			}
+		}
+	}
+
+	memcpy(last, current, sizeof(float) * samples);
+
+	DiveEndImageBufferAccess(hDive, DiveBuffer);
+
+	DiveBlitImage(hDive, DiveBuffer, DIVE_BUFFER_SCREEN);
+
+}
+
+MRESULT EXPENTRY PlugWinProc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+	switch (msg)
+	{
+
+	case DM_DRAGOVER:
+	case DM_DROP:
+	case 0x041f:
+	case 0x041e:
+	case WM_CONTEXTMENU:
+	case WM_BUTTON2MOTIONSTART:
+		WinSendMsg(hwndPM123, msg, mp1, mp2);
+		break;
+
+	case WM_TIMER:
+		if(procs.decoder_playing())
+		{
+			if(usedive)
+				DiveRender(hwnd);
+			else
+				GpiRender(hwnd);
+		}
+		break;
+	case WM_REALIZEPALETTE:
+		/* This tells DIVE that the physical palette may have changed. */
+		if(usedive)
+			DiveSetDestinationPalette(hDive, 0, 256, 0);
+		break;
+	case WM_VRNDISABLED:
+		if(usedive)
+			DiveSetupBlitter (hDive, 0);
+		break;
+	case WM_VRNENABLED:
+		if(usedive)
+		{
+			HPS hps = WinGetPS(hwnd);
+			HRGN hrgn = GpiCreateRegion(hps, 0L, NULL );
+			SWP swp;
+			RECTL rcls[50];
+			RGNRECT rgnCtl;
+			SETUP_BLITTER SetupBlitter;
+			POINTL pointl;
+
+			if(hrgn)
+			{
+				WinQueryVisibleRegion(hwnd, hrgn);
+				rgnCtl.ircStart = 0;
+				rgnCtl.crc = 50;
+				rgnCtl.ulDirection = 1;
+
+				/* Get the all ORed rectangles */
+				if(GpiQueryRegionRects(hps, hrgn, NULL, &rgnCtl, rcls))
+				{
+					/* Now find the window position and size, relative to parent. */
+					WinQueryWindowPos(hwndClient, &swp);
+
+					/* Convert the point to offset from desktop lower left. */
+					pointl.x = swp.x;
+					pointl.y = swp.y;
+					WinMapWindowPoints(hwndPM123, HWND_DESKTOP, &pointl, 1);
+
+					/* Tell DIVE about the new settings. */
+					SetupBlitter.ulStructLen = sizeof(SETUP_BLITTER);
+					SetupBlitter.fccSrcColorFormat = FOURCC_LUT8;
+					SetupBlitter.ulSrcWidth = cx;
+					SetupBlitter.ulSrcHeight = cy;
+					SetupBlitter.ulSrcPosX = 0;
+					SetupBlitter.ulSrcPosY = 0;
+					SetupBlitter.fInvert = FALSE;
+					SetupBlitter.ulDitherType = 1;
+
+					SetupBlitter.fccDstColorFormat = FOURCC_SCRN;
+					SetupBlitter.ulDstWidth = swp.cx;
+					SetupBlitter.ulDstHeight = swp.cy;
+					SetupBlitter.lDstPosX = 0;
+					SetupBlitter.lDstPosY = 0;
+					SetupBlitter.lScreenPosX = pointl.x;
+					SetupBlitter.lScreenPosY = pointl.y;
+					SetupBlitter.ulNumDstRects = rgnCtl.crcReturned;
+					SetupBlitter.pVisDstRects = rcls;
+					DiveSetupBlitter(hDive, &SetupBlitter);
+				}
+				else
+					DiveSetupBlitter(hDive, 0);
+
+				GpiDestroyRegion(hps, hrgn);
+			}
+			WinReleasePS(hps);
+		}
+		break;
+	}
+	return WinDefWindowProc (hwnd, msg, mp1, mp2);
+}
+
+HWND _System vis_init(PVISPLUGININIT initdata)
+{
+	int z = 1, wantedsamples;
+	SIZEL sizl;
+
+	bands = 0;
+
+	WinRegisterClass(initdata->hab,
+					 "NuclearPlugin",
+					 PlugWinProc,
+					 CS_SIZEREDRAW, 0);
+
+	hwndClient = WinCreateWindow(initdata->hwnd,
+								 "NuclearPlugin",
+								 "PM123 Nuclear Visual Plug-in",
+								 WS_VISIBLE,
+								 initdata->x,
+								 initdata->y,
+								 initdata->cx,
+								 initdata->cy,
+								 initdata->hwnd,
+								 HWND_TOP,
+								 initdata->id,
+								 NULL,
+								 NULL);
+
+
+	/* Save the PM123 window handle so we can bounce
+	 * messages to it when we don't want to deal with
+	 * them.
+	 */
+	hwndPM123 = initdata->hwnd;
+
+	/* Save copies of the function pointers for our use */
+	memcpy(&procs, initdata->procs, sizeof(PLUGIN_PROCS));
+	specana_init = initdata->procs->specana_init;
+	specana_dobands = initdata->procs->specana_dobands;
+
+	cx = initdata->cx;
+	cy = initdata->cy;
+	hab = initdata->hab;
+
+	loadconfig();
+
+	samples = (int)(cx / (blockwidth+spacing));
+	wantedsamples = (int)((cx / (blockwidth+spacing))*(100/percentage));
+
+	/* Find the ideal number of bars (bands) for our analyzer */
+	while(bands < wantedsamples)
+	{
+		bands = specana_init(z);
+		z++;
+		if(z < 1 || z > 4097)
+		{
+			dw_messagebox("Nuclear Visuals", DW_MB_OK | DW_MB_ERROR, "Error getting spectrum analyzer");
+			samples = 0;
+			break;
+		}
+	}
+
+	maxage = (int *)calloc(bands, sizeof(int));
+	bmax = (float *)calloc(bands, sizeof(float));
+	last = (float *)calloc(bands, sizeof(float));
+	current = (float *)calloc(bands, sizeof(float));
+	if(usedive)
+	{
+		DiveColors = (RGB2 *)calloc(cy+2, sizeof(RGB2));
+		DiveInit();
+		WinSetVisibleRegionNotify(hwndClient, TRUE);
+		WinPostMsg(hwndClient, WM_VRNENABLED, 0L, 0L);
+	}
+
+	hdcClient = WinOpenWindowDC(hwndClient);
+	hpsDive = GpiCreatePS(hab, hdcClient, &sizl,
+						  PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC);
+
+	dw_init(FALSE, 0, NULL);
+
+	clear_analyzer();
+
+	WinStartTimer(hab, hwndClient, 449, updatefreq);
+
+	return(hwndClient);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nuclear.def	Fri Feb 18 02:50:18 2011 -0600
@@ -0,0 +1,9 @@
+LIBRARY ANALYZER
+
+DESCRIPTION 'PM123 Nuclear Visual Plugin'
+
+EXPORTS plugin_query
+EXPORTS plugin_configure
+EXPORTS plugin_deinit
+EXPORTS vis_init
+
Binary file ooura1d.lib has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ooura1d.txt	Fri Feb 18 02:50:18 2011 -0600
@@ -0,0 +1,12 @@
+OOURA1D.DLL contains code found in the 1 dimension DFT / DCT / DST package
+by Takuya OOURA <ooura@kurims.kyoto-u.ac.jp> or <ooura@mmm.t.u-tokyo.ac.jp>,
+who owns the copyright.  Thanks to him for the nice code!
+
+I have replaced all double precision floats to single precision.  It gives
+an awful e-07 precision instead of e-17, but it's faster and e-07 is by far
+enough for my needs.
+
+You can find the original code and documenation at
+http://momonga.t.u-tokyo.ac.jp/~ooura/fft.html
+
+- Samuel Audet <guardia@cam.org>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/output_plug.h	Fri Feb 18 02:50:18 2011 -0600
@@ -0,0 +1,56 @@
+
+#define WM_PLAYERROR          WM_USER+100
+#define WM_OUTPUT_OUTOFDATA   WM_USER+667
+
+ULONG _System output_init(void **a);
+ULONG _System output_uninit(void *a);
+
+#define OUTPUT_OPEN          1 // may not be necessary!
+#define OUTPUT_CLOSE         2
+#define OUTPUT_VOLUME        3
+#define OUTPUT_PAUSE         4
+#define OUTPUT_SETUP         5
+#define OUTPUT_TRASH_BUFFERS 6
+#define OUTPUT_NOBUFFERMODE  7
+
+typedef struct
+{
+   int size;
+
+  /* --- OUTPUT_SETUP */
+
+   FORMAT_INFO formatinfo;
+
+   int buffersize;
+
+   unsigned short boostclass, normalclass;
+   signed   short boostdelta, normaldelta;
+
+   void (* _System error_display)(char *);
+
+   HWND hwnd; // commodity for PM interface, sends a few messages to this handle
+
+  /* --- OUTPUT_VOLUME */
+
+   char volume;
+   float amplifier;
+
+  /* --- OUTPUT_PAUSE */
+
+   BOOL pause;
+
+  /* --- OUTPUT_NOBUFFERMODE */
+
+   BOOL nobuffermode;
+
+  /* --- OUTPUT_TRASH_BUFFERS */
+
+   ULONG temp_playingpos; // used until new buffers come in
+
+} OUTPUT_PARAMS;
+ULONG _System output_command(void *a, ULONG msg, OUTPUT_PARAMS *info);
+
+ULONG _System output_playing_samples(void *a, FORMAT_INFO *info, char *buf, int len);
+int _System output_play_samples(void *a, FORMAT_INFO *format, char *buf,int len, int posmarker);
+ULONG _System output_playing_pos(void *a);
+BOOL _System output_playing_data(void *a);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/output_plug.html	Fri Feb 18 02:50:18 2011 -0600
@@ -0,0 +1,116 @@
+<HTML>
+<HEAD>
+   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+   <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (OS/2; U) [Netscape]">
+   <TITLE>PM123 Output Plug-in Developer's Guide</TITLE>
+</HEAD>
+<BODY>
+
+<H3>Output plug-ins</H3>
+
+Decoder plug-ins must implement and export the functions defined in
+output_plug.h.<P>
+
+<TT>
+ULONG _System output_init(void **a)<BR>
+ULONG _System output_uninit(void *a)<BR>
+</TT>
+
+<UL>
+<LI>a : Allocate any chunk of memory necessary for the output's
+function.  This pointer will be passed to the other functions.</LI>
+<LI>return value : 0 means the output was initialized successfully.</LI>
+</UL>
+
+Init function is called when the user requests the use of your output
+plug-in So only one output plug-in is active at any given time.  It
+should initialize the control variables for an eventual call to
+OUTPUT_OPEN. <TT>decoder_uninit</TT> is called when another output
+plug-in is request by the user and should free the allocated memory for
+a.<P>
+
+<TT>ULONG _System output_command(void *a, ULONG msg, OUTPUT_PARAMS *info)</TT>
+
+<UL>
+<LI>msg: one of the following:<BR>
+OUTPUT_OPEN<BR>
+OUTPUT_CLOSE<BR>
+OUTPUT_VOLUME<BR>
+OUTPUT_PAUSE<BR>
+OUTPUT_SETUP<BR>
+OUTPUT_TRASH_BUFFERS<BR>
+OUTPUT_NOBUFFERMODE</LI>
+<LI>info: structure that contains the parameters needed by the preceding
+commands</LI>
+<LI>return value:<BR>
+0 -> ok<BR>
+others -> MMOS/2 errors or anything else</LI>
+</UL>
+
+There is a lot of commands to implement for this function.  Parameters
+needed for each of the are described in the definition of the structure
+in the .h file.
+
+<UL>
+
+OUTPUT_OPEN opens the device or file needed for output.<BR>
+OUTPUT_CLOSE closes it<BR>
+OUTPUT_VOLUME changes the volume of an output device<BR>
+OUTPUT_PAUSE pauses the playback (ie.: block in output_playsamples())<BR>
+OUTPUT_SETUP setup the format that output_playsamples() will most likely
+receive, boost priority values, error_display functions and hwnd<BR>
+OUTPUT_TRASH_BUFFERS trash any buffers currently awating to be played<BR>
+OUTPUT_NOBUFFERMODE forces the plug-in to not accumulate buffers for the time being</LI>
+</UL>
+
+The output MUST WinPostMsg() the following messages to <TT>hwnd</TT>:
+
+<UL>
+<LI>WM_PLAYERROR when a playback error occures</LI>
+<LI>WM_OUTPUT_OUTOFDATA when the output plug-in has finished playing all
+its buffers</LI>
+</UL>
+
+<TT>ULONG _System output_playing_samples(void *a, FORMAT_INFO *info,
+char *buf, int len);</TT>
+
+<UL>
+<LI>info - return the format of buf.</LI>
+<LI>buf - return len amount of data currently being played.</LI>
+<LI>len - requested amount of data to be placed in buf.</LI>
+</UL>
+
+This function is used by visual plug-ins so the user can visualize what
+is currently being played.  <TT>len</TT> is usually not so big, so check
+that amount usually required by your visual plug-ins before making
+complicated buffering functions in your output plug-in.<P>
+
+<TT>int _System output_play_samples(void *a, FORMAT_INFO *format, char
+*buf,int len, int posmarker)</TT>
+
+<UL>
+<LI>format - format of buf</LI>
+<LI>buf - data to play</LI>
+<LI>len - length of buf</LI>
+<LI>posmarker = position marker to return with output_playing_pos</LI>
+<LI>return value: the number of bytes from len processed. ie.: 0 == error
+</UL>
+
+This function is called by the decoder or last in chain filter plug-in
+to play samples.<P>
+
+<TT>ULONG _System output_playing_pos(void *a)</TT><P>
+
+This function returns the <TT>posmarker</TT> from the buffer that the
+user currently hears.<P>
+
+<TT>BOOL _System output_playing_data(void *a)</TT><P>
+
+Returns TRUE if the output plug-in still has some buffers to play.
+
+<HR size=1><I><FONT SIZE=-1>Last revised July 3, 2000, Copyright &copy;
+Taneli Lepp&auml; &lt;rosmo@sektori.com>, Samuel Audet &lt;guardia@cam.org></FONT></I>
+</BODY>
+</HTML>
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin.h	Fri Feb 18 02:50:18 2011 -0600
@@ -0,0 +1,92 @@
+
+/*
+   PM123 Plugin Definitions
+   Copyright (C) 1998 Taneli Lepp„ <rosmo@kalja.com>
+                      Samuel Audet <guardia@cam.org>
+*/
+
+#define PLUGIN_NULL    0x000
+#define PLUGIN_VISUAL  0x001
+#define PLUGIN_FILTER  0x002
+#define PLUGIN_DECODER 0x004
+#define PLUGIN_OUTPUT  0x008
+
+/* see decoder_plug.h and output_plug.h for more information
+   on some of these functions */
+typedef struct {
+  ULONG (* _System output_playing_samples)(FORMAT_INFO *info, char *buf, int len);
+  BOOL  (* _System decoder_playing)();
+  ULONG (* _System output_playing_pos)();
+  ULONG (* _System decoder_status)();
+  ULONG (* _System decoder_command)(ULONG msg, DECODER_PARAMS *params);
+  /* name is the DLL filename of the decoder that can play that file */
+  ULONG (* _System decoder_fileinfo)(char *filename, DECODER_INFO *info, char *name);
+
+  PFN specana_init;
+  /* int specana_init(int setnumsamples);
+     Returns the number of bands in return (setnumsamples/2+1).
+  */
+  PFN specana_dobands;
+  /*
+     int specana_dobands(float bands[]);
+     Returns the max value.
+  */
+  PFN pm123_getstring;
+  PFN pm123_control;
+
+  /* name is the DLL filename of the decoder that can play that track */
+  ULONG (* _System decoder_trackinfo)(char *drive, int track, DECODER_INFO *info, char *name);
+  ULONG (* _System decoder_cdinfo)(char *drive, DECODER_CDINFO *info);
+  ULONG (* _System decoder_length)();
+
+} PLUGIN_PROCS, *PPLUGIN_PROCS;
+
+/*
+  int pm123_getstring(int index, int subindex, int bufsize, char *buf)
+
+    index    - which string (see STR_* defines below)
+    subindex - not currently used
+    bufsize  - bytes in buf
+    buf      - buffer for the string
+*/
+
+#define STR_NULL         0
+#define STR_VERSION      1 /* PM123 version          */
+#define STR_DISPLAY_TEXT 2 /* Display text           */
+#define STR_FILENAME     3 /* Currently loaded file  */
+
+/*
+  int pm123_control(int index, void *param);
+
+    index - operation
+    param - parameter for the operation
+*/
+#define CONTROL_NEXTMODE 1  /* Next display mode */
+
+typedef struct {
+  int           x, y, cx, cy;   /* Input        */
+  HWND          hwnd;           /* Input/Output */
+  PPLUGIN_PROCS procs;          /* Input        */
+  int           id;             /* Input        */
+  char          *param;         /* Input        */
+  HAB           hab;            /* Input        */
+} VISPLUGININIT, *PVISPLUGININIT;
+
+typedef struct
+{
+ int  type;         /* null, visual, filter, input. values can be ORred */
+ char *author;      /* Author of the plugin                             */
+ char *desc;        /* Description of the plugin                        */
+ int  configurable; /* Is the plugin configurable                       */
+} PLUGIN_QUERYPARAM, *PPLUGIN_QUERYPARAM;
+
+
+/* Plugin notify message */
+#define WM_PLUGIN_CONTROL (WM_USER + 666)
+/*
+   WM_PLUGIN_CONTROL
+     LONGFROMMP(mp1) = notify code
+     LONGFROMMP(mp2) = additional information
+*/
+/* Notify codes */
+#define PN_TEXTCHANGED  1   /* Display text changed */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin.html	Fri Feb 18 02:50:18 2011 -0600
@@ -0,0 +1,76 @@
+<HTML>
+<HEAD>
+   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+   <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (OS/2; U) [Netscape]">
+   <TITLE>PM123 Plug-in Developer's Guide</TITLE>
+</HEAD>
+<BODY>
+
+<H2>Developing PM123 Plug-ins</H2>
+
+PM123 1.1 beta 1 supports four kinds of plug-ins: visual, decoder,
+output and filter.  Visual plug-ins are used to peek at the data
+currently being heard (or not) by the user through the output plug-in
+and visually produce data from it back to the user.  Decoder plug-ins
+are used to decode different types of files, tracks or streams the user
+can play.  Output plug-ins is the final destination of the decoded data.
+It can be rerouted to a sound card, to the hard disk or anywhere else
+appropriate. The data is in standard PCM format. Filter plug-ins are
+chained between the decoder and the output plug-in to modify the PCM
+data before getting to the output plug-in.<P>
+
+Visual plug-in interface has not been changed since version 1.0,
+eventhough it could have been ameliorate.  This might be done later on.
+Currently, Visual plugins allow the creation of internal or external
+windows and they can tap into PM123 in several ways: they can retrieve
+currently playing samples, control PM123 and so on. Plugins are Dynamic
+Linked Libraries, DLLs, which PM123 loads on use.  Note that visual
+plugins cannot be loaded via PM123's Properties dialog because they are
+skin specific.  They can of course be loaded when loading a new skin.
+<P>
+
+plugin.h contains the necessary structures for all pm123 plug-ins.
+A plugin must have a function that identifies it as a plugin:
+
+<PRE>    int _System plugin_query(PPLUGIN_QUERYPARAM param);</PRE>
+
+The plugin will then have to fill the variables in the <TT>param</TT> structure, for example:
+<PRE>     param->type         = PLUGIN_VISUAL; /* Identify the plugin as
+visual plugin. Types can be ORred to include multiple plugin types in
+the same DLL. */
+
+     param->author       = "Matti Meik&auml;l&auml;inen";
+      /* Author of the plugin */
+
+     param->desc         = "Example plugin";
+      /* A short description of the plugin */
+
+     param->configurable = TRUE;
+      /* Toggles plugin configurability via PM123 Properties dialog */</PRE>
+
+
+<P>If you set <TT>param->configurable = TRUE</TT>, configuration dialog
+should appear when PM123 calls
+<PRE>     int _System plugin_configure(HWND hwnd, HMODULE module);</PRE>
+where <TT>hwnd </TT>is the notebook window so that you can "lock" your
+window on it if you want and where <TT>module</TT> can be used to load
+a resource from your DLL
+
+<P>Visual plugins should deinitialize and destroy their windows and free allocated
+memory when receiving a
+<PRE>     int _System plugin_deinit(int unload);</PRE>
+
+It can also be used to save settings in your INI file for other sort of plug-ins.
+
+<UL>
+<LI><A HREF="visual_plug.html">Visual Plug-ins</A></LI>
+<LI><A HREF="decoder_plug.html">Decoder Plug-ins</A></LI>
+<LI><A HREF="output_plug.html">Output Plug-ins</A></LI>
+<LI><A HREF="filter_plug.html">Filter Plug-ins</A></LI>
+</UL>
+
+<HR size=1><I><FONT SIZE=-1>Last revised July 3, 2000, Copyright &copy;
+Taneli Lepp&auml; &lt;rosmo@sektori.com>, Samuel Audet &lt;guardia@cam.org></FONT></I>
+</BODY>
+</HTML>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visual_plug.html	Fri Feb 18 02:50:18 2011 -0600
@@ -0,0 +1,82 @@
+<HTML>
+<HEAD>
+   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+   <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (OS/2; U) [Netscape]">
+   <TITLE>PM123 Visual Plug-in Developer's Guide</TITLE>
+</HEAD>
+<BODY>
+
+<H3>Visual plug-ins</H3>
+
+Visual plug-in's <TT>vis_init()</TT> routine gets called every time plug-in
+gets activated.
+<PRE>     HWND _System vis_init(PVISPLUGININIT initdata);</PRE>
+The <TT>VISPLUGININIT</TT> structure contains the initialization data that
+PM123 passes to the plug-in.
+<PRE>     typedef struct {
+       int           x, y, cx, cy;
+        /* Location where the plug-in should create its window */
+       HWND          hwnd;
+        /* PM123's window handle */
+       PPLUGIN_PROCS procs;
+        /* Pointers to functions which plug-ins can utilize */
+       int           id;
+        /* Plug-in's ID (1-32) */
+       char          *param;
+        /* Parameters passed to the plug-in */
+     } VISPLUGININIT, *PVISPLUGININIT;</PRE>
+On return from the initialization function, the function should return
+the plug-in's window handle. The plug-in shouldn't not rely that <TT>initdata</TT>
+structure is pointing to the right location all the time, instead it should
+make its own copy of the structure.
+
+<P>If the plug-in creates a window, here's a window procedure you should
+base yours on:
+<PRE>MRESULT EXPENTRY PlugWinProc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+ switch (msg)
+  {
+
+   case DM_DRAGOVER:
+   case DM_DROP:
+   case 0x041f:
+   case 0x041e:
+   case WM_CONTEXTMENU:
+   case WM_BUTTON2MOTIONSTART:
+                WinSendMsg(plug.hwnd, msg, mp1, mp2);
+                break;
+
+   /* your stuff */
+
+   default:
+                return WinDefWindowProc (hwnd, msg, mp1, mp2);
+  }
+}</PRE>
+If you want to create a window inside PM123's window, use <TT>WinCreateWindow()</TT>in
+<TT>vis_init()</TT>:
+<PRE> WinRegisterClass(hab,
+                  "ExamplePlugin",
+                  PlugWinProc,
+                  CS_SIZEREDRAW, 0);
+
+ hwndClient = WinCreateWindow(initdata->hwnd,
+                              "ExamplePlugin",
+                              "PM123 Example Visual Plug-in",
+                              WS_VISIBLE,
+                              initdata->x,
+                              initdata->y,
+                              initdata->cx,
+                              initdata->cy,
+                              initdata->hwnd,
+                              HWND_TOP,
+                              initdata->id,
+                              NULL,
+                              NULL);
+
+ return(hwndClient);</PRE>
+
+<HR size=1><I><FONT SIZE=-1>Last revised July 3, 2000, Copyright &copy;
+Taneli Lepp&auml; &lt;rosmo@sektori.com>, Samuel Audet &lt;guardia@cam.org></FONT></I>
+</BODY>
+</HTML>
+