Skip to content
Snippets Groups Projects
Forked from wine / wine
175850 commits behind the upstream repository.
  • Alexandre Julliard's avatar
    f0cbfa0c
    Release 970215 · f0cbfa0c
    Alexandre Julliard authored
    Sat Feb 15 11:59:17 1997  Alexandre Julliard  <julliard@lrc.epfl.ch>
    
    	* [*/*]
    	Converted a lot of functions to Win32 types.
    	Removed HWND type.
    
    Fri Feb 14 15:09:19 1997  Onno Hovers <onno@stack.nl>
    
    	* [memory/global.c]
    	Implemented GMEM_MOVEABLE blocks for Win32.
    
    Fri Feb 14 00:24:39 1997  Alex Korobka <alex@trantor.pharm.sunysb.edu>
    
    	* [loader/task.c] [windows/queue.c]
    	Do not read X events while in the intertask SendMessage().
    
    	* [misc/lstr.c]
    	Fixed CharPrev32A().
    
    	* [windows/hook.c] [include/hook.h]
    	Restored broken WH_CALLWNDPROC functionality for dialogs, etc...
    
    	* [windows/win.c] [windows/defwnd.c] [windows/mdi.c]
    	  [windows/event.c] [controls/edit.c] 
    	Added WIN_ISWIN32 flag to windows created by Win32 calls. 
    	Several new Win32 messages are sent when this flag is on.
    	
    	* [msdos/dosmem.c] [memory/global.c]
    	Some changes in DOS memory allocation.
    
    Fri Feb  7 21:46:03 1997  Andrew Taylor  <andrew@riscan.com>
    
    	* [win32/security.c]
    	Added SID manipulation functions.
    
    	* [include/debug.h]
    	Added debugging class "security".
    
    Fri  Feb 7 20:46:33 1997  Robert Pouliot <krynos@clic.net>
    
    	* [debugger/msc.c] [debugger/source.c] 
    	  [documentation/wine_os2.txt] [loader/signal.c]
    	Some more changes for OS/2. Doesn't work yet.
    
    Fri  Feb 7 09:31:17 1997  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>
    
    	* [scheduler/process.c]
    	Added ExpandEnvironmentStrings*.
    
    	* [misc/ntdll.c] [include/ntdll.h]
    	Added some new functions.
    
    	* [objects/cursoricon.c]
    	CURSORICON_LoadHandler: check against some bizarre out of memory
    	conditions.
    	
    	* [windows/mdi.c]
    	Fixed DefFrameProc32*, added TranslateMDISysAccel32.
    
    Wed Feb  5 01:31:05 1997  John Zero <john@globe.graphisoft.hu>
    
    	* [resources/sysres_Hu.rc] [misc/ole2nls.c] [misc/main.c]
    	  [programs/progman/Hu.rc] [programs/winhelp/Hu.rc]
    	Added Hungarian language support.
    f0cbfa0c
    History
    Release 970215
    Alexandre Julliard authored
    Sat Feb 15 11:59:17 1997  Alexandre Julliard  <julliard@lrc.epfl.ch>
    
    	* [*/*]
    	Converted a lot of functions to Win32 types.
    	Removed HWND type.
    
    Fri Feb 14 15:09:19 1997  Onno Hovers <onno@stack.nl>
    
    	* [memory/global.c]
    	Implemented GMEM_MOVEABLE blocks for Win32.
    
    Fri Feb 14 00:24:39 1997  Alex Korobka <alex@trantor.pharm.sunysb.edu>
    
    	* [loader/task.c] [windows/queue.c]
    	Do not read X events while in the intertask SendMessage().
    
    	* [misc/lstr.c]
    	Fixed CharPrev32A().
    
    	* [windows/hook.c] [include/hook.h]
    	Restored broken WH_CALLWNDPROC functionality for dialogs, etc...
    
    	* [windows/win.c] [windows/defwnd.c] [windows/mdi.c]
    	  [windows/event.c] [controls/edit.c] 
    	Added WIN_ISWIN32 flag to windows created by Win32 calls. 
    	Several new Win32 messages are sent when this flag is on.
    	
    	* [msdos/dosmem.c] [memory/global.c]
    	Some changes in DOS memory allocation.
    
    Fri Feb  7 21:46:03 1997  Andrew Taylor  <andrew@riscan.com>
    
    	* [win32/security.c]
    	Added SID manipulation functions.
    
    	* [include/debug.h]
    	Added debugging class "security".
    
    Fri  Feb 7 20:46:33 1997  Robert Pouliot <krynos@clic.net>
    
    	* [debugger/msc.c] [debugger/source.c] 
    	  [documentation/wine_os2.txt] [loader/signal.c]
    	Some more changes for OS/2. Doesn't work yet.
    
    Fri  Feb 7 09:31:17 1997  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>
    
    	* [scheduler/process.c]
    	Added ExpandEnvironmentStrings*.
    
    	* [misc/ntdll.c] [include/ntdll.h]
    	Added some new functions.
    
    	* [objects/cursoricon.c]
    	CURSORICON_LoadHandler: check against some bizarre out of memory
    	conditions.
    	
    	* [windows/mdi.c]
    	Fixed DefFrameProc32*, added TranslateMDISysAccel32.
    
    Wed Feb  5 01:31:05 1997  John Zero <john@globe.graphisoft.hu>
    
    	* [resources/sysres_Hu.rc] [misc/ole2nls.c] [misc/main.c]
    	  [programs/progman/Hu.rc] [programs/winhelp/Hu.rc]
    	Added Hungarian language support.
combo.c 38.27 KiB
/*
 * Combo controls
 * 
 * Copyright 1993 Martin Ayotte
 * Copyright 1995 Bernd Schmidt
 * Copyright 1996 Albrecht Kleine  [some fixes]
 * 
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "windows.h"
#include "sysmetrics.h"
#include "win.h"
#include "combo.h"
#include "user.h"
#include "graphics.h"
#include "heap.h"
#include "listbox.h"
#include "drive.h"
#include "stddebug.h"
#include "debug.h"
#include "xmalloc.h"

 /*
  * Note: Combos are probably implemented in a different way by Windows.
  * Using a message spy for Windows, you can see some undocumented
  * messages being passed between ComboBox and ComboLBox.
  * I hope no programs rely on the implementation of combos.
  */

