Release 960818 Sun Aug 18 12:17:54 1996 Alexandre Julliard <julliard@lrc.epfl.ch> * [files/drive.c] Added 'Filesystem' option in drives configuration. * [files/dos_fs.c] Added handling of case-insensitive filesystems. * [memory/selector.c] [include/stackframe.h] Removed MAKE_SEGPTR. * [misc/commdlg.c] [multimedia/mcistring.c] Replaced MAKE_SEGPTR by the SEGPTR_* macros. * [objects/bitblt.c] [windows/graphics.c] Use an intermediary pixmap to avoid some BadMatch errors on XGetImage(). Sun Aug 18 09:21:27 1996 Albrecht Kleine <kleine@ak.sax.de> * [windows/message.c] Added handling of WM_NC...mouse messages in JOURNALRECORD hook. * [misc/ver.c] Fixed a bad string result in VerQueryValue[16|32A|32W]. Fri Aug 16 19:55:04 1996 Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de> * [if1632/crtdll.spec] [misc/crtdll.c] More additions to get win95 programs further down the road. * [if1632/kernel.spec] [loader/module.c] GetModuleName() added. LoadModule(): params->showCmd can be NULL. * [if1632/kernel32.spec] [if1632/thunk.c] ThunkConnect32() stub added. * [loader/resource.c] Entries include lastentry. * [misc/shell.c] [files/file.c] Made progman work again. Fri Aug 16 09:00:00 1996 Alex Korobka <alex@phm30.pharm.sunysb.edu> * [windows/defwnd.c] [windows/winpos.c] [windows/painting.c] Icon painting fixes. * [windows/winpos.c] [windows/painting.c] Enforce and follow hrgnUpdate more closely to cut down on redundant RedrawWindow() calls. * [windows/event.c] Process ConfigureNotify only for managed windows. * [windows/winpos.c] Do not redraw parent if the window was hidden before SetWindowPos(). * [windows/nonclient.c] Omit some nonclient decoration painting for managed windows. * [controls/menu.c] [windows/mdi.c] [windows/nonclient.c] Implemented WM_NEXTMENU. * [controls/listbox.c] Multicolumn listboxes return WVR_VREDRAW on WM_NCCALCSIZE. * [misc/shell.c] Added .ICO file handling to ExtractIcon().
diff --git a/controls/menu.c b/controls/menu.c index fc36acb..7ac8c35 100644 --- a/controls/menu.c +++ b/controls/menu.c
@@ -60,6 +60,9 @@ #define MENU_MAGIC 0x554d /* 'MU' */ +#define ITEM_PREV -1 +#define ITEM_NEXT 1 + /* Dimension of the menu bitmaps */ static WORD check_bitmap_width = 0, check_bitmap_height = 0; static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0; @@ -85,6 +88,7 @@ MF_MENUBARBREAK | MF_MENUBREAK | MF_SEPARATOR))) extern void NC_DrawSysButton(HWND hwnd, HDC hdc, BOOL down); /* nonclient.c */ +extern BOOL NC_GetSysPopupPos(WND* wndPtr, RECT16* rect); static HBITMAP hStdCheck = 0; static HBITMAP hStdMnArrow = 0; @@ -802,10 +806,11 @@ uSubPWndLevel++; + wndPtr = WIN_FindWndPtr( menu->hWnd ); + SetWindowPos(menu->hWnd, 0, x, y, menu->Width + 2*SYSMETRICS_CXBORDER, menu->Height + 2*SYSMETRICS_CYBORDER, - SWP_NOACTIVATE | SWP_NOZORDER ); - + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW); /* Display the window */ SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0, @@ -879,11 +884,12 @@ /*********************************************************************** - * MENU_SelectNextItem + * MENU_SelectItemRel + * */ -static void MENU_SelectNextItem( HWND hwndOwner, HMENU hmenu ) +static void MENU_SelectItemRel( HWND hwndOwner, HMENU hmenu, int offset ) { - int i; + int i, min = 0; POPUPMENU *menu; menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ); @@ -891,7 +897,8 @@ if ((menu->FocusedItem != NO_SELECTED_ITEM) && (menu->FocusedItem != SYSMENU_SELECTED)) { - for (i = menu->FocusedItem+1; i < menu->nItems; i++) + for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems + ; i += offset) { if (!(menu->items[i].item_flags & MF_SEPARATOR)) { @@ -899,53 +906,18 @@ return; } } + if (MENU_HasSysMenu( menu )) { MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED, TRUE ); return; } } - for (i = 0; i < menu->nItems; i++) - { - if (!(menu->items[i].item_flags & MF_SEPARATOR)) - { - MENU_SelectItem( hwndOwner, hmenu, i, TRUE ); - return; - } - } - if (MENU_HasSysMenu( menu )) - MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED, TRUE ); -} - -/*********************************************************************** - * MENU_SelectPrevItem - */ -static void MENU_SelectPrevItem( HWND hwndOwner, HMENU hmenu ) -{ - int i; - POPUPMENU *menu; - - menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ); - if (!menu->items) return; - if ((menu->FocusedItem != NO_SELECTED_ITEM) && - (menu->FocusedItem != SYSMENU_SELECTED)) - { - for (i = menu->FocusedItem - 1; i >= 0; i--) - { - if (!(menu->items[i].item_flags & MF_SEPARATOR)) - { - MENU_SelectItem( hwndOwner, hmenu, i, TRUE ); - return; - } - } - if (MENU_HasSysMenu( menu )) - { - MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED, TRUE ); - return; - } - } - for (i = menu->nItems - 1; i > 0; i--) + if( offset > 0 ) { i = 0; min = -1; } + else i = menu->nItems - 1; + + for ( ; i > min && i < menu->nItems ; i += offset) { if (!(menu->items[i].item_flags & MF_SEPARATOR)) { @@ -1193,7 +1165,7 @@ { MENU_ShowPopup(hwndOwner, wndPtr->hSysMenu, 0, wndPtr->rectClient.left, wndPtr->rectClient.top - menu->Height - 2*SYSMETRICS_CYBORDER); - if (selectFirst) MENU_SelectNextItem( hwndOwner, wndPtr->hSysMenu ); + if (selectFirst) MENU_SelectItemRel( hwndOwner, wndPtr->hSysMenu, ITEM_NEXT ); return wndPtr->hSysMenu; } item = &menu->items[menu->FocusedItem]; @@ -1212,7 +1184,7 @@ wndPtr->rectWindow.left + item->rect.left, wndPtr->rectWindow.top + item->rect.bottom ); } - if (selectFirst) MENU_SelectNextItem( hwndOwner, (HMENU)item->item_id ); + if (selectFirst) MENU_SelectItemRel( hwndOwner, (HMENU)item->item_id, ITEM_NEXT ); return (HMENU)item->item_id; } @@ -1373,7 +1345,7 @@ } /* Select first item of sub-popup */ MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, FALSE ); - MENU_SelectNextItem( hwndOwner, hsubmenu ); + MENU_SelectItemRel( hwndOwner, hsubmenu, ITEM_NEXT ); return TRUE; } @@ -1415,6 +1387,86 @@ return TRUE; } +/*********************************************************************** + * MENU_DoNextMenu + */ +static LRESULT MENU_DoNextMenu( HWND* hwndOwner, HMENU* hmenu, HMENU *hmenuCurrent, UINT vk) +{ + POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( *hmenu ); + UINT id = 0; + + if( (vk == VK_LEFT && !menu->FocusedItem) + || (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1) + || menu->FocusedItem == SYSMENU_SELECTED + || ((menu->wFlags & (MF_POPUP | MF_SYSMENU)) == (MF_POPUP | MF_SYSMENU)) ) + { + LRESULT l = SendMessage16( *hwndOwner, WM_NEXTMENU, (WPARAM)vk, + (LPARAM)((menu->FocusedItem == SYSMENU_SELECTED) + ? GetSystemMenu( *hwndOwner, 0) + : *hmenu)); + + if( l == 0 || !IsMenu(LOWORD(l)) || !IsWindow(HIWORD(l)) ) return 0; + + /* shutdown current menu - + * all these checks for system popup window are needed + * only because Wine system menu tracking is unsuitable + * for a lot of things (esp. when we do not have wIDmenu to fall back on). + */ + + MENU_SelectItem( *hwndOwner, *hmenu, NO_SELECTED_ITEM, FALSE ); + + if( (menu->wFlags & (MF_POPUP | MF_SYSMENU)) == (MF_POPUP | MF_SYSMENU) ) + { + HDC hdc; + + ShowWindow( menu->hWnd, SW_HIDE ); + uSubPWndLevel = 0; + + if( !IsIconic( *hwndOwner ) ) + { + hdc = GetDCEx( *hwndOwner, 0, DCX_CACHE | DCX_WINDOW); + NC_DrawSysButton( *hwndOwner, hdc, FALSE ); + ReleaseDC( *hwndOwner, hdc ); + } + } + + ReleaseCapture(); + *hwndOwner = HIWORD(l); + *hmenu = LOWORD(l); + SetCapture( *hwndOwner ); + + menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( *hmenu ); + + /* init next menu */ + + if( (menu->wFlags & (MF_POPUP | MF_SYSMENU)) == (MF_POPUP | MF_SYSMENU) ) + { + RECT16 rect; + WND* wndPtr = WIN_FindWndPtr( *hwndOwner ); + + /* stupid kludge, see above */ + + if( wndPtr->wIDmenu && !(wndPtr->dwStyle & WS_CHILD) ) + { *hmenu = wndPtr->wIDmenu; id = SYSMENU_SELECTED; } + else + { + if( NC_GetSysPopupPos( wndPtr, &rect ) ) + MENU_ShowPopup( *hwndOwner, *hmenu, 0, rect.left, rect.bottom ); + + if( !IsIconic( *hwndOwner ) ) + { + HDC hdc = GetDCEx( *hwndOwner, 0, DCX_CACHE | DCX_WINDOW); + NC_DrawSysButton( *hwndOwner, hdc, TRUE ); + ReleaseDC( *hwndOwner, hdc ); + } + } + } + + MENU_SelectItem( *hwndOwner, *hmenu, id, TRUE ); + return l; + } + return 0; +} /*********************************************************************** * MENU_KeyLeft @@ -1422,28 +1474,34 @@ * Handle a VK_LEFT key event in a menu. * hmenuCurrent is the top-most visible popup. */ -static void MENU_KeyLeft( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent ) +static void MENU_KeyLeft( HWND* hwndOwner, HMENU* hmenu, HMENU *hmenuCurrent ) { POPUPMENU *menu; HMENU hmenutmp, hmenuprev; - menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ); - hmenuprev = hmenutmp = hmenu; + menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( *hmenu ); + hmenuprev = hmenutmp = *hmenu; while (hmenutmp != *hmenuCurrent) { hmenutmp = MENU_GetSubPopup( hmenuprev ); if (hmenutmp != *hmenuCurrent) hmenuprev = hmenutmp; } - MENU_HideSubPopups( hwndOwner, hmenuprev, TRUE ); + MENU_HideSubPopups( *hwndOwner, hmenuprev, TRUE ); + hmenutmp = *hmenu; - if ((hmenuprev == hmenu) && !(menu->wFlags & MF_POPUP)) + if ( (hmenuprev == *hmenu) && + ((menu->wFlags & MF_SYSMENU) || !(menu->wFlags & MF_POPUP)) ) { - /* Select previous item on the menu bar */ - MENU_SelectPrevItem( hwndOwner, hmenu ); - if (*hmenuCurrent != hmenu) + /* send WM_NEXTMENU */ + + if( !MENU_DoNextMenu( hwndOwner, hmenu, hmenuCurrent, VK_LEFT) ) + MENU_SelectItemRel( *hwndOwner, *hmenu, ITEM_PREV ); + else *hmenuCurrent = *hmenu; + + if (*hmenuCurrent != hmenutmp) { - /* A popup menu was displayed -> display the next one */ - *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, TRUE ); + /* A sublevel menu was displayed -> display the next one */ + *hmenuCurrent = MENU_ShowSubPopup( *hwndOwner, *hmenu, TRUE ); } } else *hmenuCurrent = hmenuprev; @@ -1456,17 +1514,17 @@ * Handle a VK_RIGHT key event in a menu. * hmenuCurrent is the top-most visible popup. */ -static void MENU_KeyRight( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent ) +static void MENU_KeyRight( HWND* hwndOwner, HMENU* hmenu, HMENU *hmenuCurrent ) { POPUPMENU *menu; HMENU hmenutmp; - menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ); + menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( *hmenu ); - if ((menu->wFlags & MF_POPUP) || (*hmenuCurrent != hmenu)) + if ((menu->wFlags & MF_POPUP) || (*hmenuCurrent != *hmenu)) { /* If already displaying a popup, try to display sub-popup */ - hmenutmp = MENU_ShowSubPopup( hwndOwner, *hmenuCurrent, TRUE ); + hmenutmp = MENU_ShowSubPopup( *hwndOwner, *hmenuCurrent, TRUE ); if (hmenutmp != *hmenuCurrent) /* Sub-popup displayed */ { *hmenuCurrent = hmenutmp; @@ -1474,27 +1532,35 @@ } } - /* If on menu-bar, go to next item */ - if (!(menu->wFlags & MF_POPUP)) + /* If menu-bar tracking, go to next item */ + + if (!(menu->wFlags & MF_POPUP) || (menu->wFlags & MF_SYSMENU)) { - MENU_HideSubPopups( hwndOwner, hmenu, FALSE ); - MENU_SelectNextItem( hwndOwner, hmenu ); - if (*hmenuCurrent != hmenu) + MENU_HideSubPopups( *hwndOwner, *hmenu, FALSE ); + hmenutmp = *hmenu; + + /* Send WM_NEXTMENU */ + + if( !MENU_DoNextMenu( hwndOwner, hmenu, hmenuCurrent, VK_RIGHT) ) + MENU_SelectItemRel( *hwndOwner, *hmenu, ITEM_NEXT ); + else *hmenuCurrent = *hmenu; + + if (*hmenuCurrent != hmenutmp) { - /* A popup menu was displayed -> display the next one */ - *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, TRUE ); + /* A sublevel menu was displayed -> display the next one */ + *hmenuCurrent = MENU_ShowSubPopup( *hwndOwner, *hmenu, TRUE ); } } - else if (*hmenuCurrent != hmenu) /* Hide last level popup */ + else if (*hmenuCurrent != *hmenu) /* Hide last level popup */ { HMENU hmenuprev; - hmenuprev = hmenutmp = hmenu; + hmenuprev = hmenutmp = *hmenu; while (hmenutmp != *hmenuCurrent) { hmenutmp = MENU_GetSubPopup( hmenuprev ); if (hmenutmp != *hmenuCurrent) hmenuprev = hmenutmp; } - MENU_HideSubPopups( hwndOwner, hmenuprev, TRUE ); + MENU_HideSubPopups( *hwndOwner, hmenuprev, TRUE ); *hmenuCurrent = hmenuprev; } } @@ -1510,8 +1576,7 @@ static BOOL MENU_TrackMenu( HMENU hmenu, UINT wFlags, int x, int y, HWND hwnd, const RECT16 *lprect ) { - MSG16 *msg; - HLOCAL16 hMsg; + MSG16 msg; POPUPMENU *menu; HMENU hmenuCurrent = hmenu; BOOL fClosed = FALSE, fRemove; @@ -1525,23 +1590,20 @@ MENU_ButtonDown( hwnd, hmenu, &hmenuCurrent, pt ); } SetCapture( hwnd ); - hMsg = USER_HEAP_ALLOC( sizeof(MSG16) ); - msg = (MSG16 *)USER_HEAP_LIN_ADDR( hMsg ); while (!fClosed) { - if (!MSG_InternalGetMessage( (SEGPTR)USER_HEAP_SEG_ADDR(hMsg), 0, - hwnd, MSGF_MENU, 0, TRUE )) + if (!MSG_InternalGetMessage( &msg, 0, hwnd, MSGF_MENU, 0, TRUE )) break; - TranslateMessage( msg ); + TranslateMessage( &msg ); fRemove = FALSE; - if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST)) + if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST)) { /* Find the sub-popup for this mouse event (if any) */ - HMENU hsubmenu = MENU_FindMenuByCoords( hmenu, msg->pt ); + HMENU hsubmenu = MENU_FindMenuByCoords( hmenu, msg.pt ); - switch(msg->message) + switch(msg.message) { case WM_RBUTTONDOWN: case WM_NCRBUTTONDOWN: @@ -1550,7 +1612,7 @@ case WM_LBUTTONDOWN: case WM_NCLBUTTONDOWN: fClosed = !MENU_ButtonDown( hwnd, hsubmenu, - &hmenuCurrent, msg->pt ); + &hmenuCurrent, msg.pt ); break; case WM_RBUTTONUP: @@ -1560,59 +1622,56 @@ case WM_LBUTTONUP: case WM_NCLBUTTONUP: /* If outside all menus but inside lprect, ignore it */ - if (!hsubmenu && lprect && PtInRect16(lprect, msg->pt)) break; + if (!hsubmenu && lprect && PtInRect16(lprect, msg.pt)) break; fClosed = !MENU_ButtonUp( hwnd, hsubmenu, - &hmenuCurrent, msg->pt ); + &hmenuCurrent, msg.pt ); fRemove = TRUE; /* Remove event even if outside menu */ break; case WM_MOUSEMOVE: case WM_NCMOUSEMOVE: - if ((msg->wParam & MK_LBUTTON) || - ((wFlags & TPM_RIGHTBUTTON) && (msg->wParam & MK_RBUTTON))) + if ((msg.wParam & MK_LBUTTON) || + ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON))) { fClosed = !MENU_MouseMove( hwnd, hsubmenu, - &hmenuCurrent, msg->pt ); + &hmenuCurrent, msg.pt ); } break; } } - else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST)) + else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST)) { fRemove = TRUE; /* Keyboard messages are always removed */ - switch(msg->message) + switch(msg.message) { case WM_KEYDOWN: - switch(msg->wParam) + switch(msg.wParam) { case VK_HOME: - MENU_SelectItem( hwnd, hmenuCurrent, NO_SELECTED_ITEM, FALSE ); - MENU_SelectNextItem( hwnd, hmenuCurrent ); - break; - case VK_END: MENU_SelectItem( hwnd, hmenuCurrent, NO_SELECTED_ITEM, FALSE ); - MENU_SelectPrevItem( hwnd, hmenuCurrent ); - break; + /* fall through */ case VK_UP: - MENU_SelectPrevItem( hwnd, hmenuCurrent ); + MENU_SelectItemRel( hwnd, hmenuCurrent, + (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV ); break; - case VK_DOWN: - /* If on menu bar, pull-down the menu */ + case VK_DOWN: /* If on menu bar, pull-down the menu */ + + menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ); if (!(menu->wFlags & MF_POPUP) && (hmenuCurrent == hmenu)) hmenuCurrent = MENU_ShowSubPopup( hwnd, hmenu, TRUE ); else - MENU_SelectNextItem( hwnd, hmenuCurrent ); + MENU_SelectItemRel( hwnd, hmenuCurrent, ITEM_NEXT ); break; case VK_LEFT: - MENU_KeyLeft( hwnd, hmenu, &hmenuCurrent ); + MENU_KeyLeft( &hwnd, &hmenu, &hmenuCurrent ); break; case VK_RIGHT: - MENU_KeyRight( hwnd, hmenu, &hmenuCurrent ); + MENU_KeyRight( &hwnd, &hmenu, &hmenuCurrent ); break; case VK_SPACE: @@ -1631,7 +1690,7 @@ break; /* WM_KEYDOWN */ case WM_SYSKEYDOWN: - switch(msg->wParam) + switch(msg.wParam) { case VK_MENU: fClosed = TRUE; @@ -1644,8 +1703,8 @@ { /* Hack to avoid control chars. */ /* We will find a better way real soon... */ - if ((msg->wParam <= 32) || (msg->wParam >= 127)) break; - pos = MENU_FindItemByKey( hwnd, hmenuCurrent, msg->wParam ); + if ((msg.wParam <= 32) || (msg.wParam >= 127)) break; + pos = MENU_FindItemByKey( hwnd, hmenuCurrent, msg.wParam ); if (pos == (UINT)-2) fClosed = TRUE; else if (pos == (UINT)-1) MessageBeep(0); else @@ -1657,22 +1716,23 @@ } } break; /* WM_CHAR */ - } /* switch(msg->message) */ + } /* switch(msg.message) */ } else { - DispatchMessage( msg ); + DispatchMessage( &msg ); } if (fEndMenuCalled) fClosed = TRUE; if (!fClosed) fRemove = TRUE; if (fRemove) /* Remove the message from the queue */ - PeekMessage16( msg, 0, msg->message, msg->message, PM_REMOVE ); + PeekMessage16( &msg, 0, msg.message, msg.message, PM_REMOVE ); } - USER_HEAP_FREE( hMsg ); + ReleaseCapture(); MENU_HideSubPopups( hwnd, hmenu, FALSE ); - if (menu->wFlags & MF_POPUP) + menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ); + if (menu && menu->wFlags & MF_POPUP) { ShowWindow( menu->hWnd, SW_HIDE ); uSubPWndLevel = 0; @@ -1756,7 +1816,7 @@ MENU_SelectItem( wndPtr->hwndSelf, hTrackMenu, uItem, TRUE ); if( uItem == NO_SELECTED_ITEM ) - MENU_SelectNextItem( wndPtr->hwndSelf, hTrackMenu ); + MENU_SelectItemRel( wndPtr->hwndSelf, hTrackMenu, ITEM_NEXT ); else PostMessage( wndPtr->hwndSelf, WM_KEYDOWN, VK_DOWN, 0L );