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