From: Jacek Caban jacek@codeweavers.com
Signed-off-by: Jacek Caban jacek@codeweavers.com --- dlls/user32/controls.h | 3 - dlls/user32/defwnd.c | 4 - dlls/user32/menu.c | 25 --- dlls/user32/nonclient.c | 70 ------- dlls/win32u/defwnd.c | 64 +++++++ dlls/win32u/menu.c | 345 +++++++++++++++++++++++++++++++++++ dlls/win32u/sysparams.c | 4 +- dlls/win32u/win32u_private.h | 3 + 8 files changed, 414 insertions(+), 104 deletions(-)
diff --git a/dlls/user32/controls.h b/dlls/user32/controls.h index 83d07e4ad76..2b6c4912709 100644 --- a/dlls/user32/controls.h +++ b/dlls/user32/controls.h @@ -114,8 +114,6 @@ extern BOOL update_wallpaper( const WCHAR *wallpaper, const WCHAR *pattern ) DEC
/* menu controls */ extern HWND MENU_IsMenuActive(void) DECLSPEC_HIDDEN; -extern UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth, - INT orgX, INT orgY ) DECLSPEC_HIDDEN; extern void MENU_TrackMouseMenuBar( HWND hwnd, INT ht, POINT pt ) DECLSPEC_HIDDEN; extern void MENU_TrackKbdMenuBar( HWND hwnd, UINT wParam, WCHAR wChar ) DECLSPEC_HIDDEN; extern UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd ) DECLSPEC_HIDDEN; @@ -123,7 +121,6 @@ extern void MENU_EndMenu(HWND) DECLSPEC_HIDDEN; extern HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu ) DECLSPEC_HIDDEN;
/* nonclient area */ -extern void NC_HandleNCCalcSize( HWND hwnd, WPARAM wParam, RECT *winRect ) DECLSPEC_HIDDEN; extern LRESULT NC_HandleNCHitTest( HWND hwnd, POINT pt ) DECLSPEC_HIDDEN; extern LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam ) DECLSPEC_HIDDEN; extern LRESULT NC_HandleNCMouseMove( HWND hwnd, WPARAM wParam, LPARAM lParam ) DECLSPEC_HIDDEN; diff --git a/dlls/user32/defwnd.c b/dlls/user32/defwnd.c index 9b23d1e6315..df5aa9353f4 100644 --- a/dlls/user32/defwnd.c +++ b/dlls/user32/defwnd.c @@ -173,10 +173,6 @@ static LRESULT DEFWND_DefWinProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPa return NC_HandleNCHitTest( hwnd, pt ); }
- case WM_NCCALCSIZE: - NC_HandleNCCalcSize( hwnd, wParam, (RECT *)lParam ); - break; - case WM_WINDOWPOSCHANGED: DEFWND_HandleWindowPosChanged( hwnd, (const WINDOWPOS *)lParam ); break; diff --git a/dlls/user32/menu.c b/dlls/user32/menu.c index 1ae722b7662..e30cb4110d2 100644 --- a/dlls/user32/menu.c +++ b/dlls/user32/menu.c @@ -3506,31 +3506,6 @@ LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM }
-/*********************************************************************** - * MENU_GetMenuBarHeight - * - * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize(). - */ -UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth, - INT orgX, INT orgY ) -{ - HDC hdc; - RECT rectBar; - LPPOPUPMENU lppop; - - TRACE("HWND %p, width %d, at (%d, %d).\n", hwnd, menubarWidth, orgX, orgY ); - - if (!(lppop = MENU_GetMenu( GetMenu(hwnd) ))) return 0; - - hdc = NtUserGetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW ); - SelectObject( hdc, get_menu_font(FALSE)); - SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU)); - MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd ); - NtUserReleaseDC( hwnd, hdc ); - return lppop->Height; -} - - /******************************************************************* * ChangeMenuA (USER32.@) */ diff --git a/dlls/user32/nonclient.c b/dlls/user32/nonclient.c index dab6b73ee1c..96518ed4648 100644 --- a/dlls/user32/nonclient.c +++ b/dlls/user32/nonclient.c @@ -341,76 +341,6 @@ BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRectExForDpi( LPRECT rect, DWORD style }
-/*********************************************************************** - * NC_HandleNCCalcSize - * - * Handle a WM_NCCALCSIZE message. Called from DefWindowProc(). - */ -void NC_HandleNCCalcSize( HWND hwnd, WPARAM wparam, RECT *winRect ) -{ - RECT tmpRect = { 0, 0, 0, 0 }; - LONG style = GetWindowLongW( hwnd, GWL_STYLE ); - LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE ); - - if (winRect == NULL) - return; - - if (!(style & WS_MINIMIZE)) - { - AdjustWindowRectEx( &tmpRect, style, FALSE, exStyle & ~WS_EX_CLIENTEDGE); - - winRect->left -= tmpRect.left; - winRect->top -= tmpRect.top; - winRect->right -= tmpRect.right; - winRect->bottom -= tmpRect.bottom; - - if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd)) - { - TRACE("Calling GetMenuBarHeight with hwnd %p, width %ld, at (%ld, %ld).\n", - hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top ); - - winRect->top += - MENU_GetMenuBarHeight( hwnd, - winRect->right - winRect->left, - -tmpRect.left, -tmpRect.top ); - } - - if( exStyle & WS_EX_CLIENTEDGE) - if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) && - winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE)) - InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE), - - GetSystemMetrics(SM_CYEDGE)); - - if (style & WS_VSCROLL) - if (winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL)) - { - /* rectangle is in screen coords when wparam is false */ - if (!wparam && (exStyle & WS_EX_LAYOUTRTL)) exStyle ^= WS_EX_LEFTSCROLLBAR; - - if((exStyle & WS_EX_LEFTSCROLLBAR) != 0) - winRect->left += GetSystemMetrics(SM_CXVSCROLL); - else - winRect->right -= GetSystemMetrics(SM_CXVSCROLL); - } - - if (style & WS_HSCROLL) - if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL)) - winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL); - - if (winRect->top > winRect->bottom) - winRect->bottom = winRect->top; - - if (winRect->left > winRect->right) - winRect->right = winRect->left; - } - else - { - winRect->right = winRect->left; - winRect->bottom = winRect->top; - } -} - - /*********************************************************************** * NC_GetInsideRect * diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c index db8187a3ea1..75a7efd2c8d 100644 --- a/dlls/win32u/defwnd.c +++ b/dlls/win32u/defwnd.c @@ -1487,6 +1487,66 @@ static LRESULT handle_nc_activate( HWND hwnd, WPARAM wparam, LPARAM lparam ) return TRUE; }
+static void handle_nc_calc_size( HWND hwnd, WPARAM wparam, RECT *win_rect ) +{ + RECT rect = { 0, 0, 0, 0 }; + LONG style = get_window_long( hwnd, GWL_STYLE ); + LONG ex_style = get_window_long( hwnd, GWL_EXSTYLE ); + + if (!win_rect) return; + + if (!(style & WS_MINIMIZE)) + { + AdjustWindowRectEx( &rect, style, FALSE, ex_style & ~WS_EX_CLIENTEDGE ); + + win_rect->left -= rect.left; + win_rect->top -= rect.top; + win_rect->right -= rect.right; + win_rect->bottom -= rect.bottom; + + if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && get_menu( hwnd )) + { + TRACE( "getting menu bar height with hwnd %p, width %d, at (%d, %d)\n", + hwnd, win_rect->right - win_rect->left, -rect.left, -rect.top ); + + win_rect->top += get_menu_bar_height( hwnd, win_rect->right - win_rect->left, + -rect.left, -rect.top ); + } + + if (ex_style & WS_EX_CLIENTEDGE) + if (win_rect->right - win_rect->left > 2 * get_system_metrics( SM_CXEDGE ) && + win_rect->bottom - win_rect->top > 2 * get_system_metrics( SM_CYEDGE )) + InflateRect( win_rect, -get_system_metrics( SM_CXEDGE ), + -get_system_metrics( SM_CYEDGE )); + + if ((style & WS_VSCROLL) && + win_rect->right - win_rect->left >= get_system_metrics( SM_CXVSCROLL )) + { + /* rectangle is in screen coords when wparam is false */ + if (!wparam && (ex_style & WS_EX_LAYOUTRTL)) ex_style ^= WS_EX_LEFTSCROLLBAR; + + if (ex_style & WS_EX_LEFTSCROLLBAR) + win_rect->left += get_system_metrics( SM_CXVSCROLL ); + else + win_rect->right -= get_system_metrics( SM_CXVSCROLL ); + } + + if ((style & WS_HSCROLL) && + win_rect->bottom - win_rect->top > get_system_metrics( SM_CYHSCROLL )) + { + win_rect->bottom -= get_system_metrics( SM_CYHSCROLL ); + } + + if (win_rect->top > win_rect->bottom) win_rect->bottom = win_rect->top; + if (win_rect->left > win_rect->right) win_rect->right = win_rect->left; + } + else + { + win_rect->right = win_rect->left; + win_rect->bottom = win_rect->top; + } +} + LRESULT default_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL ansi ) { LRESULT result = 0; @@ -1514,6 +1574,10 @@ LRESULT default_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, break; }
+ case WM_NCCALCSIZE: + handle_nc_calc_size( hwnd, wparam, (RECT *)lparam ); + break; + case WM_NCPAINT: return handle_nc_paint( hwnd, (HRGN)wparam );
diff --git a/dlls/win32u/menu.c b/dlls/win32u/menu.c index 4622105ddf1..2ac469908b9 100644 --- a/dlls/win32u/menu.c +++ b/dlls/win32u/menu.c @@ -23,6 +23,7 @@ #pragma makedep unix #endif
+#define OEMRESOURCE #include "win32u_private.h" #include "ntuser_private.h" #include "wine/server.h" @@ -59,6 +60,10 @@ struct accelerator #define STATE_MASK (~TYPE_MASK) #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
+ +static SIZE menucharsize; +static UINT od_item_hight; /* default owner drawn item height */ + /********************************************************************** * NtUserCopyAcceleratorTable (win32u.@) */ @@ -221,6 +226,17 @@ static void release_menu_ptr( POPUPMENU *menu ) } }
+/* + * Validate the given menu handle and returns the menu structure pointer. + * FIXME: this is unsafe, we should use a better mechanism instead. + */ +static POPUPMENU *unsafe_menu_ptr( HMENU handle ) +{ + POPUPMENU *menu = grab_menu_ptr( handle ); + if (menu) release_menu_ptr( menu ); + return menu; +} + /* see IsMenu */ static BOOL is_menu( HMENU handle ) { @@ -1327,3 +1343,332 @@ INT WINAPI NtUserTranslateAccelerator( HWND hwnd, HACCEL accel, MSG *msg ) if (ptr != data) free( ptr ); return (i < count); } + +static HFONT get_menu_font( BOOL bold ) +{ + static HFONT menu_font, menu_font_bold; + + HFONT ret = bold ? menu_font_bold : menu_font; + + if (!ret) + { + NONCLIENTMETRICSW ncm; + HFONT prev; + + ncm.cbSize = sizeof(NONCLIENTMETRICSW); + NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &ncm, 0 ); + + if (bold) + { + ncm.lfMenuFont.lfWeight += 300; + if (ncm.lfMenuFont.lfWeight > 1000) ncm.lfMenuFont.lfWeight = 1000; + } + if (!(ret = NtGdiHfontCreate( &ncm.lfMenuFont, sizeof(ncm.lfMenuFont), 0, 0, NULL ))) + return 0; + prev = InterlockedCompareExchangePointer( (void **)(bold ? &menu_font_bold : &menu_font), + ret, NULL ); + if (prev) + { + /* another thread beat us to it */ + NtGdiDeleteObjectApp( ret ); + ret = prev; + } + } + return ret; +} + +static HBITMAP get_arrow_bitmap(void) +{ + static HBITMAP arrow_bitmap; + + if (!arrow_bitmap) + arrow_bitmap = LoadImageW( 0, MAKEINTRESOURCEW(OBM_MNARROW), IMAGE_BITMAP, 0, 0, 0 ); + return arrow_bitmap; +} + +/* Get the size of a bitmap item */ +static void get_bitmap_item_size( MENUITEM *item, SIZE *size, HWND owner ) +{ + HBITMAP bmp = item->hbmpItem; + BITMAP bm; + + size->cx = size->cy = 0; + + /* check if there is a magic menu item associated with this item */ + switch ((INT_PTR)bmp) + { + case (INT_PTR)HBMMENU_CALLBACK: + { + MEASUREITEMSTRUCT meas_item; + meas_item.CtlType = ODT_MENU; + meas_item.CtlID = 0; + meas_item.itemID = item->wID; + meas_item.itemWidth = item->rect.right - item->rect.left; + meas_item.itemHeight = item->rect.bottom - item->rect.top; + meas_item.itemData = item->dwItemData; + send_message( owner, WM_MEASUREITEM, 0, (LPARAM)&meas_item ); + size->cx = meas_item.itemWidth; + size->cy = meas_item.itemHeight; + return; + } + break; + case (INT_PTR)HBMMENU_SYSTEM: + if (item->dwItemData) + { + bmp = (HBITMAP)item->dwItemData; + break; + } + /* fall through */ + case (INT_PTR)HBMMENU_MBAR_RESTORE: + case (INT_PTR)HBMMENU_MBAR_MINIMIZE: + case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D: + case (INT_PTR)HBMMENU_MBAR_CLOSE: + case (INT_PTR)HBMMENU_MBAR_CLOSE_D: + size->cx = get_system_metrics( SM_CYMENU ) - 4; + size->cy = size->cx; + return; + case (INT_PTR)HBMMENU_POPUP_CLOSE: + case (INT_PTR)HBMMENU_POPUP_RESTORE: + case (INT_PTR)HBMMENU_POPUP_MAXIMIZE: + case (INT_PTR)HBMMENU_POPUP_MINIMIZE: + size->cx = get_system_metrics( SM_CXMENUSIZE ); + size->cy = get_system_metrics( SM_CYMENUSIZE ); + return; + } + if (NtGdiExtGetObjectW( bmp, sizeof(bm), &bm )) + { + size->cx = bm.bmWidth; + size->cy = bm.bmHeight; + } +} + +/* Calculate the size of the menu item and store it in item->rect */ +static void calc_menu_item_size( HDC hdc, MENUITEM *item, HWND owner, INT org_x, INT org_y, + BOOL menu_bar, POPUPMENU *menu ) +{ + UINT check_bitmap_width = get_system_metrics( SM_CXMENUCHECK ); + UINT arrow_bitmap_width; + INT item_height; + BITMAP bm; + WCHAR *p; + + TRACE( "dc=%p owner=%p (%d,%d) item %s\n", hdc, owner, org_x, org_y, debugstr_menuitem( item )); + + NtGdiExtGetObjectW( get_arrow_bitmap(), sizeof(bm), &bm ); + arrow_bitmap_width = bm.bmWidth; + + if (!menucharsize.cx) + { + menucharsize.cx = get_char_dimensions( hdc, NULL, &menucharsize.cy ); + /* Win95/98/ME will use menucharsize.cy here. Testing is possible + * but it is unlikely an application will depend on that */ + od_item_hight = HIWORD( get_dialog_base_units() ); + } + + SetRect( &item->rect, org_x, org_y, org_x, org_y ); + + if (item->fType & MF_OWNERDRAW) + { + MEASUREITEMSTRUCT mis; + mis.CtlType = ODT_MENU; + mis.CtlID = 0; + mis.itemID = item->wID; + mis.itemData = item->dwItemData; + mis.itemHeight = od_item_hight; + mis.itemWidth = 0; + send_message( owner, WM_MEASUREITEM, 0, (LPARAM)&mis ); + /* Tests reveal that Windows ( Win95 through WinXP) adds twice the average + * width of a menufont character to the width of an owner-drawn menu. */ + item->rect.right += mis.itemWidth + 2 * menucharsize.cx; + if (menu_bar) + { + /* Under at least win95 you seem to be given a standard + * height for the menu and the height value is ignored. */ + item->rect.bottom += get_system_metrics( SM_CYMENUSIZE ); + } + else + item->rect.bottom += mis.itemHeight; + + TRACE( "id=%04lx size=%dx%d\n", item->wID, item->rect.right-item->rect.left, + item->rect.bottom-item->rect.top ); + return; + } + + if (item->fType & MF_SEPARATOR) + { + item->rect.bottom += get_system_metrics( SM_CYMENUSIZE ) / 2; + if (!menu_bar) item->rect.right += arrow_bitmap_width + menucharsize.cx; + return; + } + + item_height = 0; + item->xTab = 0; + + if (!menu_bar) + { + if (item->hbmpItem) + { + SIZE size; + + get_bitmap_item_size( item, &size, owner ); + /* Keep the size of the bitmap in callback mode to be able + * to draw it correctly */ + item->bmpsize = size; + menu->textOffset = max( menu->textOffset, size.cx ); + item->rect.right += size.cx + 2; + item_height = size.cy + 2; + } + if (!(menu->dwStyle & MNS_NOCHECK)) item->rect.right += check_bitmap_width; + item->rect.right += 4 + menucharsize.cx; + item->xTab = item->rect.right; + item->rect.right += arrow_bitmap_width; + } + else if (item->hbmpItem) /* menu_bar */ + { + SIZE size; + + get_bitmap_item_size( item, &size, owner ); + item->bmpsize = size; + item->rect.right += size.cx; + if (item->text) item->rect.right += 2; + item_height = size.cy; + } + + /* it must be a text item - unless it's the system menu */ + if (!(item->fType & MF_SYSMENU) && item->text) + { + LONG txt_height, txt_width; + HFONT prev_font = NULL; + RECT rc = item->rect; + + if (item->fState & MFS_DEFAULT) + prev_font = NtGdiSelectFont( hdc, get_menu_font(TRUE) ); + + if (menu_bar) + { + txt_height = DrawTextW( hdc, item->text, -1, &rc, DT_SINGLELINE | DT_CALCRECT ); + item->rect.right += rc.right - rc.left; + item_height = max( max( item_height, txt_height ), + get_system_metrics( SM_CYMENU ) - 1 ); + item->rect.right += 2 * menucharsize.cx; + } + else + { + if ((p = wcschr( item->text, '\t' ))) + { + RECT r = rc; + int h, n = (int)(p - item->text); + + /* Item contains a tab (only meaningful in popup menus) */ + /* get text size before the tab */ + txt_height = DrawTextW( hdc, item->text, n, &rc, DT_SINGLELINE | DT_CALCRECT ); + txt_width = rc.right - rc.left; + p += 1; /* advance past the Tab */ + /* get text size after the tab */ + h = DrawTextW( hdc, p, -1, &r, DT_SINGLELINE | DT_CALCRECT ); + item->xTab += txt_width; + txt_height = max( txt_height, h ); + /* space for the tab and the short cut */ + txt_width += menucharsize.cx + r.right - r.left; + } + else + { + txt_height = DrawTextW( hdc, item->text, -1, &rc, DT_SINGLELINE | DT_CALCRECT ); + txt_width = rc.right - rc.left; + item->xTab += txt_width; + } + item->rect.right += 2 + txt_width; + item_height = max( item_height, max( txt_height + 2, menucharsize.cy + 4 )); + } + if (prev_font) NtGdiSelectFont( hdc, prev_font ); + } + else if (menu_bar) + { + item_height = max( item_height, get_system_metrics( SM_CYMENU ) - 1 ); + } + item->rect.bottom += item_height; + TRACE( "%s\n", wine_dbgstr_rect( &item->rect )); +} + +/* Calculate the size of the menu bar */ +static void calc_menu_bar_size( HDC hdc, RECT *rect, POPUPMENU *menu, HWND owner ) +{ + UINT start, i, help_pos; + int org_x, org_y; + MENUITEM *item; + + if (!rect || !menu || !menu->nItems) return; + + TRACE( "rect %p %s\n", rect, wine_dbgstr_rect( rect )); + /* Start with a 1 pixel top border. + This corresponds to the difference between SM_CYMENU and SM_CYMENUSIZE. */ + SetRect( &menu->items_rect, 0, 0, rect->right - rect->left, 1 ); + start = 0; + help_pos = ~0u; + menu->textOffset = 0; + while (start < menu->nItems) + { + item = &menu->items[start]; + org_x = menu->items_rect.left; + org_y = menu->items_rect.bottom; + + /* Parse items until line break or end of menu */ + for (i = start; i < menu->nItems; i++, item++) + { + if (help_pos == ~0u && (item->fType & MF_RIGHTJUSTIFY)) help_pos = i; + if (i != start && (item->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break; + + TRACE("item org=(%d, %d) %s\n", org_x, org_y, debugstr_menuitem( item )); + calc_menu_item_size( hdc, item, owner, org_x, org_y, TRUE, menu ); + + if (item->rect.right > menu->items_rect.right) + { + if (i != start) break; + else item->rect.right = menu->items_rect.right; + } + menu->items_rect.bottom = max( menu->items_rect.bottom, item->rect.bottom ); + org_x = item->rect.right; + } + + /* Finish the line (set all items to the largest height found) */ + while (start < i) menu->items[start++].rect.bottom = menu->items_rect.bottom; + } + + OffsetRect( &menu->items_rect, rect->left, rect->top ); + menu->Width = menu->items_rect.right - menu->items_rect.left; + menu->Height = menu->items_rect.bottom - menu->items_rect.top; + rect->bottom = menu->items_rect.bottom; + + /* Flush right all items between the MF_RIGHTJUSTIFY and */ + /* the last item (if several lines, only move the last line) */ + if (help_pos == ~0u) return; + item = &menu->items[menu->nItems-1]; + org_y = item->rect.top; + org_x = rect->right - rect->left; + for (i = menu->nItems - 1; i >= help_pos; i--, item--) + { + if (item->rect.top != org_y) break; /* other line */ + if (item->rect.right >= org_x) break; /* too far right already */ + item->rect.left += org_x - item->rect.right; + item->rect.right = org_x; + org_x = item->rect.left; + } +} + +UINT get_menu_bar_height( HWND hwnd, UINT width, INT org_x, INT org_y ) +{ + POPUPMENU *menu; + RECT rect_bar; + HDC hdc; + + TRACE( "hwnd %p, width %d, at (%d, %d).\n", hwnd, width, org_x, org_y ); + + if (!(menu = unsafe_menu_ptr( get_menu( hwnd )))) return 0; + + hdc = NtUserGetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW ); + NtGdiSelectFont( hdc, get_menu_font(FALSE)); + SetRect( &rect_bar, org_x, org_y, org_x + width, org_y + get_system_metrics( SM_CYMENU )); + calc_menu_bar_size( hdc, &rect_bar, menu, hwnd ); + NtUserReleaseDC( hwnd, hdc ); + return menu->Height; +} diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 0b6053a5ab9..1c1d9ddc621 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2724,7 +2724,7 @@ static void get_real_fontname( LOGFONTW *lf, WCHAR fullname[LF_FACESIZE] ) lstrcpyW( fullname, lf->lfFaceName ); }
-static LONG get_char_dimensions( HDC hdc, TEXTMETRICW *metric, LONG *height ) +LONG get_char_dimensions( HDC hdc, TEXTMETRICW *metric, LONG *height ) { SIZE sz; static const WCHAR abcdW[] = @@ -2763,7 +2763,7 @@ static void get_text_metr_size( HDC hdc, LOGFONTW *lf, TEXTMETRICW *metric, UINT NtGdiDeleteObjectApp( hfont ); }
-static DWORD get_dialog_base_units(void) +DWORD get_dialog_base_units(void) { static LONG cx, cy;
diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index be15dac62e7..b8a2beeb15f 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -392,6 +392,7 @@ extern void update_mouse_tracking_info( HWND hwnd ) DECLSPEC_HIDDEN; extern HMENU create_menu( BOOL is_popup ) DECLSPEC_HIDDEN; extern BOOL draw_menu_bar( HWND hwnd ) DECLSPEC_HIDDEN; extern HMENU get_menu( HWND hwnd ) DECLSPEC_HIDDEN; +extern UINT get_menu_bar_height( HWND hwnd, UINT width, INT org_x, INT org_y ) DECLSPEC_HIDDEN; extern BOOL get_menu_info( HMENU handle, MENUINFO *info ) DECLSPEC_HIDDEN; extern INT get_menu_item_count( HMENU handle ) DECLSPEC_HIDDEN; extern UINT get_menu_state( HMENU handle, UINT item_id, UINT flags ) DECLSPEC_HIDDEN; @@ -413,6 +414,8 @@ extern LRESULT send_message_timeout( HWND hwnd, UINT msg, WPARAM wparam, LPARAM /* sysparams.c */ extern BOOL enable_thunk_lock DECLSPEC_HIDDEN; extern HBRUSH get_55aa_brush(void) DECLSPEC_HIDDEN; +extern DWORD get_dialog_base_units(void) DECLSPEC_HIDDEN; +extern LONG get_char_dimensions( HDC hdc, TEXTMETRICW *metric, LONG *height ) DECLSPEC_HIDDEN; extern RECT get_display_rect( const WCHAR *display ) DECLSPEC_HIDDEN; extern UINT get_monitor_dpi( HMONITOR monitor ) DECLSPEC_HIDDEN; extern BOOL get_monitor_info( HMONITOR handle, MONITORINFO *info ) DECLSPEC_HIDDEN;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=116898
Your paranoid android.
=== debian11 (32 bit report) ===
user32: menu.c:2324: Test failed: test 25
=== debian11 (32 bit Chinese:China report) ===
user32: win.c:11787: Test failed: 007200BE: expected NOT topmost win.c:11606: Test succeeded inside todo block: 5: hwnd 013F0054 is still topmost
From: Jacek Caban jacek@codeweavers.com
Signed-off-by: Jacek Caban jacek@codeweavers.com --- dlls/user32/menu.c | 140 +-------- dlls/user32/user32.spec | 2 +- dlls/win32u/dc.c | 13 + dlls/win32u/defwnd.c | 77 ++++- dlls/win32u/gdiobj.c | 1 + dlls/win32u/menu.c | 556 ++++++++++++++++++++++++++++++++++- dlls/win32u/ntgdi_private.h | 1 + dlls/win32u/win32u.spec | 2 +- dlls/win32u/win32u_private.h | 5 + dlls/win32u/wrappers.c | 6 + include/ntuser.h | 1 + 11 files changed, 659 insertions(+), 145 deletions(-)
diff --git a/dlls/user32/menu.c b/dlls/user32/menu.c index e30cb4110d2..1372baca6cc 100644 --- a/dlls/user32/menu.c +++ b/dlls/user32/menu.c @@ -119,8 +119,6 @@ static HMENU top_popup_hmenu; /* Flag set by EndMenu() to force an exit from menu tracking */ static BOOL fEndMenu = FALSE;
-DWORD WINAPI DrawMenuBarTemp(HWND hwnd, HDC hDC, LPRECT lprect, HMENU hMenu, HFONT hFont); - static BOOL is_win_menu_disallowed(HWND hwnd) { return (GetWindowLongW(hwnd, GWL_STYLE) & (WS_CHILD | WS_POPUP)) == WS_CHILD; @@ -1198,81 +1196,6 @@ static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, UINT max_height ) }
-/*********************************************************************** - * MENU_MenuBarCalcSize - * - * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap - * height is off by 1 pixel which causes lengthy window relocations when - * active document window is maximized/restored. - * - * Calculate the size of the menu bar. - */ -static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect, - LPPOPUPMENU lppop, HWND hwndOwner ) -{ - MENUITEM *lpitem; - UINT start, i, helpPos; - int orgX, orgY; - - if ((lprect == NULL) || (lppop == NULL)) return; - if (lppop->nItems == 0) return; - TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect)); - /* Start with a 1 pixel top border. - This corresponds to the difference between SM_CYMENU and SM_CYMENUSIZE. */ - SetRect(&lppop->items_rect, 0, 0, lprect->right - lprect->left, 1); - start = 0; - helpPos = ~0U; - lppop->textOffset = 0; - while (start < lppop->nItems) - { - lpitem = &lppop->items[start]; - orgX = lppop->items_rect.left; - orgY = lppop->items_rect.bottom; - - /* Parse items until line break or end of menu */ - for (i = start; i < lppop->nItems; i++, lpitem++) - { - if ((helpPos == ~0U) && (lpitem->fType & MF_RIGHTJUSTIFY)) helpPos = i; - if ((i != start) && - (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break; - - TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX, orgY ); - debug_print_menuitem (" item: ", lpitem, ""); - MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE, lppop ); - - if (lpitem->rect.right > lppop->items_rect.right) - { - if (i != start) break; - else lpitem->rect.right = lppop->items_rect.right; - } - lppop->items_rect.bottom = max( lppop->items_rect.bottom, lpitem->rect.bottom ); - orgX = lpitem->rect.right; - } - - /* Finish the line (set all items to the largest height found) */ - while (start < i) lppop->items[start++].rect.bottom = lppop->items_rect.bottom; - } - - OffsetRect(&lppop->items_rect, lprect->left, lprect->top); - lppop->Width = lppop->items_rect.right - lppop->items_rect.left; - lppop->Height = lppop->items_rect.bottom - lppop->items_rect.top; - lprect->bottom = lppop->items_rect.bottom; - - /* Flush right all items between the MF_RIGHTJUSTIFY and */ - /* the last item (if several lines, only move the last line) */ - if (helpPos == ~0U) return; - lpitem = &lppop->items[lppop->nItems-1]; - orgY = lpitem->rect.top; - orgX = lprect->right - lprect->left; - for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--) { - if (lpitem->rect.top != orgY) break; /* Other line */ - if (lpitem->rect.right >= orgX) break; /* Too far right already */ - lpitem->rect.left += orgX - lpitem->rect.right; - lpitem->rect.right = orgX; - orgX = lpitem->rect.left; - } -} - static void draw_scroll_arrow(HDC hdc, int x, int top, int height, BOOL up, BOOL enabled) { RECT rect, light_rect; @@ -1787,7 +1710,7 @@ UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd ) return GetSystemMetrics(SM_CYMENU); }
- return DrawMenuBarTemp(hwnd, hDC, lprect, hMenu, NULL); + return NtUserDrawMenuBarTemp( hwnd, hDC, lprect, hMenu, NULL ); }
@@ -4028,67 +3951,6 @@ BOOL WINAPI DrawMenuBar( HWND hwnd ) return NtUserDrawMenuBar( hwnd ); }
-/*********************************************************************** - * DrawMenuBarTemp (USER32.@) - * - * UNDOCUMENTED !! - * - * called by W98SE desk.cpl Control Panel Applet - * - * Not 100% sure about the param names, but close. - */ -DWORD WINAPI DrawMenuBarTemp(HWND hwnd, HDC hDC, LPRECT lprect, HMENU hMenu, HFONT hFont) -{ - LPPOPUPMENU lppop; - UINT i,retvalue; - HFONT hfontOld = 0; - BOOL flat_menu = FALSE; - - SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0); - - if (!hMenu) - hMenu = GetMenu(hwnd); - - if (!hFont) - hFont = get_menu_font(FALSE); - - lppop = MENU_GetMenu( hMenu ); - if (lppop == NULL || lprect == NULL) - { - retvalue = GetSystemMetrics(SM_CYMENU); - goto END; - } - - TRACE("(%p, %p, %p, %p, %p)\n", hwnd, hDC, lprect, hMenu, hFont); - - hfontOld = SelectObject( hDC, hFont); - - if (lppop->Height == 0) - MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd); - - lprect->bottom = lprect->top + lppop->Height; - - FillRect(hDC, lprect, GetSysColorBrush(flat_menu ? COLOR_MENUBAR : COLOR_MENU) ); - - SelectObject( hDC, SYSCOLOR_GetPen(COLOR_3DFACE)); - MoveToEx( hDC, lprect->left, lprect->bottom, NULL ); - LineTo( hDC, lprect->right, lprect->bottom ); - - if (lppop->nItems == 0) - { - retvalue = GetSystemMetrics(SM_CYMENU); - goto END; - } - - for (i = 0; i < lppop->nItems; i++) - MENU_DrawMenuItem( hwnd, lppop, hwnd, hDC, &lppop->items[i], TRUE, ODA_DRAWENTIRE ); - - retvalue = lppop->Height; - -END: - if (hfontOld) SelectObject (hDC, hfontOld); - return retvalue; -}
/*********************************************************************** * EndMenu (USER.187) diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index b41d661ee2a..1399f488720 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -194,7 +194,7 @@ @ stdcall DrawIcon(long long long long) @ stdcall DrawIconEx(long long long long long long long long long) NtUserDrawIconEx @ stdcall DrawMenuBar(long) -@ stdcall DrawMenuBarTemp(long long ptr long long) +@ stdcall DrawMenuBarTemp(long long ptr long long) NtUserDrawMenuBarTemp @ stdcall DrawStateA(long long ptr long long long long long long long) @ stdcall DrawStateW(long long ptr long long long long long long long) @ stdcall DrawTextA(long str long ptr long) diff --git a/dlls/win32u/dc.c b/dlls/win32u/dc.c index fc112f0d4b1..d43be1c20be 100644 --- a/dlls/win32u/dc.c +++ b/dlls/win32u/dc.c @@ -1103,6 +1103,19 @@ BOOL WINAPI NtGdiSetBrushOrg( HDC hdc, INT x, INT y, POINT *oldorg ) }
+BOOL set_viewport_org( HDC hdc, INT x, INT y, POINT *point ) +{ + DC *dc; + + if (!(dc = get_dc_ptr( hdc ))) return FALSE; + if (point) *point = dc->attr->vport_org; + dc->attr->vport_org.x = x; + dc->attr->vport_org.y = y; + release_dc_ptr( dc ); + return NtGdiComputeXformCoefficients( hdc ); +} + + /*********************************************************************** * NtGdiGetTransform (win32u.@) * diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c index 75a7efd2c8d..9a51b9a463a 100644 --- a/dlls/win32u/defwnd.c +++ b/dlls/win32u/defwnd.c @@ -138,7 +138,7 @@ static const signed char ltrb_inner_mono[] = { -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW, };
-static BOOL draw_rect_edge( HDC hdc, RECT *rc, UINT type, UINT flags, UINT width ) +BOOL draw_rect_edge( HDC hdc, RECT *rc, UINT type, UINT flags, UINT width ) { int lbi_offset = 0, lti_offset = 0, rti_offset = 0, rbi_offset = 0; signed char lt_inner, lt_outer, rb_inner, rb_outer; @@ -1016,7 +1016,7 @@ static void draw_caption_bar( HDC hdc, const RECT *rect, DWORD style, BOOL activ }
/* Draw the system icon */ -static BOOL draw_nc_sys_button( HWND hwnd, HDC hdc, BOOL down ) +BOOL draw_nc_sys_button( HWND hwnd, HDC hdc, BOOL down ) { HICON icon = get_nc_icon_for_window( hwnd );
@@ -1122,7 +1122,7 @@ static BOOL draw_push_button( HDC dc, RECT *r, UINT flags ) return TRUE; }
-static BOOL draw_frame_caption( HDC dc, RECT *r, UINT flags ) +BOOL draw_frame_caption( HDC dc, RECT *r, UINT flags ) { RECT rect; int small_diam = make_square_rect( r, &rect ) - 2; @@ -1181,6 +1181,77 @@ static BOOL draw_frame_caption( HDC dc, RECT *r, UINT flags ) return TRUE; }
+BOOL draw_frame_menu( HDC dc, RECT *r, UINT flags ) +{ + RECT rect; + int dmall_diam = make_square_rect( r, &rect ); + HBRUSH prev_brush; + HPEN prev_pen; + POINT points[6]; + int xe, ye; + int xc, yc; + BOOL retval = TRUE; + ULONG count; + int i; + + fill_rect( dc, r, GetStockObject( WHITE_BRUSH )); + + prev_brush = NtGdiSelectBrush( dc, GetStockObject( BLACK_BRUSH )); + prev_pen = NtGdiSelectPen( dc, GetStockObject( BLACK_PEN )); + + switch (flags & 0xff) + { + case DFCS_MENUARROW: + i = 187 * dmall_diam / 750; + points[2].x = rect.left + 468 * dmall_diam/ 750; + points[2].y = rect.top + 352 * dmall_diam/ 750 + 1; + points[0].y = points[2].y - i; + points[1].y = points[2].y + i; + points[0].x = points[1].x = points[2].x - i; + count = 3; + NtGdiPolyPolyDraw( dc, points, &count, 1, NtGdiPolyPolygon ); + break; + + case DFCS_MENUBULLET: + xe = rect.left; + ye = rect.top + dmall_diam - dmall_diam / 2; + xc = rect.left + dmall_diam - dmall_diam / 2; + yc = rect.top + dmall_diam - dmall_diam / 2; + i = 234 * dmall_diam / 750; + i = i < 1 ? 1 : i; + SetRect( &rect, xc - i + i / 2, yc - i + i / 2, xc + i / 2, yc + i / 2 ); + NtGdiArcInternal( NtGdiPie, dc, rect.left, rect.top, rect.right, rect.bottom, + xe, ye, xe, ye ); + break; + + case DFCS_MENUCHECK: + points[0].x = rect.left + 253 * dmall_diam / 1000; + points[0].y = rect.top + 445 * dmall_diam / 1000; + points[1].x = rect.left + 409 * dmall_diam / 1000; + points[1].y = points[0].y + (points[1].x - points[0].x); + points[2].x = rect.left + 690 * dmall_diam / 1000; + points[2].y = points[1].y - (points[2].x - points[1].x); + points[3].x = points[2].x; + points[3].y = points[2].y + 3 * dmall_diam / 16; + points[4].x = points[1].x; + points[4].y = points[1].y + 3 * dmall_diam / 16; + points[5].x = points[0].x; + points[5].y = points[0].y + 3 * dmall_diam / 16; + count = 6; + NtGdiPolyPolyDraw( dc, points, &count, 1, NtGdiPolyPolygon ); + break; + + default: + WARN( "Invalid menu; flags=0x%04x\n", flags ); + retval = FALSE; + break; + } + + NtGdiSelectPen( dc, prev_pen ); + NtGdiSelectBrush( dc, prev_brush ); + return retval; +} + static void draw_close_button( HWND hwnd, HDC hdc, BOOL down, BOOL grayed ) { RECT rect; diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c index 72924bb658a..9c6415236c2 100644 --- a/dlls/win32u/gdiobj.c +++ b/dlls/win32u/gdiobj.c @@ -1160,6 +1160,7 @@ static struct unix_funcs unix_funcs = NtUserDispatchMessage, NtUserDragDetect, NtUserDrawIconEx, + NtUserDrawMenuBarTemp, NtUserEmptyClipboard, NtUserEnableMenuItem, NtUserEndDeferWindowPosEx, diff --git a/dlls/win32u/menu.c b/dlls/win32u/menu.c index 2ac469908b9..182dbb6cf58 100644 --- a/dlls/win32u/menu.c +++ b/dlls/win32u/menu.c @@ -24,7 +24,7 @@ #endif
#define OEMRESOURCE -#include "win32u_private.h" +#include "ntgdi_private.h" #include "ntuser_private.h" #include "wine/server.h" #include "wine/debug.h" @@ -48,6 +48,9 @@ struct accelerator /* (other menu->FocusedItem values give the position of the focused item) */ #define NO_SELECTED_ITEM 0xffff
+/* Space between 2 columns */ +#define MENU_COL_SPACE 4 + /* macro to test that flags do not indicate bitmap, ownerdraw or separator */ #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING) #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1)) @@ -1672,3 +1675,554 @@ UINT get_menu_bar_height( HWND hwnd, UINT width, INT org_x, INT org_y ) NtUserReleaseDC( hwnd, hdc ); return menu->Height; } + +static void draw_popup_arrow( HDC hdc, RECT rect, UINT arrow_width, UINT arrow_height ) +{ + HDC mem_hdc = NtGdiCreateCompatibleDC( hdc ); + HBITMAP prev_bitmap; + + prev_bitmap = NtGdiSelectBitmap( mem_hdc, get_arrow_bitmap() ); + NtGdiBitBlt( hdc, rect.right - arrow_width - 1, + (rect.top + rect.bottom - arrow_height) / 2, + arrow_width, arrow_height, mem_hdc, 0, 0, SRCCOPY, 0, 0 ); + NtGdiSelectBitmap( mem_hdc, prev_bitmap ); + NtGdiDeleteObjectApp( mem_hdc ); +} + +static void draw_bitmap_item( HDC hdc, MENUITEM *item, const RECT *rect, + POPUPMENU *menu, HWND owner, UINT odaction ) +{ + int w = rect->right - rect->left; + int h = rect->bottom - rect->top; + int bmp_xoffset = 0, left, top; + HBITMAP bmp_to_draw = item->hbmpItem; + HBITMAP bmp = bmp_to_draw; + BITMAP bm; + DWORD rop; + HDC mem_hdc; + + /* Check if there is a magic menu item associated with this item */ + if (IS_MAGIC_BITMAP( bmp_to_draw )) + { + UINT flags = 0; + WCHAR bmchr = 0; + RECT r; + + switch ((INT_PTR)bmp_to_draw) + { + case (INT_PTR)HBMMENU_SYSTEM: + if (item->dwItemData) + { + bmp = (HBITMAP)item->dwItemData; + if (!NtGdiExtGetObjectW( bmp, sizeof(bm), &bm )) return; + } + else + { + static HBITMAP sys_menu_bmp; + + if (!sys_menu_bmp) + sys_menu_bmp = LoadImageW( 0, MAKEINTRESOURCEW(OBM_CLOSE), IMAGE_BITMAP, 0, 0, 0 ); + bmp = sys_menu_bmp; + if (!NtGdiExtGetObjectW( bmp, sizeof(bm), &bm )) return; + /* only use right half of the bitmap */ + bmp_xoffset = bm.bmWidth / 2; + bm.bmWidth -= bmp_xoffset; + } + goto got_bitmap; + case (INT_PTR)HBMMENU_MBAR_RESTORE: + flags = DFCS_CAPTIONRESTORE; + break; + case (INT_PTR)HBMMENU_MBAR_MINIMIZE: + flags = DFCS_CAPTIONMIN; + break; + case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D: + flags = DFCS_CAPTIONMIN | DFCS_INACTIVE; + break; + case (INT_PTR)HBMMENU_MBAR_CLOSE: + flags = DFCS_CAPTIONCLOSE; + break; + case (INT_PTR)HBMMENU_MBAR_CLOSE_D: + flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE; + break; + case (INT_PTR)HBMMENU_CALLBACK: + { + DRAWITEMSTRUCT drawItem; + drawItem.CtlType = ODT_MENU; + drawItem.CtlID = 0; + drawItem.itemID = item->wID; + drawItem.itemAction = odaction; + drawItem.itemState = 0; + if (item->fState & MF_CHECKED) drawItem.itemState |= ODS_CHECKED; + if (item->fState & MF_DEFAULT) drawItem.itemState |= ODS_DEFAULT; + if (item->fState & MF_DISABLED) drawItem.itemState |= ODS_DISABLED; + if (item->fState & MF_GRAYED) drawItem.itemState |= ODS_GRAYED|ODS_DISABLED; + if (item->fState & MF_HILITE) drawItem.itemState |= ODS_SELECTED; + drawItem.hwndItem = (HWND)menu->obj.handle; + drawItem.hDC = hdc; + drawItem.itemData = item->dwItemData; + drawItem.rcItem = *rect; + send_message( owner, WM_DRAWITEM, 0, (LPARAM)&drawItem ); + return; + } + break; + case (INT_PTR)HBMMENU_POPUP_CLOSE: + bmchr = 0x72; + break; + case (INT_PTR)HBMMENU_POPUP_RESTORE: + bmchr = 0x32; + break; + case (INT_PTR)HBMMENU_POPUP_MAXIMIZE: + bmchr = 0x31; + break; + case (INT_PTR)HBMMENU_POPUP_MINIMIZE: + bmchr = 0x30; + break; + default: + FIXME( "Magic %p not implemented\n", bmp_to_draw ); + return; + } + + if (bmchr) + { + /* draw the magic bitmaps using marlett font characters */ + /* FIXME: fontsize and the position (x,y) could probably be better */ + HFONT hfont, prev_font; + LOGFONTW logfont = { 0, 0, 0, 0, FW_NORMAL, 0, 0, 0, SYMBOL_CHARSET, 0, 0, 0, 0, + {'M','a','r','l','e','t','t'}}; + logfont.lfHeight = min( h, w) - 5 ; + TRACE( " height %d rect %s\n", logfont.lfHeight, wine_dbgstr_rect( rect )); + hfont = NtGdiHfontCreate( &logfont, sizeof(logfont), 0, 0, NULL ); + prev_font = NtGdiSelectFont( hdc, hfont ); + NtGdiExtTextOutW( hdc, rect->left, rect->top + 2, 0, NULL, &bmchr, 1, NULL, 0 ); + NtGdiSelectFont( hdc, prev_font ); + NtGdiDeleteObjectApp( hfont ); + } + else + { + r = *rect; + InflateRect( &r, -1, -1 ); + if (item->fState & MF_HILITE) flags |= DFCS_PUSHED; + draw_frame_caption( hdc, &r, flags ); + } + return; + } + + if (!bmp || !NtGdiExtGetObjectW( bmp, sizeof(bm), &bm )) return; + +got_bitmap: + mem_hdc = NtGdiCreateCompatibleDC( hdc ); + NtGdiSelectBitmap( mem_hdc, bmp ); + + /* handle fontsize > bitmap_height */ + top = (h>bm.bmHeight) ? rect->top + (h - bm.bmHeight) / 2 : rect->top; + left=rect->left; + rop= ((item->fState & MF_HILITE) && !IS_MAGIC_BITMAP(bmp_to_draw)) ? NOTSRCCOPY : SRCCOPY; + if ((item->fState & MF_HILITE) && item->hbmpItem) + NtGdiGetAndSetDCDword( hdc, NtGdiSetBkColor, get_sys_color( COLOR_HIGHLIGHT ), NULL ); + NtGdiBitBlt( hdc, left, top, w, h, mem_hdc, bmp_xoffset, 0, rop, 0, 0 ); + NtGdiDeleteObjectApp( mem_hdc ); +} + +/* Adjust menu item rectangle according to scrolling state */ +static void adjust_menu_item_rect( const POPUPMENU *menu, RECT *rect ) +{ + INT scroll_offset = menu->bScrolling ? menu->nScrollPos : 0; + OffsetRect( rect, menu->items_rect.left, menu->items_rect.top - scroll_offset ); +} + +/* Draw a single menu item */ +static void draw_menu_item( HWND hwnd, POPUPMENU *menu, HWND owner, HDC hdc, + MENUITEM *item, BOOL menu_bar, UINT odaction ) +{ + UINT arrow_width = 0, arrow_height = 0; + HRGN old_clip = NULL, clip; + BOOL flat_menu = FALSE; + RECT rect, bmprc; + int bkgnd; + + TRACE( "%s\n", debugstr_menuitem( item )); + + if (!menu_bar) + { + BITMAP bmp; + NtGdiExtGetObjectW( get_arrow_bitmap(), sizeof(bmp), &bmp ); + arrow_width = bmp.bmWidth; + arrow_height = bmp.bmHeight; + } + + if (item->fType & MF_SYSMENU) + { + if (!is_iconic( hwnd )) + draw_nc_sys_button( hwnd, hdc, item->fState & (MF_HILITE | MF_MOUSESELECT) ); + return; + } + + TRACE( "rect=%s\n", wine_dbgstr_rect( &item->rect )); + rect = item->rect; + adjust_menu_item_rect( menu, &rect ); + if (!intersect_rect( &bmprc, &rect, &menu->items_rect )) /* bmprc is used as a dummy */ + return; + + NtUserSystemParametersInfo( SPI_GETFLATMENU, 0, &flat_menu, 0 ); + bkgnd = (menu_bar && flat_menu) ? COLOR_MENUBAR : COLOR_MENU; + + /* Setup colors */ + if (item->fState & MF_HILITE) + { + if (menu_bar && !flat_menu) + { + NtGdiGetAndSetDCDword( hdc, NtGdiSetTextColor, get_sys_color(COLOR_MENUTEXT), NULL ); + NtGdiGetAndSetDCDword( hdc, NtGdiSetBkColor, get_sys_color(COLOR_MENU), NULL ); + } + else + { + if (item->fState & MF_GRAYED) + NtGdiGetAndSetDCDword( hdc, NtGdiSetTextColor, get_sys_color( COLOR_GRAYTEXT ), NULL ); + else + NtGdiGetAndSetDCDword( hdc, NtGdiSetTextColor, get_sys_color( COLOR_HIGHLIGHTTEXT ), NULL ); + NtGdiGetAndSetDCDword( hdc, NtGdiSetBkColor, get_sys_color( COLOR_HIGHLIGHT ), NULL ); + } + } + else + { + if (item->fState & MF_GRAYED) + NtGdiGetAndSetDCDword( hdc, NtGdiSetTextColor, get_sys_color( COLOR_GRAYTEXT ), NULL ); + else + NtGdiGetAndSetDCDword( hdc, NtGdiSetTextColor, get_sys_color( COLOR_MENUTEXT ), NULL ); + NtGdiGetAndSetDCDword( hdc, NtGdiSetBkColor, get_sys_color( bkgnd ), NULL ); + } + + old_clip = NtGdiCreateRectRgn( 0, 0, 0, 0 ); + if (NtGdiGetRandomRgn( hdc, old_clip, NTGDI_RGN_MIRROR_RTL | 1 ) <= 0) + { + NtGdiDeleteObjectApp( old_clip ); + old_clip = NULL; + } + clip = NtGdiCreateRectRgn( menu->items_rect.left, menu->items_rect.top, + menu->items_rect.right, menu->items_rect.bottom ); + NtGdiExtSelectClipRgn( hdc, clip, RGN_AND ); + NtGdiDeleteObjectApp( clip ); + + if (item->fType & MF_OWNERDRAW) + { + /* + * Experimentation under Windows reveals that an owner-drawn + * menu is given the rectangle which includes the space it requested + * in its response to WM_MEASUREITEM _plus_ width for a checkmark + * and a popup-menu arrow. This is the value of item->rect. + * Windows will leave all drawing to the application except for + * the popup-menu arrow. Windows always draws that itself, after + * the menu owner has finished drawing. + */ + DRAWITEMSTRUCT dis; + DWORD old_bk, old_text; + + dis.CtlType = ODT_MENU; + dis.CtlID = 0; + dis.itemID = item->wID; + dis.itemData = item->dwItemData; + dis.itemState = 0; + if (item->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED; + if (item->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED|ODS_DISABLED; + if (item->fState & MF_HILITE) dis.itemState |= ODS_SELECTED; + dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */ + dis.hwndItem = (HWND)menu->obj.handle; + dis.hDC = hdc; + dis.rcItem = rect; + TRACE( "Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, " + "hwndItem=%p, hdc=%p, rcItem=%s\n", owner, + dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem, + dis.hDC, wine_dbgstr_rect( &dis.rcItem )); + NtGdiGetDCDword( hdc, NtGdiGetBkColor, &old_bk ); + NtGdiGetDCDword( hdc, NtGdiGetTextColor, &old_text ); + send_message( owner, WM_DRAWITEM, 0, (LPARAM)&dis ); + /* Draw the popup-menu arrow */ + NtGdiGetAndSetDCDword( hdc, NtGdiGetBkColor, old_bk, NULL ); + NtGdiGetAndSetDCDword( hdc, NtGdiGetTextColor, old_text, NULL ); + if (item->fType & MF_POPUP) + draw_popup_arrow( hdc, rect, arrow_width, arrow_height ); + goto done; + } + + if (menu_bar && (item->fType & MF_SEPARATOR)) goto done; + + if (item->fState & MF_HILITE) + { + if (flat_menu) + { + InflateRect (&rect, -1, -1); + fill_rect( hdc, &rect, get_sys_color_brush( COLOR_MENUHILIGHT )); + InflateRect (&rect, 1, 1); + fill_rect( hdc, &rect, get_sys_color_brush( COLOR_HIGHLIGHT )); + } + else + { + if (menu_bar) + draw_rect_edge( hdc, &rect, BDR_SUNKENOUTER, BF_RECT, 1 ); + else + fill_rect( hdc, &rect, get_sys_color_brush( COLOR_HIGHLIGHT )); + } + } + else + fill_rect( hdc, &rect, get_sys_color_brush(bkgnd) ); + + NtGdiGetAndSetDCDword( hdc, NtGdiSetBkMode, TRANSPARENT, NULL ); + + /* vertical separator */ + if (!menu_bar && (item->fType & MF_MENUBARBREAK)) + { + HPEN oldPen; + RECT rc = rect; + + rc.left -= MENU_COL_SPACE / 2 + 1; + rc.top = 3; + rc.bottom = menu->Height - 3; + if (flat_menu) + { + oldPen = NtGdiSelectPen( hdc, get_sys_color_pen( COLOR_BTNSHADOW )); + NtGdiMoveTo( hdc, rc.left, rc.top, NULL ); + NtGdiLineTo( hdc, rc.left, rc.bottom ); + NtGdiSelectPen( hdc, oldPen ); + } + else + draw_rect_edge( hdc, &rc, EDGE_ETCHED, BF_LEFT, 1 ); + } + + /* horizontal separator */ + if (item->fType & MF_SEPARATOR) + { + HPEN oldPen; + RECT rc = rect; + + InflateRect( &rc, -1, 0 ); + rc.top = ( rc.top + rc.bottom) / 2; + if (flat_menu) + { + oldPen = NtGdiSelectPen( hdc, get_sys_color_pen( COLOR_BTNSHADOW )); + NtGdiMoveTo( hdc, rc.left, rc.top, NULL ); + NtGdiLineTo( hdc, rc.right, rc.top ); + NtGdiSelectPen( hdc, oldPen ); + } + else + draw_rect_edge( hdc, &rc, EDGE_ETCHED, BF_TOP, 1 ); + goto done; + } + + if (item->hbmpItem) + { + /* calculate the bitmap rectangle in coordinates relative + * to the item rectangle */ + if (menu_bar) + { + if (item->hbmpItem == HBMMENU_CALLBACK) + bmprc.left = 3; + else + bmprc.left = item->text ? menucharsize.cx : 0; + } + else if (menu->dwStyle & MNS_NOCHECK) + bmprc.left = 4; + else if (menu->dwStyle & MNS_CHECKORBMP) + bmprc.left = 2; + else + bmprc.left = 4 + get_system_metrics( SM_CXMENUCHECK ); + bmprc.right = bmprc.left + item->bmpsize.cx; + if (menu_bar && !(item->hbmpItem == HBMMENU_CALLBACK)) + bmprc.top = 0; + else + bmprc.top = (rect.bottom - rect.top - item->bmpsize.cy) / 2; + bmprc.bottom = bmprc.top + item->bmpsize.cy; + } + + if (!menu_bar) + { + HBITMAP bm; + INT y = rect.top + rect.bottom; + BOOL checked = FALSE; + UINT check_bitmap_width = get_system_metrics( SM_CXMENUCHECK ); + UINT check_bitmap_height = get_system_metrics( SM_CYMENUCHECK ); + + /* Draw the check mark */ + if (!(menu->dwStyle & MNS_NOCHECK)) + { + bm = (item->fState & MF_CHECKED) ? item->hCheckBit : + item->hUnCheckBit; + if (bm) /* we have a custom bitmap */ + { + HDC mem_hdc = NtGdiCreateCompatibleDC( hdc ); + + NtGdiSelectBitmap( mem_hdc, bm ); + NtGdiBitBlt( hdc, rect.left, (y - check_bitmap_height) / 2, + check_bitmap_width, check_bitmap_height, + mem_hdc, 0, 0, SRCCOPY, 0, 0 ); + NtGdiDeleteObjectApp( mem_hdc ); + checked = TRUE; + } + else if (item->fState & MF_CHECKED) /* standard bitmaps */ + { + RECT r; + HBITMAP bm = NtGdiCreateBitmap( check_bitmap_width, + check_bitmap_height, 1, 1, NULL ); + HDC mem_hdc = NtGdiCreateCompatibleDC( hdc ); + + NtGdiSelectBitmap( mem_hdc, bm ); + SetRect( &r, 0, 0, check_bitmap_width, check_bitmap_height); + draw_frame_menu( mem_hdc, &r, + (item->fType & MFT_RADIOCHECK) ? DFCS_MENUBULLET : DFCS_MENUCHECK ); + NtGdiBitBlt( hdc, rect.left, (y - r.bottom) / 2, r.right, r.bottom, + mem_hdc, 0, 0, SRCCOPY, 0, 0 ); + NtGdiDeleteObjectApp( mem_hdc ); + NtGdiDeleteObjectApp( bm ); + checked = TRUE; + } + } + if (item->hbmpItem && !(checked && (menu->dwStyle & MNS_CHECKORBMP))) + { + POINT origorg; + /* some applications make this assumption on the DC's origin */ + set_viewport_org( hdc, rect.left, rect.top, &origorg ); + draw_bitmap_item( hdc, item, &bmprc, menu, owner, odaction ); + set_viewport_org( hdc, origorg.x, origorg.y, NULL ); + } + /* Draw the popup-menu arrow */ + if (item->fType & MF_POPUP) + draw_popup_arrow( hdc, rect, arrow_width, arrow_height); + rect.left += 4; + if (!(menu->dwStyle & MNS_NOCHECK)) + rect.left += check_bitmap_width; + rect.right -= arrow_width; + } + else if (item->hbmpItem) + { /* Draw the bitmap */ + POINT origorg; + + set_viewport_org( hdc, rect.left, rect.top, &origorg); + draw_bitmap_item( hdc, item, &bmprc, menu, owner, odaction ); + set_viewport_org( hdc, origorg.x, origorg.y, NULL); + } + /* process text if present */ + if (item->text) + { + int i; + HFONT prev_font = 0; + UINT format = menu_bar ? + DT_CENTER | DT_VCENTER | DT_SINGLELINE : + DT_LEFT | DT_VCENTER | DT_SINGLELINE; + + if (!(menu->dwStyle & MNS_CHECKORBMP)) + rect.left += menu->textOffset; + + if (item->fState & MFS_DEFAULT) + { + prev_font = NtGdiSelectFont(hdc, get_menu_font( TRUE )); + } + + if (menu_bar) + { + if (item->hbmpItem) + rect.left += item->bmpsize.cx; + if (item->hbmpItem != HBMMENU_CALLBACK) + rect.left += menucharsize.cx; + rect.right -= menucharsize.cx; + } + + for (i = 0; item->text[i]; i++) + if ((item->text[i] == '\t') || (item->text[i] == '\b')) + break; + + if (item->fState & MF_GRAYED) + { + if (!(item->fState & MF_HILITE) ) + { + ++rect.left; ++rect.top; ++rect.right; ++rect.bottom; + NtGdiGetAndSetDCDword( hdc, NtGdiSetTextColor, RGB(0xff, 0xff, 0xff), NULL ); + DrawTextW( hdc, item->text, i, &rect, format ); + --rect.left; --rect.top; --rect.right; --rect.bottom; + } + NtGdiGetAndSetDCDword( hdc, NtGdiSetTextColor, RGB(0x80, 0x80, 0x80), NULL ); + } + + DrawTextW( hdc, item->text, i, &rect, format ); + + /* paint the shortcut text */ + if (!menu_bar && item->text[i]) /* There's a tab or flush-right char */ + { + if (item->text[i] == '\t') + { + rect.left = item->xTab; + format = DT_LEFT | DT_VCENTER | DT_SINGLELINE; + } + else + { + rect.right = item->xTab; + format = DT_RIGHT | DT_VCENTER | DT_SINGLELINE; + } + + if (item->fState & MF_GRAYED) + { + if (!(item->fState & MF_HILITE) ) + { + ++rect.left; ++rect.top; ++rect.right; ++rect.bottom; + NtGdiGetAndSetDCDword( hdc, NtGdiSetTextColor, RGB(0xff, 0xff, 0xff), NULL ); + DrawTextW( hdc, item->text + i + 1, -1, &rect, format ); + --rect.left; --rect.top; --rect.right; --rect.bottom; + } + NtGdiGetAndSetDCDword( hdc, NtGdiSetTextColor, RGB(0x80, 0x80, 0x80), NULL ); + } + DrawTextW( hdc, item->text + i + 1, -1, &rect, format ); + } + + if (prev_font) NtGdiSelectFont( hdc, prev_font ); + } + +done: + NtGdiExtSelectClipRgn( hdc, old_clip, RGN_COPY ); + if (old_clip) NtGdiDeleteObjectApp( old_clip ); +} + +/*********************************************************************** + * NtUserDrawMenuBarTemp (win32u.@) + */ +DWORD WINAPI NtUserDrawMenuBarTemp( HWND hwnd, HDC hdc, RECT *rect, HMENU handle, HFONT font ) +{ + BOOL flat_menu = FALSE; + HFONT prev_font = 0; + POPUPMENU *menu; + UINT i, retvalue; + + NtUserSystemParametersInfo( SPI_GETFLATMENU, 0, &flat_menu, 0 ); + + if (!handle) handle = get_menu( hwnd ); + if (!font) font = get_menu_font(FALSE); + + menu = unsafe_menu_ptr( handle ); + if (!menu || !rect) return get_system_metrics( SM_CYMENU ); + + TRACE( "(%p, %p, %p, %p, %p)\n", hwnd, hdc, rect, handle, font ); + + prev_font = NtGdiSelectFont( hdc, font ); + + if (!menu->Height) calc_menu_bar_size( hdc, rect, menu, hwnd ); + + rect->bottom = rect->top + menu->Height; + + fill_rect( hdc, rect, get_sys_color_brush( flat_menu ? COLOR_MENUBAR : COLOR_MENU )); + + NtGdiSelectPen( hdc, get_sys_color_pen( COLOR_3DFACE )); + NtGdiMoveTo( hdc, rect->left, rect->bottom, NULL ); + NtGdiLineTo( hdc, rect->right, rect->bottom ); + + if (menu->nItems) + { + for (i = 0; i < menu->nItems; i++) + draw_menu_item( hwnd, menu, hwnd, hdc, &menu->items[i], TRUE, ODA_DRAWENTIRE ); + + retvalue = menu->Height; + } + else + { + retvalue = get_system_metrics( SM_CYMENU ); + } + + if (prev_font) NtGdiSelectFont( hdc, prev_font ); + return retvalue; +} diff --git a/dlls/win32u/ntgdi_private.h b/dlls/win32u/ntgdi_private.h index b04f7a87e34..ac552897769 100644 --- a/dlls/win32u/ntgdi_private.h +++ b/dlls/win32u/ntgdi_private.h @@ -181,6 +181,7 @@ extern struct dce *get_dc_dce( HDC hdc ) DECLSPEC_HIDDEN; extern void set_dc_dce( HDC hdc, struct dce *dce ) DECLSPEC_HIDDEN; extern WORD set_dce_flags( HDC hdc, WORD flags ) DECLSPEC_HIDDEN; extern DWORD set_stretch_blt_mode( HDC hdc, DWORD mode ) DECLSPEC_HIDDEN; +extern BOOL set_viewport_org( HDC hdc, INT x, INT y, POINT *point ) DECLSPEC_HIDDEN; extern void DC_InitDC( DC * dc ) DECLSPEC_HIDDEN; extern void DC_UpdateXforms( DC * dc ) DECLSPEC_HIDDEN;
diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index de500da143b..4dfebaa9d2d 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -851,7 +851,7 @@ @ stub NtUserDrawCaption @ stub NtUserDrawCaptionTemp @ stdcall NtUserDrawIconEx(long long long long long long long long long) -@ stub NtUserDrawMenuBarTemp +@ stdcall NtUserDrawMenuBarTemp(long long ptr long long) @ stub NtUserDwmGetRemoteSessionOcclusionEvent @ stub NtUserDwmGetRemoteSessionOcclusionState @ stub NtUserDwmKernelShutdown diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index b8a2beeb15f..5f5563ec9f9 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -217,6 +217,7 @@ struct unix_funcs BOOL (WINAPI *pNtUserDragDetect)( HWND hwnd, int x, int y ); BOOL (WINAPI *pNtUserDrawIconEx)( HDC hdc, INT x0, INT y0, HICON icon, INT width, INT height, UINT istep, HBRUSH hbr, UINT flags ); + DWORD (WINAPI *pNtUserDrawMenuBarTemp)( HWND hwnd, HDC hdc, RECT *rect, HMENU handle, HFONT font ); BOOL (WINAPI *pNtUserEmptyClipboard)(void); BOOL (WINAPI *pNtUserEnableMenuItem)( HMENU handle, UINT id, UINT flags ); BOOL (WINAPI *pNtUserEndDeferWindowPosEx)( HDWP hdwp, BOOL async ); @@ -365,6 +366,10 @@ extern void register_window_surface( struct window_surface *old, extern LRESULT default_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL ansi ) DECLSPEC_HIDDEN; extern LRESULT desktop_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) DECLSPEC_HIDDEN; +extern BOOL draw_frame_caption( HDC dc, LPRECT r, UINT uFlags ) DECLSPEC_HIDDEN; +extern BOOL draw_frame_menu( HDC dc, RECT *r, UINT flags ) DECLSPEC_HIDDEN; +extern BOOL draw_nc_sys_button( HWND hwnd, HDC hdc, BOOL down ) DECLSPEC_HIDDEN; +extern BOOL draw_rect_edge( HDC hdc, RECT *rc, UINT uType, UINT uFlags, UINT width ) DECLSPEC_HIDDEN; extern void fill_rect( HDC dc, const RECT *rect, HBRUSH hbrush ) DECLSPEC_HIDDEN;
/* hook.c */ diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c index 99e0b9f3d88..6620597b7b1 100644 --- a/dlls/win32u/wrappers.c +++ b/dlls/win32u/wrappers.c @@ -868,6 +868,12 @@ BOOL WINAPI NtUserDrawIconEx( HDC hdc, INT x0, INT y0, HICON icon, INT width, return unix_funcs->pNtUserDrawIconEx( hdc, x0, y0, icon, width, height, istep, hbr, flags ); }
+DWORD WINAPI NtUserDrawMenuBarTemp( HWND hwnd, HDC hdc, RECT *rect, HMENU handle, HFONT font ) +{ + if (!unix_funcs) return 0; + return unix_funcs->pNtUserDrawMenuBarTemp( hwnd, hdc, rect, handle, font ); +} + BOOL WINAPI NtUserEnableMenuItem( HMENU handle, UINT id, UINT flags ) { if (!unix_funcs) return FALSE; diff --git a/include/ntuser.h b/include/ntuser.h index f2fdab6c0f9..9cf26534e10 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -539,6 +539,7 @@ LRESULT WINAPI NtUserDispatchMessage( const MSG *msg ); BOOL WINAPI NtUserDragDetect( HWND hwnd, int x, int y ); BOOL WINAPI NtUserDrawIconEx( HDC hdc, INT x0, INT y0, HICON icon, INT width, INT height, UINT istep, HBRUSH hbr, UINT flags ); +DWORD WINAPI NtUserDrawMenuBarTemp( HWND hwnd, HDC hdc, RECT *rect, HMENU handle, HFONT font ); BOOL WINAPI NtUserEmptyClipboard(void); BOOL WINAPI NtUserEnableMenuItem( HMENU handle, UINT id, UINT flags ); BOOL WINAPI NtUserEndDeferWindowPosEx( HDWP hdwp, BOOL async );
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=116899
Your paranoid android.
=== debian11 (32 bit Chinese:China report) ===
user32: msg.c:6881: Test failed: SetFocus(hwnd) on a button: 5: the msg 0x0135 was expected, but got msg 0x030f instead msg.c:6881: Test failed: SetFocus(hwnd) on a button: 6: the msg 0x002b was expected, but got msg 0x001c instead msg.c:6881: Test failed: SetFocus(hwnd) on a button: 7: the msg 0x0111 was expected, but got msg 0x0086 instead msg.c:6881: Test failed: SetFocus(hwnd) on a button: 8: the msg 0x8000 was expected, but got msg 0x0006 instead msg.c:6881: Test failed: SetFocus(hwnd) on a button: 9: the msg sequence is not complete: expected 0000 - actual 0009 win.c:11787: Test failed: 007200BE: expected NOT topmost win.c:11606: Test succeeded inside todo block: 5: hwnd 01420056 is still topmost
From: Jacek Caban jacek@codeweavers.com
Signed-off-by: Jacek Caban jacek@codeweavers.com --- dlls/user32/controls.h | 1 - dlls/user32/menu.c | 20 -------------------- dlls/user32/user_main.c | 1 - dlls/win32u/defwnd.c | 7 +++++-- dlls/win32u/menu.c | 2 +- dlls/win32u/ntuser_private.h | 1 - dlls/win32u/win32u_private.h | 1 + 7 files changed, 7 insertions(+), 26 deletions(-)
diff --git a/dlls/user32/controls.h b/dlls/user32/controls.h index 2b6c4912709..c09ab1233d0 100644 --- a/dlls/user32/controls.h +++ b/dlls/user32/controls.h @@ -116,7 +116,6 @@ extern BOOL update_wallpaper( const WCHAR *wallpaper, const WCHAR *pattern ) DEC extern HWND MENU_IsMenuActive(void) DECLSPEC_HIDDEN; extern void MENU_TrackMouseMenuBar( HWND hwnd, INT ht, POINT pt ) DECLSPEC_HIDDEN; extern void MENU_TrackKbdMenuBar( HWND hwnd, UINT wParam, WCHAR wChar ) DECLSPEC_HIDDEN; -extern UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd ) DECLSPEC_HIDDEN; extern void MENU_EndMenu(HWND) DECLSPEC_HIDDEN; extern HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu ) DECLSPEC_HIDDEN;
diff --git a/dlls/user32/menu.c b/dlls/user32/menu.c index 1372baca6cc..2d01e01872c 100644 --- a/dlls/user32/menu.c +++ b/dlls/user32/menu.c @@ -1693,26 +1693,6 @@ static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu ) } }
-/*********************************************************************** - * MENU_DrawMenuBar - * - * Paint a menu bar. Returns the height of the menu bar. - * called from [windows/nonclient.c] - */ -UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd ) -{ - LPPOPUPMENU lppop; - HMENU hMenu = GetMenu(hwnd); - - lppop = MENU_GetMenu( hMenu ); - if (lppop == NULL || lprect == NULL) - { - return GetSystemMetrics(SM_CYMENU); - } - - return NtUserDrawMenuBarTemp( hwnd, hDC, lprect, hMenu, NULL ); -} -
/*********************************************************************** * MENU_InitPopup diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c index 5344dafd359..bca56fc4141 100644 --- a/dlls/user32/user_main.c +++ b/dlls/user32/user_main.c @@ -145,7 +145,6 @@ static const struct user_callbacks user_funcs = ImmProcessKey, ImmTranslateMessage, NtWaitForMultipleObjects, - MENU_DrawMenuBar, SCROLL_DrawNCScrollBar, free_win_ptr, MENU_GetSysMenu, diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c index 9a51b9a463a..f9a23bcee3f 100644 --- a/dlls/win32u/defwnd.c +++ b/dlls/win32u/defwnd.c @@ -1487,12 +1487,15 @@ static void nc_paint( HWND hwnd, HRGN clip ) if (has_menu( hwnd, style )) { RECT r = rect; + HMENU menu; + r.bottom = rect.top + get_system_metrics( SM_CYMENU );
TRACE( "drawing menu with rect %s\n", wine_dbgstr_rect( &r ));
- if (user_callbacks) - rect.top += user_callbacks->draw_menu( hdc, &r, hwnd ) + 1; + menu = get_menu( hwnd ); + if (!is_menu( menu )) rect.top += get_system_metrics( SM_CYMENU ); + else rect.top += NtUserDrawMenuBarTemp( hwnd, hdc, &r, menu, NULL ); }
TRACE( "rect after menu %s\n", wine_dbgstr_rect( &rect )); diff --git a/dlls/win32u/menu.c b/dlls/win32u/menu.c index 182dbb6cf58..b794b9a162a 100644 --- a/dlls/win32u/menu.c +++ b/dlls/win32u/menu.c @@ -241,7 +241,7 @@ static POPUPMENU *unsafe_menu_ptr( HMENU handle ) }
/* see IsMenu */ -static BOOL is_menu( HMENU handle ) +BOOL is_menu( HMENU handle ) { POPUPMENU *menu; BOOL is_menu; diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 6fc1c1423bd..69fb831c03f 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -36,7 +36,6 @@ struct user_callbacks BOOL (WINAPI *pImmProcessKey)(HWND, HKL, UINT, LPARAM, DWORD); BOOL (WINAPI *pImmTranslateMessage)(HWND, UINT, WPARAM, LPARAM); NTSTATUS (WINAPI *pNtWaitForMultipleObjects)(ULONG,const HANDLE*,BOOLEAN,BOOLEAN,const LARGE_INTEGER*); - UINT (CDECL *draw_menu)( HDC hDC, LPRECT lprect, HWND hwnd ); void (CDECL *draw_nc_scrollbar)( HWND hwnd, HDC hdc, BOOL draw_horizontal, BOOL draw_vertical ); void (CDECL *free_win_ptr)( struct tagWND *win ); HMENU (CDECL *get_sys_menu)( HWND hwnd, HMENU popup ); diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 5f5563ec9f9..cf3e5c75b16 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -401,6 +401,7 @@ extern UINT get_menu_bar_height( HWND hwnd, UINT width, INT org_x, INT org_y ) D extern BOOL get_menu_info( HMENU handle, MENUINFO *info ) DECLSPEC_HIDDEN; extern INT get_menu_item_count( HMENU handle ) DECLSPEC_HIDDEN; extern UINT get_menu_state( HMENU handle, UINT item_id, UINT flags ) DECLSPEC_HIDDEN; +extern BOOL is_menu( HMENU handle ) DECLSPEC_HIDDEN; extern BOOL set_window_menu( HWND hwnd, HMENU handle ) DECLSPEC_HIDDEN;
/* message.c */
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=116900
Your paranoid android.
=== debian11 (64 bit WoW report) ===
user32: msg.c:6881: Test failed: SetFocus(hwnd) on a button: 5: the msg 0x0138 was expected, but got msg 0x030f instead msg.c:6881: Test failed: SetFocus(hwnd) on a button: 8: the msg 0x8000 was expected, but got msg 0x0086 instead msg.c:6881: Test failed: SetFocus(hwnd) on a button: 9: the msg sequence is not complete: expected 0000 - actual 0006
From: Jacek Caban jacek@codeweavers.com
Signed-off-by: Jacek Caban jacek@codeweavers.com --- dlls/user32/menu.c | 165 ++------------------------------ dlls/win32u/menu.c | 179 +++++++++++++++++++++++++++++++++++ dlls/win32u/message.c | 2 + dlls/win32u/win32u_private.h | 3 + dlls/win32u/window.c | 2 +- include/ntuser.h | 1 + 6 files changed, 193 insertions(+), 159 deletions(-)
diff --git a/dlls/user32/menu.c b/dlls/user32/menu.c index 2d01e01872c..f5b74a24c25 100644 --- a/dlls/user32/menu.c +++ b/dlls/user32/menu.c @@ -1196,62 +1196,6 @@ static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, UINT max_height ) }
-static void draw_scroll_arrow(HDC hdc, int x, int top, int height, BOOL up, BOOL enabled) -{ - RECT rect, light_rect; - HBRUSH brush = GetSysColorBrush( enabled ? COLOR_BTNTEXT : COLOR_BTNSHADOW ); - HBRUSH light = GetSysColorBrush( COLOR_3DLIGHT ); - - if (!up) - { - top = top + height; - if (!enabled) - { - SetRect( &rect, x + 1, top, x + 2, top + 1); - FillRect( hdc, &rect, light ); - } - top--; - } - - SetRect( &rect, x, top, x + 1, top + 1); - while (height--) - { - FillRect( hdc, &rect, brush ); - if (!enabled && !up && height) - { - SetRect( &light_rect, rect.right, rect.top, rect.right + 2, rect.bottom ); - FillRect( hdc, &light_rect, light ); - } - InflateRect( &rect, 1, 0 ); - OffsetRect( &rect, 0, up ? 1 : -1 ); - } - - if (!enabled && up) - { - rect.left += 2; - FillRect( hdc, &rect, light ); - } -} - -/*********************************************************************** - * MENU_DrawScrollArrows - * - * Draw scroll arrows. - */ -static void -MENU_DrawScrollArrows(const POPUPMENU *menu, HDC hdc) -{ - UINT full_height = get_scroll_arrow_height( menu ); - UINT arrow_height = full_height / 3; - BOOL at_end = menu->nScrollPos + menu->items_rect.bottom - menu->items_rect.top == menu->nTotalHeight; - - draw_scroll_arrow( hdc, menu->Width / 3, arrow_height, arrow_height, - TRUE, menu->nScrollPos != 0); - draw_scroll_arrow( hdc, menu->Width / 3, menu->Height - 2 * arrow_height, arrow_height, - FALSE, !at_end ); -} - - /*********************************************************************** * draw_popup_arrow * @@ -1634,66 +1578,6 @@ done: }
-/*********************************************************************** - * MENU_DrawPopupMenu - * - * Paint a popup menu. - */ -static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu ) -{ - HBRUSH hPrevBrush, brush = GetSysColorBrush( COLOR_MENU ); - RECT rect; - POPUPMENU *menu = MENU_GetMenu( hmenu ); - - TRACE("wnd=%p dc=%p menu=%p\n", hwnd, hdc, hmenu); - - GetClientRect( hwnd, &rect ); - - if (menu && menu->hbrBack) brush = menu->hbrBack; - if ((hPrevBrush = SelectObject( hdc, brush )) - && SelectObject( hdc, get_menu_font(FALSE) )) - { - HPEN hPrevPen; - - Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom ); - - hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) ); - if( hPrevPen ) - { - BOOL flat_menu = FALSE; - - SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0); - if (flat_menu) - FrameRect(hdc, &rect, GetSysColorBrush(COLOR_BTNSHADOW)); - else - DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT); - - if (menu) - { - TRACE("hmenu %p Style %08lx\n", hmenu, menu->dwStyle); - /* draw menu items */ - if (menu->nItems) - { - MENUITEM *item; - UINT u; - - item = menu->items; - for (u = menu->nItems; u > 0; u--, item++) - MENU_DrawMenuItem( hwnd, menu, menu->hwndOwner, hdc, - item, FALSE, ODA_DRAWENTIRE ); - } - /* draw scroll arrows */ - if (menu->bScrolling) - MENU_DrawScrollArrows(menu, hdc); - } - } else - { - SelectObject( hdc, hPrevBrush ); - } - } -} - - /*********************************************************************** * MENU_InitPopup * @@ -3347,40 +3231,8 @@ BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y, */ LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) { - TRACE("hwnd=%p msg=0x%04x wp=0x%04Ix lp=0x%08Ix\n", hwnd, message, wParam, lParam); - switch(message) { - case WM_CREATE: - { - CREATESTRUCTW *cs = (CREATESTRUCTW*)lParam; - SetWindowLongPtrW( hwnd, 0, (LONG_PTR)cs->lpCreateParams ); - return 0; - } - - case WM_MOUSEACTIVATE: /* We don't want to be activated */ - return MA_NOACTIVATE; - - case WM_PAINT: - { - PAINTSTRUCT ps; - NtUserBeginPaint( hwnd, &ps ); - MENU_DrawPopupMenu( hwnd, ps.hdc, - (HMENU)GetWindowLongPtrW( hwnd, 0 ) ); - NtUserEndPaint( hwnd, &ps ); - return 0; - } - - case WM_PRINTCLIENT: - { - MENU_DrawPopupMenu( hwnd, (HDC)wParam, - (HMENU)GetWindowLongPtrW( hwnd, 0 ) ); - return 0; - } - - case WM_ERASEBKGND: - return 1; - case WM_DESTROY: /* zero out global pointer in case resident popup window was destroyed. */ if (hwnd == top_popup) { @@ -3389,18 +3241,15 @@ LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM } break;
+ case WM_CREATE: + case WM_MOUSEACTIVATE: + case WM_PAINT: + case WM_PRINTCLIENT: + case WM_ERASEBKGND: case WM_SHOWWINDOW: - - if( wParam ) - { - if (!GetWindowLongPtrW( hwnd, 0 )) ERR("no menu to display\n"); - } - else - SetWindowLongPtrW( hwnd, 0, 0 ); - break; - case MN_GETHMENU: - return GetWindowLongPtrW( hwnd, 0 ); + return NtUserMessageCall( hwnd, message, wParam, lParam, + NULL, NtUserPopupMenuWndProc, FALSE );
default: return DefWindowProcW( hwnd, message, wParam, lParam ); diff --git a/dlls/win32u/menu.c b/dlls/win32u/menu.c index b794b9a162a..7825e0f416f 100644 --- a/dlls/win32u/menu.c +++ b/dlls/win32u/menu.c @@ -2226,3 +2226,182 @@ DWORD WINAPI NtUserDrawMenuBarTemp( HWND hwnd, HDC hdc, RECT *rect, HMENU handle if (prev_font) NtGdiSelectFont( hdc, prev_font ); return retvalue; } + +static UINT get_scroll_arrow_height( const POPUPMENU *menu ) +{ + return menucharsize.cy + 4; +} + +static void draw_scroll_arrow( HDC hdc, int x, int top, int height, BOOL up, BOOL enabled ) +{ + RECT rect, light_rect; + HBRUSH brush = get_sys_color_brush( enabled ? COLOR_BTNTEXT : COLOR_BTNSHADOW ); + HBRUSH light = get_sys_color_brush( COLOR_3DLIGHT ); + + if (!up) + { + top = top + height; + if (!enabled) + { + SetRect( &rect, x + 1, top, x + 2, top + 1); + fill_rect( hdc, &rect, light ); + } + top--; + } + + SetRect( &rect, x, top, x + 1, top + 1); + while (height--) + { + fill_rect( hdc, &rect, brush ); + if (!enabled && !up && height) + { + SetRect( &light_rect, rect.right, rect.top, rect.right + 2, rect.bottom ); + fill_rect( hdc, &light_rect, light ); + } + InflateRect( &rect, 1, 0 ); + OffsetRect( &rect, 0, up ? 1 : -1 ); + } + + if (!enabled && up) + { + rect.left += 2; + fill_rect( hdc, &rect, light ); + } +} + +static void draw_scroll_arrows( const POPUPMENU *menu, HDC hdc ) +{ + UINT full_height = get_scroll_arrow_height( menu ); + UINT arrow_height = full_height / 3; + BOOL at_end = menu->nScrollPos + menu->items_rect.bottom - menu->items_rect.top == menu->nTotalHeight; + + draw_scroll_arrow( hdc, menu->Width / 3, arrow_height, arrow_height, + TRUE, menu->nScrollPos != 0); + draw_scroll_arrow( hdc, menu->Width / 3, menu->Height - 2 * arrow_height, arrow_height, + FALSE, !at_end ); +} + +static int frame_rect( HDC hdc, const RECT *rect, HBRUSH hbrush ) +{ + HBRUSH prev_brush; + RECT r = *rect; + + if (IsRectEmpty(&r)) return 0; + if (!(prev_brush = NtGdiSelectBrush( hdc, hbrush ))) return 0; + + NtGdiPatBlt( hdc, r.left, r.top, 1, r.bottom - r.top, PATCOPY ); + NtGdiPatBlt( hdc, r.right - 1, r.top, 1, r.bottom - r.top, PATCOPY ); + NtGdiPatBlt( hdc, r.left, r.top, r.right - r.left, 1, PATCOPY ); + NtGdiPatBlt( hdc, r.left, r.bottom - 1, r.right - r.left, 1, PATCOPY ); + + NtGdiSelectBrush( hdc, prev_brush ); + return TRUE; +} + +static void draw_popup_menu( HWND hwnd, HDC hdc, HMENU hmenu ) +{ + HBRUSH prev_hrush, brush = get_sys_color_brush( COLOR_MENU ); + POPUPMENU *menu = unsafe_menu_ptr( hmenu ); + RECT rect; + + TRACE( "wnd=%p dc=%p menu=%p\n", hwnd, hdc, hmenu ); + + get_client_rect( hwnd, &rect ); + + if (menu && menu->hbrBack) brush = menu->hbrBack; + if ((prev_hrush = NtGdiSelectBrush( hdc, brush )) + && NtGdiSelectFont( hdc, get_menu_font( FALSE ))) + { + HPEN prev_pen; + + NtGdiRectangle( hdc, rect.left, rect.top, rect.right, rect.bottom ); + + prev_pen = NtGdiSelectPen( hdc, GetStockObject( NULL_PEN )); + if (prev_pen) + { + BOOL flat_menu = FALSE; + + NtUserSystemParametersInfo( SPI_GETFLATMENU, 0, &flat_menu, 0 ); + if (flat_menu) + frame_rect( hdc, &rect, get_sys_color_brush( COLOR_BTNSHADOW )); + else + draw_rect_edge( hdc, &rect, EDGE_RAISED, BF_RECT, 1 ); + + if (menu) + { + TRACE( "hmenu %p Style %08x\n", hmenu, menu->dwStyle ); + /* draw menu items */ + if (menu->nItems) + { + MENUITEM *item; + UINT u; + + item = menu->items; + for (u = menu->nItems; u > 0; u--, item++) + draw_menu_item( hwnd, menu, menu->hwndOwner, hdc, + item, FALSE, ODA_DRAWENTIRE ); + } + if (menu->bScrolling) draw_scroll_arrows( menu, hdc ); + } + } + else + { + NtGdiSelectBrush( hdc, prev_hrush ); + } + } +} + +LRESULT popup_menu_window_proc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam ) +{ + TRACE( "hwnd=%p msg=0x%04x wp=0x%04lx lp=0x%08lx\n", hwnd, message, wparam, lparam ); + + switch(message) + { + case WM_CREATE: + { + CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam; + NtUserSetWindowLongPtr( hwnd, 0, (LONG_PTR)cs->lpCreateParams, FALSE ); + return 0; + } + + case WM_MOUSEACTIVATE: /* We don't want to be activated */ + return MA_NOACTIVATE; + + case WM_PAINT: + { + PAINTSTRUCT ps; + NtUserBeginPaint( hwnd, &ps ); + draw_popup_menu( hwnd, ps.hdc, (HMENU)get_window_long_ptr( hwnd, 0, FALSE )); + NtUserEndPaint( hwnd, &ps ); + return 0; + } + + case WM_PRINTCLIENT: + { + draw_popup_menu( hwnd, (HDC)wparam, (HMENU)get_window_long_ptr( hwnd, 0, FALSE )); + return 0; + } + + case WM_ERASEBKGND: + return 1; + + case WM_DESTROY: + break; + + case WM_SHOWWINDOW: + if (wparam) + { + if (!get_window_long_ptr( hwnd, 0, FALSE )) ERR( "no menu to display\n" ); + } + else + NtUserSetWindowLongPtr( hwnd, 0, 0, FALSE ); + break; + + case MN_GETHMENU: + return get_window_long_ptr( hwnd, 0, FALSE ); + + default: + return default_window_proc( hwnd, message, wparam, lparam, FALSE ); + } + return 0; +} diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index b41d252457d..cea1a33812a 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2890,6 +2890,8 @@ LRESULT WINAPI NtUserMessageCall( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpa { switch (type) { + case NtUserPopupMenuWndProc: + return popup_menu_window_proc( hwnd, msg, wparam, lparam ); case NtUserDesktopWindowProc: return desktop_window_proc( hwnd, msg, wparam, lparam ); case NtUserDefWindowProc: diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index cf3e5c75b16..d3f060669a4 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -402,6 +402,8 @@ extern BOOL get_menu_info( HMENU handle, MENUINFO *info ) DECLSPEC_HIDDEN; extern INT get_menu_item_count( HMENU handle ) DECLSPEC_HIDDEN; extern UINT get_menu_state( HMENU handle, UINT item_id, UINT flags ) DECLSPEC_HIDDEN; extern BOOL is_menu( HMENU handle ) DECLSPEC_HIDDEN; +extern LRESULT popup_menu_window_proc( HWND hwnd, UINT message, WPARAM wparam, + LPARAM lparam ) DECLSPEC_HIDDEN; extern BOOL set_window_menu( HWND hwnd, HMENU handle ) DECLSPEC_HIDDEN;
/* message.c */ @@ -473,6 +475,7 @@ extern BOOL is_window_unicode( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL is_window_visible( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL is_zoomed( HWND hwnd ) DECLSPEC_HIDDEN; extern DWORD get_window_long( HWND hwnd, INT offset ) DECLSPEC_HIDDEN; +extern ULONG_PTR get_window_long_ptr( HWND hwnd, INT offset, BOOL ansi ) DECLSPEC_HIDDEN; extern BOOL get_window_rect( HWND hwnd, RECT *rect, UINT dpi ) DECLSPEC_HIDDEN; enum coords_relative; extern BOOL get_window_rects( HWND hwnd, enum coords_relative relative, RECT *window_rect, diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index f98dabe27f3..94f285de2bb 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -1097,7 +1097,7 @@ DWORD get_window_long( HWND hwnd, INT offset ) }
/* see GetWindowLongPtr */ -static ULONG_PTR get_window_long_ptr( HWND hwnd, INT offset, BOOL ansi ) +ULONG_PTR get_window_long_ptr( HWND hwnd, INT offset, BOOL ansi ) { return get_window_long_size( hwnd, offset, sizeof(LONG_PTR), ansi ); } diff --git a/include/ntuser.h b/include/ntuser.h index 9cf26534e10..5f744c24906 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -204,6 +204,7 @@ struct render_synthesized_format_params /* NtUserMessageCall codes */ enum { + NtUserPopupMenuWndProc = 0x029c, NtUserDesktopWindowProc = 0x029d, NtUserDefWindowProc = 0x029e, NtUserCallWindowProc = 0x02ab,
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=116901
Your paranoid android.
=== debian11 (32 bit report) ===
user32: menu.c:2324: Test failed: test 25
From: Jacek Caban jacek@codeweavers.com
Signed-off-by: Jacek Caban jacek@codeweavers.com --- dlls/user32/menu.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-)
diff --git a/dlls/user32/menu.c b/dlls/user32/menu.c index f5b74a24c25..73aee6b849d 100644 --- a/dlls/user32/menu.c +++ b/dlls/user32/menu.c @@ -4309,20 +4309,13 @@ BOOL WINAPI GetMenuInfo( HMENU menu, MENUINFO *info ) /********************************************************************** * GetMenuContextHelpId (USER32.@) */ -DWORD WINAPI GetMenuContextHelpId( HMENU hMenu ) +DWORD WINAPI GetMenuContextHelpId( HMENU menu ) { - DWORD help_id = 0; - POPUPMENU *menu; - - TRACE("(%p)\n", hMenu); - - if ((menu = grab_menu_ptr(hMenu))) - { - help_id = menu->dwContextHelpID; - release_menu_ptr(menu); - } - - return help_id; + MENUINFO info; + TRACE( "(%p)\n", menu ); + info.cbSize = sizeof(info); + info.fMask = MIM_HELPID; + return GetMenuInfo( menu, &info ) ? info.dwContextHelpID : 0; }
/**********************************************************************
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=116902
Your paranoid android.
=== debian11 (32 bit Chinese:China report) ===
user32: msg.c:6881: Test failed: SetFocus(hwnd) on a button: 5: the msg 0x0135 was expected, but got msg 0x030f instead msg.c:6881: Test failed: SetFocus(hwnd) on a button: 7: the msg 0x8000 was expected, but got msg 0x0086 instead msg.c:6881: Test failed: SetFocus(hwnd) on a button: 8: the msg sequence is not complete: expected 0000 - actual 0006