#define ID_EDIT  1
#define ID_CLB   2
#define CBLMM_EDGE   4    /* distance inside box which is same as moving mouse
			     outside box, to trigger scrolling of CBL */

static BOOL CBCheckSize(HWND16 hwnd);
static BOOL CBLCheckSize(HWND16 hwnd);

static HBITMAP16 hComboBit = 0;
static WORD CBitHeight, CBitWidth;

static int COMBO_Init()
{
  BITMAP16 bm;
  
  dprintf_combo(stddeb, "COMBO_Init\n");
  hComboBit = LoadBitmap16(0, MAKEINTRESOURCE(OBM_COMBO));
  GetObject16( hComboBit, sizeof(bm), &bm );
  CBitHeight = bm.bmHeight;
  CBitWidth = bm.bmWidth;
  return 0;
}

LPHEADCOMBO ComboGetStorageHeader(HWND16 hwnd)
{
  return (LPHEADCOMBO)GetWindowLong32A(hwnd,4);
}

LPHEADLIST ComboGetListHeader(HWND16 hwnd)
{
  return (LPHEADLIST)GetWindowLong32A(hwnd,0);
}

int CreateComboStruct(HWND16 hwnd, LONG style)
{
  LPHEADCOMBO lphc;

  lphc = (LPHEADCOMBO)xmalloc(sizeof(HEADCOMBO));
  SetWindowLong32A(hwnd,4,(LONG)lphc);
  lphc->hWndEdit = 0;
  lphc->hWndLBox = 0;
  lphc->dwState = 0;
  lphc->LastSel = -1;
  lphc->dwStyle = style; 
  lphc->DropDownVisible = FALSE;
  return TRUE;
}

void ComboUpdateWindow(HWND16 hwnd, LPHEADLIST lphl, LPHEADCOMBO lphc, BOOL repaint)
{
  WND *wndPtr = WIN_FindWndPtr(hwnd);

  if (wndPtr->dwStyle & WS_VSCROLL) 
    SetScrollRange32(lphc->hWndLBox,SB_VERT,0,ListMaxFirstVisible(lphl),TRUE);
  if (repaint && lphl->bRedrawFlag) InvalidateRect32( hwnd, NULL, TRUE );
}

/***********************************************************************
 *           CBNCCreate
 */
static LRESULT CBNCCreate(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  CREATESTRUCT16 *createStruct;

  if (!hComboBit) COMBO_Init();

  createStruct = (CREATESTRUCT16 *)PTR_SEG_TO_LIN(lParam);
  createStruct->style |= WS_BORDER;
  SetWindowLong32A(hwnd, GWL_STYLE, createStruct->style);

  dprintf_combo(stddeb,"ComboBox WM_NCCREATE!\n");
  return DefWindowProc16(hwnd, WM_NCCREATE, wParam, lParam);

}

/***********************************************************************
 *           CBCreate
 */
static LRESULT CBCreate(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST   lphl;
  LPHEADCOMBO  lphc;
  LONG         style = 0;
  LONG         cstyle = GetWindowLong32A(hwnd,GWL_STYLE);
  RECT16       rect,lboxrect;
  WND*         wndPtr = WIN_FindWndPtr(hwnd);
  char className[] = "COMBOLBOX";  /* Hack so that class names are > 0x10000 */
  char editName[] = "EDIT";
  HWND16 hwndp=0;

  /* translate combo into listbox styles */
  cstyle |= WS_BORDER;
  if (cstyle & CBS_OWNERDRAWFIXED) style |= LBS_OWNERDRAWFIXED;
  if (cstyle & CBS_OWNERDRAWVARIABLE) style |= LBS_OWNERDRAWVARIABLE;
  if (cstyle & CBS_SORT) style |= LBS_SORT;
  if (cstyle & CBS_HASSTRINGS) style |= LBS_HASSTRINGS;
  style |= LBS_NOTIFY;
  CreateListBoxStruct(hwnd, ODT_COMBOBOX, style, GetParent16(hwnd));
  CreateComboStruct(hwnd,cstyle);

  lphl = ComboGetListHeader(hwnd);
  lphc = ComboGetStorageHeader(hwnd);

  GetClientRect16(hwnd,&rect);
  lphc->LBoxTop = lphl->StdItemHeight;

  switch(cstyle & 3) 
  {
   case CBS_SIMPLE:            /* edit control, list always visible  */
     lboxrect=rect;    
     dprintf_combo(stddeb,"CBS_SIMPLE\n");
     style= WS_BORDER |  WS_CHILD | WS_VISIBLE | WS_VSCROLL;
     SetRectEmpty16(&lphc->RectButton);
     hwndp=hwnd;
     break;

   case CBS_DROPDOWNLIST:      /* static control, dropdown listbox   */
   case CBS_DROPDOWN:          /* edit control, dropdown listbox     */
     GetWindowRect16(hwnd,&lboxrect);
     style = WS_POPUP | WS_BORDER | WS_VSCROLL;
     /* FIXME: WinSight says these should be CHILD windows with the TOPMOST flag
      * set. Wine doesn't support TOPMOST, and simply setting the WS_CHILD
      * flag doesn't work. */
     lphc->RectButton = rect;
     lphc->RectButton.left = lphc->RectButton.right - 6 - CBitWidth;
     lphc->RectButton.bottom = lphc->RectButton.top + lphl->StdItemHeight;
     SetWindowPos32(hwnd, 0, 0, 0, rect.right -rect.left + 2*SYSMETRICS_CXBORDER,
		 lphl->StdItemHeight + 2*SYSMETRICS_CYBORDER,
		 SWP_NOMOVE | SWP_NOZORDER | SWP_NOSENDCHANGING | SWP_NOACTIVATE);
     dprintf_combo(stddeb,(cstyle & 3)==CBS_DROPDOWN ? "CBS_DROPDOWN\n": "CBS_DROPDOWNLIST\n");
     break;
     
   default: fprintf(stderr,"COMBOBOX error: bad class style!\n");
     return 0;
  }

  if ((cstyle & 3) != CBS_DROPDOWNLIST)
      lphc->hWndEdit = CreateWindow16( editName, NULL,
				  WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | ES_LEFT,
				  0, 0, rect.right-6-CBitWidth,
				  lphl->StdItemHeight+2*SYSMETRICS_CYBORDER,
				  hwnd, (HMENU16)ID_EDIT, WIN_GetWindowInstance(hwnd), NULL );
				  
  lboxrect.top+=lphc->LBoxTop;
  lphc->hWndLBox = CreateWindow16( className, NULL, style |
 				((cstyle & WS_HSCROLL)? WS_HSCROLL : 0) |
 				((cstyle & WS_VSCROLL)? WS_VSCROLL : 0),
				lboxrect.left, lboxrect.top,
				lboxrect.right - lboxrect.left, 
				lboxrect.bottom - lboxrect.top,
				hwndp,(HMENU16)ID_CLB, WIN_GetWindowInstance(hwnd),
				(LPVOID)(HWND32)hwnd );

   wndPtr->dwStyle &= ~(WS_VSCROLL | WS_HSCROLL);

   dprintf_combo( stddeb, "Combo Creation hwnd=%04x  LBox=%04x  Edit=%04x\n",
                  hwnd, lphc->hWndLBox, lphc->hWndEdit);
   dprintf_combo( stddeb, "  lbox %d,%d-%d,%d     button %d,%d-%d,%d\n",
                  lboxrect.left, lboxrect.top, lboxrect.right, lboxrect.bottom,
                  lphc->RectButton.left, lphc->RectButton.top,
                  lphc->RectButton.right, lphc->RectButton.bottom );
   dprintf_combo( stddeb, "   client %d,%d-%d,%d     window %d,%d-%d,%d\n",
                  wndPtr->rectClient.left, wndPtr->rectClient.top,
                  wndPtr->rectClient.right, wndPtr->rectClient.bottom,
                  wndPtr->rectWindow.left, wndPtr->rectWindow.top,
                  wndPtr->rectWindow.right, wndPtr->rectWindow.bottom );
   return 0;
}

