4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
6 * Copyright 1997 Morten Welinder
10 * Note: the style MF_MOUSESELECT is used to mark popup items that
11 * have been selected, i.e. their popup menu is currently displayed.
12 * This is probably not the meaning this style has in MS-Windows.
21 #include "wine/winbase16.h"
22 #include "wine/winuser16.h"
26 #include "nonclient.h"
32 #include "debugtools.h"
34 DEFAULT_DEBUG_CHANNEL(menu
)
37 /* internal popup menu window messages */
39 #define MM_SETMENUHANDLE (WM_USER + 0)
40 #define MM_GETMENUHANDLE (WM_USER + 1)
42 /* Menu item structure */
44 /* ----------- MENUITEMINFO Stuff ----------- */
45 UINT fType
; /* Item type. */
46 UINT fState
; /* Item state. */
47 UINT wID
; /* Item id. */
48 HMENU hSubMenu
; /* Pop-up menu. */
49 HBITMAP hCheckBit
; /* Bitmap when checked. */
50 HBITMAP hUnCheckBit
; /* Bitmap when unchecked. */
51 LPSTR text
; /* Item text or bitmap handle. */
52 DWORD dwItemData
; /* Application defined. */
53 DWORD dwTypeData
; /* depends on fMask */
54 HBITMAP hbmpItem
; /* bitmap in win98 style menus */
55 /* ----------- Wine stuff ----------- */
56 RECT rect
; /* Item area (relative to menu window) */
57 UINT xTab
; /* X position of text after Tab */
60 /* Popup menu structure */
62 WORD wFlags
; /* Menu flags (MF_POPUP, MF_SYSMENU) */
63 WORD wMagic
; /* Magic number */
64 HQUEUE16 hTaskQ
; /* Task queue for this menu */
65 WORD Width
; /* Width of the whole menu */
66 WORD Height
; /* Height of the whole menu */
67 WORD nItems
; /* Number of items in the menu */
68 HWND hWnd
; /* Window containing the menu */
69 MENUITEM
*items
; /* Array of menu items */
70 UINT FocusedItem
; /* Currently focused item */
71 HWND hwndOwner
; /* window receiving the messages for ownerdraw */
72 BOOL bTimeToHide
; /* Request hiding when receiving a second click in the top-level menu item */
73 /* ------------ MENUINFO members ------ */
74 DWORD dwStyle
; /* Extended mennu style */
75 UINT cyMax
; /* max hight of the whole menu, 0 is screen hight */
76 HBRUSH hbrBack
; /* brush for menu background */
77 DWORD dwContextHelpID
;
78 DWORD dwMenuData
; /* application defined value */
79 HMENU hSysMenuOwner
; /* Handle to the dummy sys menu holder */
80 } POPUPMENU
, *LPPOPUPMENU
;
82 /* internal flags for menu tracking */
84 #define TF_ENDMENU 0x0001
85 #define TF_SUSPENDPOPUP 0x0002
86 #define TF_SKIPREMOVE 0x0004
91 HMENU hCurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
92 HMENU hTopMenu
; /* initial menu */
93 HWND hOwnerWnd
; /* where notifications are sent */
97 #define MENU_MAGIC 0x554d /* 'MU' */
98 #define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
103 /* Internal MENU_TrackMenu() flags */
104 #define TPM_INTERNAL 0xF0000000
105 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
106 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
107 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
109 /* popup menu shade thickness */
110 #define POPUP_XSHADE 4
111 #define POPUP_YSHADE 4
113 /* Space between 2 menu bar items */
114 #define MENU_BAR_ITEMS_SPACE 12
116 /* Minimum width of a tab character */
117 #define MENU_TAB_SPACE 8
119 /* Height of a separator item */
120 #define SEPARATOR_HEIGHT 5
122 /* (other menu->FocusedItem values give the position of the focused item) */
123 #define NO_SELECTED_ITEM 0xffff
125 #define MENU_ITEM_TYPE(flags) \
126 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
128 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
129 #define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
131 #define IS_SYSTEM_MENU(menu) \
132 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
134 #define IS_SYSTEM_POPUP(menu) \
135 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
137 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
138 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
139 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
140 MF_POPUP | MF_SYSMENU | MF_HELP)
141 #define STATE_MASK (~TYPE_MASK)
143 /* Dimension of the menu bitmaps */
144 static WORD check_bitmap_width
= 0, check_bitmap_height
= 0;
145 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
147 static HBITMAP hStdRadioCheck
= 0;
148 static HBITMAP hStdCheck
= 0;
149 static HBITMAP hStdMnArrow
= 0;
151 /* Minimze/restore/close buttons to be inserted in menubar */
152 static HBITMAP hBmpMinimize
= 0;
153 static HBITMAP hBmpMinimizeD
= 0;
154 static HBITMAP hBmpMaximize
= 0;
155 static HBITMAP hBmpMaximizeD
= 0;
156 static HBITMAP hBmpClose
= 0;
157 static HBITMAP hBmpCloseD
= 0;
160 static HBRUSH hShadeBrush
= 0;
161 static HFONT hMenuFont
= 0;
162 static HFONT hMenuFontBold
= 0;
164 static HMENU MENU_DefSysPopup
= 0; /* Default system menu popup */
166 /* Use global popup window because there's no way 2 menus can
167 * be tracked at the same time. */
169 static WND
* pTopPopupWnd
= 0;
170 static UINT uSubPWndLevel
= 0;
172 /* Flag set by EndMenu() to force an exit from menu tracking */
173 static BOOL fEndMenu
= FALSE
;
176 /***********************************************************************
177 * debug_print_menuitem
179 * Print a menuitem in readable form.
182 #define debug_print_menuitem(pre, mp, post) \
183 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
185 #define MENUOUT(text) \
186 DPRINTF("%s%s", (count++ ? "," : ""), (text))
188 #define MENUFLAG(bit,text) \
190 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
193 static void do_debug_print_menuitem(const char *prefix
, MENUITEM
* mp
,
196 TRACE("%s ", prefix
);
198 UINT flags
= mp
->fType
;
199 int typ
= MENU_ITEM_TYPE(flags
);
200 DPRINTF( "{ ID=0x%x", mp
->wID
);
201 if (flags
& MF_POPUP
)
202 DPRINTF( ", Sub=0x%x", mp
->hSubMenu
);
206 if (typ
== MFT_STRING
)
208 else if (typ
== MFT_SEPARATOR
)
210 else if (typ
== MFT_OWNERDRAW
)
212 else if (typ
== MFT_BITMAP
)
218 MENUFLAG(MF_POPUP
, "pop");
219 MENUFLAG(MFT_MENUBARBREAK
, "barbrk");
220 MENUFLAG(MFT_MENUBREAK
, "brk");
221 MENUFLAG(MFT_RADIOCHECK
, "radio");
222 MENUFLAG(MFT_RIGHTORDER
, "rorder");
223 MENUFLAG(MF_SYSMENU
, "sys");
224 MENUFLAG(MFT_RIGHTJUSTIFY
, "right"); /* same as MF_HELP */
227 DPRINTF( "+0x%x", flags
);
232 DPRINTF( ", State=");
233 MENUFLAG(MFS_GRAYED
, "grey");
234 MENUFLAG(MFS_DEFAULT
, "default");
235 MENUFLAG(MFS_DISABLED
, "dis");
236 MENUFLAG(MFS_CHECKED
, "check");
237 MENUFLAG(MFS_HILITE
, "hi");
238 MENUFLAG(MF_USECHECKBITMAPS
, "usebit");
239 MENUFLAG(MF_MOUSESELECT
, "mouse");
241 DPRINTF( "+0x%x", flags
);
244 DPRINTF( ", Chk=0x%x", mp
->hCheckBit
);
246 DPRINTF( ", Unc=0x%x", mp
->hUnCheckBit
);
248 if (typ
== MFT_STRING
) {
250 DPRINTF( ", Text=\"%s\"", mp
->text
);
252 DPRINTF( ", Text=Null");
253 } else if (mp
->text
== NULL
)
256 DPRINTF( ", Text=%p", mp
->text
);
258 DPRINTF( ", ItemData=0x%08lx", mp
->dwItemData
);
264 DPRINTF(" %s\n", postfix
);
270 /***********************************************************************
273 * Return the default system menu.
275 static HMENU
MENU_CopySysPopup(void)
277 HMENU hMenu
= LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
280 POPUPMENU
* menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
281 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
282 SetMenuDefaultItem(hMenu
, SC_CLOSE
, FALSE
);
286 ERR("Unable to load default system menu\n" );
289 TRACE("returning %x.\n", hMenu
);
294 /***********************************************************************
295 * MENU_GetTopPopupWnd()
297 * Return the locked pointer pTopPopupWnd.
299 static WND
*MENU_GetTopPopupWnd()
301 return WIN_LockWndPtr(pTopPopupWnd
);
303 /***********************************************************************
304 * MENU_ReleaseTopPopupWnd()
306 * Realease the locked pointer pTopPopupWnd.
308 static void MENU_ReleaseTopPopupWnd()
310 WIN_ReleaseWndPtr(pTopPopupWnd
);
312 /***********************************************************************
313 * MENU_DestroyTopPopupWnd()
315 * Destroy the locked pointer pTopPopupWnd.
317 static void MENU_DestroyTopPopupWnd()
319 WND
*tmpWnd
= pTopPopupWnd
;
321 WIN_ReleaseWndPtr(tmpWnd
);
326 /**********************************************************************
329 * Create a copy of the system menu. System menu in Windows is
330 * a special menu-bar with the single entry - system menu popup.
331 * This popup is presented to the outside world as a "system menu".
332 * However, the real system menu handle is sometimes seen in the
333 * WM_MENUSELECT paramemters (and Word 6 likes it this way).
335 HMENU
MENU_GetSysMenu( HWND hWnd
, HMENU hPopupMenu
)
339 if ((hMenu
= CreateMenu()))
341 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
342 menu
->wFlags
= MF_SYSMENU
;
345 if (hPopupMenu
== (HMENU
)(-1))
346 hPopupMenu
= MENU_CopySysPopup();
347 else if( !hPopupMenu
) hPopupMenu
= MENU_DefSysPopup
;
351 InsertMenuA( hMenu
, -1, MF_SYSMENU
| MF_POPUP
| MF_BYPOSITION
, hPopupMenu
, NULL
);
353 menu
->items
[0].fType
= MF_SYSMENU
| MF_POPUP
;
354 menu
->items
[0].fState
= 0;
355 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hPopupMenu
);
356 menu
->wFlags
|= MF_SYSMENU
;
358 TRACE("GetSysMenu hMenu=%04x (%04x)\n", hMenu
, hPopupMenu
);
361 DestroyMenu( hMenu
);
363 ERR("failed to load system menu!\n");
368 /***********************************************************************
371 * Menus initialisation.
376 NONCLIENTMETRICSA ncm
;
378 static unsigned char shade_bits
[16] = { 0x55, 0, 0xAA, 0,
383 /* Load menu bitmaps */
384 hStdCheck
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CHECK
));
385 hStdRadioCheck
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_RADIOCHECK
));
386 hStdMnArrow
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW
));
387 /* Load system buttons bitmaps */
388 hBmpMinimize
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCE
));
389 hBmpMinimizeD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCED
));
390 hBmpMaximize
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORE
));
391 hBmpMaximizeD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORED
));
392 hBmpClose
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSE
));
393 hBmpCloseD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSED
));
398 GetObjectA( hStdCheck
, sizeof(bm
), &bm
);
399 check_bitmap_width
= bm
.bmWidth
;
400 check_bitmap_height
= bm
.bmHeight
;
404 /* Assume that radio checks have the same size as regular check. */
411 GetObjectA( hStdMnArrow
, sizeof(bm
), &bm
);
412 arrow_bitmap_width
= bm
.bmWidth
;
413 arrow_bitmap_height
= bm
.bmHeight
;
417 if (! (hBitmap
= CreateBitmap( 8, 8, 1, 1, shade_bits
)))
420 if(!(hShadeBrush
= CreatePatternBrush( hBitmap
)))
423 DeleteObject( hBitmap
);
424 if (!(MENU_DefSysPopup
= MENU_CopySysPopup()))
427 ncm
.cbSize
= sizeof (NONCLIENTMETRICSA
);
428 if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS
, sizeof(NONCLIENTMETRICSA
), &ncm
, 0)))
431 if (!(hMenuFont
= CreateFontIndirectA( &ncm
.lfMenuFont
)))
434 ncm
.lfMenuFont
.lfWeight
+= 300;
435 if ( ncm
.lfMenuFont
.lfWeight
> 1000)
436 ncm
.lfMenuFont
.lfWeight
= 1000;
438 if (!(hMenuFontBold
= CreateFontIndirectA( &ncm
.lfMenuFont
)))
444 /***********************************************************************
445 * MENU_InitSysMenuPopup
447 * Grey the appropriate items in System menu.
449 static void MENU_InitSysMenuPopup( HMENU hmenu
, DWORD style
, DWORD clsStyle
)
453 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
454 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
455 gray
= ((style
& WS_MAXIMIZE
) != 0);
456 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
457 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
458 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
459 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
460 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
461 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
462 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
463 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
465 /* The menu item must keep its state if it's disabled */
467 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
471 /******************************************************************************
473 * UINT32 MENU_GetStartOfNextColumn(
476 *****************************************************************************/
478 static UINT
MENU_GetStartOfNextColumn(
481 POPUPMENU
*menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
482 UINT i
= menu
->FocusedItem
+ 1;
485 return NO_SELECTED_ITEM
;
487 if( i
== NO_SELECTED_ITEM
)
490 for( ; i
< menu
->nItems
; ++i
) {
491 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
495 return NO_SELECTED_ITEM
;
499 /******************************************************************************
501 * UINT32 MENU_GetStartOfPrevColumn(
504 *****************************************************************************/
506 static UINT
MENU_GetStartOfPrevColumn(
509 POPUPMENU
const *menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
513 return NO_SELECTED_ITEM
;
515 if( menu
->FocusedItem
== 0 || menu
->FocusedItem
== NO_SELECTED_ITEM
)
516 return NO_SELECTED_ITEM
;
518 /* Find the start of the column */
520 for(i
= menu
->FocusedItem
; i
!= 0 &&
521 !(menu
->items
[i
].fType
& MF_MENUBARBREAK
);
525 return NO_SELECTED_ITEM
;
527 for(--i
; i
!= 0; --i
) {
528 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
532 TRACE("ret %d.\n", i
);
539 /***********************************************************************
542 * Find a menu item. Return a pointer on the item, and modifies *hmenu
543 * in case the item was in a sub-menu.
545 static MENUITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
550 if (((*hmenu
)==0xffff) || (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(*hmenu
)))) return NULL
;
551 if (wFlags
& MF_BYPOSITION
)
553 if (*nPos
>= menu
->nItems
) return NULL
;
554 return &menu
->items
[*nPos
];
558 MENUITEM
*item
= menu
->items
;
559 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
561 if (item
->wID
== *nPos
)
566 else if (item
->fType
& MF_POPUP
)
568 HMENU hsubmenu
= item
->hSubMenu
;
569 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
581 /***********************************************************************
584 static void MENU_FreeItemData( MENUITEM
* item
)
587 if (IS_STRING_ITEM(item
->fType
) && item
->text
)
588 HeapFree( SystemHeap
, 0, item
->text
);
591 /***********************************************************************
592 * MENU_FindItemByCoords
594 * Find the item at the specified coordinates (screen coords). Does
595 * not work for child windows and therefore should not be called for
596 * an arbitrary system menu.
598 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
,
599 POINT pt
, UINT
*pos
)
605 if (!GetWindowRect(menu
->hWnd
,&wrect
)) return NULL
;
606 pt
.x
-= wrect
.left
;pt
.y
-= wrect
.top
;
608 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
610 if ((pt
.x
>= item
->rect
.left
) && (pt
.x
< item
->rect
.right
) &&
611 (pt
.y
>= item
->rect
.top
) && (pt
.y
< item
->rect
.bottom
))
621 /***********************************************************************
624 * Find the menu item selected by a key press.
625 * Return item id, -1 if none, -2 if we should close the menu.
627 static UINT
MENU_FindItemByKey( HWND hwndOwner
, HMENU hmenu
,
628 UINT key
, BOOL forceMenuChar
)
630 TRACE("\tlooking for '%c' in [%04x]\n", (char)key
, (UINT16
)hmenu
);
632 if (!IsMenu( hmenu
))
634 WND
* w
= WIN_FindWndPtr(hwndOwner
);
635 hmenu
= GetSubMenu(w
->hSysMenu
, 0);
636 WIN_ReleaseWndPtr(w
);
641 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
642 MENUITEM
*item
= menu
->items
;
650 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
652 if (item
->text
&& (IS_STRING_ITEM(item
->fType
)))
654 char *p
= item
->text
- 2;
657 p
= strchr (p
+ 2, '&');
659 while (p
!= NULL
&& p
[1] == '&');
660 if (p
&& (toupper(p
[1]) == key
)) return i
;
664 menuchar
= SendMessageA( hwndOwner
, WM_MENUCHAR
,
665 MAKEWPARAM( key
, menu
->wFlags
), hmenu
);
666 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
667 if (HIWORD(menuchar
) == 1) return (UINT
)(-2);
671 /***********************************************************************
674 * Load the bitmap associated with the magic menu item and its style
677 static HBITMAP
MENU_LoadMagicItem(UINT id
, BOOL hilite
, DWORD dwItemData
)
680 * Magic menu item id's section
681 * These magic id's are used by windows to insert "standard" mdi
682 * buttons (minimize,restore,close) on menu. Under windows,
683 * these magic id's make sure the right things appear when those
684 * bitmap buttons are pressed/selected/released.
688 { case HBMMENU_SYSTEM
:
689 return (dwItemData
) ?
690 (HBITMAP
)dwItemData
:
691 (hilite
? hBmpMinimizeD
: hBmpMinimize
);
692 case HBMMENU_MBAR_RESTORE
:
693 return (hilite
? hBmpMaximizeD
: hBmpMaximize
);
694 case HBMMENU_MBAR_MINIMIZE
:
695 return (hilite
? hBmpMinimizeD
: hBmpMinimize
);
696 case HBMMENU_MBAR_CLOSE
:
697 return (hilite
? hBmpCloseD
: hBmpClose
);
698 case HBMMENU_CALLBACK
:
699 case HBMMENU_MBAR_CLOSE_D
:
700 case HBMMENU_MBAR_MINIMIZE_D
:
701 case HBMMENU_POPUP_CLOSE
:
702 case HBMMENU_POPUP_RESTORE
:
703 case HBMMENU_POPUP_MAXIMIZE
:
704 case HBMMENU_POPUP_MINIMIZE
:
706 FIXME("Magic 0x%08x not implemented\n", id
);
712 /***********************************************************************
715 * Calculate the size of the menu item and store it in lpitem->rect.
717 static void MENU_CalcItemSize( HDC hdc
, MENUITEM
*lpitem
, HWND hwndOwner
,
718 INT orgX
, INT orgY
, BOOL menuBar
)
722 TRACE("dc=0x%04x owner=0x%04x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
723 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem
,
724 (menuBar
? " (MenuBar)" : ""));
726 SetRect( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
728 if (lpitem
->fType
& MF_OWNERDRAW
)
730 MEASUREITEMSTRUCT mis
;
731 mis
.CtlType
= ODT_MENU
;
733 mis
.itemID
= lpitem
->wID
;
734 mis
.itemData
= (DWORD
)lpitem
->dwItemData
;
737 SendMessageA( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
738 lpitem
->rect
.bottom
+= mis
.itemHeight
;
739 lpitem
->rect
.right
+= mis
.itemWidth
;
740 TRACE("id=%04x size=%dx%d\n",
741 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
745 if (lpitem
->fType
& MF_SEPARATOR
)
747 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
753 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
754 if (lpitem
->fType
& MF_POPUP
)
755 lpitem
->rect
.right
+= arrow_bitmap_width
;
758 if (IS_BITMAP_ITEM(lpitem
->fType
))
763 /* Check if there is a magic menu item associated with this item */
764 if((LOWORD((int)lpitem
->text
))<12)
766 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
, (lpitem
->fType
& MF_HILITE
),
770 resBmp
= (HBITMAP
)lpitem
->text
;
772 if (GetObjectA(resBmp
, sizeof(bm
), &bm
))
774 lpitem
->rect
.right
+= bm
.bmWidth
;
775 lpitem
->rect
.bottom
+= bm
.bmHeight
;
781 /* If we get here, then it must be a text item */
782 if (IS_STRING_ITEM( lpitem
->fType
))
785 GetTextExtentPoint32A(hdc
, lpitem
->text
, strlen(lpitem
->text
), &size
);
787 lpitem
->rect
.right
+= size
.cx
;
788 if (TWEAK_WineLook
== WIN31_LOOK
)
789 lpitem
->rect
.bottom
+= MAX( size
.cy
, GetSystemMetrics(SM_CYMENU
) );
791 lpitem
->rect
.bottom
+= MAX (size
.cy
, GetSystemMetrics(SM_CYMENU
)-1);
796 lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
798 else if ((p
= strchr( lpitem
->text
, '\t' )) != NULL
)
800 /* Item contains a tab (only meaningful in popup menus) */
801 GetTextExtentPoint32A(hdc
, lpitem
->text
, (int)(p
- lpitem
->text
) , &size
);
802 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+ size
.cx
;
803 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
807 if (strchr( lpitem
->text
, '\b' ))
808 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
809 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
810 - arrow_bitmap_width
;
813 TRACE("(%d,%d)-(%d,%d)\n", lpitem
->rect
.left
, lpitem
->rect
.top
, lpitem
->rect
.right
, lpitem
->rect
.bottom
);
817 /***********************************************************************
818 * MENU_PopupMenuCalcSize
820 * Calculate the size of a popup menu.
822 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND hwndOwner
)
827 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
829 lppop
->Width
= lppop
->Height
= 0;
830 if (lppop
->nItems
== 0) return;
833 SelectObject( hdc
, hMenuFont
);
836 maxX
= (TWEAK_WineLook
== WIN31_LOOK
) ? GetSystemMetrics(SM_CXBORDER
) : 2 ;
838 while (start
< lppop
->nItems
)
840 lpitem
= &lppop
->items
[start
];
842 orgY
= (TWEAK_WineLook
== WIN31_LOOK
) ? GetSystemMetrics(SM_CYBORDER
) : 2;
844 maxTab
= maxTabWidth
= 0;
846 /* Parse items until column break or end of menu */
847 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
850 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
852 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
854 if (lpitem
->fType
& MF_MENUBARBREAK
) orgX
++;
855 maxX
= MAX( maxX
, lpitem
->rect
.right
);
856 orgY
= lpitem
->rect
.bottom
;
857 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
859 maxTab
= MAX( maxTab
, lpitem
->xTab
);
860 maxTabWidth
= MAX(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
864 /* Finish the column (set all items to the largest width found) */
865 maxX
= MAX( maxX
, maxTab
+ maxTabWidth
);
866 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
868 lpitem
->rect
.right
= maxX
;
869 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
870 lpitem
->xTab
= maxTab
;
873 lppop
->Height
= MAX( lppop
->Height
, orgY
);
878 /* space for 3d border */
879 if(TWEAK_WineLook
> WIN31_LOOK
)
889 /***********************************************************************
890 * MENU_MenuBarCalcSize
892 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
893 * height is off by 1 pixel which causes lengthy window relocations when
894 * active document window is maximized/restored.
896 * Calculate the size of the menu bar.
898 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
,
899 LPPOPUPMENU lppop
, HWND hwndOwner
)
902 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
904 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
905 if (lppop
->nItems
== 0) return;
906 TRACE("left=%d top=%d right=%d bottom=%d\n",
907 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
908 lppop
->Width
= lprect
->right
- lprect
->left
;
913 while (start
< lppop
->nItems
)
915 lpitem
= &lppop
->items
[start
];
919 /* Parse items until line break or end of menu */
920 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
922 if ((helpPos
== -1) && (lpitem
->fType
& MF_HELP
)) helpPos
= i
;
924 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
926 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
928 debug_print_menuitem (" item: ", lpitem
, "");
929 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
931 if (lpitem
->rect
.right
> lprect
->right
)
933 if (i
!= start
) break;
934 else lpitem
->rect
.right
= lprect
->right
;
936 maxY
= MAX( maxY
, lpitem
->rect
.bottom
);
937 orgX
= lpitem
->rect
.right
;
940 /* Finish the line (set all items to the largest height found) */
941 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
944 lprect
->bottom
= maxY
;
945 lppop
->Height
= lprect
->bottom
- lprect
->top
;
947 /* Flush right all magic items and items between the MF_HELP and */
948 /* the last item (if several lines, only move the last line) */
949 lpitem
= &lppop
->items
[lppop
->nItems
-1];
950 orgY
= lpitem
->rect
.top
;
951 orgX
= lprect
->right
;
952 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--)
954 if ( !IS_BITMAP_ITEM(lpitem
->fType
) && ((helpPos
==-1) ? TRUE
: (helpPos
>i
) ))
956 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
957 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
958 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
959 lpitem
->rect
.right
= orgX
;
960 orgX
= lpitem
->rect
.left
;
964 /***********************************************************************
967 * Draw a single menu item.
969 static void MENU_DrawMenuItem( HWND hwnd
, HMENU hmenu
, HWND hwndOwner
, HDC hdc
, MENUITEM
*lpitem
,
970 UINT height
, BOOL menuBar
, UINT odaction
)
974 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem
, "");
976 if (lpitem
->fType
& MF_SYSMENU
)
978 if( !IsIconic(hwnd
) ) {
979 if (TWEAK_WineLook
> WIN31_LOOK
)
980 NC_DrawSysButton95( hwnd
, hdc
,
982 (MF_HILITE
| MF_MOUSESELECT
) );
984 NC_DrawSysButton( hwnd
, hdc
,
986 (MF_HILITE
| MF_MOUSESELECT
) );
992 if (lpitem
->fType
& MF_OWNERDRAW
)
996 dis
.CtlType
= ODT_MENU
;
998 dis
.itemID
= lpitem
->wID
;
999 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1001 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1002 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
;
1003 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1004 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1005 dis
.hwndItem
= hmenu
;
1007 dis
.rcItem
= lpitem
->rect
;
1008 TRACE("Ownerdraw: owner=%04x itemID=%d, itemState=%d, itemAction=%d, "
1009 "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n", hwndOwner
,
1010 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1011 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1013 SendMessageA( hwndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
1017 TRACE("rect={%d,%d,%d,%d}\n", lpitem
->rect
.left
, lpitem
->rect
.top
,
1018 lpitem
->rect
.right
,lpitem
->rect
.bottom
);
1020 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1022 rect
= lpitem
->rect
;
1024 if ((lpitem
->fState
& MF_HILITE
) && !(IS_BITMAP_ITEM(lpitem
->fType
)))
1025 if ((menuBar
) && (TWEAK_WineLook
==WIN98_LOOK
))
1026 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1028 FillRect( hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
) );
1030 FillRect( hdc
, &rect
, GetSysColorBrush(COLOR_MENU
) );
1032 SetBkMode( hdc
, TRANSPARENT
);
1034 /* vertical separator */
1035 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1037 if (TWEAK_WineLook
> WIN31_LOOK
)
1041 rc
.bottom
= height
- 3;
1042 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1046 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1047 MoveTo16( hdc
, rect
.left
, 0 );
1048 LineTo( hdc
, rect
.left
, height
);
1052 /* horizontal separator */
1053 if (lpitem
->fType
& MF_SEPARATOR
)
1055 if (TWEAK_WineLook
> WIN31_LOOK
)
1060 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1061 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1065 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1066 MoveTo16( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
1067 LineTo( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
1074 if ((lpitem
->fState
& MF_HILITE
) && !(IS_BITMAP_ITEM(lpitem
->fType
)) )
1076 if (lpitem
->fState
& MF_GRAYED
)
1077 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1079 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
1080 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
1084 if (lpitem
->fState
& MF_GRAYED
)
1085 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1087 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1088 SetBkColor( hdc
, GetSysColor( COLOR_MENU
) );
1091 /* helper lines for debugging */
1092 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1093 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1094 MoveTo16( hdc, rect.left, (rect.top + rect.bottom)/2 );
1095 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1100 INT y
= rect
.top
+ rect
.bottom
;
1102 /* Draw the check mark
1105 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1108 if (lpitem
->fState
& MF_CHECKED
)
1110 HBITMAP bm
= lpitem
->hCheckBit
? lpitem
->hCheckBit
:
1111 ((lpitem
->fType
& MFT_RADIOCHECK
) ? hStdRadioCheck
: hStdCheck
);
1112 HDC hdcMem
= CreateCompatibleDC( hdc
);
1114 SelectObject( hdcMem
, bm
);
1115 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1116 check_bitmap_width
, check_bitmap_height
,
1117 hdcMem
, 0, 0, SRCCOPY
);
1120 else if (lpitem
->hUnCheckBit
)
1122 HDC hdcMem
= CreateCompatibleDC( hdc
);
1124 SelectObject( hdcMem
, lpitem
->hUnCheckBit
);
1125 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1126 check_bitmap_width
, check_bitmap_height
,
1127 hdcMem
, 0, 0, SRCCOPY
);
1131 /* Draw the popup-menu arrow */
1132 if (lpitem
->fType
& MF_POPUP
)
1134 HDC hdcMem
= CreateCompatibleDC( hdc
);
1136 SelectObject( hdcMem
, hStdMnArrow
);
1137 BitBlt( hdc
, rect
.right
- arrow_bitmap_width
- 1,
1138 (y
- arrow_bitmap_height
) / 2,
1139 arrow_bitmap_width
, arrow_bitmap_height
,
1140 hdcMem
, 0, 0, SRCCOPY
);
1144 rect
.left
+= check_bitmap_width
;
1145 rect
.right
-= arrow_bitmap_width
;
1148 /* Draw the item text or bitmap */
1149 if (IS_BITMAP_ITEM(lpitem
->fType
))
1154 HDC hdcMem
= CreateCompatibleDC( hdc
);
1157 * Check if there is a magic menu item associated with this item
1158 * and load the appropriate bitmap
1160 if((LOWORD((int)lpitem
->text
)) < 12)
1162 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
, (lpitem
->fState
& MF_HILITE
),
1163 lpitem
->dwItemData
);
1166 resBmp
= (HBITMAP
)lpitem
->text
;
1171 GetObjectA( resBmp
, sizeof(bm
), &bm
);
1173 SelectObject(hdcMem
,resBmp
);
1175 /* handle fontsize > bitmap_height */
1176 top
= ((rect
.bottom
-rect
.top
)>bm
.bmHeight
) ?
1177 rect
.top
+(rect
.bottom
-rect
.top
-bm
.bmHeight
)/2 : rect
.top
;
1179 BitBlt( hdc
, rect
.left
, top
, rect
.right
- rect
.left
,
1180 rect
.bottom
- rect
.top
, hdcMem
, 0, 0, SRCCOPY
);
1187 /* No bitmap - process text if present */
1188 else if (IS_STRING_ITEM(lpitem
->fType
))
1193 UINT uFormat
= (menuBar
) ?
1194 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
1195 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1197 if ( lpitem
->fState
& MFS_DEFAULT
)
1199 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
1204 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1205 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1206 i
= strlen( lpitem
->text
);
1210 for (i
= 0; lpitem
->text
[i
]; i
++)
1211 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
1215 if( !(TWEAK_WineLook
== WIN31_LOOK
) && (lpitem
->fState
& MF_GRAYED
))
1217 if (!(lpitem
->fState
& MF_HILITE
) )
1219 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1220 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1221 DrawTextA( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1222 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1224 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1227 DrawTextA( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1229 /* paint the shortcut text */
1230 if (lpitem
->text
[i
]) /* There's a tab or flush-right char */
1232 if (lpitem
->text
[i
] == '\t')
1234 rect
.left
= lpitem
->xTab
;
1235 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1239 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1242 if( !(TWEAK_WineLook
== WIN31_LOOK
) && (lpitem
->fState
& MF_GRAYED
))
1244 if (!(lpitem
->fState
& MF_HILITE
) )
1246 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1247 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1248 DrawTextA( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1249 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1251 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1253 DrawTextA( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1257 SelectObject (hdc
, hfontOld
);
1262 /***********************************************************************
1263 * MENU_DrawPopupMenu
1265 * Paint a popup menu.
1267 static void MENU_DrawPopupMenu( HWND hwnd
, HDC hdc
, HMENU hmenu
)
1269 HBRUSH hPrevBrush
= 0;
1272 TRACE("wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd
, hdc
, hmenu
);
1274 GetClientRect( hwnd
, &rect
);
1276 if(TWEAK_WineLook
== WIN31_LOOK
)
1278 rect
.bottom
-= POPUP_YSHADE
* GetSystemMetrics(SM_CYBORDER
);
1279 rect
.right
-= POPUP_XSHADE
* GetSystemMetrics(SM_CXBORDER
);
1282 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1283 && (SelectObject( hdc
, hMenuFont
)))
1287 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1289 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1295 /* draw 3-d shade */
1296 if(TWEAK_WineLook
== WIN31_LOOK
) {
1297 SelectObject( hdc
, hShadeBrush
);
1298 SetBkMode( hdc
, TRANSPARENT
);
1299 ropPrev
= SetROP2( hdc
, R2_MASKPEN
);
1301 i
= rect
.right
; /* why SetBrushOrg() doesn't? */
1302 PatBlt( hdc
, i
& 0xfffffffe,
1303 rect
.top
+ POPUP_YSHADE
*GetSystemMetrics(SM_CYBORDER
),
1304 i
%2 + POPUP_XSHADE
*GetSystemMetrics(SM_CXBORDER
),
1305 rect
.bottom
- rect
.top
, 0x00a000c9 );
1307 PatBlt( hdc
, rect
.left
+ POPUP_XSHADE
*GetSystemMetrics(SM_CXBORDER
),
1308 i
& 0xfffffffe,rect
.right
- rect
.left
,
1309 i
%2 + POPUP_YSHADE
*GetSystemMetrics(SM_CYBORDER
), 0x00a000c9 );
1310 SelectObject( hdc
, hPrevPen
);
1311 SelectObject( hdc
, hPrevBrush
);
1312 SetROP2( hdc
, ropPrev
);
1315 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1317 /* draw menu items */
1319 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1320 if (menu
&& menu
->nItems
)
1325 for (u
= menu
->nItems
, item
= menu
->items
; u
> 0; u
--, item
++)
1326 MENU_DrawMenuItem( hwnd
, hmenu
, menu
->hwndOwner
, hdc
, item
,
1327 menu
->Height
, FALSE
, ODA_DRAWENTIRE
);
1332 SelectObject( hdc
, hPrevBrush
);
1337 /***********************************************************************
1340 * Paint a menu bar. Returns the height of the menu bar.
1341 * called from [windows/nonclient.c]
1343 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1350 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1352 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( (HMENU
)wndPtr
->wIDmenu
);
1353 if (lppop
== NULL
|| lprect
== NULL
)
1355 retvalue
= GetSystemMetrics(SM_CYMENU
);
1359 TRACE("(%04x, %p, %p)\n", hDC
, lprect
, lppop
);
1361 hfontOld
= SelectObject( hDC
, hMenuFont
);
1363 if (lppop
->Height
== 0)
1364 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
1366 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
1370 retvalue
= lppop
->Height
;
1374 FillRect(hDC
, lprect
, GetSysColorBrush(COLOR_MENU
) );
1376 if (TWEAK_WineLook
== WIN31_LOOK
)
1378 SelectObject( hDC
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1379 MoveTo16( hDC
, lprect
->left
, lprect
->bottom
);
1380 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1384 SelectObject( hDC
, GetSysColorPen(COLOR_3DFACE
));
1385 MoveTo16( hDC
, lprect
->left
, lprect
->bottom
);
1386 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1389 if (lppop
->nItems
== 0)
1391 retvalue
= GetSystemMetrics(SM_CYMENU
);
1395 for (i
= 0; i
< lppop
->nItems
; i
++)
1397 MENU_DrawMenuItem( hwnd
, (HMENU
)wndPtr
->wIDmenu
, GetWindow(hwnd
,GW_OWNER
),
1398 hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
, ODA_DRAWENTIRE
);
1400 retvalue
= lppop
->Height
;
1404 SelectObject (hDC
, hfontOld
);
1406 WIN_ReleaseWndPtr(wndPtr
);
1410 /***********************************************************************
1411 * MENU_PatchResidentPopup
1413 BOOL
MENU_PatchResidentPopup( HQUEUE16 checkQueue
, WND
* checkWnd
)
1415 WND
*pTPWnd
= MENU_GetTopPopupWnd();
1421 TRACE("patching resident popup: %04x %04x [%04x %04x]\n",
1422 checkQueue
, checkWnd
? checkWnd
->hwndSelf
: 0, pTPWnd
->hmemTaskQ
,
1423 pTPWnd
->owner
? pTPWnd
->owner
->hwndSelf
: 0);
1425 switch( checkQueue
)
1427 case 0: /* checkWnd is the new popup owner */
1430 pTPWnd
->owner
= checkWnd
;
1431 if( pTPWnd
->hmemTaskQ
!= checkWnd
->hmemTaskQ
)
1432 hTask
= QUEUE_GetQueueTask( checkWnd
->hmemTaskQ
);
1436 case 0xFFFF: /* checkWnd is destroyed */
1437 if( pTPWnd
->owner
== checkWnd
)
1438 pTPWnd
->owner
= NULL
;
1439 MENU_ReleaseTopPopupWnd();
1442 default: /* checkQueue is exiting */
1443 if( pTPWnd
->hmemTaskQ
== checkQueue
)
1445 hTask
= QUEUE_GetQueueTask( pTPWnd
->hmemTaskQ
);
1446 hTask
= TASK_GetNextTask( hTask
);
1453 TDB
* task
= (TDB
*)GlobalLock16( hTask
);
1456 pTPWnd
->hInstance
= task
->hInstance
;
1457 pTPWnd
->hmemTaskQ
= task
->hQueue
;
1458 MENU_ReleaseTopPopupWnd();
1461 else WARN("failed to patch resident popup.\n");
1464 MENU_ReleaseTopPopupWnd();
1468 /***********************************************************************
1471 * Display a popup menu.
1473 static BOOL
MENU_ShowPopup( HWND hwndOwner
, HMENU hmenu
, UINT id
,
1474 INT x
, INT y
, INT xanchor
, INT yanchor
)
1477 WND
*wndOwner
= NULL
;
1479 TRACE("owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1480 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1482 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
1483 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1485 menu
->items
[menu
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1486 menu
->FocusedItem
= NO_SELECTED_ITEM
;
1489 /* store the owner for DrawItem*/
1490 menu
->hwndOwner
= hwndOwner
;
1492 if( (wndOwner
= WIN_FindWndPtr( hwndOwner
)) )
1496 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
1498 /* adjust popup menu pos so that it fits within the desktop */
1500 width
= menu
->Width
+ GetSystemMetrics(SM_CXBORDER
);
1501 height
= menu
->Height
+ GetSystemMetrics(SM_CYBORDER
);
1503 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1506 x
-= width
- xanchor
;
1507 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1508 x
= GetSystemMetrics(SM_CXSCREEN
) - width
;
1512 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1515 y
-= height
+ yanchor
;
1516 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1517 y
= GetSystemMetrics(SM_CYSCREEN
) - height
;
1521 if( TWEAK_WineLook
== WIN31_LOOK
)
1523 width
+= POPUP_XSHADE
* GetSystemMetrics(SM_CXBORDER
); /* add space for shading */
1524 height
+= POPUP_YSHADE
* GetSystemMetrics(SM_CYBORDER
);
1527 /* NOTE: In Windows, top menu popup is not owned. */
1528 if (!pTopPopupWnd
) /* create top level popup menu window */
1530 assert( uSubPWndLevel
== 0 );
1532 pTopPopupWnd
= WIN_FindWndPtr(CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1533 WS_POPUP
, x
, y
, width
, height
,
1534 hwndOwner
, 0, wndOwner
->hInstance
,
1538 WIN_ReleaseWndPtr(wndOwner
);
1541 menu
->hWnd
= pTopPopupWnd
->hwndSelf
;
1542 MENU_ReleaseTopPopupWnd();
1547 /* create a new window for the submenu */
1549 menu
->hWnd
= CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1550 WS_POPUP
, x
, y
, width
, height
,
1551 hwndOwner
, 0, wndOwner
->hInstance
,
1555 WIN_ReleaseWndPtr(wndOwner
);
1559 else /* top level popup menu window already exists */
1561 WND
*pTPWnd
= MENU_GetTopPopupWnd();
1562 menu
->hWnd
= pTPWnd
->hwndSelf
;
1564 MENU_PatchResidentPopup( 0, wndOwner
);
1565 SendMessageA( pTPWnd
->hwndSelf
, MM_SETMENUHANDLE
, (WPARAM16
)hmenu
, 0L);
1567 /* adjust its size */
1569 SetWindowPos( menu
->hWnd
, 0, x
, y
, width
, height
,
1570 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_NOREDRAW
);
1571 MENU_ReleaseTopPopupWnd();
1574 uSubPWndLevel
++; /* menu level counter */
1576 /* Display the window */
1578 SetWindowPos( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
1579 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1580 UpdateWindow( menu
->hWnd
);
1581 WIN_ReleaseWndPtr(wndOwner
);
1588 /***********************************************************************
1591 static void MENU_SelectItem( HWND hwndOwner
, HMENU hmenu
, UINT wIndex
,
1592 BOOL sendMenuSelect
)
1597 TRACE("owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1599 lppop
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1600 if (!lppop
->nItems
) return;
1602 if ((wIndex
!= NO_SELECTED_ITEM
) &&
1603 (lppop
->items
[wIndex
].fType
& MF_SEPARATOR
))
1604 wIndex
= NO_SELECTED_ITEM
;
1606 if (lppop
->FocusedItem
== wIndex
) return;
1607 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC( lppop
->hWnd
);
1608 else hdc
= GetDCEx( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1610 SelectObject( hdc
, hMenuFont
);
1612 /* Clear previous highlighted item */
1613 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1615 lppop
->items
[lppop
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1616 MENU_DrawMenuItem(lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,&lppop
->items
[lppop
->FocusedItem
],
1617 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
),
1621 /* Highlight new item (if any) */
1622 lppop
->FocusedItem
= wIndex
;
1623 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1625 lppop
->items
[lppop
->FocusedItem
].fState
|= MF_HILITE
;
1626 MENU_DrawMenuItem( lppop
->hWnd
, hmenu
, hwndOwner
, hdc
, &lppop
->items
[lppop
->FocusedItem
],
1627 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
),
1631 MENUITEM
*ip
= &lppop
->items
[lppop
->FocusedItem
];
1632 SendMessageA( hwndOwner
, WM_MENUSELECT
,
1633 MAKELONG(ip
->wID
,ip
->fType
| (ip
->fState
| MF_MOUSESELECT
)), hmenu
);
1636 else if (sendMenuSelect
) {
1637 SendMessageA( hwndOwner
, WM_MENUSELECT
,
1638 MAKELONG( hmenu
, lppop
->wFlags
| MF_MOUSESELECT
), hmenu
);
1640 ReleaseDC( lppop
->hWnd
, hdc
);
1644 /***********************************************************************
1645 * MENU_MoveSelection
1647 * Moves currently selected item according to the offset parameter.
1648 * If there is no selection then it should select the last item if
1649 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1651 static void MENU_MoveSelection( HWND hwndOwner
, HMENU hmenu
, INT offset
)
1656 TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner
, hmenu
, offset
);
1658 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1659 if (!menu
->items
) return;
1661 if ( menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1663 if( menu
->nItems
== 1 ) return; else
1664 for (i
= menu
->FocusedItem
+ offset
; i
>= 0 && i
< menu
->nItems
1666 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1668 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
1673 for ( i
= (offset
> 0) ? 0 : menu
->nItems
- 1;
1674 i
>= 0 && i
< menu
->nItems
; i
+= offset
)
1675 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1677 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
1683 /**********************************************************************
1686 * Set an item flags, id and text ptr. Called by InsertMenu() and
1689 static BOOL
MENU_SetItemData( MENUITEM
*item
, UINT flags
, UINT id
,
1692 LPSTR prevText
= IS_STRING_ITEM(item
->fType
) ? item
->text
: NULL
;
1694 debug_print_menuitem("MENU_SetItemData from: ", item
, "");
1696 if (IS_STRING_ITEM(flags
))
1700 flags
|= MF_SEPARATOR
;
1706 /* Item beginning with a backspace is a help item */
1712 if (!(text
= HEAP_strdupA( SystemHeap
, 0, str
))) return FALSE
;
1716 else if (IS_BITMAP_ITEM(flags
))
1717 item
->text
= (LPSTR
)(HBITMAP
)LOWORD(str
);
1718 else item
->text
= NULL
;
1720 if (flags
& MF_OWNERDRAW
)
1721 item
->dwItemData
= (DWORD
)str
;
1723 item
->dwItemData
= 0;
1725 if ((item
->fType
& MF_POPUP
) && (flags
& MF_POPUP
) && (item
->hSubMenu
!= id
) )
1726 DestroyMenu( item
->hSubMenu
); /* ModifyMenu() spec */
1728 if (flags
& MF_POPUP
)
1730 POPUPMENU
*menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR((UINT16
)id
);
1731 if (IS_A_MENU(menu
)) menu
->wFlags
|= MF_POPUP
;
1743 if (flags
& MF_POPUP
)
1744 item
->hSubMenu
= id
;
1746 if ((item
->fType
& MF_POPUP
) && !(flags
& MF_POPUP
) )
1747 flags
|= MF_POPUP
; /* keep popup */
1749 item
->fType
= flags
& TYPE_MASK
;
1750 item
->fState
= (flags
& STATE_MASK
) &
1751 ~(MF_HILITE
| MF_MOUSESELECT
| MF_BYPOSITION
);
1754 /* Don't call SetRectEmpty here! */
1757 if (prevText
) HeapFree( SystemHeap
, 0, prevText
);
1759 debug_print_menuitem("MENU_SetItemData to : ", item
, "");
1764 /**********************************************************************
1767 * Insert a new item into a menu.
1769 static MENUITEM
*MENU_InsertItem( HMENU hMenu
, UINT pos
, UINT flags
)
1774 if (!(menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
)))
1776 WARN("%04x not a menu handle\n",
1781 /* Find where to insert new item */
1783 if ((flags
& MF_BYPOSITION
) &&
1784 ((pos
== (UINT
)-1) || (pos
== menu
->nItems
)))
1786 /* Special case: append to menu */
1787 /* Some programs specify the menu length to do that */
1792 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
1794 WARN("item %x not found\n",
1798 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
)))
1800 WARN("%04x not a menu handle\n",
1806 /* Create new items array */
1808 newItems
= HeapAlloc( SystemHeap
, 0, sizeof(MENUITEM
) * (menu
->nItems
+1) );
1811 WARN("allocation failed\n" );
1814 if (menu
->nItems
> 0)
1816 /* Copy the old array into the new */
1817 if (pos
> 0) memcpy( newItems
, menu
->items
, pos
* sizeof(MENUITEM
) );
1818 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &menu
->items
[pos
],
1819 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
1820 HeapFree( SystemHeap
, 0, menu
->items
);
1822 menu
->items
= newItems
;
1824 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
1825 return &newItems
[pos
];
1829 /**********************************************************************
1830 * MENU_ParseResource
1832 * Parse a standard menu resource and add items to the menu.
1833 * Return a pointer to the end of the resource.
1835 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1842 flags
= GET_WORD(res
);
1843 res
+= sizeof(WORD
);
1844 if (!(flags
& MF_POPUP
))
1847 res
+= sizeof(WORD
);
1849 if (!IS_STRING_ITEM(flags
))
1850 ERR("not a string item %04x\n", flags
);
1852 if (!unicode
) res
+= strlen(str
) + 1;
1853 else res
+= (lstrlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1854 if (flags
& MF_POPUP
)
1856 HMENU hSubMenu
= CreatePopupMenu();
1857 if (!hSubMenu
) return NULL
;
1858 if (!(res
= MENU_ParseResource( res
, hSubMenu
, unicode
)))
1860 if (!unicode
) AppendMenuA( hMenu
, flags
, (UINT
)hSubMenu
, str
);
1861 else AppendMenuW( hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1863 else /* Not a popup */
1865 if (!unicode
) AppendMenuA( hMenu
, flags
, id
, *str
? str
: NULL
);
1866 else AppendMenuW( hMenu
, flags
, id
,
1867 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1869 } while (!(flags
& MF_END
));
1874 /**********************************************************************
1875 * MENUEX_ParseResource
1877 * Parse an extended menu resource and add items to the menu.
1878 * Return a pointer to the end of the resource.
1880 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
1886 mii
.cbSize
= sizeof(mii
);
1887 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
1888 mii
.fType
= GET_DWORD(res
);
1889 res
+= sizeof(DWORD
);
1890 mii
.fState
= GET_DWORD(res
);
1891 res
+= sizeof(DWORD
);
1892 mii
.wID
= GET_DWORD(res
);
1893 res
+= sizeof(DWORD
);
1894 resinfo
= GET_WORD(res
); /* FIXME: for 16-bit apps this is a byte. */
1895 res
+= sizeof(WORD
);
1896 /* Align the text on a word boundary. */
1897 res
+= (~((int)res
- 1)) & 1;
1898 mii
.dwTypeData
= (LPWSTR
) res
;
1899 res
+= (1 + lstrlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
1900 /* Align the following fields on a dword boundary. */
1901 res
+= (~((int)res
- 1)) & 3;
1903 /* FIXME: This is inefficient and cannot be optimised away by gcc. */
1905 LPSTR newstr
= HEAP_strdupWtoA(GetProcessHeap(),
1907 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
1908 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, newstr
);
1909 HeapFree( GetProcessHeap(), 0, newstr
);
1912 if (resinfo
& 1) { /* Pop-up? */
1913 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
1914 res
+= sizeof(DWORD
);
1915 mii
.hSubMenu
= CreatePopupMenu();
1918 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
1919 DestroyMenu(mii
.hSubMenu
);
1922 mii
.fMask
|= MIIM_SUBMENU
;
1923 mii
.fType
|= MF_POPUP
;
1925 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
1926 } while (!(resinfo
& MF_END
));
1931 /***********************************************************************
1934 * Return the handle of the selected sub-popup menu (if any).
1936 static HMENU
MENU_GetSubPopup( HMENU hmenu
)
1941 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1943 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return 0;
1945 item
= &menu
->items
[menu
->FocusedItem
];
1946 if ((item
->fType
& MF_POPUP
) && (item
->fState
& MF_MOUSESELECT
))
1947 return item
->hSubMenu
;
1952 /***********************************************************************
1953 * MENU_HideSubPopups
1955 * Hide the sub-popup menus of this menu.
1957 static void MENU_HideSubPopups( HWND hwndOwner
, HMENU hmenu
,
1958 BOOL sendMenuSelect
)
1960 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);;
1962 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner
, hmenu
, sendMenuSelect
);
1964 if (menu
&& uSubPWndLevel
)
1970 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1972 item
= &menu
->items
[menu
->FocusedItem
];
1973 if (!(item
->fType
& MF_POPUP
) ||
1974 !(item
->fState
& MF_MOUSESELECT
)) return;
1975 item
->fState
&= ~MF_MOUSESELECT
;
1976 hsubmenu
= item
->hSubMenu
;
1979 submenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hsubmenu
);
1980 MENU_HideSubPopups( hwndOwner
, hsubmenu
, FALSE
);
1981 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, sendMenuSelect
);
1983 if (submenu
->hWnd
== MENU_GetTopPopupWnd()->hwndSelf
)
1985 ShowWindow( submenu
->hWnd
, SW_HIDE
);
1990 DestroyWindow( submenu
->hWnd
);
1993 MENU_ReleaseTopPopupWnd();
1998 /***********************************************************************
2001 * Display the sub-menu of the selected item of this menu.
2002 * Return the handle of the submenu, or hmenu if no submenu to display.
2004 static HMENU
MENU_ShowSubPopup( HWND hwndOwner
, HMENU hmenu
,
2013 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner
, hmenu
, selectFirst
);
2015 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return hmenu
;
2017 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
)) ||
2018 (menu
->FocusedItem
== NO_SELECTED_ITEM
))
2020 WIN_ReleaseWndPtr(wndPtr
);
2024 item
= &menu
->items
[menu
->FocusedItem
];
2025 if (!(item
->fType
& MF_POPUP
) ||
2026 (item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
2028 WIN_ReleaseWndPtr(wndPtr
);
2032 /* message must be send before using item,
2033 because nearly everything may by changed by the application ! */
2035 SendMessageA( hwndOwner
, WM_INITMENUPOPUP
, item
->hSubMenu
,
2036 MAKELONG( menu
->FocusedItem
, IS_SYSTEM_MENU(menu
) ));
2038 item
= &menu
->items
[menu
->FocusedItem
];
2041 /* correct item if modified as a reaction to WM_INITMENUPOPUP-message */
2042 if (!(item
->fState
& MF_HILITE
))
2044 if (menu
->wFlags
& MF_POPUP
) hdc
= GetDC( menu
->hWnd
);
2045 else hdc
= GetDCEx( menu
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2047 SelectObject( hdc
, hMenuFont
);
2049 item
->fState
|= MF_HILITE
;
2050 MENU_DrawMenuItem( menu
->hWnd
, hmenu
, hwndOwner
, hdc
, item
, menu
->Height
, !(menu
->wFlags
& MF_POPUP
), ODA_DRAWENTIRE
);
2051 ReleaseDC( menu
->hWnd
, hdc
);
2053 if (!item
->rect
.top
&& !item
->rect
.left
&& !item
->rect
.bottom
&& !item
->rect
.right
)
2056 item
->fState
|= MF_MOUSESELECT
;
2058 if (IS_SYSTEM_MENU(menu
))
2060 MENU_InitSysMenuPopup(item
->hSubMenu
, wndPtr
->dwStyle
, GetClassLongA(wndPtr
->hwndSelf
, GCL_STYLE
));
2062 NC_GetSysPopupPos( wndPtr
, &rect
);
2063 rect
.top
= rect
.bottom
;
2064 rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2065 rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2069 if (menu
->wFlags
& MF_POPUP
)
2071 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.right
-arrow_bitmap_width
;
2072 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.top
;
2073 rect
.right
= item
->rect
.left
- item
->rect
.right
+ 2*arrow_bitmap_width
;
2074 rect
.bottom
= item
->rect
.top
- item
->rect
.bottom
;
2078 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.left
;
2079 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.bottom
;
2080 rect
.right
= item
->rect
.right
- item
->rect
.left
;
2081 rect
.bottom
= item
->rect
.bottom
- item
->rect
.top
;
2085 MENU_ShowPopup( hwndOwner
, item
->hSubMenu
, menu
->FocusedItem
,
2086 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2088 MENU_MoveSelection( hwndOwner
, item
->hSubMenu
, ITEM_NEXT
);
2089 WIN_ReleaseWndPtr(wndPtr
);
2090 return item
->hSubMenu
;
2093 /***********************************************************************
2096 * Walks menu chain trying to find a menu pt maps to.
2098 static HMENU
MENU_PtMenu( HMENU hMenu
, POINT16 pt
)
2100 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hMenu
);
2101 register UINT ht
= menu
->FocusedItem
;
2103 /* try subpopup first (if any) */
2104 ht
= (ht
!= NO_SELECTED_ITEM
&&
2105 (menu
->items
[ht
].fType
& MF_POPUP
) &&
2106 (menu
->items
[ht
].fState
& MF_MOUSESELECT
))
2107 ? (UINT
) MENU_PtMenu(menu
->items
[ht
].hSubMenu
, pt
) : 0;
2109 if( !ht
) /* check the current window (avoiding WM_HITTEST) */
2111 ht
= (UINT
)NC_HandleNCHitTest( menu
->hWnd
, pt
);
2112 if( menu
->wFlags
& MF_POPUP
)
2113 ht
= (ht
!= (UINT
)HTNOWHERE
&&
2114 ht
!= (UINT
)HTERROR
) ? (UINT
)hMenu
: 0;
2117 WND
* wndPtr
= WIN_FindWndPtr(menu
->hWnd
);
2119 ht
= ( ht
== HTSYSMENU
) ? (UINT
)(wndPtr
->hSysMenu
)
2120 : ( ht
== HTMENU
) ? (UINT
)(wndPtr
->wIDmenu
) : 0;
2121 WIN_ReleaseWndPtr(wndPtr
);
2127 /***********************************************************************
2128 * MENU_ExecFocusedItem
2130 * Execute a menu item (for instance when user pressed Enter).
2131 * Return the wID of the executed item. Otherwise, zero indicating
2132 * that no menu item wase executed;
2133 * Have to receive the flags for the TrackPopupMenu options to avoid
2134 * sending unwanted message.
2137 static INT
MENU_ExecFocusedItem( MTRACKER
* pmt
, HMENU hMenu
, UINT wFlags
)
2140 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hMenu
);
2142 TRACE("%p hmenu=0x%04x\n", pmt
, hMenu
);
2144 if (!menu
|| !menu
->nItems
||
2145 (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return 0;
2147 item
= &menu
->items
[menu
->FocusedItem
];
2149 TRACE("%08x %08x %08x\n",
2150 hMenu
, item
->wID
, item
->hSubMenu
);
2152 if (!(item
->fType
& MF_POPUP
))
2154 if (!(item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
2156 /* If TPM_RETURNCMD is set you return the id, but
2157 do not send a message to the owner */
2158 if(!(wFlags
& TPM_RETURNCMD
))
2160 if( menu
->wFlags
& MF_SYSMENU
)
2161 PostMessageA( pmt
->hOwnerWnd
, WM_SYSCOMMAND
, item
->wID
,
2162 MAKELPARAM((INT16
)pmt
->pt
.x
, (INT16
)pmt
->pt
.y
) );
2164 PostMessageA( pmt
->hOwnerWnd
, WM_COMMAND
, item
->wID
, 0 );
2170 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hMenu
, TRUE
);
2175 /***********************************************************************
2176 * MENU_SwitchTracking
2178 * Helper function for menu navigation routines.
2180 static void MENU_SwitchTracking( MTRACKER
* pmt
, HMENU hPtMenu
, UINT id
)
2182 POPUPMENU
*ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
2183 POPUPMENU
*topmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( pmt
->hTopMenu
);
2185 TRACE("%p hmenu=0x%04x 0x%04x\n", pmt
, hPtMenu
, id
);
2187 if( pmt
->hTopMenu
!= hPtMenu
&&
2188 !((ptmenu
->wFlags
| topmenu
->wFlags
) & MF_POPUP
) )
2190 /* both are top level menus (system and menu-bar) */
2191 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2192 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
);
2193 pmt
->hTopMenu
= hPtMenu
;
2195 else MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
2196 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, id
, TRUE
);
2200 /***********************************************************************
2203 * Return TRUE if we can go on with menu tracking.
2205 static BOOL
MENU_ButtonDown( MTRACKER
* pmt
, HMENU hPtMenu
)
2207 TRACE("%p hmenu=0x%04x\n", pmt
, hPtMenu
);
2212 POPUPMENU
*ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
2215 if( IS_SYSTEM_MENU(ptmenu
) )
2216 item
= ptmenu
->items
;
2218 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2222 if( ptmenu
->FocusedItem
!= id
)
2223 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2225 /* If the popup menu is not already "popped" */
2226 if(!(item
->fState
& MF_MOUSESELECT
))
2227 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
2231 else WARN("\tunable to find clicked item!\n");
2236 /***********************************************************************
2239 * Return the value of MENU_ExecFocusedItem if
2240 * the selected item was not a popup. Else open the popup.
2241 * A zero return value indicates that we go on with menu tracking.
2244 static INT
MENU_ButtonUp( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2246 TRACE("%p hmenu=0x%04x\n", pmt
, hPtMenu
);
2251 POPUPMENU
*ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
2254 if( IS_SYSTEM_MENU(ptmenu
) )
2255 item
= ptmenu
->items
;
2257 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2259 if( item
&& (ptmenu
->FocusedItem
== id
))
2261 if( !(item
->fType
& MF_POPUP
) )
2262 return MENU_ExecFocusedItem( pmt
, hPtMenu
, wFlags
);
2264 /* If we are dealing with the top-level menu and that this */
2265 /* is a click on an already "poppped" item */
2266 /* Stop the menu tracking and close the opened submenus */
2267 if((pmt
->hTopMenu
== hPtMenu
) && (ptmenu
->bTimeToHide
== TRUE
))
2270 ptmenu
->bTimeToHide
= TRUE
;
2276 /***********************************************************************
2279 * Return TRUE if we can go on with menu tracking.
2281 static BOOL
MENU_MouseMove( MTRACKER
* pmt
, HMENU hPtMenu
)
2283 UINT id
= NO_SELECTED_ITEM
;
2284 POPUPMENU
*ptmenu
= NULL
;
2288 ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
2289 if( IS_SYSTEM_MENU(ptmenu
) )
2292 MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2295 if( id
== NO_SELECTED_ITEM
)
2297 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2298 NO_SELECTED_ITEM
, TRUE
);
2300 else if( ptmenu
->FocusedItem
!= id
)
2302 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2303 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
2309 /***********************************************************************
2312 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2314 static LRESULT
MENU_DoNextMenu( MTRACKER
* pmt
, UINT vk
)
2316 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( pmt
->hTopMenu
);
2318 if( (vk
== VK_LEFT
&& menu
->FocusedItem
== 0 ) ||
2319 (vk
== VK_RIGHT
&& menu
->FocusedItem
== menu
->nItems
- 1))
2325 LRESULT l
= SendMessageA( pmt
->hOwnerWnd
, WM_NEXTMENU
, vk
,
2326 (IS_SYSTEM_MENU(menu
)) ? GetSubMenu16(pmt
->hTopMenu
,0) : pmt
->hTopMenu
);
2328 TRACE("%04x [%04x] -> %04x [%04x]\n",
2329 (UINT16
)pmt
->hCurrentMenu
, (UINT16
)pmt
->hOwnerWnd
, LOWORD(l
), HIWORD(l
) );
2333 wndPtr
= WIN_FindWndPtr(pmt
->hOwnerWnd
);
2335 hNewWnd
= pmt
->hOwnerWnd
;
2336 if( IS_SYSTEM_MENU(menu
) )
2338 /* switch to the menu bar */
2340 if( wndPtr
->dwStyle
& WS_CHILD
|| !wndPtr
->wIDmenu
)
2342 WIN_ReleaseWndPtr(wndPtr
);
2346 hNewMenu
= wndPtr
->wIDmenu
;
2349 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hNewMenu
);
2350 id
= menu
->nItems
- 1;
2353 else if( wndPtr
->dwStyle
& WS_SYSMENU
)
2355 /* switch to the system menu */
2356 hNewMenu
= wndPtr
->hSysMenu
;
2360 WIN_ReleaseWndPtr(wndPtr
);
2363 WIN_ReleaseWndPtr(wndPtr
);
2365 else /* application returned a new menu to switch to */
2367 hNewMenu
= LOWORD(l
); hNewWnd
= HIWORD(l
);
2369 if( IsMenu(hNewMenu
) && IsWindow(hNewWnd
) )
2371 wndPtr
= WIN_FindWndPtr(hNewWnd
);
2373 if( wndPtr
->dwStyle
& WS_SYSMENU
&&
2374 GetSubMenu16(wndPtr
->hSysMenu
, 0) == hNewMenu
)
2376 /* get the real system menu */
2377 hNewMenu
= wndPtr
->hSysMenu
;
2379 else if( wndPtr
->dwStyle
& WS_CHILD
|| wndPtr
->wIDmenu
!= hNewMenu
)
2381 /* FIXME: Not sure what to do here, perhaps,
2382 * try to track hNewMenu as a popup? */
2384 TRACE(" -- got confused.\n");
2385 WIN_ReleaseWndPtr(wndPtr
);
2388 WIN_ReleaseWndPtr(wndPtr
);
2393 if( hNewMenu
!= pmt
->hTopMenu
)
2395 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
);
2396 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2397 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2400 if( hNewWnd
!= pmt
->hOwnerWnd
)
2403 pmt
->hOwnerWnd
= hNewWnd
;
2404 EVENT_Capture( pmt
->hOwnerWnd
, HTMENU
);
2407 pmt
->hTopMenu
= pmt
->hCurrentMenu
= hNewMenu
; /* all subpopups are hidden */
2408 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, id
, TRUE
);
2415 /***********************************************************************
2418 * The idea is not to show the popup if the next input message is
2419 * going to hide it anyway.
2421 static BOOL
MENU_SuspendPopup( MTRACKER
* pmt
, UINT16 uMsg
)
2425 msg
.hwnd
= pmt
->hOwnerWnd
;
2427 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2428 pmt
->trackFlags
|= TF_SKIPREMOVE
;
2433 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2434 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
2436 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2437 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2438 if( msg
.message
== WM_KEYDOWN
&&
2439 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
2441 pmt
->trackFlags
|= TF_SUSPENDPOPUP
;
2448 /* failures go through this */
2449 pmt
->trackFlags
&= ~TF_SUSPENDPOPUP
;
2453 /***********************************************************************
2456 * Handle a VK_LEFT key event in a menu.
2458 static void MENU_KeyLeft( MTRACKER
* pmt
)
2461 HMENU hmenutmp
, hmenuprev
;
2464 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
2465 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenutmp
);
2467 /* Try to move 1 column left (if possible) */
2468 if( (prevcol
= MENU_GetStartOfPrevColumn( pmt
->hCurrentMenu
)) !=
2469 NO_SELECTED_ITEM
) {
2471 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2476 /* close topmost popup */
2477 while (hmenutmp
!= pmt
->hCurrentMenu
)
2479 hmenuprev
= hmenutmp
;
2480 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
2483 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
);
2484 pmt
->hCurrentMenu
= hmenuprev
;
2486 if ( (hmenuprev
== pmt
->hTopMenu
) && !(menu
->wFlags
& MF_POPUP
) )
2488 /* move menu bar selection if no more popups are left */
2490 if( !MENU_DoNextMenu( pmt
, VK_LEFT
) )
2491 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_PREV
);
2493 if ( hmenuprev
!= hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2495 /* A sublevel menu was displayed - display the next one
2496 * unless there is another displacement coming up */
2498 if( !MENU_SuspendPopup( pmt
, WM_KEYDOWN
) )
2499 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
,
2500 pmt
->hTopMenu
, TRUE
);
2506 /***********************************************************************
2509 * Handle a VK_RIGHT key event in a menu.
2511 static void MENU_KeyRight( MTRACKER
* pmt
)
2514 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( pmt
->hTopMenu
);
2517 TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2519 ((POPUPMENU
*)USER_HEAP_LIN_ADDR(pmt
->hCurrentMenu
))->
2521 pmt
->hTopMenu
, menu
->items
[0].text
);
2523 if ( (menu
->wFlags
& MF_POPUP
) || (pmt
->hCurrentMenu
!= pmt
->hTopMenu
))
2525 /* If already displaying a popup, try to display sub-popup */
2527 hmenutmp
= pmt
->hCurrentMenu
;
2528 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hmenutmp
, TRUE
);
2530 /* if subpopup was displayed then we are done */
2531 if (hmenutmp
!= pmt
->hCurrentMenu
) return;
2534 /* Check to see if there's another column */
2535 if( (nextcol
= MENU_GetStartOfNextColumn( pmt
->hCurrentMenu
)) !=
2536 NO_SELECTED_ITEM
) {
2537 TRACE("Going to %d.\n", nextcol
);
2538 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2543 if (!(menu
->wFlags
& MF_POPUP
)) /* menu bar tracking */
2545 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2547 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2548 hmenutmp
= pmt
->hCurrentMenu
= pmt
->hTopMenu
;
2549 } else hmenutmp
= 0;
2551 /* try to move to the next item */
2552 if( !MENU_DoNextMenu( pmt
, VK_RIGHT
) )
2553 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_NEXT
);
2555 if( hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2556 if( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
2557 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
,
2558 pmt
->hTopMenu
, TRUE
);
2562 /***********************************************************************
2565 * Menu tracking code.
2567 static INT
MENU_TrackMenu( HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
2568 HWND hwnd
, const RECT
*lprect
)
2573 INT executedMenuId
= 0;
2575 BOOL enterIdleSent
= FALSE
;
2578 mt
.hCurrentMenu
= hmenu
;
2579 mt
.hTopMenu
= hmenu
;
2580 mt
.hOwnerWnd
= hwnd
;
2584 TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2585 hmenu
, wFlags
, x
, y
, hwnd
, (lprect
) ? lprect
->left
: 0, (lprect
) ? lprect
->top
: 0,
2586 (lprect
) ? lprect
->right
: 0, (lprect
) ? lprect
->bottom
: 0);
2589 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
2591 if (wFlags
& TPM_BUTTONDOWN
) MENU_ButtonDown( &mt
, hmenu
);
2593 EVENT_Capture( mt
.hOwnerWnd
, HTMENU
);
2597 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( mt
.hCurrentMenu
);
2598 msg
.hwnd
= (wFlags
& TPM_ENTERIDLEEX
&& menu
->wFlags
& MF_POPUP
) ? menu
->hWnd
: 0;
2600 /* we have to keep the message in the queue until it's
2601 * clear that menu loop is not over yet. */
2603 if (!MSG_InternalGetMessage( &msg
, msg
.hwnd
, mt
.hOwnerWnd
,
2604 MSGF_MENU
, PM_NOREMOVE
, !enterIdleSent
, &enterIdleSent
)) break;
2606 TranslateMessage( &msg
);
2609 if ( (msg
.hwnd
==menu
->hWnd
) || (msg
.message
!=WM_TIMER
) )
2610 enterIdleSent
=FALSE
;
2613 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
2615 /* Find a menu for this mouse event */
2617 CONV_POINT32TO16( &msg
.pt
, &pt16
);
2618 hmenu
= MENU_PtMenu( mt
.hTopMenu
, pt16
);
2622 /* no WM_NC... messages in captured state */
2624 case WM_RBUTTONDBLCLK
:
2625 case WM_RBUTTONDOWN
:
2626 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2628 case WM_LBUTTONDBLCLK
:
2629 case WM_LBUTTONDOWN
:
2630 fEndMenu
|= !MENU_ButtonDown( &mt
, hmenu
);
2634 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2637 /* Check if a menu was selected by the mouse */
2640 executedMenuId
= MENU_ButtonUp( &mt
, hmenu
, wFlags
);
2642 /* End the loop if executedMenuId is an item ID */
2643 /* or if the job was done (executedMenuId = 1). */
2644 fEndMenu
= fRemove
= (executedMenuId
!= 0);
2646 /* No menu was selected by the mouse */
2647 /* if the function was called by TrackPopupMenu, continue
2648 with the menu tracking. If not, stop it */
2650 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
2655 /* In win95 winelook, the selected menu item must be changed every time the
2656 mouse moves. In Win31 winelook, the mouse button has to be held down */
2658 if ( (TWEAK_WineLook
> WIN31_LOOK
) ||
2659 ( (msg
.wParam
& MK_LBUTTON
) ||
2660 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
.wParam
& MK_RBUTTON
))) )
2662 fEndMenu
|= !MENU_MouseMove( &mt
, hmenu
);
2664 } /* switch(msg.message) - mouse */
2666 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
2668 fRemove
= TRUE
; /* Keyboard messages are always removed */
2676 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2677 NO_SELECTED_ITEM
, FALSE
);
2680 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2681 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
2684 case VK_DOWN
: /* If on menu bar, pull-down the menu */
2686 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( mt
.hCurrentMenu
);
2687 if (!(menu
->wFlags
& MF_POPUP
))
2688 mt
.hCurrentMenu
= MENU_ShowSubPopup( mt
.hOwnerWnd
, mt
.hTopMenu
, TRUE
);
2689 else /* otherwise try to move selection */
2690 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
, ITEM_NEXT
);
2694 MENU_KeyLeft( &mt
);
2698 MENU_KeyRight( &mt
);
2708 break; /* WM_KEYDOWN */
2718 break; /* WM_SYSKEYDOWN */
2724 if (msg
.wParam
== '\r' || msg
.wParam
== ' ')
2726 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2727 fEndMenu
= (executedMenuId
!= 0);
2732 /* Hack to avoid control chars. */
2733 /* We will find a better way real soon... */
2734 if ((msg
.wParam
<= 32) || (msg
.wParam
>= 127)) break;
2736 pos
= MENU_FindItemByKey( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2737 LOWORD(msg
.wParam
), FALSE
);
2738 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
2739 else if (pos
== (UINT
)-1) MessageBeep(0);
2742 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
, pos
, TRUE
);
2743 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2744 fEndMenu
= (executedMenuId
!= 0);
2748 } /* switch(msg.message) - kbd */
2752 DispatchMessageA( &msg
);
2755 if (!fEndMenu
) fRemove
= TRUE
;
2757 /* finally remove message from the queue */
2759 if (fRemove
&& !(mt
.trackFlags
& TF_SKIPREMOVE
) )
2760 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2761 else mt
.trackFlags
&= ~TF_SKIPREMOVE
;
2766 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( mt
.hTopMenu
);
2768 if( IsWindow( mt
.hOwnerWnd
) )
2770 MENU_HideSubPopups( mt
.hOwnerWnd
, mt
.hTopMenu
, FALSE
);
2772 if (menu
&& menu
->wFlags
& MF_POPUP
)
2774 ShowWindow( menu
->hWnd
, SW_HIDE
);
2777 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hTopMenu
, NO_SELECTED_ITEM
, FALSE
);
2778 SendMessageA( mt
.hOwnerWnd
, WM_MENUSELECT
, MAKELONG(0,0), 0xffff );
2781 /* Reset the variable for hiding menu */
2782 menu
->bTimeToHide
= FALSE
;
2784 /* Returning the id of the selected menu.
2785 The return value is only used by TrackPopupMenu */
2786 return executedMenuId
;
2789 /***********************************************************************
2792 static BOOL
MENU_InitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
)
2795 TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd
, hMenu
);
2798 SendMessageA( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
2799 SendMessageA( hWnd
, WM_SETCURSOR
, hWnd
, HTCAPTION
);
2800 SendMessageA( hWnd
, WM_INITMENU
, hMenu
, 0 );
2803 /***********************************************************************
2806 static BOOL
MENU_ExitTracking(HWND hWnd
)
2808 TRACE("hwnd=0x%04x\n", hWnd
);
2810 SendMessageA( hWnd
, WM_EXITMENULOOP
, 0, 0 );
2815 /***********************************************************************
2816 * MENU_TrackMouseMenuBar
2818 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2820 void MENU_TrackMouseMenuBar( WND
* wndPtr
, INT ht
, POINT pt
)
2822 HWND hWnd
= wndPtr
->hwndSelf
;
2823 HMENU hMenu
= (ht
== HTSYSMENU
) ? wndPtr
->hSysMenu
: wndPtr
->wIDmenu
;
2825 TRACE("pwnd=%p ht=0x%04x (%ld,%ld)\n", wndPtr
, ht
, pt
.x
, pt
.y
);
2829 MENU_InitTracking( hWnd
, hMenu
, FALSE
);
2830 MENU_TrackMenu( hMenu
, TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
|
2831 TPM_LEFTALIGN
| TPM_LEFTBUTTON
, pt
.x
, pt
.y
, hWnd
, NULL
);
2832 MENU_ExitTracking(hWnd
);
2837 /***********************************************************************
2838 * MENU_TrackKbdMenuBar
2840 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
2842 void MENU_TrackKbdMenuBar( WND
* wndPtr
, UINT wParam
, INT vkey
)
2844 UINT uItem
= NO_SELECTED_ITEM
;
2847 /* find window that has a menu */
2849 while( wndPtr
->dwStyle
& WS_CHILD
&& !(wndPtr
->dwStyle
& WS_SYSMENU
) )
2850 if( !(wndPtr
= wndPtr
->parent
) ) return;
2852 /* check if we have to track a system menu */
2854 if( (wndPtr
->dwStyle
& (WS_CHILD
| WS_MINIMIZE
)) ||
2855 !wndPtr
->wIDmenu
|| vkey
== VK_SPACE
)
2857 if( !(wndPtr
->dwStyle
& WS_SYSMENU
) ) return;
2858 hTrackMenu
= wndPtr
->hSysMenu
;
2860 wParam
|= HTSYSMENU
; /* prevent item lookup */
2863 hTrackMenu
= wndPtr
->wIDmenu
;
2865 if (IsMenu( hTrackMenu
))
2867 MENU_InitTracking( wndPtr
->hwndSelf
, hTrackMenu
, FALSE
);
2869 if( vkey
&& vkey
!= VK_SPACE
)
2871 uItem
= MENU_FindItemByKey( wndPtr
->hwndSelf
, hTrackMenu
,
2872 vkey
, (wParam
& HTSYSMENU
) );
2873 if( uItem
>= (UINT
)(-2) )
2875 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
2882 MENU_SelectItem( wndPtr
->hwndSelf
, hTrackMenu
, uItem
, TRUE
);
2884 if( uItem
== NO_SELECTED_ITEM
)
2885 MENU_MoveSelection( wndPtr
->hwndSelf
, hTrackMenu
, ITEM_NEXT
);
2887 PostMessageA( wndPtr
->hwndSelf
, WM_KEYDOWN
, VK_DOWN
, 0L );
2889 MENU_TrackMenu( hTrackMenu
, TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
2890 0, 0, wndPtr
->hwndSelf
, NULL
);
2893 MENU_ExitTracking (wndPtr
->hwndSelf
);
2898 /**********************************************************************
2899 * TrackPopupMenu16 (USER.416)
2901 BOOL16 WINAPI
TrackPopupMenu16( HMENU16 hMenu
, UINT16 wFlags
, INT16 x
, INT16 y
,
2902 INT16 nReserved
, HWND16 hWnd
, const RECT16
*lpRect
)
2906 CONV_RECT16TO32( lpRect
, &r
);
2907 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, nReserved
, hWnd
,
2908 lpRect
? &r
: NULL
);
2912 /**********************************************************************
2913 * TrackPopupMenu (USER32.549)
2915 * Like the win32 API, the function return the command ID only if the
2916 * flag TPM_RETURNCMD is on.
2919 BOOL WINAPI
TrackPopupMenu( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
2920 INT nReserved
, HWND hWnd
, const RECT
*lpRect
)
2924 MENU_InitTracking(hWnd
, hMenu
, TRUE
);
2925 SendMessageA( hWnd
, WM_INITMENUPOPUP
, hMenu
, 0);
2926 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
, 0, 0 ))
2927 ret
= MENU_TrackMenu( hMenu
, wFlags
| TPM_POPUPMENU
, 0, 0, hWnd
, lpRect
);
2928 MENU_ExitTracking(hWnd
);
2930 if( (!(wFlags
& TPM_RETURNCMD
)) && (ret
!= FALSE
) )
2936 /**********************************************************************
2937 * TrackPopupMenuEx (USER32.550)
2939 BOOL WINAPI
TrackPopupMenuEx( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
2940 HWND hWnd
, LPTPMPARAMS lpTpm
)
2942 FIXME("not fully implemented\n" );
2943 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, 0, hWnd
,
2944 lpTpm
? &lpTpm
->rcExclude
: NULL
);
2947 /***********************************************************************
2950 * NOTE: Windows has totally different (and undocumented) popup wndproc.
2952 LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
,
2955 WND
* wndPtr
= WIN_FindWndPtr(hwnd
);
2958 TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
2959 hwnd
, message
, wParam
, lParam
);
2965 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*)lParam
;
2966 SetWindowLongA( hwnd
, 0, (LONG
)cs
->lpCreateParams
);
2971 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2972 retvalue
= MA_NOACTIVATE
;
2978 BeginPaint( hwnd
, &ps
);
2979 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
2980 (HMENU
)GetWindowLongA( hwnd
, 0 ) );
2981 EndPaint( hwnd
, &ps
);
2991 /* zero out global pointer in case resident popup window
2992 * was somehow destroyed. */
2994 if(MENU_GetTopPopupWnd() )
2996 if( hwnd
== pTopPopupWnd
->hwndSelf
)
2998 ERR("resident popup destroyed!\n");
3000 MENU_DestroyTopPopupWnd();
3005 MENU_ReleaseTopPopupWnd();
3013 if( !(*(HMENU
*)wndPtr
->wExtra
) )
3014 ERR("no menu to display\n");
3017 *(HMENU
*)wndPtr
->wExtra
= 0;
3020 case MM_SETMENUHANDLE
:
3022 *(HMENU
*)wndPtr
->wExtra
= (HMENU
)wParam
;
3025 case MM_GETMENUHANDLE
:
3027 retvalue
= *(HMENU
*)wndPtr
->wExtra
;
3031 retvalue
= DefWindowProcA( hwnd
, message
, wParam
, lParam
);
3036 WIN_ReleaseWndPtr(wndPtr
);
3041 /***********************************************************************
3042 * MENU_GetMenuBarHeight
3044 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3046 UINT
MENU_GetMenuBarHeight( HWND hwnd
, UINT menubarWidth
,
3047 INT orgX
, INT orgY
)
3055 TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3056 hwnd
, menubarWidth
, orgX
, orgY
);
3058 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
3061 if (!(lppop
= (LPPOPUPMENU
)USER_HEAP_LIN_ADDR((HMENU16
)wndPtr
->wIDmenu
)))
3063 WIN_ReleaseWndPtr(wndPtr
);
3067 hdc
= GetDCEx( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3068 SelectObject( hdc
, hMenuFont
);
3069 SetRect(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+GetSystemMetrics(SM_CYMENU
));
3070 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
3071 ReleaseDC( hwnd
, hdc
);
3072 retvalue
= lppop
->Height
;
3073 WIN_ReleaseWndPtr(wndPtr
);
3078 /*******************************************************************
3079 * ChangeMenu16 (USER.153)
3081 BOOL16 WINAPI
ChangeMenu16( HMENU16 hMenu
, UINT16 pos
, SEGPTR data
,
3082 UINT16 id
, UINT16 flags
)
3084 TRACE("menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
3085 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3086 if (flags
& MF_APPEND
) return AppendMenu16( hMenu
, flags
& ~MF_APPEND
,
3089 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
3090 /* for MF_DELETE. We should check the parameters for all others */
3091 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
3093 if (flags
& MF_DELETE
) return DeleteMenu16(hMenu
, pos
, flags
& ~MF_DELETE
);
3094 if (flags
& MF_CHANGE
) return ModifyMenu16(hMenu
, pos
, flags
& ~MF_CHANGE
,
3096 if (flags
& MF_REMOVE
) return RemoveMenu16(hMenu
,
3097 flags
& MF_BYPOSITION
? pos
: id
,
3098 flags
& ~MF_REMOVE
);
3099 /* Default: MF_INSERT */
3100 return InsertMenu16( hMenu
, pos
, flags
, id
, data
);
3104 /*******************************************************************
3105 * ChangeMenu32A (USER32.23)
3107 BOOL WINAPI
ChangeMenuA( HMENU hMenu
, UINT pos
, LPCSTR data
,
3108 UINT id
, UINT flags
)
3110 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3111 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3112 if (flags
& MF_APPEND
) return AppendMenuA( hMenu
, flags
& ~MF_APPEND
,
3114 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3115 if (flags
& MF_CHANGE
) return ModifyMenuA(hMenu
, pos
, flags
& ~MF_CHANGE
,
3117 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3118 flags
& MF_BYPOSITION
? pos
: id
,
3119 flags
& ~MF_REMOVE
);
3120 /* Default: MF_INSERT */
3121 return InsertMenuA( hMenu
, pos
, flags
, id
, data
);
3125 /*******************************************************************
3126 * ChangeMenu32W (USER32.24)
3128 BOOL WINAPI
ChangeMenuW( HMENU hMenu
, UINT pos
, LPCWSTR data
,
3129 UINT id
, UINT flags
)
3131 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3132 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3133 if (flags
& MF_APPEND
) return AppendMenuW( hMenu
, flags
& ~MF_APPEND
,
3135 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3136 if (flags
& MF_CHANGE
) return ModifyMenuW(hMenu
, pos
, flags
& ~MF_CHANGE
,
3138 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3139 flags
& MF_BYPOSITION
? pos
: id
,
3140 flags
& ~MF_REMOVE
);
3141 /* Default: MF_INSERT */
3142 return InsertMenuW( hMenu
, pos
, flags
, id
, data
);
3146 /*******************************************************************
3147 * CheckMenuItem16 (USER.154)
3149 BOOL16 WINAPI
CheckMenuItem16( HMENU16 hMenu
, UINT16 id
, UINT16 flags
)
3151 return (BOOL16
)CheckMenuItem( hMenu
, id
, flags
);
3155 /*******************************************************************
3156 * CheckMenuItem (USER32.46)
3158 DWORD WINAPI
CheckMenuItem( HMENU hMenu
, UINT id
, UINT flags
)
3163 TRACE("menu=%04x id=%04x flags=%04x\n", hMenu
, id
, flags
);
3164 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
3165 ret
= item
->fState
& MF_CHECKED
;
3166 if (flags
& MF_CHECKED
) item
->fState
|= MF_CHECKED
;
3167 else item
->fState
&= ~MF_CHECKED
;
3172 /**********************************************************************
3173 * EnableMenuItem16 (USER.155)
3175 UINT16 WINAPI
EnableMenuItem16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3177 return EnableMenuItem( hMenu
, wItemID
, wFlags
);
3181 /**********************************************************************
3182 * EnableMenuItem32 (USER32.170)
3184 UINT WINAPI
EnableMenuItem( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3190 TRACE("(%04x, %04X, %04X) !\n",
3191 hMenu
, wItemID
, wFlags
);
3193 /* Get the Popupmenu to access the owner menu */
3194 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
)))
3197 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
)))
3200 oldflags
= item
->fState
& (MF_GRAYED
| MF_DISABLED
);
3201 item
->fState
^= (oldflags
^ wFlags
) & (MF_GRAYED
| MF_DISABLED
);
3203 /* In win95 if the close item in the system menu change update the close button */
3204 if (TWEAK_WineLook
== WIN95_LOOK
)
3205 if((item
->wID
== SC_CLOSE
) && (oldflags
!= wFlags
))
3207 if (menu
->hSysMenuOwner
!= 0)
3209 POPUPMENU
* parentMenu
;
3211 /* Get the parent menu to access*/
3212 if (!(parentMenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(menu
->hSysMenuOwner
)))
3215 /* Refresh the frame to reflect the change*/
3216 SetWindowPos(parentMenu
->hWnd
, 0, 0, 0, 0, 0,
3217 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
3225 /*******************************************************************
3226 * GetMenuString16 (USER.161)
3228 INT16 WINAPI
GetMenuString16( HMENU16 hMenu
, UINT16 wItemID
,
3229 LPSTR str
, INT16 nMaxSiz
, UINT16 wFlags
)
3231 return GetMenuStringA( hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3235 /*******************************************************************
3236 * GetMenuString32A (USER32.268)
3238 INT WINAPI
GetMenuStringA( HMENU hMenu
, UINT wItemID
,
3239 LPSTR str
, INT nMaxSiz
, UINT wFlags
)
3243 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3244 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3245 if (!str
|| !nMaxSiz
) return 0;
3247 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3248 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3249 lstrcpynA( str
, item
->text
, nMaxSiz
);
3250 TRACE("returning '%s'\n", str
);
3255 /*******************************************************************
3256 * GetMenuString32W (USER32.269)
3258 INT WINAPI
GetMenuStringW( HMENU hMenu
, UINT wItemID
,
3259 LPWSTR str
, INT nMaxSiz
, UINT wFlags
)
3263 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3264 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3265 if (!str
|| !nMaxSiz
) return 0;
3267 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3268 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3269 lstrcpynAtoW( str
, item
->text
, nMaxSiz
);
3270 return lstrlenW(str
);
3274 /**********************************************************************
3275 * HiliteMenuItem16 (USER.162)
3277 BOOL16 WINAPI
HiliteMenuItem16( HWND16 hWnd
, HMENU16 hMenu
, UINT16 wItemID
,
3280 return HiliteMenuItem( hWnd
, hMenu
, wItemID
, wHilite
);
3284 /**********************************************************************
3285 * HiliteMenuItem32 (USER32.318)
3287 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
3291 TRACE("(%04x, %04x, %04x, %04x);\n",
3292 hWnd
, hMenu
, wItemID
, wHilite
);
3293 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
3294 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
3295 if (menu
->FocusedItem
== wItemID
) return TRUE
;
3296 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
3297 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
);
3302 /**********************************************************************
3303 * GetMenuState16 (USER.250)
3305 UINT16 WINAPI
GetMenuState16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3307 return GetMenuState( hMenu
, wItemID
, wFlags
);
3311 /**********************************************************************
3312 * GetMenuState (USER32.267)
3314 UINT WINAPI
GetMenuState( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3317 TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
3318 hMenu
, wItemID
, wFlags
);
3319 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
3320 debug_print_menuitem (" item: ", item
, "");
3321 if (item
->fType
& MF_POPUP
)
3323 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( item
->hSubMenu
);
3324 if (!menu
) return -1;
3325 else return (menu
->nItems
<< 8) | ((item
->fState
|item
->fType
) & 0xff);
3329 /* We used to (from way back then) mask the result to 0xff. */
3330 /* I don't know why and it seems wrong as the documented */
3331 /* return flag MF_SEPARATOR is outside that mask. */
3332 return (item
->fType
| item
->fState
);
3337 /**********************************************************************
3338 * GetMenuItemCount16 (USER.263)
3340 INT16 WINAPI
GetMenuItemCount16( HMENU16 hMenu
)
3342 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3343 if (!IS_A_MENU(menu
)) return -1;
3344 TRACE("(%04x) returning %d\n",
3345 hMenu
, menu
->nItems
);
3346 return menu
->nItems
;
3350 /**********************************************************************
3351 * GetMenuItemCount32 (USER32.262)
3353 INT WINAPI
GetMenuItemCount( HMENU hMenu
)
3355 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3356 if (!IS_A_MENU(menu
)) return -1;
3357 TRACE("(%04x) returning %d\n",
3358 hMenu
, menu
->nItems
);
3359 return menu
->nItems
;
3362 /**********************************************************************
3363 * GetMenuItemID16 (USER.264)
3365 UINT16 WINAPI
GetMenuItemID16( HMENU16 hMenu
, INT16 nPos
)
3367 return (UINT16
) GetMenuItemID (hMenu
, nPos
);
3370 /**********************************************************************
3371 * GetMenuItemID32 (USER32.263)
3373 UINT WINAPI
GetMenuItemID( HMENU hMenu
, INT nPos
)
3377 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return 0;
3378 if (lpmi
->fType
& MF_POPUP
) return -1;
3383 /*******************************************************************
3384 * InsertMenu16 (USER.410)
3386 BOOL16 WINAPI
InsertMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3387 UINT16 id
, SEGPTR data
)
3389 UINT pos32
= (UINT
)pos
;
3390 if ((pos
== (UINT16
)-1) && (flags
& MF_BYPOSITION
)) pos32
= (UINT
)-1;
3391 if (IS_STRING_ITEM(flags
) && data
)
3392 return InsertMenuA( hMenu
, pos32
, flags
, id
,
3393 (LPSTR
)PTR_SEG_TO_LIN(data
) );
3394 return InsertMenuA( hMenu
, pos32
, flags
, id
, (LPSTR
)data
);
3398 /*******************************************************************
3399 * InsertMenu32A (USER32.322)
3401 BOOL WINAPI
InsertMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3402 UINT id
, LPCSTR str
)
3406 if (IS_STRING_ITEM(flags
) && str
)
3407 TRACE("hMenu %04x, pos %d, flags %08x, "
3408 "id %04x, str '%s'\n",
3409 hMenu
, pos
, flags
, id
, str
);
3410 else TRACE("hMenu %04x, pos %d, flags %08x, "
3411 "id %04x, str %08lx (not a string)\n",
3412 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3414 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
3416 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
3418 RemoveMenu( hMenu
, pos
, flags
);
3422 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
3423 ((POPUPMENU
*)USER_HEAP_LIN_ADDR((HMENU16
)id
))->wFlags
|= MF_POPUP
;
3425 item
->hCheckBit
= item
->hUnCheckBit
= 0;
3430 /*******************************************************************
3431 * InsertMenu32W (USER32.325)
3433 BOOL WINAPI
InsertMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3434 UINT id
, LPCWSTR str
)
3438 if (IS_STRING_ITEM(flags
) && str
)
3440 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
3441 ret
= InsertMenuA( hMenu
, pos
, flags
, id
, newstr
);
3442 HeapFree( GetProcessHeap(), 0, newstr
);
3445 else return InsertMenuA( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
3449 /*******************************************************************
3450 * AppendMenu16 (USER.411)
3452 BOOL16 WINAPI
AppendMenu16(HMENU16 hMenu
, UINT16 flags
, UINT16 id
, SEGPTR data
)
3454 return InsertMenu16( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3458 /*******************************************************************
3459 * AppendMenu32A (USER32.5)
3461 BOOL WINAPI
AppendMenuA( HMENU hMenu
, UINT flags
,
3462 UINT id
, LPCSTR data
)
3464 return InsertMenuA( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3468 /*******************************************************************
3469 * AppendMenu32W (USER32.6)
3471 BOOL WINAPI
AppendMenuW( HMENU hMenu
, UINT flags
,
3472 UINT id
, LPCWSTR data
)
3474 return InsertMenuW( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3478 /**********************************************************************
3479 * RemoveMenu16 (USER.412)
3481 BOOL16 WINAPI
RemoveMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3483 return RemoveMenu( hMenu
, nPos
, wFlags
);
3487 /**********************************************************************
3488 * RemoveMenu (USER32.441)
3490 BOOL WINAPI
RemoveMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3495 TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu
, nPos
, wFlags
);
3496 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3497 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
3501 MENU_FreeItemData( item
);
3503 if (--menu
->nItems
== 0)
3505 HeapFree( SystemHeap
, 0, menu
->items
);
3510 while(nPos
< menu
->nItems
)
3516 menu
->items
= HeapReAlloc( SystemHeap
, 0, menu
->items
,
3517 menu
->nItems
* sizeof(MENUITEM
) );
3523 /**********************************************************************
3524 * DeleteMenu16 (USER.413)
3526 BOOL16 WINAPI
DeleteMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3528 return DeleteMenu( hMenu
, nPos
, wFlags
);
3532 /**********************************************************************
3533 * DeleteMenu32 (USER32.129)
3535 BOOL WINAPI
DeleteMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3537 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
3538 if (!item
) return FALSE
;
3539 if (item
->fType
& MF_POPUP
) DestroyMenu( item
->hSubMenu
);
3540 /* nPos is now the position of the item */
3541 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
3546 /*******************************************************************
3547 * ModifyMenu16 (USER.414)
3549 BOOL16 WINAPI
ModifyMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3550 UINT16 id
, SEGPTR data
)
3552 if (IS_STRING_ITEM(flags
))
3553 return ModifyMenuA( hMenu
, pos
, flags
, id
,
3554 (LPSTR
)PTR_SEG_TO_LIN(data
) );
3555 return ModifyMenuA( hMenu
, pos
, flags
, id
, (LPSTR
)data
);
3559 /*******************************************************************
3560 * ModifyMenu32A (USER32.397)
3562 BOOL WINAPI
ModifyMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3563 UINT id
, LPCSTR str
)
3567 if (IS_STRING_ITEM(flags
))
3569 TRACE("%04x %d %04x %04x '%s'\n",
3570 hMenu
, pos
, flags
, id
, str
? str
: "#NULL#" );
3571 if (!str
) return FALSE
;
3575 TRACE("%04x %d %04x %04x %08lx\n",
3576 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3579 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
3580 return MENU_SetItemData( item
, flags
, id
, str
);
3584 /*******************************************************************
3585 * ModifyMenu32W (USER32.398)
3587 BOOL WINAPI
ModifyMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3588 UINT id
, LPCWSTR str
)
3592 if (IS_STRING_ITEM(flags
) && str
)
3594 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
3595 ret
= ModifyMenuA( hMenu
, pos
, flags
, id
, newstr
);
3596 HeapFree( GetProcessHeap(), 0, newstr
);
3599 else return ModifyMenuA( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
3603 /**********************************************************************
3604 * CreatePopupMenu16 (USER.415)
3606 HMENU16 WINAPI
CreatePopupMenu16(void)
3608 return CreatePopupMenu();
3612 /**********************************************************************
3613 * CreatePopupMenu32 (USER32.82)
3615 HMENU WINAPI
CreatePopupMenu(void)
3620 if (!(hmenu
= CreateMenu())) return 0;
3621 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
3622 menu
->wFlags
|= MF_POPUP
;
3623 menu
->bTimeToHide
= FALSE
;
3628 /**********************************************************************
3629 * GetMenuCheckMarkDimensions (USER.417) (USER32.258)
3631 DWORD WINAPI
GetMenuCheckMarkDimensions(void)
3633 return MAKELONG( check_bitmap_width
, check_bitmap_height
);
3637 /**********************************************************************
3638 * SetMenuItemBitmaps16 (USER.418)
3640 BOOL16 WINAPI
SetMenuItemBitmaps16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
,
3641 HBITMAP16 hNewUnCheck
, HBITMAP16 hNewCheck
)
3643 return SetMenuItemBitmaps( hMenu
, nPos
, wFlags
, hNewUnCheck
, hNewCheck
);
3647 /**********************************************************************
3648 * SetMenuItemBitmaps32 (USER32.490)
3650 BOOL WINAPI
SetMenuItemBitmaps( HMENU hMenu
, UINT nPos
, UINT wFlags
,
3651 HBITMAP hNewUnCheck
, HBITMAP hNewCheck
)
3654 TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3655 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
3656 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3658 if (!hNewCheck
&& !hNewUnCheck
)
3660 item
->fState
&= ~MF_USECHECKBITMAPS
;
3662 else /* Install new bitmaps */
3664 item
->hCheckBit
= hNewCheck
;
3665 item
->hUnCheckBit
= hNewUnCheck
;
3666 item
->fState
|= MF_USECHECKBITMAPS
;
3672 /**********************************************************************
3673 * CreateMenu16 (USER.151)
3675 HMENU16 WINAPI
CreateMenu16(void)
3677 return CreateMenu();
3681 /**********************************************************************
3682 * CreateMenu (USER32.81)
3684 HMENU WINAPI
CreateMenu(void)
3688 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) ))) return 0;
3689 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3691 ZeroMemory(menu
, sizeof(POPUPMENU
));
3692 menu
->wMagic
= MENU_MAGIC
;
3693 menu
->FocusedItem
= NO_SELECTED_ITEM
;
3694 menu
->bTimeToHide
= FALSE
;
3696 TRACE("return %04x\n", hMenu
);
3702 /**********************************************************************
3703 * DestroyMenu16 (USER.152)
3705 BOOL16 WINAPI
DestroyMenu16( HMENU16 hMenu
)
3707 return DestroyMenu( hMenu
);
3711 /**********************************************************************
3712 * DestroyMenu32 (USER32.134)
3714 BOOL WINAPI
DestroyMenu( HMENU hMenu
)
3716 TRACE("(%04x)\n", hMenu
);
3718 /* Silently ignore attempts to destroy default system popup */
3720 if (hMenu
&& hMenu
!= MENU_DefSysPopup
)
3722 LPPOPUPMENU lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3723 WND
*pTPWnd
= MENU_GetTopPopupWnd();
3725 if( pTPWnd
&& (hMenu
== *(HMENU
*)pTPWnd
->wExtra
) )
3726 *(UINT
*)pTPWnd
->wExtra
= 0;
3728 if (IS_A_MENU( lppop
))
3730 lppop
->wMagic
= 0; /* Mark it as destroyed */
3732 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
&&
3733 (!pTPWnd
|| (lppop
->hWnd
!= pTPWnd
->hwndSelf
)))
3734 DestroyWindow( lppop
->hWnd
);
3736 if (lppop
->items
) /* recursively destroy submenus */
3739 MENUITEM
*item
= lppop
->items
;
3740 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
3742 if (item
->fType
& MF_POPUP
) DestroyMenu(item
->hSubMenu
);
3743 MENU_FreeItemData( item
);
3745 HeapFree( SystemHeap
, 0, lppop
->items
);
3747 USER_HEAP_FREE( hMenu
);
3748 MENU_ReleaseTopPopupWnd();
3752 MENU_ReleaseTopPopupWnd();
3756 return (hMenu
!= MENU_DefSysPopup
);
3760 /**********************************************************************
3761 * GetSystemMenu16 (USER.156)
3763 HMENU16 WINAPI
GetSystemMenu16( HWND16 hWnd
, BOOL16 bRevert
)
3765 return GetSystemMenu( hWnd
, bRevert
);
3769 /**********************************************************************
3770 * GetSystemMenu32 (USER32.291)
3772 HMENU WINAPI
GetSystemMenu( HWND hWnd
, BOOL bRevert
)
3774 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
3779 if( wndPtr
->hSysMenu
)
3783 DestroyMenu(wndPtr
->hSysMenu
);
3784 wndPtr
->hSysMenu
= 0;
3788 POPUPMENU
*menu
= (POPUPMENU
*)
3789 USER_HEAP_LIN_ADDR(wndPtr
->hSysMenu
);
3790 if( IS_A_MENU(menu
) )
3792 if( menu
->nItems
> 0 && menu
->items
[0].hSubMenu
== MENU_DefSysPopup
)
3793 menu
->items
[0].hSubMenu
= MENU_CopySysPopup();
3797 WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
3798 wndPtr
->hSysMenu
, hWnd
);
3799 wndPtr
->hSysMenu
= 0;
3804 if(!wndPtr
->hSysMenu
&& (wndPtr
->dwStyle
& WS_SYSMENU
) )
3805 wndPtr
->hSysMenu
= MENU_GetSysMenu( hWnd
, (HMENU
)(-1) );
3807 if( wndPtr
->hSysMenu
)
3810 retvalue
= GetSubMenu16(wndPtr
->hSysMenu
, 0);
3812 /* Store the dummy sysmenu handle to facilitate the refresh */
3813 /* of the close button if the SC_CLOSE item change */
3814 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(retvalue
);
3815 if ( IS_A_MENU(menu
) )
3816 menu
->hSysMenuOwner
= wndPtr
->hSysMenu
;
3818 WIN_ReleaseWndPtr(wndPtr
);
3824 /*******************************************************************
3825 * SetSystemMenu16 (USER.280)
3827 BOOL16 WINAPI
SetSystemMenu16( HWND16 hwnd
, HMENU16 hMenu
)
3829 return SetSystemMenu( hwnd
, hMenu
);
3833 /*******************************************************************
3834 * SetSystemMenu32 (USER32.508)
3836 BOOL WINAPI
SetSystemMenu( HWND hwnd
, HMENU hMenu
)
3838 WND
*wndPtr
= WIN_FindWndPtr(hwnd
);
3842 if (wndPtr
->hSysMenu
) DestroyMenu( wndPtr
->hSysMenu
);
3843 wndPtr
->hSysMenu
= MENU_GetSysMenu( hwnd
, hMenu
);
3844 WIN_ReleaseWndPtr(wndPtr
);
3851 /**********************************************************************
3852 * GetMenu16 (USER.157)
3854 HMENU16 WINAPI
GetMenu16( HWND16 hWnd
)
3857 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
3858 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
3860 retvalue
= (HMENU16
)wndPtr
->wIDmenu
;
3865 WIN_ReleaseWndPtr(wndPtr
);
3870 /**********************************************************************
3871 * GetMenu32 (USER32.257)
3873 HMENU WINAPI
GetMenu( HWND hWnd
)
3876 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
3877 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
3879 retvalue
= (HMENU
)wndPtr
->wIDmenu
;
3884 WIN_ReleaseWndPtr(wndPtr
);
3889 /**********************************************************************
3890 * SetMenu16 (USER.158)
3892 BOOL16 WINAPI
SetMenu16( HWND16 hWnd
, HMENU16 hMenu
)
3894 return SetMenu( hWnd
, hMenu
);
3898 /**********************************************************************
3899 * SetMenu32 (USER32.487)
3901 BOOL WINAPI
SetMenu( HWND hWnd
, HMENU hMenu
)
3903 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
3905 TRACE("(%04x, %04x);\n", hWnd
, hMenu
);
3907 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
3909 if (GetCapture() == hWnd
) ReleaseCapture();
3911 wndPtr
->wIDmenu
= (UINT
)hMenu
;
3916 if (!(lpmenu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
)))
3918 WIN_ReleaseWndPtr(wndPtr
);
3921 lpmenu
->hWnd
= hWnd
;
3922 lpmenu
->wFlags
&= ~MF_POPUP
; /* Can't be a popup */
3923 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
3925 if (IsWindowVisible(hWnd
))
3926 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3927 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3928 WIN_ReleaseWndPtr(wndPtr
);
3931 WIN_ReleaseWndPtr(wndPtr
);
3937 /**********************************************************************
3938 * GetSubMenu16 (USER.159)
3940 HMENU16 WINAPI
GetSubMenu16( HMENU16 hMenu
, INT16 nPos
)
3942 return GetSubMenu( hMenu
, nPos
);
3946 /**********************************************************************
3947 * GetSubMenu32 (USER32.288)
3949 HMENU WINAPI
GetSubMenu( HMENU hMenu
, INT nPos
)
3953 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return 0;
3954 if (!(lpmi
->fType
& MF_POPUP
)) return 0;
3955 return lpmi
->hSubMenu
;
3959 /**********************************************************************
3960 * DrawMenuBar16 (USER.160)
3962 void WINAPI
DrawMenuBar16( HWND16 hWnd
)
3964 DrawMenuBar( hWnd
);
3968 /**********************************************************************
3969 * DrawMenuBar (USER32.161)
3971 BOOL WINAPI
DrawMenuBar( HWND hWnd
)
3974 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
3975 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
) && wndPtr
->wIDmenu
)
3977 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR((HMENU16
)wndPtr
->wIDmenu
);
3980 WIN_ReleaseWndPtr(wndPtr
);
3984 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
3985 lppop
->hwndOwner
= hWnd
;
3986 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3987 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3988 WIN_ReleaseWndPtr(wndPtr
);
3991 WIN_ReleaseWndPtr(wndPtr
);
3996 /***********************************************************************
3997 * EndMenu (USER.187) (USER32.175)
3999 void WINAPI
EndMenu(void)
4002 * FIXME: NOT ENOUGH! This has to cancel menu tracking right away.
4009 /***********************************************************************
4010 * LookupMenuHandle (USER.217)
4012 HMENU16 WINAPI
LookupMenuHandle16( HMENU16 hmenu
, INT16 id
)
4014 HMENU hmenu32
= hmenu
;
4016 if (!MENU_FindItem( &hmenu32
, &id32
, MF_BYCOMMAND
)) return 0;
4017 else return hmenu32
;
4021 /**********************************************************************
4022 * LoadMenu16 (USER.150)
4024 HMENU16 WINAPI
LoadMenu16( HINSTANCE16 instance
, SEGPTR name
)
4032 char *str
= (char *)PTR_SEG_TO_LIN( name
);
4033 TRACE("(%04x,'%s')\n", instance
, str
);
4034 if (str
[0] == '#') name
= (SEGPTR
)atoi( str
+ 1 );
4037 TRACE("(%04x,%04x)\n",instance
,LOWORD(name
));
4039 if (!name
) return 0;
4041 /* check for Win32 module */
4042 if (HIWORD(instance
))
4043 return LoadMenuA(instance
,PTR_SEG_TO_LIN(name
));
4044 instance
= GetExePtr( instance
);
4046 if (!(hRsrc
= FindResource16( instance
, name
, RT_MENU16
))) return 0;
4047 if (!(handle
= LoadResource16( instance
, hRsrc
))) return 0;
4048 hMenu
= LoadMenuIndirect16(LockResource16(handle
));
4049 FreeResource16( handle
);
4054 /*****************************************************************
4055 * LoadMenu32A (USER32.370)
4057 HMENU WINAPI
LoadMenuA( HINSTANCE instance
, LPCSTR name
)
4059 HRSRC hrsrc
= FindResourceA( instance
, name
, RT_MENUA
);
4060 if (!hrsrc
) return 0;
4061 return LoadMenuIndirectA( (LPCVOID
)LoadResource( instance
, hrsrc
));
4065 /*****************************************************************
4066 * LoadMenu32W (USER32.373)
4068 HMENU WINAPI
LoadMenuW( HINSTANCE instance
, LPCWSTR name
)
4070 HRSRC hrsrc
= FindResourceW( instance
, name
, RT_MENUW
);
4071 if (!hrsrc
) return 0;
4072 return LoadMenuIndirectW( (LPCVOID
)LoadResource( instance
, hrsrc
));
4076 /**********************************************************************
4077 * LoadMenuIndirect16 (USER.220)
4079 HMENU16 WINAPI
LoadMenuIndirect16( LPCVOID
template )
4082 WORD version
, offset
;
4083 LPCSTR p
= (LPCSTR
)template;
4085 TRACE("(%p)\n", template );
4086 version
= GET_WORD(p
);
4090 WARN("version must be 0 for Win16\n" );
4093 offset
= GET_WORD(p
);
4094 p
+= sizeof(WORD
) + offset
;
4095 if (!(hMenu
= CreateMenu())) return 0;
4096 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
4098 DestroyMenu( hMenu
);
4105 /**********************************************************************
4106 * LoadMenuIndirect32A (USER32.371)
4108 HMENU WINAPI
LoadMenuIndirectA( LPCVOID
template )
4111 WORD version
, offset
;
4112 LPCSTR p
= (LPCSTR
)template;
4114 TRACE("%p\n", template );
4115 version
= GET_WORD(p
);
4120 offset
= GET_WORD(p
);
4121 p
+= sizeof(WORD
) + offset
;
4122 if (!(hMenu
= CreateMenu())) return 0;
4123 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
4125 DestroyMenu( hMenu
);
4130 offset
= GET_WORD(p
);
4131 p
+= sizeof(WORD
) + offset
;
4132 if (!(hMenu
= CreateMenu())) return 0;
4133 if (!MENUEX_ParseResource( p
, hMenu
))
4135 DestroyMenu( hMenu
);
4140 ERR("version %d not supported.\n", version
);
4146 /**********************************************************************
4147 * LoadMenuIndirect32W (USER32.372)
4149 HMENU WINAPI
LoadMenuIndirectW( LPCVOID
template )
4151 /* FIXME: is there anything different between A and W? */
4152 return LoadMenuIndirectA( template );
4156 /**********************************************************************
4157 * IsMenu16 (USER.358)
4159 BOOL16 WINAPI
IsMenu16( HMENU16 hmenu
)
4161 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
4162 return IS_A_MENU(menu
);
4166 /**********************************************************************
4167 * IsMenu32 (USER32.346)
4169 BOOL WINAPI
IsMenu(HMENU hmenu
)
4171 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
4172 return IS_A_MENU(menu
);
4175 /**********************************************************************
4176 * GetMenuItemInfo32_common
4179 static BOOL
GetMenuItemInfo_common ( HMENU hmenu
, UINT item
, BOOL bypos
,
4180 LPMENUITEMINFOA lpmii
, BOOL unicode
)
4182 MENUITEM
*menu
= MENU_FindItem (&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0);
4184 debug_print_menuitem("GetMenuItemInfo32_common: ", menu
, "");
4189 if (lpmii
->fMask
& MIIM_TYPE
) {
4190 lpmii
->fType
= menu
->fType
;
4191 switch (MENU_ITEM_TYPE(menu
->fType
)) {
4193 if (menu
->text
&& lpmii
->dwTypeData
&& lpmii
->cch
) {
4195 lstrcpynAtoW((LPWSTR
) lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4196 lpmii
->cch
= lstrlenW((LPWSTR
)menu
->text
);
4198 lstrcpynA(lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4199 lpmii
->cch
= lstrlenA(menu
->text
);
4205 lpmii
->dwTypeData
= menu
->text
;
4212 if (lpmii
->fMask
& MIIM_STRING
) {
4214 lstrcpynAtoW((LPWSTR
) lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4215 lpmii
->cch
= lstrlenW((LPWSTR
)menu
->text
);
4217 lstrcpynA(lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4218 lpmii
->cch
= lstrlenA(menu
->text
);
4222 if (lpmii
->fMask
& MIIM_FTYPE
)
4223 lpmii
->fType
= menu
->fType
;
4225 if (lpmii
->fMask
& MIIM_BITMAP
)
4226 lpmii
->hbmpItem
= menu
->hbmpItem
;
4228 if (lpmii
->fMask
& MIIM_STATE
)
4229 lpmii
->fState
= menu
->fState
;
4231 if (lpmii
->fMask
& MIIM_ID
)
4232 lpmii
->wID
= menu
->wID
;
4234 if (lpmii
->fMask
& MIIM_SUBMENU
)
4235 lpmii
->hSubMenu
= menu
->hSubMenu
;
4237 if (lpmii
->fMask
& MIIM_CHECKMARKS
) {
4238 lpmii
->hbmpChecked
= menu
->hCheckBit
;
4239 lpmii
->hbmpUnchecked
= menu
->hUnCheckBit
;
4241 if (lpmii
->fMask
& MIIM_DATA
)
4242 lpmii
->dwItemData
= menu
->dwItemData
;
4247 /**********************************************************************
4248 * GetMenuItemInfoA (USER32.264)
4250 BOOL WINAPI
GetMenuItemInfoA( HMENU hmenu
, UINT item
, BOOL bypos
,
4251 LPMENUITEMINFOA lpmii
)
4253 return GetMenuItemInfo_common (hmenu
, item
, bypos
, lpmii
, FALSE
);
4256 /**********************************************************************
4257 * GetMenuItemInfoW (USER32.265)
4259 BOOL WINAPI
GetMenuItemInfoW( HMENU hmenu
, UINT item
, BOOL bypos
,
4260 LPMENUITEMINFOW lpmii
)
4262 return GetMenuItemInfo_common (hmenu
, item
, bypos
,
4263 (LPMENUITEMINFOA
)lpmii
, TRUE
);
4266 /**********************************************************************
4267 * SetMenuItemInfo32_common
4270 static BOOL
SetMenuItemInfo_common(MENUITEM
* menu
,
4271 const MENUITEMINFOA
*lpmii
,
4274 if (!menu
) return FALSE
;
4276 if (lpmii
->fMask
& MIIM_TYPE
) {
4277 /* Get rid of old string. */
4278 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4279 HeapFree(SystemHeap
, 0, menu
->text
);
4283 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4284 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4285 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4287 menu
->text
= lpmii
->dwTypeData
;
4289 if (IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4291 menu
->text
= HEAP_strdupWtoA(SystemHeap
, 0, (LPWSTR
) lpmii
->dwTypeData
);
4293 menu
->text
= HEAP_strdupA(SystemHeap
, 0, lpmii
->dwTypeData
);
4297 if (lpmii
->fMask
& MIIM_FTYPE
) {
4298 /* free the string when the type is changing */
4299 if ( (!IS_STRING_ITEM(lpmii
->fType
)) && IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4300 HeapFree(SystemHeap
, 0, menu
->text
);
4303 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4304 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4307 if (lpmii
->fMask
& MIIM_STRING
) {
4308 /* free the string when used */
4309 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4310 HeapFree(SystemHeap
, 0, menu
->text
);
4312 menu
->text
= HEAP_strdupWtoA(SystemHeap
, 0, (LPWSTR
) lpmii
->dwTypeData
);
4314 menu
->text
= HEAP_strdupA(SystemHeap
, 0, lpmii
->dwTypeData
);
4318 if (lpmii
->fMask
& MIIM_STATE
)
4320 /* fixme: MFS_DEFAULT do we have to reset the other menu items? */
4321 menu
->fState
= lpmii
->fState
;
4324 if (lpmii
->fMask
& MIIM_ID
)
4325 menu
->wID
= lpmii
->wID
;
4327 if (lpmii
->fMask
& MIIM_SUBMENU
) {
4328 menu
->hSubMenu
= lpmii
->hSubMenu
;
4329 if (menu
->hSubMenu
) {
4330 POPUPMENU
*subMenu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR((UINT16
)menu
->hSubMenu
);
4331 if (IS_A_MENU(subMenu
)) {
4332 subMenu
->wFlags
|= MF_POPUP
;
4333 menu
->fType
|= MF_POPUP
;
4336 /* FIXME: Return an error ? */
4337 menu
->fType
&= ~MF_POPUP
;
4340 menu
->fType
&= ~MF_POPUP
;
4343 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
4345 menu
->hCheckBit
= lpmii
->hbmpChecked
;
4346 menu
->hUnCheckBit
= lpmii
->hbmpUnchecked
;
4348 if (lpmii
->fMask
& MIIM_DATA
)
4349 menu
->dwItemData
= lpmii
->dwItemData
;
4351 debug_print_menuitem("SetMenuItemInfo32_common: ", menu
, "");
4355 /**********************************************************************
4356 * SetMenuItemInfo32A (USER32.491)
4358 BOOL WINAPI
SetMenuItemInfoA(HMENU hmenu
, UINT item
, BOOL bypos
,
4359 const MENUITEMINFOA
*lpmii
)
4361 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4365 /**********************************************************************
4366 * SetMenuItemInfo32W (USER32.492)
4368 BOOL WINAPI
SetMenuItemInfoW(HMENU hmenu
, UINT item
, BOOL bypos
,
4369 const MENUITEMINFOW
*lpmii
)
4371 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4372 (const MENUITEMINFOA
*)lpmii
, TRUE
);
4375 /**********************************************************************
4376 * SetMenuDefaultItem (USER32.489)
4379 BOOL WINAPI
SetMenuDefaultItem(HMENU hmenu
, UINT uItem
, UINT bypos
)
4385 TRACE("(0x%x,%d,%d)\n", hmenu
, uItem
, bypos
);
4387 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hmenu
))) return FALSE
;
4389 /* reset all default-item flags */
4391 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4393 item
->fState
&= ~MFS_DEFAULT
;
4396 /* no default item */
4405 if ( uItem
>= menu
->nItems
) return FALSE
;
4406 item
[uItem
].fState
|= MFS_DEFAULT
;
4411 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4413 if (item
->wID
== uItem
)
4415 item
->fState
|= MFS_DEFAULT
;
4424 /**********************************************************************
4425 * GetMenuDefaultItem (USER32.260)
4427 UINT WINAPI
GetMenuDefaultItem(HMENU hmenu
, UINT bypos
, UINT flags
)
4433 TRACE("(0x%x,%d,%d)\n", hmenu
, bypos
, flags
);
4435 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hmenu
))) return -1;
4437 /* find default item */
4441 if (! item
) return -1;
4443 while ( !( item
->fState
& MFS_DEFAULT
) )
4446 if (i
>= menu
->nItems
) return -1;
4449 /* default: don't return disabled items */
4450 if ( (!(GMDI_USEDISABLED
& flags
)) && (item
->fState
& MFS_DISABLED
)) return -1;
4452 /* search rekursiv when needed */
4453 if ( (item
->fType
& MF_POPUP
) && (flags
& GMDI_GOINTOPOPUPS
) )
4456 ret
= GetMenuDefaultItem( item
->hSubMenu
, bypos
, flags
);
4457 if ( -1 != ret
) return ret
;
4459 /* when item not found in submenu, return the popup item */
4461 return ( bypos
) ? i
: item
->wID
;
4465 /*******************************************************************
4466 * InsertMenuItem16 (USER.441)
4470 BOOL16 WINAPI
InsertMenuItem16( HMENU16 hmenu
, UINT16 pos
, BOOL16 byposition
,
4471 const MENUITEMINFO16
*mii
)
4475 miia
.cbSize
= sizeof(miia
);
4476 miia
.fMask
= mii
->fMask
;
4477 miia
.dwTypeData
= mii
->dwTypeData
;
4478 miia
.fType
= mii
->fType
;
4479 miia
.fState
= mii
->fState
;
4480 miia
.wID
= mii
->wID
;
4481 miia
.hSubMenu
= mii
->hSubMenu
;
4482 miia
.hbmpChecked
= mii
->hbmpChecked
;
4483 miia
.hbmpUnchecked
= mii
->hbmpUnchecked
;
4484 miia
.dwItemData
= mii
->dwItemData
;
4485 miia
.cch
= mii
->cch
;
4486 if (IS_STRING_ITEM(miia
.fType
))
4487 miia
.dwTypeData
= PTR_SEG_TO_LIN(miia
.dwTypeData
);
4488 return InsertMenuItemA( hmenu
, pos
, byposition
, &miia
);
4492 /**********************************************************************
4493 * InsertMenuItem32A (USER32.323)
4495 BOOL WINAPI
InsertMenuItemA(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4496 const MENUITEMINFOA
*lpmii
)
4498 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4499 return SetMenuItemInfo_common(item
, lpmii
, FALSE
);
4503 /**********************************************************************
4504 * InsertMenuItem32W (USER32.324)
4506 BOOL WINAPI
InsertMenuItemW(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4507 const MENUITEMINFOW
*lpmii
)
4509 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4510 return SetMenuItemInfo_common(item
, (const MENUITEMINFOA
*)lpmii
, TRUE
);
4513 /**********************************************************************
4514 * CheckMenuRadioItem32 (USER32.47)
4517 BOOL WINAPI
CheckMenuRadioItem(HMENU hMenu
,
4518 UINT first
, UINT last
, UINT check
,
4521 MENUITEM
*mifirst
, *milast
, *micheck
;
4522 HMENU mfirst
= hMenu
, mlast
= hMenu
, mcheck
= hMenu
;
4524 TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4525 hMenu
, first
, last
, check
, bypos
);
4527 mifirst
= MENU_FindItem (&mfirst
, &first
, bypos
);
4528 milast
= MENU_FindItem (&mlast
, &last
, bypos
);
4529 micheck
= MENU_FindItem (&mcheck
, &check
, bypos
);
4531 if (mifirst
== NULL
|| milast
== NULL
|| micheck
== NULL
||
4532 mifirst
> milast
|| mfirst
!= mlast
|| mfirst
!= mcheck
||
4533 micheck
> milast
|| micheck
< mifirst
)
4536 while (mifirst
<= milast
)
4538 if (mifirst
== micheck
)
4540 mifirst
->fType
|= MFT_RADIOCHECK
;
4541 mifirst
->fState
|= MFS_CHECKED
;
4543 mifirst
->fType
&= ~MFT_RADIOCHECK
;
4544 mifirst
->fState
&= ~MFS_CHECKED
;
4552 /**********************************************************************
4553 * CheckMenuRadioItem16 (not a Windows API)
4556 BOOL16 WINAPI
CheckMenuRadioItem16(HMENU16 hMenu
,
4557 UINT16 first
, UINT16 last
, UINT16 check
,
4560 return CheckMenuRadioItem (hMenu
, first
, last
, check
, bypos
);
4563 /**********************************************************************
4564 * GetMenuItemRect32 (USER32.266)
4566 * ATTENTION: Here, the returned values in rect are the screen
4567 * coordinates of the item just like if the menu was
4568 * always on the upper left side of the application.
4571 BOOL WINAPI
GetMenuItemRect (HWND hwnd
, HMENU hMenu
, UINT uItem
,
4574 POPUPMENU
*itemMenu
;
4578 TRACE("(0x%x,0x%x,%d,%p)\n", hwnd
, hMenu
, uItem
, rect
);
4580 item
= MENU_FindItem (&hMenu
, &uItem
, MF_BYPOSITION
);
4581 referenceHwnd
= hwnd
;
4585 itemMenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
4586 if (itemMenu
== NULL
)
4589 if(itemMenu
->hWnd
== 0)
4591 referenceHwnd
= itemMenu
->hWnd
;
4594 if ((rect
== NULL
) || (item
== NULL
))
4599 MapWindowPoints(referenceHwnd
, 0, (LPPOINT
)rect
, 2);
4604 /**********************************************************************
4605 * GetMenuItemRect16 (USER.665)
4608 BOOL16 WINAPI
GetMenuItemRect16 (HWND16 hwnd
, HMENU16 hMenu
, UINT16 uItem
,
4614 if (!rect
) return FALSE
;
4615 res
= GetMenuItemRect (hwnd
, hMenu
, uItem
, &r32
);
4616 CONV_RECT32TO16 (&r32
, rect
);
4620 /**********************************************************************
4624 * MIM_APPLYTOSUBMENUS
4625 * actually use the items to draw the menu
4627 BOOL WINAPI
SetMenuInfo (HMENU hMenu
, LPCMENUINFO lpmi
)
4631 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4633 if (lpmi
&& (lpmi
->cbSize
==sizeof(MENUINFO
)) && (menu
=(POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
)))
4636 if (lpmi
->fMask
& MIM_BACKGROUND
)
4637 menu
->hbrBack
= lpmi
->hbrBack
;
4639 if (lpmi
->fMask
& MIM_HELPID
)
4640 menu
->dwContextHelpID
= lpmi
->dwContextHelpID
;
4642 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4643 menu
->cyMax
= lpmi
->cyMax
;
4645 if (lpmi
->fMask
& MIM_MENUDATA
)
4646 menu
->dwMenuData
= lpmi
->dwMenuData
;
4648 if (lpmi
->fMask
& MIM_STYLE
)
4649 menu
->dwStyle
= lpmi
->dwStyle
;
4656 /**********************************************************************
4663 BOOL WINAPI
GetMenuInfo (HMENU hMenu
, LPMENUINFO lpmi
)
4666 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4668 if (lpmi
&& (menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
)))
4671 if (lpmi
->fMask
& MIM_BACKGROUND
)
4672 lpmi
->hbrBack
= menu
->hbrBack
;
4674 if (lpmi
->fMask
& MIM_HELPID
)
4675 lpmi
->dwContextHelpID
= menu
->dwContextHelpID
;
4677 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4678 lpmi
->cyMax
= menu
->cyMax
;
4680 if (lpmi
->fMask
& MIM_MENUDATA
)
4681 lpmi
->dwMenuData
= menu
->dwMenuData
;
4683 if (lpmi
->fMask
& MIM_STYLE
)
4684 lpmi
->dwStyle
= menu
->dwStyle
;
4691 /**********************************************************************
4692 * SetMenuContextHelpId16 (USER.384)
4694 BOOL16 WINAPI
SetMenuContextHelpId16( HMENU16 hMenu
, DWORD dwContextHelpID
)
4696 return SetMenuContextHelpId( hMenu
, dwContextHelpID
);
4700 /**********************************************************************
4701 * SetMenuContextHelpId (USER32.488)
4703 BOOL WINAPI
SetMenuContextHelpId( HMENU hMenu
, DWORD dwContextHelpID
)
4707 TRACE("(0x%04x 0x%08lx)\n", hMenu
, dwContextHelpID
);
4709 if ((menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
)))
4711 menu
->dwContextHelpID
= dwContextHelpID
;
4717 /**********************************************************************
4718 * GetMenuContextHelpId16 (USER.385)
4720 DWORD WINAPI
GetMenuContextHelpId16( HMENU16 hMenu
)
4722 return GetMenuContextHelpId( hMenu
);
4725 /**********************************************************************
4726 * GetMenuContextHelpId (USER32.488)
4728 DWORD WINAPI
GetMenuContextHelpId( HMENU hMenu
)
4732 TRACE("(0x%04x)\n", hMenu
);
4734 if ((menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
)))
4736 return menu
->dwContextHelpID
;