Release 0.4.7

Mon Nov  1 14:40:21 1993  julliard@di.epfl.ch (Alexandre Julliard)

	* [if1632/user.spec]
	Removed some duplicate entries.

	* [include/dialog.h] [windows/dialog.c]
	Implemented dialog units and fonts.
	Added preliminary loading of dialog resources.
	Preliminary implementation of DialogBox().
	Implemented Get/SetDlgItem* functions.

	* [windows/win.c]
	Implemented WM_PARENTNOTIFY message.
	Implemented CreateWindowEx() and GetWindow().
	Completed DestroyWindow().

Mon Nov  1 18:19:34 1993  Erik Bos

	* [loader/signal.c]
	Added support for int 0x11 & 0x12.

        * [loader/int21.c]
	Improved function handling.

Sun Oct 31 12:38:09 1993  David Metcalfe <david@prism.demon.co.uk>

	* [objects/font.c]
	Implemented GetCharWidth().

Wed Oct 27 09:56:06 1993  John Brezak <brezak@ch.hp.com>

	* [Makefile]
        Use GNU malloc.

	* [include/int21.h include/wine.h]
        Change sc_eflags to sc_efl .

	* [include/wine.h]
        Fix misplaced #endif
        Include <signal.h> for NetBSD

	* [loader/int21.c]
        Don't include <sys/vfs.h> in NetBSD
        Do include <sys/mount.h> in NetBSD
        Cleanup some lint.

Mon Oct 26 17:59:01 1993  Erik Bos

        * [include/int21.h]
        Added.

        * [loader/int21.c]
        Added support for many dos ints.

        * [misc/file.c] [include/files.h]
        Moved OPEN_MAX and DosDriveStruct to files.h.

Sun Oct 24 13:36:50 1993  David Metcalfe <david@prism.demon.co.uk>

	* [controls/button.c]
	Implemented CHECKBOX, AUTOCHECKBOX, 3STATE, AUTO3STATE,
	RADIOBUTTON, AUTORADIOBUTTON, GROUPBOX controls, together with
	a preliminary USERBUTTON control.

	* [objects/text.c]
	Corrected bugs in TEXT_NextLine() and added handling of prefix
	character.

	* [controls/button.c]
	Disabled focus handling by commenting out SetFocus() calls until
	serious bug can be found.

Oct  20, 93 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte)

	* [controls/listbox.c]
	Listbox control window
		Painting cleanup, new messages processed.

	* [controls/scroll.c]
	Scroll bar control window
		Painting cleanup.

	* [controls/combo.c]
	Combo box control window
		Painting cleanup.

Tue Oct 12 17:50:11 1993  julliard@di.epfl.ch (Alexandre Julliard)

	* [objects/color.c] [objects/palette.c] [windows/syscolor.c]
	Better support for the private color map.
	Using a private map is now the default.

	* [windows/win.c]
	Bug fix.

	* [include/dialog.h] [windows/dialog.c]
	Implemented CreateDialog*() and IsDialogMessage().

	* [misc/xt.c] [windows/defwnd.c]
	Moved DefWindowProc() to defwnd.c.
	Added WM_NCCREATE, WM_NCDESTROY and WM_CTLCOLOR handling.

	* [windows/defdlg.c]
	Started the implementation of DefDlgProc().

	* [windows/win.c]
	Added WM_NCCREATE and WM_NCDESTROY messages.
	Implemented IsChild().

Tue Oct 12 17:50:20 1993  David Metcalfe <david@prism.demon.co.uk>

	* [windows/focus.c]
	Implemented GetFocus() and SetFocus().

	* [windows/event.c]
	Added processing of FocusIn and FocusOut events.

	* [windows/graphics.c]
	Added DrawFocusRect().

Sat Oct  9 14:36:57 1993  Erik Bos

	* [loader/int1a.c]
	Added more function handling.

Wed Oct  6 12:21:22 1993  Erik Bos

	* [loader/signal.c]
	Split signal.c into int1a.c, int21.c and signal.c.

Tue Oct  5 22:12:40 1993  David Metcalfe

	* [controls/static.c] [control/widgets.c]
	Static control class.

	* [objects/text.c]
	Added processing of additional DT_ flags to DrawText().

	* [windows/win.c] [misc/xt.c]
	Added SetWindowText() and WM_SETTEXT processing.

Tue Oct  5 22:12:40 1993  Martin Ayotte

	* [controls/listbox.c]
	Listbox control window

	* [controls/scroll.c]
	Scroll bar control window

	* [controls/combo.c]
	Combo box control window

	* [include/combo.h]
	Combo box definitions

	* [include/listbox.h]
	Listbox definitions

	* [include/scroll.h]
	Scroll bar definitions

Sat Oct  2 09:35:54 1993  Bob Amstadt  (bob at pooh)

	* [if1632/callback.c]
	Fixed bug in MakeProcInstance().

	* [debugger/info.c]
	Changed x/w and x/b to display in hex.

	* [debugger/i386-pinsn.c]
	Added code to properly unassemble 16-bit indexing.

Fri Oct  1 08:29:05 1993  Bob Amstadt  (bob at pooh)

	* [loader/files.c] [misc/profile.c]
	System initialization file is now called "wine.ini" and can
	be located in the current directory, the user's home directory,
	or any directories specified in the WINEPATH environment variable.

	* [tools/build.c] [if1632/call.S] [include/regfunc.h]
	Changed register function stack to match sigcontext structure.

Thu Sep 30 22:30:21 1993  Bob Amstadt  (bob at pooh)

	* [loader/files.c]
	Created function to search a path for files to load.

	* [loader/wine.c]
	Modified exe and dll file loading to search through path
	specified by the environment variable WINEPATH.

Thu Sep 30 22:30:21 1993  Eric Youngdale

	* [loader/signal.c]
	Bug fix.

Thu Sep 30 22:30:21 1993  John Brezak

	* [debugger/dbg.y] [debugger/debug.l] [debugger/dtest.c] 
	  [debugger/obstack.h]
	Updates to allow debugger to function under NetBSD.