/***********************************************************************
 *           CBDestroy
 */
static LRESULT CBDestroy(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);

  if (lphc->hWndEdit) DestroyWindow32( lphc->hWndEdit );
  if (lphc->hWndLBox) DestroyWindow32( lphc->hWndLBox );
  return 0;
}

/***********************************************************************
 *           CBPaint
 */
static LRESULT CBPaint(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
  LPLISTSTRUCT lpls;
  PAINTSTRUCT16  ps;
  HBRUSH32 hBrush;
  HFONT32 hOldFont;
  HDC16 hdc;
  RECT16 rect;
  
  hdc = BeginPaint16(hwnd, &ps);

  GetClientRect16(hwnd, &rect);
  CBCheckSize(hwnd);
  /* 1 for button border */
  rect.right = lphc->RectButton.left - 1;

  if (hComboBit != 0 && !IsRectEmpty16(&lphc->RectButton))
  {
    Rectangle32(hdc,lphc->RectButton.left-1,lphc->RectButton.top-1,
                lphc->RectButton.right+1,lphc->RectButton.bottom+1);
    {
        RECT32 r;
        CONV_RECT16TO32( &lphc->RectButton, &r );
        GRAPH_DrawReliefRect(hdc, &r, 2, 2, FALSE);
    }
    GRAPH_DrawBitmap(hdc, hComboBit,
		     lphc->RectButton.left + 2,lphc->RectButton.top + 2,
		     0, 0, CBitWidth, CBitHeight );
  }
  if (!IsWindowVisible16(hwnd) || !lphl->bRedrawFlag 
      || (lphc->dwStyle & 3) != CBS_DROPDOWNLIST) 
  {
    /* we don't want to draw an entry when there is an edit control */
    EndPaint16(hwnd, &ps);
    return 0;
  }

  hOldFont = SelectObject32(hdc, lphl->hFont);

  hBrush = SendMessage32A( lphl->hParent, WM_CTLCOLORLISTBOX, hdc, hwnd );
  if (hBrush == 0) hBrush = GetStockObject32(WHITE_BRUSH);

  lpls = ListBoxGetItem(lphl,lphl->ItemFocused);
  if (lpls != NULL) {  
    FillRect16(hdc, &rect, hBrush);
    ListBoxDrawItem (hwnd, lphl, hdc, lpls, &rect, ODA_DRAWENTIRE, 0);
    if (GetFocus32() == hwnd)
    ListBoxDrawItem (hwnd,lphl, hdc, lpls, &rect, ODA_FOCUS, ODS_FOCUS);
  }
  else FillRect16(hdc, &rect, hBrush);
  SelectObject32(hdc,hOldFont);
  EndPaint16(hwnd, &ps);
  return 0;
}

/***********************************************************************
 *           CBGetDlgCode
 */
static LRESULT CBGetDlgCode(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  return DLGC_WANTARROWS | DLGC_WANTCHARS;
}

/***********************************************************************
 *           CBLButtonDown
 */
static LRESULT CBLButtonDown(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
  SendMessage16(hwnd,CB_SHOWDROPDOWN16,!lphc->DropDownVisible,0);
  return 0;
}

/***********************************************************************
 *           CBKeyDown
 */
