1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: Menus 5 * FILE: win32ss/user/ntuser/menu.c 6 * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net) 7 */ 8 9 #include <win32k.h> 10 DBG_DEFAULT_CHANNEL(UserMenu); 11 12 /* INTERNAL ******************************************************************/ 13 14 BOOL FASTCALL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags); /* draw.c */ 15 16 HFONT ghMenuFont = NULL; 17 HFONT ghMenuFontBold = NULL; 18 static SIZE MenuCharSize; 19 20 /* Use global popup window because there's no way 2 menus can 21 * be tracked at the same time. */ 22 static HWND top_popup = NULL; 23 static HMENU top_popup_hmenu = NULL; 24 25 BOOL fInsideMenuLoop = FALSE; 26 BOOL fInEndMenu = FALSE; 27 28 /* internal popup menu window messages */ 29 30 #define MM_SETMENUHANDLE (WM_USER + 0) 31 #define MM_GETMENUHANDLE (WM_USER + 1) 32 33 /* internal flags for menu tracking */ 34 35 #define TF_ENDMENU 0x10000 36 #define TF_SUSPENDPOPUP 0x20000 37 #define TF_SKIPREMOVE 0x40000 38 39 40 /* maximum allowed depth of any branch in the menu tree. 41 * This value is slightly larger than in windows (25) to 42 * stay on the safe side. */ 43 #define MAXMENUDEPTH 30 44 45 #define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP) 46 47 #define MENUITEMINFO_TYPE_MASK \ 48 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \ 49 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \ 50 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ ) 51 52 #define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU) 53 54 #define STATE_MASK (~TYPE_MASK) 55 56 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT)) 57 58 #define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT) 59 60 #define IS_SYSTEM_MENU(MenuInfo) \ 61 (!((MenuInfo)->fFlags & MNF_POPUP) && ((MenuInfo)->fFlags & MNF_SYSMENU)) 62 63 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags)) 64 65 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1)) 66 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags)) 67 68 /* Maximum number of menu items a menu can contain */ 69 #define MAX_MENU_ITEMS (0x4000) 70 #define MAX_GOINTOSUBMENU (0x10) 71 72 /* Space between 2 columns */ 73 #define MENU_COL_SPACE 4 74 75 #define MENU_ITEM_HBMP_SPACE (5) 76 #define MENU_BAR_ITEMS_SPACE (12) 77 #define SEPARATOR_HEIGHT (5) 78 #define MENU_TAB_SPACE (8) 79 80 typedef struct 81 { 82 UINT TrackFlags; 83 PMENU CurrentMenu; /* current submenu (can be equal to hTopMenu)*/ 84 PMENU TopMenu; /* initial menu */ 85 PWND OwnerWnd; /* where notifications are sent */ 86 POINT Pt; 87 } MTRACKER; 88 89 /* Internal MenuTrackMenu() flags */ 90 #define TPM_INTERNAL 0xF0000000 91 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */ 92 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */ 93 94 #define ITEM_PREV -1 95 #define ITEM_NEXT 1 96 97 #define UpdateMenuItemState(state, change) \ 98 {\ 99 if((change) & MF_GRAYED) { \ 100 (state) |= MF_GRAYED; \ 101 } else { \ 102 (state) &= ~MF_GRAYED; \ 103 } /* Separate the two for test_menu_resource_layout.*/ \ 104 if((change) & MF_DISABLED) { \ 105 (state) |= MF_DISABLED; \ 106 } else { \ 107 (state) &= ~MF_DISABLED; \ 108 } \ 109 if((change) & MFS_CHECKED) { \ 110 (state) |= MFS_CHECKED; \ 111 } else { \ 112 (state) &= ~MFS_CHECKED; \ 113 } \ 114 if((change) & MFS_HILITE) { \ 115 (state) |= MFS_HILITE; \ 116 } else { \ 117 (state) &= ~MFS_HILITE; \ 118 } \ 119 if((change) & MFS_DEFAULT) { \ 120 (state) |= MFS_DEFAULT; \ 121 } else { \ 122 (state) &= ~MFS_DEFAULT; \ 123 } \ 124 if((change) & MF_MOUSESELECT) { \ 125 (state) |= MF_MOUSESELECT; \ 126 } else { \ 127 (state) &= ~MF_MOUSESELECT; \ 128 } \ 129 } 130 131 #if 0 132 void FASTCALL 133 DumpMenuItemList(PMENU Menu, PITEM MenuItem) 134 { 135 UINT cnt = 0, i = Menu->cItems; 136 while(i) 137 { 138 if(MenuItem->lpstr.Length) 139 DbgPrint(" %d. %wZ\n", ++cnt, &MenuItem->lpstr); 140 else 141 DbgPrint(" %d. NO TEXT dwTypeData==%d\n", ++cnt, (DWORD)MenuItem->lpstr.Buffer); 142 DbgPrint(" fType="); 143 if(MFT_BITMAP & MenuItem->fType) 144 DbgPrint("MFT_BITMAP "); 145 if(MFT_MENUBARBREAK & MenuItem->fType) 146 DbgPrint("MFT_MENUBARBREAK "); 147 if(MFT_MENUBREAK & MenuItem->fType) 148 DbgPrint("MFT_MENUBREAK "); 149 if(MFT_OWNERDRAW & MenuItem->fType) 150 DbgPrint("MFT_OWNERDRAW "); 151 if(MFT_RADIOCHECK & MenuItem->fType) 152 DbgPrint("MFT_RADIOCHECK "); 153 if(MFT_RIGHTJUSTIFY & MenuItem->fType) 154 DbgPrint("MFT_RIGHTJUSTIFY "); 155 if(MFT_SEPARATOR & MenuItem->fType) 156 DbgPrint("MFT_SEPARATOR "); 157 if(MFT_STRING & MenuItem->fType) 158 DbgPrint("MFT_STRING "); 159 DbgPrint("\n fState="); 160 if(MFS_DISABLED & MenuItem->fState) 161 DbgPrint("MFS_DISABLED "); 162 else 163 DbgPrint("MFS_ENABLED "); 164 if(MFS_CHECKED & MenuItem->fState) 165 DbgPrint("MFS_CHECKED "); 166 else 167 DbgPrint("MFS_UNCHECKED "); 168 if(MFS_HILITE & MenuItem->fState) 169 DbgPrint("MFS_HILITE "); 170 else 171 DbgPrint("MFS_UNHILITE "); 172 if(MFS_DEFAULT & MenuItem->fState) 173 DbgPrint("MFS_DEFAULT "); 174 if(MFS_GRAYED & MenuItem->fState) 175 DbgPrint("MFS_GRAYED "); 176 DbgPrint("\n wId=%d\n", MenuItem->wID); 177 MenuItem++; 178 i--; 179 } 180 DbgPrint("Entries: %d\n", cnt); 181 return; 182 } 183 #endif 184 185 #define FreeMenuText(Menu,MenuItem) \ 186 { \ 187 if((MENU_ITEM_TYPE((MenuItem)->fType) == MF_STRING) && \ 188 (MenuItem)->lpstr.Length) { \ 189 DesktopHeapFree(((PMENU)Menu)->head.rpdesk, (MenuItem)->lpstr.Buffer); \ 190 } \ 191 } 192 193 PMENU FASTCALL 194 IntGetMenuObject(HMENU hMenu) 195 { 196 PMENU Menu = UserGetMenuObject(hMenu); 197 if (Menu) 198 Menu->head.cLockObj++; 199 200 return Menu; 201 } 202 203 PMENU FASTCALL VerifyMenu(PMENU pMenu) 204 { 205 HMENU hMenu; 206 PITEM pItem; 207 ULONG Error; 208 UINT i; 209 if (!pMenu) return NULL; 210 211 Error = EngGetLastError(); 212 213 _SEH2_TRY 214 { 215 hMenu = UserHMGetHandle(pMenu); 216 pItem = pMenu->rgItems; 217 if (pItem) 218 { 219 i = pItem[0].wID; 220 pItem[0].wID = i; 221 } 222 } 223 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 224 { 225 ERR("Run away LOOP!\n"); 226 EngSetLastError(Error); 227 _SEH2_YIELD(return NULL); 228 } 229 _SEH2_END 230 231 if ( UserObjectInDestroy(hMenu)) 232 { 233 ERR("Menu is marked for destruction!\n"); 234 pMenu = NULL; 235 } 236 EngSetLastError(Error); 237 return pMenu; 238 } 239 240 BOOL 241 FASTCALL 242 IntIsMenu(HMENU Menu) 243 { 244 if (UserGetMenuObject(Menu)) return TRUE; 245 return FALSE; 246 } 247 248 249 PMENU WINAPI 250 IntGetMenu(HWND hWnd) 251 { 252 PWND Wnd = ValidateHwndNoErr(hWnd); 253 254 if (!Wnd) 255 return NULL; 256 257 return UserGetMenuObject(UlongToHandle(Wnd->IDMenu)); 258 } 259 260 PMENU get_win_sys_menu( HWND hwnd ) 261 { 262 PMENU ret = 0; 263 WND *win = ValidateHwndNoErr( hwnd ); 264 if (win) 265 { 266 ret = UserGetMenuObject(win->SystemMenu); 267 } 268 return ret; 269 } 270 271 BOOL IntDestroyMenu( PMENU pMenu, BOOL bRecurse) 272 { 273 PMENU SubMenu; 274 275 ASSERT(UserIsEnteredExclusive()); 276 if (pMenu->rgItems) /* recursively destroy submenus */ 277 { 278 int i; 279 ITEM *item = pMenu->rgItems; 280 for (i = pMenu->cItems; i > 0; i--, item++) 281 { 282 SubMenu = item->spSubMenu; 283 item->spSubMenu = NULL; 284 285 /* Remove Item Text */ 286 FreeMenuText(pMenu,item); 287 288 /* Remove Item Bitmap and set it for this process */ 289 if (item->hbmp && !(item->fState & MFS_HBMMENUBMP)) 290 { 291 GreSetObjectOwner(item->hbmp, GDI_OBJ_HMGR_POWNED); 292 item->hbmp = NULL; 293 } 294 295 /* Remove Item submenu */ 296 if (bRecurse && SubMenu)//VerifyMenu(SubMenu)) 297 { 298 /* Release submenu since it was referenced when inserted */ 299 IntReleaseMenuObject(SubMenu); 300 IntDestroyMenuObject(SubMenu, bRecurse); 301 } 302 } 303 /* Free the Item */ 304 DesktopHeapFree(pMenu->head.rpdesk, pMenu->rgItems ); 305 pMenu->rgItems = NULL; 306 pMenu->cItems = 0; 307 } 308 return TRUE; 309 } 310 311 /* Callback for the object manager */ 312 BOOLEAN 313 UserDestroyMenuObject(PVOID Object) 314 { 315 return IntDestroyMenuObject(Object, TRUE); 316 } 317 318 BOOL FASTCALL 319 IntDestroyMenuObject(PMENU Menu, BOOL bRecurse) 320 { 321 ASSERT(UserIsEnteredExclusive()); 322 if (Menu) 323 { 324 PWND Window; 325 326 if (PsGetCurrentProcessSessionId() == Menu->head.rpdesk->rpwinstaParent->dwSessionId) 327 { 328 BOOL ret; 329 if (Menu->hWnd) 330 { 331 Window = ValidateHwndNoErr(Menu->hWnd); 332 if (Window) 333 { 334 //Window->IDMenu = 0; Only in Win9x!! wine win test_SetMenu test... 335 336 /* DestroyMenu should not destroy system menu popup owner */ 337 if ((Menu->fFlags & (MNF_POPUP | MNF_SYSSUBMENU)) == MNF_POPUP) 338 { 339 // Should we check it to see if it has Class? 340 ERR("FIXME Pop up menu window thing'ie\n"); 341 //co_UserDestroyWindow( Window ); 342 //Menu->hWnd = 0; 343 } 344 } 345 } 346 347 if (!UserMarkObjectDestroy(Menu)) return TRUE; 348 349 /* Remove all menu items */ 350 IntDestroyMenu( Menu, bRecurse); 351 352 ret = UserDeleteObject(Menu->head.h, TYPE_MENU); 353 TRACE("IntDestroyMenuObject %d\n",ret); 354 return ret; 355 } 356 } 357 return FALSE; 358 } 359 360 BOOL 361 MenuInit(VOID) 362 { 363 NONCLIENTMETRICSW ncm; 364 365 /* get the menu font */ 366 if (!ghMenuFont || !ghMenuFontBold) 367 { 368 ncm.cbSize = sizeof(ncm); 369 if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)) 370 { 371 ERR("MenuInit(): SystemParametersInfo(SPI_GETNONCLIENTMETRICS) failed!\n"); 372 return FALSE; 373 } 374 375 ghMenuFont = GreCreateFontIndirectW(&ncm.lfMenuFont); 376 if (ghMenuFont == NULL) 377 { 378 ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n"); 379 return FALSE; 380 } 381 ncm.lfMenuFont.lfWeight = min(ncm.lfMenuFont.lfWeight + (FW_BOLD - FW_NORMAL), FW_HEAVY); 382 ghMenuFontBold = GreCreateFontIndirectW(&ncm.lfMenuFont); 383 if (ghMenuFontBold == NULL) 384 { 385 ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n"); 386 GreDeleteObject(ghMenuFont); 387 ghMenuFont = NULL; 388 return FALSE; 389 } 390 391 GreSetObjectOwner(ghMenuFont, GDI_OBJ_HMGR_PUBLIC); 392 GreSetObjectOwner(ghMenuFontBold, GDI_OBJ_HMGR_PUBLIC); 393 394 co_IntSetupOBM(); 395 } 396 397 return TRUE; 398 } 399 400 401 /********************************************************************** 402 * MENU_depth 403 * 404 * detect if there are loops in the menu tree (or the depth is too large) 405 */ 406 int FASTCALL MENU_depth( PMENU pmenu, int depth) 407 { 408 UINT i; 409 ITEM *item; 410 int subdepth; 411 412 if (!pmenu) return depth; 413 414 depth++; 415 if( depth > MAXMENUDEPTH) return depth; 416 item = pmenu->rgItems; 417 subdepth = depth; 418 for( i = 0; i < pmenu->cItems && subdepth <= MAXMENUDEPTH; i++, item++) 419 { 420 if( item->spSubMenu)//VerifyMenu(item->spSubMenu)) 421 { 422 int bdepth = MENU_depth( item->spSubMenu, depth); 423 if( bdepth > subdepth) subdepth = bdepth; 424 } 425 if( subdepth > MAXMENUDEPTH) 426 TRACE("<- hmenu %p\n", item->spSubMenu); 427 } 428 return subdepth; 429 } 430 431 432 /****************************************************************************** 433 * 434 * UINT MenuGetStartOfNextColumn( 435 * PMENU Menu) 436 * 437 *****************************************************************************/ 438 439 static UINT MENU_GetStartOfNextColumn( 440 PMENU menu ) 441 { 442 PITEM pItem; 443 UINT i; 444 445 if(!menu) 446 return NO_SELECTED_ITEM; 447 448 i = menu->iItem + 1; 449 if( i == NO_SELECTED_ITEM ) 450 return i; 451 452 pItem = menu->rgItems; 453 if (!pItem) return NO_SELECTED_ITEM; 454 455 for( ; i < menu->cItems; ++i ) { 456 if (pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK)) 457 return i; 458 } 459 460 return NO_SELECTED_ITEM; 461 } 462 463 /****************************************************************************** 464 * 465 * UINT MenuGetStartOfPrevColumn( 466 * PMENU Menu) 467 * 468 *****************************************************************************/ 469 static UINT MENU_GetStartOfPrevColumn( 470 PMENU menu ) 471 { 472 UINT i; 473 PITEM pItem; 474 475 if( !menu ) 476 return NO_SELECTED_ITEM; 477 478 if( menu->iItem == 0 || menu->iItem == NO_SELECTED_ITEM ) 479 return NO_SELECTED_ITEM; 480 481 pItem = menu->rgItems; 482 if (!pItem) return NO_SELECTED_ITEM; 483 484 /* Find the start of the column */ 485 486 for(i = menu->iItem; i != 0 && 487 !(pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK)); 488 --i); /* empty */ 489 490 if(i == 0) 491 return NO_SELECTED_ITEM; 492 493 for(--i; i != 0; --i) { 494 if (pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK)) 495 break; 496 } 497 498 TRACE("ret %d.\n", i ); 499 500 return i; 501 } 502 503 /*********************************************************************** 504 * MENU_FindItem 505 * 506 * Find a menu item. Return a pointer on the item, and modifies *hmenu 507 * in case the item was in a sub-menu. 508 */ 509 PITEM FASTCALL MENU_FindItem( PMENU *pmenu, UINT *nPos, UINT wFlags ) 510 { 511 MENU *menu = *pmenu; 512 ITEM *fallback = NULL; 513 UINT fallback_pos = 0; 514 UINT i; 515 516 if (!menu) return NULL; 517 518 if (wFlags & MF_BYPOSITION) 519 { 520 if (!menu->cItems) return NULL; 521 if (*nPos >= menu->cItems) return NULL; 522 return &menu->rgItems[*nPos]; 523 } 524 else 525 { 526 PITEM item = menu->rgItems; 527 for (i = 0; i < menu->cItems; i++, item++) 528 { 529 if (item->spSubMenu) 530 { 531 PMENU psubmenu = item->spSubMenu;//VerifyMenu(item->spSubMenu); 532 PITEM subitem = MENU_FindItem( &psubmenu, nPos, wFlags ); 533 if (subitem) 534 { 535 *pmenu = psubmenu; 536 return subitem; 537 } 538 else if (item->wID == *nPos) 539 { 540 /* fallback to this item if nothing else found */ 541 fallback_pos = i; 542 fallback = item; 543 } 544 } 545 else if (item->wID == *nPos) 546 { 547 *nPos = i; 548 return item; 549 } 550 } 551 } 552 553 if (fallback) 554 *nPos = fallback_pos; 555 556 return fallback; 557 } 558 559 /*********************************************************************** 560 * MenuFindSubMenu 561 * 562 * Find a Sub menu. Return the position of the submenu, and modifies 563 * *hmenu in case it is found in another sub-menu. 564 * If the submenu cannot be found, NO_SELECTED_ITEM is returned. 565 */ 566 static UINT FASTCALL MENU_FindSubMenu(PMENU *menu, PMENU SubTarget ) 567 { 568 UINT i; 569 PITEM item; 570 571 item = ((PMENU)*menu)->rgItems; 572 for (i = 0; i < ((PMENU)*menu)->cItems; i++, item++) 573 { 574 if (!item->spSubMenu) 575 continue; 576 else 577 { 578 if (item->spSubMenu == SubTarget) 579 { 580 return i; 581 } 582 else 583 { 584 PMENU pSubMenu = item->spSubMenu; 585 UINT pos = MENU_FindSubMenu( &pSubMenu, SubTarget ); 586 if (pos != NO_SELECTED_ITEM) 587 { 588 *menu = pSubMenu; 589 return pos; 590 } 591 } 592 } 593 } 594 return NO_SELECTED_ITEM; 595 } 596 597 BOOL FASTCALL 598 IntRemoveMenuItem( PMENU pMenu, UINT nPos, UINT wFlags, BOOL bRecurse ) 599 { 600 PITEM item; 601 PITEM newItems; 602 603 TRACE("(menu=%p pos=%04x flags=%04x)\n",pMenu, nPos, wFlags); 604 if (!(item = MENU_FindItem( &pMenu, &nPos, wFlags ))) return FALSE; 605 606 /* Remove item */ 607 608 FreeMenuText(pMenu,item); 609 if (bRecurse && item->spSubMenu) 610 { 611 IntDestroyMenuObject(item->spSubMenu, bRecurse); 612 } 613 ////// Use cAlloced with inc's of 8's.... 614 if (--pMenu->cItems == 0) 615 { 616 DesktopHeapFree(pMenu->head.rpdesk, pMenu->rgItems ); 617 pMenu->rgItems = NULL; 618 } 619 else 620 { 621 while (nPos < pMenu->cItems) 622 { 623 *item = *(item+1); 624 item++; 625 nPos++; 626 } 627 newItems = DesktopHeapReAlloc(pMenu->head.rpdesk, pMenu->rgItems, pMenu->cItems * sizeof(ITEM)); 628 if (newItems) 629 { 630 pMenu->rgItems = newItems; 631 } 632 } 633 return TRUE; 634 } 635 636 /********************************************************************** 637 * MENU_InsertItem 638 * 639 * Insert (allocate) a new item into a menu. 640 */ 641 ITEM *MENU_InsertItem( PMENU menu, UINT pos, UINT flags, PMENU *submenu, UINT *npos ) 642 { 643 ITEM *newItems; 644 645 /* Find where to insert new item */ 646 647 if (flags & MF_BYPOSITION) { 648 if (pos > menu->cItems) 649 pos = menu->cItems; 650 } else { 651 if (!MENU_FindItem( &menu, &pos, flags )) 652 { 653 if (submenu) *submenu = menu; 654 if (npos) *npos = pos; 655 pos = menu->cItems; 656 } 657 } 658 659 /* Make sure that MDI system buttons stay on the right side. 660 * Note: XP treats only bitmap handles 1 - 6 as "magic" ones 661 * regardless of their id. 662 */ 663 while ( pos > 0 && 664 (INT_PTR)menu->rgItems[pos - 1].hbmp >= (INT_PTR)HBMMENU_SYSTEM && 665 (INT_PTR)menu->rgItems[pos - 1].hbmp <= (INT_PTR)HBMMENU_MBAR_CLOSE_D) 666 pos--; 667 668 TRACE("inserting at %u flags %x\n", pos, flags); 669 670 /* Create new items array */ 671 672 newItems = DesktopHeapAlloc(menu->head.rpdesk, sizeof(ITEM) * (menu->cItems+1) ); 673 if (!newItems) 674 { 675 WARN("allocation failed\n" ); 676 return NULL; 677 } 678 if (menu->cItems > 0) 679 { 680 /* Copy the old array into the new one */ 681 if (pos > 0) RtlCopyMemory( newItems, menu->rgItems, pos * sizeof(ITEM) ); 682 if (pos < menu->cItems) RtlCopyMemory( &newItems[pos+1], &menu->rgItems[pos], (menu->cItems-pos)*sizeof(ITEM) ); 683 DesktopHeapFree(menu->head.rpdesk, menu->rgItems ); 684 } 685 menu->rgItems = newItems; 686 menu->cItems++; 687 RtlZeroMemory( &newItems[pos], sizeof(*newItems) ); 688 menu->cyMenu = 0; /* force size recalculate */ 689 return &newItems[pos]; 690 } 691 692 BOOL FASTCALL 693 IntInsertMenuItem( 694 _In_ PMENU MenuObject, 695 UINT uItem, 696 BOOL fByPosition, 697 PROSMENUITEMINFO ItemInfo, 698 PUNICODE_STRING lpstr) 699 { 700 PITEM MenuItem; 701 PMENU SubMenu = NULL; 702 703 NT_ASSERT(MenuObject != NULL); 704 705 if (MAX_MENU_ITEMS <= MenuObject->cItems) 706 { 707 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 708 return FALSE; 709 } 710 711 SubMenu = MenuObject; 712 713 if(!(MenuItem = MENU_InsertItem( SubMenu, uItem, fByPosition ? MF_BYPOSITION : MF_BYCOMMAND, &SubMenu, &uItem ))) return FALSE; 714 715 if(!IntSetMenuItemInfo(SubMenu, MenuItem, ItemInfo, lpstr)) 716 { 717 IntRemoveMenuItem(SubMenu, uItem, fByPosition ? MF_BYPOSITION : MF_BYCOMMAND, FALSE); 718 return FALSE; 719 } 720 721 /* Force size recalculation! */ 722 SubMenu->cyMenu = 0; 723 MenuItem->hbmpChecked = MenuItem->hbmpUnchecked = 0; 724 725 TRACE("IntInsertMenuItemToList = %u %i\n", uItem, (BOOL)((INT)uItem >= 0)); 726 727 return TRUE; 728 } 729 730 PMENU FASTCALL 731 IntCreateMenu( 732 _Out_ PHANDLE Handle, 733 _In_ BOOL IsMenuBar, 734 _In_ PDESKTOP Desktop, 735 _In_ PPROCESSINFO ppi) 736 { 737 PMENU Menu; 738 739 Menu = (PMENU)UserCreateObject( gHandleTable, 740 Desktop, 741 ppi->ptiList, 742 Handle, 743 TYPE_MENU, 744 sizeof(MENU)); 745 if(!Menu) 746 { 747 *Handle = 0; 748 return NULL; 749 } 750 751 Menu->cyMax = 0; /* Default */ 752 Menu->hbrBack = NULL; /* No brush */ 753 Menu->dwContextHelpId = 0; /* Default */ 754 Menu->dwMenuData = 0; /* Default */ 755 Menu->iItem = NO_SELECTED_ITEM; // Focused item 756 Menu->fFlags = (IsMenuBar ? 0 : MNF_POPUP); 757 Menu->spwndNotify = NULL; 758 Menu->cyMenu = 0; // Height 759 Menu->cxMenu = 0; // Width 760 Menu->cItems = 0; // Item count 761 Menu->iTop = 0; 762 Menu->iMaxTop = 0; 763 Menu->cxTextAlign = 0; 764 Menu->rgItems = NULL; 765 766 Menu->hWnd = NULL; 767 Menu->TimeToHide = FALSE; 768 769 return Menu; 770 } 771 772 BOOL FASTCALL 773 IntCloneMenuItems(PMENU Destination, PMENU Source) 774 { 775 PITEM MenuItem, NewMenuItem = NULL; 776 UINT i; 777 778 if(!Source->cItems) 779 return FALSE; 780 781 NewMenuItem = DesktopHeapAlloc(Destination->head.rpdesk, Source->cItems * sizeof(ITEM)); 782 if(!NewMenuItem) return FALSE; 783 784 RtlZeroMemory(NewMenuItem, Source->cItems * sizeof(ITEM)); 785 786 Destination->rgItems = NewMenuItem; 787 788 MenuItem = Source->rgItems; 789 for (i = 0; i < Source->cItems; i++, MenuItem++, NewMenuItem++) 790 { 791 NewMenuItem->fType = MenuItem->fType; 792 NewMenuItem->fState = MenuItem->fState; 793 NewMenuItem->wID = MenuItem->wID; 794 NewMenuItem->spSubMenu = MenuItem->spSubMenu; 795 NewMenuItem->hbmpChecked = MenuItem->hbmpChecked; 796 NewMenuItem->hbmpUnchecked = MenuItem->hbmpUnchecked; 797 NewMenuItem->dwItemData = MenuItem->dwItemData; 798 if (MenuItem->lpstr.Length) 799 { 800 NewMenuItem->lpstr.Length = 0; 801 NewMenuItem->lpstr.MaximumLength = MenuItem->lpstr.MaximumLength; 802 NewMenuItem->lpstr.Buffer = DesktopHeapAlloc(Destination->head.rpdesk, MenuItem->lpstr.MaximumLength); 803 if (!NewMenuItem->lpstr.Buffer) 804 { 805 DesktopHeapFree(Destination->head.rpdesk, NewMenuItem); 806 break; 807 } 808 RtlCopyUnicodeString(&NewMenuItem->lpstr, &MenuItem->lpstr); 809 NewMenuItem->lpstr.Buffer[MenuItem->lpstr.Length / sizeof(WCHAR)] = 0; 810 NewMenuItem->Xlpstr = NewMenuItem->lpstr.Buffer; 811 } 812 else 813 { 814 NewMenuItem->lpstr.Buffer = MenuItem->lpstr.Buffer; 815 NewMenuItem->Xlpstr = NewMenuItem->lpstr.Buffer; 816 } 817 NewMenuItem->hbmp = MenuItem->hbmp; 818 Destination->cItems = i + 1; 819 } 820 return TRUE; 821 } 822 823 PMENU FASTCALL 824 IntCloneMenu(PMENU Source) 825 { 826 HANDLE hMenu; 827 PMENU Menu; 828 829 if(!Source) 830 return NULL; 831 832 /* A menu is valid process wide. We can pass to the object manager any thread ptr */ 833 Menu = (PMENU)UserCreateObject( gHandleTable, 834 Source->head.rpdesk, 835 ((PPROCESSINFO)Source->head.hTaskWow)->ptiList, 836 &hMenu, 837 TYPE_MENU, 838 sizeof(MENU)); 839 if(!Menu) 840 return NULL; 841 842 Menu->fFlags = Source->fFlags; 843 Menu->cyMax = Source->cyMax; 844 Menu->hbrBack = Source->hbrBack; 845 Menu->dwContextHelpId = Source->dwContextHelpId; 846 Menu->dwMenuData = Source->dwMenuData; 847 Menu->iItem = NO_SELECTED_ITEM; 848 Menu->spwndNotify = NULL; 849 Menu->cyMenu = 0; 850 Menu->cxMenu = 0; 851 Menu->cItems = 0; 852 Menu->iTop = 0; 853 Menu->iMaxTop = 0; 854 Menu->cxTextAlign = 0; 855 Menu->rgItems = NULL; 856 857 Menu->hWnd = NULL; 858 Menu->TimeToHide = FALSE; 859 860 IntCloneMenuItems(Menu, Source); 861 862 return Menu; 863 } 864 865 BOOL FASTCALL 866 IntSetMenuFlagRtoL(PMENU Menu) 867 { 868 ERR("SetMenuFlagRtoL\n"); 869 Menu->fFlags |= MNF_RTOL; 870 return TRUE; 871 } 872 873 BOOL FASTCALL 874 IntSetMenuContextHelpId(PMENU Menu, DWORD dwContextHelpId) 875 { 876 Menu->dwContextHelpId = dwContextHelpId; 877 return TRUE; 878 } 879 880 BOOL FASTCALL 881 IntGetMenuInfo(PMENU Menu, PROSMENUINFO lpmi) 882 { 883 if(lpmi->fMask & MIM_BACKGROUND) 884 lpmi->hbrBack = Menu->hbrBack; 885 if(lpmi->fMask & MIM_HELPID) 886 lpmi->dwContextHelpID = Menu->dwContextHelpId; 887 if(lpmi->fMask & MIM_MAXHEIGHT) 888 lpmi->cyMax = Menu->cyMax; 889 if(lpmi->fMask & MIM_MENUDATA) 890 lpmi->dwMenuData = Menu->dwMenuData; 891 if(lpmi->fMask & MIM_STYLE) 892 lpmi->dwStyle = Menu->fFlags & MNS_STYLE_MASK; 893 894 if (sizeof(MENUINFO) < lpmi->cbSize) 895 { 896 lpmi->cItems = Menu->cItems; 897 898 lpmi->iItem = Menu->iItem; 899 lpmi->cxMenu = Menu->cxMenu; 900 lpmi->cyMenu = Menu->cyMenu; 901 lpmi->spwndNotify = Menu->spwndNotify; 902 lpmi->cxTextAlign = Menu->cxTextAlign; 903 lpmi->iTop = Menu->iTop; 904 lpmi->iMaxTop = Menu->iMaxTop; 905 lpmi->dwArrowsOn = Menu->dwArrowsOn; 906 907 lpmi->fFlags = Menu->fFlags; 908 lpmi->Self = Menu->head.h; 909 lpmi->TimeToHide = Menu->TimeToHide; 910 lpmi->Wnd = Menu->hWnd; 911 } 912 return TRUE; 913 } 914 915 BOOL FASTCALL 916 IntSetMenuInfo(PMENU Menu, PROSMENUINFO lpmi) 917 { 918 if(lpmi->fMask & MIM_BACKGROUND) 919 Menu->hbrBack = lpmi->hbrBack; 920 if(lpmi->fMask & MIM_HELPID) 921 Menu->dwContextHelpId = lpmi->dwContextHelpID; 922 if(lpmi->fMask & MIM_MAXHEIGHT) 923 Menu->cyMax = lpmi->cyMax; 924 if(lpmi->fMask & MIM_MENUDATA) 925 Menu->dwMenuData = lpmi->dwMenuData; 926 if(lpmi->fMask & MIM_STYLE) 927 Menu->fFlags ^= (Menu->fFlags ^ lpmi->dwStyle) & MNS_STYLE_MASK; 928 if(lpmi->fMask & MIM_APPLYTOSUBMENUS) 929 { 930 int i; 931 PITEM item = Menu->rgItems; 932 for ( i = Menu->cItems; i; i--, item++) 933 { 934 if ( item->spSubMenu ) 935 { 936 IntSetMenuInfo( item->spSubMenu, lpmi); 937 } 938 } 939 } 940 if (sizeof(MENUINFO) < lpmi->cbSize) 941 { 942 Menu->iItem = lpmi->iItem; 943 Menu->cyMenu = lpmi->cyMenu; 944 Menu->cxMenu = lpmi->cxMenu; 945 Menu->spwndNotify = lpmi->spwndNotify; 946 Menu->cxTextAlign = lpmi->cxTextAlign; 947 Menu->iTop = lpmi->iTop; 948 Menu->iMaxTop = lpmi->iMaxTop; 949 Menu->dwArrowsOn = lpmi->dwArrowsOn; 950 951 Menu->TimeToHide = lpmi->TimeToHide; 952 Menu->hWnd = lpmi->Wnd; 953 } 954 if ( lpmi->fMask & MIM_STYLE) 955 { 956 if (lpmi->dwStyle & MNS_AUTODISMISS) FIXME("MNS_AUTODISMISS unimplemented wine\n"); 957 if (lpmi->dwStyle & MNS_DRAGDROP) FIXME("MNS_DRAGDROP unimplemented wine\n"); 958 if (lpmi->dwStyle & MNS_MODELESS) FIXME("MNS_MODELESS unimplemented wine\n"); 959 } 960 return TRUE; 961 } 962 963 BOOL FASTCALL 964 IntGetMenuItemInfo(PMENU Menu, /* UNUSED PARAM!! */ 965 PITEM MenuItem, PROSMENUITEMINFO lpmii) 966 { 967 NTSTATUS Status; 968 969 if(lpmii->fMask & (MIIM_FTYPE | MIIM_TYPE)) 970 { 971 lpmii->fType = MenuItem->fType; 972 } 973 if(lpmii->fMask & MIIM_BITMAP) 974 { 975 lpmii->hbmpItem = MenuItem->hbmp; 976 } 977 if(lpmii->fMask & MIIM_CHECKMARKS) 978 { 979 lpmii->hbmpChecked = MenuItem->hbmpChecked; 980 lpmii->hbmpUnchecked = MenuItem->hbmpUnchecked; 981 } 982 if(lpmii->fMask & MIIM_DATA) 983 { 984 lpmii->dwItemData = MenuItem->dwItemData; 985 } 986 if(lpmii->fMask & MIIM_ID) 987 { 988 lpmii->wID = MenuItem->wID; 989 } 990 if(lpmii->fMask & MIIM_STATE) 991 { 992 lpmii->fState = MenuItem->fState; 993 } 994 if(lpmii->fMask & MIIM_SUBMENU) 995 { 996 lpmii->hSubMenu = MenuItem->spSubMenu ? MenuItem->spSubMenu->head.h : NULL; 997 } 998 999 if ((lpmii->fMask & MIIM_STRING) || 1000 ((lpmii->fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(lpmii->fType) == MF_STRING))) 1001 { 1002 if (lpmii->dwTypeData == NULL) 1003 { 1004 lpmii->cch = MenuItem->lpstr.Length / sizeof(WCHAR); 1005 } 1006 else 1007 { //// lpmii->lpstr can be read in user mode!!!! 1008 Status = MmCopyToCaller(lpmii->dwTypeData, MenuItem->lpstr.Buffer, 1009 min(lpmii->cch * sizeof(WCHAR), 1010 MenuItem->lpstr.MaximumLength)); 1011 if (! NT_SUCCESS(Status)) 1012 { 1013 SetLastNtError(Status); 1014 return FALSE; 1015 } 1016 } 1017 } 1018 1019 if (sizeof(ROSMENUITEMINFO) == lpmii->cbSize) 1020 { 1021 lpmii->Rect.left = MenuItem->xItem; 1022 lpmii->Rect.top = MenuItem->yItem; 1023 lpmii->Rect.right = MenuItem->cxItem; // Do this for now...... 1024 lpmii->Rect.bottom = MenuItem->cyItem; 1025 lpmii->dxTab = MenuItem->dxTab; 1026 lpmii->lpstr = MenuItem->lpstr.Buffer; 1027 lpmii->maxBmpSize.cx = MenuItem->cxBmp; 1028 lpmii->maxBmpSize.cy = MenuItem->cyBmp; 1029 } 1030 1031 return TRUE; 1032 } 1033 1034 BOOL FASTCALL 1035 IntSetMenuItemInfo(PMENU MenuObject, PITEM MenuItem, PROSMENUITEMINFO lpmii, PUNICODE_STRING lpstr) 1036 { 1037 PMENU SubMenuObject; 1038 BOOL circref = FALSE; 1039 1040 if(!MenuItem || !MenuObject || !lpmii) 1041 { 1042 return FALSE; 1043 } 1044 if ( lpmii->fMask & MIIM_FTYPE ) 1045 { 1046 MenuItem->fType &= ~MENUITEMINFO_TYPE_MASK; 1047 MenuItem->fType |= lpmii->fType & MENUITEMINFO_TYPE_MASK; 1048 } 1049 if (lpmii->fMask & MIIM_TYPE) 1050 { 1051 #if 0 //// Done in User32. 1052 if (lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) 1053 { 1054 ERR("IntSetMenuItemInfo: Invalid combination of fMask bits used\n"); 1055 KeRosDumpStackFrames(NULL, 20); 1056 /* This does not happen on Win9x/ME */ 1057 SetLastNtError( ERROR_INVALID_PARAMETER); 1058 return FALSE; 1059 } 1060 #endif 1061 /* 1062 * Delete the menu item type when changing type from 1063 * MF_STRING. 1064 */ 1065 if (MenuItem->fType != lpmii->fType && 1066 MENU_ITEM_TYPE(MenuItem->fType) == MFT_STRING) 1067 { 1068 FreeMenuText(MenuObject,MenuItem); 1069 RtlInitUnicodeString(&MenuItem->lpstr, NULL); 1070 MenuItem->Xlpstr = NULL; 1071 } 1072 if(lpmii->fType & MFT_BITMAP) 1073 { 1074 if(lpmii->hbmpItem) 1075 MenuItem->hbmp = lpmii->hbmpItem; 1076 else 1077 { /* Win 9x/Me stuff */ 1078 MenuItem->hbmp = (HBITMAP)((ULONG_PTR)(LOWORD(lpmii->dwTypeData))); 1079 } 1080 lpmii->dwTypeData = 0; 1081 } 1082 } 1083 if(lpmii->fMask & MIIM_BITMAP) 1084 { 1085 MenuItem->hbmp = lpmii->hbmpItem; 1086 if (MenuItem->hbmp <= HBMMENU_POPUP_MINIMIZE && MenuItem->hbmp >= HBMMENU_CALLBACK) 1087 MenuItem->fState |= MFS_HBMMENUBMP; 1088 else 1089 MenuItem->fState &= ~MFS_HBMMENUBMP; 1090 } 1091 if(lpmii->fMask & MIIM_CHECKMARKS) 1092 { 1093 MenuItem->hbmpChecked = lpmii->hbmpChecked; 1094 MenuItem->hbmpUnchecked = lpmii->hbmpUnchecked; 1095 } 1096 if(lpmii->fMask & MIIM_DATA) 1097 { 1098 MenuItem->dwItemData = lpmii->dwItemData; 1099 } 1100 if(lpmii->fMask & MIIM_ID) 1101 { 1102 MenuItem->wID = lpmii->wID; 1103 } 1104 if(lpmii->fMask & MIIM_STATE) 1105 { 1106 /* Remove MFS_DEFAULT flag from all other menu items if this item 1107 has the MFS_DEFAULT state */ 1108 if(lpmii->fState & MFS_DEFAULT) 1109 UserSetMenuDefaultItem(MenuObject, -1, 0); 1110 /* Update the menu item state flags */ 1111 UpdateMenuItemState(MenuItem->fState, lpmii->fState); 1112 } 1113 1114 if(lpmii->fMask & MIIM_SUBMENU) 1115 { 1116 if (lpmii->hSubMenu) 1117 { 1118 SubMenuObject = UserGetMenuObject(lpmii->hSubMenu); 1119 if ( SubMenuObject && !(UserObjectInDestroy(lpmii->hSubMenu)) ) 1120 { 1121 //// wine Bug 12171 : Adding Popup Menu to itself! Could create endless loops. 1122 //// CORE-7967. 1123 if (MenuObject == SubMenuObject) 1124 { 1125 HANDLE hMenu; 1126 ERR("Pop Up Menu Double Trouble!\n"); 1127 SubMenuObject = IntCreateMenu(&hMenu, 1128 FALSE, 1129 MenuObject->head.rpdesk, 1130 (PPROCESSINFO)MenuObject->head.hTaskWow); // It will be marked. 1131 if (!SubMenuObject) return FALSE; 1132 IntReleaseMenuObject(SubMenuObject); // This will be referenced again after insertion. 1133 circref = TRUE; 1134 } 1135 if ( MENU_depth( SubMenuObject, 0) > MAXMENUDEPTH ) 1136 { 1137 ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded!\n"); 1138 if (circref) IntDestroyMenuObject(SubMenuObject, FALSE); 1139 return FALSE; 1140 } 1141 /* Make sure the submenu is marked as a popup menu */ 1142 SubMenuObject->fFlags |= MNF_POPUP; 1143 // Now fix the test_subpopup_locked_by_menu tests.... 1144 if (MenuItem->spSubMenu) IntReleaseMenuObject(MenuItem->spSubMenu); 1145 MenuItem->spSubMenu = SubMenuObject; 1146 UserReferenceObject(SubMenuObject); 1147 } 1148 else 1149 { 1150 EngSetLastError( ERROR_INVALID_PARAMETER); 1151 return FALSE; 1152 } 1153 } 1154 else 1155 { // If submenu just dereference it. 1156 if (MenuItem->spSubMenu) IntReleaseMenuObject(MenuItem->spSubMenu); 1157 MenuItem->spSubMenu = NULL; 1158 } 1159 } 1160 1161 if ((lpmii->fMask & MIIM_STRING) || 1162 ((lpmii->fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(lpmii->fType) == MF_STRING))) 1163 { 1164 /* free the string when used */ 1165 FreeMenuText(MenuObject,MenuItem); 1166 RtlInitUnicodeString(&MenuItem->lpstr, NULL); 1167 MenuItem->Xlpstr = NULL; 1168 1169 if(lpmii->dwTypeData && lpmii->cch && lpstr && lpstr->Buffer) 1170 { 1171 UNICODE_STRING Source; 1172 1173 if (!NT_VERIFY(lpmii->cch <= UNICODE_STRING_MAX_CHARS)) 1174 { 1175 return FALSE; 1176 } 1177 1178 Source.Length = Source.MaximumLength = (USHORT)(lpmii->cch * sizeof(WCHAR)); 1179 Source.Buffer = lpmii->dwTypeData; 1180 1181 MenuItem->lpstr.Buffer = DesktopHeapAlloc( MenuObject->head.rpdesk, Source.Length + sizeof(WCHAR)); 1182 if(MenuItem->lpstr.Buffer != NULL) 1183 { 1184 MenuItem->lpstr.Length = 0; 1185 MenuItem->lpstr.MaximumLength = Source.Length + sizeof(WCHAR); 1186 RtlCopyUnicodeString(&MenuItem->lpstr, &Source); 1187 MenuItem->lpstr.Buffer[MenuItem->lpstr.Length / sizeof(WCHAR)] = 0; 1188 1189 MenuItem->cch = MenuItem->lpstr.Length / sizeof(WCHAR); 1190 MenuItem->Xlpstr = (USHORT*)MenuItem->lpstr.Buffer; 1191 } 1192 } 1193 } 1194 1195 if( !(MenuObject->fFlags & MNF_SYSMENU) && 1196 !MenuItem->Xlpstr && 1197 !lpmii->dwTypeData && 1198 !(MenuItem->fType & MFT_OWNERDRAW) && 1199 !MenuItem->hbmp) 1200 MenuItem->fType |= MFT_SEPARATOR; 1201 1202 if (sizeof(ROSMENUITEMINFO) == lpmii->cbSize) 1203 { 1204 MenuItem->xItem = lpmii->Rect.left; 1205 MenuItem->yItem = lpmii->Rect.top; 1206 MenuItem->cxItem = lpmii->Rect.right; // Do this for now...... 1207 MenuItem->cyItem = lpmii->Rect.bottom; 1208 MenuItem->dxTab = lpmii->dxTab; 1209 lpmii->lpstr = MenuItem->lpstr.Buffer; /* Send back new allocated string or zero */ 1210 MenuItem->cxBmp = lpmii->maxBmpSize.cx; 1211 MenuItem->cyBmp = lpmii->maxBmpSize.cy; 1212 } 1213 1214 return TRUE; 1215 } 1216 1217 1218 UINT FASTCALL 1219 IntEnableMenuItem(PMENU MenuObject, UINT uIDEnableItem, UINT uEnable) 1220 { 1221 PITEM MenuItem; 1222 UINT res; 1223 1224 if (!(MenuItem = MENU_FindItem( &MenuObject, &uIDEnableItem, uEnable ))) return (UINT)-1; 1225 1226 res = MenuItem->fState & (MF_GRAYED | MF_DISABLED); 1227 1228 MenuItem->fState ^= (res ^ uEnable) & (MF_GRAYED | MF_DISABLED); 1229 1230 /* If the close item in the system menu change update the close button */ 1231 if (res != uEnable) 1232 { 1233 switch (MenuItem->wID) // More than just close. 1234 { 1235 case SC_CLOSE: 1236 case SC_MAXIMIZE: 1237 case SC_MINIMIZE: 1238 case SC_MOVE: 1239 case SC_RESTORE: 1240 case SC_SIZE: 1241 if (MenuObject->fFlags & MNF_SYSSUBMENU && MenuObject->spwndNotify != 0) 1242 { 1243 //RECTL rc = MenuObject->spwndNotify->rcWindow; 1244 1245 /* Refresh the frame to reflect the change */ 1246 //IntMapWindowPoints(0, MenuObject->spwndNotify, (POINT *)&rc, 2); 1247 //rc.bottom = 0; 1248 //co_UserRedrawWindow(MenuObject->spwndNotify, &rc, 0, RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN); 1249 1250 // Allow UxTheme! 1251 UserPaintCaption(MenuObject->spwndNotify, DC_BUTTONS); 1252 } 1253 default: 1254 break; 1255 } 1256 } 1257 return res; 1258 } 1259 1260 DWORD FASTCALL 1261 IntCheckMenuItem(PMENU MenuObject, UINT uIDCheckItem, UINT uCheck) 1262 { 1263 PITEM MenuItem; 1264 DWORD res; 1265 1266 if (!(MenuItem = MENU_FindItem( &MenuObject, &uIDCheckItem, uCheck ))) return -1; 1267 1268 res = (DWORD)(MenuItem->fState & MF_CHECKED); 1269 1270 MenuItem->fState ^= (res ^ uCheck) & MF_CHECKED; 1271 1272 return res; 1273 } 1274 1275 BOOL FASTCALL 1276 UserSetMenuDefaultItem(PMENU MenuObject, UINT uItem, UINT fByPos) 1277 { 1278 UINT i; 1279 PITEM MenuItem = MenuObject->rgItems; 1280 1281 if (!MenuItem) return FALSE; 1282 1283 /* reset all default-item flags */ 1284 for (i = 0; i < MenuObject->cItems; i++, MenuItem++) 1285 { 1286 MenuItem->fState &= ~MFS_DEFAULT; 1287 } 1288 1289 /* no default item */ 1290 if(uItem == (UINT)-1) 1291 { 1292 return TRUE; 1293 } 1294 MenuItem = MenuObject->rgItems; 1295 if ( fByPos ) 1296 { 1297 if ( uItem >= MenuObject->cItems ) return FALSE; 1298 MenuItem[uItem].fState |= MFS_DEFAULT; 1299 return TRUE; 1300 } 1301 else 1302 { 1303 for (i = 0; i < MenuObject->cItems; i++, MenuItem++) 1304 { 1305 if (MenuItem->wID == uItem) 1306 { 1307 MenuItem->fState |= MFS_DEFAULT; 1308 return TRUE; 1309 } 1310 } 1311 1312 } 1313 return FALSE; 1314 } 1315 1316 UINT FASTCALL 1317 IntGetMenuDefaultItem(PMENU MenuObject, UINT fByPos, UINT gmdiFlags, DWORD *gismc) 1318 { 1319 UINT i = 0; 1320 PITEM MenuItem = MenuObject->rgItems; 1321 1322 /* empty menu */ 1323 if (!MenuItem) return -1; 1324 1325 while ( !( MenuItem->fState & MFS_DEFAULT ) ) 1326 { 1327 i++; MenuItem++; 1328 if (i >= MenuObject->cItems ) return -1; 1329 } 1330 1331 /* default: don't return disabled items */ 1332 if ( (!(GMDI_USEDISABLED & gmdiFlags)) && (MenuItem->fState & MFS_DISABLED )) return -1; 1333 1334 /* search rekursiv when needed */ 1335 if ( (gmdiFlags & GMDI_GOINTOPOPUPS) && MenuItem->spSubMenu ) 1336 { 1337 UINT ret; 1338 (*gismc)++; 1339 ret = IntGetMenuDefaultItem( MenuItem->spSubMenu, fByPos, gmdiFlags, gismc ); 1340 (*gismc)--; 1341 if ( -1 != ret ) return ret; 1342 1343 /* when item not found in submenu, return the popup item */ 1344 } 1345 return ( fByPos ) ? i : MenuItem->wID; 1346 } 1347 1348 PMENU 1349 FASTCALL 1350 co_IntGetSubMenu( 1351 PMENU pMenu, 1352 int nPos) 1353 { 1354 PITEM pItem; 1355 if (!(pItem = MENU_FindItem( &pMenu, (UINT*)&nPos, MF_BYPOSITION ))) return NULL; 1356 return pItem->spSubMenu; 1357 } 1358 1359 /*********************************************************************** 1360 * MenuInitSysMenuPopup 1361 * 1362 * Grey the appropriate items in System menu. 1363 */ 1364 void FASTCALL MENU_InitSysMenuPopup(PMENU menu, DWORD style, DWORD clsStyle, LONG HitTest ) 1365 { 1366 BOOL gray; 1367 UINT DefItem; 1368 1369 gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE)); 1370 IntEnableMenuItem( menu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) ); 1371 gray = ((style & WS_MAXIMIZE) != 0); 1372 IntEnableMenuItem( menu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) ); 1373 gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE); 1374 IntEnableMenuItem( menu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) ); 1375 gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE); 1376 IntEnableMenuItem( menu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) ); 1377 gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE)); 1378 IntEnableMenuItem( menu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) ); 1379 gray = (clsStyle & CS_NOCLOSE) != 0; 1380 1381 /* The menu item must keep its state if it's disabled */ 1382 if(gray) 1383 IntEnableMenuItem( menu, SC_CLOSE, MF_GRAYED); 1384 1385 /* Set default menu item */ 1386 if(style & WS_MINIMIZE) DefItem = SC_RESTORE; 1387 else if(HitTest == HTCAPTION) DefItem = ((style & (WS_MAXIMIZE | WS_MINIMIZE)) ? SC_RESTORE : SC_MAXIMIZE); 1388 else DefItem = SC_CLOSE; 1389 1390 UserSetMenuDefaultItem(menu, DefItem, MF_BYCOMMAND); 1391 } 1392 1393 1394 /*********************************************************************** 1395 * MenuDrawPopupGlyph 1396 * 1397 * Draws popup magic glyphs (can be found in system menu). 1398 */ 1399 static void FASTCALL 1400 MENU_DrawPopupGlyph(HDC dc, LPRECT r, INT_PTR popupMagic, BOOL inactive, BOOL hilite) 1401 { 1402 LOGFONTW lf; 1403 HFONT hFont, hOldFont; 1404 COLORREF clrsave; 1405 INT bkmode; 1406 WCHAR symbol; 1407 switch (popupMagic) 1408 { 1409 case (INT_PTR) HBMMENU_POPUP_RESTORE: 1410 symbol = '2'; 1411 break; 1412 case (INT_PTR) HBMMENU_POPUP_MINIMIZE: 1413 symbol = '0'; 1414 break; 1415 case (INT_PTR) HBMMENU_POPUP_MAXIMIZE: 1416 symbol = '1'; 1417 break; 1418 case (INT_PTR) HBMMENU_POPUP_CLOSE: 1419 symbol = 'r'; 1420 break; 1421 default: 1422 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic); 1423 return; 1424 } 1425 RtlZeroMemory(&lf, sizeof(LOGFONTW)); 1426 RECTL_vInflateRect(r, -2, -2); 1427 lf.lfHeight = r->bottom - r->top; 1428 lf.lfWidth = 0; 1429 lf.lfWeight = FW_NORMAL; 1430 lf.lfCharSet = DEFAULT_CHARSET; 1431 RtlCopyMemory(lf.lfFaceName, L"Marlett", sizeof(L"Marlett")); 1432 hFont = GreCreateFontIndirectW(&lf); 1433 /* save font and text color */ 1434 hOldFont = NtGdiSelectFont(dc, hFont); 1435 clrsave = GreGetTextColor(dc); 1436 bkmode = GreGetBkMode(dc); 1437 /* set color and drawing mode */ 1438 IntGdiSetBkMode(dc, TRANSPARENT); 1439 if (inactive) 1440 { 1441 /* draw shadow */ 1442 if (!hilite) 1443 { 1444 IntGdiSetTextColor(dc, IntGetSysColor(COLOR_HIGHLIGHTTEXT)); 1445 GreTextOutW(dc, r->left + 1, r->top + 1, &symbol, 1); 1446 } 1447 } 1448 IntGdiSetTextColor(dc, IntGetSysColor(inactive ? COLOR_GRAYTEXT : (hilite ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT))); 1449 /* draw selected symbol */ 1450 GreTextOutW(dc, r->left, r->top, &symbol, 1); 1451 /* restore previous settings */ 1452 IntGdiSetTextColor(dc, clrsave); 1453 NtGdiSelectFont(dc, hOldFont); 1454 IntGdiSetBkMode(dc, bkmode); 1455 GreDeleteObject(hFont); 1456 } 1457 1458 /*********************************************************************** 1459 * MENU_AdjustMenuItemRect 1460 * 1461 * Adjust menu item rectangle according to scrolling state. 1462 */ 1463 VOID FASTCALL 1464 MENU_AdjustMenuItemRect(PMENU menu, PRECTL rect) 1465 { 1466 if (menu->dwArrowsOn) 1467 { 1468 UINT arrow_bitmap_height; 1469 arrow_bitmap_height = gpsi->oembmi[OBI_UPARROW].cy; ///// Menu up arrow! OBM_UPARROW 1470 rect->top += arrow_bitmap_height - menu->iTop; 1471 rect->bottom += arrow_bitmap_height - menu->iTop; 1472 } 1473 } 1474 1475 /*********************************************************************** 1476 * MENU_FindItemByCoords 1477 * 1478 * Find the item at the specified coordinates (screen coords). Does 1479 * not work for child windows and therefore should not be called for 1480 * an arbitrary system menu. 1481 */ 1482 static ITEM *MENU_FindItemByCoords( MENU *menu, POINT pt, UINT *pos ) 1483 { 1484 ITEM *item; 1485 UINT i; 1486 INT cx, cy; 1487 RECT rect; 1488 PWND pWnd = ValidateHwndNoErr(menu->hWnd); 1489 1490 if (!IntGetWindowRect(pWnd, &rect)) return NULL; 1491 1492 cx = UserGetSystemMetrics(SM_CXDLGFRAME); 1493 cy = UserGetSystemMetrics(SM_CYDLGFRAME); 1494 RECTL_vInflateRect(&rect, -cx, -cy); 1495 1496 if (pWnd->ExStyle & WS_EX_LAYOUTRTL) 1497 pt.x = rect.right - 1 - pt.x; 1498 else 1499 pt.x -= rect.left; 1500 pt.y -= rect.top; 1501 item = menu->rgItems; 1502 for (i = 0; i < menu->cItems; i++, item++) 1503 { 1504 //rect = item->rect; 1505 rect.left = item->xItem; 1506 rect.top = item->yItem; 1507 rect.right = item->cxItem; // Do this for now...... 1508 rect.bottom = item->cyItem; 1509 1510 MENU_AdjustMenuItemRect(menu, &rect); 1511 if (RECTL_bPointInRect(&rect, pt.x, pt.y)) 1512 { 1513 if (pos) *pos = i; 1514 return item; 1515 } 1516 } 1517 return NULL; 1518 } 1519 1520 INT FASTCALL IntMenuItemFromPoint(PWND pWnd, HMENU hMenu, POINT ptScreen) 1521 { 1522 MENU *menu = UserGetMenuObject(hMenu); 1523 UINT pos; 1524 1525 /*FIXME: Do we have to handle hWnd here? */ 1526 if (!menu) return -1; 1527 if (!MENU_FindItemByCoords(menu, ptScreen, &pos)) return -1; 1528 return pos; 1529 } 1530 1531 /*********************************************************************** 1532 * MenuFindItemByKey 1533 * 1534 * Find the menu item selected by a key press. 1535 * Return item id, -1 if none, -2 if we should close the menu. 1536 */ 1537 static UINT FASTCALL MENU_FindItemByKey(PWND WndOwner, PMENU menu, 1538 WCHAR Key, BOOL ForceMenuChar) 1539 { 1540 LRESULT MenuChar; 1541 WORD Flags = 0; 1542 1543 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)Key, Key, menu ); 1544 1545 if (!menu || !VerifyMenu(menu)) 1546 menu = co_IntGetSubMenu( UserGetMenuObject(WndOwner->SystemMenu), 0 ); 1547 if (menu) 1548 { 1549 ITEM *item = menu->rgItems; 1550 1551 if ( !ForceMenuChar ) 1552 { 1553 UINT i; 1554 BOOL cjk = UserGetSystemMetrics( SM_DBCSENABLED ); 1555 1556 for (i = 0; i < menu->cItems; i++, item++) 1557 { 1558 LPWSTR text = item->Xlpstr; 1559 if( text) 1560 { 1561 const WCHAR *p = text - 2; 1562 do 1563 { 1564 const WCHAR *q = p + 2; 1565 p = wcschr (q, '&'); 1566 if (!p && cjk) p = wcschr (q, '\036'); /* Japanese Win16 */ 1567 } 1568 while (p != NULL && p [1] == '&'); 1569 if (p && (towupper(p[1]) == towupper(Key))) return i; 1570 } 1571 } 1572 } 1573 1574 Flags |= menu->fFlags & MNF_POPUP ? MF_POPUP : 0; 1575 Flags |= menu->fFlags & MNF_SYSMENU ? MF_SYSMENU : 0; 1576 1577 MenuChar = co_IntSendMessage( UserHMGetHandle(WndOwner), WM_MENUCHAR, 1578 MAKEWPARAM(Key, Flags), (LPARAM) UserHMGetHandle(menu)); 1579 if (HIWORD(MenuChar) == MNC_EXECUTE) return LOWORD(MenuChar); 1580 if (HIWORD(MenuChar) == MNC_CLOSE) return (UINT)(-2); 1581 } 1582 return (UINT)(-1); 1583 } 1584 1585 /*********************************************************************** 1586 * MenuGetBitmapItemSize 1587 * 1588 * Get the size of a bitmap item. 1589 */ 1590 static void FASTCALL MENU_GetBitmapItemSize(PITEM lpitem, SIZE *size, PWND WndOwner) 1591 { 1592 BITMAP bm; 1593 HBITMAP bmp = lpitem->hbmp; 1594 1595 size->cx = size->cy = 0; 1596 1597 /* check if there is a magic menu item associated with this item */ 1598 if (IS_MAGIC_BITMAP(bmp)) 1599 { 1600 switch((INT_PTR) bmp) 1601 { 1602 case (INT_PTR)HBMMENU_CALLBACK: 1603 { 1604 MEASUREITEMSTRUCT measItem; 1605 measItem.CtlType = ODT_MENU; 1606 measItem.CtlID = 0; 1607 measItem.itemID = lpitem->wID; 1608 measItem.itemWidth = lpitem->cxItem - lpitem->xItem; //lpitem->Rect.right - lpitem->Rect.left; 1609 measItem.itemHeight = lpitem->cyItem - lpitem->yItem; //lpitem->Rect.bottom - lpitem->Rect.top; 1610 measItem.itemData = lpitem->dwItemData; 1611 co_IntSendMessage( UserHMGetHandle(WndOwner), WM_MEASUREITEM, 0, (LPARAM)&measItem); 1612 size->cx = measItem.itemWidth; 1613 size->cy = measItem.itemHeight; 1614 TRACE("HBMMENU_CALLBACK Height %d Width %d\n",measItem.itemHeight,measItem.itemWidth); 1615 return; 1616 } 1617 break; 1618 1619 case (INT_PTR) HBMMENU_SYSTEM: 1620 if (lpitem->dwItemData) 1621 { 1622 bmp = (HBITMAP) lpitem->dwItemData; 1623 break; 1624 } 1625 /* fall through */ 1626 case (INT_PTR) HBMMENU_MBAR_RESTORE: 1627 case (INT_PTR) HBMMENU_MBAR_MINIMIZE: 1628 case (INT_PTR) HBMMENU_MBAR_CLOSE: 1629 case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D: 1630 case (INT_PTR) HBMMENU_MBAR_CLOSE_D: 1631 case (INT_PTR) HBMMENU_POPUP_CLOSE: 1632 case (INT_PTR) HBMMENU_POPUP_RESTORE: 1633 case (INT_PTR) HBMMENU_POPUP_MAXIMIZE: 1634 case (INT_PTR) HBMMENU_POPUP_MINIMIZE: 1635 /* FIXME: Why we need to subtract these magic values? */ 1636 /* to make them smaller than the menu bar? */ 1637 size->cx = UserGetSystemMetrics(SM_CXSIZE) - 2; 1638 size->cy = UserGetSystemMetrics(SM_CYSIZE) - 4; 1639 return; 1640 } 1641 } 1642 1643 if (GreGetObject(bmp, sizeof(BITMAP), &bm)) 1644 { 1645 size->cx = bm.bmWidth; 1646 size->cy = bm.bmHeight; 1647 } 1648 } 1649 1650 /*********************************************************************** 1651 * MenuDrawBitmapItem 1652 * 1653 * Draw a bitmap item. 1654 */ 1655 static void FASTCALL MENU_DrawBitmapItem(HDC hdc, PITEM lpitem, const RECT *rect, 1656 PMENU Menu, PWND WndOwner, UINT odaction, BOOL MenuBar) 1657 { 1658 BITMAP bm; 1659 DWORD rop; 1660 HDC hdcMem; 1661 HBITMAP bmp; 1662 int w = rect->right - rect->left; 1663 int h = rect->bottom - rect->top; 1664 int bmp_xoffset = 0; 1665 int left, top; 1666 BOOL flat_menu; 1667 HBITMAP hbmToDraw = lpitem->hbmp; 1668 bmp = hbmToDraw; 1669 1670 UserSystemParametersInfo(SPI_GETFLATMENU, 0, &flat_menu, 0); 1671 1672 /* Check if there is a magic menu item associated with this item */ 1673 if (IS_MAGIC_BITMAP(hbmToDraw)) 1674 { 1675 UINT flags = 0; 1676 RECT r; 1677 1678 r = *rect; 1679 switch ((INT_PTR)hbmToDraw) 1680 { 1681 case (INT_PTR)HBMMENU_SYSTEM: 1682 if (lpitem->dwItemData) 1683 { 1684 if (ValidateHwndNoErr((HWND)lpitem->dwItemData)) 1685 { 1686 ERR("Get Item Data from this Window!!!\n"); 1687 } 1688 1689 ERR("Draw Bitmap\n"); 1690 bmp = (HBITMAP)lpitem->dwItemData; 1691 if (!GreGetObject( bmp, sizeof(bm), &bm )) return; 1692 } 1693 else 1694 { 1695 PCURICON_OBJECT pIcon = NULL; 1696 //if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE)); 1697 //bmp = BmpSysMenu; 1698 //if (! GreGetObject(bmp, sizeof(bm), &bm)) return; 1699 /* only use right half of the bitmap */ 1700 //bmp_xoffset = bm.bmWidth / 2; 1701 //bm.bmWidth -= bmp_xoffset; 1702 if (WndOwner) 1703 { 1704 pIcon = NC_IconForWindow(WndOwner); 1705 // FIXME: NC_IconForWindow should reference it for us */ 1706 if (pIcon) UserReferenceObject(pIcon); 1707 } 1708 ERR("Draw ICON\n"); 1709 if (pIcon) 1710 { 1711 LONG cx = UserGetSystemMetrics(SM_CXSMICON); 1712 LONG cy = UserGetSystemMetrics(SM_CYSMICON); 1713 LONG x = rect->left - cx/2 + 1 + (rect->bottom - rect->top)/2; // this is really what Window does 1714 LONG y = (rect->top + rect->bottom)/2 - cy/2; // center 1715 UserDrawIconEx(hdc, x, y, pIcon, cx, cy, 0, NULL, DI_NORMAL); 1716 UserDereferenceObject(pIcon); 1717 } 1718 return; 1719 } 1720 goto got_bitmap; 1721 case (INT_PTR)HBMMENU_MBAR_RESTORE: 1722 flags = DFCS_CAPTIONRESTORE; 1723 break; 1724 case (INT_PTR)HBMMENU_MBAR_MINIMIZE: 1725 r.right += 1; 1726 flags = DFCS_CAPTIONMIN; 1727 break; 1728 case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D: 1729 r.right += 1; 1730 flags = DFCS_CAPTIONMIN | DFCS_INACTIVE; 1731 break; 1732 case (INT_PTR)HBMMENU_MBAR_CLOSE: 1733 flags = DFCS_CAPTIONCLOSE; 1734 break; 1735 case (INT_PTR)HBMMENU_MBAR_CLOSE_D: 1736 flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE; 1737 break; 1738 case (INT_PTR)HBMMENU_CALLBACK: 1739 { 1740 DRAWITEMSTRUCT drawItem; 1741 POINT origorg; 1742 drawItem.CtlType = ODT_MENU; 1743 drawItem.CtlID = 0; 1744 drawItem.itemID = lpitem->wID; 1745 drawItem.itemAction = odaction; 1746 drawItem.itemState = (lpitem->fState & MF_CHECKED)?ODS_CHECKED:0; 1747 drawItem.itemState |= (lpitem->fState & MF_DEFAULT)?ODS_DEFAULT:0; 1748 drawItem.itemState |= (lpitem->fState & MF_DISABLED)?ODS_DISABLED:0; 1749 drawItem.itemState |= (lpitem->fState & MF_GRAYED)?ODS_GRAYED|ODS_DISABLED:0; 1750 drawItem.itemState |= (lpitem->fState & MF_HILITE)?ODS_SELECTED:0; 1751 drawItem.itemState |= (!(Menu->fFlags & MNF_UNDERLINE))?ODS_NOACCEL:0; 1752 drawItem.itemState |= (Menu->fFlags & MNF_INACTIVE)?ODS_INACTIVE:0; 1753 drawItem.hwndItem = (HWND)UserHMGetHandle(Menu); 1754 drawItem.hDC = hdc; 1755 drawItem.rcItem = *rect; 1756 drawItem.itemData = lpitem->dwItemData; 1757 /* some applications make this assumption on the DC's origin */ 1758 GreSetViewportOrgEx( hdc, lpitem->xItem, lpitem->yItem, &origorg); 1759 RECTL_vOffsetRect(&drawItem.rcItem, -(LONG)lpitem->xItem, -(LONG)lpitem->yItem); 1760 co_IntSendMessage( UserHMGetHandle(WndOwner), WM_DRAWITEM, 0, (LPARAM)&drawItem); 1761 GreSetViewportOrgEx( hdc, origorg.x, origorg.y, NULL); 1762 return; 1763 } 1764 break; 1765 1766 case (INT_PTR) HBMMENU_POPUP_CLOSE: 1767 case (INT_PTR) HBMMENU_POPUP_RESTORE: 1768 case (INT_PTR) HBMMENU_POPUP_MAXIMIZE: 1769 case (INT_PTR) HBMMENU_POPUP_MINIMIZE: 1770 MENU_DrawPopupGlyph(hdc, &r, (INT_PTR)hbmToDraw, lpitem->fState & MF_GRAYED, lpitem->fState & MF_HILITE); 1771 return; 1772 } 1773 RECTL_vInflateRect(&r, -1, -1); 1774 if (lpitem->fState & MF_HILITE) flags |= DFCS_PUSHED; 1775 DrawFrameControl(hdc, &r, DFC_CAPTION, flags); 1776 return; 1777 } 1778 1779 if (!bmp || !GreGetObject( bmp, sizeof(bm), &bm )) return; 1780 1781 got_bitmap: 1782 hdcMem = NtGdiCreateCompatibleDC( hdc ); 1783 NtGdiSelectBitmap( hdcMem, bmp ); 1784 /* handle fontsize > bitmap_height */ 1785 top = (h>bm.bmHeight) ? rect->top+(h-bm.bmHeight)/2 : rect->top; 1786 left=rect->left; 1787 rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_BITMAP(hbmToDraw)) ? NOTSRCCOPY : SRCCOPY; 1788 if ((lpitem->fState & MF_HILITE) && lpitem->hbmp) 1789 IntGdiSetBkColor(hdc, IntGetSysColor(COLOR_HIGHLIGHT)); 1790 if (MenuBar && 1791 !flat_menu && 1792 (lpitem->fState & (MF_HILITE | MF_GRAYED)) == MF_HILITE) 1793 { 1794 ++left; 1795 ++top; 1796 } 1797 NtGdiBitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop , 0, 0); 1798 IntGdiDeleteDC( hdcMem, FALSE ); 1799 } 1800 1801 LONG 1802 IntGetDialogBaseUnits(VOID) 1803 { 1804 static DWORD units; 1805 1806 if (!units) 1807 { 1808 HDC hdc; 1809 SIZE size; 1810 1811 if ((hdc = UserGetDCEx(NULL, NULL, DCX_CACHE))) 1812 { 1813 size.cx = IntGetCharDimensions( hdc, NULL, (PDWORD)&size.cy ); 1814 if (size.cx) units = MAKELONG( size.cx, size.cy ); 1815 UserReleaseDC( 0, hdc, FALSE); 1816 } 1817 } 1818 return units; 1819 } 1820 1821 1822 /*********************************************************************** 1823 * MenuCalcItemSize 1824 * 1825 * Calculate the size of the menu item and store it in lpitem->rect. 1826 */ 1827 static void FASTCALL MENU_CalcItemSize( HDC hdc, PITEM lpitem, PMENU Menu, PWND pwndOwner, 1828 INT orgX, INT orgY, BOOL menuBar, BOOL textandbmp) 1829 { 1830 WCHAR *p; 1831 UINT check_bitmap_width = UserGetSystemMetrics( SM_CXMENUCHECK ); 1832 UINT arrow_bitmap_width; 1833 RECT Rect; 1834 INT itemheight = 0; 1835 1836 TRACE("dc=%x owner=%x (%d,%d)\n", hdc, pwndOwner, orgX, orgY); 1837 1838 arrow_bitmap_width = gpsi->oembmi[OBI_MNARROW].cx; 1839 1840 MenuCharSize.cx = IntGetCharDimensions( hdc, NULL, (PDWORD)&MenuCharSize.cy ); 1841 1842 RECTL_vSetRect( &Rect, orgX, orgY, orgX, orgY ); 1843 1844 if (lpitem->fType & MF_OWNERDRAW) 1845 { 1846 MEASUREITEMSTRUCT mis; 1847 mis.CtlType = ODT_MENU; 1848 mis.CtlID = 0; 1849 mis.itemID = lpitem->wID; 1850 mis.itemData = lpitem->dwItemData; 1851 mis.itemHeight = HIWORD( IntGetDialogBaseUnits()); 1852 mis.itemWidth = 0; 1853 co_IntSendMessage( UserHMGetHandle(pwndOwner), WM_MEASUREITEM, 0, (LPARAM)&mis ); 1854 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average 1855 * width of a menufont character to the width of an owner-drawn menu. 1856 */ 1857 Rect.right += mis.itemWidth + 2 * MenuCharSize.cx; 1858 if (menuBar) { 1859 /* under at least win95 you seem to be given a standard 1860 height for the menu and the height value is ignored */ 1861 Rect.bottom += UserGetSystemMetrics(SM_CYMENUSIZE); 1862 } else 1863 Rect.bottom += mis.itemHeight; 1864 // Or this, 1865 //lpitem->cxBmp = mis.itemWidth; 1866 //lpitem->cyBmp = mis.itemHeight; 1867 TRACE("MF_OWNERDRAW Height %d Width %d\n",mis.itemHeight,mis.itemWidth); 1868 TRACE("MF_OWNERDRAW id=%04lx size=%dx%d cx %d cy %d\n", 1869 lpitem->wID, Rect.right-Rect.left, 1870 Rect.bottom-Rect.top, MenuCharSize.cx, MenuCharSize.cy); 1871 1872 lpitem->xItem = Rect.left; 1873 lpitem->yItem = Rect.top; 1874 lpitem->cxItem = Rect.right; 1875 lpitem->cyItem = Rect.bottom; 1876 1877 return; 1878 } 1879 1880 lpitem->xItem = orgX; 1881 lpitem->yItem = orgY; 1882 lpitem->cxItem = orgX; 1883 lpitem->cyItem = orgY; 1884 1885 if (lpitem->fType & MF_SEPARATOR) 1886 { 1887 lpitem->cyItem += UserGetSystemMetrics( SM_CYMENUSIZE)/2;//SEPARATOR_HEIGHT; 1888 if( !menuBar) 1889 lpitem->cxItem += arrow_bitmap_width + MenuCharSize.cx; 1890 return; 1891 } 1892 1893 lpitem->dxTab = 0; 1894 1895 if (lpitem->hbmp) 1896 { 1897 SIZE size; 1898 1899 if (!menuBar) { 1900 MENU_GetBitmapItemSize(lpitem, &size, pwndOwner ); 1901 /* Keep the size of the bitmap in callback mode to be able 1902 * to draw it correctly */ 1903 lpitem->cxBmp = size.cx; 1904 lpitem->cyBmp = size.cy; 1905 Menu->cxTextAlign = max(Menu->cxTextAlign, size.cx); 1906 lpitem->cxItem += size.cx + 2; 1907 itemheight = size.cy + 2; 1908 1909 if( !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK)) 1910 lpitem->cxItem += 2 * check_bitmap_width; 1911 lpitem->cxItem += 4 + MenuCharSize.cx; 1912 lpitem->dxTab = lpitem->cxItem; 1913 lpitem->cxItem += arrow_bitmap_width; 1914 } else /* hbmpItem & MenuBar */ { 1915 MENU_GetBitmapItemSize(lpitem, &size, pwndOwner ); 1916 lpitem->cxItem += size.cx; 1917 if( lpitem->Xlpstr) lpitem->cxItem += 2; 1918 itemheight = size.cy; 1919 1920 /* Special case: Minimize button doesn't have a space behind it. */ 1921 if (lpitem->hbmp == (HBITMAP)HBMMENU_MBAR_MINIMIZE || 1922 lpitem->hbmp == (HBITMAP)HBMMENU_MBAR_MINIMIZE_D) 1923 lpitem->cxItem -= 1; 1924 } 1925 } 1926 else if (!menuBar) { 1927 if( !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK)) 1928 lpitem->cxItem += check_bitmap_width; 1929 lpitem->cxItem += 4 + MenuCharSize.cx; 1930 lpitem->dxTab = lpitem->cxItem; 1931 lpitem->cxItem += arrow_bitmap_width; 1932 } 1933 1934 /* it must be a text item - unless it's the system menu */ 1935 if (!(lpitem->fType & MF_SYSMENU) && lpitem->Xlpstr) { 1936 HFONT hfontOld = NULL; 1937 RECT rc;// = lpitem->Rect; 1938 LONG txtheight, txtwidth; 1939 1940 rc.left = lpitem->xItem; 1941 rc.top = lpitem->yItem; 1942 rc.right = lpitem->cxItem; // Do this for now...... 1943 rc.bottom = lpitem->cyItem; 1944 1945 if ( lpitem->fState & MFS_DEFAULT ) { 1946 hfontOld = NtGdiSelectFont( hdc, ghMenuFontBold ); 1947 } 1948 if (menuBar) { 1949 txtheight = DrawTextW( hdc, lpitem->Xlpstr, -1, &rc, DT_SINGLELINE|DT_CALCRECT); 1950 1951 lpitem->cxItem += rc.right - rc.left; 1952 itemheight = max( max( itemheight, txtheight), UserGetSystemMetrics( SM_CYMENU) - 1); 1953 1954 lpitem->cxItem += 2 * MenuCharSize.cx; 1955 } else { 1956 if ((p = wcschr( lpitem->Xlpstr, '\t' )) != NULL) { 1957 RECT tmprc = rc; 1958 LONG tmpheight; 1959 int n = (int)( p - lpitem->Xlpstr); 1960 /* Item contains a tab (only meaningful in popup menus) */ 1961 /* get text size before the tab */ 1962 txtheight = DrawTextW( hdc, lpitem->Xlpstr, n, &rc, 1963 DT_SINGLELINE|DT_CALCRECT); 1964 txtwidth = rc.right - rc.left; 1965 p += 1; /* advance past the Tab */ 1966 /* get text size after the tab */ 1967 tmpheight = DrawTextW( hdc, p, -1, &tmprc, 1968 DT_SINGLELINE|DT_CALCRECT); 1969 lpitem->dxTab += txtwidth; 1970 txtheight = max( txtheight, tmpheight); 1971 txtwidth += MenuCharSize.cx + /* space for the tab */ 1972 tmprc.right - tmprc.left; /* space for the short cut */ 1973 } else { 1974 txtheight = DrawTextW( hdc, lpitem->Xlpstr, -1, &rc, 1975 DT_SINGLELINE|DT_CALCRECT); 1976 txtwidth = rc.right - rc.left; 1977 lpitem->dxTab += txtwidth; 1978 } 1979 lpitem->cxItem += 2 + txtwidth; 1980 itemheight = max( itemheight, 1981 max( txtheight + 2, MenuCharSize.cy + 4)); 1982 } 1983 if (hfontOld) 1984 { 1985 NtGdiSelectFont (hdc, hfontOld); 1986 } 1987 } else if( menuBar) { 1988 itemheight = max( itemheight, UserGetSystemMetrics(SM_CYMENU)-1); 1989 } 1990 lpitem->cyItem += itemheight; 1991 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem->xItem, lpitem->yItem, lpitem->cxItem, lpitem->cyItem); 1992 } 1993 1994 /*********************************************************************** 1995 * MENU_GetMaxPopupHeight 1996 */ 1997 static UINT 1998 MENU_GetMaxPopupHeight(PMENU lppop) 1999 { 2000 if (lppop->cyMax) 2001 { 2002 //ERR("MGMaxPH cyMax %d\n",lppop->cyMax); 2003 return lppop->cyMax; 2004 } 2005 //ERR("MGMaxPH SyMax %d\n",UserGetSystemMetrics(SM_CYSCREEN) - UserGetSystemMetrics(SM_CYBORDER)); 2006 return UserGetSystemMetrics(SM_CYSCREEN) - UserGetSystemMetrics(SM_CYBORDER); 2007 } 2008 2009 /*********************************************************************** 2010 * MenuPopupMenuCalcSize 2011 * 2012 * Calculate the size of a popup menu. 2013 */ 2014 static void FASTCALL MENU_PopupMenuCalcSize(PMENU Menu, PWND WndOwner) 2015 { 2016 PITEM lpitem; 2017 HDC hdc; 2018 int start, i; 2019 int orgX, orgY, maxX, maxTab, maxTabWidth, maxHeight; 2020 BOOL textandbmp = FALSE; 2021 2022 Menu->cxMenu = Menu->cyMenu = 0; 2023 if (Menu->cItems == 0) return; 2024 2025 hdc = UserGetDCEx(NULL, NULL, DCX_CACHE); 2026 2027 NtGdiSelectFont( hdc, ghMenuFont ); 2028 2029 start = 0; 2030 maxX = 0; 2031 2032 Menu->cxTextAlign = 0; 2033 2034 while (start < Menu->cItems) 2035 { 2036 lpitem = &Menu->rgItems[start]; 2037 orgX = maxX; 2038 if( lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK)) 2039 orgX += MENU_COL_SPACE; 2040 orgY = 0; 2041 2042 maxTab = maxTabWidth = 0; 2043 /* Parse items until column break or end of menu */ 2044 for (i = start; i < Menu->cItems; i++, lpitem++) 2045 { 2046 if (i != start && 2047 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break; 2048 2049 MENU_CalcItemSize(hdc, lpitem, Menu, WndOwner, orgX, orgY, FALSE, textandbmp); 2050 maxX = max(maxX, lpitem->cxItem); 2051 orgY = lpitem->cyItem; 2052 if (IS_STRING_ITEM(lpitem->fType) && lpitem->dxTab ) 2053 { 2054 maxTab = max( maxTab, lpitem->dxTab ); 2055 maxTabWidth = max(maxTabWidth, lpitem->cxItem - lpitem->dxTab); 2056 } 2057 if( lpitem->Xlpstr && lpitem->hbmp) textandbmp = TRUE; 2058 } 2059 2060 /* Finish the column (set all items to the largest width found) */ 2061 maxX = max( maxX, maxTab + maxTabWidth ); 2062 for (lpitem = &Menu->rgItems[start]; start < i; start++, lpitem++) 2063 { 2064 lpitem->cxItem = maxX; 2065 if (IS_STRING_ITEM(lpitem->fType) && lpitem->dxTab) 2066 lpitem->dxTab = maxTab; 2067 } 2068 Menu->cyMenu = max(Menu->cyMenu, orgY); 2069 } 2070 2071 Menu->cxMenu = maxX; 2072 /* if none of the items have both text and bitmap then 2073 * the text and bitmaps are all aligned on the left. If there is at 2074 * least one item with both text and bitmap then bitmaps are 2075 * on the left and texts left aligned with the right hand side 2076 * of the bitmaps */ 2077 if( !textandbmp) Menu->cxTextAlign = 0; 2078 2079 /* Adjust popup height if it exceeds maximum */ 2080 maxHeight = MENU_GetMaxPopupHeight(Menu); 2081 Menu->iMaxTop = Menu->cyMenu; 2082 if (Menu->cyMenu >= maxHeight) 2083 { 2084 Menu->cyMenu = maxHeight; 2085 Menu->dwArrowsOn = 1; 2086 } 2087 else 2088 { 2089 Menu->dwArrowsOn = 0; 2090 } 2091 UserReleaseDC( 0, hdc, FALSE ); 2092 } 2093 2094 /*********************************************************************** 2095 * MENU_MenuBarCalcSize 2096 * 2097 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap 2098 * height is off by 1 pixel which causes lengthy window relocations when 2099 * active document window is maximized/restored. 2100 * 2101 * Calculate the size of the menu bar. 2102 */ 2103 static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect, PMENU lppop, PWND pwndOwner ) 2104 { 2105 ITEM *lpitem; 2106 UINT start, i, helpPos; 2107 int orgX, orgY, maxY; 2108 2109 if ((lprect == NULL) || (lppop == NULL)) return; 2110 if (lppop->cItems == 0) return; 2111 //TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect)); 2112 lppop->cxMenu = lprect->right - lprect->left; 2113 lppop->cyMenu = 0; 2114 maxY = lprect->top; 2115 start = 0; 2116 helpPos = ~0U; 2117 lppop->cxTextAlign = 0; 2118 while (start < lppop->cItems) 2119 { 2120 lpitem = &lppop->rgItems[start]; 2121 orgX = lprect->left; 2122 orgY = maxY; 2123 2124 /* Parse items until line break or end of menu */ 2125 for (i = start; i < lppop->cItems; i++, lpitem++) 2126 { 2127 if ((helpPos == ~0U) && (lpitem->fType & MF_RIGHTJUSTIFY)) helpPos = i; 2128 if ((i != start) && 2129 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break; 2130 2131 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX, orgY ); 2132 //debug_print_menuitem (" item: ", lpitem, ""); 2133 //MENU_CalcItemSize( hdc, lpitem, pwndOwner, orgX, orgY, TRUE, lppop ); 2134 MENU_CalcItemSize(hdc, lpitem, lppop, pwndOwner, orgX, orgY, TRUE, FALSE); 2135 2136 if (lpitem->cxItem > lprect->right) 2137 { 2138 if (i != start) break; 2139 else lpitem->cxItem = lprect->right; 2140 } 2141 maxY = max( maxY, lpitem->cyItem ); 2142 orgX = lpitem->cxItem; 2143 } 2144 2145 /* Finish the line (set all items to the largest height found) */ 2146 2147 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the 2148 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */ 2149 #if 0 2150 while (start < i) lppop->rgItems[start++].cyItem = maxY; 2151 #endif 2152 start = i; /* This works! */ 2153 } 2154 2155 lprect->bottom = maxY + 1; 2156 lppop->cyMenu = lprect->bottom - lprect->top; 2157 2158 /* Flush right all items between the MF_RIGHTJUSTIFY and */ 2159 /* the last item (if several lines, only move the last line) */ 2160 if (helpPos == ~0U) return; 2161 lpitem = &lppop->rgItems[lppop->cItems-1]; 2162 orgY = lpitem->yItem; 2163 orgX = lprect->right; 2164 for (i = lppop->cItems - 1; i >= helpPos; i--, lpitem--) { 2165 if (lpitem->yItem != orgY) break; /* Other line */ 2166 if (lpitem->cxItem >= orgX) break; /* Too far right already */ 2167 lpitem->xItem += orgX - lpitem->cxItem; 2168 lpitem->cxItem = orgX; 2169 orgX = lpitem->xItem; 2170 } 2171 } 2172 2173 /*********************************************************************** 2174 * MENU_DrawScrollArrows 2175 * 2176 * Draw scroll arrows. 2177 */ 2178 static void MENU_DrawScrollArrows(PMENU lppop, HDC hdc) 2179 { 2180 UINT arrow_bitmap_height; 2181 RECT rect; 2182 UINT Flags = 0; 2183 2184 arrow_bitmap_height = gpsi->oembmi[OBI_DNARROW].cy; 2185 2186 rect.left = 0; 2187 rect.top = 0; 2188 rect.right = lppop->cxMenu; 2189 rect.bottom = arrow_bitmap_height; 2190 FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_MENU)); 2191 UITOOLS95_DrawFrameMenu(hdc, &rect, (lppop->iTop ? 0 : DFCS_INACTIVE) | DFCS_MENUARROWUP); 2192 2193 rect.top = lppop->cyMenu - arrow_bitmap_height; 2194 rect.bottom = lppop->cyMenu; 2195 FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_MENU)); 2196 if (!(lppop->iTop < lppop->iMaxTop - (MENU_GetMaxPopupHeight(lppop) - 2 * arrow_bitmap_height))) 2197 Flags = DFCS_INACTIVE; 2198 UITOOLS95_DrawFrameMenu(hdc, &rect, Flags | DFCS_MENUARROWDOWN); 2199 } 2200 2201 /*********************************************************************** 2202 * MenuDrawMenuItem 2203 * 2204 * Draw a single menu item. 2205 */ 2206 static void FASTCALL MENU_DrawMenuItem(PWND Wnd, PMENU Menu, PWND WndOwner, HDC hdc, 2207 PITEM lpitem, UINT Height, BOOL menuBar, UINT odaction) 2208 { 2209 RECT rect; 2210 PWCHAR Text; 2211 BOOL flat_menu = FALSE; 2212 int bkgnd; 2213 UINT arrow_bitmap_width = 0; 2214 //RECT bmprc; 2215 2216 if (!menuBar) { 2217 arrow_bitmap_width = gpsi->oembmi[OBI_MNARROW].cx; 2218 } 2219 2220 if (lpitem->fType & MF_SYSMENU) 2221 { 2222 if (!(Wnd->style & WS_MINIMIZE)) 2223 { 2224 NC_GetInsideRect(Wnd, &rect); 2225 UserDrawSysMenuButton(Wnd, hdc, &rect, lpitem->fState & (MF_HILITE | MF_MOUSESELECT)); 2226 } 2227 return; 2228 } 2229 2230 UserSystemParametersInfo (SPI_GETFLATMENU, 0, &flat_menu, 0); 2231 bkgnd = (menuBar && flat_menu) ? COLOR_MENUBAR : COLOR_MENU; 2232 2233 /* Setup colors */ 2234 2235 if (lpitem->fState & MF_HILITE) 2236 { 2237 if(menuBar && !flat_menu) { 2238 IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_MENUTEXT)); 2239 IntGdiSetBkColor(hdc, IntGetSysColor(COLOR_MENU)); 2240 } else { 2241 if (lpitem->fState & MF_GRAYED) 2242 IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_GRAYTEXT)); 2243 else 2244 IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_HIGHLIGHTTEXT)); 2245 IntGdiSetBkColor(hdc, IntGetSysColor(COLOR_HIGHLIGHT)); 2246 } 2247 } 2248 else 2249 { 2250 if (lpitem->fState & MF_GRAYED) 2251 IntGdiSetTextColor( hdc, IntGetSysColor( COLOR_GRAYTEXT ) ); 2252 else 2253 IntGdiSetTextColor( hdc, IntGetSysColor( COLOR_MENUTEXT ) ); 2254 IntGdiSetBkColor( hdc, IntGetSysColor( bkgnd ) ); 2255 } 2256 2257 //TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->Rect)); 2258 //rect = lpitem->Rect; 2259 rect.left = lpitem->xItem; 2260 rect.top = lpitem->yItem; 2261 rect.right = lpitem->cxItem; // Do this for now...... 2262 rect.bottom = lpitem->cyItem; 2263 2264 MENU_AdjustMenuItemRect(Menu, &rect); 2265 2266 if (lpitem->fType & MF_OWNERDRAW) 2267 { 2268 /* 2269 ** Experimentation under Windows reveals that an owner-drawn 2270 ** menu is given the rectangle which includes the space it requested 2271 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark 2272 ** and a popup-menu arrow. This is the value of lpitem->rect. 2273 ** Windows will leave all drawing to the application except for 2274 ** the popup-menu arrow. Windows always draws that itself, after 2275 ** the menu owner has finished drawing. 2276 */ 2277 DRAWITEMSTRUCT dis; 2278 COLORREF old_bk, old_text; 2279 2280 dis.CtlType = ODT_MENU; 2281 dis.CtlID = 0; 2282 dis.itemID = lpitem->wID; 2283 dis.itemData = (DWORD)lpitem->dwItemData; 2284 dis.itemState = 0; 2285 if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED; 2286 if (lpitem->fState & MF_DEFAULT) dis.itemState |= ODS_DEFAULT; 2287 if (lpitem->fState & MF_DISABLED) dis.itemState |= ODS_DISABLED; 2288 if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED | ODS_DISABLED; 2289 if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED; 2290 if (!(Menu->fFlags & MNF_UNDERLINE)) dis.itemState |= ODS_NOACCEL; 2291 if (Menu->fFlags & MNF_INACTIVE) dis.itemState |= ODS_INACTIVE; 2292 dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */ 2293 dis.hwndItem = (HWND) UserHMGetHandle(Menu); 2294 dis.hDC = hdc; 2295 dis.rcItem = rect; 2296 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, " 2297 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", Wnd, 2298 dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem, 2299 dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right, 2300 dis.rcItem.bottom); 2301 TRACE("Ownerdraw: Width %d Height %d\n", dis.rcItem.right-dis.rcItem.left, dis.rcItem.bottom-dis.rcItem.top); 2302 old_bk = GreGetBkColor(hdc); 2303 old_text = GreGetTextColor(hdc); 2304 co_IntSendMessage(UserHMGetHandle(WndOwner), WM_DRAWITEM, 0, (LPARAM) &dis); 2305 IntGdiSetBkColor(hdc, old_bk); 2306 IntGdiSetTextColor(hdc, old_text); 2307 /* Draw the popup-menu arrow */ 2308 if (!menuBar && lpitem->spSubMenu) 2309 { 2310 RECT rectTemp; 2311 RtlCopyMemory(&rectTemp, &rect, sizeof(RECT)); 2312 rectTemp.left = rectTemp.right - UserGetSystemMetrics(SM_CXMENUCHECK); 2313 UITOOLS95_DrawFrameMenu(hdc, &rectTemp, DFCS_MENUARROW); 2314 } 2315 return; 2316 } 2317 2318 if (menuBar && (lpitem->fType & MF_SEPARATOR)) return; 2319 2320 if (lpitem->fState & MF_HILITE) 2321 { 2322 if (flat_menu) 2323 { 2324 RECTL_vInflateRect (&rect, -1, -1); 2325 FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_MENUHILIGHT)); 2326 RECTL_vInflateRect (&rect, 1, 1); 2327 FrameRect(hdc, &rect, IntGetSysColorBrush(COLOR_HIGHLIGHT)); 2328 } 2329 else 2330 { 2331 if (menuBar) 2332 { 2333 FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_MENU)); 2334 DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT); 2335 } 2336 else 2337 { 2338 FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_HIGHLIGHT)); 2339 } 2340 } 2341 } 2342 else 2343 FillRect( hdc, &rect, IntGetSysColorBrush(bkgnd) ); 2344 2345 IntGdiSetBkMode( hdc, TRANSPARENT ); 2346 2347 /* vertical separator */ 2348 if (!menuBar && (lpitem->fType & MF_MENUBARBREAK)) 2349 { 2350 HPEN oldPen; 2351 RECT rc = rect; 2352 2353 rc.left -= 3;//MENU_COL_SPACE / 2 + 1; == 3!! 2354 rc.top = 3; 2355 rc.bottom = Height - 3; 2356 if (flat_menu) 2357 { 2358 oldPen = NtGdiSelectPen( hdc, NtGdiGetStockObject(DC_PEN) ); 2359 IntSetDCPenColor(hdc, IntGetSysColor(COLOR_BTNSHADOW)); 2360 GreMoveTo( hdc, rc.left, rc.top, NULL ); 2361 NtGdiLineTo( hdc, rc.left, rc.bottom ); 2362 NtGdiSelectPen( hdc, oldPen ); 2363 } 2364 else 2365 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT); 2366 } 2367 2368 /* horizontal separator */ 2369 if (lpitem->fType & MF_SEPARATOR) 2370 { 2371 HPEN oldPen; 2372 RECT rc = rect; 2373 2374 rc.left++; 2375 rc.right--; 2376 rc.top = (rc.top + rc.bottom) / 2 - 1; 2377 if (flat_menu) 2378 { 2379 oldPen = NtGdiSelectPen( hdc, NtGdiGetStockObject(DC_PEN) ); 2380 IntSetDCPenColor( hdc, IntGetSysColor(COLOR_BTNSHADOW)); 2381 GreMoveTo( hdc, rc.left, rc.top, NULL ); 2382 NtGdiLineTo( hdc, rc.right, rc.top ); 2383 NtGdiSelectPen( hdc, oldPen ); 2384 } 2385 else 2386 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP); 2387 return; 2388 } 2389 #if 0 2390 /* helper lines for debugging */ 2391 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */ 2392 FrameRect(hdc, &rect, NtGdiGetStockObject(BLACK_BRUSH)); 2393 NtGdiSelectPen(hdc, NtGdiGetStockObject(DC_PEN)); 2394 IntSetDCPenColor(hdc, IntGetSysColor(COLOR_WINDOWFRAME)); 2395 GreMoveTo(hdc, rect.left, (rect.top + rect.bottom) / 2, NULL); 2396 NtGdiLineTo(hdc, rect.right, (rect.top + rect.bottom) / 2); 2397 #endif 2398 #if 0 // breaks mdi menu bar icons. 2399 if (lpitem->hbmp) { 2400 /* calculate the bitmap rectangle in coordinates relative 2401 * to the item rectangle */ 2402 if( menuBar) { 2403 if( lpitem->hbmp == HBMMENU_CALLBACK) 2404 bmprc.left = 3; 2405 else 2406 bmprc.left = lpitem->Xlpstr ? MenuCharSize.cx : 0; 2407 } 2408 else if ((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK) 2409 bmprc.left = 4; 2410 else if ((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP) 2411 bmprc.left = 2; 2412 else 2413 bmprc.left = 4 + UserGetSystemMetrics(SM_CXMENUCHECK); 2414 2415 bmprc.right = bmprc.left + lpitem->cxBmp; 2416 2417 if( menuBar && !(lpitem->hbmp == HBMMENU_CALLBACK)) 2418 bmprc.top = 0; 2419 else 2420 bmprc.top = (rect.bottom - rect.top - lpitem->cyBmp) / 2; 2421 2422 bmprc.bottom = bmprc.top + lpitem->cyBmp; 2423 } 2424 #endif 2425 if (!menuBar) 2426 { 2427 HBITMAP bm; 2428 INT y = rect.top + rect.bottom; 2429 RECT rc = rect; 2430 BOOL checked = FALSE; 2431 UINT check_bitmap_width = UserGetSystemMetrics( SM_CXMENUCHECK ); 2432 UINT check_bitmap_height = UserGetSystemMetrics( SM_CYMENUCHECK ); 2433 /* Draw the check mark 2434 * 2435 * FIXME: 2436 * Custom checkmark bitmaps are monochrome but not always 1bpp. 2437 */ 2438 if( !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK)) { 2439 bm = (lpitem->fState & MF_CHECKED) ? lpitem->hbmpChecked : 2440 lpitem->hbmpUnchecked; 2441 if (bm) /* we have a custom bitmap */ 2442 { 2443 HDC hdcMem = NtGdiCreateCompatibleDC( hdc ); 2444 2445 NtGdiSelectBitmap( hdcMem, bm ); 2446 NtGdiBitBlt( hdc, rc.left, (y - check_bitmap_height) / 2, 2447 check_bitmap_width, check_bitmap_height, 2448 hdcMem, 0, 0, SRCCOPY, 0,0); 2449 IntGdiDeleteDC( hdcMem, FALSE ); 2450 checked = TRUE; 2451 } 2452 else if (lpitem->fState & MF_CHECKED) /* standard bitmaps */ 2453 { 2454 RECT r; 2455 r = rect; 2456 r.right = r.left + check_bitmap_width; 2457 UITOOLS95_DrawFrameMenu(hdc, &r, 2458 (lpitem->fType & MFT_RADIOCHECK) ? 2459 DFCS_MENUBULLET : DFCS_MENUCHECK); 2460 checked = TRUE; 2461 } 2462 } 2463 if ( lpitem->hbmp )//&& !( checked && ((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP))) 2464 { 2465 RECT bmpRect = rect; 2466 if (!((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP) && !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK)) 2467 bmpRect.left += check_bitmap_width + 2; 2468 if (!(checked && ((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP))) 2469 { 2470 bmpRect.right = bmpRect.left + lpitem->cxBmp; 2471 MENU_DrawBitmapItem(hdc, lpitem, &bmpRect, Menu, WndOwner, odaction, menuBar); 2472 } 2473 } 2474 /* Draw the popup-menu arrow */ 2475 if (lpitem->spSubMenu) 2476 { 2477 RECT rectTemp; 2478 RtlCopyMemory(&rectTemp, &rect, sizeof(RECT)); 2479 rectTemp.left = rectTemp.right - check_bitmap_width; 2480 UITOOLS95_DrawFrameMenu(hdc, &rectTemp, DFCS_MENUARROW); 2481 } 2482 rect.left += 4; 2483 if( !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK)) 2484 rect.left += check_bitmap_width; 2485 rect.right -= arrow_bitmap_width; 2486 } 2487 else if( lpitem->hbmp) 2488 { /* Draw the bitmap */ 2489 MENU_DrawBitmapItem(hdc, lpitem, &rect/*bmprc*/, Menu, WndOwner, odaction, menuBar); 2490 } 2491 2492 /* process text if present */ 2493 if (lpitem->Xlpstr) 2494 { 2495 int i = 0; 2496 HFONT hfontOld = 0; 2497 2498 UINT uFormat = menuBar ? 2499 DT_CENTER | DT_VCENTER | DT_SINGLELINE : 2500 DT_LEFT | DT_VCENTER | DT_SINGLELINE; 2501 2502 if (((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP)) 2503 rect.left += max(0, (int)(Menu->cxTextAlign - UserGetSystemMetrics(SM_CXMENUCHECK))); 2504 else 2505 rect.left += Menu->cxTextAlign; 2506 2507 if ( lpitem->fState & MFS_DEFAULT ) 2508 { 2509 hfontOld = NtGdiSelectFont(hdc, ghMenuFontBold); 2510 } 2511 2512 if (menuBar) { 2513 if( lpitem->hbmp) 2514 rect.left += lpitem->cxBmp; 2515 if( !(lpitem->hbmp == HBMMENU_CALLBACK)) 2516 rect.left += MenuCharSize.cx; 2517 rect.right -= MenuCharSize.cx; 2518 } 2519 2520 Text = lpitem->Xlpstr; 2521 if(Text) 2522 { 2523 for (i = 0; Text[i]; i++) 2524 if (Text[i] == L'\t' || Text[i] == L'\b') 2525 break; 2526 } 2527 2528 if (menuBar && 2529 !flat_menu && 2530 (lpitem->fState & (MF_HILITE | MF_GRAYED)) == MF_HILITE) 2531 { 2532 RECTL_vOffsetRect(&rect, +1, +1); 2533 } 2534 2535 if (!menuBar) 2536 --rect.bottom; 2537 2538 if(lpitem->fState & MF_GRAYED) 2539 { 2540 if (!(lpitem->fState & MF_HILITE) ) 2541 { 2542 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom; 2543 IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_BTNHIGHLIGHT)); 2544 DrawTextW( hdc, Text, i, &rect, uFormat ); 2545 --rect.left; --rect.top; --rect.right; --rect.bottom; 2546 } 2547 IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_BTNSHADOW)); 2548 } 2549 DrawTextW( hdc, Text, i, &rect, uFormat); 2550 2551 /* paint the shortcut text */ 2552 if (!menuBar && L'\0' != Text[i]) /* There's a tab or flush-right char */ 2553 { 2554 if (L'\t' == Text[i]) 2555 { 2556 rect.left = lpitem->dxTab; 2557 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE; 2558 } 2559 else 2560 { 2561 rect.right = lpitem->dxTab; 2562 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE; 2563 } 2564 2565 if (lpitem->fState & MF_GRAYED) 2566 { 2567 if (!(lpitem->fState & MF_HILITE) ) 2568 { 2569 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom; 2570 IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_BTNHIGHLIGHT)); 2571 DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat); 2572 --rect.left; --rect.top; --rect.right; --rect.bottom; 2573 } 2574 IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_BTNSHADOW)); 2575 } 2576 DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat ); 2577 } 2578 2579 if (!menuBar) 2580 ++rect.bottom; 2581 2582 if (menuBar && 2583 !flat_menu && 2584 (lpitem->fState & (MF_HILITE | MF_GRAYED)) == MF_HILITE) 2585 { 2586 RECTL_vOffsetRect(&rect, -1, -1); 2587 } 2588 2589 if (hfontOld) 2590 { 2591 NtGdiSelectFont (hdc, hfontOld); 2592 } 2593 } 2594 } 2595 2596 /*********************************************************************** 2597 * MenuDrawPopupMenu 2598 * 2599 * Paint a popup menu. 2600 */ 2601 static void FASTCALL MENU_DrawPopupMenu(PWND wnd, HDC hdc, PMENU menu ) 2602 { 2603 HBRUSH hPrevBrush = 0, brush = IntGetSysColorBrush(COLOR_MENU); 2604 RECT rect; 2605 2606 TRACE("DPM wnd=%p dc=%p menu=%p\n", wnd, hdc, menu); 2607 2608 IntGetClientRect( wnd, &rect ); 2609 2610 if (menu && menu->hbrBack) brush = menu->hbrBack; 2611 if((hPrevBrush = NtGdiSelectBrush( hdc, brush )) 2612 && (NtGdiSelectFont( hdc, ghMenuFont))) 2613 { 2614 HPEN hPrevPen; 2615 2616 /* FIXME: Maybe we don't have to fill the background manually */ 2617 FillRect(hdc, &rect, brush); 2618 2619 hPrevPen = NtGdiSelectPen( hdc, NtGdiGetStockObject( NULL_PEN ) ); 2620 if ( hPrevPen ) 2621 { 2622 TRACE("hmenu %p Style %08x\n", UserHMGetHandle(menu), (menu->fFlags & MNS_STYLE_MASK)); 2623 /* draw menu items */ 2624 if (menu && menu->cItems) 2625 { 2626 ITEM *item; 2627 UINT u; 2628 2629 item = menu->rgItems; 2630 for( u = menu->cItems; u > 0; u--, item++) 2631 { 2632 MENU_DrawMenuItem(wnd, menu, menu->spwndNotify, hdc, item, 2633 menu->cyMenu, FALSE, ODA_DRAWENTIRE); 2634 } 2635 /* draw scroll arrows */ 2636 if (menu->dwArrowsOn) 2637 { 2638 MENU_DrawScrollArrows(menu, hdc); 2639 } 2640 } 2641 } 2642 else 2643 { 2644 NtGdiSelectBrush( hdc, hPrevBrush ); 2645 } 2646 } 2647 } 2648 2649 /********************************************************************** 2650 * MENU_IsMenuActive 2651 */ 2652 PWND MENU_IsMenuActive(VOID) 2653 { 2654 return ValidateHwndNoErr(top_popup); 2655 } 2656 2657 /********************************************************************** 2658 * MENU_EndMenu 2659 * 2660 * Calls EndMenu() if the hwnd parameter belongs to the menu owner 2661 * 2662 * Does the (menu stuff) of the default window handling of WM_CANCELMODE 2663 */ 2664 void MENU_EndMenu( PWND pwnd ) 2665 { 2666 PMENU menu = NULL; 2667 menu = UserGetMenuObject(top_popup_hmenu); 2668 if ( menu && ( UserHMGetHandle(pwnd) == menu->hWnd || pwnd == menu->spwndNotify ) ) 2669 { 2670 if (fInsideMenuLoop && top_popup) 2671 { 2672 fInsideMenuLoop = FALSE; 2673 2674 if (fInEndMenu) 2675 { 2676 ERR("Already in End loop\n"); 2677 return; 2678 } 2679 2680 fInEndMenu = TRUE; 2681 UserPostMessage( top_popup, WM_CANCELMODE, 0, 0); 2682 } 2683 } 2684 } 2685 2686 DWORD WINAPI 2687 IntDrawMenuBarTemp(PWND pWnd, HDC hDC, LPRECT Rect, PMENU pMenu, HFONT Font) 2688 { 2689 UINT i; 2690 HFONT FontOld = NULL; 2691 BOOL flat_menu = FALSE; 2692 2693 UserSystemParametersInfo(SPI_GETFLATMENU, 0, &flat_menu, 0); 2694 2695 if (!pMenu) 2696 { 2697 pMenu = UserGetMenuObject(UlongToHandle(pWnd->IDMenu)); 2698 } 2699 2700 if (!Font) 2701 { 2702 Font = ghMenuFont; 2703 } 2704 2705 if (Rect == NULL || !pMenu) 2706 { 2707 return UserGetSystemMetrics(SM_CYMENU); 2708 } 2709 2710 TRACE("(%x, %x, %p, %x, %x)\n", pWnd, hDC, Rect, pMenu, Font); 2711 2712 FontOld = NtGdiSelectFont(hDC, Font); 2713 2714 if (pMenu->cyMenu == 0) 2715 { 2716 MENU_MenuBarCalcSize(hDC, Rect, pMenu, pWnd); 2717 } 2718 2719 Rect->bottom = Rect->top + pMenu->cyMenu; 2720 2721 FillRect(hDC, Rect, IntGetSysColorBrush(flat_menu ? COLOR_MENUBAR : COLOR_MENU)); 2722 2723 NtGdiSelectPen(hDC, NtGdiGetStockObject(DC_PEN)); 2724 IntSetDCPenColor(hDC, IntGetSysColor(COLOR_3DFACE)); 2725 GreMoveTo(hDC, Rect->left, Rect->bottom - 1, NULL); 2726 NtGdiLineTo(hDC, Rect->right, Rect->bottom - 1); 2727 2728 if (pMenu->cItems == 0) 2729 { 2730 NtGdiSelectFont(hDC, FontOld); 2731 return UserGetSystemMetrics(SM_CYMENU); 2732 } 2733 2734 for (i = 0; i < pMenu->cItems; i++) 2735 { 2736 MENU_DrawMenuItem(pWnd, pMenu, pWnd, hDC, &pMenu->rgItems[i], pMenu->cyMenu, TRUE, ODA_DRAWENTIRE); 2737 } 2738 2739 NtGdiSelectFont(hDC, FontOld); 2740 2741 return pMenu->cyMenu; 2742 } 2743 2744 UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, PWND pWnd, BOOL suppress_draw ) 2745 { 2746 HFONT hfontOld = 0; 2747 PMENU lppop = UserGetMenuObject(UlongToHandle(pWnd->IDMenu)); 2748 2749 if (lppop == NULL) 2750 { 2751 // No menu. Do not reserve any space 2752 return 0; 2753 } 2754 2755 if (lprect == NULL) 2756 { 2757 return UserGetSystemMetrics(SM_CYMENU); 2758 } 2759 2760 if (suppress_draw) 2761 { 2762 hfontOld = NtGdiSelectFont(hDC, ghMenuFont); 2763 2764 MENU_MenuBarCalcSize(hDC, lprect, lppop, pWnd); 2765 2766 lprect->bottom = lprect->top + lppop->cyMenu; 2767 2768 if (hfontOld) NtGdiSelectFont( hDC, hfontOld); 2769 2770 return lppop->cyMenu; 2771 } 2772 else 2773 { 2774 return IntDrawMenuBarTemp(pWnd, hDC, lprect, lppop, NULL); 2775 } 2776 } 2777 2778 /*********************************************************************** 2779 * MENU_InitPopup 2780 * 2781 * Popup menu initialization before WM_ENTERMENULOOP. 2782 */ 2783 static BOOL MENU_InitPopup( PWND pWndOwner, PMENU menu, UINT flags ) 2784 { 2785 PWND pWndCreated; 2786 PPOPUPMENU pPopupMenu; 2787 CREATESTRUCTW Cs; 2788 LARGE_STRING WindowName; 2789 UNICODE_STRING ClassName; 2790 DWORD ex_style = WS_EX_PALETTEWINDOW | WS_EX_DLGMODALFRAME; 2791 2792 TRACE("owner=%p hmenu=%p\n", pWndOwner, menu); 2793 2794 menu->spwndNotify = pWndOwner; 2795 2796 if (flags & TPM_LAYOUTRTL || pWndOwner->ExStyle & WS_EX_LAYOUTRTL) 2797 ex_style |= WS_EX_LAYOUTRTL; 2798 2799 ClassName.Buffer = WC_MENU; 2800 ClassName.Length = 0; 2801 2802 RtlZeroMemory(&WindowName, sizeof(WindowName)); 2803 RtlZeroMemory(&Cs, sizeof(Cs)); 2804 Cs.style = WS_POPUP | WS_CLIPSIBLINGS | WS_BORDER; 2805 Cs.dwExStyle = ex_style; 2806 Cs.hInstance = hModClient; // hModuleWin; // Server side winproc! 2807 Cs.lpszName = (LPCWSTR) &WindowName; 2808 Cs.lpszClass = (LPCWSTR) &ClassName; 2809 Cs.lpCreateParams = UserHMGetHandle(menu); 2810 Cs.hwndParent = UserHMGetHandle(pWndOwner); 2811 2812 /* NOTE: In Windows, top menu popup is not owned. */ 2813 pWndCreated = co_UserCreateWindowEx( &Cs, &ClassName, &WindowName, NULL, WINVER ); 2814 2815 if( !pWndCreated ) return FALSE; 2816 2817 // 2818 // Setup pop up menu structure. 2819 // 2820 menu->hWnd = UserHMGetHandle(pWndCreated); 2821 2822 pPopupMenu = ((PMENUWND)pWndCreated)->ppopupmenu; 2823 2824 pPopupMenu->spwndActivePopup = pWndCreated; // top_popup = MenuInfo.Wnd or menu->hWnd 2825 pPopupMenu->spwndNotify = pWndOwner; // Same as MenuInfo.spwndNotify(which could be wrong) or menu->hwndOwner 2826 //pPopupMenu->spmenu = menu; Should be set up already from WM_CREATE! 2827 2828 pPopupMenu->fIsTrackPopup = !!(flags & TPM_POPUPMENU); 2829 pPopupMenu->fIsSysMenu = !!(flags & TPM_SYSTEM_MENU); 2830 pPopupMenu->fNoNotify = !!(flags & TPM_NONOTIFY); 2831 pPopupMenu->fRightButton = !!(flags & TPM_RIGHTBUTTON); 2832 pPopupMenu->fSynchronous = !!(flags & TPM_RETURNCMD); 2833 2834 if (pPopupMenu->fRightButton) 2835 pPopupMenu->fFirstClick = !!(UserGetKeyState(VK_RBUTTON) & 0x8000); 2836 else 2837 pPopupMenu->fFirstClick = !!(UserGetKeyState(VK_LBUTTON) & 0x8000); 2838 2839 if (gpsi->aiSysMet[SM_MENUDROPALIGNMENT] || 2840 menu->fFlags & MNF_RTOL) 2841 { 2842 pPopupMenu->fDroppedLeft = TRUE; 2843 } 2844 return TRUE; 2845 } 2846 2847 2848 #define SHOW_DEBUGRECT 0 2849 2850 #if SHOW_DEBUGRECT 2851 static void DebugRect(const RECT* rectl, COLORREF color) 2852 { 2853 HBRUSH brush; 2854 RECT rr; 2855 HDC hdc; 2856 2857 if (!rectl) 2858 return; 2859 2860 hdc = UserGetDCEx(NULL, 0, DCX_USESTYLE); 2861 2862 brush = IntGdiCreateSolidBrush(color); 2863 2864 rr = *rectl; 2865 RECTL_vInflateRect(&rr, 1, 1); 2866 FrameRect(hdc, rectl, brush); 2867 FrameRect(hdc, &rr, brush); 2868 2869 NtGdiDeleteObjectApp(brush); 2870 UserReleaseDC(NULL, hdc, TRUE); 2871 } 2872 2873 static void DebugPoint(INT x, INT y, COLORREF color) 2874 { 2875 RECT r1 = {x-10, y, x+10, y}; 2876 RECT r2 = {x, y-10, x, y+10}; 2877 DebugRect(&r1, color); 2878 DebugRect(&r2, color); 2879 } 2880 #endif 2881 2882 static BOOL RECTL_Intersect(const RECT* pRect, INT x, INT y, UINT width, UINT height) 2883 { 2884 RECT other = {x, y, x + width, y + height}; 2885 RECT dum; 2886 2887 return RECTL_bIntersectRect(&dum, pRect, &other); 2888 } 2889 2890 static BOOL MENU_MoveRect(UINT flags, INT* x, INT* y, INT width, INT height, const RECT* pExclude, PMONITOR monitor) 2891 { 2892 /* Figure out if we should move vertical or horizontal */ 2893 if (flags & TPM_VERTICAL) 2894 { 2895 /* Move in the vertical direction: TPM_BOTTOMALIGN means drop it above, otherways drop it below */ 2896 if (flags & TPM_BOTTOMALIGN) 2897 { 2898 if (pExclude->top - height >= monitor->rcMonitor.top) 2899 { 2900 *y = pExclude->top - height; 2901 return TRUE; 2902 } 2903 } 2904 else 2905 { 2906 if (pExclude->bottom + height < monitor->rcMonitor.bottom) 2907 { 2908 *y = pExclude->bottom; 2909 return TRUE; 2910 } 2911 } 2912 } 2913 else 2914 { 2915 /* Move in the horizontal direction: TPM_RIGHTALIGN means drop it to the left, otherways go right */ 2916 if (flags & TPM_RIGHTALIGN) 2917 { 2918 if (pExclude->left - width >= monitor->rcMonitor.left) 2919 { 2920 *x = pExclude->left - width; 2921 return TRUE; 2922 } 2923 } 2924 else 2925 { 2926 if (pExclude->right + width < monitor->rcMonitor.right) 2927 { 2928 *x = pExclude->right; 2929 return TRUE; 2930 } 2931 } 2932 } 2933 return FALSE; 2934 } 2935 2936 /*********************************************************************** 2937 * MenuShowPopup 2938 * 2939 * Display a popup menu. 2940 */ 2941 static BOOL FASTCALL MENU_ShowPopup(PWND pwndOwner, PMENU menu, UINT id, UINT flags, 2942 INT x, INT y, const RECT* pExclude) 2943 { 2944 INT width, height; 2945 POINT ptx; 2946 PMONITOR monitor; 2947 PWND pWnd; 2948 USER_REFERENCE_ENTRY Ref; 2949 BOOL bIsPopup = (flags & TPM_POPUPMENU) != 0; 2950 2951 TRACE("owner=%p menu=%p id=0x%04x x=0x%04x y=0x%04x\n", 2952 pwndOwner, menu, id, x, y); 2953 2954 if (menu->iItem != NO_SELECTED_ITEM) 2955 { 2956 menu->rgItems[menu->iItem].fState &= ~(MF_HILITE|MF_MOUSESELECT); 2957 menu->iItem = NO_SELECTED_ITEM; 2958 } 2959 2960 #if SHOW_DEBUGRECT 2961 if (pExclude) 2962 DebugRect(pExclude, RGB(255, 0, 0)); 2963 #endif 2964 2965 menu->dwArrowsOn = 0; 2966 MENU_PopupMenuCalcSize(menu, pwndOwner); 2967 2968 /* adjust popup menu pos so that it fits within the desktop */ 2969 2970 width = menu->cxMenu + UserGetSystemMetrics(SM_CXDLGFRAME) * 2; 2971 height = menu->cyMenu + UserGetSystemMetrics(SM_CYDLGFRAME) * 2; 2972 2973 if (flags & TPM_LAYOUTRTL) 2974 flags ^= TPM_RIGHTALIGN; 2975 2976 if (flags & TPM_RIGHTALIGN) 2977 x -= width; 2978 if (flags & TPM_CENTERALIGN) 2979 x -= width / 2; 2980 2981 if (flags & TPM_BOTTOMALIGN) 2982 y -= height; 2983 if (flags & TPM_VCENTERALIGN) 2984 y -= height / 2; 2985 2986 /* FIXME: should use item rect */ 2987 ptx.x = x; 2988 ptx.y = y; 2989 #if SHOW_DEBUGRECT 2990 DebugPoint(x, y, RGB(0, 0, 255)); 2991 #endif 2992 monitor = UserMonitorFromPoint( ptx, MONITOR_DEFAULTTONEAREST ); 2993 2994 /* We are off the right side of the screen */ 2995 if (x + width > monitor->rcMonitor.right) 2996 { 2997 if ((x - width) < monitor->rcMonitor.left || x >= monitor->rcMonitor.right) 2998 x = monitor->rcMonitor.right - width; 2999 else 3000 x -= width; 3001 } 3002 3003 /* We are off the left side of the screen */ 3004 if (x < monitor->rcMonitor.left) 3005 { 3006 /* Re-orient the menu around the x-axis */ 3007 x += width; 3008 3009 if (x < monitor->rcMonitor.left || x >= monitor->rcMonitor.right || bIsPopup) 3010 x = monitor->rcMonitor.left; 3011 } 3012 3013 /* Same here, but then the top */ 3014 if (y < monitor->rcMonitor.top) 3015 { 3016 y += height; 3017 3018 if (y < monitor->rcMonitor.top || y >= monitor->rcMonitor.bottom || bIsPopup) 3019 y = monitor->rcMonitor.top; 3020 } 3021 3022 /* And the bottom */ 3023 if (y + height > monitor->rcMonitor.bottom) 3024 { 3025 if ((y - height) < monitor->rcMonitor.top || y >= monitor->rcMonitor.bottom) 3026 y = monitor->rcMonitor.bottom - height; 3027 else 3028 y -= height; 3029 } 3030 3031 if (pExclude) 3032 { 3033 RECT Cleaned; 3034 3035 if (RECTL_bIntersectRect(&Cleaned, pExclude, &monitor->rcMonitor) && 3036 RECTL_Intersect(&Cleaned, x, y, width, height)) 3037 { 3038 UINT flag_mods[] = { 3039 0, /* First try the 'normal' way */ 3040 TPM_BOTTOMALIGN | TPM_RIGHTALIGN, /* Then try the opposite side */ 3041 TPM_VERTICAL, /* Then swap horizontal / vertical */ 3042 TPM_BOTTOMALIGN | TPM_RIGHTALIGN | TPM_VERTICAL, /* Then the other side again (still swapped hor/ver) */ 3043 }; 3044 3045 UINT n; 3046 for (n = 0; n < RTL_NUMBER_OF(flag_mods); ++n) 3047 { 3048 INT tx = x; 3049 INT ty = y; 3050 3051 /* Try to move a bit around */ 3052 if (MENU_MoveRect(flags ^ flag_mods[n], &tx, &ty, width, height, &Cleaned, monitor) && 3053 !RECTL_Intersect(&Cleaned, tx, ty, width, height)) 3054 { 3055 x = tx; 3056 y = ty; 3057 break; 3058 } 3059 } 3060 /* If none worked, we go with the original x/y */ 3061 } 3062 } 3063 3064 #if SHOW_DEBUGRECT 3065 { 3066 RECT rr = {x, y, x + width, y + height}; 3067 DebugRect(&rr, RGB(0, 255, 0)); 3068 } 3069 #endif 3070 3071 pWnd = ValidateHwndNoErr( menu->hWnd ); 3072 3073 if (!pWnd) 3074 { 3075 ERR("menu->hWnd bad hwnd %p\n",menu->hWnd); 3076 return FALSE; 3077 } 3078 3079 if (!top_popup) { 3080 top_popup = menu->hWnd; 3081 top_popup_hmenu = UserHMGetHandle(menu); 3082 } 3083 3084 /* Display the window */ 3085 UserRefObjectCo(pWnd, &Ref); 3086 co_WinPosSetWindowPos( pWnd, HWND_TOPMOST, x, y, width, height, SWP_SHOWWINDOW | SWP_NOACTIVATE); 3087 3088 co_IntUpdateWindows(pWnd, RDW_ALLCHILDREN, FALSE); 3089 3090 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART, pWnd, OBJID_CLIENT, CHILDID_SELF, 0); 3091 UserDerefObjectCo(pWnd); 3092 3093 return TRUE; 3094 } 3095 3096 /*********************************************************************** 3097 * MENU_EnsureMenuItemVisible 3098 */ 3099 void MENU_EnsureMenuItemVisible(PMENU lppop, UINT wIndex, HDC hdc) 3100 { 3101 USER_REFERENCE_ENTRY Ref; 3102 if (lppop->dwArrowsOn) 3103 { 3104 ITEM *item = &lppop->rgItems[wIndex]; 3105 UINT nMaxHeight = MENU_GetMaxPopupHeight(lppop); 3106 UINT nOldPos = lppop->iTop; 3107 RECT rc; 3108 UINT arrow_bitmap_height; 3109 PWND pWnd = ValidateHwndNoErr(lppop->hWnd); 3110 3111 IntGetClientRect(pWnd, &rc); 3112 3113 arrow_bitmap_height = gpsi->oembmi[OBI_DNARROW].cy; 3114 3115 rc.top += arrow_bitmap_height; 3116 rc.bottom -= arrow_bitmap_height; 3117 3118 nMaxHeight -= UserGetSystemMetrics(SM_CYBORDER) + 2 * arrow_bitmap_height; 3119 UserRefObjectCo(pWnd, &Ref); 3120 if (item->cyItem > lppop->iTop + nMaxHeight) 3121 { 3122 lppop->iTop = item->cyItem - nMaxHeight; 3123 IntScrollWindow(pWnd, 0, nOldPos - lppop->iTop, &rc, &rc); 3124 MENU_DrawScrollArrows(lppop, hdc); 3125 //ERR("Scroll Down iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight); 3126 } 3127 else if (item->yItem < lppop->iTop) 3128 { 3129 lppop->iTop = item->yItem; 3130 IntScrollWindow(pWnd, 0, nOldPos - lppop->iTop, &rc, &rc); 3131 MENU_DrawScrollArrows(lppop, hdc); 3132 //ERR("Scroll Up iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight); 3133 } 3134 UserDerefObjectCo(pWnd); 3135 } 3136 } 3137 3138 /*********************************************************************** 3139 * MenuSelectItem 3140 */ 3141 static void FASTCALL MENU_SelectItem(PWND pwndOwner, PMENU menu, UINT wIndex, 3142 BOOL sendMenuSelect, PMENU topmenu) 3143 { 3144 HDC hdc; 3145 PWND pWnd; 3146 3147 TRACE("M_SI: owner=%p menu=%p index=0x%04x select=0x%04x\n", pwndOwner, menu, wIndex, sendMenuSelect); 3148 3149 if (!menu || !menu->cItems) return; 3150 3151 pWnd = ValidateHwndNoErr(menu->hWnd); 3152 3153 if (!pWnd) return; 3154 3155 if (menu->iItem == wIndex) return; 3156 3157 if (menu->fFlags & MNF_POPUP) 3158 hdc = UserGetDCEx(pWnd, 0, DCX_USESTYLE); 3159 else 3160 hdc = UserGetDCEx(pWnd, 0, DCX_CACHE | DCX_WINDOW); 3161 3162 if (!top_popup) { 3163 top_popup = menu->hWnd; //pPopupMenu->spwndActivePopup or 3164 //pPopupMenu->fIsTrackPopup set pPopupMenu->spwndPopupMenu; 3165 top_popup_hmenu = UserHMGetHandle(menu); //pPopupMenu->spmenu 3166 } 3167 3168 NtGdiSelectFont( hdc, ghMenuFont ); 3169 3170 /* Clear previous highlighted item */ 3171 if (menu->iItem != NO_SELECTED_ITEM) 3172 { 3173 menu->rgItems[menu->iItem].fState &= ~(MF_HILITE|MF_MOUSESELECT); 3174 MENU_DrawMenuItem(pWnd, menu, pwndOwner, hdc, &menu->rgItems[menu->iItem], 3175 menu->cyMenu, !(menu->fFlags & MNF_POPUP), 3176 ODA_SELECT); 3177 } 3178 3179 /* Highlight new item (if any) */ 3180 menu->iItem = wIndex; 3181 if (menu->iItem != NO_SELECTED_ITEM) 3182 { 3183 if (!(menu->rgItems[wIndex].fType & MF_SEPARATOR)) 3184 { 3185 menu->rgItems[wIndex].fState |= MF_HILITE; 3186 MENU_EnsureMenuItemVisible(menu, wIndex, hdc); 3187 MENU_DrawMenuItem(pWnd, menu, pwndOwner, hdc, 3188 &menu->rgItems[wIndex], menu->cyMenu, !(menu->fFlags & MNF_POPUP), ODA_SELECT); 3189 } 3190 if (sendMenuSelect) 3191 { 3192 ITEM *ip = &menu->rgItems[menu->iItem]; 3193 WPARAM wParam = MAKEWPARAM( ip->spSubMenu ? wIndex : ip->wID, 3194 ip->fType | ip->fState | 3195 (ip->spSubMenu ? MF_POPUP : 0) | 3196 (menu->fFlags & MNF_SYSMENU ? MF_SYSMENU : 0 ) ); 3197 3198 co_IntSendMessage(UserHMGetHandle(pwndOwner), WM_MENUSELECT, wParam, (LPARAM) UserHMGetHandle(menu)); 3199 } 3200 } 3201 else if (sendMenuSelect) 3202 { 3203 if (topmenu) 3204 { 3205 int pos; 3206 pos = MENU_FindSubMenu(&topmenu, menu); 3207 if (pos != NO_SELECTED_ITEM) 3208 { 3209 ITEM *ip = &topmenu->rgItems[pos]; 3210 WPARAM wParam = MAKEWPARAM( Pos, ip->fType | ip->fState | 3211 (ip->spSubMenu ? MF_POPUP : 0) | 3212 (topmenu->fFlags & MNF_SYSMENU ? MF_SYSMENU : 0 ) ); 3213 3214 co_IntSendMessage(UserHMGetHandle(pwndOwner), WM_MENUSELECT, wParam, (LPARAM) UserHMGetHandle(topmenu)); 3215 } 3216 } 3217 } 3218 UserReleaseDC(pWnd, hdc, FALSE); 3219 } 3220 3221 /*********************************************************************** 3222 * MenuMoveSelection 3223 * 3224 * Moves currently selected item according to the Offset parameter. 3225 * If there is no selection then it should select the last item if 3226 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT. 3227 */ 3228 static void FASTCALL MENU_MoveSelection(PWND pwndOwner, PMENU menu, INT offset) 3229 { 3230 INT i; 3231 3232 TRACE("pwnd=%x menu=%x off=0x%04x\n", pwndOwner, menu, offset); 3233 3234 if ((!menu) || (!menu->rgItems)) return; 3235 3236 if ( menu->iItem != NO_SELECTED_ITEM ) 3237 { 3238 if ( menu->cItems == 1 ) 3239 return; 3240 else 3241 for (i = menu->iItem + offset ; i >= 0 && i < menu->cItems 3242 ; i += offset) 3243 if (!(menu->rgItems[i].fType & MF_SEPARATOR)) 3244 { 3245 MENU_SelectItem( pwndOwner, menu, i, TRUE, 0 ); 3246 return; 3247 } 3248 } 3249 3250 for ( i = (offset > 0) ? 0 : menu->cItems - 1; 3251 i >= 0 && i < menu->cItems ; i += offset) 3252 if (!(menu->rgItems[i].fType & MF_SEPARATOR)) 3253 { 3254 MENU_SelectItem( pwndOwner, menu, i, TRUE, 0 ); 3255 return; 3256 } 3257 } 3258 3259 /*********************************************************************** 3260 * MenuHideSubPopups 3261 * 3262 * Hide the sub-popup menus of this menu. 3263 */ 3264 static void FASTCALL MENU_HideSubPopups(PWND pWndOwner, PMENU Menu, 3265 BOOL SendMenuSelect, UINT wFlags) 3266 { 3267 TRACE("owner=%x menu=%x 0x%04x\n", pWndOwner, Menu, SendMenuSelect); 3268 3269 if ( Menu && top_popup ) 3270 { 3271 PITEM Item; 3272 3273 if (Menu->iItem != NO_SELECTED_ITEM) 3274 { 3275 Item = &Menu->rgItems[Menu->iItem]; 3276 if (!(Item->spSubMenu) || 3277 !(Item->fState & MF_MOUSESELECT)) return; 3278 Item->fState &= ~MF_MOUSESELECT; 3279 } 3280 else 3281 return; 3282 3283 if (Item->spSubMenu) 3284 { 3285 PWND pWnd; 3286 if (!VerifyMenu(Item->spSubMenu)) return; 3287 pWnd = ValidateHwndNoErr(Item->spSubMenu->hWnd); 3288 MENU_HideSubPopups(pWndOwner, Item->spSubMenu, FALSE, wFlags); 3289 MENU_SelectItem(pWndOwner, Item->spSubMenu, NO_SELECTED_ITEM, SendMenuSelect, NULL); 3290 TRACE("M_HSP top p hm %p pWndOwner IDMenu %p\n",top_popup_hmenu,pWndOwner->IDMenu); 3291 co_UserDestroyWindow(pWnd); 3292 3293 /* Native returns handle to destroyed window */ 3294 if (!(wFlags & TPM_NONOTIFY)) 3295 { 3296 co_IntSendMessage( UserHMGetHandle(pWndOwner), WM_UNINITMENUPOPUP, (WPARAM)UserHMGetHandle(Item->spSubMenu), 3297 MAKELPARAM(0, IS_SYSTEM_MENU(Item->spSubMenu)) ); 3298 } 3299 //// 3300 // Call WM_UNINITMENUPOPUP FIRST before destroy!! 3301 // Fixes todo_wine User32 test menu.c line 2239 GetMenuBarInfo callback.... 3302 // 3303 Item->spSubMenu->hWnd = NULL; 3304 //// 3305 } 3306 } 3307 } 3308 3309 /*********************************************************************** 3310 * MenuShowSubPopup 3311 * 3312 * Display the sub-menu of the selected item of this menu. 3313 * Return the handle of the submenu, or menu if no submenu to display. 3314 */ 3315 static PMENU FASTCALL MENU_ShowSubPopup(PWND WndOwner, PMENU Menu, BOOL SelectFirst, UINT Flags) 3316 { 3317 RECT Rect, ParentRect; 3318 ITEM *Item; 3319 HDC Dc; 3320 PWND pWnd; 3321 3322 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner, Menu, SelectFirst); 3323 3324 if (!Menu) return Menu; 3325 3326 if (Menu->iItem == NO_SELECTED_ITEM) return Menu; 3327 3328 Item = &Menu->rgItems[Menu->iItem]; 3329 if (!(Item->spSubMenu) || (Item->fState & (MF_GRAYED | MF_DISABLED))) 3330 return Menu; 3331 3332 /* message must be sent before using item, 3333 because nearly everything may be changed by the application ! */ 3334 3335 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */ 3336 if (!(Flags & TPM_NONOTIFY)) 3337 { 3338 co_IntSendMessage(UserHMGetHandle(WndOwner), WM_INITMENUPOPUP, 3339 (WPARAM) UserHMGetHandle(Item->spSubMenu), 3340 MAKELPARAM(Menu->iItem, IS_SYSTEM_MENU(Menu))); 3341 } 3342 3343 Item = &Menu->rgItems[Menu->iItem]; 3344 //Rect = ItemInfo.Rect; 3345 Rect.left = Item->xItem; 3346 Rect.top = Item->yItem; 3347 Rect.right = Item->cxItem; // Do this for now...... 3348 Rect.bottom = Item->cyItem; 3349 3350 pWnd = ValidateHwndNoErr(Menu->hWnd); 3351 3352 /* Grab the rect of our (entire) parent menu, so we can try to not overlap it */ 3353 if (Menu->fFlags & MNF_POPUP) 3354 { 3355 if (!IntGetWindowRect(pWnd, &ParentRect)) 3356 { 3357 ERR("No pWnd\n"); 3358 ParentRect = Rect; 3359 } 3360 3361 /* Ensure we can slightly overlap our parent */ 3362 RECTL_vInflateRect(&ParentRect, -UserGetSystemMetrics(SM_CXEDGE) * 2, 0); 3363 } 3364 else 3365 { 3366 /* Inside the menu bar, we do not want to grab the entire window... */ 3367 ParentRect = Rect; 3368 if (pWnd) 3369 RECTL_vOffsetRect(&ParentRect, pWnd->rcWindow.left, pWnd->rcWindow.top); 3370 } 3371 3372 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */ 3373 if (!(Item->fState & MF_HILITE)) 3374 { 3375 if (Menu->fFlags & MNF_POPUP) Dc = UserGetDCEx(pWnd, NULL, DCX_USESTYLE); 3376 else Dc = UserGetDCEx(pWnd, 0, DCX_CACHE | DCX_WINDOW); 3377 3378 NtGdiSelectFont(Dc, ghMenuFont); 3379 3380 Item->fState |= MF_HILITE; 3381 MENU_DrawMenuItem(pWnd, Menu, WndOwner, Dc, Item, Menu->cyMenu, 3382 !(Menu->fFlags & MNF_POPUP), ODA_DRAWENTIRE); 3383 3384 UserReleaseDC(pWnd, Dc, FALSE); 3385 } 3386 3387 if (!Item->yItem && !Item->xItem && !Item->cyItem && !Item->cxItem) 3388 { 3389 Item->xItem = Rect.left; 3390 Item->yItem = Rect.top; 3391 Item->cxItem = Rect.right; // Do this for now...... 3392 Item->cyItem = Rect.bottom; 3393 } 3394 Item->fState |= MF_MOUSESELECT; 3395 3396 if (IS_SYSTEM_MENU(Menu)) 3397 { 3398 MENU_InitSysMenuPopup(Item->spSubMenu, pWnd->style, pWnd->pcls->style, HTSYSMENU); 3399 3400 NC_GetSysPopupPos(pWnd, &Rect); 3401 /* Ensure we do not overlap this */ 3402 ParentRect = Rect; 3403 if (Flags & TPM_LAYOUTRTL) Rect.left = Rect.right; 3404 Rect.top = Rect.bottom; 3405 Rect.right = UserGetSystemMetrics(SM_CXSIZE); 3406 Rect.bottom = UserGetSystemMetrics(SM_CYSIZE); 3407 } 3408 else 3409 { 3410 IntGetWindowRect(pWnd, &Rect); 3411 if (Menu->fFlags & MNF_POPUP) 3412 { 3413 RECT rc; 3414 rc.left = Item->xItem; 3415 rc.top = Item->yItem; 3416 rc.right = Item->cxItem; 3417 rc.bottom = Item->cyItem; 3418 3419 MENU_AdjustMenuItemRect(Menu, &rc); 3420 3421 /* The first item in the popup menu has to be at the 3422 same y position as the focused menu item */ 3423 if(Flags & TPM_LAYOUTRTL) 3424 Rect.left += UserGetSystemMetrics(SM_CXDLGFRAME); 3425 else 3426 Rect.left += rc.right - UserGetSystemMetrics(SM_CXDLGFRAME); 3427 3428 Rect.top += rc.top; 3429 } 3430 else 3431 { 3432 if(Flags & TPM_LAYOUTRTL) 3433 Rect.left += Rect.right - Item->xItem; //ItemInfo.Rect.left; 3434 else 3435 Rect.left += Item->xItem; //ItemInfo.Rect.left; 3436 Rect.top += Item->cyItem; //ItemInfo.Rect.bottom; 3437 Rect.right = Item->cxItem - Item->xItem; //ItemInfo.Rect.right - ItemInfo.Rect.left; 3438 Rect.bottom = Item->cyItem - Item->yItem; //ItemInfo.Rect.bottom - ItemInfo.Rect.top; 3439 } 3440 } 3441 3442 /* Next menu does not need to be shown vertical anymore */ 3443 if (Menu->fFlags & MNF_POPUP) 3444 Flags &= (~TPM_VERTICAL); 3445 3446 3447 3448 /* use default alignment for submenus */ 3449 Flags &= ~(TPM_CENTERALIGN | TPM_RIGHTALIGN | TPM_VCENTERALIGN | TPM_BOTTOMALIGN); 3450 3451 MENU_InitPopup( WndOwner, Item->spSubMenu, Flags ); 3452 3453 MENU_ShowPopup( WndOwner, Item->spSubMenu, Menu->iItem, Flags, 3454 Rect.left, Rect.top, &ParentRect); 3455 if (SelectFirst) 3456 { 3457 MENU_MoveSelection(WndOwner, Item->spSubMenu, ITEM_NEXT); 3458 } 3459 return Item->spSubMenu; 3460 } 3461 3462 /*********************************************************************** 3463 * MenuExecFocusedItem 3464 * 3465 * Execute a menu item (for instance when user pressed Enter). 3466 * Return the wID of the executed item. Otherwise, -1 indicating 3467 * that no menu item was executed, -2 if a popup is shown; 3468 * Have to receive the flags for the TrackPopupMenu options to avoid 3469 * sending unwanted message. 3470 * 3471 */ 3472 static INT FASTCALL MENU_ExecFocusedItem(MTRACKER *pmt, PMENU Menu, UINT Flags) 3473 { 3474 PITEM Item; 3475 3476 TRACE("%p menu=%p\n", pmt, Menu); 3477 3478 if (!Menu || !Menu->cItems || Menu->iItem == NO_SELECTED_ITEM) 3479 { 3480 return -1; 3481 } 3482 3483 Item = &Menu->rgItems[Menu->iItem]; 3484 3485 TRACE("%p %08x %p\n", Menu, Item->wID, Item->spSubMenu); 3486 3487 if (!(Item->spSubMenu)) 3488 { 3489 if (!(Item->fState & (MF_GRAYED | MF_DISABLED)) && !(Item->fType & MF_SEPARATOR)) 3490 { 3491 /* If TPM_RETURNCMD is set you return the id, but 3492 do not send a message to the owner */ 3493 if (!(Flags & TPM_RETURNCMD)) 3494 { 3495 if (Menu->fFlags & MNF_SYSMENU) 3496 { 3497 UserPostMessage(UserHMGetHandle(pmt->OwnerWnd), WM_SYSCOMMAND, Item->wID, 3498 MAKELPARAM((SHORT) pmt->Pt.x, (SHORT) pmt->Pt.y)); 3499 } 3500 else 3501 { 3502 DWORD dwStyle = ((Menu->fFlags & MNS_STYLE_MASK) | ( pmt->TopMenu ? (pmt->TopMenu->fFlags & MNS_STYLE_MASK) : 0) ); 3503 3504 if (dwStyle & MNS_NOTIFYBYPOS) 3505 UserPostMessage(UserHMGetHandle(pmt->OwnerWnd), WM_MENUCOMMAND, Menu->iItem, (LPARAM)UserHMGetHandle(Menu)); 3506 else 3507 UserPostMessage(UserHMGetHandle(pmt->OwnerWnd), WM_COMMAND, Item->wID, 0); 3508 } 3509 } 3510 return Item->wID; 3511 } 3512 } 3513 else 3514 { 3515 pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, Menu, TRUE, Flags); 3516 return -2; 3517 } 3518 3519 return -1; 3520 } 3521 3522 /*********************************************************************** 3523 * MenuSwitchTracking 3524 * 3525 * Helper function for menu navigation routines. 3526 */ 3527 static void FASTCALL MENU_SwitchTracking(MTRACKER* pmt, PMENU PtMenu, UINT Index, UINT wFlags) 3528 { 3529 TRACE("%x menu=%x 0x%04x\n", pmt, PtMenu, Index); 3530 3531 if ( pmt->TopMenu != PtMenu && 3532 !((PtMenu->fFlags | pmt->TopMenu->fFlags) & MNF_POPUP) ) 3533 { 3534 /* both are top level menus (system and menu-bar) */ 3535 MENU_HideSubPopups(pmt->OwnerWnd, pmt->TopMenu, FALSE, wFlags); 3536 MENU_SelectItem(pmt->OwnerWnd, pmt->TopMenu, NO_SELECTED_ITEM, FALSE, NULL); 3537 pmt->TopMenu = PtMenu; 3538 } 3539 else 3540 { 3541 MENU_HideSubPopups(pmt->OwnerWnd, PtMenu, FALSE, wFlags); 3542 } 3543 3544 MENU_SelectItem(pmt->OwnerWnd, PtMenu, Index, TRUE, NULL); 3545 } 3546 3547 /*********************************************************************** 3548 * MenuButtonDown 3549 * 3550 * Return TRUE if we can go on with menu tracking. 3551 */ 3552 static BOOL FASTCALL MENU_ButtonDown(MTRACKER* pmt, PMENU PtMenu, UINT Flags) 3553 { 3554 TRACE("%x PtMenu=%p\n", pmt, PtMenu); 3555 3556 if (PtMenu) 3557 { 3558 UINT id = 0; 3559 PITEM item; 3560 if (IS_SYSTEM_MENU(PtMenu)) 3561 { 3562 item = PtMenu->rgItems; 3563 } 3564 else 3565 { 3566 item = MENU_FindItemByCoords( PtMenu, pmt->Pt, &id ); 3567 } 3568 3569 if (item) 3570 { 3571 if (PtMenu->iItem != id) 3572 MENU_SwitchTracking(pmt, PtMenu, id, Flags); 3573 3574 /* If the popup menu is not already "popped" */ 3575 if (!(item->fState & MF_MOUSESELECT)) 3576 { 3577 pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, PtMenu, FALSE, Flags); 3578 } 3579 3580 return TRUE; 3581 } 3582 /* Else the click was on the menu bar, finish the tracking */ 3583 } 3584 return FALSE; 3585 } 3586 3587 /*********************************************************************** 3588 * MenuButtonUp 3589 * 3590 * Return the value of MenuExecFocusedItem if 3591 * the selected item was not a popup. Else open the popup. 3592 * A -1 return value indicates that we go on with menu tracking. 3593 * 3594 */ 3595 static INT FASTCALL MENU_ButtonUp(MTRACKER *pmt, PMENU PtMenu, UINT Flags) 3596 { 3597 TRACE("%p pmenu=%x\n", pmt, PtMenu); 3598 3599 if (PtMenu) 3600 { 3601 UINT Id = 0; 3602 ITEM *item; 3603 3604 if ( IS_SYSTEM_MENU(PtMenu) ) 3605 { 3606 item = PtMenu->rgItems; 3607 } 3608 else 3609 { 3610 item = MENU_FindItemByCoords( PtMenu, pmt->Pt, &Id ); 3611 } 3612 3613 if (item && ( PtMenu->iItem == Id)) 3614 { 3615 if (!(item->spSubMenu)) 3616 { 3617 INT ExecutedMenuId = MENU_ExecFocusedItem( pmt, PtMenu, Flags); 3618 if (ExecutedMenuId == -1 || ExecutedMenuId == -2) return -1; 3619 return ExecutedMenuId; 3620 } 3621 3622 /* If we are dealing with the menu bar */ 3623 /* and this is a click on an already "popped" item: */ 3624 /* Stop the menu tracking and close the opened submenus */ 3625 if (pmt->TopMenu == PtMenu && PtMenu->TimeToHide) 3626 { 3627 return 0; 3628 } 3629 } 3630 if ( IntGetMenu(PtMenu->hWnd) == PtMenu ) 3631 { 3632 PtMenu->TimeToHide = TRUE; 3633 } 3634 } 3635 return -1; 3636 } 3637 3638 /*********************************************************************** 3639 * MenuPtMenu 3640 * 3641 * Walks menu chain trying to find a menu pt maps to. 3642 */ 3643 static PMENU FASTCALL MENU_PtMenu(PMENU menu, POINT pt) 3644 { 3645 PITEM pItem; 3646 PMENU ret = NULL; 3647 3648 if (!menu) return NULL; 3649 3650 /* try subpopup first (if any) */ 3651 if (menu->iItem != NO_SELECTED_ITEM) 3652 { 3653 pItem = menu->rgItems; 3654 if ( pItem ) pItem = &pItem[menu->iItem]; 3655 if ( pItem && pItem->spSubMenu && pItem->fState & MF_MOUSESELECT) 3656 { 3657 ret = MENU_PtMenu( pItem->spSubMenu, pt); 3658 } 3659 } 3660 3661 /* check the current window (avoiding WM_HITTEST) */ 3662 if (!ret) 3663 { 3664 PWND pWnd = ValidateHwndNoErr(menu->hWnd); 3665 INT ht = GetNCHitEx(pWnd, pt); 3666 if ( menu->fFlags & MNF_POPUP ) 3667 { 3668 if (ht != HTNOWHERE && ht != HTERROR) ret = menu; 3669 } 3670 else if (ht == HTSYSMENU) 3671 ret = get_win_sys_menu(menu->hWnd); 3672 else if (ht == HTMENU) 3673 ret = IntGetMenu( menu->hWnd ); 3674 } 3675 return ret; 3676 } 3677 3678 /*********************************************************************** 3679 * MenuMouseMove 3680 * 3681 * Return TRUE if we can go on with menu tracking. 3682 */ 3683 static BOOL FASTCALL MENU_MouseMove(MTRACKER *pmt, PMENU PtMenu, UINT Flags) 3684 { 3685 UINT Index = NO_SELECTED_ITEM; 3686 3687 if ( PtMenu ) 3688 { 3689 if (IS_SYSTEM_MENU(PtMenu)) 3690 { 3691 Index = 0; 3692 //// ReactOS only HACK: CORE-2338 3693 // Windows tracks mouse moves to the system menu but does not open it. 3694 // Only keyboard tracking can do that. 3695 // 3696 TRACE("SystemMenu\n"); 3697 return TRUE; // Stay inside the Loop! 3698 } 3699 else 3700 MENU_FindItemByCoords( PtMenu, pmt->Pt, &Index ); 3701 } 3702 3703 if (Index == NO_SELECTED_ITEM) 3704 { 3705 MENU_SelectItem(pmt->OwnerWnd, pmt->CurrentMenu, NO_SELECTED_ITEM, TRUE, pmt->TopMenu); 3706 } 3707 else if (PtMenu->iItem != Index) 3708 { 3709 MENU_SwitchTracking(pmt, PtMenu, Index, Flags); 3710 pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, PtMenu, FALSE, Flags); 3711 } 3712 return TRUE; 3713 } 3714 3715 /*********************************************************************** 3716 * MenuGetSubPopup 3717 * 3718 * Return the handle of the selected sub-popup menu (if any). 3719 */ 3720 static PMENU MENU_GetSubPopup( PMENU menu ) 3721 { 3722 ITEM *item; 3723 3724 if ((!menu) || (menu->iItem == NO_SELECTED_ITEM)) return 0; 3725 3726 item = &menu->rgItems[menu->iItem]; 3727 if (item && (item->spSubMenu) && (item->fState & MF_MOUSESELECT)) 3728 { 3729 return item->spSubMenu; 3730 } 3731 return 0; 3732 } 3733 3734 /*********************************************************************** 3735 * MenuDoNextMenu 3736 * 3737 * NOTE: WM_NEXTMENU documented in Win32 is a bit different. 3738 */ 3739 static LRESULT FASTCALL MENU_DoNextMenu(MTRACKER* pmt, UINT Vk, UINT wFlags) 3740 { 3741 BOOL atEnd = FALSE; 3742 3743 /* When skipping left, we need to do something special after the 3744 first menu. */ 3745 if (Vk == VK_LEFT && pmt->TopMenu->iItem == 0) 3746 { 3747 atEnd = TRUE; 3748 } 3749 /* When skipping right, for the non-system menu, we need to 3750 handle the last non-special menu item (ie skip any window 3751 icons such as MDI maximize, restore or close) */ 3752 else if ((Vk == VK_RIGHT) && !IS_SYSTEM_MENU(pmt->TopMenu)) 3753 { 3754 UINT i = pmt->TopMenu->iItem + 1; 3755 while (i < pmt->TopMenu->cItems) { 3756 if ((pmt->TopMenu->rgItems[i].wID >= SC_SIZE && 3757 pmt->TopMenu->rgItems[i].wID <= SC_RESTORE)) { 3758 i++; 3759 } else break; 3760 } 3761 if (i == pmt->TopMenu->cItems) { 3762 atEnd = TRUE; 3763 } 3764 } 3765 /* When skipping right, we need to cater for the system menu */ 3766 else if ((Vk == VK_RIGHT) && IS_SYSTEM_MENU(pmt->TopMenu)) 3767 { 3768 if (pmt->TopMenu->iItem == (pmt->TopMenu->cItems - 1)) { 3769 atEnd = TRUE; 3770 } 3771 } 3772 3773 if ( atEnd ) 3774 { 3775 MDINEXTMENU NextMenu; 3776 PMENU MenuTmp; 3777 PWND pwndTemp; 3778 HMENU hNewMenu; 3779 HWND hNewWnd; 3780 UINT Id = 0; 3781 3782 MenuTmp = (IS_SYSTEM_MENU(pmt->TopMenu)) ? co_IntGetSubMenu(pmt->TopMenu, 0) : pmt->TopMenu; 3783 NextMenu.hmenuIn = UserHMGetHandle(MenuTmp); 3784 NextMenu.hmenuNext = NULL; 3785 NextMenu.hwndNext = NULL; 3786 co_IntSendMessage(UserHMGetHandle(pmt->OwnerWnd), WM_NEXTMENU, Vk, (LPARAM) &NextMenu); 3787 3788 TRACE("%p [%p] -> %p [%p]\n", 3789 pmt->CurrentMenu, pmt->OwnerWnd, NextMenu.hmenuNext, NextMenu.hwndNext ); 3790 3791 if (NULL == NextMenu.hmenuNext || NULL == NextMenu.hwndNext) 3792 { 3793 hNewWnd = UserHMGetHandle(pmt->OwnerWnd); 3794 if (IS_SYSTEM_MENU(pmt->TopMenu)) 3795 { 3796 /* switch to the menu bar */ 3797 3798 if (pmt->OwnerWnd->style & WS_CHILD || !(MenuTmp = IntGetMenu(hNewWnd))) return FALSE; 3799 3800 if (Vk == VK_LEFT) 3801 { 3802 Id = MenuTmp->cItems - 1; 3803 3804 /* Skip backwards over any system predefined icons, 3805 eg. MDI close, restore etc icons */ 3806 while ((Id > 0) && 3807 (MenuTmp->rgItems[Id].wID >= SC_SIZE && 3808 MenuTmp->rgItems[Id].wID <= SC_RESTORE)) Id--; 3809 3810 } 3811 hNewMenu = UserHMGetHandle(MenuTmp); 3812 } 3813 else if (pmt->OwnerWnd->style & WS_SYSMENU) 3814 { 3815 /* switch to the system menu */ 3816 MenuTmp = get_win_sys_menu(hNewWnd); 3817 if (MenuTmp) hNewMenu = UserHMGetHandle(MenuTmp); 3818 else hNewMenu = NULL; 3819 } 3820 else 3821 return FALSE; 3822 } 3823 else /* application returned a new menu to switch to */ 3824 { 3825 hNewMenu = NextMenu.hmenuNext; 3826 hNewWnd = NextMenu.hwndNext; 3827 3828 if ((MenuTmp = UserGetMenuObject(hNewMenu)) && (pwndTemp = ValidateHwndNoErr(hNewWnd))) 3829 { 3830 if ( pwndTemp->style & WS_SYSMENU && (get_win_sys_menu(hNewWnd) == MenuTmp) ) 3831 { 3832 /* get the real system menu */ 3833 MenuTmp = get_win_sys_menu(hNewWnd); 3834 hNewMenu = UserHMGetHandle(MenuTmp); 3835 } 3836 else if (pwndTemp->style & WS_CHILD || IntGetMenu(hNewWnd) != MenuTmp) 3837 { 3838 /* FIXME: Not sure what to do here; 3839 * perhaps try to track NewMenu as a popup? */ 3840 3841 WARN(" -- got confused.\n"); 3842 return FALSE; 3843 } 3844 } 3845 else return FALSE; 3846 } 3847 3848 if (hNewMenu != UserHMGetHandle(pmt->TopMenu)) 3849 { 3850 MENU_SelectItem(pmt->OwnerWnd, pmt->TopMenu, NO_SELECTED_ITEM, FALSE, 0 ); 3851 3852 if (pmt->CurrentMenu != pmt->TopMenu) 3853 MENU_HideSubPopups(pmt->OwnerWnd, pmt->TopMenu, FALSE, wFlags); 3854 } 3855 3856 if (hNewWnd != UserHMGetHandle(pmt->OwnerWnd)) 3857 { 3858 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 3859 pmt->OwnerWnd = ValidateHwndNoErr(hNewWnd); 3860 ///// Use thread pms!!!! 3861 MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, hNewWnd); 3862 pti->MessageQueue->QF_flags &= ~QF_CAPTURELOCKED; 3863 co_UserSetCapture(UserHMGetHandle(pmt->OwnerWnd)); 3864 pti->MessageQueue->QF_flags |= QF_CAPTURELOCKED; 3865 } 3866 3867 pmt->TopMenu = pmt->CurrentMenu = UserGetMenuObject(hNewMenu); /* all subpopups are hidden */ 3868 MENU_SelectItem(pmt->OwnerWnd, pmt->TopMenu, Id, TRUE, 0); 3869 3870 return TRUE; 3871 } 3872 return FALSE; 3873 } 3874 3875 /*********************************************************************** 3876 * MenuSuspendPopup 3877 * 3878 * The idea is not to show the popup if the next input message is 3879 * going to hide it anyway. 3880 */ 3881 static BOOL FASTCALL MENU_SuspendPopup(MTRACKER* pmt, UINT uMsg) 3882 { 3883 MSG msg; 3884 3885 msg.hwnd = UserHMGetHandle(pmt->OwnerWnd); ////// ? silly wine'isms? 3886 3887 co_IntGetPeekMessage( &msg, 0, uMsg, uMsg, PM_NOYIELD | PM_REMOVE, FALSE); 3888 pmt->TrackFlags |= TF_SKIPREMOVE; 3889 3890 switch( uMsg ) 3891 { 3892 case WM_KEYDOWN: 3893 co_IntGetPeekMessage( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE, FALSE); 3894 if( msg.message == WM_KEYUP || msg.message == WM_PAINT ) 3895 { 3896 co_IntGetPeekMessage( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE, FALSE); 3897 co_IntGetPeekMessage( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE, FALSE); 3898 if( msg.message == WM_KEYDOWN && 3899 (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT)) 3900 { 3901 pmt->TrackFlags |= TF_SUSPENDPOPUP; 3902 return TRUE; 3903 } 3904 } 3905 break; 3906 } 3907 /* failures go through this */ 3908 pmt->TrackFlags &= ~TF_SUSPENDPOPUP; 3909 return FALSE; 3910 } 3911 3912 /*********************************************************************** 3913 * MenuKeyEscape 3914 * 3915 * Handle a VK_ESCAPE key event in a menu. 3916 */ 3917 static BOOL FASTCALL MENU_KeyEscape(MTRACKER *pmt, UINT Flags) 3918 { 3919 BOOL EndMenu = TRUE; 3920 3921 if (pmt->CurrentMenu != pmt->TopMenu) 3922 { 3923 if (pmt->CurrentMenu && (pmt->CurrentMenu->fFlags & MNF_POPUP)) 3924 { 3925 PMENU MenuPrev, MenuTmp; 3926 3927 MenuPrev = MenuTmp = pmt->TopMenu; 3928 3929 /* close topmost popup */ 3930 while (MenuTmp != pmt->CurrentMenu) 3931 { 3932 MenuPrev = MenuTmp; 3933 MenuTmp = MENU_GetSubPopup(MenuPrev); 3934 } 3935 3936 MENU_HideSubPopups(pmt->OwnerWnd, MenuPrev, TRUE, Flags); 3937 pmt->CurrentMenu = MenuPrev; 3938 EndMenu = FALSE; 3939 } 3940 } 3941 3942 return EndMenu; 3943 } 3944 3945 /*********************************************************************** 3946 * MenuKeyLeft 3947 * 3948 * Handle a VK_LEFT key event in a menu. 3949 */ 3950 static void FASTCALL MENU_KeyLeft(MTRACKER* pmt, UINT Flags, UINT msg) 3951 { 3952 PMENU MenuTmp, MenuPrev; 3953 UINT PrevCol; 3954 3955 MenuPrev = MenuTmp = pmt->TopMenu; 3956 3957 /* Try to move 1 column left (if possible) */ 3958 if ( (PrevCol = MENU_GetStartOfPrevColumn(pmt->CurrentMenu)) != NO_SELECTED_ITEM) 3959 { 3960 MENU_SelectItem(pmt->OwnerWnd, pmt->CurrentMenu, PrevCol, TRUE, 0); 3961 return; 3962 } 3963 3964 /* close topmost popup */ 3965 while (MenuTmp != pmt->CurrentMenu) 3966 { 3967 MenuPrev = MenuTmp; 3968 MenuTmp = MENU_GetSubPopup(MenuPrev); 3969 } 3970 3971 MENU_HideSubPopups(pmt->OwnerWnd, MenuPrev, TRUE, Flags); 3972 pmt->CurrentMenu = MenuPrev; 3973 3974 if ((MenuPrev == pmt->TopMenu) && !(pmt->TopMenu->fFlags & MNF_POPUP)) 3975 { 3976 /* move menu bar selection if no more popups are left */ 3977 3978 if (!MENU_DoNextMenu(pmt, VK_LEFT, Flags)) 3979 MENU_MoveSelection(pmt->OwnerWnd, pmt->TopMenu, ITEM_PREV); 3980 3981 if (MenuPrev != MenuTmp || pmt->TrackFlags & TF_SUSPENDPOPUP) 3982 { 3983 /* A sublevel menu was displayed - display the next one 3984 * unless there is another displacement coming up */ 3985 3986 if (!MENU_SuspendPopup(pmt, msg)) 3987 pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, pmt->TopMenu, 3988 TRUE, Flags); 3989 } 3990 } 3991 } 3992 3993 /*********************************************************************** 3994 * MenuKeyRight 3995 * 3996 * Handle a VK_RIGHT key event in a menu. 3997 */ 3998 static void FASTCALL MENU_KeyRight(MTRACKER *pmt, UINT Flags, UINT msg) 3999 { 4000 PMENU menutmp; 4001 UINT NextCol; 4002 4003 TRACE("MenuKeyRight called, cur %p, top %p.\n", 4004 pmt->CurrentMenu, pmt->TopMenu); 4005 4006 if ((pmt->TopMenu->fFlags & MNF_POPUP) || (pmt->CurrentMenu != pmt->TopMenu)) 4007 { 4008 /* If already displaying a popup, try to display sub-popup */ 4009 4010 menutmp = pmt->CurrentMenu; 4011 pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, menutmp, TRUE, Flags); 4012 4013 /* if subpopup was displayed then we are done */ 4014 if (menutmp != pmt->CurrentMenu) return; 4015 } 4016 4017 /* Check to see if there's another column */ 4018 if ( (NextCol = MENU_GetStartOfNextColumn(pmt->CurrentMenu)) != NO_SELECTED_ITEM) 4019 { 4020 TRACE("Going to %d.\n", NextCol); 4021 MENU_SelectItem(pmt->OwnerWnd, pmt->CurrentMenu, NextCol, TRUE, 0); 4022 return; 4023 } 4024 4025 if (!(pmt->TopMenu->fFlags & MNF_POPUP)) /* menu bar tracking */ 4026 { 4027 if (pmt->CurrentMenu != pmt->TopMenu) 4028 { 4029 MENU_HideSubPopups(pmt->OwnerWnd, pmt->TopMenu, FALSE, Flags); 4030 menutmp = pmt->CurrentMenu = pmt->TopMenu; 4031 } 4032 else 4033 { 4034 menutmp = NULL; 4035 } 4036 4037 /* try to move to the next item */ 4038 if ( !MENU_DoNextMenu(pmt, VK_RIGHT, Flags)) 4039 MENU_MoveSelection(pmt->OwnerWnd, pmt->TopMenu, ITEM_NEXT); 4040 4041 if ( menutmp || pmt->TrackFlags & TF_SUSPENDPOPUP ) 4042 { 4043 if ( !MENU_SuspendPopup(pmt, msg) ) 4044 pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, pmt->TopMenu, TRUE, Flags); 4045 } 4046 } 4047 } 4048 4049 /*********************************************************************** 4050 * MenuTrackMenu 4051 * 4052 * Menu tracking code. 4053 */ 4054 static INT FASTCALL MENU_TrackMenu(PMENU pmenu, UINT wFlags, INT x, INT y, 4055 PWND pwnd) 4056 { 4057 MSG msg; 4058 BOOL fRemove; 4059 INT executedMenuId = -1; 4060 MTRACKER mt; 4061 HWND capture_win; 4062 PMENU pmMouse; 4063 BOOL enterIdleSent = FALSE; 4064 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 4065 4066 if (pti != pwnd->head.pti) 4067 { 4068 ERR("Not the same PTI!!!!\n"); 4069 } 4070 4071 mt.TrackFlags = 0; 4072 mt.CurrentMenu = pmenu; 4073 mt.TopMenu = pmenu; 4074 mt.OwnerWnd = pwnd; 4075 mt.Pt.x = x; 4076 mt.Pt.y = y; 4077 4078 TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x\n", 4079 UserHMGetHandle(pmenu), wFlags, x, y, UserHMGetHandle(pwnd)); 4080 4081 pti->MessageQueue->QF_flags &= ~QF_ACTIVATIONCHANGE; 4082 4083 if (wFlags & TPM_BUTTONDOWN) 4084 { 4085 /* Get the result in order to start the tracking or not */ 4086 fRemove = MENU_ButtonDown( &mt, pmenu, wFlags ); 4087 fInsideMenuLoop = fRemove; 4088 } 4089 4090 if (wFlags & TF_ENDMENU) fInsideMenuLoop = FALSE; 4091 4092 if (wFlags & TPM_POPUPMENU && pmenu->cItems == 0) // Tracking empty popup menu... 4093 { 4094 MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL); 4095 pti->MessageQueue->QF_flags &= ~QF_CAPTURELOCKED; 4096 co_UserSetCapture(NULL); /* release the capture */ 4097 return 0; 4098 } 4099 4100 capture_win = IntGetCapture(); 4101 4102 while (fInsideMenuLoop) 4103 { 4104 BOOL ErrorExit = FALSE; 4105 if (!VerifyMenu( mt.CurrentMenu )) /* sometimes happens if I do a window manager close */ 4106 break; 4107 4108 /* we have to keep the message in the queue until it's 4109 * clear that menu loop is not over yet. */ 4110 4111 for (;;) 4112 { 4113 if (co_IntGetPeekMessage( &msg, 0, 0, 0, PM_NOREMOVE, FALSE )) 4114 { 4115 if (!IntCallMsgFilter( &msg, MSGF_MENU )) break; 4116 /* remove the message from the queue */ 4117 co_IntGetPeekMessage( &msg, 0, msg.message, msg.message, PM_REMOVE, FALSE ); 4118 } 4119 else 4120 { 4121 /* ReactOS Checks */ 4122 if (!VerifyWnd(mt.OwnerWnd) || 4123 !ValidateHwndNoErr(mt.CurrentMenu->hWnd) || 4124 //pti->MessageQueue->QF_flags & QF_ACTIVATIONCHANGE || // See CORE-17338 4125 capture_win != IntGetCapture() ) // Should not happen, but this is ReactOS... 4126 { 4127 ErrorExit = TRUE; // Do not wait on dead windows, now win test_capture_4 works. 4128 break; 4129 } 4130 4131 if (!enterIdleSent) 4132 { 4133 HWND win = mt.CurrentMenu->fFlags & MNF_POPUP ? mt.CurrentMenu->hWnd : NULL; 4134 enterIdleSent = TRUE; 4135 co_IntSendMessage( UserHMGetHandle(mt.OwnerWnd), WM_ENTERIDLE, MSGF_MENU, (LPARAM) win); 4136 } 4137 co_IntWaitMessage(NULL, 0, 0); 4138 } 4139 } 4140 4141 if (ErrorExit) break; // Gracefully dropout. 4142 4143 /* check if EndMenu() tried to cancel us, by posting this message */ 4144 if (msg.message == WM_CANCELMODE) 4145 { 4146 /* we are now out of the loop */ 4147 fInsideMenuLoop = FALSE; 4148 4149 /* remove the message from the queue */ 4150 co_IntGetPeekMessage( &msg, 0, msg.message, msg.message, PM_REMOVE, FALSE ); 4151 4152 /* break out of internal loop, ala ESCAPE */ 4153 break; 4154 } 4155 4156 mt.Pt = msg.pt; 4157 4158 if ( (msg.hwnd == mt.CurrentMenu->hWnd) || ((msg.message!=WM_TIMER) && (msg.message!=WM_SYSTIMER)) ) 4159 enterIdleSent=FALSE; 4160 4161 fRemove = FALSE; 4162 if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST)) 4163 { 4164 /* 4165 * Use the mouse coordinates in lParam instead of those in the MSG 4166 * struct to properly handle synthetic messages. They are already 4167 * in screen coordinates. 4168 */ 4169 mt.Pt.x = (short)LOWORD(msg.lParam); 4170 mt.Pt.y = (short)HIWORD(msg.lParam); 4171 4172 /* Find a menu for this mouse event */ 4173 pmMouse = MENU_PtMenu( mt.TopMenu, mt.Pt ); 4174 4175 switch(msg.message) 4176 { 4177 /* no WM_NC... messages in captured state */ 4178 4179 case WM_RBUTTONDBLCLK: 4180 case WM_RBUTTONDOWN: 4181 if (!(wFlags & TPM_RIGHTBUTTON)) 4182 { 4183 if ( msg.message == WM_RBUTTONDBLCLK ) fInsideMenuLoop = FALSE; // Must exit or loop forever! 4184 break; 4185 } 4186 /* fall through */ 4187 case WM_LBUTTONDBLCLK: 4188 case WM_LBUTTONDOWN: 4189 /* If the message belongs to the menu, removes it from the queue */ 4190 /* Else, end menu tracking */ 4191 fRemove = MENU_ButtonDown(&mt, pmMouse, wFlags); 4192 fInsideMenuLoop = fRemove; 4193 if ( msg.message == WM_LBUTTONDBLCLK || 4194 msg.message == WM_RBUTTONDBLCLK ) fInsideMenuLoop = FALSE; // Must exit or loop forever! 4195 break; 4196 4197 case WM_RBUTTONUP: 4198 if (!(wFlags & TPM_RIGHTBUTTON)) break; 4199 /* fall through */ 4200 case WM_LBUTTONUP: 4201 /* Check if a menu was selected by the mouse */ 4202 if (pmMouse) 4203 { 4204 executedMenuId = MENU_ButtonUp( &mt, pmMouse, wFlags); 4205 4206 /* End the loop if executedMenuId is an item ID */ 4207 /* or if the job was done (executedMenuId = 0). */ 4208 fRemove = (executedMenuId != -1); 4209 fInsideMenuLoop = !fRemove; 4210 } 4211 /* No menu was selected by the mouse */ 4212 /* if the function was called by TrackPopupMenu, continue 4213 with the menu tracking. If not, stop it */ 4214 else 4215 fInsideMenuLoop = ((wFlags & TPM_POPUPMENU) ? TRUE : FALSE); 4216 4217 break; 4218 4219 case WM_MOUSEMOVE: 4220 /* the selected menu item must be changed every time */ 4221 /* the mouse moves. */ 4222 4223 if (pmMouse) 4224 fInsideMenuLoop |= MENU_MouseMove( &mt, pmMouse, wFlags ); 4225 4226 } /* switch(msg.message) - mouse */ 4227 } 4228 else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST)) 4229 { 4230 fRemove = TRUE; /* Keyboard messages are always removed */ 4231 switch(msg.message) 4232 { 4233 case WM_KEYDOWN: 4234 case WM_SYSKEYDOWN: 4235 switch(msg.wParam) 4236 { 4237 case VK_MENU: 4238 case VK_F10: 4239 fInsideMenuLoop = FALSE; 4240 break; 4241 4242 case VK_HOME: 4243 case VK_END: 4244 MENU_SelectItem(mt.OwnerWnd, mt.CurrentMenu, NO_SELECTED_ITEM, FALSE, 0 ); 4245 MENU_MoveSelection(mt.OwnerWnd, mt.CurrentMenu, VK_HOME == msg.wParam ? ITEM_NEXT : ITEM_PREV); 4246 break; 4247 4248 case VK_UP: 4249 case VK_DOWN: /* If on menu bar, pull-down the menu */ 4250 if (!(mt.CurrentMenu->fFlags & MNF_POPUP)) 4251 mt.CurrentMenu = MENU_ShowSubPopup(mt.OwnerWnd, mt.TopMenu, TRUE, wFlags); 4252 else /* otherwise try to move selection */ 4253 MENU_MoveSelection(mt.OwnerWnd, mt.CurrentMenu, (msg.wParam == VK_UP)? ITEM_PREV : ITEM_NEXT ); 4254 break; 4255 4256 case VK_LEFT: 4257 MENU_KeyLeft( &mt, wFlags, msg.message ); 4258 break; 4259 4260 case VK_RIGHT: 4261 MENU_KeyRight( &mt, wFlags, msg.message ); 4262 break; 4263 4264 case VK_ESCAPE: 4265 fInsideMenuLoop = !MENU_KeyEscape(&mt, wFlags); 4266 break; 4267 4268 case VK_F1: 4269 { 4270 HELPINFO hi; 4271 hi.cbSize = sizeof(HELPINFO); 4272 hi.iContextType = HELPINFO_MENUITEM; 4273 if (mt.CurrentMenu->iItem == NO_SELECTED_ITEM) 4274 hi.iCtrlId = 0; 4275 else 4276 hi.iCtrlId = pmenu->rgItems[mt.CurrentMenu->iItem].wID; 4277 hi.hItemHandle = UserHMGetHandle(mt.CurrentMenu); 4278 hi.dwContextId = pmenu->dwContextHelpId; 4279 hi.MousePos = msg.pt; 4280 co_IntSendMessage( UserHMGetHandle(pwnd), WM_HELP, 0, (LPARAM)&hi); 4281 break; 4282 } 4283 4284 default: 4285 IntTranslateKbdMessage(&msg, 0); 4286 break; 4287 } 4288 break; /* WM_KEYDOWN */ 4289 4290 case WM_CHAR: 4291 case WM_SYSCHAR: 4292 { 4293 UINT pos; 4294 BOOL fEndMenu; 4295 4296 if (msg.wParam == L'\r' || msg.wParam == L' ') 4297 { 4298 executedMenuId = MENU_ExecFocusedItem(&mt, mt.CurrentMenu, wFlags); 4299 fEndMenu = (executedMenuId != -2); 4300 fInsideMenuLoop = !fEndMenu; 4301 break; 4302 } 4303 4304 /* Hack to avoid control chars. */ 4305 /* We will find a better way real soon... */ 4306 if (msg.wParam < 32) break; 4307 4308 pos = MENU_FindItemByKey(mt.OwnerWnd, mt.CurrentMenu, LOWORD(msg.wParam), FALSE); 4309 4310 if (pos == (UINT)-2) fInsideMenuLoop = FALSE; 4311 else if (pos == (UINT)-1) UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_MESSAGE_BEEP, 0); //MessageBeep(0); 4312 else 4313 { 4314 MENU_SelectItem(mt.OwnerWnd, mt.CurrentMenu, pos, TRUE, 0); 4315 executedMenuId = MENU_ExecFocusedItem(&mt, mt.CurrentMenu, wFlags); 4316 fEndMenu = (executedMenuId != -2); 4317 fInsideMenuLoop = !fEndMenu; 4318 } 4319 } 4320 break; 4321 } /* switch(msg.message) - kbd */ 4322 } 4323 else 4324 { 4325 co_IntGetPeekMessage( &msg, 0, msg.message, msg.message, PM_REMOVE, FALSE ); 4326 IntDispatchMessage( &msg ); 4327 continue; 4328 } 4329 4330 if (fInsideMenuLoop) fRemove = TRUE; 4331 4332 /* finally remove message from the queue */ 4333 4334 if (fRemove && !(mt.TrackFlags & TF_SKIPREMOVE) ) 4335 co_IntGetPeekMessage( &msg, 0, msg.message, msg.message, PM_REMOVE, FALSE ); 4336 else mt.TrackFlags &= ~TF_SKIPREMOVE; 4337 } 4338 4339 MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL); 4340 pti->MessageQueue->QF_flags &= ~QF_CAPTURELOCKED; 4341 co_UserSetCapture(NULL); /* release the capture */ 4342 4343 /* If dropdown is still painted and the close box is clicked on 4344 then the menu will be destroyed as part of the DispatchMessage above. 4345 This will then invalidate the menu handle in mt.hTopMenu. We should 4346 check for this first. */ 4347 if ( VerifyMenu( mt.TopMenu ) ) 4348 { 4349 if (VerifyWnd(mt.OwnerWnd)) 4350 { 4351 MENU_HideSubPopups(mt.OwnerWnd, mt.TopMenu, FALSE, wFlags); 4352 4353 if (mt.TopMenu->fFlags & MNF_POPUP) 4354 { 4355 PWND pwndTM = ValidateHwndNoErr(mt.TopMenu->hWnd); 4356 if (pwndTM) 4357 { 4358 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND, pwndTM, OBJID_CLIENT, CHILDID_SELF, 0); 4359 4360 co_UserDestroyWindow(pwndTM); 4361 } 4362 mt.TopMenu->hWnd = NULL; 4363 4364 if (!(wFlags & TPM_NONOTIFY)) 4365 { 4366 co_IntSendMessage( UserHMGetHandle(mt.OwnerWnd), WM_UNINITMENUPOPUP, (WPARAM)UserHMGetHandle(mt.TopMenu), 4367 MAKELPARAM(0, IS_SYSTEM_MENU(mt.TopMenu)) ); 4368 } 4369 } 4370 MENU_SelectItem( mt.OwnerWnd, mt.TopMenu, NO_SELECTED_ITEM, FALSE, 0 ); 4371 co_IntSendMessage( UserHMGetHandle(mt.OwnerWnd), WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0 ); 4372 } 4373 4374 /* Reset the variable for hiding menu */ 4375 mt.TopMenu->TimeToHide = FALSE; 4376 } 4377 4378 EngSetLastError( ERROR_SUCCESS ); 4379 /* The return value is only used by TrackPopupMenu */ 4380 if (!(wFlags & TPM_RETURNCMD)) return TRUE; 4381 if (executedMenuId == -1) executedMenuId = 0; 4382 return executedMenuId; 4383 } 4384 4385 /*********************************************************************** 4386 * MenuInitTracking 4387 */ 4388 static BOOL FASTCALL MENU_InitTracking(PWND pWnd, PMENU Menu, BOOL bPopup, UINT wFlags) 4389 { 4390 HWND capture_win; 4391 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 4392 4393 TRACE("hwnd=%p hmenu=%p\n", UserHMGetHandle(pWnd), UserHMGetHandle(Menu)); 4394 4395 co_UserHideCaret(0); 4396 4397 /* This makes the menus of applications built with Delphi work. 4398 * It also enables menus to be displayed in more than one window, 4399 * but there are some bugs left that need to be fixed in this case. 4400 */ 4401 if (!bPopup) 4402 { 4403 Menu->hWnd = UserHMGetHandle(pWnd); 4404 } 4405 4406 if (!top_popup) { 4407 top_popup = Menu->hWnd; 4408 top_popup_hmenu = UserHMGetHandle(Menu); 4409 } 4410 4411 fInsideMenuLoop = TRUE; 4412 fInEndMenu = FALSE; 4413 4414 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */ 4415 if (!(wFlags & TPM_NONOTIFY)) 4416 { 4417 co_IntSendMessage( UserHMGetHandle(pWnd), WM_ENTERMENULOOP, bPopup, 0 ); 4418 } 4419 4420 // 4421 // Capture is set before calling WM_INITMENU and after WM_ENTERMENULOOP, see msg_menu. 4422 // 4423 capture_win = (wFlags & TPM_POPUPMENU) ? Menu->hWnd : UserHMGetHandle(pWnd); 4424 MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, capture_win); // 1 4425 co_UserSetCapture(capture_win); // 2 4426 pti->MessageQueue->QF_flags |= QF_CAPTURELOCKED; // Set the Q bits so noone can change this! 4427 4428 co_IntSendMessage( UserHMGetHandle(pWnd), WM_SETCURSOR, (WPARAM)UserHMGetHandle(pWnd), HTCAPTION ); 4429 4430 if (!(wFlags & TPM_NONOTIFY)) 4431 { 4432 co_IntSendMessage( UserHMGetHandle(pWnd), WM_INITMENU, (WPARAM)UserHMGetHandle(Menu), 0 ); 4433 /* If an app changed/recreated menu bar entries in WM_INITMENU 4434 * menu sizes will be recalculated once the menu created/shown. 4435 */ 4436 } 4437 4438 IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART, 4439 pWnd, 4440 Menu->fFlags & MNF_SYSMENU ? OBJID_SYSMENU : OBJID_MENU, 4441 CHILDID_SELF, 0); 4442 return TRUE; 4443 } 4444 4445 /*********************************************************************** 4446 * MenuExitTracking 4447 */ 4448 static BOOL FASTCALL MENU_ExitTracking(PWND pWnd, BOOL bPopup, UINT wFlags) 4449 { 4450 TRACE("Exit Track hwnd=%p bPopup %d\n", UserHMGetHandle(pWnd), bPopup); 4451 4452 IntNotifyWinEvent( EVENT_SYSTEM_MENUEND, pWnd, OBJID_WINDOW, CHILDID_SELF, 0); 4453 4454 if (!(wFlags & TPM_NONOTIFY)) 4455 co_IntSendMessage( UserHMGetHandle(pWnd), WM_EXITMENULOOP, bPopup, 0 ); 4456 4457 co_UserShowCaret(0); 4458 4459 top_popup = 0; 4460 top_popup_hmenu = NULL; 4461 4462 return TRUE; 4463 } 4464 4465 /*********************************************************************** 4466 * MenuTrackMouseMenuBar 4467 * 4468 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand(). 4469 */ 4470 VOID MENU_TrackMouseMenuBar( PWND pWnd, ULONG ht, POINT pt) 4471 { 4472 PMENU pMenu = (ht == HTSYSMENU) ? IntGetSystemMenu(pWnd, FALSE) : IntGetMenu( UserHMGetHandle(pWnd) ); // See 74276 and CORE-12801 4473 UINT wFlags = TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL; 4474 4475 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", pWnd, ht, pt.x, pt.y); 4476 4477 if (pWnd->ExStyle & WS_EX_LAYOUTRTL) wFlags |= TPM_LAYOUTRTL; 4478 if (VerifyMenu(pMenu)) 4479 { 4480 /* map point to parent client coordinates */ 4481 PWND Parent = UserGetAncestor(pWnd, GA_PARENT ); 4482 if (Parent != UserGetDesktopWindow()) 4483 { 4484 IntScreenToClient(Parent, &pt); 4485 } 4486 4487 MENU_InitTracking(pWnd, pMenu, FALSE, wFlags); 4488 /* fetch the window menu again, it may have changed */ 4489 pMenu = (ht == HTSYSMENU) ? get_win_sys_menu( UserHMGetHandle(pWnd) ) : IntGetMenu( UserHMGetHandle(pWnd) ); 4490 MENU_TrackMenu(pMenu, wFlags, pt.x, pt.y, pWnd); 4491 MENU_ExitTracking(pWnd, FALSE, wFlags); 4492 } 4493 } 4494 4495 /*********************************************************************** 4496 * MenuTrackKbdMenuBar 4497 * 4498 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand(). 4499 */ 4500 VOID MENU_TrackKbdMenuBar(PWND pwnd, UINT wParam, WCHAR wChar) 4501 { 4502 UINT uItem = NO_SELECTED_ITEM; 4503 PMENU TrackMenu; 4504 UINT wFlags = TPM_LEFTALIGN | TPM_LEFTBUTTON; 4505 4506 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", UserHMGetHandle(pwnd), wParam, wChar); 4507 4508 /* find window that has a menu */ 4509 4510 while (!( (pwnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD ) ) 4511 if (!(pwnd = UserGetAncestor( pwnd, GA_PARENT ))) return; 4512 4513 /* check if we have to track a system menu */ 4514 4515 TrackMenu = IntGetMenu( UserHMGetHandle(pwnd) ); 4516 if (!TrackMenu || (pwnd->style & WS_MINIMIZE) != 0 || wChar == ' ' ) 4517 { 4518 if (!(pwnd->style & WS_SYSMENU)) return; 4519 TrackMenu = get_win_sys_menu( UserHMGetHandle(pwnd) ); 4520 uItem = 0; 4521 wParam |= HTSYSMENU; /* prevent item lookup */ 4522 } 4523 4524 if (!VerifyMenu( TrackMenu )) return; 4525 4526 MENU_InitTracking( pwnd, TrackMenu, FALSE, wFlags ); 4527 4528 /* fetch the window menu again, it may have changed */ 4529 TrackMenu = (wParam & HTSYSMENU) ? get_win_sys_menu( UserHMGetHandle(pwnd) ) : IntGetMenu( UserHMGetHandle(pwnd) ); 4530 4531 if( wChar && wChar != ' ' ) 4532 { 4533 uItem = MENU_FindItemByKey( pwnd, TrackMenu, wChar, (wParam & HTSYSMENU) ); 4534 if ( uItem >= (UINT)(-2) ) 4535 { 4536 if( uItem == (UINT)(-1) ) UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_MESSAGE_BEEP, 0); //MessageBeep(0); 4537 /* schedule end of menu tracking */ 4538 wFlags |= TF_ENDMENU; 4539 goto track_menu; 4540 } 4541 } 4542 4543 MENU_SelectItem( pwnd, TrackMenu, uItem, TRUE, 0 ); 4544 4545 if (!(wParam & HTSYSMENU) || wChar == ' ') 4546 { 4547 if( uItem == NO_SELECTED_ITEM ) 4548 MENU_MoveSelection( pwnd, TrackMenu, ITEM_NEXT ); 4549 else 4550 UserPostMessage( UserHMGetHandle(pwnd), WM_KEYDOWN, VK_RETURN, 0 ); 4551 } 4552 4553 track_menu: 4554 MENU_TrackMenu( TrackMenu, wFlags, 0, 0, pwnd ); 4555 MENU_ExitTracking( pwnd, FALSE, wFlags); 4556 } 4557 4558 /********************************************************************** 4559 * TrackPopupMenuEx (USER32.@) 4560 */ 4561 BOOL WINAPI IntTrackPopupMenuEx( PMENU menu, UINT wFlags, int x, int y, 4562 PWND pWnd, LPTPMPARAMS lpTpm) 4563 { 4564 BOOL ret = FALSE; 4565 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 4566 4567 if (pti != pWnd->head.pti) 4568 { 4569 ERR("Must be the same pti!\n"); 4570 return ret; 4571 } 4572 4573 TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p \n", //rect %s\n", 4574 UserHMGetHandle(menu), wFlags, x, y, UserHMGetHandle(pWnd), lpTpm); //, 4575 //lpTpm ? wine_dbgstr_rect( &lpTpm->rcExclude) : "-" ); 4576 4577 if (menu->hWnd && IntIsWindow(menu->hWnd)) 4578 { 4579 EngSetLastError( ERROR_POPUP_ALREADY_ACTIVE ); 4580 return FALSE; 4581 } 4582 4583 if (MENU_InitPopup( pWnd, menu, wFlags )) 4584 { 4585 MENU_InitTracking(pWnd, menu, TRUE, wFlags); 4586 4587 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */ 4588 if (!(wFlags & TPM_NONOTIFY)) 4589 { 4590 co_IntSendMessage( UserHMGetHandle(pWnd), WM_INITMENUPOPUP, (WPARAM) UserHMGetHandle(menu), 0); 4591 } 4592 4593 if (menu->fFlags & MNF_SYSMENU) 4594 MENU_InitSysMenuPopup( menu, pWnd->style, pWnd->pcls->style, HTSYSMENU); 4595 4596 if (MENU_ShowPopup(pWnd, menu, 0, wFlags | TPM_POPUPMENU, x, y, lpTpm ? &lpTpm->rcExclude : NULL)) 4597 ret = MENU_TrackMenu( menu, wFlags | TPM_POPUPMENU, 0, 0, pWnd); 4598 else 4599 { 4600 MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL); 4601 pti->MessageQueue->QF_flags &= ~QF_CAPTURELOCKED; 4602 co_UserSetCapture(NULL); /* release the capture */ 4603 } 4604 4605 MENU_ExitTracking(pWnd, TRUE, wFlags); 4606 4607 if (menu->hWnd) 4608 { 4609 PWND pwndM = ValidateHwndNoErr( menu->hWnd ); 4610 if (pwndM) // wine hack around this with their destroy function. 4611 { 4612 if (!(pWnd->state & WNDS_DESTROYED)) 4613 co_UserDestroyWindow( pwndM ); // Fix wrong error return. 4614 } 4615 menu->hWnd = 0; 4616 4617 if (!(wFlags & TPM_NONOTIFY)) 4618 { 4619 co_IntSendMessage( UserHMGetHandle(pWnd), WM_UNINITMENUPOPUP, (WPARAM)UserHMGetHandle(menu), 4620 MAKELPARAM(0, IS_SYSTEM_MENU(menu)) ); 4621 } 4622 } 4623 } 4624 return ret; 4625 } 4626 4627 // 4628 // Menu Class Proc. 4629 // 4630 BOOL WINAPI 4631 PopupMenuWndProc( 4632 PWND Wnd, 4633 UINT Message, 4634 WPARAM wParam, 4635 LPARAM lParam, 4636 LRESULT *lResult) 4637 { 4638 PPOPUPMENU pPopupMenu; 4639 4640 *lResult = 0; 4641 4642 TRACE("PMWP : pwnd=%x msg=%d wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam); 4643 4644 if (Wnd) 4645 { 4646 if (!Wnd->fnid) 4647 { 4648 if (Message != WM_NCCREATE) 4649 { 4650 *lResult = IntDefWindowProc(Wnd, Message, wParam, lParam, FALSE); 4651 return TRUE; 4652 } 4653 Wnd->fnid = FNID_MENU; 4654 pPopupMenu = DesktopHeapAlloc( Wnd->head.rpdesk, sizeof(POPUPMENU) ); 4655 if (pPopupMenu == NULL) 4656 { 4657 return TRUE; 4658 } 4659 pPopupMenu->posSelectedItem = NO_SELECTED_ITEM; 4660 pPopupMenu->spwndPopupMenu = Wnd; 4661 ((PMENUWND)Wnd)->ppopupmenu = pPopupMenu; 4662 TRACE("Pop Up Menu is Setup! Msg %d\n",Message); 4663 *lResult = 1; 4664 return TRUE; 4665 } 4666 else 4667 { 4668 if (Wnd->fnid != FNID_MENU) 4669 { 4670 ERR("Wrong window class for Menu! fnid %x\n",Wnd->fnid); 4671 return TRUE; 4672 } 4673 pPopupMenu = ((PMENUWND)Wnd)->ppopupmenu; 4674 } 4675 } 4676 4677 switch(Message) 4678 { 4679 case WM_CREATE: 4680 { 4681 CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam; 4682 pPopupMenu->spmenu = UserGetMenuObject(cs->lpCreateParams); 4683 if (pPopupMenu->spmenu) 4684 { 4685 UserReferenceObject(pPopupMenu->spmenu); 4686 } 4687 break; 4688 } 4689 4690 case WM_MOUSEACTIVATE: /* We don't want to be activated */ 4691 *lResult = MA_NOACTIVATE; 4692 break; 4693 4694 case WM_PAINT: 4695 { 4696 PAINTSTRUCT ps; 4697 IntBeginPaint(Wnd, &ps); 4698 MENU_DrawPopupMenu(Wnd, ps.hdc, pPopupMenu->spmenu); 4699 IntEndPaint(Wnd, &ps); 4700 break; 4701 } 4702 4703 case WM_PRINTCLIENT: 4704 { 4705 MENU_DrawPopupMenu( Wnd, (HDC)wParam, pPopupMenu->spmenu); 4706 break; 4707 } 4708 4709 case WM_ERASEBKGND: 4710 *lResult = 1; 4711 break; 4712 4713 case WM_DESTROY: 4714 /* zero out global pointer in case resident popup window was destroyed. */ 4715 if (pPopupMenu) 4716 { 4717 if (UserHMGetHandle(Wnd) == top_popup) 4718 { 4719 top_popup = NULL; 4720 top_popup_hmenu = NULL; 4721 } 4722 } 4723 else 4724 { 4725 ERR("No Window Pop Up!\n"); 4726 } 4727 break; 4728 4729 case WM_NCDESTROY: 4730 { 4731 if (pPopupMenu->spmenu) 4732 { 4733 IntReleaseMenuObject(pPopupMenu->spmenu); 4734 } 4735 DesktopHeapFree(Wnd->head.rpdesk, pPopupMenu ); 4736 ((PMENUWND)Wnd)->ppopupmenu = 0; 4737 Wnd->fnid = FNID_DESTROY; 4738 break; 4739 } 4740 4741 case MM_SETMENUHANDLE: // wine'isms 4742 case MN_SETHMENU: 4743 { 4744 PMENU pmenu = UserGetMenuObject((HMENU)wParam); 4745 if (!pmenu) 4746 { 4747 ERR("Bad Menu Handle\n"); 4748 break; 4749 } 4750 UserReferenceObject(pmenu); 4751 if (pPopupMenu->spmenu) 4752 { 4753 IntReleaseMenuObject(pPopupMenu->spmenu); 4754 } 4755 pPopupMenu->spmenu = pmenu; 4756 break; 4757 } 4758 4759 case MM_GETMENUHANDLE: // wine'isms 4760 case MN_GETHMENU: 4761 *lResult = (LRESULT)(pPopupMenu ? (pPopupMenu->spmenu ? UserHMGetHandle(pPopupMenu->spmenu) : NULL) : NULL); 4762 break; 4763 4764 default: 4765 if (Message > MN_GETHMENU && Message < MN_GETHMENU+19) 4766 { 4767 ERR("Someone is passing unknown menu messages %d\n",Message); 4768 } 4769 TRACE("PMWP to IDWP %d\n",Message); 4770 *lResult = IntDefWindowProc(Wnd, Message, wParam, lParam, FALSE); 4771 break; 4772 } 4773 4774 return TRUE; 4775 } 4776 4777 BOOL FASTCALL 4778 IntHiliteMenuItem(PWND WindowObject, 4779 PMENU MenuObject, 4780 UINT uItemHilite, 4781 UINT uHilite) 4782 { 4783 PITEM MenuItem; 4784 UINT uItem = uItemHilite; 4785 4786 if (!(MenuItem = MENU_FindItem( &MenuObject, &uItem, uHilite ))) return TRUE; 4787 4788 if (uHilite & MF_HILITE) 4789 { 4790 MenuItem->fState |= MF_HILITE; 4791 } 4792 else 4793 { 4794 MenuItem->fState &= ~MF_HILITE; 4795 } 4796 if (MenuObject->iItem == uItemHilite) return TRUE; 4797 MENU_HideSubPopups( WindowObject, MenuObject, FALSE, 0 ); 4798 MENU_SelectItem( WindowObject, MenuObject, uItemHilite, TRUE, 0 ); 4799 4800 return TRUE; // Always returns true!!!! 4801 } 4802 4803 BOOLEAN APIENTRY 4804 intGetTitleBarInfo(PWND pWindowObject, PTITLEBARINFO bti) 4805 { 4806 4807 DWORD dwStyle = 0; 4808 DWORD dwExStyle = 0; 4809 BOOLEAN retValue = TRUE; 4810 4811 if (bti->cbSize == sizeof(TITLEBARINFO)) 4812 { 4813 RtlZeroMemory(&bti->rgstate[0],sizeof(DWORD)*(CCHILDREN_TITLEBAR+1)); 4814 4815 bti->rgstate[0] = STATE_SYSTEM_FOCUSABLE; 4816 4817 dwStyle = pWindowObject->style; 4818 dwExStyle = pWindowObject->ExStyle; 4819 4820 bti->rcTitleBar.top = 0; 4821 bti->rcTitleBar.left = 0; 4822 bti->rcTitleBar.right = pWindowObject->rcWindow.right - pWindowObject->rcWindow.left; 4823 bti->rcTitleBar.bottom = pWindowObject->rcWindow.bottom - pWindowObject->rcWindow.top; 4824 4825 /* Is it iconiced ? */ 4826 if ((dwStyle & WS_ICONIC)!=WS_ICONIC) 4827 { 4828 /* Remove frame from rectangle */ 4829 if (HAS_THICKFRAME( dwStyle, dwExStyle )) 4830 { 4831 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */ 4832 RECTL_vInflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME) ); 4833 } 4834 else if (HAS_DLGFRAME( dwStyle, dwExStyle )) 4835 { 4836 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */ 4837 RECTL_vInflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME)); 4838 } 4839 else if (HAS_THINFRAME( dwStyle, dwExStyle)) 4840 { 4841 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */ 4842 RECTL_vInflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER) ); 4843 } 4844 4845 /* We have additional border information if the window 4846 * is a child (but not an MDI child) */ 4847 if ( (dwStyle & WS_CHILD) && 4848 ((dwExStyle & WS_EX_MDICHILD) == 0 ) ) 4849 { 4850 if (dwExStyle & WS_EX_CLIENTEDGE) 4851 { 4852 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */ 4853 RECTL_vInflateRect (&bti->rcTitleBar, -UserGetSystemMetrics(SM_CXEDGE), -UserGetSystemMetrics(SM_CYEDGE)); 4854 } 4855 4856 if (dwExStyle & WS_EX_STATICEDGE) 4857 { 4858 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */ 4859 RECTL_vInflateRect (&bti->rcTitleBar, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER)); 4860 } 4861 } 4862 } 4863 4864 bti->rcTitleBar.top += pWindowObject->rcWindow.top; 4865 bti->rcTitleBar.left += pWindowObject->rcWindow.left; 4866 bti->rcTitleBar.right += pWindowObject->rcWindow.left; 4867 4868 bti->rcTitleBar.bottom = bti->rcTitleBar.top; 4869 if (dwExStyle & WS_EX_TOOLWINDOW) 4870 { 4871 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */ 4872 bti->rcTitleBar.bottom += UserGetSystemMetrics(SM_CYSMCAPTION); 4873 } 4874 else 4875 { 4876 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */ 4877 bti->rcTitleBar.bottom += UserGetSystemMetrics(SM_CYCAPTION); 4878 bti->rcTitleBar.left += UserGetSystemMetrics(SM_CXSIZE); 4879 } 4880 4881 if (dwStyle & WS_CAPTION) 4882 { 4883 bti->rgstate[1] = STATE_SYSTEM_INVISIBLE; 4884 if (dwStyle & WS_SYSMENU) 4885 { 4886 if (!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) 4887 { 4888 bti->rgstate[2] = STATE_SYSTEM_INVISIBLE; 4889 bti->rgstate[3] = STATE_SYSTEM_INVISIBLE; 4890 } 4891 else 4892 { 4893 if (!(dwStyle & WS_MINIMIZEBOX)) 4894 { 4895 bti->rgstate[2] = STATE_SYSTEM_UNAVAILABLE; 4896 } 4897 if (!(dwStyle & WS_MAXIMIZEBOX)) 4898 { 4899 bti->rgstate[3] = STATE_SYSTEM_UNAVAILABLE; 4900 } 4901 } 4902 4903 if (!(dwExStyle & WS_EX_CONTEXTHELP)) 4904 { 4905 bti->rgstate[4] = STATE_SYSTEM_INVISIBLE; 4906 } 4907 if (pWindowObject->pcls->style & CS_NOCLOSE) 4908 { 4909 bti->rgstate[5] = STATE_SYSTEM_UNAVAILABLE; 4910 } 4911 } 4912 else 4913 { 4914 bti->rgstate[2] = STATE_SYSTEM_INVISIBLE; 4915 bti->rgstate[3] = STATE_SYSTEM_INVISIBLE; 4916 bti->rgstate[4] = STATE_SYSTEM_INVISIBLE; 4917 bti->rgstate[5] = STATE_SYSTEM_INVISIBLE; 4918 } 4919 } 4920 else 4921 { 4922 bti->rgstate[0] |= STATE_SYSTEM_INVISIBLE; 4923 } 4924 } 4925 else 4926 { 4927 EngSetLastError(ERROR_INVALID_PARAMETER); 4928 retValue = FALSE; 4929 } 4930 4931 return retValue; 4932 } 4933 4934 DWORD FASTCALL 4935 UserInsertMenuItem( 4936 PMENU Menu, 4937 UINT uItem, 4938 BOOL fByPosition, 4939 LPCMENUITEMINFOW UnsafeItemInfo, 4940 PUNICODE_STRING lpstr) 4941 { 4942 NTSTATUS Status; 4943 ROSMENUITEMINFO ItemInfo; 4944 4945 /* Try to copy the whole MENUITEMINFOW structure */ 4946 Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, sizeof(MENUITEMINFOW)); 4947 if (NT_SUCCESS(Status)) 4948 { 4949 if (sizeof(MENUITEMINFOW) != ItemInfo.cbSize 4950 && FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize) 4951 { 4952 EngSetLastError(ERROR_INVALID_PARAMETER); 4953 return FALSE; 4954 } 4955 return IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo, lpstr); 4956 } 4957 4958 /* Try to copy without last field (not present in older versions) */ 4959 Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, FIELD_OFFSET(MENUITEMINFOW, hbmpItem)); 4960 if (NT_SUCCESS(Status)) 4961 { 4962 if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize) 4963 { 4964 EngSetLastError(ERROR_INVALID_PARAMETER); 4965 return FALSE; 4966 } 4967 ItemInfo.hbmpItem = (HBITMAP)0; 4968 return IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo, lpstr); 4969 } 4970 4971 SetLastNtError(Status); 4972 return FALSE; 4973 } 4974 4975 UINT FASTCALL IntGetMenuState( HMENU hMenu, UINT uId, UINT uFlags) 4976 { 4977 PMENU MenuObject; 4978 PITEM pItem; 4979 4980 if (!(MenuObject = UserGetMenuObject(hMenu))) 4981 { 4982 return (UINT)-1; 4983 } 4984 4985 if (!(pItem = MENU_FindItem( &MenuObject, &uId, uFlags ))) return -1; 4986 4987 if (pItem->spSubMenu) 4988 { 4989 return (pItem->spSubMenu->cItems << 8) | ((pItem->fState|pItem->fType|MF_POPUP) & 0xff); 4990 } 4991 else 4992 return (pItem->fType | pItem->fState); 4993 } 4994 4995 HMENU FASTCALL IntGetSubMenu( HMENU hMenu, int nPos) 4996 { 4997 PMENU MenuObject; 4998 PITEM pItem; 4999 5000 if (!(MenuObject = UserGetMenuObject(hMenu))) 5001 { 5002 return NULL; 5003 } 5004 5005 if (!(pItem = MENU_FindItem( &MenuObject, (UINT*)&nPos, MF_BYPOSITION ))) return NULL; 5006 5007 if (pItem->spSubMenu) 5008 { 5009 HMENU hsubmenu = UserHMGetHandle(pItem->spSubMenu); 5010 return hsubmenu; 5011 } 5012 return NULL; 5013 } 5014 5015 UINT FASTCALL IntFindSubMenu(HMENU *hMenu, HMENU hSubTarget ) 5016 { 5017 PMENU menu, pSubTarget; 5018 UINT Pos; 5019 if (((*hMenu)==(HMENU)0xffff) ||(!(menu = UserGetMenuObject(*hMenu)))) 5020 return NO_SELECTED_ITEM; 5021 5022 pSubTarget = UserGetMenuObject(hSubTarget); 5023 5024 Pos = MENU_FindSubMenu(&menu, pSubTarget ); 5025 5026 *hMenu = (menu ? UserHMGetHandle(menu) : NULL); 5027 5028 return Pos; 5029 } 5030 5031 5032 HMENU FASTCALL UserCreateMenu(PDESKTOP Desktop, BOOL PopupMenu) 5033 { 5034 PWINSTATION_OBJECT WinStaObject; 5035 HANDLE Handle; 5036 PMENU Menu; 5037 NTSTATUS Status; 5038 PEPROCESS CurrentProcess = PsGetCurrentProcess(); 5039 5040 if (gpepCSRSS != CurrentProcess) 5041 { 5042 /* 5043 * gpepCSRSS does not have a Win32WindowStation 5044 */ 5045 5046 Status = IntValidateWindowStationHandle(CurrentProcess->Win32WindowStation, 5047 UserMode, 5048 0, 5049 &WinStaObject, 5050 0); 5051 5052 if (!NT_SUCCESS(Status)) 5053 { 5054 ERR("Validation of window station handle (%p) failed\n", 5055 CurrentProcess->Win32WindowStation); 5056 SetLastNtError(Status); 5057 return (HMENU)0; 5058 } 5059 Menu = IntCreateMenu(&Handle, !PopupMenu, Desktop, GetW32ProcessInfo()); 5060 if (Menu && Menu->head.rpdesk->rpwinstaParent != WinStaObject) 5061 { 5062 ERR("Desktop Window Station does not match Process one!\n"); 5063 } 5064 ObDereferenceObject(WinStaObject); 5065 } 5066 else 5067 { 5068 Menu = IntCreateMenu(&Handle, !PopupMenu, GetW32ThreadInfo()->rpdesk, GetW32ProcessInfo()); 5069 } 5070 5071 if (Menu) UserDereferenceObject(Menu); 5072 return (HMENU)Handle; 5073 } 5074 5075 BOOL FASTCALL 5076 IntMenuItemInfo( 5077 PMENU Menu, 5078 UINT Item, 5079 BOOL ByPosition, 5080 PROSMENUITEMINFO ItemInfo, 5081 BOOL SetOrGet, 5082 PUNICODE_STRING lpstr) 5083 { 5084 PITEM MenuItem; 5085 BOOL Ret; 5086 5087 if (!(MenuItem = MENU_FindItem( &Menu, &Item, (ByPosition ? MF_BYPOSITION : MF_BYCOMMAND) ))) 5088 { 5089 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND); 5090 return( FALSE); 5091 } 5092 if (SetOrGet) 5093 { 5094 Ret = IntSetMenuItemInfo(Menu, MenuItem, ItemInfo, lpstr); 5095 } 5096 else 5097 { 5098 Ret = IntGetMenuItemInfo(Menu, MenuItem, ItemInfo); 5099 } 5100 return( Ret); 5101 } 5102 5103 BOOL FASTCALL 5104 UserMenuItemInfo( 5105 PMENU Menu, 5106 UINT Item, 5107 BOOL ByPosition, 5108 PROSMENUITEMINFO UnsafeItemInfo, 5109 BOOL SetOrGet, 5110 PUNICODE_STRING lpstr) 5111 { 5112 PITEM MenuItem; 5113 ROSMENUITEMINFO ItemInfo; 5114 NTSTATUS Status; 5115 UINT Size; 5116 BOOL Ret; 5117 5118 Status = MmCopyFromCaller(&Size, &UnsafeItemInfo->cbSize, sizeof(UINT)); 5119 if (! NT_SUCCESS(Status)) 5120 { 5121 SetLastNtError(Status); 5122 return( FALSE); 5123 } 5124 if ( Size != sizeof(MENUITEMINFOW) && 5125 Size != FIELD_OFFSET(MENUITEMINFOW, hbmpItem) && 5126 Size != sizeof(ROSMENUITEMINFO) ) 5127 { 5128 EngSetLastError(ERROR_INVALID_PARAMETER); 5129 return( FALSE); 5130 } 5131 Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, Size); 5132 if (! NT_SUCCESS(Status)) 5133 { 5134 SetLastNtError(Status); 5135 return( FALSE); 5136 } 5137 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't 5138 set/get hbmpItem */ 5139 if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) == Size 5140 && 0 != (ItemInfo.fMask & MIIM_BITMAP)) 5141 { 5142 EngSetLastError(ERROR_INVALID_PARAMETER); 5143 return( FALSE); 5144 } 5145 5146 if (!(MenuItem = MENU_FindItem( &Menu, &Item, (ByPosition ? MF_BYPOSITION : MF_BYCOMMAND) ))) 5147 { 5148 /* workaround for Word 95: pretend that SC_TASKLIST item exists. */ 5149 if ( SetOrGet && Item == SC_TASKLIST && !ByPosition ) 5150 return TRUE; 5151 5152 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND); 5153 return( FALSE); 5154 } 5155 5156 if (SetOrGet) 5157 { 5158 Ret = IntSetMenuItemInfo(Menu, MenuItem, &ItemInfo, lpstr); 5159 } 5160 else 5161 { 5162 Ret = IntGetMenuItemInfo(Menu, MenuItem, &ItemInfo); 5163 if (Ret) 5164 { 5165 Status = MmCopyToCaller(UnsafeItemInfo, &ItemInfo, Size); 5166 if (! NT_SUCCESS(Status)) 5167 { 5168 SetLastNtError(Status); 5169 return( FALSE); 5170 } 5171 } 5172 } 5173 5174 return( Ret); 5175 } 5176 5177 BOOL FASTCALL 5178 UserMenuInfo( 5179 PMENU Menu, 5180 PROSMENUINFO UnsafeMenuInfo, 5181 BOOL SetOrGet) 5182 { 5183 BOOL Res; 5184 DWORD Size; 5185 NTSTATUS Status; 5186 ROSMENUINFO MenuInfo; 5187 5188 Status = MmCopyFromCaller(&Size, &UnsafeMenuInfo->cbSize, sizeof(DWORD)); 5189 if (! NT_SUCCESS(Status)) 5190 { 5191 SetLastNtError(Status); 5192 return( FALSE); 5193 } 5194 if ( Size < sizeof(MENUINFO) || Size > sizeof(ROSMENUINFO) ) 5195 { 5196 EngSetLastError(ERROR_INVALID_PARAMETER); 5197 return( FALSE); 5198 } 5199 Status = MmCopyFromCaller(&MenuInfo, UnsafeMenuInfo, Size); 5200 if (! NT_SUCCESS(Status)) 5201 { 5202 SetLastNtError(Status); 5203 return( FALSE); 5204 } 5205 5206 if(SetOrGet) 5207 { 5208 /* Set MenuInfo */ 5209 Res = IntSetMenuInfo(Menu, &MenuInfo); 5210 } 5211 else 5212 { 5213 /* Get MenuInfo */ 5214 Res = IntGetMenuInfo(Menu, &MenuInfo); 5215 if (Res) 5216 { 5217 Status = MmCopyToCaller(UnsafeMenuInfo, &MenuInfo, Size); 5218 if (! NT_SUCCESS(Status)) 5219 { 5220 SetLastNtError(Status); 5221 return( FALSE); 5222 } 5223 } 5224 } 5225 5226 return( Res); 5227 } 5228 5229 BOOL FASTCALL 5230 IntGetMenuItemRect( 5231 PWND pWnd, 5232 PMENU Menu, 5233 UINT uItem, 5234 PRECTL Rect) 5235 { 5236 LONG XMove, YMove; 5237 PITEM MenuItem; 5238 UINT I = uItem; 5239 5240 if ((MenuItem = MENU_FindItem (&Menu, &I, MF_BYPOSITION))) 5241 { 5242 Rect->left = MenuItem->xItem; 5243 Rect->top = MenuItem->yItem; 5244 Rect->right = MenuItem->cxItem; // Do this for now...... 5245 Rect->bottom = MenuItem->cyItem; 5246 } 5247 else 5248 { 5249 ERR("Failed Item Lookup! %u\n", uItem); 5250 return FALSE; 5251 } 5252 5253 if (!pWnd) 5254 { 5255 HWND hWnd = Menu->hWnd; 5256 if (!(pWnd = UserGetWindowObject(hWnd))) return FALSE; 5257 } 5258 5259 if (Menu->fFlags & MNF_POPUP) 5260 { 5261 XMove = pWnd->rcClient.left; 5262 YMove = pWnd->rcClient.top; 5263 } 5264 else 5265 { 5266 XMove = pWnd->rcWindow.left; 5267 YMove = pWnd->rcWindow.top; 5268 } 5269 5270 Rect->left += XMove; 5271 Rect->top += YMove; 5272 Rect->right += XMove; 5273 Rect->bottom += YMove; 5274 5275 return TRUE; 5276 } 5277 5278 PMENU FASTCALL MENU_GetSystemMenu(PWND Window, PMENU Popup) 5279 { 5280 PMENU Menu, NewMenu = NULL, SysMenu = NULL; 5281 HMENU hSysMenu, hNewMenu = NULL; 5282 ROSMENUITEMINFO ItemInfoSet = {0}; 5283 ROSMENUITEMINFO ItemInfo = {0}; 5284 UNICODE_STRING MenuName; 5285 5286 hSysMenu = UserCreateMenu(Window->head.rpdesk, FALSE); 5287 if (NULL == hSysMenu) 5288 { 5289 return NULL; 5290 } 5291 SysMenu = UserGetMenuObject(hSysMenu); 5292 if (NULL == SysMenu) 5293 { 5294 UserDestroyMenu(hSysMenu); 5295 return NULL; 5296 } 5297 5298 SysMenu->fFlags |= MNF_SYSMENU; 5299 SysMenu->hWnd = UserHMGetHandle(Window); 5300 5301 if (!Popup) 5302 { 5303 //hNewMenu = co_IntLoadSysMenuTemplate(); 5304 if ( Window->ExStyle & WS_EX_MDICHILD ) 5305 { 5306 RtlInitUnicodeString( &MenuName, L"SYSMENUMDI"); 5307 hNewMenu = co_IntCallLoadMenu( hModClient, &MenuName); 5308 } 5309 else 5310 { 5311 RtlInitUnicodeString( &MenuName, L"SYSMENU"); 5312 hNewMenu = co_IntCallLoadMenu( hModClient, &MenuName); 5313 //ERR("%wZ\n",&MenuName); 5314 } 5315 if (!hNewMenu) 5316 { 5317 ERR("No Menu!!\n"); 5318 IntDestroyMenuObject(SysMenu, FALSE); 5319 return NULL; 5320 } 5321 Menu = UserGetMenuObject(hNewMenu); 5322 if (!Menu) 5323 { 5324 IntDestroyMenuObject(SysMenu, FALSE); 5325 return NULL; 5326 } 5327 5328 // Do the rest in here. 5329 5330 Menu->fFlags |= MNS_CHECKORBMP | MNF_SYSMENU | MNF_POPUP; 5331 5332 ItemInfoSet.cbSize = sizeof( MENUITEMINFOW); 5333 ItemInfoSet.fMask = MIIM_BITMAP; 5334 ItemInfoSet.hbmpItem = HBMMENU_POPUP_CLOSE; 5335 IntMenuItemInfo(Menu, SC_CLOSE, FALSE, &ItemInfoSet, TRUE, NULL); 5336 ItemInfoSet.hbmpItem = HBMMENU_POPUP_RESTORE; 5337 IntMenuItemInfo(Menu, SC_RESTORE, FALSE, &ItemInfoSet, TRUE, NULL); 5338 ItemInfoSet.hbmpItem = HBMMENU_POPUP_MAXIMIZE; 5339 IntMenuItemInfo(Menu, SC_MAXIMIZE, FALSE, &ItemInfoSet, TRUE, NULL); 5340 ItemInfoSet.hbmpItem = HBMMENU_POPUP_MINIMIZE; 5341 IntMenuItemInfo(Menu, SC_MINIMIZE, FALSE, &ItemInfoSet, TRUE, NULL); 5342 5343 NewMenu = IntCloneMenu(Menu); 5344 if (NewMenu == NULL) 5345 { 5346 IntDestroyMenuObject(Menu, FALSE); 5347 IntDestroyMenuObject(SysMenu, FALSE); 5348 return NULL; 5349 } 5350 5351 IntReleaseMenuObject(NewMenu); 5352 UserSetMenuDefaultItem(NewMenu, SC_CLOSE, FALSE); 5353 5354 IntDestroyMenuObject(Menu, FALSE); 5355 } 5356 else 5357 { 5358 NewMenu = Popup; 5359 } 5360 if (NewMenu) 5361 { 5362 NewMenu->fFlags |= MNF_SYSMENU | MNF_POPUP; 5363 5364 if (Window->pcls->style & CS_NOCLOSE) 5365 IntRemoveMenuItem(NewMenu, SC_CLOSE, MF_BYCOMMAND, TRUE); 5366 5367 ItemInfo.cbSize = sizeof(MENUITEMINFOW); 5368 ItemInfo.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_SUBMENU; 5369 ItemInfo.fType = MF_POPUP; 5370 ItemInfo.fState = MFS_ENABLED; 5371 ItemInfo.dwTypeData = NULL; 5372 ItemInfo.cch = 0; 5373 ItemInfo.hSubMenu = UserHMGetHandle(NewMenu); 5374 IntInsertMenuItem(SysMenu, (UINT) -1, TRUE, &ItemInfo, NULL); 5375 5376 return SysMenu; 5377 } 5378 ERR("failed to load system menu!\n"); 5379 return NULL; 5380 } 5381 5382 PMENU FASTCALL 5383 IntGetSystemMenu(PWND Window, BOOL bRevert) 5384 { 5385 PMENU Menu; 5386 5387 if (bRevert) 5388 { 5389 if (Window->SystemMenu) 5390 { 5391 Menu = UserGetMenuObject(Window->SystemMenu); 5392 if (Menu && !(Menu->fFlags & MNF_SYSDESKMN)) 5393 { 5394 IntDestroyMenuObject(Menu, TRUE); 5395 Window->SystemMenu = NULL; 5396 } 5397 } 5398 } 5399 else 5400 { 5401 Menu = Window->SystemMenu ? UserGetMenuObject(Window->SystemMenu) : NULL; 5402 if ((!Menu || Menu->fFlags & MNF_SYSDESKMN) && Window->style & WS_SYSMENU) 5403 { 5404 Menu = MENU_GetSystemMenu(Window, NULL); 5405 Window->SystemMenu = Menu ? UserHMGetHandle(Menu) : NULL; 5406 } 5407 } 5408 5409 if (Window->SystemMenu) 5410 { 5411 HMENU hMenu = IntGetSubMenu( Window->SystemMenu, 0); 5412 /* Store the dummy sysmenu handle to facilitate the refresh */ 5413 /* of the close button if the SC_CLOSE item change */ 5414 Menu = UserGetMenuObject(hMenu); 5415 if (Menu) 5416 { 5417 Menu->spwndNotify = Window; 5418 Menu->fFlags |= MNF_SYSSUBMENU; 5419 } 5420 return Menu; 5421 } 5422 return NULL; 5423 } 5424 5425 BOOL FASTCALL 5426 IntSetSystemMenu(PWND Window, PMENU Menu) 5427 { 5428 PMENU OldMenu; 5429 5430 if (!(Window->style & WS_SYSMENU)) return FALSE; 5431 5432 if (Window->SystemMenu) 5433 { 5434 OldMenu = UserGetMenuObject(Window->SystemMenu); 5435 if (OldMenu) 5436 { 5437 OldMenu->fFlags &= ~MNF_SYSMENU; 5438 IntDestroyMenuObject(OldMenu, TRUE); 5439 } 5440 } 5441 5442 OldMenu = MENU_GetSystemMenu(Window, Menu); 5443 if (OldMenu) 5444 { // Use spmenuSys too! 5445 Window->SystemMenu = UserHMGetHandle(OldMenu); 5446 } 5447 else 5448 Window->SystemMenu = NULL; 5449 5450 if (Menu && Window != Menu->spwndNotify) 5451 { 5452 Menu->spwndNotify = Window; 5453 } 5454 5455 return TRUE; 5456 } 5457 5458 BOOL FASTCALL 5459 IntSetMenu( 5460 PWND Wnd, 5461 HMENU Menu, 5462 BOOL *Changed) 5463 { 5464 PMENU OldMenu, NewMenu = NULL; 5465 5466 if ((Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD) 5467 { 5468 ERR("SetMenu: Window is a Child 0x%p!\n",UserHMGetHandle(Wnd)); 5469 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE); 5470 return FALSE; 5471 } 5472 5473 *Changed = (UlongToHandle(Wnd->IDMenu) != Menu); 5474 if (! *Changed) 5475 { 5476 return TRUE; 5477 } 5478 5479 if (Wnd->IDMenu) 5480 { 5481 OldMenu = IntGetMenuObject(UlongToHandle(Wnd->IDMenu)); 5482 ASSERT(NULL == OldMenu || OldMenu->hWnd == UserHMGetHandle(Wnd)); 5483 } 5484 else 5485 { 5486 OldMenu = NULL; 5487 } 5488 5489 if (NULL != Menu) 5490 { 5491 NewMenu = IntGetMenuObject(Menu); 5492 if (NULL == NewMenu) 5493 { 5494 if (NULL != OldMenu) 5495 { 5496 IntReleaseMenuObject(OldMenu); 5497 } 5498 EngSetLastError(ERROR_INVALID_MENU_HANDLE); 5499 return FALSE; 5500 } 5501 if (NULL != NewMenu->hWnd) 5502 { 5503 /* Can't use the same menu for two windows */ 5504 if (NULL != OldMenu) 5505 { 5506 IntReleaseMenuObject(OldMenu); 5507 } 5508 EngSetLastError(ERROR_INVALID_MENU_HANDLE); 5509 return FALSE; 5510 } 5511 5512 } 5513 5514 Wnd->IDMenu = (UINT_PTR) Menu; 5515 if (NULL != NewMenu) 5516 { 5517 NewMenu->hWnd = UserHMGetHandle(Wnd); 5518 IntReleaseMenuObject(NewMenu); 5519 } 5520 if (NULL != OldMenu) 5521 { 5522 OldMenu->hWnd = NULL; 5523 IntReleaseMenuObject(OldMenu); 5524 } 5525 5526 return TRUE; 5527 } 5528 5529 5530 /* FUNCTIONS *****************************************************************/ 5531 5532 /* 5533 * @implemented 5534 */ 5535 /* http://www.cyber-ta.org/releases/malware-analysis/public/SOURCES/b47155634ccb2c30630da7e3666d3d07/b47155634ccb2c30630da7e3666d3d07.trace.html#NtUserGetIconSize */ 5536 DWORD 5537 APIENTRY 5538 NtUserCalcMenuBar( 5539 HWND hwnd, 5540 DWORD leftBorder, 5541 DWORD rightBorder, 5542 DWORD top, 5543 LPRECT prc ) 5544 { 5545 HDC hdc; 5546 PWND Window; 5547 RECT Rect; 5548 DWORD ret; 5549 5550 UserEnterExclusive(); 5551 5552 if(!(Window = UserGetWindowObject(hwnd))) 5553 { 5554 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE); 5555 UserLeave(); 5556 return 0; 5557 } 5558 5559 hdc = UserGetDCEx(NULL, NULL, DCX_CACHE); 5560 if (!hdc) 5561 { 5562 UserLeave(); 5563 return 0; 5564 } 5565 5566 Rect.left = leftBorder; 5567 Rect.right = Window->rcWindow.right - Window->rcWindow.left - rightBorder; 5568 Rect.top = top; 5569 Rect.bottom = 0; 5570 5571 ret = MENU_DrawMenuBar(hdc, &Rect, Window, TRUE); 5572 5573 UserReleaseDC( 0, hdc, FALSE ); 5574 5575 UserLeave(); 5576 5577 return ret; 5578 } 5579 5580 /* 5581 * @implemented 5582 */ 5583 DWORD APIENTRY 5584 NtUserCheckMenuItem( 5585 HMENU hMenu, 5586 UINT uIDCheckItem, 5587 UINT uCheck) 5588 { 5589 PMENU Menu; 5590 DECLARE_RETURN(DWORD); 5591 5592 TRACE("Enter NtUserCheckMenuItem\n"); 5593 UserEnterExclusive(); 5594 5595 if(!(Menu = UserGetMenuObject(hMenu))) 5596 { 5597 RETURN( (DWORD)-1); 5598 } 5599 5600 RETURN( IntCheckMenuItem(Menu, uIDCheckItem, uCheck)); 5601 5602 CLEANUP: 5603 TRACE("Leave NtUserCheckMenuItem, ret=%lu\n",_ret_); 5604 UserLeave(); 5605 END_CLEANUP; 5606 } 5607 5608 /* 5609 * @implemented 5610 */ 5611 BOOL APIENTRY 5612 NtUserDeleteMenu( 5613 HMENU hMenu, 5614 UINT uPosition, 5615 UINT uFlags) 5616 { 5617 PMENU Menu; 5618 DECLARE_RETURN(BOOL); 5619 5620 TRACE("Enter NtUserDeleteMenu\n"); 5621 UserEnterExclusive(); 5622 5623 if(!(Menu = UserGetMenuObject(hMenu))) 5624 { 5625 RETURN( FALSE); 5626 } 5627 5628 RETURN( IntRemoveMenuItem(Menu, uPosition, uFlags, TRUE)); 5629 5630 CLEANUP: 5631 TRACE("Leave NtUserDeleteMenu, ret=%i\n",_ret_); 5632 UserLeave(); 5633 END_CLEANUP; 5634 } 5635 5636 /* 5637 * NtUserGetSystemMenu 5638 * 5639 * The NtUserGetSystemMenu function allows the application to access the 5640 * window menu (also known as the system menu or the control menu) for 5641 * copying and modifying. 5642 * 5643 * Parameters 5644 * hWnd 5645 * Handle to the window that will own a copy of the window menu. 5646 * bRevert 5647 * Specifies the action to be taken. If this parameter is FALSE, 5648 * NtUserGetSystemMenu returns a handle to the copy of the window menu 5649 * currently in use. The copy is initially identical to the window menu 5650 * but it can be modified. 5651 * If this parameter is TRUE, GetSystemMenu resets the window menu back 5652 * to the default state. The previous window menu, if any, is destroyed. 5653 * 5654 * Return Value 5655 * If the bRevert parameter is FALSE, the return value is a handle to a 5656 * copy of the window menu. If the bRevert parameter is TRUE, the return 5657 * value is NULL. 5658 * 5659 * Status 5660 * @implemented 5661 */ 5662 5663 HMENU APIENTRY 5664 NtUserGetSystemMenu(HWND hWnd, BOOL bRevert) 5665 { 5666 PWND Window; 5667 PMENU Menu; 5668 DECLARE_RETURN(HMENU); 5669 5670 TRACE("Enter NtUserGetSystemMenu\n"); 5671 UserEnterExclusive(); 5672 5673 if (!(Window = UserGetWindowObject(hWnd))) 5674 { 5675 RETURN(NULL); 5676 } 5677 5678 if (!(Menu = IntGetSystemMenu(Window, bRevert))) 5679 { 5680 RETURN(NULL); 5681 } 5682 5683 RETURN(Menu->head.h); 5684 5685 CLEANUP: 5686 TRACE("Leave NtUserGetSystemMenu, ret=%p\n", _ret_); 5687 UserLeave(); 5688 END_CLEANUP; 5689 } 5690 5691 /* 5692 * NtUserSetSystemMenu 5693 * 5694 * Status 5695 * @implemented 5696 */ 5697 5698 BOOL APIENTRY 5699 NtUserSetSystemMenu(HWND hWnd, HMENU hMenu) 5700 { 5701 BOOL Result = FALSE; 5702 PWND Window; 5703 PMENU Menu; 5704 DECLARE_RETURN(BOOL); 5705 5706 TRACE("Enter NtUserSetSystemMenu\n"); 5707 UserEnterExclusive(); 5708 5709 if (!(Window = UserGetWindowObject(hWnd))) 5710 { 5711 RETURN( FALSE); 5712 } 5713 5714 if (hMenu) 5715 { 5716 /* 5717 * Assign new menu handle and Up the Lock Count. 5718 */ 5719 if (!(Menu = IntGetMenuObject(hMenu))) 5720 { 5721 RETURN( FALSE); 5722 } 5723 5724 Result = IntSetSystemMenu(Window, Menu); 5725 } 5726 else 5727 EngSetLastError(ERROR_INVALID_MENU_HANDLE); 5728 5729 RETURN( Result); 5730 5731 CLEANUP: 5732 TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_); 5733 UserLeave(); 5734 END_CLEANUP; 5735 } 5736 5737 /* 5738 * @implemented 5739 */ 5740 BOOLEAN APIENTRY 5741 NtUserGetTitleBarInfo( 5742 HWND hwnd, 5743 PTITLEBARINFO bti) 5744 { 5745 PWND WindowObject; 5746 TITLEBARINFO bartitleinfo; 5747 DECLARE_RETURN(BOOLEAN); 5748 BOOLEAN retValue = TRUE; 5749 5750 TRACE("Enter NtUserGetTitleBarInfo\n"); 5751 UserEnterExclusive(); 5752 5753 /* Vaildate the windows handle */ 5754 if (!(WindowObject = UserGetWindowObject(hwnd))) 5755 { 5756 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE); 5757 retValue = FALSE; 5758 } 5759 5760 _SEH2_TRY 5761 { 5762 /* Copy our usermode buffer bti to local buffer bartitleinfo */ 5763 ProbeForRead(bti, sizeof(TITLEBARINFO), 1); 5764 RtlCopyMemory(&bartitleinfo, bti, sizeof(TITLEBARINFO)); 5765 } 5766 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 5767 { 5768 /* Fail copy the data */ 5769 EngSetLastError(ERROR_INVALID_PARAMETER); 5770 retValue = FALSE; 5771 } 5772 _SEH2_END 5773 5774 /* Get the tile bar info */ 5775 if (retValue) 5776 { 5777 retValue = intGetTitleBarInfo(WindowObject, &bartitleinfo); 5778 if (retValue) 5779 { 5780 _SEH2_TRY 5781 { 5782 /* Copy our buffer to user mode buffer bti */ 5783 ProbeForWrite(bti, sizeof(TITLEBARINFO), 1); 5784 RtlCopyMemory(bti, &bartitleinfo, sizeof(TITLEBARINFO)); 5785 } 5786 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 5787 { 5788 /* Fail copy the data */ 5789 EngSetLastError(ERROR_INVALID_PARAMETER); 5790 retValue = FALSE; 5791 } 5792 _SEH2_END 5793 } 5794 } 5795 5796 RETURN( retValue ); 5797 5798 CLEANUP: 5799 TRACE("Leave NtUserGetTitleBarInfo, ret=%u\n",_ret_); 5800 UserLeave(); 5801 END_CLEANUP; 5802 } 5803 5804 /* 5805 * @implemented 5806 */ 5807 BOOL FASTCALL UserDestroyMenu(HMENU hMenu) 5808 { 5809 PMENU Menu; 5810 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 5811 5812 if(!(Menu = UserGetMenuObject(hMenu))) 5813 { 5814 return FALSE; 5815 } 5816 5817 if (Menu->head.rpdesk != pti->rpdesk) 5818 { 5819 EngSetLastError(ERROR_ACCESS_DENIED); 5820 return FALSE; 5821 } 5822 return IntDestroyMenuObject(Menu, FALSE); 5823 } 5824 5825 /* 5826 * @implemented 5827 */ 5828 BOOL APIENTRY 5829 NtUserDestroyMenu( 5830 HMENU hMenu) 5831 { 5832 PMENU Menu; 5833 DECLARE_RETURN(BOOL); 5834 5835 TRACE("Enter NtUserDestroyMenu\n"); 5836 UserEnterExclusive(); 5837 5838 if(!(Menu = UserGetMenuObject(hMenu))) 5839 { 5840 RETURN( FALSE); 5841 } 5842 if (Menu->head.rpdesk != gptiCurrent->rpdesk) 5843 { 5844 EngSetLastError(ERROR_ACCESS_DENIED); 5845 RETURN( FALSE); 5846 } 5847 RETURN( IntDestroyMenuObject(Menu, TRUE)); 5848 5849 CLEANUP: 5850 TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_); 5851 UserLeave(); 5852 END_CLEANUP; 5853 } 5854 5855 /* 5856 * @implemented 5857 */ 5858 UINT APIENTRY 5859 NtUserEnableMenuItem( 5860 HMENU hMenu, 5861 UINT uIDEnableItem, 5862 UINT uEnable) 5863 { 5864 PMENU Menu; 5865 DECLARE_RETURN(UINT); 5866 5867 TRACE("Enter NtUserEnableMenuItem\n"); 5868 UserEnterExclusive(); 5869 5870 if(!(Menu = UserGetMenuObject(hMenu))) 5871 { 5872 RETURN(-1); 5873 } 5874 5875 RETURN( IntEnableMenuItem(Menu, uIDEnableItem, uEnable)); 5876 5877 CLEANUP: 5878 TRACE("Leave NtUserEnableMenuItem, ret=%u\n",_ret_); 5879 UserLeave(); 5880 END_CLEANUP; 5881 } 5882 5883 /* 5884 * @implemented 5885 */ 5886 BOOL APIENTRY 5887 NtUserEndMenu(VOID) 5888 { 5889 //PWND pWnd; 5890 TRACE("Enter NtUserEndMenu\n"); 5891 UserEnterExclusive(); 5892 /* if ( gptiCurrent->pMenuState && 5893 gptiCurrent->pMenuState->pGlobalPopupMenu ) 5894 { 5895 pWnd = IntGetMSWND(gptiCurrent->pMenuState); 5896 if (pWnd) 5897 { 5898 UserPostMessage( UserHMGetHandle(pWnd), WM_CANCELMODE, 0, 0); 5899 } 5900 else 5901 gptiCurrent->pMenuState->fInsideMenuLoop = FALSE; 5902 }*/ 5903 if (fInsideMenuLoop && top_popup) 5904 { 5905 fInsideMenuLoop = FALSE; 5906 UserPostMessage( top_popup, WM_CANCELMODE, 0, 0); 5907 } 5908 UserLeave(); 5909 TRACE("Leave NtUserEndMenu\n"); 5910 return TRUE; 5911 } 5912 5913 /* 5914 * @implemented 5915 */ 5916 BOOL APIENTRY 5917 NtUserGetMenuBarInfo( 5918 HWND hwnd, 5919 LONG idObject, 5920 LONG idItem, 5921 PMENUBARINFO pmbi) 5922 { 5923 PWND pWnd; 5924 HMENU hMenu; 5925 MENUBARINFO kmbi; 5926 BOOL Ret; 5927 PPOPUPMENU pPopupMenu; 5928 USER_REFERENCE_ENTRY Ref; 5929 NTSTATUS Status = STATUS_SUCCESS; 5930 PMENU Menu = NULL; 5931 DECLARE_RETURN(BOOL); 5932 5933 TRACE("Enter NtUserGetMenuBarInfo\n"); 5934 UserEnterShared(); 5935 5936 if (!(pWnd = UserGetWindowObject(hwnd))) 5937 { 5938 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE); 5939 RETURN(FALSE); 5940 } 5941 5942 UserRefObjectCo(pWnd, &Ref); 5943 5944 RECTL_vSetEmptyRect(&kmbi.rcBar); 5945 kmbi.hMenu = NULL; 5946 kmbi.hwndMenu = NULL; 5947 kmbi.fBarFocused = FALSE; 5948 kmbi.fFocused = FALSE; 5949 5950 switch (idObject) 5951 { 5952 case OBJID_CLIENT: 5953 if (!pWnd->pcls->fnid) 5954 RETURN(FALSE); 5955 if (pWnd->pcls->fnid != FNID_MENU) 5956 { 5957 WARN("called on invalid window: %u\n", pWnd->pcls->fnid); 5958 EngSetLastError(ERROR_INVALID_MENU_HANDLE); 5959 RETURN(FALSE); 5960 } 5961 // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW. 5962 hMenu = (HMENU)co_IntSendMessage(hwnd, MN_GETHMENU, 0, 0); 5963 pPopupMenu = ((PMENUWND)pWnd)->ppopupmenu; 5964 if (pPopupMenu && pPopupMenu->spmenu) 5965 { 5966 if (UserHMGetHandle(pPopupMenu->spmenu) != hMenu) 5967 { 5968 ERR("Window Pop Up hMenu %p not the same as Get hMenu %p!\n",pPopupMenu->spmenu->head.h,hMenu); 5969 } 5970 } 5971 break; 5972 case OBJID_MENU: 5973 if (pWnd->style & WS_CHILD) RETURN(FALSE); 5974 hMenu = UlongToHandle(pWnd->IDMenu); 5975 TRACE("GMBI: OBJID_MENU hMenu %p\n",hMenu); 5976 break; 5977 case OBJID_SYSMENU: 5978 if (!(pWnd->style & WS_SYSMENU)) RETURN(FALSE); 5979 Menu = IntGetSystemMenu(pWnd, FALSE); 5980 hMenu = UserHMGetHandle(Menu); 5981 break; 5982 default: 5983 RETURN(FALSE); 5984 } 5985 5986 if (!hMenu) 5987 RETURN(FALSE); 5988 5989 _SEH2_TRY 5990 { 5991 ProbeForRead(pmbi, sizeof(MENUBARINFO), 1); 5992 kmbi.cbSize = pmbi->cbSize; 5993 } 5994 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 5995 { 5996 kmbi.cbSize = 0; 5997 } 5998 _SEH2_END 5999 6000 if (kmbi.cbSize != sizeof(MENUBARINFO)) 6001 { 6002 EngSetLastError(ERROR_INVALID_PARAMETER); 6003 RETURN(FALSE); 6004 } 6005 6006 if (!Menu) Menu = UserGetMenuObject(hMenu); 6007 if (!Menu) 6008 RETURN(FALSE); 6009 6010 if ((idItem < 0) || ((ULONG)idItem > Menu->cItems)) 6011 RETURN(FALSE); 6012 6013 if (idItem == 0) 6014 { 6015 Ret = IntGetMenuItemRect(pWnd, Menu, 0, &kmbi.rcBar); 6016 kmbi.rcBar.right = kmbi.rcBar.left + Menu->cxMenu; 6017 kmbi.rcBar.bottom = kmbi.rcBar.top + Menu->cyMenu; 6018 TRACE("idItem a 0 %d\n",Ret); 6019 } 6020 else 6021 { 6022 Ret = IntGetMenuItemRect(pWnd, Menu, idItem-1, &kmbi.rcBar); 6023 TRACE("idItem b %d %d\n", idItem-1, Ret); 6024 } 6025 6026 kmbi.hMenu = hMenu; 6027 kmbi.fBarFocused = top_popup_hmenu == hMenu; 6028 TRACE("GMBI: top p hm %p hMenu %p\n",top_popup_hmenu, hMenu); 6029 if (idItem) 6030 { 6031 kmbi.fFocused = Menu->iItem == idItem-1; 6032 if (kmbi.fFocused && (Menu->rgItems[idItem - 1].spSubMenu)) 6033 { 6034 kmbi.hwndMenu = Menu->rgItems[idItem - 1].spSubMenu->hWnd; 6035 } 6036 } 6037 else 6038 { 6039 kmbi.fFocused = kmbi.fBarFocused; 6040 } 6041 6042 _SEH2_TRY 6043 { 6044 ProbeForWrite(pmbi, sizeof(MENUBARINFO), 1); 6045 RtlCopyMemory(pmbi, &kmbi, sizeof(MENUBARINFO)); 6046 } 6047 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6048 { 6049 Status = _SEH2_GetExceptionCode(); 6050 } 6051 _SEH2_END 6052 6053 if (!NT_SUCCESS(Status)) 6054 { 6055 SetLastNtError(Status); 6056 RETURN(FALSE); 6057 } 6058 6059 RETURN(TRUE); 6060 6061 CLEANUP: 6062 if (pWnd) UserDerefObjectCo(pWnd); 6063 TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_); 6064 UserLeave(); 6065 END_CLEANUP; 6066 } 6067 6068 /* 6069 * @implemented 6070 */ 6071 UINT APIENTRY 6072 NtUserGetMenuIndex( 6073 HMENU hMenu, 6074 HMENU hSubMenu) 6075 { 6076 PMENU Menu, SubMenu; 6077 PITEM MenuItem; 6078 UINT i; 6079 DECLARE_RETURN(UINT); 6080 6081 TRACE("Enter NtUserGetMenuIndex\n"); 6082 UserEnterShared(); 6083 6084 if ( !(Menu = UserGetMenuObject(hMenu)) || 6085 !(SubMenu = UserGetMenuObject(hSubMenu)) ) 6086 RETURN(0xFFFFFFFF); 6087 6088 MenuItem = Menu->rgItems; 6089 for (i = 0; i < Menu->cItems; i++, MenuItem++) 6090 { 6091 if (MenuItem->spSubMenu == SubMenu) 6092 RETURN(MenuItem->wID); 6093 } 6094 RETURN(0xFFFFFFFF); 6095 6096 CLEANUP: 6097 TRACE("Leave NtUserGetMenuIndex, ret=%u\n",_ret_); 6098 UserLeave(); 6099 END_CLEANUP; 6100 } 6101 6102 /* 6103 * @implemented 6104 */ 6105 BOOL APIENTRY 6106 NtUserGetMenuItemRect( 6107 HWND hWnd, 6108 HMENU hMenu, 6109 UINT uItem, 6110 PRECTL lprcItem) 6111 { 6112 PWND ReferenceWnd; 6113 LONG XMove, YMove; 6114 RECTL Rect; 6115 PMENU Menu; 6116 PITEM MenuItem; 6117 NTSTATUS Status = STATUS_SUCCESS; 6118 DECLARE_RETURN(BOOL); 6119 6120 TRACE("Enter NtUserGetMenuItemRect\n"); 6121 UserEnterShared(); 6122 6123 if (!(Menu = UserGetMenuObject(hMenu))) 6124 { 6125 RETURN(FALSE); 6126 } 6127 6128 if ((MenuItem = MENU_FindItem (&Menu, &uItem, MF_BYPOSITION))) 6129 { 6130 Rect.left = MenuItem->xItem; 6131 Rect.top = MenuItem->yItem; 6132 Rect.right = MenuItem->cxItem; // Do this for now...... 6133 Rect.bottom = MenuItem->cyItem; 6134 } 6135 else 6136 RETURN(FALSE); 6137 6138 if(!hWnd) 6139 { 6140 hWnd = Menu->hWnd; 6141 } 6142 6143 if (lprcItem == NULL) RETURN( FALSE); 6144 6145 if (!(ReferenceWnd = UserGetWindowObject(hWnd))) RETURN( FALSE); 6146 6147 if (Menu->fFlags & MNF_POPUP) 6148 { 6149 XMove = ReferenceWnd->rcClient.left; 6150 YMove = ReferenceWnd->rcClient.top; 6151 } 6152 else 6153 { 6154 XMove = ReferenceWnd->rcWindow.left; 6155 YMove = ReferenceWnd->rcWindow.top; 6156 } 6157 6158 Rect.left += XMove; 6159 Rect.top += YMove; 6160 Rect.right += XMove; 6161 Rect.bottom += YMove; 6162 6163 _SEH2_TRY 6164 { 6165 RtlCopyMemory(lprcItem, &Rect, sizeof(RECTL)); 6166 } 6167 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6168 { 6169 Status = _SEH2_GetExceptionCode(); 6170 } 6171 _SEH2_END 6172 6173 if (!NT_SUCCESS(Status)) 6174 { 6175 SetLastNtError(Status); 6176 RETURN(FALSE); 6177 } 6178 RETURN(TRUE); 6179 6180 CLEANUP: 6181 TRACE("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_); 6182 UserLeave(); 6183 END_CLEANUP; 6184 } 6185 6186 /* 6187 * @implemented 6188 */ 6189 BOOL APIENTRY 6190 NtUserHiliteMenuItem( 6191 HWND hWnd, 6192 HMENU hMenu, 6193 UINT uItemHilite, 6194 UINT uHilite) 6195 { 6196 PMENU Menu; 6197 PWND Window; 6198 DECLARE_RETURN(BOOLEAN); 6199 6200 TRACE("Enter NtUserHiliteMenuItem\n"); 6201 UserEnterExclusive(); 6202 6203 if(!(Window = UserGetWindowObject(hWnd))) 6204 { 6205 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE); 6206 RETURN(FALSE); 6207 } 6208 6209 if(!(Menu = UserGetMenuObject(hMenu))) 6210 { 6211 EngSetLastError(ERROR_INVALID_MENU_HANDLE); 6212 RETURN(FALSE); 6213 } 6214 6215 RETURN( IntHiliteMenuItem(Window, Menu, uItemHilite, uHilite)); 6216 6217 CLEANUP: 6218 TRACE("Leave NtUserHiliteMenuItem, ret=%u\n",_ret_); 6219 UserLeave(); 6220 END_CLEANUP; 6221 } 6222 6223 /* 6224 * @implemented 6225 */ 6226 DWORD 6227 APIENTRY 6228 NtUserDrawMenuBarTemp( 6229 HWND hWnd, 6230 HDC hDC, 6231 PRECT pRect, 6232 HMENU hMenu, 6233 HFONT hFont) 6234 { 6235 PMENU Menu; 6236 PWND Window; 6237 RECT Rect; 6238 NTSTATUS Status = STATUS_SUCCESS; 6239 DECLARE_RETURN(DWORD); 6240 6241 ERR("Enter NtUserDrawMenuBarTemp\n"); 6242 UserEnterExclusive(); 6243 6244 if(!(Window = UserGetWindowObject(hWnd))) 6245 { 6246 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE); 6247 RETURN(0); 6248 } 6249 6250 if(!(Menu = UserGetMenuObject(hMenu))) 6251 { 6252 EngSetLastError(ERROR_INVALID_MENU_HANDLE); 6253 RETURN(0); 6254 } 6255 6256 _SEH2_TRY 6257 { 6258 ProbeForRead(pRect, sizeof(RECT), sizeof(ULONG)); 6259 RtlCopyMemory(&Rect, pRect, sizeof(RECT)); 6260 } 6261 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6262 { 6263 Status = _SEH2_GetExceptionCode(); 6264 } 6265 _SEH2_END; 6266 6267 if (Status != STATUS_SUCCESS) 6268 { 6269 SetLastNtError(Status); 6270 RETURN(0); 6271 } 6272 6273 RETURN( IntDrawMenuBarTemp(Window, hDC, &Rect, Menu, hFont)); 6274 6275 CLEANUP: 6276 ERR("Leave NtUserDrawMenuBarTemp, ret=%u\n",_ret_); 6277 UserLeave(); 6278 END_CLEANUP; 6279 } 6280 6281 /* 6282 * @implemented 6283 */ 6284 int APIENTRY 6285 NtUserMenuItemFromPoint( 6286 HWND hWnd, 6287 HMENU hMenu, 6288 DWORD X, 6289 DWORD Y) 6290 { 6291 PMENU Menu; 6292 PWND Window = NULL; 6293 PITEM mi; 6294 ULONG i; 6295 DECLARE_RETURN(int); 6296 6297 TRACE("Enter NtUserMenuItemFromPoint\n"); 6298 UserEnterExclusive(); 6299 6300 if (!(Menu = UserGetMenuObject(hMenu))) 6301 { 6302 RETURN( -1); 6303 } 6304 6305 if (!(Window = UserGetWindowObject(Menu->hWnd))) 6306 { 6307 RETURN( -1); 6308 } 6309 6310 X -= Window->rcWindow.left; 6311 Y -= Window->rcWindow.top; 6312 6313 mi = Menu->rgItems; 6314 for (i = 0; i < Menu->cItems; i++, mi++) 6315 { 6316 RECTL Rect; 6317 6318 Rect.left = mi->xItem; 6319 Rect.top = mi->yItem; 6320 Rect.right = mi->cxItem; 6321 Rect.bottom = mi->cyItem; 6322 6323 MENU_AdjustMenuItemRect(Menu, &Rect); 6324 6325 if (RECTL_bPointInRect(&Rect, X, Y)) 6326 { 6327 break; 6328 } 6329 } 6330 6331 RETURN( (mi ? i : NO_SELECTED_ITEM)); 6332 6333 CLEANUP: 6334 TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_); 6335 UserLeave(); 6336 END_CLEANUP; 6337 } 6338 6339 6340 DWORD 6341 APIENTRY 6342 NtUserPaintMenuBar( 6343 HWND hWnd, 6344 HDC hDC, 6345 ULONG leftBorder, 6346 ULONG rightBorder, 6347 ULONG top, 6348 BOOL bActive) 6349 { 6350 PWND Window; 6351 RECT Rect; 6352 DWORD ret; 6353 6354 UserEnterExclusive(); 6355 6356 if(!(Window = UserGetWindowObject(hWnd))) 6357 { 6358 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE); 6359 UserLeave(); 6360 return 0; 6361 } 6362 6363 Rect.left = leftBorder; 6364 Rect.right = Window->rcWindow.right - Window->rcWindow.left - rightBorder; 6365 Rect.top = top; 6366 Rect.bottom = 0; 6367 6368 ret = MENU_DrawMenuBar(hDC, &Rect, Window, FALSE); 6369 6370 UserLeave(); 6371 6372 return ret; 6373 } 6374 6375 /* 6376 * @implemented 6377 */ 6378 BOOL APIENTRY 6379 NtUserRemoveMenu( 6380 HMENU hMenu, 6381 UINT uPosition, 6382 UINT uFlags) 6383 { 6384 PMENU Menu; 6385 DECLARE_RETURN(BOOL); 6386 6387 TRACE("Enter NtUserRemoveMenu\n"); 6388 UserEnterExclusive(); 6389 6390 if(!(Menu = UserGetMenuObject(hMenu))) 6391 { 6392 RETURN( FALSE); 6393 } 6394 6395 RETURN(IntRemoveMenuItem(Menu, uPosition, uFlags, FALSE)); 6396 6397 CLEANUP: 6398 TRACE("Leave NtUserRemoveMenu, ret=%i\n",_ret_); 6399 UserLeave(); 6400 END_CLEANUP; 6401 6402 } 6403 6404 /* 6405 * @implemented 6406 */ 6407 BOOL APIENTRY 6408 NtUserSetMenu( 6409 HWND hWnd, 6410 HMENU Menu, 6411 BOOL Repaint) 6412 { 6413 PWND Window; 6414 BOOL Changed; 6415 DECLARE_RETURN(BOOL); 6416 6417 TRACE("Enter NtUserSetMenu\n"); 6418 UserEnterExclusive(); 6419 6420 if (!(Window = UserGetWindowObject(hWnd))) 6421 { 6422 RETURN( FALSE); 6423 } 6424 6425 if (!IntSetMenu(Window, Menu, &Changed)) 6426 { 6427 RETURN( FALSE); 6428 } 6429 6430 // Not minimized and please repaint!!! 6431 if (!(Window->style & WS_MINIMIZE) && (Repaint || Changed)) 6432 { 6433 USER_REFERENCE_ENTRY Ref; 6434 UserRefObjectCo(Window, &Ref); 6435 co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED); 6436 UserDerefObjectCo(Window); 6437 } 6438 6439 RETURN( TRUE); 6440 6441 CLEANUP: 6442 TRACE("Leave NtUserSetMenu, ret=%i\n",_ret_); 6443 UserLeave(); 6444 END_CLEANUP; 6445 } 6446 6447 /* 6448 * @implemented 6449 */ 6450 BOOL APIENTRY 6451 NtUserSetMenuContextHelpId( 6452 HMENU hMenu, 6453 DWORD dwContextHelpId) 6454 { 6455 PMENU Menu; 6456 DECLARE_RETURN(BOOL); 6457 6458 TRACE("Enter NtUserSetMenuContextHelpId\n"); 6459 UserEnterExclusive(); 6460 6461 if(!(Menu = UserGetMenuObject(hMenu))) 6462 { 6463 RETURN( FALSE); 6464 } 6465 6466 RETURN(IntSetMenuContextHelpId(Menu, dwContextHelpId)); 6467 6468 CLEANUP: 6469 TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_); 6470 UserLeave(); 6471 END_CLEANUP; 6472 } 6473 6474 /* 6475 * @implemented 6476 */ 6477 BOOL APIENTRY 6478 NtUserSetMenuDefaultItem( 6479 HMENU hMenu, 6480 UINT uItem, 6481 UINT fByPos) 6482 { 6483 PMENU Menu; 6484 DECLARE_RETURN(BOOL); 6485 6486 TRACE("Enter NtUserSetMenuDefaultItem\n"); 6487 UserEnterExclusive(); 6488 6489 if(!(Menu = UserGetMenuObject(hMenu))) 6490 { 6491 RETURN( FALSE); 6492 } 6493 6494 RETURN( UserSetMenuDefaultItem(Menu, uItem, fByPos)); 6495 6496 CLEANUP: 6497 TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_); 6498 UserLeave(); 6499 END_CLEANUP; 6500 } 6501 6502 /* 6503 * @implemented 6504 */ 6505 BOOL APIENTRY 6506 NtUserSetMenuFlagRtoL( 6507 HMENU hMenu) 6508 { 6509 PMENU Menu; 6510 DECLARE_RETURN(BOOL); 6511 6512 TRACE("Enter NtUserSetMenuFlagRtoL\n"); 6513 UserEnterExclusive(); 6514 6515 if(!(Menu = UserGetMenuObject(hMenu))) 6516 { 6517 RETURN( FALSE); 6518 } 6519 6520 RETURN(IntSetMenuFlagRtoL(Menu)); 6521 6522 CLEANUP: 6523 TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_); 6524 UserLeave(); 6525 END_CLEANUP; 6526 } 6527 6528 /* 6529 * @implemented 6530 */ 6531 BOOL APIENTRY 6532 NtUserThunkedMenuInfo( 6533 HMENU hMenu, 6534 LPCMENUINFO lpcmi) 6535 { 6536 PMENU Menu; 6537 DECLARE_RETURN(BOOL); 6538 6539 TRACE("Enter NtUserThunkedMenuInfo\n"); 6540 UserEnterExclusive(); 6541 6542 if (!(Menu = UserGetMenuObject(hMenu))) 6543 { 6544 RETURN(FALSE); 6545 } 6546 6547 RETURN(UserMenuInfo(Menu, (PROSMENUINFO)lpcmi, TRUE)); 6548 6549 CLEANUP: 6550 TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n",_ret_); 6551 UserLeave(); 6552 END_CLEANUP; 6553 } 6554 6555 /* 6556 * @implemented 6557 */ 6558 BOOL APIENTRY 6559 NtUserThunkedMenuItemInfo( 6560 HMENU hMenu, 6561 UINT uItem, 6562 BOOL fByPosition, 6563 BOOL bInsert, 6564 LPMENUITEMINFOW lpmii, 6565 PUNICODE_STRING lpszCaption) 6566 { 6567 PMENU Menu; 6568 NTSTATUS Status; 6569 UNICODE_STRING lstrCaption; 6570 DECLARE_RETURN(BOOL); 6571 6572 TRACE("Enter NtUserThunkedMenuItemInfo\n"); 6573 UserEnterExclusive(); 6574 6575 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString() 6576 if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo() */ 6577 6578 RtlInitEmptyUnicodeString(&lstrCaption, NULL, 0); 6579 6580 if (!(Menu = UserGetMenuObject(hMenu))) 6581 { 6582 RETURN(FALSE); 6583 } 6584 6585 /* Check if we got a Caption */ 6586 if (lpszCaption && lpszCaption->Buffer) 6587 { 6588 /* Copy the string to kernel mode */ 6589 Status = ProbeAndCaptureUnicodeString( &lstrCaption, 6590 UserMode, 6591 lpszCaption); 6592 if (!NT_SUCCESS(Status)) 6593 { 6594 ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status); 6595 SetLastNtError(Status); 6596 RETURN(FALSE); 6597 } 6598 } 6599 6600 if (bInsert) RETURN( UserInsertMenuItem(Menu, uItem, fByPosition, lpmii, &lstrCaption)); 6601 6602 RETURN( UserMenuItemInfo(Menu, uItem, fByPosition, (PROSMENUITEMINFO)lpmii, TRUE, &lstrCaption)); 6603 6604 CLEANUP: 6605 if (lstrCaption.Buffer) 6606 { 6607 ReleaseCapturedUnicodeString(&lstrCaption, UserMode); 6608 } 6609 6610 TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n",_ret_); 6611 UserLeave(); 6612 END_CLEANUP; 6613 } 6614 6615 /* 6616 * @implemented 6617 */ 6618 BOOL APIENTRY 6619 NtUserTrackPopupMenuEx( 6620 HMENU hMenu, 6621 UINT fuFlags, 6622 int x, 6623 int y, 6624 HWND hWnd, 6625 LPTPMPARAMS lptpm) 6626 { 6627 PMENU menu; 6628 PWND pWnd; 6629 TPMPARAMS tpm; 6630 BOOL Ret = FALSE; 6631 USER_REFERENCE_ENTRY Ref; 6632 6633 TRACE("Enter NtUserTrackPopupMenuEx\n"); 6634 UserEnterExclusive(); 6635 /* Parameter check */ 6636 if (!(menu = UserGetMenuObject( hMenu ))) 6637 { 6638 ERR("TPME : Invalid Menu handle.\n"); 6639 EngSetLastError( ERROR_INVALID_MENU_HANDLE ); 6640 goto Exit; 6641 } 6642 6643 if (!(pWnd = UserGetWindowObject(hWnd))) 6644 { 6645 ERR("TPME : Invalid Window handle.\n"); 6646 goto Exit; 6647 } 6648 6649 if (lptpm) 6650 { 6651 _SEH2_TRY 6652 { 6653 ProbeForRead(lptpm, sizeof(TPMPARAMS), sizeof(ULONG)); 6654 tpm = *lptpm; 6655 } 6656 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6657 { 6658 _SEH2_YIELD(goto Exit); 6659 } 6660 _SEH2_END 6661 } 6662 UserRefObjectCo(pWnd, &Ref); 6663 Ret = IntTrackPopupMenuEx(menu, fuFlags, x, y, pWnd, lptpm ? &tpm : NULL); 6664 UserDerefObjectCo(pWnd); 6665 6666 Exit: 6667 TRACE("Leave NtUserTrackPopupMenuEx, ret=%i\n",Ret); 6668 UserLeave(); 6669 return Ret; 6670 } 6671 6672 /* EOF */ 6673