diff --git a/controls/listbox.c b/controls/listbox.c
new file mode 100644
index 0000000..dc2ae49
--- /dev/null
+++ b/controls/listbox.c
@@ -0,0 +1,963 @@
+/*
+ * Interface code to listbox widgets
+ *
+ * Copyright  Martin Ayotte, 1993
+ *
+ */
+
+/*
+#define DEBUG_LISTBOX
+*/
+
+static char Copyright[] = "Copyright Martin Ayotte, 1993";
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include "windows.h"
+#include "user.h"
+#include "heap.h"
+#include "win.h"
+#include "listbox.h"
+#include "scroll.h"
+#include "dirent.h"
+#include <sys/stat.h>
+
+#define GMEM_ZEROINIT 0x0040
+
+
+LPHEADLIST ListBoxGetWindowAndStorage(HWND hwnd, WND **wndPtr);
+LPHEADLIST ListBoxGetStorageHeader(HWND hwnd);
+void StdDrawListBox(HWND hwnd);
+void OwnerDrawListBox(HWND hwnd);
+int ListBoxFindMouse(HWND hwnd, int X, int Y);
+int CreateListBoxStruct(HWND hwnd);
+int ListBoxAddString(HWND hwnd, LPSTR newstr);
+int ListBoxInsertString(HWND hwnd, UINT uIndex, LPSTR newstr);
+int ListBoxGetText(HWND hwnd, UINT uIndex, LPSTR OutStr);
+int ListBoxDeleteString(HWND hwnd, UINT uIndex);
+int ListBoxFindString(HWND hwnd, UINT nFirst, LPSTR MatchStr);
+int ListBoxResetContent(HWND hwnd);
+int ListBoxSetCurSel(HWND hwnd, WORD wIndex);
+int ListBoxSetSel(HWND hwnd, WORD wIndex);
+int ListBoxDirectory(HWND hwnd, UINT attrib, LPSTR filespec);
+int ListBoxGetItemRect(HWND hwnd, WORD wIndex, LPRECT rect);
+int ListBoxSetItemHeight(HWND hwnd, WORD wIndex, long height);
+int ListBoxDefaultItem(HWND hwnd, WND *wndPtr, 
+	LPHEADLIST lphl, LPLISTSTRUCT lpls);
+int ListBoxFindNextMatch(HWND hwnd, WORD wChar);
+
+
+
+void LISTBOX_CreateListBox(LPSTR className, LPSTR listboxLabel, HWND hwnd)
+{
+    WND *wndPtr    = WIN_FindWndPtr(hwnd);
+    WND *parentPtr = WIN_FindWndPtr(wndPtr->hwndParent);
+    DWORD style;
+    char widgetName[15];
+
+#ifdef DEBUG_LISTBOX
+    printf("listbox: label = %s, x = %d, y = %d\n", listboxLabel,
+	   wndPtr->rectClient.left, wndPtr->rectClient.top);
+    printf("        width = %d, height = %d\n",
+	   wndPtr->rectClient.right - wndPtr->rectClient.left,
+	   wndPtr->rectClient.bottom - wndPtr->rectClient.top);
+#endif
+
+    if (!wndPtr)
+	return;
+
+    style = wndPtr->dwStyle & 0x0000FFFF;
+/*
+    if ((style & LBS_NOTIFY) == LBS_NOTIFY)
+    if ((style & LBS_SORT) == LBS_SORT)
+*/    
+    sprintf(widgetName, "%s%d", className, wndPtr->wIDmenu);
+    wndPtr->winWidget = XtVaCreateManagedWidget(widgetName,
+				    compositeWidgetClass,
+				    parentPtr->winWidget,
+				    XtNx, wndPtr->rectClient.left,
+				    XtNy, wndPtr->rectClient.top,
+				    XtNwidth, wndPtr->rectClient.right -
+				        wndPtr->rectClient.left,
+				    XtNheight, wndPtr->rectClient.bottom -
+				        wndPtr->rectClient.top,
+				    NULL );
+    GlobalUnlock(hwnd);
+    GlobalUnlock(wndPtr->hwndParent);
+}
+
+
+
+/***********************************************************************
+ *           WIDGETS_ListBoxWndProc
+ */
+LONG LISTBOX_ListBoxWndProc( HWND hwnd, WORD message,
+			   WORD wParam, LONG lParam )
+{    
+    WND  *wndPtr;
+    LPHEADLIST  lphl;
+    WORD	wRet;
+    RECT	rect;
+    int		y;
+    int		width, height;
+    CREATESTRUCT *createStruct;
+    static RECT rectsel;
+    switch(message)
+    {
+    case WM_CREATE:
+	CreateListBoxStruct(hwnd);
+	lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
+	createStruct = (CREATESTRUCT *)lParam;
+     	if (HIWORD(createStruct->lpCreateParams) != 0)
+	    lphl->hWndLogicParent = (HWND)HIWORD(createStruct->lpCreateParams);
+	else
+	    lphl->hWndLogicParent = GetParent(hwnd);
+	width = wndPtr->rectClient.right - wndPtr->rectClient.left;
+	height = wndPtr->rectClient.bottom - wndPtr->rectClient.top;
+	lphl->hWndScroll = CreateWindow("SCROLLBAR", "",
+		WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBS_VERT,
+		width - 17, 0, 16, height, hwnd, 1, wndPtr->hInstance, NULL);
+    	ShowWindow(lphl->hWndScroll, SW_HIDE);
+	SetScrollRange(lphl->hWndScroll, WM_VSCROLL, 1, lphl->ItemsCount, TRUE);
+	return 0;
+    case WM_DESTROY:
+        lphl = ListBoxGetStorageHeader(hwnd);
+	ListBoxResetContent(hwnd);
+	DestroyWindow(lphl->hWndScroll);
+	free(lphl);
+        printf("ListBox WM_DESTROY !\n");
+	return 0;
+
+    case WM_VSCROLL:
+        lphl = ListBoxGetStorageHeader(hwnd);
+        if (lphl == NULL) return 0;
+        y = lphl->FirstVisible;
+        switch(wParam) {
+            case SB_LINEUP:
+		if (lphl->FirstVisible > 1)
+		    lphl->FirstVisible--;
+		break;
+            case SB_LINEDOWN:
+		if (lphl->FirstVisible < lphl->ItemsCount)
+		    lphl->FirstVisible++;
+		break;
+	    case SB_PAGEUP:
+		if (lphl->FirstVisible > 1)  
+		    lphl->FirstVisible -= lphl->ItemsVisible;
+		break;
+	    case SB_PAGEDOWN:
+		if (lphl->FirstVisible < lphl->ItemsCount)  
+		    lphl->FirstVisible += lphl->ItemsVisible;
+		break;
+	    case SB_THUMBTRACK:
+	    	lphl->FirstVisible = LOWORD(lParam);
+		break;
+	    }
+	if (lphl->FirstVisible < 1)    lphl->FirstVisible = 1;
+	if (lphl->FirstVisible > lphl->ItemsCount)
+	    lphl->FirstVisible = lphl->ItemsCount;
+	if (y != lphl->FirstVisible) {
+	    SetScrollPos(lphl->hWndScroll, WM_VSCROLL, lphl->FirstVisible, TRUE);
+	    InvalidateRect(hwnd, NULL, TRUE);
+	    UpdateWindow(hwnd);
+            }
+	return 0;
+	
+    case WM_LBUTTONDOWN:
+        lphl = ListBoxGetStorageHeader(hwnd);
+        if (lphl == NULL) return 0;
+	lphl->PrevSelected = lphl->ItemSelected;
+        wRet = ListBoxFindMouse(hwnd, LOWORD(lParam), HIWORD(lParam));
+	ListBoxSetCurSel(hwnd, wRet);
+	ListBoxGetItemRect(hwnd, wRet, &rectsel);
+        InvalidateRect(hwnd, NULL, TRUE);
+        UpdateWindow(hwnd);
+	return 0;
+    case WM_LBUTTONUP:
+	lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
+        if (lphl == NULL) return 0;
+	if (lphl->PrevSelected != lphl->ItemSelected)
+	    SendMessage(lphl->hWndLogicParent, WM_COMMAND, wndPtr->wIDmenu,
+		        	MAKELONG(hwnd, LBN_SELCHANGE));
+	return 0;
+    case WM_RBUTTONUP:
+    case WM_LBUTTONDBLCLK:
+	lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
+        if (lphl == NULL) return 0;
+        SendMessage(lphl->hWndLogicParent, WM_COMMAND, wndPtr->wIDmenu,
+		        	MAKELONG(hwnd, LBN_DBLCLK));
+        printf("ListBox Send LBN_DBLCLK !\n");
+	return 0;
+    case WM_KEYDOWN:
+        printf("ListBox WM_KEYDOWN wParam %X!\n", wParam);
+	ListBoxFindNextMatch(hwnd, wParam);
+	break;
+    case WM_PAINT:
+	wndPtr = WIN_FindWndPtr(hwnd);
+	if ((wndPtr->dwStyle & LBS_OWNERDRAWFIXED) == LBS_OWNERDRAWFIXED) {
+	    OwnerDrawListBox(hwnd);
+	    break;
+	    }
+	if ((wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE) == LBS_OWNERDRAWVARIABLE) {
+	    OwnerDrawListBox(hwnd);
+	    break;
+	    }
+	StdDrawListBox(hwnd);
+	break;
+    case WM_MOUSEMOVE:
+        if ((wParam & MK_LBUTTON) != 0) {
+            y = HIWORD(lParam);
+	    if (y < 4) {
+	        lphl = ListBoxGetStorageHeader(hwnd);
+		if (lphl->FirstVisible > 1) {
+		    lphl->FirstVisible--;
+		    SetScrollPos(lphl->hWndScroll, WM_VSCROLL, lphl->FirstVisible, TRUE);
+		    InvalidateRect(hwnd, NULL, TRUE);
+		    UpdateWindow(hwnd);
+		    break;
+		    }
+		}
+	    GetClientRect(hwnd, &rect);
+	    if (y > (rect.bottom - 4)) {
+	        lphl = ListBoxGetStorageHeader(hwnd);
+		if (lphl->FirstVisible < lphl->ItemsCount) {
+		    lphl->FirstVisible++;
+		    SetScrollPos(lphl->hWndScroll, WM_VSCROLL, lphl->FirstVisible, TRUE);
+		    InvalidateRect(hwnd, NULL, TRUE);
+		    UpdateWindow(hwnd);
+		    break;
+		    }
+		}
+	    if ((y > 0) && (y < (rect.bottom - 4))) {
+		if ((y < rectsel.top) || (y > rectsel.bottom)) {
+		    wRet = ListBoxFindMouse(hwnd, LOWORD(lParam), HIWORD(lParam));
+		    ListBoxSetCurSel(hwnd, wRet);
+		    ListBoxGetItemRect(hwnd, wRet, &rectsel);
+		    InvalidateRect(hwnd, NULL, TRUE);
+		    UpdateWindow(hwnd);
+		    }
+	        
+		}
+	    }
+	break;
+
+    case LB_RESETCONTENT:
+        printf("ListBox LB_RESETCONTENT !\n");
+	ListBoxResetContent(hwnd);
+	return 0;
+    case LB_DIR:
+        printf("ListBox LB_DIR !\n");
+	wRet = ListBoxDirectory(hwnd, wParam, (LPSTR)lParam);
+        InvalidateRect(hwnd, NULL, TRUE);
+        UpdateWindow(hwnd);
+	return wRet;
+    case LB_ADDSTRING:
+	wRet = ListBoxAddString(hwnd, (LPSTR)lParam);
+	return wRet;
+    case LB_GETTEXT:
+	wRet = ListBoxGetText(hwnd, wParam, (LPSTR)lParam);
+        printf("ListBox LB_GETTEXT #%u '%s' !\n", wParam, (LPSTR)lParam);
+	return wRet;
+    case LB_INSERTSTRING:
+	wRet = ListBoxInsertString(hwnd, wParam, (LPSTR)lParam);
+	return wRet;
+    case LB_DELETESTRING:
+        printf("ListBox LB_DELETESTRING #%u !\n", wParam);
+	wRet = ListBoxDeleteString(hwnd, wParam);
+	return wRet;
+    case LB_FINDSTRING:
+	wRet = ListBoxFindString(hwnd, wParam, (LPSTR)lParam);
+	return wRet;
+    case LB_GETCARETINDEX:
+	return wRet;
+    case LB_GETCOUNT:
+        lphl = ListBoxGetStorageHeader(hwnd);
+	return lphl->ItemsCount;
+    case LB_GETCURSEL:
+	lphl = ListBoxGetStorageHeader(hwnd);
+        printf("ListBox LB_GETCURSEL %u !\n", lphl->ItemSelected);
+	if (lphl->ItemSelected == 0) return LB_ERR;
+	return lphl->ItemSelected;
+    case LB_GETHORIZONTALEXTENT:
+	return wRet;
+    case LB_GETITEMDATA:
+	return wRet;
+    case LB_GETITEMHEIGHT:
+	return wRet;
+    case LB_GETITEMRECT:
+	return wRet;
+    case LB_GETSEL:
+	return wRet;
+    case LB_GETSELCOUNT:
+	return wRet;
+    case LB_GETSELITEMS:
+	return wRet;
+    case LB_GETTEXTLEN:
+	return wRet;
+    case LB_GETTOPINDEX:
+	return wRet;
+    case LB_SELECTSTRING:
+	return wRet;
+    case LB_SELITEMRANGE:
+	return wRet;
+    case LB_SETCARETINDEX:
+	return wRet;
+    case LB_SETCOLUMNWIDTH:
+	return wRet;
+    case LB_SETHORIZONTALEXTENT:
+	return wRet;
+    case LB_SETITEMDATA:
+	return wRet;
+    case LB_SETTABSTOPS:
+	return wRet;
+    case LB_SETCURSEL:
+#ifdef DEBUG_LISTBOX
+        printf("ListBox LB_SETCURSEL wParam=%x !\n", wParam);
+#endif
+	wRet = ListBoxSetCurSel(hwnd, wParam);
+        InvalidateRect(hwnd, NULL, TRUE);
+        UpdateWindow(hwnd);
+	return wRet;
+    case LB_SETSEL:
+        printf("ListBox LB_SETSEL wParam=%x lParam=%lX !\n", wParam, lParam);
+	wRet = ListBoxSetSel(hwnd, wParam);
+        InvalidateRect(hwnd, NULL, TRUE);
+        UpdateWindow(hwnd);
+	return wRet;
+    case LB_SETTOPINDEX:
+        printf("ListBox LB_SETTOPINDEX wParam=%x !\n", wParam);
+        lphl = ListBoxGetStorageHeader(hwnd);
+	lphl->FirstVisible = wParam;
+	SetScrollPos(lphl->hWndScroll, WM_VSCROLL, lphl->FirstVisible, TRUE);
+        InvalidateRect(hwnd, NULL, TRUE);
+        UpdateWindow(hwnd);
+	break;
+    case LB_SETITEMHEIGHT:
+#ifdef DEBUG_LISTBOX
+        printf("ListBox LB_SETITEMHEIGHT wParam=%x lParam=%lX !\n", wParam, lParam);
+#endif
+	wRet = ListBoxSetItemHeight(hwnd, wParam, lParam);
+        InvalidateRect(hwnd, NULL, TRUE);
+        UpdateWindow(hwnd);
+	return wRet;
+	
+    default:
+	return DefWindowProc( hwnd, message, wParam, lParam );
+    }
+return 0;
+}
+
+
+LPHEADLIST ListBoxGetWindowAndStorage(HWND hwnd, WND **wndPtr)
+{
+    WND  *Ptr;
+    LPHEADLIST lphl;
+    *(wndPtr) = Ptr = WIN_FindWndPtr(hwnd);
+    lphl = *((LPHEADLIST *)&Ptr->wExtra[1]);
+    return lphl;
+}
+
+
+LPHEADLIST ListBoxGetStorageHeader(HWND hwnd)
+{
+    WND  *wndPtr;
+    LPHEADLIST lphl;
+    wndPtr = WIN_FindWndPtr(hwnd);
+    lphl = *((LPHEADLIST *)&wndPtr->wExtra[1]);
+    return lphl;
+}
+
+
+void StdDrawListBox(HWND hwnd)
+{
+	LPHEADLIST  lphl;
+	LPLISTSTRUCT lpls;
+	PAINTSTRUCT ps;
+	HBRUSH hBrush;
+	HWND	hWndParent;
+	HDC hdc;
+	RECT rect;
+	UINT  i, h, h2;
+	char	C[128];
+	h = 0;
+	hdc = BeginPaint( hwnd, &ps );
+	GetClientRect(hwnd, &rect);
+        lphl = ListBoxGetStorageHeader(hwnd);
+	if (lphl == NULL) goto EndOfPaint;
+	hBrush = SendMessage(lphl->hWndLogicParent, WM_CTLCOLOR, (WORD)hdc,
+		    MAKELONG(hwnd, CTLCOLOR_LISTBOX));
+	if (hBrush == (HBRUSH)NULL)  hBrush = GetStockObject(WHITE_BRUSH);
+	if (lphl->ItemsCount > lphl->ItemsVisible) rect.right -= 16;
+	FillRect(hdc, &rect, hBrush);
+	if (lphl->ItemsCount == 0) goto EndOfPaint;
+	lpls = lphl->lpFirst;
+	if (lpls == NULL) goto EndOfPaint;
+	lphl->ItemsVisible = 0;
+	for(i = 1; i <= lphl->ItemsCount; i++) {
+	    if (i >= lphl->FirstVisible) {
+		h2 = lpls->dis.rcItem.bottom - lpls->dis.rcItem.top;
+		lpls->dis.rcItem.top = h;
+		lpls->dis.rcItem.bottom = h + h2;
+		lpls->dis.rcItem.right = rect.right;
+		TextOut(hdc, 5, h + 2, (char *)lpls->dis.itemData, 
+			strlen((char *)lpls->dis.itemData));
+		if (lpls->dis.itemState != 0) {
+		    InvertRect(hdc, &lpls->dis.rcItem);
+		    }
+		h += h2;
+		lphl->ItemsVisible++;
+		if (h > rect.bottom) break;
+		}
+	    if (lpls->lpNext == NULL) goto EndOfPaint;
+	    lpls = (LPLISTSTRUCT)lpls->lpNext;
+	}
+EndOfPaint:
+    EndPaint( hwnd, &ps );
+    if (lphl->ItemsCount > lphl->ItemsVisible) {
+        InvalidateRect(lphl->hWndScroll, NULL, TRUE);
+        UpdateWindow(lphl->hWndScroll);
+ 	}
+}
+
+
+
+void OwnerDrawListBox(HWND hwnd)
+{
+	LPHEADLIST  lphl;
+	LPLISTSTRUCT lpls;
+	HANDLE	hTemp;
+	PAINTSTRUCT ps;
+	HBRUSH 	hBrush;
+	HWND	hWndParent;
+	HDC hdc;
+	RECT rect;
+	UINT  i, h, h2;
+	char	C[128];
+	h = 0;
+	hdc = BeginPaint( hwnd, &ps );
+	GetClientRect(hwnd, &rect);
+        lphl = ListBoxGetStorageHeader(hwnd);
+	if (lphl == NULL) goto EndOfPaint;
+	hBrush = SendMessage(lphl->hWndLogicParent, WM_CTLCOLOR, (WORD)hdc,
+		    MAKELONG(hwnd, CTLCOLOR_LISTBOX));
+	if (hBrush == (HBRUSH)NULL)  hBrush = GetStockObject(WHITE_BRUSH);
+	if (lphl->ItemsCount > lphl->ItemsVisible) rect.right -= 16;
+	FillRect(hdc, &rect, hBrush);
+	if (lphl->ItemsCount == 0) goto EndOfPaint;
+	lpls = lphl->lpFirst;
+	if (lpls == NULL) goto EndOfPaint;
+	lphl->ItemsVisible = 0;
+	for(i = 1; i <= lphl->ItemsCount; i++) {
+	    if (i >= lphl->FirstVisible) {
+		lpls->dis.hDC = hdc;
+		lpls->dis.itemID = i;
+		h2 = lpls->dis.rcItem.bottom - lpls->dis.rcItem.top;
+		lpls->dis.rcItem.top = h;
+		lpls->dis.rcItem.bottom = h + h2;
+		lpls->dis.rcItem.right = rect.right;
+		lpls->dis.itemAction = ODA_DRAWENTIRE;
+		if (lpls->dis.itemState != 0) {
+		    lpls->dis.itemAction |= ODA_SELECT;
+		    }
+#ifdef DEBUT_LISTBOX
+		printf("LBOX WM_DRAWITEM #%d left=%d top=%d right=%d bottom=%d !\n", 
+			i, lpls->dis.rcItem.left, lpls->dis.rcItem.top, 
+			lpls->dis.rcItem.right, lpls->dis.rcItem.bottom);
+		printf("LBOX WM_DRAWITEM Parent=%X &dis=%lX CtlID=%u !\n", 
+			hWndParent, (LONG)&lpls->dis, lpls->dis.CtlID);
+#endif
+		printf("LBOX WM_DRAWITEM '%s' !\n", lpls->dis.itemData);
+		SendMessage(lphl->hWndLogicParent, WM_DRAWITEM, i, (LPARAM)&lpls->dis);
+		GlobalUnlock(hTemp);
+		GlobalFree(hTemp);
+		if (lpls->dis.itemState != 0) {
+		    InvertRect(hdc, &lpls->dis.rcItem);
+		    }
+		h += h2;
+		lphl->ItemsVisible++;
+		if (h > rect.bottom) break;
+		}
+	    if (lpls->lpNext == NULL) goto EndOfPaint;
+	    lpls = (LPLISTSTRUCT)lpls->lpNext;
+	}
+EndOfPaint:
+    EndPaint( hwnd, &ps );
+    if (lphl->ItemsCount > lphl->ItemsVisible) {
+        InvalidateRect(lphl->hWndScroll, NULL, TRUE);
+        UpdateWindow(lphl->hWndScroll);
+        }
+}
+
+
+
+int ListBoxFindMouse(HWND hwnd, int X, int Y)
+{
+LPHEADLIST 	lphl;
+LPLISTSTRUCT	lpls;
+RECT rect;
+UINT  i, h, h2;
+char	C[128];
+h = 0;
+lphl = ListBoxGetStorageHeader(hwnd);
+if (lphl == NULL) return LB_ERR;
+if (lphl->ItemsCount == 0) return LB_ERR;
+lpls = lphl->lpFirst;
+if (lpls == NULL) return LB_ERR;
+for(i = 1; i <= lphl->ItemsCount; i++) {
+    if (i >= lphl->FirstVisible) {
+	h2 = h;
+	h += lpls->dis.rcItem.bottom - lpls->dis.rcItem.top;
+	if ((Y > h2) && (Y < h)) return(i);
+	}
+    if (lpls->lpNext == NULL) return LB_ERR;
+    lpls = (LPLISTSTRUCT)lpls->lpNext;
+    }
+return(LB_ERR);
+}
+
+
+
+int CreateListBoxStruct(HWND hwnd)
+{
+    WND  *wndPtr;
+    LPHEADLIST lphl;
+    wndPtr = WIN_FindWndPtr(hwnd);
+    lphl = (LPHEADLIST)malloc(sizeof(HEADLIST));
+    lphl->lpFirst = NULL;
+    *((LPHEADLIST *)&wndPtr->wExtra[1]) = lphl; 	/* HEAD of List */
+    lphl->ItemsCount = 0;
+    lphl->ItemsVisible = 0;
+    lphl->FirstVisible = 1;
+    lphl->StdItemHeight = 15;
+    lphl->DrawCtlType = ODT_LISTBOX;
+    return TRUE;
+}
+
+
+int ListBoxAddString(HWND hwnd, LPSTR newstr)
+{
+    WND  	*wndPtr;
+    LPHEADLIST 	lphl;
+    LPLISTSTRUCT lpls, lplsnew;
+    HANDLE 	hTemp;
+    LPSTR 	str;
+    lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
+    if (lphl == NULL) return LB_ERR;
+    hTemp = USER_HEAP_ALLOC(GMEM_MOVEABLE, sizeof(LISTSTRUCT));
+    lplsnew = (LPLISTSTRUCT) USER_HEAP_ADDR(hTemp);
+    lpls = lphl->lpFirst;
+    if (lpls != NULL) {
+	while(lpls->lpNext != NULL) {
+	    lpls = (LPLISTSTRUCT)lpls->lpNext;
+	    }
+	lpls->lpNext = lplsnew;
+ 	}
+    else
+	lphl->lpFirst = lplsnew;
+    lphl->ItemsCount++;
+#ifdef DEBUG_LISTBOX
+    printf("Items Count = %u\n", lphl->ItemsCount);
+#endif
+    hTemp = 0;
+    if ((wndPtr->dwStyle & LBS_HASSTRINGS) != LBS_HASSTRINGS) {
+	if (((wndPtr->dwStyle & LBS_OWNERDRAWFIXED) != LBS_OWNERDRAWFIXED) &&
+	    ((wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE) != LBS_OWNERDRAWVARIABLE)) {
+	    hTemp = USER_HEAP_ALLOC(GMEM_MOVEABLE, strlen(newstr) + 1);
+	    str = (LPSTR)USER_HEAP_ADDR(hTemp);
+	    if (str == NULL) return LB_ERRSPACE;
+	    strcpy(str, newstr);
+	    newstr = str;
+	    }
+	}
+    ListBoxDefaultItem(hwnd, wndPtr, lphl, lplsnew);
+    lplsnew->hMem = hTemp;
+    lplsnew->lpNext = NULL;
+    lplsnew->dis.itemID = lphl->ItemsCount;
+    lplsnew->dis.itemData = (DWORD)newstr;
+    lplsnew->hData = hTemp;
+    SetScrollRange(lphl->hWndScroll, WM_VSCROLL, 1, lphl->ItemsCount, TRUE);
+    if (lphl->FirstVisible >= (lphl->ItemsCount - lphl->ItemsVisible)) {
+        InvalidateRect(hwnd, NULL, TRUE);
+        UpdateWindow(hwnd);
+        }
+    if ((lphl->ItemsCount - lphl->FirstVisible) == lphl->ItemsVisible) 
+    	ShowWindow(lphl->hWndScroll, SW_NORMAL);
+    return lphl->ItemsCount;
+}
+
+
+int ListBoxInsertString(HWND hwnd, UINT uIndex, LPSTR newstr)
+{
+    WND  	*wndPtr;
+    LPHEADLIST 	lphl;
+    LPLISTSTRUCT lpls, lplsnew;
+    HANDLE	hTemp;
+    LPSTR	str;
+    UINT	Count;
+    lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
+    if (lphl == NULL) return LB_ERR;
+    if (uIndex < 1 || uIndex > lphl->ItemsCount) return LB_ERR;
+    lpls = lphl->lpFirst;
+    if (lpls == NULL) return LB_ERR;
+    if (uIndex > lphl->ItemsCount) return LB_ERR;
+    for(Count = 1; Count < uIndex; Count++) {
+	if (lpls->lpNext == NULL) return LB_ERR;
+	lpls = (LPLISTSTRUCT)lpls->lpNext;
+    }
+    hTemp = USER_HEAP_ALLOC(GMEM_MOVEABLE, sizeof(LISTSTRUCT));
+    lplsnew = (LPLISTSTRUCT) USER_HEAP_ADDR(hTemp);
+    ListBoxDefaultItem(hwnd, wndPtr, lphl, lplsnew);
+    lplsnew->hMem = hTemp;
+    lpls->lpNext = lplsnew;
+    lphl->ItemsCount++;
+    hTemp = 0;
+    if ((wndPtr->dwStyle & LBS_HASSTRINGS) != LBS_HASSTRINGS) {
+	if (((wndPtr->dwStyle & LBS_OWNERDRAWFIXED) != LBS_OWNERDRAWFIXED) &&
+	    ((wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE) != LBS_OWNERDRAWVARIABLE)) {
+	    hTemp = USER_HEAP_ALLOC(GMEM_MOVEABLE, strlen(newstr) + 1);
+	    str = (LPSTR)USER_HEAP_ADDR(hTemp);
+	    if (str == NULL) return LB_ERRSPACE;
+	    strcpy(str, newstr);
+	    newstr = str;
+	    }
+	}
+    lplsnew->lpNext = NULL;
+    lplsnew->dis.itemID = lphl->ItemsCount;
+    lplsnew->dis.itemData = (DWORD)newstr;
+    lplsnew->hData = hTemp;
+    SetScrollRange(lphl->hWndScroll, WM_VSCROLL, 1, lphl->ItemsCount, TRUE);
+    if (((lphl->ItemsCount - lphl->FirstVisible) == lphl->ItemsVisible) && 
+        (lphl->ItemsVisible != 0)) 
+    	ShowWindow(lphl->hWndScroll, SW_NORMAL);
+    if ((lphl->FirstVisible <= uIndex) &&
+        ((lphl->FirstVisible + lphl->ItemsVisible) >= uIndex)) {
+        InvalidateRect(hwnd, NULL, TRUE);
+        UpdateWindow(hwnd);
+        }
+    return lphl->ItemsCount;
+}
+
+
+int ListBoxGetText(HWND hwnd, UINT uIndex, LPSTR OutStr)
+{
+    WND  	*wndPtr;
+    LPHEADLIST 	lphl;
+    LPLISTSTRUCT lpls;
+    UINT	Count;
+    lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
+    if (lphl == NULL) return LB_ERR;
+    if (uIndex < 1 || uIndex > lphl->ItemsCount) return LB_ERR;
+    lpls = lphl->lpFirst;
+    if (lpls == NULL) return LB_ERR;
+    if (uIndex > lphl->ItemsCount) return LB_ERR;
+    for(Count = 1; Count < uIndex; Count++) {
+	if (lpls->lpNext == NULL) return LB_ERR;
+	lpls = (LPLISTSTRUCT)lpls->lpNext;
+    }
+    if (((wndPtr->dwStyle & LBS_OWNERDRAWFIXED) == LBS_OWNERDRAWFIXED) ||
+	    ((wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE) == LBS_OWNERDRAWVARIABLE)) {
+	if ((wndPtr->dwStyle & LBS_HASSTRINGS) != LBS_HASSTRINGS) { 
+	    *((long *)OutStr) = lpls->dis.itemData;
+	    return 4;
+	    }
+	}
+	
+    strcpy(OutStr, (char *)lpls->dis.itemData);
+    return strlen(OutStr);
+}
+
+
+int ListBoxDeleteString(HWND hwnd, UINT uIndex)
+{
+    LPHEADLIST 	lphl;
+    LPLISTSTRUCT lpls, lpls2;
+    UINT	Count;
+    lphl = ListBoxGetStorageHeader(hwnd);
+    if (lphl == NULL) return LB_ERR;
+    if (uIndex < 1 || uIndex > lphl->ItemsCount) return LB_ERR;
+    lpls = lphl->lpFirst;
+    if (lpls == NULL) return LB_ERR;
+    if (uIndex > lphl->ItemsCount) return LB_ERR;
+    for(Count = 1; Count < uIndex; Count++) {
+	if (lpls->lpNext == NULL) return LB_ERR;
+	lpls2 = lpls;
+	lpls = (LPLISTSTRUCT)lpls->lpNext;
+    }
+    lpls2->lpNext = (LPLISTSTRUCT)lpls->lpNext;
+    lphl->ItemsCount--;
+    if (lpls->hData != 0) USER_HEAP_FREE(lpls->hData);
+    if (lpls->hMem != 0) USER_HEAP_FREE(lpls->hMem);
+    SetScrollRange(lphl->hWndScroll, WM_VSCROLL, 1, lphl->ItemsCount, TRUE);
+    if (lphl->ItemsCount < lphl->ItemsVisible) 
+    	ShowWindow(lphl->hWndScroll, SW_HIDE);
+    if ((lphl->FirstVisible <= uIndex) &&
+        ((lphl->FirstVisible + lphl->ItemsVisible) >= uIndex)) {
+        InvalidateRect(hwnd, NULL, TRUE);
+        UpdateWindow(hwnd);
+        }
+    return lphl->ItemsCount;
+}
+
+
+int ListBoxFindString(HWND hwnd, UINT nFirst, LPSTR MatchStr)
+{
+    LPHEADLIST 	lphl;
+    LPLISTSTRUCT lpls;
+    UINT	Count;
+    lphl = ListBoxGetStorageHeader(hwnd);
+    if (lphl == NULL) return LB_ERR;
+    if (nFirst < 1 || nFirst > lphl->ItemsCount) return LB_ERR;
+    lpls = lphl->lpFirst;
+    if (lpls == NULL) return LB_ERR;
+    Count = 1;
+    while(lpls != NULL) {
+    	if (strcmp((char *)lpls->dis.itemData, MatchStr) == 0)
+	    return Count;
+	lpls = (LPLISTSTRUCT)lpls->lpNext;
+	Count++;
+        }
+    return LB_ERR;
+}
+
+
+int ListBoxResetContent(HWND hwnd)
+{
+    WND  *wndPtr;
+    LPHEADLIST 	lphl;
+    LPLISTSTRUCT lpls, lpls2;
+    UINT	i;
+    lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
+    if (lphl == NULL) return LB_ERR;
+    lpls = lphl->lpFirst;
+    if (lpls == NULL) return LB_ERR;
+    for(i = 0; i <= lphl->ItemsCount; i++) {
+	lpls2 = lpls;
+	lpls = (LPLISTSTRUCT)lpls->lpNext;
+	if (i != 0) {
+#ifdef DEBUG_LISTBOX
+	    printf("ResetContent #%u\n", i);
+#endif
+	    if (lpls2->hData != 0) USER_HEAP_FREE(lpls->hData);
+	    if (lpls2->hMem != 0) USER_HEAP_FREE(lpls->hMem);
+	    }  
+	if (lpls == NULL)  break;
+    }
+    lphl->lpFirst = NULL;
+    lphl->FirstVisible = 1;
+    lphl->ItemsCount = 0;
+    lphl->ItemSelected = 0;
+    lphl->PrevSelected = 0;
+    if ((wndPtr->dwStyle && LBS_NOTIFY) != 0)
+	SendMessage(wndPtr->hwndParent, WM_COMMAND, 
+    	    wndPtr->wIDmenu, MAKELONG(hwnd, LBN_SELCHANGE));
+
+    SetScrollRange(lphl->hWndScroll, WM_VSCROLL, 1, lphl->ItemsCount, TRUE);
+    ShowWindow(lphl->hWndScroll, SW_HIDE);
+    InvalidateRect(hwnd, NULL, TRUE);
+    UpdateWindow(hwnd);
+    return TRUE;
+}
+
+
+int ListBoxSetCurSel(HWND hwnd, WORD wIndex)
+{
+    WND  *wndPtr;
+    LPHEADLIST 	lphl;
+    LPLISTSTRUCT lpls, lpls2;
+    UINT	i;
+    lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
+    if (lphl == NULL) return LB_ERR;
+    lphl->ItemSelected = LB_ERR;
+    if (wIndex < 1 || wIndex > lphl->ItemsCount) return LB_ERR;
+    lpls = lphl->lpFirst;
+    if (lpls == NULL) return LB_ERR;
+    for(i = 1; i <= lphl->ItemsCount; i++) {
+	lpls2 = lpls;
+	lpls = (LPLISTSTRUCT)lpls->lpNext;
+	if (i == wIndex)
+	    lpls2->dis.itemState = 1;
+	else 
+	    if (lpls2->dis.itemState != 0)
+	        lpls2->dis.itemState = 0;
+	if (lpls == NULL)  break;
+    }
+    lphl->ItemSelected = wIndex;
+    if ((wndPtr->dwStyle && LBS_NOTIFY) != 0)
+	SendMessage(wndPtr->hwndParent, WM_COMMAND, 
+    	    wndPtr->wIDmenu, MAKELONG(hwnd, LBN_SELCHANGE));
+    return LB_ERR;
+}
+
+
+
+int ListBoxSetSel(HWND hwnd, WORD wIndex)
+{
+    LPHEADLIST 	lphl;
+    LPLISTSTRUCT lpls, lpls2;
+    UINT	i;
+    lphl = ListBoxGetStorageHeader(hwnd);
+    if (lphl == NULL) return LB_ERR;
+    if (wIndex < 1 || wIndex > lphl->ItemsCount) return LB_ERR;
+    lpls = lphl->lpFirst;
+    if (lpls == NULL) return LB_ERR;
+    for(i = 1; i <= lphl->ItemsCount; i++) {
+	lpls2 = lpls;
+	lpls = (LPLISTSTRUCT)lpls->lpNext;
+	if (i == wIndex) {
+	    lpls2->dis.itemState = 1;
+	    break;
+	    }  
+	if (lpls == NULL)  break;
+    }
+    return LB_ERR;
+}
+
+
+int ListBoxDirectory(HWND hwnd, UINT attrib, LPSTR filespec)
+{
+DIR           	*dirp;
+struct dirent 	*dp;
+struct stat	st;
+char		str[128];
+int		wRet;
+dirp = opendir(".");
+while ( (dp = readdir(dirp)) != NULL) 
+    {
+    stat(dp->d_name, &st);
+#ifdef DEBUG_LBDIR
+    printf("LB_DIR : st_mode=%lX / d_name='%s'\n", st.st_mode, dp->d_name);
+#endif
+    if S_ISDIR(st.st_mode) {
+	sprintf(str, "[%s]", dp->d_name);
+	}
+    else
+	strcpy(str, dp->d_name);
+    wRet = ListBoxAddString(hwnd, str);
+    if (wRet == LB_ERR) break;
+    }
+closedir(dirp);	
+return wRet;
+}
+
+
+int ListBoxGetItemRect(HWND hwnd, WORD wIndex, LPRECT lprect)
+{
+    LPHEADLIST 	lphl;
+    LPLISTSTRUCT lpls, lpls2;
+    UINT	i;
+    lphl = ListBoxGetStorageHeader(hwnd);
+    if (lphl == NULL) return LB_ERR;
+    if (wIndex < 1 || wIndex > lphl->ItemsCount) return LB_ERR;
+    lpls = lphl->lpFirst;
+    if (lpls == NULL) return LB_ERR;
+    for(i = 0; i <= lphl->ItemsCount; i++) {
+	lpls2 = lpls;
+	lpls = (LPLISTSTRUCT)lpls->lpNext;
+	if (i == wIndex) {
+	    *(lprect) = lpls2->dis.rcItem;
+	    break;
+	    }  
+	if (lpls == NULL)  break;
+    }
+    return LB_ERR;
+}
+
+
+
+int ListBoxSetItemHeight(HWND hwnd, WORD wIndex, long height)
+{
+    LPHEADLIST 	lphl;
+    LPLISTSTRUCT lpls, lpls2;
+    UINT	i;
+    lphl = ListBoxGetStorageHeader(hwnd);
+    if (lphl == NULL) return LB_ERR;
+    if (wIndex < 1 || wIndex > lphl->ItemsCount) return LB_ERR;
+    lpls = lphl->lpFirst;
+    if (lpls == NULL) return LB_ERR;
+    for(i = 0; i <= lphl->ItemsCount; i++) {
+	lpls2 = lpls;
+	lpls = (LPLISTSTRUCT)lpls->lpNext;
+	if (i == wIndex) {
+	    lpls2->dis.rcItem.bottom = lpls2->dis.rcItem.top + (short)height;
+	    break;
+	    }  
+	if (lpls == NULL)  break;
+    }
+    return LB_ERR;
+}
+
+
+
+
+
+int ListBoxDefaultItem(HWND hwnd, WND *wndPtr, 
+	LPHEADLIST lphl, LPLISTSTRUCT lpls)
+{
+    RECT	rect;
+    GetClientRect(hwnd, &rect);
+    SetRect(&lpls->dis.rcItem, 0, 0, rect.right, lphl->StdItemHeight);
+    lpls->dis.CtlType = lphl->DrawCtlType;
+    lpls->dis.CtlID = wndPtr->wIDmenu;
+    lpls->dis.itemID = 0;
+    lpls->dis.itemAction = 0;
+    lpls->dis.itemState = 0;
+    lpls->dis.hwndItem = hwnd;
+    lpls->dis.hDC = 0;
+    lpls->dis.itemData = 0;
+}
+
+
+
+int ListBoxFindNextMatch(HWND hwnd, WORD wChar)
+{
+    WND  	*wndPtr;
+    LPHEADLIST 	lphl;
+    LPLISTSTRUCT lpls;
+    UINT	Count;
+    lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
+    if (lphl == NULL) return LB_ERR;
+    lpls = lphl->lpFirst;
+    if (lpls == NULL) return LB_ERR;
+    if (wChar < ' ') return LB_ERR;
+    if (((wndPtr->dwStyle & LBS_OWNERDRAWFIXED) == LBS_OWNERDRAWFIXED) ||
+	    ((wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE) == LBS_OWNERDRAWVARIABLE)) {
+	if ((wndPtr->dwStyle & LBS_HASSTRINGS) != LBS_HASSTRINGS) { 
+	    return LB_ERR;
+	    }
+	}
+    Count = 1;
+    while(lpls != NULL) {
+        if (Count > lphl->ItemSelected) {
+	    if (*((char *)lpls->dis.itemData) == (char)wChar) {
+		lphl->FirstVisible = Count - lphl->ItemsVisible / 2;
+		if (lphl->FirstVisible < 1) lphl->FirstVisible = 1;
+		ListBoxSetCurSel(hwnd, Count);
+		SetScrollPos(lphl->hWndScroll, WM_VSCROLL, lphl->FirstVisible, TRUE);
+	        InvalidateRect(hwnd, NULL, TRUE);
+	        UpdateWindow(hwnd);
+	        return Count;
+	        }
+	    }
+	lpls = (LPLISTSTRUCT)lpls->lpNext;
+	Count++;
+	}
+    Count = 1;
+    lpls = lphl->lpFirst;
+    while(lpls != NULL) {
+	if (*((char *)lpls->dis.itemData) == (char)wChar) {
+	    if (Count == lphl->ItemSelected)    return LB_ERR;
+	    lphl->FirstVisible = Count - lphl->ItemsVisible / 2;
+	    if (lphl->FirstVisible < 1) lphl->FirstVisible = 1;
+	    ListBoxSetCurSel(hwnd, Count);
+	    SetScrollPos(lphl->hWndScroll, WM_VSCROLL, lphl->FirstVisible, TRUE);
+	    InvalidateRect(hwnd, NULL, TRUE);
+	    UpdateWindow(hwnd);
+	    return Count;
+	    }
+	lpls = (LPLISTSTRUCT)lpls->lpNext;
+	Count++;
+        }
+    return LB_ERR;
+}
+
+