static LRESULT CBKeyDown(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  WORD       newFocused = lphl->ItemFocused;

  switch(wParam) {
  case VK_HOME:
    newFocused = 0;
    break;
  case VK_END:
    newFocused = lphl->ItemsCount - 1;
    break;
  case VK_UP:
    if (newFocused > 0) newFocused--;
    break;
  case VK_DOWN:
    newFocused++;
    break;
  default:
    return 0;
  }

  if (newFocused >= lphl->ItemsCount)
    newFocused = lphl->ItemsCount - 1;
  
  ListBoxSetCurSel(lphl, newFocused);
  SendMessage16(hwnd, WM_COMMAND,ID_CLB,MAKELONG(0,CBN_SELCHANGE));
  ListBoxSendNotification(lphl, CBN_SELCHANGE);

  lphl->ItemFocused = newFocused;
  ListBoxScrollToFocus(lphl);
/*  SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
  InvalidateRect32( hwnd, NULL, TRUE );

  return 0;
}

/***********************************************************************
 *           CBChar
 */
static LRESULT CBChar(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  WORD       newFocused;

  newFocused = ListBoxFindNextMatch(lphl, wParam);
  if (newFocused == (WORD)LB_ERR) return 0;

  if (newFocused >= lphl->ItemsCount)
    newFocused = lphl->ItemsCount - 1;
  
  ListBoxSetCurSel(lphl, newFocused);
  SendMessage16(hwnd, WM_COMMAND,ID_CLB,MAKELONG(0,CBN_SELCHANGE));
  ListBoxSendNotification(lphl, CBN_SELCHANGE);
  lphl->ItemFocused = newFocused;
  ListBoxScrollToFocus(lphl);
  
/*  SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
  InvalidateRect32( hwnd, NULL, TRUE );

  return 0;
}

/***********************************************************************
 *           CBKillFocus
 */
static LRESULT CBKillFocus(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  return 0;
}

/***********************************************************************
 *           CBSetFocus
 */
static LRESULT CBSetFocus(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  return 0;
}

/***********************************************************************
 *           CBResetContent
 */
static LRESULT CBResetContent(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);

  ListBoxResetContent(lphl);
  ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
  return 0;
}

/***********************************************************************
 *           CBDir
 */
static LRESULT CBDir(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  WORD wRet;
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);

  wRet = ListBoxDirectory(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
  ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
  return wRet;
}

/***********************************************************************
 *           CBInsertString
 */
static LRESULT CBInsertString(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  WORD  wRet;
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);

  if (lphl->HasStrings)
    wRet = ListBoxInsertString(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
  else
    wRet = ListBoxInsertString(lphl, wParam, (LPSTR)lParam);
  ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
  return wRet;
}
/***********************************************************************
 *           CBAddString
 */
static LRESULT CBAddString(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  WORD  wRet;
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);

  wRet = ListBoxAddString(lphl, (SEGPTR)lParam);

  ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
  return wRet;
}

/***********************************************************************
 *           CBDeleteString
 */
static LRESULT CBDeleteString(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
  LONG lRet = ListBoxDeleteString(lphl,wParam);
  
  ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
  return lRet;
}

/***********************************************************************
 *           CBSelectString
 */
static LRESULT CBSelectString(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  WORD  wRet;

  wRet = ListBoxFindString(lphl, wParam, (SEGPTR)lParam);

  /* XXX add functionality here */

  return 0;
}

/***********************************************************************
 *           CBFindString
 */
static LRESULT CBFindString(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  return ListBoxFindString(lphl, wParam, (SEGPTR)lParam);
}

/***********************************************************************
 *           CBFindStringExact
 */
static LRESULT CBFindStringExact(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  return ListBoxFindStringExact(lphl, wParam, (SEGPTR)lParam);
}

/***********************************************************************
 *           CBGetCount
 */
static LRESULT CBGetCount(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  return lphl->ItemsCount;
}
/***********************************************************************
 *           CBSetCurSel
 */
static LRESULT CBSetCurSel(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  WORD  wRet;

  wRet = ListBoxSetCurSel(lphl, wParam);

  dprintf_combo(stddeb,"CBSetCurSel: hwnd %04x wp %x lp %lx wRet %d\n",
		hwnd,wParam,lParam,wRet);
/*  SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
  InvalidateRect32( hwnd, NULL, TRUE );

  return wRet;
}

/***********************************************************************
 *           CBGetCurSel
 */
static LRESULT CBGetCurSel(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  return lphl->ItemFocused;
}

/***********************************************************************
 *           CBGetItemHeight
 */
static LRESULT CBGetItemHeight(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  LPLISTSTRUCT lpls = ListBoxGetItem (lphl, wParam);

  if (lpls == NULL) return LB_ERR;
  return lpls->mis.itemHeight;
}

/***********************************************************************
 *           CBSetItemHeight
 */
static LRESULT CBSetItemHeight(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  return ListBoxSetItemHeight(lphl, wParam, lParam);
}

/***********************************************************************
 *           CBSetRedraw
 */
static LRESULT CBSetRedraw(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  lphl->bRedrawFlag = wParam;
  return 0;
}

/***********************************************************************
 *           CBSetFont
 */
static LRESULT CBSetFont(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST  lphl = ComboGetListHeader(hwnd);
  LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
  
  if (wParam == 0)
    lphl->hFont = GetStockObject32(SYSTEM_FONT);
  else
    lphl->hFont = (HFONT16)wParam;
  if (lphc->hWndEdit)
     SendMessage16(lphc->hWndEdit,WM_SETFONT,lphl->hFont,0); 
  return 0;
}

/***********************************************************************
 *           CBGetLBTextLen
 */
static LRESULT CBGetLBTextLen(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST   lphl = ComboGetListHeader(hwnd);
  LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wParam);

  if (lpls == NULL || !lphl->HasStrings) return LB_ERR;
  return strlen(lpls->itemText);
}

/***********************************************************************
 *           CBGetLBText
 */
