Release 960728
Sun Jul 28 17:57:19 1996 Alexandre Julliard <julliard@lrc.epfl.ch>
* [loader/task.c] [include/task.h]
Implemented SwitchStackTo()/SwitchStackBack().
* [include/wintypes.h] [loader/main.c]
Added __winelib variable to distinguish between emulator and
library at run-time. Later on, this should avoid some
recompilations when building Winelib.
* [windows/property.c]
Implemented Win32 functions for window properties.
Fri Jul 26 18:00:00 1996 Alex Korobka <alex@phm30.pharm.sunysb.edu>
* [controls/listbox.c]
Implemented LBS_SORT style, WM_COMPAREITEM, and WM_DELETEITEM
messages.
* [controls/menu.c]
Call TranslateMessage() to enable shortcuts (on WM_CHAR).
* [include/cursoricon.h]
Moved #pragma pack(1) back to where it belongs.
* [objects/palette.c]
RealizeDefaultPalette() maps to system colors only.
Do not broadcast palette notifications when in TrueColor.
* [objects/color.c] [include/palette.h]
Miscellaneous optimizations. Had to fix several
"improvements" made to my patch for previous release.
* [objects/dib.c]
Reverse dib bits order for 24-bit SetDIBits().
* [objects/dc.c]
GetDeviceCaps() does not return RC_PALETTE when in TrueColor.
* [windows/scroll.c]
Scroll update region too.
* [windows/message.c]
Include QS_MOUSE into the event mask for nonclient mouse
message filter. Fixes problems with Word 6 freezing when
mouse hits nonclient area.
* [windows/win.c]
Allow top-level windows to be linked as HWND_TOP in CreateWindow().
* [windows/winpos.c] [windows/mdi.c]
Attempt to fix control menu duplication.
Fri Jul 26 09:49:35 1996 Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>
* [files/drive.c]
GetDriveType32A(): return value for CDROM fixed.
* [files/file.c]
SearchPath* added.
* [if1632/gdi32.spec] [objects/brush.c]
SetBrushOrgEx() added.
* [loader/pe_resource.c]
If even loading the default entry fails, we just use the first
entry from the resource directory.
[loader/task.c]
SetSigHandler() stub added, Paradox 4.5 now starts up.
* [misc/comm.c] [include/windows.h] [if1632/kernel32.spec]
COMM functions updated to win32, not complete.
* [misc/lstr.c]
FormatMessageA partially implemented.
* [include/miscemu.h] [memory/selector.c]
[memory/global.c] [miscemu/dosmem.c]
DOS memory handling changed: 1MB preallocated block, real-mode
segment handling possible, SetSelectorBase into lower physical 1MB
possible.
* [miscemu/dpmi.c]
Real-mode segments changed, real-mode int 21,ax=6506 added.
AX=0x0303 added.
* [multimedia/time.c]
Fixed bug in killTimer.
* [objects/bitmap.c]
LoadImageA partially implemented.
Wed Jul 24 18:20:24 1996 Albrecht Kleine <kleine@ak.sax.de>
* [include/dde_mem.h][include/dde_proc.h]
[ipc/dde_atom.c][ipc/dde_proc.c][windows/message.c]
[ipc/generic_hash.h][library/miscstubs.c]
Changes for error free compilation using "--with-ipc":
replaced some names with *16-equivalent (e.g. MSG to MSG16),
modified prototype of function DDE_GlobalFree() .
* [objects/palette.c]
Added check for metafile-DC in GDISelectPalette(),
GDIRealizePalette(),RealizeDefaultPalette() and
IsDCCurrentPalette().
Tue Jul 23 22:46:53 1996 Andrew Lewycky <plewycky@oise.utoronto.ca>
* [controls/edit.c]
EDIT_WM_Create: Don't EDIT_EM_ReplaceSel if created with lParam = "",
fixes Winhelp.
* [windows/dialog.c]
DIALOG_CreateIndirect: Initialise dlgProc before creating children.
diff --git a/controls/listbox.c b/controls/listbox.c
index b3a5b8d..1cbb28c 100644
--- a/controls/listbox.c
+++ b/controls/listbox.c
@@ -3,15 +3,17 @@
*
* Copyright Martin Ayotte, 1993
* Constantine Sapuntzakis, 1995
- * Alex Korobka, 1995
+ * Alex Korobka, 1995, 1996
*
*/
/*
* FIXME:
- * - check if multi-column listboxes work
- * - implement more messages and styles
- * - implement caret for LBS_EXTENDEDSEL
+ * - proper scrolling for multicolumn style
+ * - anchor and caret for LBS_EXTENDEDSEL
+ * - proper selection with keyboard
+ * - how to handle (LBS_EXTENDEDSEL | LBS_MULTIPLESEL) style
+ * - support for LBS_NOINTEGRALHEIGHT and LBS_OWNERDRAWVARIABLE styles
*/
#include <stdio.h>
@@ -27,6 +29,7 @@
#include "drive.h"
#include "file.h"
#include "heap.h"
+#include "stackframe.h"
#include "stddebug.h"
#include "debug.h"
#include "xmalloc.h"
@@ -43,6 +46,10 @@
#define LBMM_EDGE 4 /* distance inside box which is same as moving mouse
outside box, to trigger scrolling of LB */
+#define MATCH_SUBSTR 2
+#define MATCH_EXACT 1
+#define MATCH_NEAREST 0
+
static void ListBoxInitialize(LPHEADLIST lphl)
{
lphl->lpFirst = NULL;
@@ -267,6 +274,21 @@
return LB_ERR;
}
+BOOL lbDeleteItemNotify(LPHEADLIST lphl, LPLISTSTRUCT lpls)
+{
+ /* called only for owner drawn listboxes */
+
+ DELETEITEMSTRUCT16 delItem;
+
+ delItem.CtlType = lphl->DrawCtlType;
+ delItem.CtlID = lphl->CtlID;
+ delItem.itemID = lpls->mis.itemID;
+ delItem.hwndItem= lphl->hSelf;
+ delItem.itemData= lpls->mis.itemData;
+
+ return (BOOL) SendMessage16(lphl->hParent, WM_DELETEITEM, (WPARAM)lphl->CtlID,
+ (LPARAM)MAKE_SEGPTR(&delItem));
+}
void ListBoxAskMeasure(LPHEADLIST lphl, LPLISTSTRUCT lpls)
{
@@ -306,7 +328,97 @@
return lplsnew;
}
+int ListBoxAskCompare(LPHEADLIST lphl, int startItem, SEGPTR matchData, BOOL exactMatch )
+{
+ /* Do binary search for sorted listboxes. Linked list item storage sort of
+ * defeats the purpose ( forces to traverse item list all the time ) but M$ does it this way...
+ *
+ * MATCH_NEAREST (0) - return position for insertion - for all styles
+ * MATCH_EXACT (1) - search for an item, return index or LB_ERR
+ * MATCH_SUBSTR (2) - same as exact match but with strncmp for string comparision
+ */
+ COMPAREITEMSTRUCT16 itemCmp;
+ LPLISTSTRUCT currentItem = NULL;
+ LPCSTR matchStr = (lphl->HasStrings)?(LPCSTR)PTR_SEG_TO_LIN(matchData):NULL;
+ int head, pos = -1, tail, loop = 1;
+ short b = 0, s_length = 0;
+
+ /* check if empty */
+
+ if( !lphl->ItemsCount )
+ return (exactMatch)? LB_ERR: 0;
+
+ /* set up variables */
+
+ if( exactMatch == MATCH_NEAREST )
+ startItem = 0;
+ else if( ++startItem )
+ {
+ loop = 2;
+ if( startItem >= lphl->ItemsCount ) startItem = lphl->ItemsCount - 1;
+ }
+
+ if( exactMatch == MATCH_SUBSTR && lphl->HasStrings )
+ {
+ s_length = strlen( matchStr );
+ if( !s_length ) return 0; /* head of the list - empty string */
+ }
+
+ head = startItem; tail = lphl->ItemsCount - 1;
+
+ dprintf_listbox(stddeb,"AskCompare: head = %i, tail = %i, data = %08x\n", head, tail, (unsigned)matchData );
+
+ itemCmp.CtlType = lphl->DrawCtlType;
+ itemCmp.CtlID = lphl->CtlID;
+ itemCmp.hwndItem = lphl->hSelf;
+
+ /* search from startItem */
+
+ while ( loop-- )
+ {
+ while( head <= tail )
+ {
+ pos = (tail + head)/2;
+ currentItem = ListBoxGetItem( lphl, pos );
+
+ if( lphl->HasStrings )
+ {
+ b = ( s_length )? strncasecmp( currentItem->itemText, matchStr, s_length)
+ : strcasecmp( currentItem->itemText, matchStr);
+ }
+ else
+ {
+ itemCmp.itemID1 = pos;
+ itemCmp.itemData1 = currentItem->mis.itemData;
+ itemCmp.itemID2 = -1;
+ itemCmp.itemData2 = matchData;
+
+ b = SendMessage16( lphl->hParent, WM_COMPAREITEM, (WPARAM)lphl->CtlID,
+ (LPARAM)MAKE_SEGPTR(&itemCmp) );
+ }
+
+ if( b == 0 )
+ return pos; /* found exact match */
+ else
+ if( b < 0 ) head = ++pos;
+ else
+ if( b > 0 ) tail = pos - 1;
+ }
+
+ /* reset to search from the first item */
+ head = 0; tail = startItem - 1;
+ }
+
+ dprintf_listbox(stddeb,"\t-> pos = %i\n", pos );
+
+ /* if we got here match is not exact */
+
+ if( pos < 0 ) pos = 0;
+ else if( pos > lphl->ItemsCount ) pos = lphl->ItemsCount;
+
+ return (exactMatch)? LB_ERR: pos;
+}
int ListBoxInsertString(LPHEADLIST lphl, UINT uIndex, LPCSTR newstr)
{
@@ -371,16 +483,14 @@
}
-int ListBoxAddString(LPHEADLIST lphl, LPCSTR newstr)
+int ListBoxAddString(LPHEADLIST lphl, SEGPTR itemData)
{
- UINT pos = (UINT) -1;
-
- if (lphl->HasStrings && (lphl->dwStyle & LBS_SORT)) {
- LPLISTSTRUCT lpls = lphl->lpFirst;
- for (pos = 0; lpls != NULL; lpls = lpls->lpNext, pos++)
- if (strcmp(lpls->itemText, newstr) >= 0)
- break;
- }
+ UINT pos = (UINT) -1;
+ LPCSTR newstr = (lphl->HasStrings)?(LPCSTR)PTR_SEG_TO_LIN(itemData):(LPCSTR)itemData;
+
+ if ( lphl->dwStyle & LBS_SORT )
+ pos = ListBoxAskCompare( lphl, -1, itemData, MATCH_NEAREST );
+
return ListBoxInsertString(lphl, pos, newstr);
}
@@ -438,8 +548,13 @@
if (lpls == NULL) return LB_ERR;
if (uIndex == 0)
+ {
+ if( lphl->OwnerDrawn )
+ lbDeleteItemNotify( lphl, lpls);
lphl->lpFirst = lpls->lpNext;
- else {
+ }
+ else
+ {
LPLISTSTRUCT lpls2 = NULL;
for(Count = 0; Count < uIndex; Count++) {
if (lpls->lpNext == NULL) return LB_ERR;
@@ -447,6 +562,8 @@
lpls2 = lpls;
lpls = (LPLISTSTRUCT)lpls->lpNext;
}
+ if( lphl->OwnerDrawn )
+ lbDeleteItemNotify( lphl, lpls);
lpls2->lpNext = lpls->lpNext;
}
@@ -463,28 +580,43 @@
return lphl->ItemsCount;
}
-
-int ListBoxFindString(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr)
+int lbFindString(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr, BOOL match)
{
+ /* match is either MATCH_SUBSTR or MATCH_EXACT */
+
LPLISTSTRUCT lpls;
UINT Count;
- UINT First = nFirst + 1;
+ UINT First = nFirst + 1;
+ int s_length = 0;
LPSTR lpMatchStr = (LPSTR)MatchStr;
if (First > lphl->ItemsCount) return LB_ERR;
- if (lphl->HasStrings) lpMatchStr = PTR_SEG_TO_LIN(MatchStr);
-
+ if (lphl->dwStyle & LBS_SORT )
+ return ListBoxAskCompare( lphl, nFirst, MatchStr, match );
+
+ if (lphl->HasStrings )
+ {
+ lpMatchStr = PTR_SEG_TO_LIN(MatchStr);
+
+ if( match == MATCH_SUBSTR )
+ {
+ s_length = strlen(lpMatchStr);
+ if( !s_length ) return (lphl->ItemsCount)?0:LB_ERR;
+ }
+ }
+
lpls = ListBoxGetItem(lphl, First);
Count = 0;
- while(lpls != NULL) {
- if (lphl->HasStrings) {
- if (strstr(lpls->itemText, lpMatchStr) == lpls->itemText) return Count;
- } else if (lphl->dwStyle & LBS_SORT) {
- /* XXX Do a compare item */
+ while(lpls != NULL)
+ {
+ if (lphl->HasStrings)
+ {
+ if ( ( s_length )? !strncasecmp(lpls->itemText, lpMatchStr, s_length)
+ : !strcasecmp(lpls->itemText, lpMatchStr) ) return Count;
}
else
- if (lpls->mis.itemData == (DWORD)lpMatchStr) return Count;
+ if ( lpls->mis.itemData == (DWORD)lpMatchStr ) return Count;
lpls = lpls->lpNext;
Count++;
@@ -494,14 +626,16 @@
Count = 0;
lpls = lphl->lpFirst;
- while (Count < First) {
- if (lphl->HasStrings) {
- if (strstr(lpls->itemText, lpMatchStr) == lpls->itemText) return Count;
- } else if (lphl->dwStyle & LBS_SORT) {
- /* XXX Do a compare item */
- } else {
- if (lpls->mis.itemData == (DWORD)lpMatchStr) return Count;
+ while (Count < First)
+ {
+ if (lphl->HasStrings)
+ {
+ if ( ( s_length )? !strncasecmp(lpls->itemText, lpMatchStr, s_length)
+ : !strcasecmp(lpls->itemText, lpMatchStr) ) return Count;
}
+ else
+ if ( lpls->mis.itemData == (DWORD)lpMatchStr ) return Count;
+
lpls = lpls->lpNext;
Count++;
}
@@ -509,6 +643,15 @@
return LB_ERR;
}
+int ListBoxFindString(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr)
+{
+ return lbFindString(lphl, nFirst, MatchStr, MATCH_SUBSTR );
+}
+
+int ListBoxFindStringExact(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr)
+{
+ return lbFindString(lphl, nFirst, MatchStr, MATCH_EXACT );
+}
int ListBoxResetContent(LPHEADLIST lphl)
{
@@ -523,7 +666,9 @@
for(i = 0; i < lphl->ItemsCount; i++) {
lpls = lphl->lpFirst;
if (lpls == NULL) return LB_ERR;
-
+
+ if (lphl->OwnerDrawn) lbDeleteItemNotify(lphl, lpls);
+
lphl->lpFirst = lpls->lpNext;
if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData);
free(lpls);
@@ -603,12 +748,13 @@
LONG ListBoxDirectory(LPHEADLIST lphl, UINT attrib, LPCSTR filespec)
{
- char temp[16], mask[13];
+ char mask[13];
+ char* temp = NULL;
+ const char* ptr;
+ int skip, count;
+ LONG ret;
+ DOS_DIRENT entry;
char *path, *p;
- const char *ptr;
- int skip, count;
- LONG ret;
- DOS_DIRENT entry;
dprintf_listbox(stddeb, "ListBoxDirectory: '%s' %04x\n", filespec, attrib);
if (!filespec) return LB_ERR;
@@ -616,11 +762,13 @@
path = xstrdup(ptr);
p = strrchr( path, '/' );
*p++ = '\0';
- if (!(ptr = DOSFS_ToDosFCBFormat( p )))
+ if (!(ptr = DOSFS_ToDosFCBFormat( p )) ||
+ !(temp = SEGPTR_ALLOC( sizeof(char) * 16 )) )
{
free( path );
return LB_ERR;
}
+
strcpy( mask, ptr );
dprintf_listbox(stddeb, "ListBoxDirectory: path=%s mask=%s\n", path, mask);
@@ -636,7 +784,7 @@
{
sprintf(temp, "[%s]", DOSFS_ToDosDTAFormat( entry.name ) );
AnsiLower( temp );
- if ((ret = ListBoxAddString(lphl, temp)) == LB_ERR) break;
+ if ((ret = ListBoxAddString(lphl, SEGPTR_GET(temp))) == LB_ERR) break;
}
}
else /* not a directory */
@@ -647,9 +795,11 @@
{
strcpy( temp, DOSFS_ToDosDTAFormat( entry.name ) );
AnsiLower( temp );
- if ((ret = ListBoxAddString(lphl, temp)) == LB_ERR) break;
+ if ((ret = ListBoxAddString(lphl, SEGPTR_GET(temp))) == LB_ERR) break;
}
}
+
+ dprintf_listbox(stddeb,"\tn - %i, file '%s'\n", count, temp);
}
if (attrib & DDL_DRIVES)
{
@@ -658,10 +808,13 @@
for (x = 0; x < MAX_DOS_DRIVES; x++, temp[2]++)
{
if (DRIVE_IsValid(x))
- if ((ret = ListBoxAddString(lphl, temp)) == LB_ERR) break;
+ if ((ret = ListBoxAddString(lphl, SEGPTR_GET(temp))) == LB_ERR) break;
}
}
+
free( path );
+ SEGPTR_FREE( temp );
+
return ret;
}
@@ -1432,10 +1585,7 @@
WORD wRet;
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
- if (lphl->HasStrings)
- wRet = ListBoxAddString(lphl, (LPCSTR)PTR_SEG_TO_LIN(lParam));
- else
- wRet = ListBoxAddString(lphl, (LPCSTR)lParam);
+ wRet = ListBoxAddString(lphl, (SEGPTR)lParam);
ListBoxUpdateWindow(hwnd,lphl,TRUE);
return wRet;
@@ -1490,7 +1640,16 @@
static LONG LBFindString(HWND hwnd, WORD wParam, LONG lParam)
{
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
- return ListBoxFindString(lphl, wParam, (SEGPTR)lParam);
+ return lbFindString(lphl, wParam, (SEGPTR)lParam, MATCH_SUBSTR);
+}
+
+/***********************************************************************
+ * LBFindStringExact
+ */
+static LONG LBFindStringExact(HWND hwnd, WORD wParam, LONG lParam)
+{
+ LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
+ return lbFindString(lphl, wParam, (SEGPTR)lParam, MATCH_EXACT);
}
/***********************************************************************
@@ -1661,7 +1820,7 @@
LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
INT iRet;
- iRet = ListBoxFindString(lphl, wParam, (SEGPTR)lParam);
+ iRet = lbFindString(lphl, wParam, (SEGPTR)lParam, MATCH_SUBSTR);
if( iRet != LB_ERR)
{
@@ -1920,6 +2079,7 @@
case LB_INSERTSTRING: return LBInsertString(hwnd, wParam, lParam);
case LB_DELETESTRING: return LBDeleteString(hwnd, wParam, lParam);
case LB_FINDSTRING: return LBFindString(hwnd, wParam, lParam);
+ case LB_FINDSTRINGEXACT: return LBFindStringExact(hwnd, wParam, lParam);
case LB_GETCARETINDEX: return LBGetCaretIndex(hwnd, wParam, lParam);
case LB_GETCOUNT: return LBGetCount(hwnd, wParam, lParam);
case LB_GETCURSEL: return LBGetCurSel(hwnd, wParam, lParam);