winehq.org
Sign In
Sign Up
Sign In
Sign Up
Manage this list
×
Keyboard Shortcuts
Thread View
j
: Next unread message
k
: Previous unread message
j a
: Jump to all threads
j l
: Jump to MailingList overview
2025
April
March
February
January
2024
December
November
October
September
August
July
June
May
April
March
February
January
2023
December
November
October
September
August
July
June
May
April
March
February
January
2022
December
November
October
September
August
July
June
May
April
March
February
January
2021
December
November
October
September
August
July
June
May
April
March
February
January
2020
December
November
October
September
August
July
June
May
April
March
February
January
2019
December
November
October
September
August
July
June
May
April
March
February
January
2018
December
November
October
September
August
July
June
May
April
March
February
January
2017
December
November
October
September
August
July
June
May
April
March
February
January
2016
December
November
October
September
August
July
June
May
April
March
February
January
2015
December
November
October
September
August
July
June
May
April
March
February
January
2014
December
November
October
September
August
July
June
May
April
March
February
January
2013
December
November
October
September
August
July
June
May
April
March
February
January
2012
December
November
October
September
August
July
June
May
April
March
February
January
2011
December
November
October
September
August
July
June
May
April
March
February
January
2010
December
November
October
September
August
July
June
May
April
March
February
January
2009
December
November
October
September
August
July
June
May
April
March
February
January
2008
December
November
October
September
August
July
June
May
April
March
February
January
2007
December
November
October
September
August
July
June
May
April
March
February
January
2006
December
November
October
September
August
July
June
May
April
March
February
January
2005
December
November
October
September
August
July
June
May
April
March
February
January
2004
December
November
October
September
August
July
June
May
April
March
February
January
2003
December
November
October
September
August
July
June
May
April
March
February
January
2002
December
November
October
September
August
July
June
May
April
March
February
January
2001
December
November
October
September
August
July
June
May
April
March
February
List overview
wine-devel
February 2018
----- 2025 -----
April 2025
March 2025
February 2025
January 2025
----- 2024 -----
December 2024
November 2024
October 2024
September 2024
August 2024
July 2024
June 2024
May 2024
April 2024
March 2024
February 2024
January 2024
----- 2023 -----
December 2023
November 2023
October 2023
September 2023
August 2023
July 2023
June 2023
May 2023
April 2023
March 2023
February 2023
January 2023
----- 2022 -----
December 2022
November 2022
October 2022
September 2022
August 2022
July 2022
June 2022
May 2022
April 2022
March 2022
February 2022
January 2022
----- 2021 -----
December 2021
November 2021
October 2021
September 2021
August 2021
July 2021
June 2021
May 2021
April 2021
March 2021
February 2021
January 2021
----- 2020 -----
December 2020
November 2020
October 2020
September 2020
August 2020
July 2020
June 2020
May 2020
April 2020
March 2020
February 2020
January 2020
----- 2019 -----
December 2019
November 2019
October 2019
September 2019
August 2019
July 2019
June 2019
May 2019
April 2019
March 2019
February 2019
January 2019
----- 2018 -----
December 2018
November 2018
October 2018
September 2018
August 2018
July 2018
June 2018
May 2018
April 2018
March 2018
February 2018
January 2018
----- 2017 -----
December 2017
November 2017
October 2017
September 2017
August 2017
July 2017
June 2017
May 2017
April 2017
March 2017
February 2017
January 2017
----- 2016 -----
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
January 2016
----- 2015 -----
December 2015
November 2015
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
January 2015
----- 2014 -----
December 2014
November 2014
October 2014
September 2014
August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
----- 2013 -----
December 2013
November 2013
October 2013
September 2013
August 2013
July 2013
June 2013
May 2013
April 2013
March 2013
February 2013
January 2013
----- 2012 -----
December 2012
November 2012
October 2012
September 2012
August 2012
July 2012
June 2012
May 2012
April 2012
March 2012
February 2012
January 2012
----- 2011 -----
December 2011
November 2011
October 2011
September 2011
August 2011
July 2011
June 2011
May 2011
April 2011
March 2011
February 2011
January 2011
----- 2010 -----
December 2010
November 2010
October 2010
September 2010
August 2010
July 2010
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
----- 2009 -----
December 2009
November 2009
October 2009
September 2009
August 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
January 2009
----- 2008 -----
December 2008
November 2008
October 2008
September 2008
August 2008
July 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
----- 2007 -----
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007
February 2007
January 2007
----- 2006 -----
December 2006
November 2006
October 2006
September 2006
August 2006
July 2006
June 2006
May 2006
April 2006
March 2006
February 2006
January 2006
----- 2005 -----
December 2005
November 2005
October 2005
September 2005
August 2005
July 2005
June 2005
May 2005
April 2005
March 2005
February 2005
January 2005
----- 2004 -----
December 2004
November 2004
October 2004
September 2004
August 2004
July 2004
June 2004
May 2004
April 2004
March 2004
February 2004
January 2004
----- 2003 -----
December 2003
November 2003
October 2003
September 2003
August 2003
July 2003
June 2003
May 2003
April 2003
March 2003
February 2003
January 2003
----- 2002 -----
December 2002
November 2002
October 2002
September 2002
August 2002
July 2002
June 2002
May 2002
April 2002
March 2002
February 2002
January 2002
----- 2001 -----
December 2001
November 2001
October 2001
September 2001
August 2001
July 2001
June 2001
May 2001
April 2001
March 2001
February 2001
wine-devel@winehq.org
74 participants
746 discussions
Start a n
N
ew thread
[PATCH 1/2] comctl32: Introduce ListBox control
by Nikolay Sivov
14 Feb '18
14 Feb '18
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com> --- dlls/comctl32/Makefile.in | 1 + dlls/comctl32/combo.c | 35 - dlls/comctl32/comctl32.h | 44 + dlls/comctl32/commctrl.c | 4 + dlls/comctl32/listbox.c | 3024 ++++++++++++++++++++++++++++++++++++++++++++ dlls/comctl32/tests/misc.c | 4 +- dlls/user32/class.c | 2 - 7 files changed, 3076 insertions(+), 38 deletions(-) create mode 100644 dlls/comctl32/listbox.c diff --git a/dlls/comctl32/
…
[View More]
Makefile.in b/dlls/comctl32/Makefile.in index 4adca3c93e..25d5e6716c 100644 --- a/dlls/comctl32/Makefile.in +++ b/dlls/comctl32/Makefile.in @@ -21,6 +21,7 @@ C_SRCS = \ hotkey.c \ imagelist.c \ ipaddress.c \ + listbox.c \ listview.c \ monthcal.c \ nativefont.c \ diff --git a/dlls/comctl32/combo.c b/dlls/comctl32/combo.c index 7a39cfcbef..43b4cb40f1 100644 --- a/dlls/comctl32/combo.c +++ b/dlls/comctl32/combo.c @@ -79,44 +79,9 @@ static UINT CBitHeight, CBitWidth; #define COMBO_EDITBUTTONSPACE() 0 #define EDIT_CONTROL_PADDING() 1 -#define CBF_DROPPED 0x0001 -#define CBF_BUTTONDOWN 0x0002 -#define CBF_NOROLLUP 0x0004 -#define CBF_MEASUREITEM 0x0008 -#define CBF_FOCUSED 0x0010 -#define CBF_CAPTURE 0x0020 -#define CBF_EDIT 0x0040 -#define CBF_NORESIZE 0x0080 -#define CBF_NOTIFY 0x0100 -#define CBF_NOREDRAW 0x0200 -#define CBF_SELCHANGE 0x0400 -#define CBF_HOT 0x0800 -#define CBF_NOEDITNOTIFY 0x1000 -#define CBF_NOLBSELECT 0x2000 /* do not change current selection */ -#define CBF_BEENFOCUSED 0x4000 /* has it ever had focus */ -#define CBF_EUI 0x8000 - #define ID_CB_LISTBOX 1000 #define ID_CB_EDIT 1001 -typedef struct -{ - HWND self; - HWND owner; - UINT dwStyle; - HWND hWndEdit; - HWND hWndLBox; - UINT wState; - HFONT hFont; - RECT textRect; - RECT buttonRect; - RECT droppedRect; - INT droppedIndex; - INT fixedOwnerDrawHeight; - INT droppedWidth; /* last two are not used unless set */ - INT editHeight; /* explicitly */ -} HEADCOMBO, *LPHEADCOMBO; - /*********************************************************************** * COMBO_Init * diff --git a/dlls/comctl32/comctl32.h b/dlls/comctl32/comctl32.h index 1ce9752951..18eaf7e5d1 100644 --- a/dlls/comctl32/comctl32.h +++ b/dlls/comctl32/comctl32.h @@ -107,6 +107,48 @@ extern HBRUSH COMCTL32_hPattern55AABrush DECLSPEC_HIDDEN; #define IDS_BUTTON_CANCEL 3004 #define IDS_BUTTON_CLOSE 3005 +#define WM_SYSTIMER 0x0118 + +enum combobox_state_flags +{ + CBF_DROPPED = 0x0001, + CBF_BUTTONDOWN = 0x0002, + CBF_NOROLLUP = 0x0004, + CBF_MEASUREITEM = 0x0008, + CBF_FOCUSED = 0x0010, + CBF_CAPTURE = 0x0020, + CBF_EDIT = 0x0040, + CBF_NORESIZE = 0x0080, + CBF_NOTIFY = 0x0100, + CBF_NOREDRAW = 0x0200, + CBF_SELCHANGE = 0x0400, + CBF_HOT = 0x0800, + CBF_NOEDITNOTIFY = 0x1000, + CBF_NOLBSELECT = 0x2000, /* do not change current selection */ + CBF_BEENFOCUSED = 0x4000, /* has it ever had focus */ + CBF_EUI = 0x8000, +}; + +typedef struct +{ + HWND self; + HWND owner; + UINT dwStyle; + HWND hWndEdit; + HWND hWndLBox; + UINT wState; + HFONT hFont; + RECT textRect; + RECT buttonRect; + RECT droppedRect; + INT droppedIndex; + INT fixedOwnerDrawHeight; + INT droppedWidth; /* last two are not used unless set */ + INT editHeight; /* explicitly */ +} HEADCOMBO, *LPHEADCOMBO; + +extern BOOL COMBO_FlipListbox(HEADCOMBO *lphc, BOOL ok, BOOL bRedrawButton) DECLSPEC_HIDDEN; + typedef struct { COLORREF clrBtnHighlight; /* COLOR_BTNHIGHLIGHT */ @@ -181,6 +223,7 @@ extern void BUTTON_Register(void) DECLSPEC_HIDDEN; extern void COMBO_Register(void) DECLSPEC_HIDDEN; extern void COMBOEX_Register(void) DECLSPEC_HIDDEN; extern void COMBOEX_Unregister(void) DECLSPEC_HIDDEN; +extern void COMBOLBOX_Register(void) DECLSPEC_HIDDEN; extern void DATETIME_Register(void) DECLSPEC_HIDDEN; extern void DATETIME_Unregister(void) DECLSPEC_HIDDEN; extern void EDIT_Register(void) DECLSPEC_HIDDEN; @@ -192,6 +235,7 @@ extern void HOTKEY_Register(void) DECLSPEC_HIDDEN; extern void HOTKEY_Unregister(void) DECLSPEC_HIDDEN; extern void IPADDRESS_Register(void) DECLSPEC_HIDDEN; extern void IPADDRESS_Unregister(void) DECLSPEC_HIDDEN; +extern void LISTBOX_Register(void) DECLSPEC_HIDDEN; extern void LISTVIEW_Register(void) DECLSPEC_HIDDEN; extern void LISTVIEW_Unregister(void) DECLSPEC_HIDDEN; extern void MONTHCAL_Register(void) DECLSPEC_HIDDEN; diff --git a/dlls/comctl32/commctrl.c b/dlls/comctl32/commctrl.c index 42c05e69fa..c1af1c89d6 100644 --- a/dlls/comctl32/commctrl.c +++ b/dlls/comctl32/commctrl.c @@ -100,7 +100,9 @@ static void unregister_versioned_classes(void) { VERSION WC_BUTTONA, VERSION WC_COMBOBOXA, + VERSION "ComboLBox", VERSION WC_EDITA, + VERSION WC_LISTBOXA, VERSION WC_STATICA, }; int i; @@ -172,7 +174,9 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) BUTTON_Register (); COMBO_Register (); + COMBOLBOX_Register (); EDIT_Register (); + LISTBOX_Register (); STATIC_Register (); /* subclass user32 controls */ diff --git a/dlls/comctl32/listbox.c b/dlls/comctl32/listbox.c new file mode 100644 index 0000000000..ad970225f1 --- /dev/null +++ b/dlls/comctl32/listbox.c @@ -0,0 +1,3024 @@ +/* + * Listbox controls + * + * Copyright 1996 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * TODO: + * - LBS_NODATA + */ + +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "commctrl.h" +#include "wine/unicode.h" +#include "wine/exception.h" +#include "wine/debug.h" + +#include "comctl32.h" + +WINE_DEFAULT_DEBUG_CHANNEL(listbox2); + +/* Items array granularity */ +#define LB_ARRAY_GRANULARITY 16 + +/* Scrolling timeout in ms */ +#define LB_SCROLL_TIMEOUT 50 + +/* Listbox system timer id */ +#define LB_TIMER_ID 2 + +/* flag listbox changed while setredraw false - internal style */ +#define LBS_DISPLAYCHANGED 0x80000000 + +/* Item structure */ +typedef struct +{ + LPWSTR str; /* Item text */ + BOOL selected; /* Is item selected? */ + UINT height; /* Item height (only for OWNERDRAWVARIABLE) */ + ULONG_PTR data; /* User data */ +} LB_ITEMDATA; + +/* Listbox structure */ +typedef struct +{ + HWND self; /* Our own window handle */ + HWND owner; /* Owner window to send notifications to */ + UINT style; /* Window style */ + INT width; /* Window width */ + INT height; /* Window height */ + LB_ITEMDATA *items; /* Array of items */ + INT nb_items; /* Number of items */ + INT top_item; /* Top visible item */ + INT selected_item; /* Selected item */ + INT focus_item; /* Item that has the focus */ + INT anchor_item; /* Anchor item for extended selection */ + INT item_height; /* Default item height */ + INT page_size; /* Items per listbox page */ + INT column_width; /* Column width for multi-column listboxes */ + INT horz_extent; /* Horizontal extent */ + INT horz_pos; /* Horizontal position */ + INT nb_tabs; /* Number of tabs in array */ + INT *tabs; /* Array of tabs */ + INT avg_char_width; /* Average width of characters */ + INT wheel_remain; /* Left over scroll amount */ + BOOL caret_on; /* Is caret on? */ + BOOL captured; /* Is mouse captured? */ + BOOL in_focus; + HFONT font; /* Current font */ + LCID locale; /* Current locale for string comparisons */ + HEADCOMBO *lphc; /* ComboLBox */ +} LB_DESCR; + + +#define IS_OWNERDRAW(descr) \ + ((descr)->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) + +#define HAS_STRINGS(descr) \ + (!IS_OWNERDRAW(descr) || ((descr)->style & LBS_HASSTRINGS)) + + +#define IS_MULTISELECT(descr) \ + ((descr)->style & (LBS_MULTIPLESEL|LBS_EXTENDEDSEL) && \ + !((descr)->style & LBS_NOSEL)) + +#define SEND_NOTIFICATION(descr,code) \ + (SendMessageW( (descr)->owner, WM_COMMAND, \ + MAKEWPARAM( GetWindowLongPtrW((descr->self),GWLP_ID), (code)), (LPARAM)(descr->self) )) + +#define ISWIN31 (LOWORD(GetVersion()) == 0x0a03) + +/* Current timer status */ +typedef enum +{ + LB_TIMER_NONE, + LB_TIMER_UP, + LB_TIMER_LEFT, + LB_TIMER_DOWN, + LB_TIMER_RIGHT +} TIMER_DIRECTION; + +static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE; + +static LRESULT LISTBOX_GetItemRect( const LB_DESCR *descr, INT index, RECT *rect ); + +/*********************************************************************** + * LISTBOX_GetCurrentPageSize + * + * Return the current page size + */ +static INT LISTBOX_GetCurrentPageSize( const LB_DESCR *descr ) +{ + INT i, height; + if (!(descr->style & LBS_OWNERDRAWVARIABLE)) return descr->page_size; + for (i = descr->top_item, height = 0; i < descr->nb_items; i++) + { + if ((height += descr->items[i].height) > descr->height) break; + } + if (i == descr->top_item) return 1; + else return i - descr->top_item; +} + + +/*********************************************************************** + * LISTBOX_GetMaxTopIndex + * + * Return the maximum possible index for the top of the listbox. + */ +static INT LISTBOX_GetMaxTopIndex( const LB_DESCR *descr ) +{ + INT max, page; + + if (descr->style & LBS_OWNERDRAWVARIABLE) + { + page = descr->height; + for (max = descr->nb_items - 1; max >= 0; max--) + if ((page -= descr->items[max].height) < 0) break; + if (max < descr->nb_items - 1) max++; + } + else if (descr->style & LBS_MULTICOLUMN) + { + if ((page = descr->width / descr->column_width) < 1) page = 1; + max = (descr->nb_items + descr->page_size - 1) / descr->page_size; + max = (max - page) * descr->page_size; + } + else + { + max = descr->nb_items - descr->page_size; + } + if (max < 0) max = 0; + return max; +} + + +/*********************************************************************** + * LISTBOX_UpdateScroll + * + * Update the scrollbars. Should be called whenever the content + * of the listbox changes. + */ +static void LISTBOX_UpdateScroll( LB_DESCR *descr ) +{ + SCROLLINFO info; + + /* Check the listbox scroll bar flags individually before we call + SetScrollInfo otherwise when the listbox style is WS_HSCROLL and + no WS_VSCROLL, we end up with an uninitialized, visible horizontal + scroll bar when we do not need one. + if (!(descr->style & WS_VSCROLL)) return; + */ + + /* It is important that we check descr->style, and not wnd->dwStyle, + for WS_VSCROLL, as the former is exactly the one passed in + argument to CreateWindow. + In Windows (and from now on in Wine :) a listbox created + with such a style (no WS_SCROLL) does not update + the scrollbar with listbox-related data, thus letting + the programmer use it for his/her own purposes. */ + + if (descr->style & LBS_NOREDRAW) return; + info.cbSize = sizeof(info); + + if (descr->style & LBS_MULTICOLUMN) + { + info.nMin = 0; + info.nMax = (descr->nb_items - 1) / descr->page_size; + info.nPos = descr->top_item / descr->page_size; + info.nPage = descr->width / descr->column_width; + if (info.nPage < 1) info.nPage = 1; + info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE; + if (descr->style & LBS_DISABLENOSCROLL) + info.fMask |= SIF_DISABLENOSCROLL; + if (descr->style & WS_HSCROLL) + SetScrollInfo( descr->self, SB_HORZ, &info, TRUE ); + info.nMax = 0; + info.fMask = SIF_RANGE; + if (descr->style & WS_VSCROLL) + SetScrollInfo( descr->self, SB_VERT, &info, TRUE ); + } + else + { + info.nMin = 0; + info.nMax = descr->nb_items - 1; + info.nPos = descr->top_item; + info.nPage = LISTBOX_GetCurrentPageSize( descr ); + info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE; + if (descr->style & LBS_DISABLENOSCROLL) + info.fMask |= SIF_DISABLENOSCROLL; + if (descr->style & WS_VSCROLL) + SetScrollInfo( descr->self, SB_VERT, &info, TRUE ); + + if ((descr->style & WS_HSCROLL) && descr->horz_extent) + { + info.nPos = descr->horz_pos; + info.nPage = descr->width; + info.fMask = SIF_POS | SIF_PAGE; + if (descr->style & LBS_DISABLENOSCROLL) + info.fMask |= SIF_DISABLENOSCROLL; + SetScrollInfo( descr->self, SB_HORZ, &info, TRUE ); + } + else + { + if (descr->style & LBS_DISABLENOSCROLL) + { + info.nMin = 0; + info.nMax = 0; + info.fMask = SIF_RANGE | SIF_DISABLENOSCROLL; + SetScrollInfo( descr->self, SB_HORZ, &info, TRUE ); + } + else + { + ShowScrollBar( descr->self, SB_HORZ, FALSE ); + } + } + } +} + + +/*********************************************************************** + * LISTBOX_SetTopItem + * + * Set the top item of the listbox, scrolling up or down if necessary. + */ +static LRESULT LISTBOX_SetTopItem( LB_DESCR *descr, INT index, BOOL scroll ) +{ + INT max = LISTBOX_GetMaxTopIndex( descr ); + + TRACE("setting top item %d, scroll %d\n", index, scroll); + + if (index > max) index = max; + if (index < 0) index = 0; + if (descr->style & LBS_MULTICOLUMN) index -= index % descr->page_size; + if (descr->top_item == index) return LB_OKAY; + if (scroll) + { + INT diff; + if (descr->style & LBS_MULTICOLUMN) + diff = (descr->top_item - index) / descr->page_size * descr->column_width; + else if (descr->style & LBS_OWNERDRAWVARIABLE) + { + INT i; + diff = 0; + if (index > descr->top_item) + { + for (i = index - 1; i >= descr->top_item; i--) + diff -= descr->items[i].height; + } + else + { + for (i = index; i < descr->top_item; i++) + diff += descr->items[i].height; + } + } + else + diff = (descr->top_item - index) * descr->item_height; + + ScrollWindowEx( descr->self, 0, diff, NULL, NULL, 0, NULL, + SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN ); + } + else + InvalidateRect( descr->self, NULL, TRUE ); + descr->top_item = index; + LISTBOX_UpdateScroll( descr ); + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_UpdatePage + * + * Update the page size. Should be called when the size of + * the client area or the item height changes. + */ +static void LISTBOX_UpdatePage( LB_DESCR *descr ) +{ + INT page_size; + + if ((descr->item_height == 0) || (page_size = descr->height / descr->item_height) < 1) + page_size = 1; + if (page_size == descr->page_size) return; + descr->page_size = page_size; + if (descr->style & LBS_MULTICOLUMN) + InvalidateRect( descr->self, NULL, TRUE ); + LISTBOX_SetTopItem( descr, descr->top_item, FALSE ); +} + + +/*********************************************************************** + * LISTBOX_UpdateSize + * + * Update the size of the listbox. Should be called when the size of + * the client area changes. + */ +static void LISTBOX_UpdateSize( LB_DESCR *descr ) +{ + RECT rect; + + GetClientRect( descr->self, &rect ); + descr->width = rect.right - rect.left; + descr->height = rect.bottom - rect.top; + if (!(descr->style & LBS_NOINTEGRALHEIGHT) && !(descr->style & LBS_OWNERDRAWVARIABLE)) + { + INT remaining; + RECT rect; + + GetWindowRect( descr->self, &rect ); + if(descr->item_height != 0) + remaining = descr->height % descr->item_height; + else + remaining = 0; + if ((descr->height > descr->item_height) && remaining) + { + TRACE("[%p]: changing height %d -> %d\n", + descr->self, descr->height, descr->height - remaining ); + SetWindowPos( descr->self, 0, 0, 0, rect.right - rect.left, + rect.bottom - rect.top - remaining, + SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE ); + return; + } + } + TRACE("[%p]: new size = %d,%d\n", descr->self, descr->width, descr->height ); + LISTBOX_UpdatePage( descr ); + LISTBOX_UpdateScroll( descr ); + + /* Invalidate the focused item so it will be repainted correctly */ + if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) == 1) + { + InvalidateRect( descr->self, &rect, FALSE ); + } +} + + +/*********************************************************************** + * LISTBOX_GetItemRect + * + * Get the rectangle enclosing an item, in listbox client coordinates. + * Return 1 if the rectangle is (partially) visible, 0 if hidden, -1 on error. + */ +static LRESULT LISTBOX_GetItemRect( const LB_DESCR *descr, INT index, RECT *rect ) +{ + /* Index <= 0 is legal even on empty listboxes */ + if (index && (index >= descr->nb_items)) + { + SetRectEmpty(rect); + SetLastError(ERROR_INVALID_INDEX); + return LB_ERR; + } + SetRect( rect, 0, 0, descr->width, descr->height ); + if (descr->style & LBS_MULTICOLUMN) + { + INT col = (index / descr->page_size) - + (descr->top_item / descr->page_size); + rect->left += col * descr->column_width; + rect->right = rect->left + descr->column_width; + rect->top += (index % descr->page_size) * descr->item_height; + rect->bottom = rect->top + descr->item_height; + } + else if (descr->style & LBS_OWNERDRAWVARIABLE) + { + INT i; + rect->right += descr->horz_pos; + if ((index >= 0) && (index < descr->nb_items)) + { + if (index < descr->top_item) + { + for (i = descr->top_item-1; i >= index; i--) + rect->top -= descr->items[i].height; + } + else + { + for (i = descr->top_item; i < index; i++) + rect->top += descr->items[i].height; + } + rect->bottom = rect->top + descr->items[index].height; + + } + } + else + { + rect->top += (index - descr->top_item) * descr->item_height; + rect->bottom = rect->top + descr->item_height; + rect->right += descr->horz_pos; + } + + TRACE("item %d, rect %s\n", index, wine_dbgstr_rect(rect)); + + return ((rect->left < descr->width) && (rect->right > 0) && + (rect->top < descr->height) && (rect->bottom > 0)); +} + + +/*********************************************************************** + * LISTBOX_GetItemFromPoint + * + * Return the item nearest from point (x,y) (in client coordinates). + */ +static INT LISTBOX_GetItemFromPoint( const LB_DESCR *descr, INT x, INT y ) +{ + INT index = descr->top_item; + + if (!descr->nb_items) return -1; /* No items */ + if (descr->style & LBS_OWNERDRAWVARIABLE) + { + INT pos = 0; + if (y >= 0) + { + while (index < descr->nb_items) + { + if ((pos += descr->items[index].height) > y) break; + index++; + } + } + else + { + while (index > 0) + { + index--; + if ((pos -= descr->items[index].height) <= y) break; + } + } + } + else if (descr->style & LBS_MULTICOLUMN) + { + if (y >= descr->item_height * descr->page_size) return -1; + if (y >= 0) index += y / descr->item_height; + if (x >= 0) index += (x / descr->column_width) * descr->page_size; + else index -= (((x + 1) / descr->column_width) - 1) * descr->page_size; + } + else + { + index += (y / descr->item_height); + } + if (index < 0) return 0; + if (index >= descr->nb_items) return -1; + return index; +} + + +/*********************************************************************** + * LISTBOX_PaintItem + * + * Paint an item. + */ +static void LISTBOX_PaintItem( LB_DESCR *descr, HDC hdc, const RECT *rect, + INT index, UINT action, BOOL ignoreFocus ) +{ + LB_ITEMDATA *item = NULL; + if (index < descr->nb_items) item = &descr->items[index]; + + if (IS_OWNERDRAW(descr)) + { + DRAWITEMSTRUCT dis; + RECT r; + HRGN hrgn; + + if (!item) + { + if (action == ODA_FOCUS) + DrawFocusRect( hdc, rect ); + else + ERR("called with an out of bounds index %d(%d) in owner draw, Not good.\n",index,descr->nb_items); + return; + } + + /* some programs mess with the clipping region when + drawing the item, *and* restore the previous region + after they are done, so a region has better to exist + else everything ends clipped */ + GetClientRect(descr->self, &r); + hrgn = set_control_clipping( hdc, &r ); + + dis.CtlType = ODT_LISTBOX; + dis.CtlID = GetWindowLongPtrW( descr->self, GWLP_ID ); + dis.hwndItem = descr->self; + dis.itemAction = action; + dis.hDC = hdc; + dis.itemID = index; + dis.itemState = 0; + if (item->selected) dis.itemState |= ODS_SELECTED; + if (!ignoreFocus && (descr->focus_item == index) && + (descr->caret_on) && + (descr->in_focus)) dis.itemState |= ODS_FOCUS; + if (!IsWindowEnabled(descr->self)) dis.itemState |= ODS_DISABLED; + dis.itemData = item->data; + dis.rcItem = *rect; + TRACE("[%p]: drawitem %d (%s) action=%02x state=%02x rect=%s\n", + descr->self, index, debugstr_w(item->str), action, + dis.itemState, wine_dbgstr_rect(rect) ); + SendMessageW(descr->owner, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis); + SelectClipRgn( hdc, hrgn ); + if (hrgn) DeleteObject( hrgn ); + } + else + { + COLORREF oldText = 0, oldBk = 0; + + if (action == ODA_FOCUS) + { + DrawFocusRect( hdc, rect ); + return; + } + if (item && item->selected) + { + oldBk = SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) ); + oldText = SetTextColor( hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + } + + TRACE("[%p]: painting %d (%s) action=%02x rect=%s\n", + descr->self, index, item ? debugstr_w(item->str) : "", action, + wine_dbgstr_rect(rect) ); + if (!item) + ExtTextOutW( hdc, rect->left + 1, rect->top, + ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL ); + else if (!(descr->style & LBS_USETABSTOPS)) + ExtTextOutW( hdc, rect->left + 1, rect->top, + ETO_OPAQUE | ETO_CLIPPED, rect, item->str, + strlenW(item->str), NULL ); + else + { + /* Output empty string to paint background in the full width. */ + ExtTextOutW( hdc, rect->left + 1, rect->top, + ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL ); + TabbedTextOutW( hdc, rect->left + 1 , rect->top, + item->str, strlenW(item->str), + descr->nb_tabs, descr->tabs, 0); + } + if (item && item->selected) + { + SetBkColor( hdc, oldBk ); + SetTextColor( hdc, oldText ); + } + if (!ignoreFocus && (descr->focus_item == index) && + (descr->caret_on) && + (descr->in_focus)) DrawFocusRect( hdc, rect ); + } +} + + +/*********************************************************************** + * LISTBOX_SetRedraw + * + * Change the redraw flag. + */ +static void LISTBOX_SetRedraw( LB_DESCR *descr, BOOL on ) +{ + if (on) + { + if (!(descr->style & LBS_NOREDRAW)) return; + descr->style &= ~LBS_NOREDRAW; + if (descr->style & LBS_DISPLAYCHANGED) + { /* page was changed while setredraw false, refresh automatically */ + InvalidateRect(descr->self, NULL, TRUE); + if ((descr->top_item + descr->page_size) > descr->nb_items) + { /* reset top of page if less than number of items/page */ + descr->top_item = descr->nb_items - descr->page_size; + if (descr->top_item < 0) descr->top_item = 0; + } + descr->style &= ~LBS_DISPLAYCHANGED; + } + LISTBOX_UpdateScroll( descr ); + } + else descr->style |= LBS_NOREDRAW; +} + + +/*********************************************************************** + * LISTBOX_RepaintItem + * + * Repaint a single item synchronously. + */ +static void LISTBOX_RepaintItem( LB_DESCR *descr, INT index, UINT action ) +{ + HDC hdc; + RECT rect; + HFONT oldFont = 0; + HBRUSH hbrush, oldBrush = 0; + + /* Do not repaint the item if the item is not visible */ + if (!IsWindowVisible(descr->self)) return; + if (descr->style & LBS_NOREDRAW) + { + descr->style |= LBS_DISPLAYCHANGED; + return; + } + if (LISTBOX_GetItemRect( descr, index, &rect ) != 1) return; + if (!(hdc = GetDCEx( descr->self, 0, DCX_CACHE ))) return; + if (descr->font) oldFont = SelectObject( hdc, descr->font ); + hbrush = (HBRUSH)SendMessageW( descr->owner, WM_CTLCOLORLISTBOX, + (WPARAM)hdc, (LPARAM)descr->self ); + if (hbrush) oldBrush = SelectObject( hdc, hbrush ); + if (!IsWindowEnabled(descr->self)) + SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) ); + SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL ); + LISTBOX_PaintItem( descr, hdc, &rect, index, action, TRUE ); + if (oldFont) SelectObject( hdc, oldFont ); + if (oldBrush) SelectObject( hdc, oldBrush ); + ReleaseDC( descr->self, hdc ); +} + + +/*********************************************************************** + * LISTBOX_DrawFocusRect + */ +static void LISTBOX_DrawFocusRect( LB_DESCR *descr, BOOL on ) +{ + HDC hdc; + RECT rect; + HFONT oldFont = 0; + + /* Do not repaint the item if the item is not visible */ + if (!IsWindowVisible(descr->self)) return; + + if (descr->focus_item == -1) return; + if (!descr->caret_on || !descr->in_focus) return; + + if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) != 1) return; + if (!(hdc = GetDCEx( descr->self, 0, DCX_CACHE ))) return; + if (descr->font) oldFont = SelectObject( hdc, descr->font ); + if (!IsWindowEnabled(descr->self)) + SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) ); + SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL ); + LISTBOX_PaintItem( descr, hdc, &rect, descr->focus_item, ODA_FOCUS, !on ); + if (oldFont) SelectObject( hdc, oldFont ); + ReleaseDC( descr->self, hdc ); +} + + +/*********************************************************************** + * LISTBOX_InitStorage + */ +static LRESULT LISTBOX_InitStorage( LB_DESCR *descr, INT nb_items ) +{ + LB_ITEMDATA *item; + + nb_items += LB_ARRAY_GRANULARITY - 1; + nb_items -= (nb_items % LB_ARRAY_GRANULARITY); + if (descr->items) { + nb_items += HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(*item); + item = HeapReAlloc( GetProcessHeap(), 0, descr->items, + nb_items * sizeof(LB_ITEMDATA)); + } + else { + item = HeapAlloc( GetProcessHeap(), 0, + nb_items * sizeof(LB_ITEMDATA)); + } + + if (!item) + { + SEND_NOTIFICATION( descr, LBN_ERRSPACE ); + return LB_ERRSPACE; + } + descr->items = item; + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_SetTabStops + */ +static BOOL LISTBOX_SetTabStops( LB_DESCR *descr, INT count, LPINT tabs ) +{ + INT i; + + if (!(descr->style & LBS_USETABSTOPS)) + { + SetLastError(ERROR_LB_WITHOUT_TABSTOPS); + return FALSE; + } + + HeapFree( GetProcessHeap(), 0, descr->tabs ); + if (!(descr->nb_tabs = count)) + { + descr->tabs = NULL; + return TRUE; + } + if (!(descr->tabs = HeapAlloc( GetProcessHeap(), 0, + descr->nb_tabs * sizeof(INT) ))) + return FALSE; + memcpy( descr->tabs, tabs, descr->nb_tabs * sizeof(INT) ); + + /* convert into "dialog units"*/ + for (i = 0; i < descr->nb_tabs; i++) + descr->tabs[i] = MulDiv(descr->tabs[i], descr->avg_char_width, 4); + + return TRUE; +} + + +/*********************************************************************** + * LISTBOX_GetText + */ +static LRESULT LISTBOX_GetText( LB_DESCR *descr, INT index, LPWSTR buffer, BOOL unicode ) +{ + DWORD len; + + if ((index < 0) || (index >= descr->nb_items)) + { + SetLastError(ERROR_INVALID_INDEX); + return LB_ERR; + } + + if (HAS_STRINGS(descr)) + { + if (!buffer) + return strlenW(descr->items[index].str); + + TRACE("index %d (0x%04x) %s\n", index, index, debugstr_w(descr->items[index].str)); + + __TRY /* hide a Delphi bug that passes a read-only buffer */ + { + strcpyW( buffer, descr->items[index].str ); + len = strlenW(buffer); + } + __EXCEPT_PAGE_FAULT + { + WARN( "got an invalid buffer (Delphi bug?)\n" ); + SetLastError( ERROR_INVALID_PARAMETER ); + return LB_ERR; + } + __ENDTRY + } else + { + if (buffer) + *((DWORD *)buffer) = *(DWORD *)&descr->items[index].data; + len = sizeof(DWORD); + } + return len; +} + +static inline INT LISTBOX_lstrcmpiW( LCID lcid, LPCWSTR str1, LPCWSTR str2 ) +{ + INT ret = CompareStringW( lcid, NORM_IGNORECASE, str1, -1, str2, -1 ); + if (ret == CSTR_LESS_THAN) + return -1; + if (ret == CSTR_EQUAL) + return 0; + if (ret == CSTR_GREATER_THAN) + return 1; + return -1; +} + +/*********************************************************************** + * LISTBOX_FindStringPos + * + * Find the nearest string located before a given string in sort order. + * If 'exact' is TRUE, return an error if we don't get an exact match. + */ +static INT LISTBOX_FindStringPos( LB_DESCR *descr, LPCWSTR str, BOOL exact ) +{ + INT index, min, max, res; + + if (!(descr->style & LBS_SORT)) return -1; /* Add it at the end */ + min = 0; + max = descr->nb_items; + while (min != max) + { + index = (min + max) / 2; + if (HAS_STRINGS(descr)) + res = LISTBOX_lstrcmpiW( descr->locale, str, descr->items[index].str); + else + { + COMPAREITEMSTRUCT cis; + UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID ); + + cis.CtlType = ODT_LISTBOX; + cis.CtlID = id; + cis.hwndItem = descr->self; + /* note that some application (MetaStock) expects the second item + * to be in the listbox */ + cis.itemID1 = -1; + cis.itemData1 = (ULONG_PTR)str; + cis.itemID2 = index; + cis.itemData2 = descr->items[index].data; + cis.dwLocaleId = descr->locale; + res = SendMessageW( descr->owner, WM_COMPAREITEM, id, (LPARAM)&cis ); + } + if (!res) return index; + if (res < 0) max = index; + else min = index + 1; + } + return exact ? -1 : max; +} + + +/*********************************************************************** + * LISTBOX_FindFileStrPos + * + * Find the nearest string located before a given string in directory + * sort order (i.e. first files, then directories, then drives). + */ +static INT LISTBOX_FindFileStrPos( LB_DESCR *descr, LPCWSTR str ) +{ + INT min, max, res; + + if (!HAS_STRINGS(descr)) + return LISTBOX_FindStringPos( descr, str, FALSE ); + min = 0; + max = descr->nb_items; + while (min != max) + { + INT index = (min + max) / 2; + LPCWSTR p = descr->items[index].str; + if (*p == '[') /* drive or directory */ + { + if (*str != '[') res = -1; + else if (p[1] == '-') /* drive */ + { + if (str[1] == '-') res = str[2] - p[2]; + else res = -1; + } + else /* directory */ + { + if (str[1] == '-') res = 1; + else res = LISTBOX_lstrcmpiW( descr->locale, str, p ); + } + } + else /* filename */ + { + if (*str == '[') res = 1; + else res = LISTBOX_lstrcmpiW( descr->locale, str, p ); + } + if (!res) return index; + if (res < 0) max = index; + else min = index + 1; + } + return max; +} + + +/*********************************************************************** + * LISTBOX_FindString + * + * Find the item beginning with a given string. + */ +static INT LISTBOX_FindString( LB_DESCR *descr, INT start, LPCWSTR str, BOOL exact ) +{ + INT i; + LB_ITEMDATA *item; + + if (start >= descr->nb_items) start = -1; + item = descr->items + start + 1; + if (HAS_STRINGS(descr)) + { + if (!str || ! str[0] ) return LB_ERR; + if (exact) + { + for (i = start + 1; i < descr->nb_items; i++, item++) + if (!LISTBOX_lstrcmpiW( descr->locale, str, item->str )) return i; + for (i = 0, item = descr->items; i <= start; i++, item++) + if (!LISTBOX_lstrcmpiW( descr->locale, str, item->str )) return i; + } + else + { + /* Special case for drives and directories: ignore prefix */ +#define CHECK_DRIVE(item) \ + if ((item)->str[0] == '[') \ + { \ + if (!strncmpiW( str, (item)->str+1, len )) return i; \ + if (((item)->str[1] == '-') && !strncmpiW(str, (item)->str+2, len)) \ + return i; \ + } + + INT len = strlenW(str); + for (i = start + 1; i < descr->nb_items; i++, item++) + { + if (!strncmpiW( str, item->str, len )) return i; + CHECK_DRIVE(item); + } + for (i = 0, item = descr->items; i <= start; i++, item++) + { + if (!strncmpiW( str, item->str, len )) return i; + CHECK_DRIVE(item); + } +#undef CHECK_DRIVE + } + } + else + { + if (exact && (descr->style & LBS_SORT)) + /* If sorted, use a WM_COMPAREITEM binary search */ + return LISTBOX_FindStringPos( descr, str, TRUE ); + + /* Otherwise use a linear search */ + for (i = start + 1; i < descr->nb_items; i++, item++) + if (item->data == (ULONG_PTR)str) return i; + for (i = 0, item = descr->items; i <= start; i++, item++) + if (item->data == (ULONG_PTR)str) return i; + } + return LB_ERR; +} + + +/*********************************************************************** + * LISTBOX_GetSelCount + */ +static LRESULT LISTBOX_GetSelCount( const LB_DESCR *descr ) +{ + INT i, count; + const LB_ITEMDATA *item = descr->items; + + if (!(descr->style & LBS_MULTIPLESEL) || + (descr->style & LBS_NOSEL)) + return LB_ERR; + for (i = count = 0; i < descr->nb_items; i++, item++) + if (item->selected) count++; + return count; +} + + +/*********************************************************************** + * LISTBOX_GetSelItems + */ +static LRESULT LISTBOX_GetSelItems( const LB_DESCR *descr, INT max, LPINT array ) +{ + INT i, count; + const LB_ITEMDATA *item = descr->items; + + if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR; + for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++) + if (item->selected) array[count++] = i; + return count; +} + + +/*********************************************************************** + * LISTBOX_Paint + */ +static LRESULT LISTBOX_Paint( LB_DESCR *descr, HDC hdc ) +{ + INT i, col_pos = descr->page_size - 1; + RECT rect; + RECT focusRect = {-1, -1, -1, -1}; + HFONT oldFont = 0; + HBRUSH hbrush, oldBrush = 0; + + if (descr->style & LBS_NOREDRAW) return 0; + + SetRect( &rect, 0, 0, descr->width, descr->height ); + if (descr->style & LBS_MULTICOLUMN) + rect.right = rect.left + descr->column_width; + else if (descr->horz_pos) + { + SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL ); + rect.right += descr->horz_pos; + } + + if (descr->font) oldFont = SelectObject( hdc, descr->font ); + hbrush = (HBRUSH)SendMessageW( descr->owner, WM_CTLCOLORLISTBOX, + (WPARAM)hdc, (LPARAM)descr->self ); + if (hbrush) oldBrush = SelectObject( hdc, hbrush ); + if (!IsWindowEnabled(descr->self)) SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) ); + + if (!descr->nb_items && (descr->focus_item != -1) && descr->caret_on && + (descr->in_focus)) + { + /* Special case for empty listbox: paint focus rect */ + rect.bottom = rect.top + descr->item_height; + ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED, + &rect, NULL, 0, NULL ); + LISTBOX_PaintItem( descr, hdc, &rect, descr->focus_item, ODA_FOCUS, FALSE ); + rect.top = rect.bottom; + } + + /* Paint all the item, regarding the selection + Focus state will be painted after */ + + for (i = descr->top_item; i < descr->nb_items; i++) + { + if (!(descr->style & LBS_OWNERDRAWVARIABLE)) + rect.bottom = rect.top + descr->item_height; + else + rect.bottom = rect.top + descr->items[i].height; + + /* keep the focus rect, to paint the focus item after */ + if (i == descr->focus_item) + focusRect = rect; + + LISTBOX_PaintItem( descr, hdc, &rect, i, ODA_DRAWENTIRE, TRUE ); + rect.top = rect.bottom; + + if ((descr->style & LBS_MULTICOLUMN) && !col_pos) + { + if (!IS_OWNERDRAW(descr)) + { + /* Clear the bottom of the column */ + if (rect.top < descr->height) + { + rect.bottom = descr->height; + ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED, + &rect, NULL, 0, NULL ); + } + } + + /* Go to the next column */ + rect.left += descr->column_width; + rect.right += descr->column_width; + rect.top = 0; + col_pos = descr->page_size - 1; + } + else + { + col_pos--; + if (rect.top >= descr->height) break; + } + } + + /* Paint the focus item now */ + if (focusRect.top != focusRect.bottom && + descr->caret_on && descr->in_focus) + LISTBOX_PaintItem( descr, hdc, &focusRect, descr->focus_item, ODA_FOCUS, FALSE ); + + if (!IS_OWNERDRAW(descr)) + { + /* Clear the remainder of the client area */ + if (rect.top < descr->height) + { + rect.bottom = descr->height; + ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED, + &rect, NULL, 0, NULL ); + } + if (rect.right < descr->width) + { + rect.left = rect.right; + rect.right = descr->width; + rect.top = 0; + rect.bottom = descr->height; + ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED, + &rect, NULL, 0, NULL ); + } + } + if (oldFont) SelectObject( hdc, oldFont ); + if (oldBrush) SelectObject( hdc, oldBrush ); + return 0; +} + + +/*********************************************************************** + * LISTBOX_InvalidateItems + * + * Invalidate all items from a given item. If the specified item is not + * visible, nothing happens. + */ +static void LISTBOX_InvalidateItems( LB_DESCR *descr, INT index ) +{ + RECT rect; + + if (LISTBOX_GetItemRect( descr, index, &rect ) == 1) + { + if (descr->style & LBS_NOREDRAW) + { + descr->style |= LBS_DISPLAYCHANGED; + return; + } + rect.bottom = descr->height; + InvalidateRect( descr->self, &rect, TRUE ); + if (descr->style & LBS_MULTICOLUMN) + { + /* Repaint the other columns */ + rect.left = rect.right; + rect.right = descr->width; + rect.top = 0; + InvalidateRect( descr->self, &rect, TRUE ); + } + } +} + +static void LISTBOX_InvalidateItemRect( LB_DESCR *descr, INT index ) +{ + RECT rect; + + if (LISTBOX_GetItemRect( descr, index, &rect ) == 1) + InvalidateRect( descr->self, &rect, TRUE ); +} + +/*********************************************************************** + * LISTBOX_GetItemHeight + */ +static LRESULT LISTBOX_GetItemHeight( const LB_DESCR *descr, INT index ) +{ + if (descr->style & LBS_OWNERDRAWVARIABLE && descr->nb_items > 0) + { + if ((index < 0) || (index >= descr->nb_items)) + { + SetLastError(ERROR_INVALID_INDEX); + return LB_ERR; + } + return descr->items[index].height; + } + else return descr->item_height; +} + + +/*********************************************************************** + * LISTBOX_SetItemHeight + */ +static LRESULT LISTBOX_SetItemHeight( LB_DESCR *descr, INT index, INT height, BOOL repaint ) +{ + if (height > MAXBYTE) + return -1; + + if (!height) height = 1; + + if (descr->style & LBS_OWNERDRAWVARIABLE) + { + if ((index < 0) || (index >= descr->nb_items)) + { + SetLastError(ERROR_INVALID_INDEX); + return LB_ERR; + } + TRACE("[%p]: item %d height = %d\n", descr->self, index, height ); + descr->items[index].height = height; + LISTBOX_UpdateScroll( descr ); + if (repaint) + LISTBOX_InvalidateItems( descr, index ); + } + else if (height != descr->item_height) + { + TRACE("[%p]: new height = %d\n", descr->self, height ); + descr->item_height = height; + LISTBOX_UpdatePage( descr ); + LISTBOX_UpdateScroll( descr ); + if (repaint) + InvalidateRect( descr->self, 0, TRUE ); + } + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_SetHorizontalPos + */ +static void LISTBOX_SetHorizontalPos( LB_DESCR *descr, INT pos ) +{ + INT diff; + + if (pos > descr->horz_extent - descr->width) + pos = descr->horz_extent - descr->width; + if (pos < 0) pos = 0; + if (!(diff = descr->horz_pos - pos)) return; + TRACE("[%p]: new horz pos = %d\n", descr->self, pos ); + descr->horz_pos = pos; + LISTBOX_UpdateScroll( descr ); + if (abs(diff) < descr->width) + { + RECT rect; + /* Invalidate the focused item so it will be repainted correctly */ + if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) == 1) + InvalidateRect( descr->self, &rect, TRUE ); + ScrollWindowEx( descr->self, diff, 0, NULL, NULL, 0, NULL, + SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN ); + } + else + InvalidateRect( descr->self, NULL, TRUE ); +} + + +/*********************************************************************** + * LISTBOX_SetHorizontalExtent + */ +static LRESULT LISTBOX_SetHorizontalExtent( LB_DESCR *descr, INT extent ) +{ + if (descr->style & LBS_MULTICOLUMN) + return LB_OKAY; + if (extent == descr->horz_extent) return LB_OKAY; + TRACE("[%p]: new horz extent = %d\n", descr->self, extent ); + descr->horz_extent = extent; + if (descr->style & WS_HSCROLL) { + SCROLLINFO info; + info.cbSize = sizeof(info); + info.nMin = 0; + info.nMax = descr->horz_extent ? descr->horz_extent - 1 : 0; + info.fMask = SIF_RANGE; + if (descr->style & LBS_DISABLENOSCROLL) + info.fMask |= SIF_DISABLENOSCROLL; + SetScrollInfo( descr->self, SB_HORZ, &info, TRUE ); + } + if (descr->horz_pos > extent - descr->width) + LISTBOX_SetHorizontalPos( descr, extent - descr->width ); + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_SetColumnWidth + */ +static LRESULT LISTBOX_SetColumnWidth( LB_DESCR *descr, INT width) +{ + if (width == descr->column_width) return LB_OKAY; + TRACE("[%p]: new column width = %d\n", descr->self, width ); + descr->column_width = width; + LISTBOX_UpdatePage( descr ); + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_SetFont + * + * Returns the item height. + */ +static INT LISTBOX_SetFont( LB_DESCR *descr, HFONT font ) +{ + HDC hdc; + HFONT oldFont = 0; + const char *alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + SIZE sz; + + descr->font = font; + + if (!(hdc = GetDCEx( descr->self, 0, DCX_CACHE ))) + { + ERR("unable to get DC.\n" ); + return 16; + } + if (font) oldFont = SelectObject( hdc, font ); + GetTextExtentPointA( hdc, alphabet, 52, &sz); + if (oldFont) SelectObject( hdc, oldFont ); + ReleaseDC( descr->self, hdc ); + + descr->avg_char_width = (sz.cx / 26 + 1) / 2; + if (!IS_OWNERDRAW(descr)) + LISTBOX_SetItemHeight( descr, 0, sz.cy, FALSE ); + return sz.cy; +} + + +/*********************************************************************** + * LISTBOX_MakeItemVisible + * + * Make sure that a given item is partially or fully visible. + */ +static void LISTBOX_MakeItemVisible( LB_DESCR *descr, INT index, BOOL fully ) +{ + INT top; + + TRACE("current top item %d, index %d, fully %d\n", descr->top_item, index, fully); + + if (index <= descr->top_item) top = index; + else if (descr->style & LBS_MULTICOLUMN) + { + INT cols = descr->width; + if (!fully) cols += descr->column_width - 1; + if (cols >= descr->column_width) cols /= descr->column_width; + else cols = 1; + if (index < descr->top_item + (descr->page_size * cols)) return; + top = index - descr->page_size * (cols - 1); + } + else if (descr->style & LBS_OWNERDRAWVARIABLE) + { + INT height = fully ? descr->items[index].height : 1; + for (top = index; top > descr->top_item; top--) + if ((height += descr->items[top-1].height) > descr->height) break; + } + else + { + if (index < descr->top_item + descr->page_size) return; + if (!fully && (index == descr->top_item + descr->page_size) && + (descr->height > (descr->page_size * descr->item_height))) return; + top = index - descr->page_size + 1; + } + LISTBOX_SetTopItem( descr, top, TRUE ); +} + +/*********************************************************************** + * LISTBOX_SetCaretIndex + * + * NOTES + * index must be between 0 and descr->nb_items-1, or LB_ERR is returned. + * + */ +static LRESULT LISTBOX_SetCaretIndex( LB_DESCR *descr, INT index, BOOL fully_visible ) +{ + INT oldfocus = descr->focus_item; + + TRACE("old focus %d, index %d\n", oldfocus, index); + + if (descr->style & LBS_NOSEL) return LB_ERR; + if ((index < 0) || (index >= descr->nb_items)) return LB_ERR; + if (index == oldfocus) return LB_OKAY; + + LISTBOX_DrawFocusRect( descr, FALSE ); + descr->focus_item = index; + + LISTBOX_MakeItemVisible( descr, index, fully_visible ); + LISTBOX_DrawFocusRect( descr, TRUE ); + + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_SelectItemRange + * + * Select a range of items. Should only be used on a MULTIPLESEL listbox. + */ +static LRESULT LISTBOX_SelectItemRange( LB_DESCR *descr, INT first, + INT last, BOOL on ) +{ + INT i; + + /* A few sanity checks */ + + if (descr->style & LBS_NOSEL) return LB_ERR; + if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR; + + if (!descr->nb_items) return LB_OKAY; + + if (last == -1 || last >= descr->nb_items) last = descr->nb_items - 1; + if (first < 0) first = 0; + if (last < first) return LB_OKAY; + + if (on) /* Turn selection on */ + { + for (i = first; i <= last; i++) + { + if (descr->items[i].selected) continue; + descr->items[i].selected = TRUE; + LISTBOX_InvalidateItemRect(descr, i); + } + } + else /* Turn selection off */ + { + for (i = first; i <= last; i++) + { + if (!descr->items[i].selected) continue; + descr->items[i].selected = FALSE; + LISTBOX_InvalidateItemRect(descr, i); + } + } + return LB_OKAY; +} + +/*********************************************************************** + * LISTBOX_SetSelection + */ +static LRESULT LISTBOX_SetSelection( LB_DESCR *descr, INT index, + BOOL on, BOOL send_notify ) +{ + TRACE( "cur_sel=%d index=%d notify=%s\n", + descr->selected_item, index, send_notify ? "YES" : "NO" ); + + if (descr->style & LBS_NOSEL) + { + descr->selected_item = index; + return LB_ERR; + } + if ((index < -1) || (index >= descr->nb_items)) return LB_ERR; + if (descr->style & LBS_MULTIPLESEL) + { + if (index == -1) /* Select all items */ + return LISTBOX_SelectItemRange( descr, 0, descr->nb_items, on ); + else /* Only one item */ + return LISTBOX_SelectItemRange( descr, index, index, on ); + } + else + { + INT oldsel = descr->selected_item; + if (index == oldsel) return LB_OKAY; + if (oldsel != -1) descr->items[oldsel].selected = FALSE; + if (index != -1) descr->items[index].selected = TRUE; + if (oldsel != -1) LISTBOX_RepaintItem( descr, oldsel, ODA_SELECT ); + descr->selected_item = index; + if (index != -1) LISTBOX_RepaintItem( descr, index, ODA_SELECT ); + if (send_notify && descr->nb_items) SEND_NOTIFICATION( descr, + (index != -1) ? LBN_SELCHANGE : LBN_SELCANCEL ); + else + if( descr->lphc ) /* set selection change flag for parent combo */ + descr->lphc->wState |= CBF_SELCHANGE; + } + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_MoveCaret + * + * Change the caret position and extend the selection to the new caret. + */ +static void LISTBOX_MoveCaret( LB_DESCR *descr, INT index, BOOL fully_visible ) +{ + TRACE("old focus %d, index %d\n", descr->focus_item, index); + + if ((index < 0) || (index >= descr->nb_items)) + return; + + /* Important, repaint needs to be done in this order if + you want to mimic Windows behavior: + 1. Remove the focus and paint the item + 2. Remove the selection and paint the item(s) + 3. Set the selection and repaint the item(s) + 4. Set the focus to 'index' and repaint the item */ + + /* 1. remove the focus and repaint the item */ + LISTBOX_DrawFocusRect( descr, FALSE ); + + /* 2. then turn off the previous selection */ + /* 3. repaint the new selected item */ + if (descr->style & LBS_EXTENDEDSEL) + { + if (descr->anchor_item != -1) + { + INT first = min( index, descr->anchor_item ); + INT last = max( index, descr->anchor_item ); + if (first > 0) + LISTBOX_SelectItemRange( descr, 0, first - 1, FALSE ); + LISTBOX_SelectItemRange( descr, last + 1, -1, FALSE ); + LISTBOX_SelectItemRange( descr, first, last, TRUE ); + } + } + else if (!(descr->style & LBS_MULTIPLESEL)) + { + /* Set selection to new caret item */ + LISTBOX_SetSelection( descr, index, TRUE, FALSE ); + } + + /* 4. repaint the new item with the focus */ + descr->focus_item = index; + LISTBOX_MakeItemVisible( descr, index, fully_visible ); + LISTBOX_DrawFocusRect( descr, TRUE ); +} + + +/*********************************************************************** + * LISTBOX_InsertItem + */ +static LRESULT LISTBOX_InsertItem( LB_DESCR *descr, INT index, + LPWSTR str, ULONG_PTR data ) +{ + LB_ITEMDATA *item; + INT max_items; + INT oldfocus = descr->focus_item; + + if (index == -1) index = descr->nb_items; + else if ((index < 0) || (index > descr->nb_items)) return LB_ERR; + if (!descr->items) max_items = 0; + else max_items = HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(*item); + if (descr->nb_items == max_items) + { + /* We need to grow the array */ + max_items += LB_ARRAY_GRANULARITY; + if (descr->items) + item = HeapReAlloc( GetProcessHeap(), 0, descr->items, + max_items * sizeof(LB_ITEMDATA) ); + else + item = HeapAlloc( GetProcessHeap(), 0, + max_items * sizeof(LB_ITEMDATA) ); + if (!item) + { + SEND_NOTIFICATION( descr, LBN_ERRSPACE ); + return LB_ERRSPACE; + } + descr->items = item; + } + + /* Insert the item structure */ + + item = &descr->items[index]; + if (index < descr->nb_items) + RtlMoveMemory( item + 1, item, + (descr->nb_items - index) * sizeof(LB_ITEMDATA) ); + item->str = str; + item->data = data; + item->height = 0; + item->selected = FALSE; + descr->nb_items++; + + /* Get item height */ + + if (descr->style & LBS_OWNERDRAWVARIABLE) + { + MEASUREITEMSTRUCT mis; + UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID ); + + mis.CtlType = ODT_LISTBOX; + mis.CtlID = id; + mis.itemID = index; + mis.itemData = descr->items[index].data; + mis.itemHeight = descr->item_height; + SendMessageW( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis ); + item->height = mis.itemHeight ? mis.itemHeight : 1; + TRACE("[%p]: measure item %d (%s) = %d\n", + descr->self, index, str ? debugstr_w(str) : "", item->height ); + } + + /* Repaint the items */ + + LISTBOX_UpdateScroll( descr ); + LISTBOX_InvalidateItems( descr, index ); + + /* Move selection and focused item */ + /* If listbox was empty, set focus to the first item */ + if (descr->nb_items == 1) + LISTBOX_SetCaretIndex( descr, 0, FALSE ); + /* single select don't change selection index in win31 */ + else if ((ISWIN31) && !(IS_MULTISELECT(descr))) + { + descr->selected_item++; + LISTBOX_SetSelection( descr, descr->selected_item-1, TRUE, FALSE ); + } + else + { + if (index <= descr->selected_item) + { + descr->selected_item++; + descr->focus_item = oldfocus; /* focus not changed */ + } + } + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_InsertString + */ +static LRESULT LISTBOX_InsertString( LB_DESCR *descr, INT index, LPCWSTR str ) +{ + LPWSTR new_str = NULL; + ULONG_PTR data = 0; + LRESULT ret; + + if (HAS_STRINGS(descr)) + { + static const WCHAR empty_stringW[] = { 0 }; + if (!str) str = empty_stringW; + if (!(new_str = HeapAlloc( GetProcessHeap(), 0, (strlenW(str) + 1) * sizeof(WCHAR) ))) + { + SEND_NOTIFICATION( descr, LBN_ERRSPACE ); + return LB_ERRSPACE; + } + strcpyW(new_str, str); + } + else data = (ULONG_PTR)str; + + if (index == -1) index = descr->nb_items; + if ((ret = LISTBOX_InsertItem( descr, index, new_str, data )) != 0) + { + HeapFree( GetProcessHeap(), 0, new_str ); + return ret; + } + + TRACE("[%p]: added item %d %s\n", + descr->self, index, HAS_STRINGS(descr) ? debugstr_w(new_str) : "" ); + return index; +} + + +/*********************************************************************** + * LISTBOX_DeleteItem + * + * Delete the content of an item. 'index' must be a valid index. + */ +static void LISTBOX_DeleteItem( LB_DESCR *descr, INT index ) +{ + /* save the item data before it gets freed by LB_RESETCONTENT */ + ULONG_PTR item_data = descr->items[index].data; + LPWSTR item_str = descr->items[index].str; + + if (!descr->nb_items) + SendMessageW( descr->self, LB_RESETCONTENT, 0, 0 ); + + /* Note: Win 3.1 only sends DELETEITEM on owner-draw items, + * while Win95 sends it for all items with user data. + * It's probably better to send it too often than not + * often enough, so this is what we do here. + */ + if (IS_OWNERDRAW(descr) || item_data) + { + DELETEITEMSTRUCT dis; + UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID ); + + dis.CtlType = ODT_LISTBOX; + dis.CtlID = id; + dis.itemID = index; + dis.hwndItem = descr->self; + dis.itemData = item_data; + SendMessageW( descr->owner, WM_DELETEITEM, id, (LPARAM)&dis ); + } + if (HAS_STRINGS(descr)) + HeapFree( GetProcessHeap(), 0, item_str ); +} + + +/*********************************************************************** + * LISTBOX_RemoveItem + * + * Remove an item from the listbox and delete its content. + */ +static LRESULT LISTBOX_RemoveItem( LB_DESCR *descr, INT index ) +{ + LB_ITEMDATA *item; + INT max_items; + + if ((index < 0) || (index >= descr->nb_items)) return LB_ERR; + + /* We need to invalidate the original rect instead of the updated one. */ + LISTBOX_InvalidateItems( descr, index ); + + descr->nb_items--; + LISTBOX_DeleteItem( descr, index ); + + if (!descr->nb_items) return LB_OKAY; + + /* Remove the item */ + + item = &descr->items[index]; + if (index < descr->nb_items) + RtlMoveMemory( item, item + 1, + (descr->nb_items - index) * sizeof(LB_ITEMDATA) ); + if (descr->anchor_item == descr->nb_items) descr->anchor_item--; + + /* Shrink the item array if possible */ + + max_items = HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(LB_ITEMDATA); + if (descr->nb_items < max_items - 2*LB_ARRAY_GRANULARITY) + { + max_items -= LB_ARRAY_GRANULARITY; + item = HeapReAlloc( GetProcessHeap(), 0, descr->items, + max_items * sizeof(LB_ITEMDATA) ); + if (item) descr->items = item; + } + /* Repaint the items */ + + LISTBOX_UpdateScroll( descr ); + /* if we removed the scrollbar, reset the top of the list + (correct for owner-drawn ???) */ + if (descr->nb_items == descr->page_size) + LISTBOX_SetTopItem( descr, 0, TRUE ); + + /* Move selection and focused item */ + if (!IS_MULTISELECT(descr)) + { + if (index == descr->selected_item) + descr->selected_item = -1; + else if (index < descr->selected_item) + { + descr->selected_item--; + if (ISWIN31) /* win 31 do not change the selected item number */ + LISTBOX_SetSelection( descr, descr->selected_item + 1, TRUE, FALSE); + } + } + + if (descr->focus_item >= descr->nb_items) + { + descr->focus_item = descr->nb_items - 1; + if (descr->focus_item < 0) descr->focus_item = 0; + } + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_ResetContent + */ +static void LISTBOX_ResetContent( LB_DESCR *descr ) +{ + INT i; + + for(i = descr->nb_items - 1; i>=0; i--) LISTBOX_DeleteItem( descr, i); + HeapFree( GetProcessHeap(), 0, descr->items ); + descr->nb_items = 0; + descr->top_item = 0; + descr->selected_item = -1; + descr->focus_item = 0; + descr->anchor_item = -1; + descr->items = NULL; +} + + +/*********************************************************************** + * LISTBOX_SetCount + */ +static LRESULT LISTBOX_SetCount( LB_DESCR *descr, INT count ) +{ + LRESULT ret; + + if (HAS_STRINGS(descr)) + { + SetLastError(ERROR_SETCOUNT_ON_BAD_LB); + return LB_ERR; + } + + /* FIXME: this is far from optimal... */ + if (count > descr->nb_items) + { + while (count > descr->nb_items) + if ((ret = LISTBOX_InsertString( descr, -1, 0 )) < 0) + return ret; + } + else if (count < descr->nb_items) + { + while (count < descr->nb_items) + if ((ret = LISTBOX_RemoveItem( descr, (descr->nb_items - 1) )) < 0) + return ret; + } + + InvalidateRect( descr->self, NULL, TRUE ); + return LB_OKAY; +} + + +/*********************************************************************** + * LISTBOX_Directory + */ +static LRESULT LISTBOX_Directory( LB_DESCR *descr, UINT attrib, + LPCWSTR filespec, BOOL long_names ) +{ + HANDLE handle; + LRESULT ret = LB_OKAY; + WIN32_FIND_DATAW entry; + int pos; + LRESULT maxinsert = LB_ERR; + + /* don't scan directory if we just want drives exclusively */ + if (attrib != (DDL_DRIVES | DDL_EXCLUSIVE)) { + /* scan directory */ + if ((handle = FindFirstFileW(filespec, &entry)) == INVALID_HANDLE_VALUE) + { + int le = GetLastError(); + if ((le != ERROR_NO_MORE_FILES) && (le != ERROR_FILE_NOT_FOUND)) return LB_ERR; + } + else + { + do + { + WCHAR buffer[270]; + if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + static const WCHAR bracketW[] = { ']',0 }; + static const WCHAR dotW[] = { '.',0 }; + if (!(attrib & DDL_DIRECTORY) || + !strcmpW( entry.cFileName, dotW )) continue; + buffer[0] = '['; + if (!long_names && entry.cAlternateFileName[0]) + strcpyW( buffer + 1, entry.cAlternateFileName ); + else + strcpyW( buffer + 1, entry.cFileName ); + strcatW(buffer, bracketW); + } + else /* not a directory */ + { +#define ATTRIBS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \ + FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE) + + if ((attrib & DDL_EXCLUSIVE) && + ((attrib & ATTRIBS) != (entry.dwFileAttributes & ATTRIBS))) + continue; +#undef ATTRIBS + if (!long_names && entry.cAlternateFileName[0]) + strcpyW( buffer, entry.cAlternateFileName ); + else + strcpyW( buffer, entry.cFileName ); + } + if (!long_names) CharLowerW( buffer ); + pos = LISTBOX_FindFileStrPos( descr, buffer ); + if ((ret = LISTBOX_InsertString( descr, pos, buffer )) < 0) + break; + if (ret <= maxinsert) maxinsert++; else maxinsert = ret; + } while (FindNextFileW( handle, &entry )); + FindClose( handle ); + } + } + if (ret >= 0) + { + ret = maxinsert; + + /* scan drives */ + if (attrib & DDL_DRIVES) + { + WCHAR buffer[] = {'[','-','a','-',']',0}; + WCHAR root[] = {'A',':','\\',0}; + int drive; + for (drive = 0; drive < 26; drive++, buffer[2]++, root[0]++) + { + if (GetDriveTypeW(root) <= DRIVE_NO_ROOT_DIR) continue; + if ((ret = LISTBOX_InsertString( descr, -1, buffer )) < 0) + break; + } + } + } + return ret; +} + + +/*********************************************************************** + * LISTBOX_HandleVScroll + */ +static LRESULT LISTBOX_HandleVScroll( LB_DESCR *descr, WORD scrollReq, WORD pos ) +{ + SCROLLINFO info; + + if (descr->style & LBS_MULTICOLUMN) return 0; + switch(scrollReq) + { + case SB_LINEUP: + LISTBOX_SetTopItem( descr, descr->top_item - 1, TRUE ); + break; + case SB_LINEDOWN: + LISTBOX_SetTopItem( descr, descr->top_item + 1, TRUE ); + break; + case SB_PAGEUP: + LISTBOX_SetTopItem( descr, descr->top_item - + LISTBOX_GetCurrentPageSize( descr ), TRUE ); + break; + case SB_PAGEDOWN: + LISTBOX_SetTopItem( descr, descr->top_item + + LISTBOX_GetCurrentPageSize( descr ), TRUE ); + break; + case SB_THUMBPOSITION: + LISTBOX_SetTopItem( descr, pos, TRUE ); + break; + case SB_THUMBTRACK: + info.cbSize = sizeof(info); + info.fMask = SIF_TRACKPOS; + GetScrollInfo( descr->self, SB_VERT, &info ); + LISTBOX_SetTopItem( descr, info.nTrackPos, TRUE ); + break; + case SB_TOP: + LISTBOX_SetTopItem( descr, 0, TRUE ); + break; + case SB_BOTTOM: + LISTBOX_SetTopItem( descr, descr->nb_items, TRUE ); + break; + } + return 0; +} + + +/*********************************************************************** + * LISTBOX_HandleHScroll + */ +static LRESULT LISTBOX_HandleHScroll( LB_DESCR *descr, WORD scrollReq, WORD pos ) +{ + SCROLLINFO info; + INT page; + + if (descr->style & LBS_MULTICOLUMN) + { + switch(scrollReq) + { + case SB_LINELEFT: + LISTBOX_SetTopItem( descr, descr->top_item-descr->page_size, + TRUE ); + break; + case SB_LINERIGHT: + LISTBOX_SetTopItem( descr, descr->top_item+descr->page_size, + TRUE ); + break; + case SB_PAGELEFT: + page = descr->width / descr->column_width; + if (page < 1) page = 1; + LISTBOX_SetTopItem( descr, + descr->top_item - page * descr->page_size, TRUE ); + break; + case SB_PAGERIGHT: + page = descr->width / descr->column_width; + if (page < 1) page = 1; + LISTBOX_SetTopItem( descr, + descr->top_item + page * descr->page_size, TRUE ); + break; + case SB_THUMBPOSITION: + LISTBOX_SetTopItem( descr, pos*descr->page_size, TRUE ); + break; + case SB_THUMBTRACK: + info.cbSize = sizeof(info); + info.fMask = SIF_TRACKPOS; + GetScrollInfo( descr->self, SB_VERT, &info ); + LISTBOX_SetTopItem( descr, info.nTrackPos*descr->page_size, + TRUE ); + break; + case SB_LEFT: + LISTBOX_SetTopItem( descr, 0, TRUE ); + break; + case SB_RIGHT: + LISTBOX_SetTopItem( descr, descr->nb_items, TRUE ); + break; + } + } + else if (descr->horz_extent) + { + switch(scrollReq) + { + case SB_LINELEFT: + LISTBOX_SetHorizontalPos( descr, descr->horz_pos - 1 ); + break; + case SB_LINERIGHT: + LISTBOX_SetHorizontalPos( descr, descr->horz_pos + 1 ); + break; + case SB_PAGELEFT: + LISTBOX_SetHorizontalPos( descr, + descr->horz_pos - descr->width ); + break; + case SB_PAGERIGHT: + LISTBOX_SetHorizontalPos( descr, + descr->horz_pos + descr->width ); + break; + case SB_THUMBPOSITION: + LISTBOX_SetHorizontalPos( descr, pos ); + break; + case SB_THUMBTRACK: + info.cbSize = sizeof(info); + info.fMask = SIF_TRACKPOS; + GetScrollInfo( descr->self, SB_HORZ, &info ); + LISTBOX_SetHorizontalPos( descr, info.nTrackPos ); + break; + case SB_LEFT: + LISTBOX_SetHorizontalPos( descr, 0 ); + break; + case SB_RIGHT: + LISTBOX_SetHorizontalPos( descr, + descr->horz_extent - descr->width ); + break; + } + } + return 0; +} + +static LRESULT LISTBOX_HandleMouseWheel(LB_DESCR *descr, SHORT delta ) +{ + UINT pulScrollLines = 3; + + SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0); + + /* if scrolling changes direction, ignore left overs */ + if ((delta < 0 && descr->wheel_remain < 0) || + (delta > 0 && descr->wheel_remain > 0)) + descr->wheel_remain += delta; + else + descr->wheel_remain = delta; + + if (descr->wheel_remain && pulScrollLines) + { + int cLineScroll; + pulScrollLines = min((UINT) descr->page_size, pulScrollLines); + cLineScroll = pulScrollLines * (float)descr->wheel_remain / WHEEL_DELTA; + descr->wheel_remain -= WHEEL_DELTA * cLineScroll / (int)pulScrollLines; + LISTBOX_SetTopItem( descr, descr->top_item - cLineScroll, TRUE ); + } + return 0; +} + +/*********************************************************************** + * LISTBOX_HandleLButtonDown + */ +static LRESULT LISTBOX_HandleLButtonDown( LB_DESCR *descr, DWORD keys, INT x, INT y ) +{ + INT index = LISTBOX_GetItemFromPoint( descr, x, y ); + + TRACE("[%p]: lbuttondown %d,%d item %d, focus item %d\n", + descr->self, x, y, index, descr->focus_item); + + if (!descr->caret_on && (descr->in_focus)) return 0; + + if (!descr->in_focus) + { + if( !descr->lphc ) SetFocus( descr->self ); + else SetFocus( (descr->lphc->hWndEdit) ? descr->lphc->hWndEdit : descr->lphc->self ); + } + + if (index == -1) return 0; + + if (!descr->lphc) + { + if (descr->style & LBS_NOTIFY ) + SendMessageW( descr->owner, WM_LBTRACKPOINT, index, + MAKELPARAM( x, y ) ); + } + + descr->captured = TRUE; + SetCapture( descr->self ); + + if (descr->style & (LBS_EXTENDEDSEL | LBS_MULTIPLESEL)) + { + /* we should perhaps make sure that all items are deselected + FIXME: needed for !LBS_EXTENDEDSEL, too ? + if (!(keys & (MK_SHIFT|MK_CONTROL))) + LISTBOX_SetSelection( descr, -1, FALSE, FALSE); + */ + + if (!(keys & MK_SHIFT)) descr->anchor_item = index; + if (keys & MK_CONTROL) + { + LISTBOX_SetCaretIndex( descr, index, FALSE ); + LISTBOX_SetSelection( descr, index, + !descr->items[index].selected, + (descr->style & LBS_NOTIFY) != 0); + } + else + { + LISTBOX_MoveCaret( descr, index, FALSE ); + + if (descr->style & LBS_EXTENDEDSEL) + { + LISTBOX_SetSelection( descr, index, + descr->items[index].selected, + (descr->style & LBS_NOTIFY) != 0 ); + } + else + { + LISTBOX_SetSelection( descr, index, + !descr->items[index].selected, + (descr->style & LBS_NOTIFY) != 0 ); + } + } + } + else + { + descr->anchor_item = index; + LISTBOX_MoveCaret( descr, index, FALSE ); + LISTBOX_SetSelection( descr, index, + TRUE, (descr->style & LBS_NOTIFY) != 0 ); + } + + if (!descr->lphc) + { + if (GetWindowLongW( descr->self, GWL_EXSTYLE ) & WS_EX_DRAGDETECT) + { + POINT pt; + + pt.x = x; + pt.y = y; + + if (DragDetect( descr->self, pt )) + SendMessageW( descr->owner, WM_BEGINDRAG, 0, 0 ); + } + } + return 0; +} + + +/************************************************************************* + * LISTBOX_HandleLButtonDownCombo [Internal] + * + * Process LButtonDown message for the ComboListBox + * + * PARAMS + * pWnd [I] The windows internal structure + * pDescr [I] The ListBox internal structure + * keys [I] Key Flag (WM_LBUTTONDOWN doc for more info) + * x [I] X Mouse Coordinate + * y [I] Y Mouse Coordinate + * + * RETURNS + * 0 since we are processing the WM_LBUTTONDOWN Message + * + * NOTES + * This function is only to be used when a ListBox is a ComboListBox + */ + +static LRESULT LISTBOX_HandleLButtonDownCombo( LB_DESCR *descr, UINT msg, DWORD keys, INT x, INT y) +{ + RECT clientRect, screenRect; + POINT mousePos; + + mousePos.x = x; + mousePos.y = y; + + GetClientRect(descr->self, &clientRect); + + if(PtInRect(&clientRect, mousePos)) + { + /* MousePos is in client, resume normal processing */ + if (msg == WM_LBUTTONDOWN) + { + descr->lphc->droppedIndex = descr->nb_items ? descr->selected_item : -1; + return LISTBOX_HandleLButtonDown( descr, keys, x, y); + } + else if (descr->style & LBS_NOTIFY) + SEND_NOTIFICATION( descr, LBN_DBLCLK ); + } + else + { + POINT screenMousePos; + HWND hWndOldCapture; + + /* Check the Non-Client Area */ + screenMousePos = mousePos; + hWndOldCapture = GetCapture(); + ReleaseCapture(); + GetWindowRect(descr->self, &screenRect); + ClientToScreen(descr->self, &screenMousePos); + + if(!PtInRect(&screenRect, screenMousePos)) + { + LISTBOX_SetCaretIndex( descr, descr->lphc->droppedIndex, FALSE ); + LISTBOX_SetSelection( descr, descr->lphc->droppedIndex, FALSE, FALSE ); + COMBO_FlipListbox( descr->lphc, FALSE, FALSE ); + } + else + { + /* Check to see the NC is a scrollbar */ + INT nHitTestType=0; + LONG style = GetWindowLongW( descr->self, GWL_STYLE ); + /* Check Vertical scroll bar */ + if (style & WS_VSCROLL) + { + clientRect.right += GetSystemMetrics(SM_CXVSCROLL); + if (PtInRect( &clientRect, mousePos )) + nHitTestType = HTVSCROLL; + } + /* Check horizontal scroll bar */ + if (style & WS_HSCROLL) + { + clientRect.bottom += GetSystemMetrics(SM_CYHSCROLL); + if (PtInRect( &clientRect, mousePos )) + nHitTestType = HTHSCROLL; + } + /* Windows sends this message when a scrollbar is clicked + */ + + if(nHitTestType != 0) + { + SendMessageW(descr->self, WM_NCLBUTTONDOWN, nHitTestType, + MAKELONG(screenMousePos.x, screenMousePos.y)); + } + /* Resume the Capture after scrolling is complete + */ + if(hWndOldCapture != 0) + SetCapture(hWndOldCapture); + } + } + return 0; +} + +/*********************************************************************** + * LISTBOX_HandleLButtonUp + */ +static LRESULT LISTBOX_HandleLButtonUp( LB_DESCR *descr ) +{ + if (LISTBOX_Timer != LB_TIMER_NONE) + KillSystemTimer( descr->self, LB_TIMER_ID ); + LISTBOX_Timer = LB_TIMER_NONE; + if (descr->captured) + { + descr->captured = FALSE; + if (GetCapture() == descr->self) ReleaseCapture(); + if ((descr->style & LBS_NOTIFY) && descr->nb_items) + SEND_NOTIFICATION( descr, LBN_SELCHANGE ); + } + return 0; +} + + +/*********************************************************************** + * LISTBOX_HandleTimer + * + * Handle scrolling upon a timer event. + * Return TRUE if scrolling should continue. + */ +static LRESULT LISTBOX_HandleTimer( LB_DESCR *descr, INT index, TIMER_DIRECTION dir ) +{ + switch(dir) + { + case LB_TIMER_UP: + if (descr->top_item) index = descr->top_item - 1; + else index = 0; + break; + case LB_TIMER_LEFT: + if (descr->top_item) index -= descr->page_size; + break; + case LB_TIMER_DOWN: + index = descr->top_item + LISTBOX_GetCurrentPageSize( descr ); + if (index == descr->focus_item) index++; + if (index >= descr->nb_items) index = descr->nb_items - 1; + break; + case LB_TIMER_RIGHT: + if (index + descr->page_size < descr->nb_items) + index += descr->page_size; + break; + case LB_TIMER_NONE: + break; + } + if (index == descr->focus_item) return FALSE; + LISTBOX_MoveCaret( descr, index, FALSE ); + return TRUE; +} + + +/*********************************************************************** + * LISTBOX_HandleSystemTimer + * + * WM_SYSTIMER handler. + */ +static LRESULT LISTBOX_HandleSystemTimer( LB_DESCR *descr ) +{ + if (!LISTBOX_HandleTimer( descr, descr->focus_item, LISTBOX_Timer )) + { + KillSystemTimer( descr->self, LB_TIMER_ID ); + LISTBOX_Timer = LB_TIMER_NONE; + } + return 0; +} + + +/*********************************************************************** + * LISTBOX_HandleMouseMove + * + * WM_MOUSEMOVE handler. + */ +static void LISTBOX_HandleMouseMove( LB_DESCR *descr, + INT x, INT y ) +{ + INT index; + TIMER_DIRECTION dir = LB_TIMER_NONE; + + if (!descr->captured) return; + + if (descr->style & LBS_MULTICOLUMN) + { + if (y < 0) y = 0; + else if (y >= descr->item_height * descr->page_size) + y = descr->item_height * descr->page_size - 1; + + if (x < 0) + { + dir = LB_TIMER_LEFT; + x = 0; + } + else if (x >= descr->width) + { + dir = LB_TIMER_RIGHT; + x = descr->width - 1; + } + } + else + { + if (y < 0) dir = LB_TIMER_UP; /* above */ + else if (y >= descr->height) dir = LB_TIMER_DOWN; /* below */ + } + + index = LISTBOX_GetItemFromPoint( descr, x, y ); + if (index == -1) index = descr->focus_item; + if (!LISTBOX_HandleTimer( descr, index, dir )) dir = LB_TIMER_NONE; + + /* Start/stop the system timer */ + + if (dir != LB_TIMER_NONE) + SetSystemTimer( descr->self, LB_TIMER_ID, LB_SCROLL_TIMEOUT, NULL); + else if (LISTBOX_Timer != LB_TIMER_NONE) + KillSystemTimer( descr->self, LB_TIMER_ID ); + LISTBOX_Timer = dir; +} + + +/*********************************************************************** + * LISTBOX_HandleKeyDown + */ +static LRESULT LISTBOX_HandleKeyDown( LB_DESCR *descr, DWORD key ) +{ + INT caret = -1; + BOOL bForceSelection = TRUE; /* select item pointed to by focus_item */ + if ((IS_MULTISELECT(descr)) || (descr->selected_item == descr->focus_item)) + bForceSelection = FALSE; /* only for single select list */ + + if (descr->style & LBS_WANTKEYBOARDINPUT) + { + caret = SendMessageW( descr->owner, WM_VKEYTOITEM, + MAKEWPARAM(LOWORD(key), descr->focus_item), + (LPARAM)descr->self ); + if (caret == -2) return 0; + } + if (caret == -1) switch(key) + { + case VK_LEFT: + if (descr->style & LBS_MULTICOLUMN) + { + bForceSelection = FALSE; + if (descr->focus_item >= descr->page_size) + caret = descr->focus_item - descr->page_size; + break; + } + /* fall through */ + case VK_UP: + caret = descr->focus_item - 1; + if (caret < 0) caret = 0; + break; + case VK_RIGHT: + if (descr->style & LBS_MULTICOLUMN) + { + bForceSelection = FALSE; + if (descr->focus_item + descr->page_size < descr->nb_items) + caret = descr->focus_item + descr->page_size; + break; + } + /* fall through */ + case VK_DOWN: + caret = descr->focus_item + 1; + if (caret >= descr->nb_items) caret = descr->nb_items - 1; + break; + + case VK_PRIOR: + if (descr->style & LBS_MULTICOLUMN) + { + INT page = descr->width / descr->column_width; + if (page < 1) page = 1; + caret = descr->focus_item - (page * descr->page_size) + 1; + } + else caret = descr->focus_item-LISTBOX_GetCurrentPageSize(descr) + 1; + if (caret < 0) caret = 0; + break; + case VK_NEXT: + if (descr->style & LBS_MULTICOLUMN) + { + INT page = descr->width / descr->column_width; + if (page < 1) page = 1; + caret = descr->focus_item + (page * descr->page_size) - 1; + } + else caret = descr->focus_item + LISTBOX_GetCurrentPageSize(descr) - 1; + if (caret >= descr->nb_items) caret = descr->nb_items - 1; + break; + case VK_HOME: + caret = 0; + break; + case VK_END: + caret = descr->nb_items - 1; + break; + case VK_SPACE: + if (descr->style & LBS_EXTENDEDSEL) caret = descr->focus_item; + else if (descr->style & LBS_MULTIPLESEL) + { + LISTBOX_SetSelection( descr, descr->focus_item, + !descr->items[descr->focus_item].selected, + (descr->style & LBS_NOTIFY) != 0 ); + } + break; + default: + bForceSelection = FALSE; + } + if (bForceSelection) /* focused item is used instead of key */ + caret = descr->focus_item; + if (caret >= 0) + { + if (((descr->style & LBS_EXTENDEDSEL) && + !(GetKeyState( VK_SHIFT ) & 0x8000)) || + !IS_MULTISELECT(descr)) + descr->anchor_item = caret; + LISTBOX_MoveCaret( descr, caret, TRUE ); + + if (descr->style & LBS_MULTIPLESEL) + descr->selected_item = caret; + else + LISTBOX_SetSelection( descr, caret, TRUE, FALSE); + if (descr->style & LBS_NOTIFY) + { + if (descr->lphc && IsWindowVisible( descr->self )) + { + /* make sure that combo parent doesn't hide us */ + descr->lphc->wState |= CBF_NOROLLUP; + } + if (descr->nb_items) SEND_NOTIFICATION( descr, LBN_SELCHANGE ); + } + } + return 0; +} + + +/*********************************************************************** + * LISTBOX_HandleChar + */ +static LRESULT LISTBOX_HandleChar( LB_DESCR *descr, WCHAR charW ) +{ + INT caret = -1; + WCHAR str[2]; + + str[0] = charW; + str[1] = '\0'; + + if (descr->style & LBS_WANTKEYBOARDINPUT) + { + caret = SendMessageW( descr->owner, WM_CHARTOITEM, + MAKEWPARAM(charW, descr->focus_item), + (LPARAM)descr->self ); + if (caret == -2) return 0; + } + if (caret == -1) + caret = LISTBOX_FindString( descr, descr->focus_item, str, FALSE); + if (caret != -1) + { + if ((!IS_MULTISELECT(descr)) && descr->selected_item == -1) + LISTBOX_SetSelection( descr, caret, TRUE, FALSE); + LISTBOX_MoveCaret( descr, caret, TRUE ); + if ((descr->style & LBS_NOTIFY) && descr->nb_items) + SEND_NOTIFICATION( descr, LBN_SELCHANGE ); + } + return 0; +} + + +/*********************************************************************** + * LISTBOX_Create + */ +static BOOL LISTBOX_Create( HWND hwnd, LPHEADCOMBO lphc ) +{ + LB_DESCR *descr; + MEASUREITEMSTRUCT mis; + RECT rect; + + if (!(descr = HeapAlloc( GetProcessHeap(), 0, sizeof(*descr) ))) + return FALSE; + + GetClientRect( hwnd, &rect ); + descr->self = hwnd; + descr->owner = GetParent( descr->self ); + descr->style = GetWindowLongW( descr->self, GWL_STYLE ); + descr->width = rect.right - rect.left; + descr->height = rect.bottom - rect.top; + descr->items = NULL; + descr->nb_items = 0; + descr->top_item = 0; + descr->selected_item = -1; + descr->focus_item = 0; + descr->anchor_item = -1; + descr->item_height = 1; + descr->page_size = 1; + descr->column_width = 150; + descr->horz_extent = 0; + descr->horz_pos = 0; + descr->nb_tabs = 0; + descr->tabs = NULL; + descr->wheel_remain = 0; + descr->caret_on = !lphc; + if (descr->style & LBS_NOSEL) descr->caret_on = FALSE; + descr->in_focus = FALSE; + descr->captured = FALSE; + descr->font = 0; + descr->locale = GetUserDefaultLCID(); + descr->lphc = lphc; + + if( lphc ) + { + TRACE("[%p]: resetting owner %p -> %p\n", descr->self, descr->owner, lphc->self ); + descr->owner = lphc->self; + } + + SetWindowLongPtrW( descr->self, 0, (LONG_PTR)descr ); + +/* if (wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) descr->style &= ~LBS_NOTIFY; + */ + if (descr->style & LBS_EXTENDEDSEL) descr->style |= LBS_MULTIPLESEL; + if (descr->style & LBS_MULTICOLUMN) descr->style &= ~LBS_OWNERDRAWVARIABLE; + if (descr->style & LBS_OWNERDRAWVARIABLE) descr->style |= LBS_NOINTEGRALHEIGHT; + descr->item_height = LISTBOX_SetFont( descr, 0 ); + + if (descr->style & LBS_OWNERDRAWFIXED) + { + if( descr->lphc && (descr->lphc->dwStyle & CBS_DROPDOWN)) + { + /* WinWord gets VERY unhappy if we send WM_MEASUREITEM from here */ + descr->item_height = lphc->fixedOwnerDrawHeight; + } + else + { + UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID ); + mis.CtlType = ODT_LISTBOX; + mis.CtlID = id; + mis.itemID = -1; + mis.itemWidth = 0; + mis.itemData = 0; + mis.itemHeight = descr->item_height; + SendMessageW( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis ); + descr->item_height = mis.itemHeight ? mis.itemHeight : 1; + } + } + + TRACE("owner: %p, style: %08x, width: %d, height: %d\n", descr->owner, descr->style, descr->width, descr->height); + return TRUE; +} + + +/*********************************************************************** + * LISTBOX_Destroy + */ +static BOOL LISTBOX_Destroy( LB_DESCR *descr ) +{ + LISTBOX_ResetContent( descr ); + SetWindowLongPtrW( descr->self, 0, 0 ); + HeapFree( GetProcessHeap(), 0, descr ); + return TRUE; +} + + +/*********************************************************************** + * ListBoxWndProc_common + */ +static LRESULT CALLBACK LISTBOX_WindowProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + LB_DESCR *descr = (LB_DESCR *)GetWindowLongPtrW( hwnd, 0 ); + LPHEADCOMBO lphc = 0; + LRESULT ret; + + if (!descr) + { + if (!IsWindow(hwnd)) return 0; + + if (msg == WM_CREATE) + { + CREATESTRUCTW *lpcs = (CREATESTRUCTW *)lParam; + if (lpcs->style & LBS_COMBOBOX) lphc = lpcs->lpCreateParams; + if (!LISTBOX_Create( hwnd, lphc )) return -1; + TRACE("creating hwnd %p descr %p\n", hwnd, (void *)GetWindowLongPtrW( hwnd, 0 ) ); + return 0; + } + /* Ignore all other messages before we get a WM_CREATE */ + return DefWindowProcW( hwnd, msg, wParam, lParam ); + } + if (descr->style & LBS_COMBOBOX) lphc = descr->lphc; + + TRACE("[%p]: msg %#x wp %08lx lp %08lx\n", descr->self, msg, wParam, lParam ); + + switch(msg) + { + case LB_RESETCONTENT: + LISTBOX_ResetContent( descr ); + LISTBOX_UpdateScroll( descr ); + InvalidateRect( descr->self, NULL, TRUE ); + return 0; + + case LB_ADDSTRING: + { + const WCHAR *textW = (const WCHAR *)lParam; + INT index = LISTBOX_FindStringPos( descr, textW, FALSE ); + return LISTBOX_InsertString( descr, index, textW ); + } + + case LB_INSERTSTRING: + return LISTBOX_InsertString( descr, wParam, (const WCHAR *)lParam ); + + case LB_ADDFILE: + { + const WCHAR *textW = (const WCHAR *)lParam; + INT index = LISTBOX_FindFileStrPos( descr, textW ); + return LISTBOX_InsertString( descr, index, textW ); + } + + case LB_DELETESTRING: + if (LISTBOX_RemoveItem( descr, wParam) != LB_ERR) + return descr->nb_items; + else + { + SetLastError(ERROR_INVALID_INDEX); + return LB_ERR; + } + + case LB_GETITEMDATA: + if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items)) + { + SetLastError(ERROR_INVALID_INDEX); + return LB_ERR; + } + return descr->items[wParam].data; + + case LB_SETITEMDATA: + if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items)) + { + SetLastError(ERROR_INVALID_INDEX); + return LB_ERR; + } + descr->items[wParam].data = lParam; + /* undocumented: returns TRUE, not LB_OKAY (0) */ + return TRUE; + + case LB_GETCOUNT: + return descr->nb_items; + + case LB_GETTEXT: + return LISTBOX_GetText( descr, wParam, (LPWSTR)lParam, TRUE ); + + case LB_GETTEXTLEN: + if ((INT)wParam >= descr->nb_items || (INT)wParam < 0) + { + SetLastError(ERROR_INVALID_INDEX); + return LB_ERR; + } + if (!HAS_STRINGS(descr)) return sizeof(DWORD); + return strlenW( descr->items[wParam].str ); + + case LB_GETCURSEL: + if (descr->nb_items == 0) + return LB_ERR; + if (!IS_MULTISELECT(descr)) + return descr->selected_item; + if (descr->selected_item != -1) + return descr->selected_item; + return descr->focus_item; + /* otherwise, if the user tries to move the selection with the */ + /* arrow keys, we will give the application something to choke on */ + case LB_GETTOPINDEX: + return descr->top_item; + + case LB_GETITEMHEIGHT: + return LISTBOX_GetItemHeight( descr, wParam ); + + case LB_SETITEMHEIGHT: + return LISTBOX_SetItemHeight( descr, wParam, lParam, TRUE ); + + case LB_ITEMFROMPOINT: + { + POINT pt; + RECT rect; + int index; + BOOL hit = TRUE; + + /* The hiword of the return value is not a client area + hittest as suggested by MSDN, but rather a hittest on + the returned listbox item. */ + + if(descr->nb_items == 0) + return 0x1ffff; /* win9x returns 0x10000, we copy winnt */ + + pt.x = (short)LOWORD(lParam); + pt.y = (short)HIWORD(lParam); + + SetRect(&rect, 0, 0, descr->width, descr->height); + + if(!PtInRect(&rect, pt)) + { + pt.x = min(pt.x, rect.right - 1); + pt.x = max(pt.x, 0); + pt.y = min(pt.y, rect.bottom - 1); + pt.y = max(pt.y, 0); + hit = FALSE; + } + + index = LISTBOX_GetItemFromPoint(descr, pt.x, pt.y); + + if(index == -1) + { + index = descr->nb_items - 1; + hit = FALSE; + } + return MAKELONG(index, hit ? 0 : 1); + } + + case LB_SETCARETINDEX: + if ((!IS_MULTISELECT(descr)) && (descr->selected_item != -1)) return LB_ERR; + if (LISTBOX_SetCaretIndex( descr, wParam, !lParam ) == LB_ERR) + return LB_ERR; + else if (ISWIN31) + return wParam; + else + return LB_OKAY; + + case LB_GETCARETINDEX: + return descr->focus_item; + + case LB_SETTOPINDEX: + return LISTBOX_SetTopItem( descr, wParam, TRUE ); + + case LB_SETCOLUMNWIDTH: + return LISTBOX_SetColumnWidth( descr, wParam ); + + case LB_GETITEMRECT: + return LISTBOX_GetItemRect( descr, wParam, (RECT *)lParam ); + + case LB_FINDSTRING: + return LISTBOX_FindString( descr, wParam, (const WCHAR *)lParam, FALSE ); + + case LB_FINDSTRINGEXACT: + return LISTBOX_FindString( descr, wParam, (const WCHAR *)lParam, TRUE ); + + case LB_SELECTSTRING: + { + const WCHAR *textW = (const WCHAR *)lParam; + INT index; + + if (HAS_STRINGS(descr)) + TRACE("LB_SELECTSTRING: %s\n", debugstr_w(textW)); + + index = LISTBOX_FindString( descr, wParam, textW, FALSE ); + if (index != LB_ERR) + { + LISTBOX_MoveCaret( descr, index, TRUE ); + LISTBOX_SetSelection( descr, index, TRUE, FALSE ); + } + return index; + } + + case LB_GETSEL: + if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items)) + return LB_ERR; + return descr->items[wParam].selected; + + case LB_SETSEL: + return LISTBOX_SetSelection( descr, lParam, wParam, FALSE ); + + case LB_SETCURSEL: + if (IS_MULTISELECT(descr)) return LB_ERR; + LISTBOX_SetCaretIndex( descr, wParam, TRUE ); + ret = LISTBOX_SetSelection( descr, wParam, TRUE, FALSE ); + if (ret != LB_ERR) ret = descr->selected_item; + return ret; + + case LB_GETSELCOUNT: + return LISTBOX_GetSelCount( descr ); + + case LB_GETSELITEMS: + return LISTBOX_GetSelItems( descr, wParam, (LPINT)lParam ); + + case LB_SELITEMRANGE: + if (LOWORD(lParam) <= HIWORD(lParam)) + return LISTBOX_SelectItemRange( descr, LOWORD(lParam), + HIWORD(lParam), wParam ); + else + return LISTBOX_SelectItemRange( descr, HIWORD(lParam), + LOWORD(lParam), wParam ); + + case LB_SELITEMRANGEEX: + if ((INT)lParam >= (INT)wParam) + return LISTBOX_SelectItemRange( descr, wParam, lParam, TRUE ); + else + return LISTBOX_SelectItemRange( descr, lParam, wParam, FALSE); + + case LB_GETHORIZONTALEXTENT: + return descr->horz_extent; + + case LB_SETHORIZONTALEXTENT: + return LISTBOX_SetHorizontalExtent( descr, wParam ); + + case LB_GETANCHORINDEX: + return descr->anchor_item; + + case LB_SETANCHORINDEX: + if (((INT)wParam < -1) || ((INT)wParam >= descr->nb_items)) + { + SetLastError(ERROR_INVALID_INDEX); + return LB_ERR; + } + descr->anchor_item = (INT)wParam; + return LB_OKAY; + + case LB_DIR: + return LISTBOX_Directory( descr, wParam, (const WCHAR *)lParam, msg == LB_DIR ); + + case LB_GETLOCALE: + return descr->locale; + + case LB_SETLOCALE: + { + LCID ret; + if (!IsValidLocale((LCID)wParam, LCID_INSTALLED)) + return LB_ERR; + ret = descr->locale; + descr->locale = (LCID)wParam; + return ret; + } + + case LB_INITSTORAGE: + return LISTBOX_InitStorage( descr, wParam ); + + case LB_SETCOUNT: + return LISTBOX_SetCount( descr, (INT)wParam ); + + case LB_SETTABSTOPS: + return LISTBOX_SetTabStops( descr, wParam, (LPINT)lParam ); + + case LB_CARETON: + if (descr->caret_on) + return LB_OKAY; + descr->caret_on = TRUE; + if ((descr->focus_item != -1) && (descr->in_focus)) + LISTBOX_RepaintItem( descr, descr->focus_item, ODA_FOCUS ); + return LB_OKAY; + + case LB_CARETOFF: + if (!descr->caret_on) + return LB_OKAY; + descr->caret_on = FALSE; + if ((descr->focus_item != -1) && (descr->in_focus)) + LISTBOX_RepaintItem( descr, descr->focus_item, ODA_FOCUS ); + return LB_OKAY; + + case LB_GETLISTBOXINFO: + return descr->page_size; + + case WM_DESTROY: + return LISTBOX_Destroy( descr ); + + case WM_ENABLE: + InvalidateRect( descr->self, NULL, TRUE ); + return 0; + + case WM_SETREDRAW: + LISTBOX_SetRedraw( descr, wParam != 0 ); + return 0; + + case WM_GETDLGCODE: + return DLGC_WANTARROWS | DLGC_WANTCHARS; + + case WM_PRINTCLIENT: + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc = ( wParam ) ? ((HDC)wParam) : BeginPaint( descr->self, &ps ); + ret = LISTBOX_Paint( descr, hdc ); + if( !wParam ) EndPaint( descr->self, &ps ); + } + return ret; + case WM_SIZE: + LISTBOX_UpdateSize( descr ); + return 0; + case WM_GETFONT: + return (LRESULT)descr->font; + case WM_SETFONT: + LISTBOX_SetFont( descr, (HFONT)wParam ); + if (lParam) InvalidateRect( descr->self, 0, TRUE ); + return 0; + case WM_SETFOCUS: + descr->in_focus = TRUE; + descr->caret_on = TRUE; + if (descr->focus_item != -1) + LISTBOX_DrawFocusRect( descr, TRUE ); + SEND_NOTIFICATION( descr, LBN_SETFOCUS ); + return 0; + case WM_KILLFOCUS: + LISTBOX_HandleLButtonUp( descr ); /* Release capture if we have it */ + descr->in_focus = FALSE; + descr->wheel_remain = 0; + if ((descr->focus_item != -1) && descr->caret_on) + LISTBOX_RepaintItem( descr, descr->focus_item, ODA_FOCUS ); + SEND_NOTIFICATION( descr, LBN_KILLFOCUS ); + return 0; + case WM_HSCROLL: + return LISTBOX_HandleHScroll( descr, LOWORD(wParam), HIWORD(wParam) ); + case WM_VSCROLL: + return LISTBOX_HandleVScroll( descr, LOWORD(wParam), HIWORD(wParam) ); + case WM_MOUSEWHEEL: + if (wParam & (MK_SHIFT | MK_CONTROL)) + return DefWindowProcW( descr->self, msg, wParam, lParam ); + return LISTBOX_HandleMouseWheel( descr, (SHORT)HIWORD(wParam) ); + case WM_LBUTTONDOWN: + if (lphc) + return LISTBOX_HandleLButtonDownCombo(descr, msg, wParam, + (INT16)LOWORD(lParam), + (INT16)HIWORD(lParam) ); + return LISTBOX_HandleLButtonDown( descr, wParam, + (INT16)LOWORD(lParam), + (INT16)HIWORD(lParam) ); + case WM_LBUTTONDBLCLK: + if (lphc) + return LISTBOX_HandleLButtonDownCombo(descr, msg, wParam, + (INT16)LOWORD(lParam), + (INT16)HIWORD(lParam) ); + if (descr->style & LBS_NOTIFY) + SEND_NOTIFICATION( descr, LBN_DBLCLK ); + return 0; + case WM_MOUSEMOVE: + if ( lphc && ((lphc->dwStyle & CBS_DROPDOWNLIST) != CBS_SIMPLE) ) + { + BOOL captured = descr->captured; + POINT mousePos; + RECT clientRect; + + mousePos.x = (INT16)LOWORD(lParam); + mousePos.y = (INT16)HIWORD(lParam); + + /* + * If we are in a dropdown combobox, we simulate that + * the mouse is captured to show the tracking of the item. + */ + if (GetClientRect(descr->self, &clientRect) && PtInRect( &clientRect, mousePos )) + descr->captured = TRUE; + + LISTBOX_HandleMouseMove( descr, mousePos.x, mousePos.y); + + descr->captured = captured; + } + else if (GetCapture() == descr->self) + { + LISTBOX_HandleMouseMove( descr, (INT16)LOWORD(lParam), + (INT16)HIWORD(lParam) ); + } + return 0; + case WM_LBUTTONUP: + if (lphc) + { + POINT mousePos; + RECT clientRect; + + /* + * If the mouse button "up" is not in the listbox, + * we make sure there is no selection by re-selecting the + * item that was selected when the listbox was made visible. + */ + mousePos.x = (INT16)LOWORD(lParam); + mousePos.y = (INT16)HIWORD(lParam); + + GetClientRect(descr->self, &clientRect); + + /* + * When the user clicks outside the combobox and the focus + * is lost, the owning combobox will send a fake buttonup with + * 0xFFFFFFF as the mouse location, we must also revert the + * selection to the original selection. + */ + if ( (lParam == (LPARAM)-1) || (!PtInRect( &clientRect, mousePos )) ) + LISTBOX_MoveCaret( descr, lphc->droppedIndex, FALSE ); + } + return LISTBOX_HandleLButtonUp( descr ); + case WM_KEYDOWN: + if( lphc && (lphc->dwStyle & CBS_DROPDOWNLIST) != CBS_SIMPLE ) + { + /* for some reason Windows makes it possible to + * show/hide ComboLBox by sending it WM_KEYDOWNs */ + + if( (!(lphc->wState & CBF_EUI) && wParam == VK_F4) || + ( (lphc->wState & CBF_EUI) && !(lphc->wState & CBF_DROPPED) + && (wParam == VK_DOWN || wParam == VK_UP)) ) + { + COMBO_FlipListbox( lphc, FALSE, FALSE ); + return 0; + } + } + return LISTBOX_HandleKeyDown( descr, wParam ); + case WM_CHAR: + return LISTBOX_HandleChar( descr, wParam ); + + case WM_SYSTIMER: + return LISTBOX_HandleSystemTimer( descr ); + case WM_ERASEBKGND: + if ((IS_OWNERDRAW(descr)) && !(descr->style & LBS_DISPLAYCHANGED)) + { + RECT rect; + HBRUSH hbrush = (HBRUSH)SendMessageW( descr->owner, WM_CTLCOLORLISTBOX, + wParam, (LPARAM)descr->self ); + TRACE("hbrush = %p\n", hbrush); + if(!hbrush) + hbrush = GetSysColorBrush(COLOR_WINDOW); + if(hbrush) + { + GetClientRect(descr->self, &rect); + FillRect((HDC)wParam, &rect, hbrush); + } + } + return 1; + case WM_DROPFILES: + if( lphc ) return 0; + return SendMessageW( descr->owner, msg, wParam, lParam ); + + case WM_NCDESTROY: + if( lphc && (lphc->dwStyle & CBS_DROPDOWNLIST) != CBS_SIMPLE ) + lphc->hWndLBox = 0; + break; + + case WM_NCACTIVATE: + if (lphc) return 0; + break; + + default: + if ((msg >= WM_USER) && (msg < 0xc000)) + WARN("[%p]: unknown msg %04x wp %08lx lp %08lx\n", + hwnd, msg, wParam, lParam ); + } + + return DefWindowProcW( hwnd, msg, wParam, lParam ); +} + +void LISTBOX_Register(void) +{ + WNDCLASSW wndClass; + + memset(&wndClass, 0, sizeof(wndClass)); + wndClass.style = CS_PARENTDC | CS_DBLCLKS | CS_GLOBALCLASS; + wndClass.lpfnWndProc = LISTBOX_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(LB_DESCR *); + wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW); + wndClass.hbrBackground = NULL; + wndClass.lpszClassName = WC_LISTBOXW; + RegisterClassW(&wndClass); +} + +void COMBOLBOX_Register(void) +{ + static const WCHAR combolboxW[] = {'C','o','m','b','o','L','B','o','x',0}; + WNDCLASSW wndClass; + + memset(&wndClass, 0, sizeof(wndClass)); + wndClass.style = CS_SAVEBITS | CS_DBLCLKS | CS_DROPSHADOW | CS_GLOBALCLASS; + wndClass.lpfnWndProc = LISTBOX_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(LB_DESCR *); + wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW); + wndClass.hbrBackground = NULL; + wndClass.lpszClassName = combolboxW; + RegisterClassW(&wndClass); +} diff --git a/dlls/comctl32/tests/misc.c b/dlls/comctl32/tests/misc.c index 7c9b4cd02e..eca85d490b 100644 --- a/dlls/comctl32/tests/misc.c +++ b/dlls/comctl32/tests/misc.c @@ -348,7 +348,9 @@ static void check_class( const char *name, int must_exist, UINT style, UINT igno todo_wine_if(strcmp(name, "Button") && strcmp(name, "ComboBox") && strcmp(name, "Edit") && - strcmp(name, "Static")) + strcmp(name, "Static") && + strcmp(name, "ListBox") && + strcmp(name, "ComboLBox")) ok( !(~wc.style & style & ~ignore), "System class %s is missing bits %x (%08x/%08x)\n", name, ~wc.style & style, wc.style, style ); ok( !(wc.style & ~style), "System class %s has extra bits %x (%08x/%08x)\n", diff --git a/dlls/user32/class.c b/dlls/user32/class.c index 0e05c1f426..e733cc2ce2 100644 --- a/dlls/user32/class.c +++ b/dlls/user32/class.c @@ -166,9 +166,7 @@ static BOOL is_builtin_class( const WCHAR *name ) { static const WCHAR classesW[][20] = { - {'C','o','m','b','o','L','B','o','x',0}, {'I','M','E',0}, - {'L','i','s','t','B','o','x',0}, {'M','D','I','C','l','i','e','n','t',0}, {'S','c','r','o','l','l','b','a','r',0}, }; -- 2.15.1
[View Less]
1
1
0
0
[PATCH] comctl32/comboex: Remove child windows subclass on window destruction
by Nikolay Sivov
14 Feb '18
14 Feb '18
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com> --- dlls/comctl32/comboex.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/dlls/comctl32/comboex.c b/dlls/comctl32/comboex.c index 076a5524d5..3c3714ac56 100644 --- a/dlls/comctl32/comboex.c +++ b/dlls/comctl32/comboex.c @@ -1502,10 +1502,10 @@ static void COMBOEX_ResetContent (COMBOEX_INFO *infoPtr) static LRESULT COMBOEX_Destroy (COMBOEX_INFO *infoPtr) { if (
…
[View More]
infoPtr->hwndCombo) - RemoveWindowSubclass(infoPtr->hwndCombo, COMBOEX_ComboWndProc, COMBO_SUBCLASSID); + SetWindowSubclass(infoPtr->hwndCombo, COMBOEX_ComboWndProc, COMBO_SUBCLASSID, 0); if (infoPtr->hwndEdit) - RemoveWindowSubclass(infoPtr->hwndEdit, COMBOEX_EditWndProc, EDIT_SUBCLASSID); + SetWindowSubclass(infoPtr->hwndEdit, COMBOEX_EditWndProc, EDIT_SUBCLASSID, 0); COMBOEX_FreeText (&infoPtr->edit); COMBOEX_ResetContent (infoPtr); @@ -1668,7 +1668,11 @@ COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx, info_ptr=%p\n", hwnd, uMsg, wParam, lParam, infoPtr); - if (!infoPtr) return 0; + if (uMsg == WM_NCDESTROY) + RemoveWindowSubclass(hwnd, COMBOEX_EditWndProc, EDIT_SUBCLASSID); + + if (!infoPtr) + return DefSubclassProc(hwnd, uMsg, wParam, lParam); switch (uMsg) { @@ -1823,11 +1827,14 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx, info_ptr=%p\n", hwnd, uMsg, wParam, lParam, infoPtr); - if (!infoPtr) return 0; + if (uMsg == WM_NCDESTROY) + RemoveWindowSubclass(hwnd, COMBOEX_ComboWndProc, COMBO_SUBCLASSID); + + if (!infoPtr) + return DefSubclassProc(hwnd, uMsg, wParam, lParam); switch (uMsg) { - case WM_DRAWITEM: /* * The only way this message should come is from the @@ -1835,7 +1842,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, * that ComboEx knows this is listbox. */ ((DRAWITEMSTRUCT *)lParam)->itemState |= ODS_COMBOEXLBOX; - return DefSubclassProc(hwnd, uMsg, wParam, lParam); + break; case WM_ERASEBKGND: hDC = (HDC) wParam; @@ -1844,7 +1851,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, TRACE("erasing (%s)\n", wine_dbgstr_rect(&rect)); ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0); SetBkColor (hDC, obkc); - return DefSubclassProc(hwnd, uMsg, wParam, lParam); + break; case WM_SETCURSOR: /* @@ -1858,7 +1865,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, nmmse.pt.y = 0; nmmse.dwHitInfo = lParam; COMBOEX_Notify (infoPtr, NM_SETCURSOR, (NMHDR *)&nmmse); - return DefSubclassProc(hwnd, uMsg, wParam, lParam); + break; case WM_LBUTTONDOWN: GetClientRect (hwnd, &rect); @@ -1868,15 +1875,15 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, pt.x = (short)LOWORD(lParam); pt.y = (short)HIWORD(lParam); if (PtInRect(&rect, pt)) - return DefSubclassProc(hwnd, uMsg, wParam, lParam); + break; infoPtr->flags |= WCBE_MOUSECAPTURED; SetCapture(hwnd); - break; + return 0; case WM_LBUTTONUP: if (!(infoPtr->flags & WCBE_MOUSECAPTURED)) - return DefSubclassProc(hwnd, uMsg, wParam, lParam); + break; ReleaseCapture(); infoPtr->flags &= ~WCBE_MOUSECAPTURED; @@ -1885,7 +1892,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, } else { SendMessageW(hwnd, CB_SHOWDROPDOWN, TRUE, 0); } - break; + return 0; case WM_MOUSEMOVE: if ( (infoPtr->flags & WCBE_MOUSECAPTURED) && @@ -1894,7 +1901,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, COMBOEX_NotifyDragBegin(infoPtr, edit_text); infoPtr->flags |= WCBE_MOUSEDRAGGED; } - return DefSubclassProc(hwnd, uMsg, wParam, lParam); + break; case WM_COMMAND: switch (HIWORD(wParam)) { @@ -1975,9 +1982,10 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, break; }/* fall through */ default: - return DefSubclassProc(hwnd, uMsg, wParam, lParam); + ; } - return 0; + + return DefSubclassProc(hwnd, uMsg, wParam, lParam); } -- 2.15.1
[View Less]
1
0
0
0
[PATCH] comctl32/tests: Use existing macros for control class names
by Nikolay Sivov
14 Feb '18
14 Feb '18
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com> --- dlls/comctl32/tests/button.c | 2 +- dlls/comctl32/tests/combo.c | 6 +++--- dlls/comctl32/tests/static.c | 3 ++- dlls/comctl32/tests/status.c | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/dlls/comctl32/tests/button.c b/dlls/comctl32/tests/button.c index 96b8bea531..47aee3f622 100644 --- a/dlls/comctl32/tests/button.c +++ b/dlls/comctl32/tests/button.c @@ -454,7 +454,7 @@ static HWND create_button(
…
[View More]
DWORD style, HWND parent) style |= WS_CHILD|BS_NOTIFY; menuid = (HMENU)ID_BUTTON; } - hwnd = CreateWindowExA(0, "Button", "test", style, 0, 0, 50, 14, parent, menuid, 0, NULL); + hwnd = CreateWindowExA(0, WC_BUTTONA, "test", style, 0, 0, 50, 14, parent, menuid, 0, NULL); ok(hwnd != NULL, "failed to create a button, 0x%08x, %p\n", style, parent); pSetWindowSubclass(hwnd, button_subclass_proc, 0, 0); return hwnd; diff --git a/dlls/comctl32/tests/combo.c b/dlls/comctl32/tests/combo.c index da2ded2328..b0457396c4 100644 --- a/dlls/comctl32/tests/combo.c +++ b/dlls/comctl32/tests/combo.c @@ -507,7 +507,7 @@ static BOOL init(void) wc.lpfnWndProc = ComboExTestWndProc; RegisterClassA(&wc); - hMainWnd = CreateWindowA("static", "Test", WS_OVERLAPPEDWINDOW, 10, 10, 300, 300, NULL, NULL, NULL, 0); + hMainWnd = CreateWindowA(WC_STATICA, "Test", WS_OVERLAPPEDWINDOW, 10, 10, 300, 300, NULL, NULL, NULL, 0); ShowWindow(hMainWnd, SW_SHOW); hComboExParentWnd = CreateWindowExA(0, ComboExTestClass, "ComboEx test", WS_OVERLAPPEDWINDOW|WS_VISIBLE, @@ -606,7 +606,7 @@ static void test_comboex_get_set_item(void) static HWND create_combobox(DWORD style) { - return CreateWindowA("ComboBox", "Combo", WS_VISIBLE|WS_CHILD|style, 5, 5, 100, 100, hMainWnd, (HMENU)COMBO_ID, NULL, 0); + return CreateWindowA(WC_COMBOBOXA, "Combo", WS_VISIBLE|WS_CHILD|style, 5, 5, 100, 100, hMainWnd, (HMENU)COMBO_ID, NULL, 0); } static int font_height(HFONT hFont) @@ -1035,7 +1035,7 @@ static void test_combo_editselection_focus(DWORD style) get_combobox_info(hCombo, &cbInfo); hEdit = cbInfo.hwndItem; - hButton = CreateWindowA("Button", "OK", WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON, + hButton = CreateWindowA(WC_BUTTONA, "OK", WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON, 5, 50, 100, 20, hMainWnd, NULL, (HINSTANCE)GetWindowLongPtrA(hMainWnd, GWLP_HINSTANCE), NULL); diff --git a/dlls/comctl32/tests/static.c b/dlls/comctl32/tests/static.c index 890fcf5b96..a65e352728 100644 --- a/dlls/comctl32/tests/static.c +++ b/dlls/comctl32/tests/static.c @@ -23,6 +23,7 @@ #define STRICT #define WIN32_LEAN_AND_MEAN #include <windows.h> +#include "commctrl.h" #include "wine/test.h" @@ -53,7 +54,7 @@ static void flush_events(void) static HWND create_static(DWORD style) { - return CreateWindowA("static", "Test", WS_VISIBLE|WS_CHILD|style, 5, 5, 100, 100, hMainWnd, (HMENU)CTRL_ID, NULL, 0); + return CreateWindowA(WC_STATICA, "Test", WS_VISIBLE|WS_CHILD|style, 5, 5, 100, 100, hMainWnd, (HMENU)CTRL_ID, NULL, 0); } static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) diff --git a/dlls/comctl32/tests/status.c b/dlls/comctl32/tests/status.c index f2fe1abf98..2308974761 100644 --- a/dlls/comctl32/tests/status.c +++ b/dlls/comctl32/tests/status.c @@ -607,7 +607,7 @@ START_TEST(status) iccex.dwICC = ICC_BAR_CLASSES; pInitCommonControlsEx(&iccex); - g_hMainWnd = CreateWindowExA(0, "static", "", WS_OVERLAPPEDWINDOW, + g_hMainWnd = CreateWindowExA(0, WC_STATICA, "", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 672+2*GetSystemMetrics(SM_CXSIZEFRAME), 226+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYSIZEFRAME), NULL, NULL, GetModuleHandleA(NULL), 0); -- 2.15.1
[View Less]
1
0
0
0
[PATCH 2/2] include: Add some wide declarations.
by Daniel Lehman
14 Feb '18
14 Feb '18
1
0
0
0
[PATCH] include: Add and use a global heap_strdupW() helper
by Michael Stefaniuc
13 Feb '18
13 Feb '18
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org> --- There are about 40+ more strdupW() functions around. Most using that name, some prefixed with something else. Of course that is fodder for more patches. dlls/appwiz.cpl/appwiz.h | 16 ---------------- dlls/dpnet/dpnet_private.h | 8 -------- dlls/dwrite/dwrite_private.h | 16 ---------------- dlls/ieframe/ieframe.h | 16 ---------------- dlls/inetcomm/protocol.c | 16 ----------------
…
[View More]
dlls/jscript/jscript.h | 16 ---------------- dlls/mshtml/mshtml_private.h | 16 ---------------- dlls/msxml3/msxml_private.h | 16 ---------------- dlls/ole32/errorinfo.c | 16 ---------------- dlls/sapi/sapi_private.h | 15 --------------- dlls/schedsvc/schedsvc_private.h | 10 ---------- dlls/taskschd/taskschd_private.h | 10 ---------- dlls/urlmon/urlmon_main.h | 16 ---------------- dlls/vbscript/vbscript.h | 16 ---------------- dlls/wbemprox/wbemprox_private.h | 8 -------- dlls/wininet/internet.h | 16 ---------------- include/wine/heap.h | 16 ++++++++++++++++ 17 files changed, 16 insertions(+), 227 deletions(-) diff --git a/dlls/appwiz.cpl/appwiz.h b/dlls/appwiz.cpl/appwiz.h index 2165ce11b1..5571ac158a 100644 --- a/dlls/appwiz.cpl/appwiz.h +++ b/dlls/appwiz.cpl/appwiz.h @@ -28,22 +28,6 @@ BOOL install_addon(addon_t) DECLSPEC_HIDDEN; extern HINSTANCE hInst DECLSPEC_HIDDEN; -static inline WCHAR *heap_strdupW(const WCHAR *str) -{ - WCHAR *ret; - - if(str) { - size_t size = strlenW(str)+1; - ret = heap_alloc(size*sizeof(WCHAR)); - if(ret) - memcpy(ret, str, size*sizeof(WCHAR)); - }else { - ret = NULL; - } - - return ret; -} - static inline WCHAR *heap_strdupAtoW(const char *str) { WCHAR *ret = NULL; diff --git a/dlls/dpnet/dpnet_private.h b/dlls/dpnet/dpnet_private.h index 2e72360c89..467ee87f6f 100644 --- a/dlls/dpnet/dpnet_private.h +++ b/dlls/dpnet/dpnet_private.h @@ -155,12 +155,4 @@ typedef struct { #define FE(x) { x, #x } #define GE(x) { &x, #x } -static inline WCHAR *heap_strdupW( const WCHAR *src ) -{ - WCHAR *dst; - if (!src) return NULL; - if ((dst = heap_alloc( (strlenW( src ) + 1) * sizeof(WCHAR) ))) strcpyW( dst, src ); - return dst; -} - #endif diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 31b977a159..867356fd73 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -31,22 +31,6 @@ static const DWRITE_MATRIX identity = 0.0f, 0.0f }; -static inline LPWSTR heap_strdupW(const WCHAR *str) -{ - LPWSTR ret = NULL; - - if(str) { - DWORD size; - - size = (strlenW(str)+1)*sizeof(WCHAR); - ret = heap_alloc(size); - if(ret) - memcpy(ret, str, size); - } - - return ret; -} - static inline LPWSTR heap_strdupnW(const WCHAR *str, UINT32 len) { WCHAR *ret = NULL; diff --git a/dlls/ieframe/ieframe.h b/dlls/ieframe/ieframe.h index 8adf47e053..d2ba262a34 100644 --- a/dlls/ieframe/ieframe.h +++ b/dlls/ieframe/ieframe.h @@ -335,22 +335,6 @@ static inline void unlock_module(void) { InterlockedDecrement(&module_ref); } -static inline LPWSTR heap_strdupW(LPCWSTR str) -{ - LPWSTR ret = NULL; - - if(str) { - DWORD size; - - size = (strlenW(str)+1)*sizeof(WCHAR); - ret = heap_alloc(size); - if(ret) - memcpy(ret, str, size); - } - - return ret; -} - static inline LPWSTR co_strdupW(LPCWSTR str) { WCHAR *ret = CoTaskMemAlloc((strlenW(str) + 1)*sizeof(WCHAR)); diff --git a/dlls/inetcomm/protocol.c b/dlls/inetcomm/protocol.c index 028463a269..7741dc8fb5 100644 --- a/dlls/inetcomm/protocol.c +++ b/dlls/inetcomm/protocol.c @@ -63,22 +63,6 @@ typedef struct { static const WCHAR mhtml_prefixW[] = {'m','h','t','m','l',':'}; static const WCHAR mhtml_separatorW[] = {'!','x','-','u','s','c',':'}; -static inline LPWSTR heap_strdupW(LPCWSTR str) -{ - LPWSTR ret = NULL; - - if(str) { - DWORD size; - - size = (strlenW(str)+1)*sizeof(WCHAR); - ret = heap_alloc(size); - if(ret) - memcpy(ret, str, size); - } - - return ret; -} - static HRESULT parse_mhtml_url(const WCHAR *url, mhtml_url_t *r) { const WCHAR *p; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 1a247511ac..f3ed3d3523 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -55,22 +55,6 @@ void heap_pool_clear(heap_pool_t*) DECLSPEC_HIDDEN; void heap_pool_free(heap_pool_t*) DECLSPEC_HIDDEN; heap_pool_t *heap_pool_mark(heap_pool_t*) DECLSPEC_HIDDEN; -static inline LPWSTR heap_strdupW(LPCWSTR str) -{ - LPWSTR ret = NULL; - - if(str) { - DWORD size; - - size = (strlenW(str)+1)*sizeof(WCHAR); - ret = heap_alloc(size); - if(ret) - memcpy(ret, str, size); - } - - return ret; -} - typedef struct jsdisp_t jsdisp_t; extern HINSTANCE jscript_hinstance DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 5ed626477f..2b7018f38a 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -1189,22 +1189,6 @@ static inline void * __WINE_ALLOC_SIZE(2) heap_realloc_zero(void *mem, size_t le return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, len); } -static inline LPWSTR heap_strdupW(LPCWSTR str) -{ - LPWSTR ret = NULL; - - if(str) { - DWORD size; - - size = (strlenW(str)+1)*sizeof(WCHAR); - ret = heap_alloc(size); - if(ret) - memcpy(ret, str, size); - } - - return ret; -} - static inline LPWSTR heap_strndupW(LPCWSTR str, unsigned len) { LPWSTR ret = NULL; diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h index 94ef66b23d..6880294160 100644 --- a/dlls/msxml3/msxml_private.h +++ b/dlls/msxml3/msxml_private.h @@ -170,22 +170,6 @@ static inline void* __WINE_ALLOC_SIZE(2) heap_realloc_zero(void *mem, size_t siz return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, size); } -static inline LPWSTR heap_strdupW(LPCWSTR str) -{ - LPWSTR ret = NULL; - - if(str) { - DWORD size; - - size = (strlenW(str)+1)*sizeof(WCHAR); - ret = heap_alloc(size); - if(ret) - memcpy(ret, str, size); - } - - return ret; -} - /* XSLProcessor parameter list */ struct xslprocessor_par { diff --git a/dlls/ole32/errorinfo.c b/dlls/ole32/errorinfo.c index d5ec17207a..19f1b04b21 100644 --- a/dlls/ole32/errorinfo.c +++ b/dlls/ole32/errorinfo.c @@ -41,22 +41,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); -static inline WCHAR *heap_strdupW(const WCHAR *str) -{ - WCHAR *ret = NULL; - - if(str) { - size_t size; - - size = (strlenW(str)+1)*sizeof(WCHAR); - ret = heap_alloc(size); - if(ret) - memcpy(ret, str, size); - } - - return ret; -} - typedef struct ErrorInfoImpl { IErrorInfo IErrorInfo_iface; diff --git a/dlls/sapi/sapi_private.h b/dlls/sapi/sapi_private.h index b069222c7d..cfc5f3e1ad 100644 --- a/dlls/sapi/sapi_private.h +++ b/dlls/sapi/sapi_private.h @@ -24,18 +24,3 @@ HRESULT data_key_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN; HRESULT token_category_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN; HRESULT token_enum_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN; - -static inline LPWSTR heap_strdupW(LPCWSTR str) -{ - LPWSTR ret = NULL; - DWORD size; - - if (str) - { - size = (strlenW( str ) + 1) * sizeof(WCHAR); - ret = heap_alloc( size ); - if (ret) memcpy( ret, str, size ); - } - - return ret; -} diff --git a/dlls/schedsvc/schedsvc_private.h b/dlls/schedsvc/schedsvc_private.h index 4404486998..60901d8ad8 100644 --- a/dlls/schedsvc/schedsvc_private.h +++ b/dlls/schedsvc/schedsvc_private.h @@ -24,14 +24,4 @@ void schedsvc_auto_start(void) DECLSPEC_HIDDEN; -static inline WCHAR *heap_strdupW(const WCHAR *src) -{ - WCHAR *dst; - unsigned len; - if (!src) return NULL; - len = (strlenW(src) + 1) * sizeof(WCHAR); - if ((dst = heap_alloc(len))) memcpy(dst, src, len); - return dst; -} - #endif /* __WINE_SCHEDSVC_PRIVATE_H__ */ diff --git a/dlls/taskschd/taskschd_private.h b/dlls/taskschd/taskschd_private.h index 6c7f916a0f..67383cbf59 100644 --- a/dlls/taskschd/taskschd_private.h +++ b/dlls/taskschd/taskschd_private.h @@ -32,14 +32,4 @@ HRESULT RegisteredTaskCollection_create(const WCHAR *path, IRegisteredTaskCollec WCHAR *get_full_path(const WCHAR *parent, const WCHAR *path) DECLSPEC_HIDDEN; -static inline WCHAR *heap_strdupW(const WCHAR *src) -{ - WCHAR *dst; - unsigned len; - if (!src) return NULL; - len = (strlenW(src) + 1) * sizeof(WCHAR); - if ((dst = heap_alloc(len))) memcpy(dst, src, len); - return dst; -} - #endif /* __WINE_TASKSCHD_PRIVATE_H__ */ diff --git a/dlls/urlmon/urlmon_main.h b/dlls/urlmon/urlmon_main.h index a4a1c78d52..89cdd389a6 100644 --- a/dlls/urlmon/urlmon_main.h +++ b/dlls/urlmon/urlmon_main.h @@ -240,22 +240,6 @@ static inline void* __WINE_ALLOC_SIZE(2) heap_realloc_zero(void *mem, size_t siz return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, size); } -static inline LPWSTR heap_strdupW(LPCWSTR str) -{ - LPWSTR ret = NULL; - - if(str) { - DWORD size; - - size = (strlenW(str)+1)*sizeof(WCHAR); - ret = heap_alloc(size); - if(ret) - memcpy(ret, str, size); - } - - return ret; -} - static inline LPWSTR heap_strndupW(LPCWSTR str, int len) { LPWSTR ret = NULL; diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 5e935ff76a..d8af4d6855 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -431,22 +431,6 @@ HRESULT create_safearray_iter(SAFEARRAY *sa, IEnumVARIANT **ev) DECLSPEC_HIDDEN; HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory*,IUnknown*,REFIID,void**) DECLSPEC_HIDDEN; HRESULT WINAPI VBScriptRegExpFactory_CreateInstance(IClassFactory*,IUnknown*,REFIID,void**) DECLSPEC_HIDDEN; -static inline LPWSTR heap_strdupW(LPCWSTR str) -{ - LPWSTR ret = NULL; - - if(str) { - DWORD size; - - size = (strlenW(str)+1)*sizeof(WCHAR); - ret = heap_alloc(size); - if(ret) - memcpy(ret, str, size); - } - - return ret; -} - #define VBSCRIPT_BUILD_VERSION 16978 #define VBSCRIPT_MAJOR_VERSION 5 #define VBSCRIPT_MINOR_VERSION 8 diff --git a/dlls/wbemprox/wbemprox_private.h b/dlls/wbemprox/wbemprox_private.h index 54b1ba3d8e..47dca73a26 100644 --- a/dlls/wbemprox/wbemprox_private.h +++ b/dlls/wbemprox/wbemprox_private.h @@ -228,14 +228,6 @@ HRESULT service_stop_service(IWbemClassObject *, IWbemClassObject *, IWbemClassO HRESULT security_get_sd(IWbemClassObject *, IWbemClassObject *, IWbemClassObject **) DECLSPEC_HIDDEN; HRESULT security_set_sd(IWbemClassObject *, IWbemClassObject *, IWbemClassObject **) DECLSPEC_HIDDEN; -static inline WCHAR *heap_strdupW( const WCHAR *src ) -{ - WCHAR *dst; - if (!src) return NULL; - if ((dst = heap_alloc( (strlenW( src ) + 1) * sizeof(WCHAR) ))) strcpyW( dst, src ); - return dst; -} - static const WCHAR class_processW[] = {'W','i','n','3','2','_','P','r','o','c','e','s','s',0}; static const WCHAR class_serviceW[] = {'W','i','n','3','2','_','S','e','r','v','i','c','e',0}; static const WCHAR class_stdregprovW[] = {'S','t','d','R','e','g','P','r','o','v',0}; diff --git a/dlls/wininet/internet.h b/dlls/wininet/internet.h index 498a79b080..736506a9ce 100644 --- a/dlls/wininet/internet.h +++ b/dlls/wininet/internet.h @@ -95,22 +95,6 @@ static inline void * __WINE_ALLOC_SIZE(2) heap_realloc_zero(void *mem, size_t le return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, len); } -static inline LPWSTR heap_strdupW(LPCWSTR str) -{ - LPWSTR ret = NULL; - - if(str) { - DWORD size; - - size = (strlenW(str)+1)*sizeof(WCHAR); - ret = heap_alloc(size); - if(ret) - memcpy(ret, str, size); - } - - return ret; -} - static inline char *heap_strdupA(const char *str) { char *ret = NULL; diff --git a/include/wine/heap.h b/include/wine/heap.h index 97d3a5662b..d970e03731 100644 --- a/include/wine/heap.h +++ b/include/wine/heap.h @@ -55,4 +55,20 @@ static inline void *heap_calloc(SIZE_T count, SIZE_T size) return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); } +static inline WCHAR *heap_strdupW(const WCHAR *str) +{ + WCHAR *dst; + SIZE_T len; + + if(!str) + return NULL; + + len = (lstrlenW(str) + 1) * sizeof(*str); + dst = heap_alloc(len); + if (dst) + memcpy(dst, str, len); + + return dst; +} + #endif /* __WINE_WINE_HEAP_H */ -- 2.14.3
[View Less]
3
6
0
0
[PATCH] include/d3d11.idl: add _D3D11_1_CONSTANTS / _D3D11_2_CONSTANTS
by Austin English
13 Feb '18
13 Feb '18
Signed-off-by: Austin English <austinenglish(a)gmail.com> --- include/d3d11.idl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/d3d11.idl b/include/d3d11.idl index a7b98126a1..f15f1217f1 100644 --- a/include/d3d11.idl +++ b/include/d3d11.idl @@ -168,6 +168,16 @@ const UINT D3D11_VS_OUTPUT_REGISTER_COUNT = 32; const UINT D3D11_OMAC_SIZE = 16; +cpp_quote("#endif") +cpp_quote("#ifndef _D3D11_1_CONSTANTS") +cpp_quote("#define _D3D11_1_CONSTANTS") +const UINT
…
[View More]
D3D11_1_UAV_SLOT_COUNT = 64; +cpp_quote("#endif") +cpp_quote("#ifndef _D3D11_2_CONSTANTS") +cpp_quote("#define _D3D11_2_CONSTANTS") +const UINT D3D11_2_TILED_RESOURCE_TILE_SIZE_IN_BYTES = 65536; +cpp_quote("#endif") + const UINT D3D11_PS_CS_UAV_REGISTER_COMPONENTS = 1; const UINT D3D11_PS_CS_UAV_REGISTER_COUNT = 8; const UINT D3D11_PS_CS_UAV_REGISTER_READS_PER_INST = 1; -- 2.13.6
[View Less]
1
0
0
0
[PATCH 1/2] msvfw32: Fix driver enumeration.
by Zebediah Figura
13 Feb '18
13 Feb '18
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com> --- Fixes e.g. msacm.l3acm being enumerated as "msac".".l3a". This behaviour matches that on Windows tested mainly by manually modifying the registry. If this is appropriate for a test I will add one. dlls/msvfw32/msvideo_main.c | 53 +++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/dlls/msvfw32/msvideo_main.c b/dlls/msvfw32/msvideo_main.c index d49ea74..82351d6 100644 --
…
[View More]
- a/dlls/msvfw32/msvideo_main.c +++ b/dlls/msvfw32/msvideo_main.c @@ -223,48 +223,48 @@ static int compare_fourcc(DWORD fcc1, DWORD fcc2) return strncasecmp(fcc_str1, fcc_str2, 4); } -typedef BOOL (*enum_handler_t)(const char*, unsigned int, void*); +typedef BOOL (*enum_handler_t)(const char *name, const char *driver, unsigned int index, void *param); static BOOL enum_drivers(DWORD fccType, enum_handler_t handler, void* param) { - CHAR buf[2048], fccTypeStr[5], *s; + char fccTypeStr[4]; + char name_buf[10]; + char buf[2048]; + DWORD i, cnt = 0, lRet; BOOL result = FALSE; HKEY hKey; fourcc_to_string(fccTypeStr, fccType); - fccTypeStr[4] = '.'; /* first, go through the registry entries */ lRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, HKLM_DRIVERS32, 0, KEY_QUERY_VALUE, &hKey); if (lRet == ERROR_SUCCESS) { - DWORD name, data, type; i = 0; for (;;) - { - name = 10; - data = sizeof buf - name; - lRet = RegEnumValueA(hKey, i++, buf, &name, 0, &type, (LPBYTE)(buf+name), &data); - if (lRet == ERROR_NO_MORE_ITEMS) break; - if (lRet != ERROR_SUCCESS) continue; - if (fccType && (name != 9 || strncasecmp(buf, fccTypeStr, 5))) continue; - buf[name] = '='; - if ((result = handler(buf, cnt++, param))) break; - } - RegCloseKey( hKey ); + { + DWORD name_len = 10, driver_len = 128; + lRet = RegEnumValueA(hKey, i++, name_buf, &name_len, 0, 0, (BYTE *)buf, &driver_len); + if (lRet == ERROR_NO_MORE_ITEMS) break; + if (name_len != 9 || name_buf[4] != '.') continue; + if (fccType && strncasecmp(name_buf, fccTypeStr, 4)) continue; + if ((result = handler(name_buf, buf, cnt++, param))) break; + } + RegCloseKey( hKey ); } if (result) return result; /* if that didn't work, go through the values in system.ini */ if (GetPrivateProfileSectionA("drivers32", buf, sizeof(buf), "system.ini")) { - for (s = buf; *s; s += strlen(s) + 1) - { - TRACE("got %s\n", s); - if (fccType && (strncasecmp(s, fccTypeStr, 5) || s[9] != '=')) continue; - if ((result = handler(s, cnt++, param))) break; - } + char *s; + for (s = buf; *s; s += strlen(s) + 1) + { + if (s[5] != '.' || s[9] != '=') continue; + if (fccType && strncasecmp(s, fccTypeStr, 4)) continue; + if ((result = handler(s, s + 10, cnt++, param))) break; + } } return result; @@ -294,10 +294,11 @@ DWORD WINAPI VideoForWindowsVersion(void) return 0x040003B6; /* 4.950 */ } -static BOOL ICInfo_enum_handler(const char *drv, unsigned int nr, void *param) +static BOOL ICInfo_enum_handler(const char *name, const char *driver, unsigned int nr, void *param) { ICINFO *lpicinfo = param; - DWORD fccHandler = mmioStringToFOURCCA(drv + 5, 0); + DWORD fccType = mmioStringToFOURCCA(name, 0); + DWORD fccHandler = mmioStringToFOURCCA(name + 5, 0); if (lpicinfo->fccHandler != nr && compare_fourcc(lpicinfo->fccHandler, fccHandler)) return FALSE; @@ -308,7 +309,7 @@ static BOOL ICInfo_enum_handler(const char *drv, unsigned int nr, void *param) lpicinfo->dwVersionICM = ICVERSION; lpicinfo->szName[0] = 0; lpicinfo->szDescription[0] = 0; - MultiByteToWideChar(CP_ACP, 0, drv + 10, -1, lpicinfo->szDriver, + MultiByteToWideChar(CP_ACP, 0, driver, -1, lpicinfo->szDriver, sizeof(lpicinfo->szDriver)/sizeof(WCHAR)); return TRUE; @@ -647,10 +648,10 @@ static HIC try_driver(driver_info_t *info) return 0; } -static BOOL ICLocate_enum_handler(const char *drv, unsigned int nr, void *param) +static BOOL ICLocate_enum_handler(const char *name, const char *driver, unsigned int nr, void *param) { driver_info_t *info = param; - info->fccHandler = mmioStringToFOURCCA(drv + 5, 0); + info->fccHandler = mmioStringToFOURCCA(name + 5, 0); info->hic = try_driver(info); return info->hic != 0; } -- 2.7.4
[View Less]
2
3
0
0
[PATCH v2 1/2] msvfw32: Fix driver enumeration.
by Zebediah Figura
13 Feb '18
13 Feb '18
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com> --- Fixes e.g. msacm.l3acm being enumerated as "msac".".l3a". This behaviour matches that on Windows tested mainly by manually modifying the registry. If this is appropriate for a test I will add one. v2: fix bad index breaking enumeration from system.ini dlls/msvfw32/msvideo_main.c | 53 +++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/dlls/msvfw32/msvideo_main.c b/
…
[View More]
dlls/msvfw32/msvideo_main.c index d49ea74..e071d95 100644 --- a/dlls/msvfw32/msvideo_main.c +++ b/dlls/msvfw32/msvideo_main.c @@ -223,48 +223,48 @@ static int compare_fourcc(DWORD fcc1, DWORD fcc2) return strncasecmp(fcc_str1, fcc_str2, 4); } -typedef BOOL (*enum_handler_t)(const char*, unsigned int, void*); +typedef BOOL (*enum_handler_t)(const char *name, const char *driver, unsigned int index, void *param); static BOOL enum_drivers(DWORD fccType, enum_handler_t handler, void* param) { - CHAR buf[2048], fccTypeStr[5], *s; + char fccTypeStr[4]; + char name_buf[10]; + char buf[2048]; + DWORD i, cnt = 0, lRet; BOOL result = FALSE; HKEY hKey; fourcc_to_string(fccTypeStr, fccType); - fccTypeStr[4] = '.'; /* first, go through the registry entries */ lRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, HKLM_DRIVERS32, 0, KEY_QUERY_VALUE, &hKey); if (lRet == ERROR_SUCCESS) { - DWORD name, data, type; i = 0; for (;;) - { - name = 10; - data = sizeof buf - name; - lRet = RegEnumValueA(hKey, i++, buf, &name, 0, &type, (LPBYTE)(buf+name), &data); - if (lRet == ERROR_NO_MORE_ITEMS) break; - if (lRet != ERROR_SUCCESS) continue; - if (fccType && (name != 9 || strncasecmp(buf, fccTypeStr, 5))) continue; - buf[name] = '='; - if ((result = handler(buf, cnt++, param))) break; - } - RegCloseKey( hKey ); + { + DWORD name_len = 10, driver_len = 128; + lRet = RegEnumValueA(hKey, i++, name_buf, &name_len, 0, 0, (BYTE *)buf, &driver_len); + if (lRet == ERROR_NO_MORE_ITEMS) break; + if (name_len != 9 || name_buf[4] != '.') continue; + if (fccType && strncasecmp(name_buf, fccTypeStr, 4)) continue; + if ((result = handler(name_buf, buf, cnt++, param))) break; + } + RegCloseKey( hKey ); } if (result) return result; /* if that didn't work, go through the values in system.ini */ if (GetPrivateProfileSectionA("drivers32", buf, sizeof(buf), "system.ini")) { - for (s = buf; *s; s += strlen(s) + 1) - { - TRACE("got %s\n", s); - if (fccType && (strncasecmp(s, fccTypeStr, 5) || s[9] != '=')) continue; - if ((result = handler(s, cnt++, param))) break; - } + char *s; + for (s = buf; *s; s += strlen(s) + 1) + { + if (s[4] != '.' || s[9] != '=') continue; + if (fccType && strncasecmp(s, fccTypeStr, 4)) continue; + if ((result = handler(s, s + 10, cnt++, param))) break; + } } return result; @@ -294,10 +294,11 @@ DWORD WINAPI VideoForWindowsVersion(void) return 0x040003B6; /* 4.950 */ } -static BOOL ICInfo_enum_handler(const char *drv, unsigned int nr, void *param) +static BOOL ICInfo_enum_handler(const char *name, const char *driver, unsigned int nr, void *param) { ICINFO *lpicinfo = param; - DWORD fccHandler = mmioStringToFOURCCA(drv + 5, 0); + DWORD fccType = mmioStringToFOURCCA(name, 0); + DWORD fccHandler = mmioStringToFOURCCA(name + 5, 0); if (lpicinfo->fccHandler != nr && compare_fourcc(lpicinfo->fccHandler, fccHandler)) return FALSE; @@ -308,7 +309,7 @@ static BOOL ICInfo_enum_handler(const char *drv, unsigned int nr, void *param) lpicinfo->dwVersionICM = ICVERSION; lpicinfo->szName[0] = 0; lpicinfo->szDescription[0] = 0; - MultiByteToWideChar(CP_ACP, 0, drv + 10, -1, lpicinfo->szDriver, + MultiByteToWideChar(CP_ACP, 0, driver, -1, lpicinfo->szDriver, sizeof(lpicinfo->szDriver)/sizeof(WCHAR)); return TRUE; @@ -647,10 +648,10 @@ static HIC try_driver(driver_info_t *info) return 0; } -static BOOL ICLocate_enum_handler(const char *drv, unsigned int nr, void *param) +static BOOL ICLocate_enum_handler(const char *name, const char *driver, unsigned int nr, void *param) { driver_info_t *info = param; - info->fccHandler = mmioStringToFOURCCA(drv + 5, 0); + info->fccHandler = mmioStringToFOURCCA(name + 5, 0); info->hic = try_driver(info); return info->hic != 0; } -- 2.7.4
[View Less]
1
1
0
0
[PATCH] user32/tests: Add more message conversion tests with different user window procedures
by Nikolay Sivov
13 Feb '18
13 Feb '18
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com> --- dlls/user32/tests/dialog.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/dlls/user32/tests/dialog.c b/dlls/user32/tests/dialog.c index 33e755b0b7..1632484509 100644 --- a/dlls/user32/tests/dialog.c +++ b/dlls/user32/tests/dialog.c @@ -1602,6 +1602,96 @@ static INT_PTR CALLBACK test_aw_conversion_dlgproc2(HWND hdlg, UINT msg, WPARAM return FALSE; } +static LRESULT
…
[View More]
CALLBACK test_aw_conversion_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); + int mode = HandleToULong(GetPropA(hwnd, "test_mode")); + WCHAR *text = (WCHAR *)lparam; + char *textA = (char *)lparam; + + switch (msg) + { + case WM_SETTEXT: + case WM_WININICHANGE: + case WM_DEVMODECHANGE: + case CB_DIR: + case LB_DIR: + case LB_ADDFILE: + case EM_REPLACESEL: + switch (mode) + { + case DLGPROCTEXT_DLGPROCA: + todo_wine_if(IsWindowUnicode(hwnd)) + ok(textA == testtext, "%s: %s, unexpected text %s.\n", IsWindowUnicode(hwnd) ? "U" : "A", + testmodes[mode], textA); + break; + case DLGPROCTEXT_DLGPROCW: + todo_wine_if(!IsWindowUnicode(hwnd)) + ok(text == testtextW, "%s: %s, unexpected text %s.\n", IsWindowUnicode(hwnd) ? "U" : "A", testmodes[mode], + wine_dbgstr_w(text)); + break; + case DLGPROCTEXT_SNDMSGA: + if (IsWindowUnicode(hwnd)) + ok(text != testtextW && !lstrcmpW(text, testtextW), + "U: %s, unexpected text %s.\n", testmodes[mode], wine_dbgstr_w(text)); + else + ok(textA == testtext, "A: %s, unexpected text %s.\n", testmodes[mode], textA); + break; + case DLGPROCTEXT_SNDMSGW: + if (IsWindowUnicode(hwnd)) + ok(text == testtextW, "U: %s, unexpected text %s.\n", testmodes[mode], wine_dbgstr_w(text)); + else + ok(textA != testtext && !strcmp(textA, testtext), "A: %s, unexpected text %s.\n", + testmodes[mode], textA); + break; + } + break; + } + + return IsWindowUnicode(hwnd) ? CallWindowProcW(oldproc, hwnd, msg, wparam, lparam) : + CallWindowProcA(oldproc, hwnd, msg, wparam, lparam); +} + +static INT_PTR CALLBACK test_aw_conversion_dlgproc3(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam) +{ + BOOL is_unicode = !!lparam; + LONG_PTR oldproc; + + switch (msg) + { + case WM_INITDIALOG: + ok(is_unicode == IsWindowUnicode(hdlg), "Unexpected unicode window property.\n"); + + oldproc = SetWindowLongPtrA(hdlg, GWLP_WNDPROC, (LONG_PTR)test_aw_conversion_wndproc); + SetWindowLongPtrA(hdlg, GWLP_USERDATA, oldproc); + ok(!IsWindowUnicode(hdlg), "Unexpected unicode window.\n"); + + dlg_test_aw_message(hdlg, WM_WININICHANGE); + dlg_test_aw_message(hdlg, WM_DEVMODECHANGE); + dlg_test_aw_message(hdlg, CB_DIR); + dlg_test_aw_message(hdlg, LB_DIR); + dlg_test_aw_message(hdlg, LB_ADDFILE); + dlg_test_aw_message(hdlg, EM_REPLACESEL); + dlg_test_aw_message(hdlg, WM_SETTEXT); + + SetWindowLongPtrW(hdlg, GWLP_WNDPROC, (LONG_PTR)test_aw_conversion_wndproc); + ok(IsWindowUnicode(hdlg), "Expected unicode window.\n"); + + dlg_test_aw_message(hdlg, WM_WININICHANGE); + dlg_test_aw_message(hdlg, WM_DEVMODECHANGE); + dlg_test_aw_message(hdlg, CB_DIR); + dlg_test_aw_message(hdlg, LB_DIR); + dlg_test_aw_message(hdlg, LB_ADDFILE); + dlg_test_aw_message(hdlg, EM_REPLACESEL); + dlg_test_aw_message(hdlg, WM_SETTEXT); + + SetWindowLongPtrA(hdlg, GWLP_WNDPROC, oldproc); + EndDialog(hdlg, -123); + return TRUE; + } + return FALSE; +} + static void test_DialogBoxParam(void) { static const WCHAR nameW[] = {'T','E','S','T','_','E','M','P','T','Y','_','D','I','A','L','O','G',0}; @@ -1665,6 +1755,12 @@ static void test_DialogBoxParam(void) ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, test_aw_conversion_dlgproc2, 0); ok(ret == -123, "Unexpected ret value %ld.\n", ret); + + ret = DialogBoxParamW(GetModuleHandleA(NULL), nameW, 0, test_aw_conversion_dlgproc3, 1); + ok(ret == -123, "Unexpected ret value %ld.\n", ret); + + ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, test_aw_conversion_dlgproc3, 0); + ok(ret == -123, "Unexpected ret value %ld.\n", ret); } static void test_DisabledDialogTest(void) -- 2.15.1
[View Less]
2
1
0
0
[PATCH vkd3d 1/6] libs/vkd3d: Fix single descriptor handles in d3d12_command_list_OMSetRenderTargets().
by Józef Kucia
13 Feb '18
13 Feb '18
From: Józef Kucia <jkucia(a)codeweavers.com> Signed-off-by: Józef Kucia <jkucia(a)codeweavers.com> --- libs/vkd3d/command.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 4273a665e800..847581c03b65 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -3372,6 +3372,8 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(ID3D12Graphi BOOL single_descriptor_handle,
…
[View More]
const D3D12_CPU_DESCRIPTOR_HANDLE *depth_stencil_descriptor) { struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList(iface); + const struct d3d12_rtv_desc *rtv_desc; + const struct d3d12_dsv_desc *dsv_desc; unsigned int i; TRACE("iface %p, render_target_descriptor_count %u, render_target_descriptors %p, " @@ -3390,7 +3392,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(ID3D12Graphi list->fb_height = 0; for (i = 0; i < render_target_descriptor_count; ++i) { - const struct d3d12_rtv_desc *rtv_desc = d3d12_rtv_desc_from_cpu_handle(render_target_descriptors[i]); + if (single_descriptor_handle) + rtv_desc = d3d12_rtv_desc_from_cpu_handle(*render_target_descriptors) + i; + else + rtv_desc = d3d12_rtv_desc_from_cpu_handle(render_target_descriptors[i]); d3d12_command_list_track_resource_usage(list, rtv_desc->resource); @@ -3403,7 +3408,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(ID3D12Graphi if (depth_stencil_descriptor) { - const struct d3d12_dsv_desc *dsv_desc = d3d12_dsv_desc_from_cpu_handle(*depth_stencil_descriptor); + dsv_desc = d3d12_dsv_desc_from_cpu_handle(*depth_stencil_descriptor); d3d12_command_list_track_resource_usage(list, dsv_desc->resource); -- 2.13.6
[View Less]
2
11
0
0
← Newer
1
...
37
38
39
40
41
42
43
...
75
Older →
Jump to page:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
Results per page:
10
25
50
100
200