static LRESULT CBGetLBText(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  return ListBoxGetText(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
}

/***********************************************************************
 *           CBGetItemData
 */
static LRESULT CBGetItemData(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  return ListBoxGetItemData(lphl, wParam);
}

/***********************************************************************
 *           CBSetItemData
 */
static LRESULT CBSetItemData(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  return ListBoxSetItemData(lphl, wParam, lParam);
}

/***********************************************************************
 *           CBShowDropDown
 */
static LRESULT CBShowDropDown(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
  RECT32 rect;
  
  if ((lphc->dwStyle & 3) == CBS_SIMPLE) return LB_ERR;
  
  wParam = !!wParam;
  if (wParam != lphc->DropDownVisible) {
    lphc->DropDownVisible = wParam;
    GetWindowRect32(hwnd,&rect);
    SetWindowPos32(lphc->hWndLBox, 0, rect.left, rect.top+lphc->LBoxTop, 0, 0,
		 SWP_NOSIZE | SWP_NOACTIVATE |
                 (wParam ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
    if (!wParam) SetFocus32(hwnd);
  }
  return 0;
}


/***********************************************************************
 *             CBCheckSize
 */
static BOOL CBCheckSize(HWND16 hwnd)
{
  LPHEADCOMBO  lphc = ComboGetStorageHeader(hwnd);
  LPHEADLIST   lphl = ComboGetListHeader(hwnd);
  LONG         cstyle = GetWindowLong32A(hwnd,GWL_STYLE);
  RECT16       cRect, wRect;

  if (lphc->hWndLBox == 0) return FALSE;

  GetClientRect16(hwnd,&cRect);
  GetWindowRect16(hwnd,&wRect);

  dprintf_combo(stddeb,
	 "CBCheckSize: hwnd %04x Rect %d,%d-%d,%d  wRect %d,%d-%d,%d\n", 
		hwnd,cRect.left,cRect.top,cRect.right,cRect.bottom,
		wRect.left,wRect.top,wRect.right,wRect.bottom);
  if ((cstyle & 3) == CBS_SIMPLE) return TRUE;

  if ((cRect.bottom - cRect.top) >
      (lphl->StdItemHeight + 2*SYSMETRICS_CYBORDER)) {
    SetWindowPos32(hwnd, 0, 0, 0, 
		 cRect.right-cRect.left,
		 lphl->StdItemHeight+2*SYSMETRICS_CYBORDER, 
		 SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE );
    GetClientRect16(hwnd,&cRect);
    GetWindowRect16(hwnd,&wRect);

    lphc->RectButton.right = cRect.right;
    lphc->RectButton.left = cRect.right - 2*SYSMETRICS_CXBORDER - 4 
                            - CBitWidth;
    lphc->RectButton.top = cRect.top;
    lphc->RectButton.bottom = cRect.bottom;
  }

  if (cRect.right < lphc->RectButton.left) {
    /* if the button is outside the window move it in */
    if ((wRect.right - wRect.left - 2*SYSMETRICS_CXBORDER) == (cRect.right - cRect.left)) {
      lphc->RectButton.right = cRect.right;
      lphc->RectButton.left = cRect.right - 2*SYSMETRICS_CXBORDER - 4 
	                       - CBitWidth;
      lphc->RectButton.top = cRect.top;
      lphc->RectButton.bottom = cRect.bottom;
    }
    /* otherwise we need to make the client include the button */
    else
      SetWindowPos32(hwnd, 0, 0, 0, lphc->RectButton.right,
		   lphl->StdItemHeight+2*SYSMETRICS_CYBORDER,
		   SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE);

      if ((lphc->dwStyle & 3) != CBS_DROPDOWNLIST)
        SetWindowPos32(lphc->hWndEdit, 0, 0, 0, lphc->RectButton.left,
		     lphl->StdItemHeight,
		     SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
  }

  CBLCheckSize(hwnd);
  return TRUE;
}

/***********************************************************************
 *           CBCommand        
 */
static LRESULT CBCommand(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
  LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
  LPHEADLIST lphl = ComboGetListHeader(hwnd);
  char       buffer[256];
  WORD       newFocused;
  WORD       id;
  if (lphc->hWndEdit)  /* interdependence only used for CBS_SIMPLE and CBS_DROPDOWN styles */
  {
   switch (wParam)
   {
    case ID_CLB:                                        /* update EDIT window */
                if (HIWORD(lParam)==CBN_SELCHANGE)
                 if (lphl->HasStrings)
                 { 
                  ListBoxGetText(lphl,lphl->ItemFocused, buffer);
                  dprintf_combo(stddeb,"CBCommand: update Edit: %s\n",buffer);
                  SetWindowText32A( lphc->hWndEdit, buffer );
                 }
                break;
    case ID_EDIT:                                      /* update LISTBOX window */
                 id=GetWindowWord(hwnd,GWW_ID);
                 switch (HIWORD(lParam))
                 {
                  case EN_UPDATE:GetWindowText32A(lphc->hWndEdit,buffer,255);
                                 if (*buffer)
                                 {
                                  char *str = SEGPTR_STRDUP(buffer);
                                  newFocused=ListBoxFindString(lphl, -1, SEGPTR_GET(str));
                                  SEGPTR_FREE(str);
                                  dprintf_combo(stddeb,"CBCommand: new selection #%d is= %s\n",
                                                newFocused,buffer);
                                  if (newFocused != (WORD)LB_ERR)
                                  {                             /* if found something */
                                   ListBoxSetCurSel(lphl, newFocused);
                                   ListBoxSendNotification(lphl, CBN_SELCHANGE);
                                   InvalidateRect32(hwnd, NULL, TRUE); 
                                  }
                                 }
                                 SendMessage16(GetParent16(hwnd),WM_COMMAND,id,
                                         MAKELONG(hwnd, CBN_EDITUPDATE));
                                 break;
                  case EN_CHANGE:SendMessage16(GetParent16(hwnd),WM_COMMAND,id,
                                         MAKELONG(hwnd, CBN_EDITCHANGE));
                                 break;
                  case EN_ERRSPACE:SendMessage16(GetParent16(hwnd),WM_COMMAND,id,
                                         MAKELONG(hwnd, CBN_ERRSPACE));
                                 break;
                }
                break;        
   }
  } 
  return 0;
}


/***********************************************************************
 *           CBGetEditSel
 * Look out! Under Win32, the parameter packing is very different.
 */
static LRESULT CBGetEditSel(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
    LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);

    if ((lphc->dwStyle & 3) == CBS_DROPDOWNLIST)
      return CB_ERR;	/* err, documented for CBSetEditSel */
    return SendMessage16(lphc->hWndEdit, EM_GETSEL16, 0, 0);
}


/***********************************************************************
 *           CBSetEditSel
 * Look out! Under Win32, the parameter packing is very different.
 */
static LRESULT CBSetEditSel(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
    LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
    if ((lphc->dwStyle & 3) == CBS_DROPDOWNLIST)
      return CB_ERR;
    return SendMessage16(lphc->hWndEdit, EM_SETSEL16, 0, lParam);
}

/***********************************************************************
 *           CBGetText
 */
static LRESULT CBGetText(HWND16 hwnd, WPARAM16 wParam, LPARAM lParam)
{
    LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);

    return SendMessage16(lphc->hWndEdit, WM_GETTEXT, wParam, lParam);   
}

/***********************************************************************
 *           ComboWndProc
 */
LRESULT ComboBoxWndProc(HWND16 hwnd, UINT message, WPARAM16 wParam, LPARAM lParam)
{
    switch(message) {	
     case WM_NCCREATE: return CBNCCreate(hwnd, wParam, lParam);
     case WM_CREATE: return CBCreate(hwnd, wParam, lParam);
     case WM_DESTROY: return CBDestroy(hwnd, wParam, lParam);
     case WM_GETDLGCODE: return CBGetDlgCode(hwnd, wParam, lParam);
     case WM_KEYDOWN: return CBKeyDown(hwnd, wParam, lParam);
     case WM_CHAR: return CBChar(hwnd, wParam, lParam);
     case WM_SETFONT: return CBSetFont(hwnd, wParam, lParam);
     case WM_SETREDRAW: return CBSetRedraw(hwnd, wParam, lParam);
     case WM_PAINT: return CBPaint(hwnd, wParam, lParam);
     case WM_GETTEXT: return CBGetText( hwnd, wParam, lParam);
     case WM_LBUTTONDOWN: return CBLButtonDown(hwnd, wParam, lParam);
     case WM_SETFOCUS: return CBSetFocus(hwnd, wParam, lParam);
     case WM_KILLFOCUS: return CBKillFocus(hwnd, wParam, lParam);
     case WM_SIZE: return CBCheckSize(hwnd);
     case WM_COMMAND: return CBCommand(hwnd, wParam, lParam);
     case CB_RESETCONTENT16: return CBResetContent(hwnd, wParam, lParam);
     case CB_DIR16: return CBDir(hwnd, wParam, lParam);
     case CB_ADDSTRING16: return CBAddString(hwnd, wParam, lParam);
     case CB_INSERTSTRING16: return CBInsertString(hwnd, wParam, lParam);
     case CB_DELETESTRING16: return CBDeleteString(hwnd, wParam, lParam);
     case CB_FINDSTRING16: return CBFindString(hwnd, wParam, lParam);
     case CB_GETCOUNT16: return CBGetCount(hwnd, wParam, lParam);
     case CB_GETCURSEL16: return CBGetCurSel(hwnd, wParam, lParam);
     case CB_GETITEMDATA16: return CBGetItemData(hwnd, wParam, lParam);
     case CB_GETITEMHEIGHT16: return CBGetItemHeight(hwnd, wParam, lParam);
     case CB_GETLBTEXT16: return CBGetLBText(hwnd, wParam, lParam);
     case CB_GETLBTEXTLEN16: return CBGetLBTextLen(hwnd, wParam, lParam);
     case CB_SELECTSTRING16: return CBSelectString(hwnd, wParam, lParam);
     case CB_SETITEMDATA16: return CBSetItemData(hwnd, wParam, lParam);
     case CB_SETCURSEL16: return CBSetCurSel(hwnd, wParam, lParam);
     case CB_SETITEMHEIGHT16: return CBSetItemHeight(hwnd, wParam, lParam);
     case CB_SHOWDROPDOWN16: return CBShowDropDown(hwnd, wParam, lParam);
     case CB_GETEDITSEL16: return CBGetEditSel(hwnd, wParam, lParam);
     case CB_SETEDITSEL16: return CBSetEditSel(hwnd, wParam, lParam);
     case CB_FINDSTRINGEXACT16: return CBFindStringExact(hwnd, wParam, lParam);
    }
    return DefWindowProc16(hwnd, message, wParam, lParam);
}

/*--------------------------------------------------------------------*/
/* ComboLBox code starts here */

HWND16 CLBoxGetCombo(HWND16 hwnd)
{
  return (HWND16)GetWindowLong32A(hwnd,0);
}

LPHEADLIST CLBoxGetListHeader(HWND16 hwnd)
{
  return ComboGetListHeader(CLBoxGetCombo(hwnd));
}

/***********************************************************************
 *           CBLCreate
 */
static LRESULT CBLCreate( HWND16 hwnd, WPARAM16 wParam, LPARAM lParam )
{
  CREATESTRUCT16 *createStruct = (CREATESTRUCT16 *)PTR_SEG_TO_LIN(lParam);
  SetWindowLong32A(hwnd,0,(LONG)createStruct->lpCreateParams);
  return 0;
}

/***********************************************************************
 *           CBLGetDlgCode
 */
static LRESULT CBLGetDlgCode( HWND16 hwnd, WPARAM16 wParam, LPARAM lParam )
{
  return DLGC_WANTARROWS | DLGC_WANTCHARS;
}

/***********************************************************************
 *           CBLKeyDown
 */
static LRESULT CBLKeyDown( HWND16 hwnd, WPARAM16 wParam, LPARAM lParam ) 
{
  LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
  WORD newFocused = lphl->ItemFocused;

  switch(wParam) {
  case VK_HOME:
    newFocused = 0;
    break;
  case VK_END:
    newFocused = lphl->ItemsCount - 1;
    break;
  case VK_UP:
    if (newFocused > 0) newFocused--;
    break;
  case VK_DOWN:
    newFocused++;
    break;
  case VK_PRIOR:
    if (newFocused > lphl->ItemsVisible) {
      newFocused -= lphl->ItemsVisible;
    } else {
      newFocused = 0;
    }
    break;
  case VK_NEXT:
    newFocused += lphl->ItemsVisible;
    break;
  default:
    return 0;
  }

  if (newFocused >= lphl->ItemsCount)
    newFocused = lphl->ItemsCount - 1;
  
  ListBoxSetCurSel(lphl, newFocused);
  ListBoxSendNotification(lphl, CBN_SELCHANGE);
  SendMessage16(GetParent16(hwnd), WM_COMMAND,ID_CLB,MAKELONG(0,CBN_SELCHANGE));
  lphl->ItemFocused = newFocused;
  ListBoxScrollToFocus(lphl);
  SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
  InvalidateRect32( hwnd, NULL, TRUE );
  return 0;
}

/***********************************************************************
 *           CBLChar
 */
static LRESULT CBLChar( HWND16 hwnd, WPARAM16 wParam, LPARAM lParam )
{
  return 0;
}

/***********************************************************************
 *           CBLPaint
 */
static LRESULT CBLPaint( HWND16 hwnd, WPARAM16 wParam, LPARAM lParam )
{
  LPHEADLIST   lphl = CLBoxGetListHeader(hwnd);
  LPLISTSTRUCT lpls;
  PAINTSTRUCT16  ps;
  HBRUSH32 hBrush;
  HFONT32 hOldFont;
  WND * wndPtr = WIN_FindWndPtr(hwnd);
  HWND16  combohwnd = CLBoxGetCombo(hwnd);
  HDC16 hdc;
  RECT16 rect;
  int   i, top, height;

  top = 0;
  if (!lphl)
    return 0;
  hdc = BeginPaint16( hwnd, &ps );

  if (!lphl) {
    fprintf(stdnimp,"CBLPaint: CLBoxGetListHeader returned NULL!\n");
  }
  if (!IsWindowVisible16(hwnd) || !lphl || !lphl->bRedrawFlag) {
    EndPaint16(hwnd, &ps);
    return 0;
  }

  hOldFont = SelectObject32(hdc, lphl->hFont);
  /* listboxes should be white */
  hBrush = GetStockObject32(WHITE_BRUSH);

  GetClientRect16(hwnd, &rect);
  FillRect16(hdc, &rect, hBrush);
  CBLCheckSize(hwnd);

  lpls = lphl->lpFirst;

  lphl->ItemsVisible = 0;
  for(i = 0; i < lphl->ItemsCount; i++) {
    if (lpls == NULL) break;

    if (i >= lphl->FirstVisible) {
      height = lpls->mis.itemHeight;
      /* must have enough room to draw entire item */
      if (top > (rect.bottom-height+1)) break;

      lpls->itemRect.top    = top;
      lpls->itemRect.bottom = top + height;
      lpls->itemRect.left   = rect.left;
      lpls->itemRect.right  = rect.right;

      dprintf_listbox(stddeb,"drawing item: %d %d %d %d %d\n",
                      rect.left,top,rect.right,top+height,lpls->itemState);
      if (lphl->OwnerDrawn) {
	ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE, 0);
	if (lpls->itemState)
	  ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_SELECT, ODS_SELECTED);
      } else {
	ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE, 
			 lpls->itemState);
      }
      if ((lphl->ItemFocused == i) && GetFocus32() == hwnd)
	ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS, ODS_FOCUS);

      top += height;
      lphl->ItemsVisible++;
    }

    lpls = lpls->lpNext;
  }

  if (wndPtr->dwStyle & WS_VSCROLL) 
      SetScrollRange32(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);

  SelectObject32(hdc,hOldFont);
  EndPaint16( hwnd, &ps );
  return 0;

}

/***********************************************************************
 *           CBLKillFocus
 */
static LRESULT CBLKillFocus( HWND16 hwnd, WPARAM16 wParam, LPARAM lParam )
{
/*  SendMessage16(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN16,0,0);*/
  return 0;
}

/***********************************************************************
 *           CBLActivate
 */
static LRESULT CBLActivate( HWND16 hwnd, WPARAM16 wParam, LPARAM lParam )
{
  if (wParam == WA_INACTIVE)
    SendMessage16(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN16,0,0);
  return 0;
}

/***********************************************************************
 *           CBLLButtonDown
 */
static LRESULT CBLLButtonDown( HWND16 hwnd, WPARAM16 wParam, LPARAM lParam )
{
  LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
  int        y;
  RECT16     rectsel;

/*  SetFocus32(hwnd); */
  SetCapture32(hwnd);

  lphl->PrevFocused = lphl->ItemFocused;

  y = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
  if (y == -1)
    return 0;

  ListBoxSetCurSel(lphl, y);
  ListBoxGetItemRect(lphl, y, &rectsel);

  InvalidateRect32( hwnd, NULL, TRUE );
  return 0;
}

/***********************************************************************
 *           CBLLButtonUp
 */
static LRESULT CBLLButtonUp( HWND16 hwnd, WPARAM16 wParam, LPARAM lParam )
{
  LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
  if (GetCapture32() == hwnd) ReleaseCapture();

  if(!lphl)
     {
      fprintf(stdnimp,"CBLLButtonUp: CLBoxGetListHeader returned NULL!\n");
     }
  else if (lphl->PrevFocused != lphl->ItemFocused) 
          {
      		SendMessage16(CLBoxGetCombo(hwnd),CB_SETCURSEL16,lphl->ItemFocused,0);
      		SendMessage16(GetParent16(hwnd), WM_COMMAND,ID_CLB,MAKELONG(0,CBN_SELCHANGE));
      		ListBoxSendNotification(lphl, CBN_SELCHANGE);
     	  }

  SendMessage16(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN16,0,0);

  return 0;
}

/***********************************************************************
 *           CBLMouseMove
 */
static LRESULT CBLMouseMove( HWND16 hwnd, WPARAM16 wParam, LPARAM lParam )
{
  LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
  short y;
  WORD wRet;
  RECT16 rect, rectsel;

  y = SHIWORD(lParam);
  wRet = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
  ListBoxGetItemRect(lphl, wRet, &rectsel);
  GetClientRect16(hwnd, &rect);

  dprintf_combo(stddeb,"CBLMouseMove: hwnd %04x wp %x lp %lx  y %d  if %d wret %d %d,%d-%d,%d\n",
hwnd,wParam,lParam,y,lphl->ItemFocused,wRet,rectsel.left,rectsel.top,rectsel.right,rectsel.bottom);
  
  if ((wParam & MK_LBUTTON) != 0) {
    if (y < CBLMM_EDGE) {
      if (lphl->FirstVisible > 0) {
	lphl->FirstVisible--;
	SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
	ListBoxSetCurSel(lphl, wRet);
	InvalidateRect32( hwnd, NULL, TRUE );
	return 0;
      }
    }
    else if (y >= (rect.bottom-CBLMM_EDGE)) {
      if (lphl->FirstVisible < ListMaxFirstVisible(lphl)) {
	lphl->FirstVisible++;
	SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
	ListBoxSetCurSel(lphl, wRet);
	InvalidateRect32( hwnd, NULL, TRUE );
	return 0;
      }
    }
    else {
      if ((short) wRet == lphl->ItemFocused) return 0;
      ListBoxSetCurSel(lphl, wRet);
      InvalidateRect32( hwnd, NULL, TRUE );
    }
  }

  return 0;
}

/***********************************************************************
 *           CBLVScroll
 */
static LRESULT CBLVScroll( HWND16 hwnd, WPARAM16 wParam, LPARAM lParam )
{
  LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
  int  y;

  y = lphl->FirstVisible;

  switch(wParam) {
  case SB_LINEUP:
    if (lphl->FirstVisible > 0)
      lphl->FirstVisible--;
    break;

  case SB_LINEDOWN:
    lphl->FirstVisible++;
    break;

  case SB_PAGEUP:
    if (lphl->FirstVisible > lphl->ItemsVisible) {
      lphl->FirstVisible -= lphl->ItemsVisible;
    } else {
      lphl->FirstVisible = 0;
    }
    break;

  case SB_PAGEDOWN:
    lphl->FirstVisible += lphl->ItemsVisible;
    break;

  case SB_THUMBTRACK:
    lphl->FirstVisible = LOWORD(lParam);
    break;
  }

  if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
    lphl->FirstVisible = ListMaxFirstVisible(lphl);

  if (y != lphl->FirstVisible) {
    SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
    InvalidateRect32( hwnd, NULL, TRUE );
  }

  return 0;
}


/***********************************************************************
 *             CBLCheckSize
 */
static BOOL CBLCheckSize(HWND16 hwnd)
{
  LPHEADCOMBO  lphc = ComboGetStorageHeader(hwnd);
  LPHEADLIST   lphl = ComboGetListHeader(hwnd);
  LPLISTSTRUCT lpls;
  HWND16         hWndLBox;
  RECT16 cRect,wRect,lRect,lwRect;
  int totheight,dw;
  char className[80];

  GetClassName32A(hwnd,className,80);
  fflush(stddeb);
  if (strncmp(className,"COMBOBOX",8)) return FALSE;
  if ((hWndLBox = lphc->hWndLBox) == 0) return FALSE;
  dprintf_combo(stddeb,"CBLCheckSize headers hw %04x  lb %04x  name %s\n",
		hwnd,hWndLBox,className);

  GetClientRect16(hwnd,&cRect);
  GetWindowRect16(hwnd,&wRect);
  GetClientRect16(hWndLBox,&lRect);
  GetWindowRect16(hWndLBox,&lwRect);

  dprintf_combo(stddeb,"CBLCheckSize: init cRect %d,%d-%d,%d  wRect %d,%d-%d,%d\n",
		cRect.left,cRect.top,cRect.right,cRect.bottom,
		wRect.left,wRect.top,wRect.right,wRect.bottom);
  dprintf_combo(stddeb,"                   lRect %d,%d-%d,%d  lwRect %d,%d-%d,%d\n",
	      lRect.left,lRect.top,lRect.right,lRect.bottom,
	      lwRect.left,lwRect.top,lwRect.right,lwRect.bottom);
  fflush(stddeb);
  
  totheight = 0;
  for (lpls=lphl->lpFirst; lpls != NULL; lpls=lpls->lpNext)
    totheight += lpls->mis.itemHeight;

  dw = cRect.right-cRect.left+2*SYSMETRICS_CXBORDER+SYSMETRICS_CXVSCROLL;
  dw -= lwRect.right-lwRect.left;
  dw -= SYSMETRICS_CXVSCROLL;

  /* TODO: This isn't really what windows does */
  if ((lRect.bottom-lRect.top < 3*lphl->StdItemHeight) || dw) {
    dprintf_combo(stddeb,"    Changing; totHeight %d  StdItemHght %d  dw %d\n",
		  totheight,lphl->StdItemHeight,dw);
    SetWindowPos32(hWndLBox, 0, lRect.left, lRect.top, 
		 lwRect.right-lwRect.left+dw, totheight+2*SYSMETRICS_CYBORDER, 
		 SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE );
  }
  return TRUE;
}


/***********************************************************************
 *           ComboLBoxWndProc
 */
LRESULT ComboLBoxWndProc(HWND16 hwnd, UINT message, WPARAM16 wParam, LPARAM lParam)
{
    switch(message) {	
     case WM_CREATE: return CBLCreate(hwnd, wParam, lParam);
     case WM_GETDLGCODE: return CBLGetDlgCode(hwnd, wParam, lParam);
     case WM_KEYDOWN: return CBLKeyDown(hwnd, wParam, lParam);
     case WM_CHAR: return CBLChar(hwnd, wParam, lParam);
     case WM_PAINT: return CBLPaint(hwnd, wParam, lParam);
     case WM_KILLFOCUS: return CBLKillFocus(hwnd, wParam, lParam);
     case WM_ACTIVATE: return CBLActivate(hwnd, wParam, lParam);
     case WM_LBUTTONDOWN: return CBLLButtonDown(hwnd, wParam, lParam);
     case WM_LBUTTONUP: return CBLLButtonUp(hwnd, wParam, lParam);
     case WM_MOUSEMOVE: return CBLMouseMove(hwnd, wParam, lParam);
     case WM_VSCROLL: return CBLVScroll(hwnd, wParam, lParam);
     case WM_SIZE: return CBLCheckSize(hwnd);
     case WM_MOUSEACTIVATE:  /* We don't want to be activated */
	return MA_NOACTIVATE;
    }
    return DefWindowProc16(hwnd, message, wParam, lParam);
}