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"
23 #include "sysmetrics.h"
27 #include "nonclient.h"
36 /* internal popup menu window messages */
38 #define MM_SETMENUHANDLE (WM_USER + 0)
39 #define MM_GETMENUHANDLE (WM_USER + 1)
41 /* Menu item structure */
43 /* ----------- MENUITEMINFO Stuff ----------- */
44 UINT fType
; /* Item type. */
45 UINT fState
; /* Item state. */
46 UINT wID
; /* Item id. */
47 HMENU hSubMenu
; /* Pop-up menu. */
48 HBITMAP hCheckBit
; /* Bitmap when checked. */
49 HBITMAP hUnCheckBit
; /* Bitmap when unchecked. */
50 LPSTR text
; /* Item text or bitmap handle. */
51 DWORD dwItemData
; /* Application defined. */
52 /* ----------- Wine stuff ----------- */
53 RECT rect
; /* Item area (relative to menu window) */
54 UINT xTab
; /* X position of text after Tab */
57 /* Popup menu structure */
59 WORD wFlags
; /* Menu flags (MF_POPUP, MF_SYSMENU) */
60 WORD wMagic
; /* Magic number */
61 HQUEUE16 hTaskQ
; /* Task queue for this menu */
62 WORD Width
; /* Width of the whole menu */
63 WORD Height
; /* Height of the whole menu */
64 WORD nItems
; /* Number of items in the menu */
65 HWND hWnd
; /* Window containing the menu */
66 MENUITEM
*items
; /* Array of menu items */
67 UINT FocusedItem
; /* Currently focused item */
68 WORD defitem
; /* default item position. Unused (except for set/get)*/
69 } POPUPMENU
, *LPPOPUPMENU
;
71 /* internal flags for menu tracking */
73 #define TF_ENDMENU 0x0001
74 #define TF_SUSPENDPOPUP 0x0002
75 #define TF_SKIPREMOVE 0x0004
80 HMENU hCurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
81 HMENU hTopMenu
; /* initial menu */
82 HWND hOwnerWnd
; /* where notifications are sent */
86 #define MENU_MAGIC 0x554d /* 'MU' */
87 #define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
92 /* Internal MENU_TrackMenu() flags */
93 #define TPM_INTERNAL 0xF0000000
94 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
95 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
96 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
98 /* popup menu shade thickness */
99 #define POPUP_XSHADE 4
100 #define POPUP_YSHADE 4
102 /* Space between 2 menu bar items */
103 #define MENU_BAR_ITEMS_SPACE 12
105 /* Minimum width of a tab character */
106 #define MENU_TAB_SPACE 8
108 /* Height of a separator item */
109 #define SEPARATOR_HEIGHT 5
111 /* (other menu->FocusedItem values give the position of the focused item) */
112 #define NO_SELECTED_ITEM 0xffff
114 #define MENU_ITEM_TYPE(flags) \
115 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
117 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
119 #define IS_SYSTEM_MENU(menu) \
120 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
121 #define IS_SYSTEM_POPUP(menu) \
122 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
124 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
125 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
126 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
127 MF_POPUP | MF_SYSMENU | MF_HELP)
128 #define STATE_MASK (~TYPE_MASK)
130 /* Dimension of the menu bitmaps */
131 static WORD check_bitmap_width
= 0, check_bitmap_height
= 0;
132 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
134 static HBITMAP hStdRadioCheck
= 0;
135 static HBITMAP hStdCheck
= 0;
136 static HBITMAP hStdMnArrow
= 0;
138 // Minimze/restore/close buttons to be inserted in menubar
139 static HBITMAP hBmpMinimize
= 0;
140 static HBITMAP hBmpMinimizeD
= 0;
141 static HBITMAP hBmpMaximize
= 0;
142 static HBITMAP hBmpMaximizeD
= 0;
143 static HBITMAP hBmpClose
= 0;
144 static HBITMAP hBmpCloseD
= 0;
147 static HBRUSH hShadeBrush
= 0;
148 static HMENU MENU_DefSysPopup
= 0; /* Default system menu popup */
150 /* Use global popup window because there's no way 2 menus can
151 * be tracked at the same time. */
153 static WND
* pTopPopupWnd
= 0;
154 static UINT uSubPWndLevel
= 0;
156 /* Flag set by EndMenu() to force an exit from menu tracking */
157 static BOOL fEndMenu
= FALSE
;
160 /***********************************************************************
161 * debug_print_menuitem
163 * Print a menuitem in readable form.
166 #define debug_print_menuitem(pre, mp, post) \
167 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
169 #define MENUOUT(text) \
170 dsprintf(menu, "%s%s", (count++ ? "," : ""), (text))
172 #define MENUFLAG(bit,text) \
174 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
177 static void do_debug_print_menuitem(const char *prefix
, MENUITEM
* mp
,
180 dbg_decl_str(menu
, 256);
183 UINT flags
= mp
->fType
;
184 int typ
= MENU_ITEM_TYPE(flags
);
185 dsprintf(menu
, "{ ID=0x%x", mp
->wID
);
186 if (flags
& MF_POPUP
)
187 dsprintf(menu
, ", Sub=0x%x", mp
->hSubMenu
);
190 dsprintf(menu
, ", Typ=");
191 if (typ
== MFT_STRING
)
193 else if (typ
== MFT_SEPARATOR
)
195 else if (typ
== MFT_OWNERDRAW
)
197 else if (typ
== MFT_BITMAP
)
203 MENUFLAG(MF_POPUP
, "pop");
204 MENUFLAG(MFT_MENUBARBREAK
, "barbrk");
205 MENUFLAG(MFT_MENUBREAK
, "brk");
206 MENUFLAG(MFT_RADIOCHECK
, "radio");
207 MENUFLAG(MFT_RIGHTORDER
, "rorder");
208 MENUFLAG(MF_SYSMENU
, "sys");
209 MENUFLAG(MFT_RIGHTJUSTIFY
, "right");
212 dsprintf(menu
, "+0x%x", flags
);
217 dsprintf(menu
, ", State=");
218 MENUFLAG(MFS_GRAYED
, "grey");
219 MENUFLAG(MFS_DISABLED
, "dis");
220 MENUFLAG(MFS_CHECKED
, "check");
221 MENUFLAG(MFS_HILITE
, "hi");
222 MENUFLAG(MF_USECHECKBITMAPS
, "usebit");
223 MENUFLAG(MF_MOUSESELECT
, "mouse");
225 dsprintf(menu
, "+0x%x", flags
);
228 dsprintf(menu
, ", Chk=0x%x", mp
->hCheckBit
);
230 dsprintf(menu
, ", Unc=0x%x", mp
->hUnCheckBit
);
232 if (typ
== MFT_STRING
) {
234 dsprintf(menu
, ", Text=\"%s\"", mp
->text
);
236 dsprintf(menu
, ", Text=Null");
237 } else if (mp
->text
== NULL
)
240 dsprintf(menu
, ", Text=%p", mp
->text
);
241 dsprintf(menu
, " }");
243 dsprintf(menu
, "NULL");
246 TRACE(menu
, "%s %s %s\n", prefix
, dbg_str(menu
), postfix
);
252 /***********************************************************************
255 * Return the default system menu.
257 static HMENU
MENU_CopySysPopup(void)
259 HMENU hMenu
= LoadMenuIndirectA(SYSRES_GetResPtr(SYSRES_MENU_SYSMENU
));
262 POPUPMENU
* menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
263 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
267 ERR(menu
, "Unable to load default system menu\n" );
270 TRACE(menu
, "returning %x.\n", hMenu
);
275 /***********************************************************************
276 * MENU_GetTopPopupWnd()
278 * Return the locked pointer pTopPopupWnd.
280 WND
*MENU_GetTopPopupWnd()
282 return WIN_LockWndPtr(pTopPopupWnd
);
284 /***********************************************************************
285 * MENU_ReleaseTopPopupWnd()
287 * Realease the locked pointer pTopPopupWnd.
289 void MENU_ReleaseTopPopupWnd()
291 WIN_ReleaseWndPtr(pTopPopupWnd
);
293 /***********************************************************************
294 * MENU_DestroyTopPopupWnd()
296 * Destroy the locked pointer pTopPopupWnd.
298 void MENU_DestroyTopPopupWnd()
300 WND
*tmpWnd
= pTopPopupWnd
;
302 WIN_ReleaseWndPtr(tmpWnd
);
307 /**********************************************************************
310 * Create a copy of the system menu. System menu in Windows is
311 * a special menu-bar with the single entry - system menu popup.
312 * This popup is presented to the outside world as a "system menu".
313 * However, the real system menu handle is sometimes seen in the
314 * WM_MENUSELECT paramemters (and Word 6 likes it this way).
316 HMENU
MENU_GetSysMenu( HWND hWnd
, HMENU hPopupMenu
)
320 if ((hMenu
= CreateMenu()))
322 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
323 menu
->wFlags
= MF_SYSMENU
;
326 if (hPopupMenu
== (HMENU
)(-1))
327 hPopupMenu
= MENU_CopySysPopup();
328 else if( !hPopupMenu
) hPopupMenu
= MENU_DefSysPopup
;
332 InsertMenuA( hMenu
, -1, MF_SYSMENU
| MF_POPUP
| MF_BYPOSITION
, hPopupMenu
, NULL
);
334 menu
->items
[0].fType
= MF_SYSMENU
| MF_POPUP
;
335 menu
->items
[0].fState
= 0;
336 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hPopupMenu
);
337 menu
->wFlags
|= MF_SYSMENU
;
339 TRACE(menu
,"GetSysMenu hMenu=%04x (%04x)\n", hMenu
, hPopupMenu
);
342 DestroyMenu( hMenu
);
344 ERR(menu
, "failed to load system menu!\n");
349 /***********************************************************************
352 * Menus initialisation.
357 static unsigned char shade_bits
[16] = { 0x55, 0, 0xAA, 0,
362 /* Load menu bitmaps */
363 hStdCheck
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CHECK
));
364 hStdRadioCheck
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_RADIOCHECK
));
365 hStdMnArrow
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW
));
366 /* Load system buttons bitmaps */
367 hBmpMinimize
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCE
));
368 hBmpMinimizeD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCED
));
369 hBmpMaximize
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORE
));
370 hBmpMaximizeD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORED
));
371 hBmpClose
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSE
));
372 hBmpCloseD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSED
));
377 GetObjectA( hStdCheck
, sizeof(bm
), &bm
);
378 check_bitmap_width
= bm
.bmWidth
;
379 check_bitmap_height
= bm
.bmHeight
;
383 /* Assume that radio checks have the same size as regular check. */
390 GetObjectA( hStdMnArrow
, sizeof(bm
), &bm
);
391 arrow_bitmap_width
= bm
.bmWidth
;
392 arrow_bitmap_height
= bm
.bmHeight
;
396 if ((hBitmap
= CreateBitmap( 8, 8, 1, 1, shade_bits
)))
398 if((hShadeBrush
= CreatePatternBrush( hBitmap
)))
400 DeleteObject( hBitmap
);
401 if ((MENU_DefSysPopup
= MENU_CopySysPopup()))
409 /***********************************************************************
410 * MENU_InitSysMenuPopup
412 * Grey the appropriate items in System menu.
414 static void MENU_InitSysMenuPopup( HMENU hmenu
, DWORD style
, DWORD clsStyle
)
418 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
419 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
420 gray
= ((style
& WS_MAXIMIZE
) != 0);
421 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
422 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
423 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
424 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
425 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
426 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
427 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
428 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
429 EnableMenuItem( hmenu
, SC_CLOSE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
433 /******************************************************************************
435 * UINT32 MENU_GetStartOfNextColumn(
438 *****************************************************************************/
440 static UINT
MENU_GetStartOfNextColumn(
443 POPUPMENU
*menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
444 UINT i
= menu
->FocusedItem
+ 1;
447 return NO_SELECTED_ITEM
;
449 if( i
== NO_SELECTED_ITEM
)
452 for( ; i
< menu
->nItems
; ++i
) {
453 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
457 return NO_SELECTED_ITEM
;
461 /******************************************************************************
463 * UINT32 MENU_GetStartOfPrevColumn(
466 *****************************************************************************/
468 static UINT
MENU_GetStartOfPrevColumn(
471 POPUPMENU
const *menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
475 return NO_SELECTED_ITEM
;
477 if( menu
->FocusedItem
== 0 || menu
->FocusedItem
== NO_SELECTED_ITEM
)
478 return NO_SELECTED_ITEM
;
480 /* Find the start of the column */
482 for(i
= menu
->FocusedItem
; i
!= 0 &&
483 !(menu
->items
[i
].fType
& MF_MENUBARBREAK
);
487 return NO_SELECTED_ITEM
;
489 for(--i
; i
!= 0; --i
) {
490 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
494 TRACE(menu
, "ret %d.\n", i
);
501 /***********************************************************************
504 * Find a menu item. Return a pointer on the item, and modifies *hmenu
505 * in case the item was in a sub-menu.
507 static MENUITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
512 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(*hmenu
))) return NULL
;
513 if (wFlags
& MF_BYPOSITION
)
515 if (*nPos
>= menu
->nItems
) return NULL
;
516 return &menu
->items
[*nPos
];
520 MENUITEM
*item
= menu
->items
;
521 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
523 if (item
->wID
== *nPos
)
528 else if (item
->fType
& MF_POPUP
)
530 HMENU hsubmenu
= item
->hSubMenu
;
531 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
543 /***********************************************************************
546 static void MENU_FreeItemData( MENUITEM
* item
)
549 if (IS_STRING_ITEM(item
->fType
) && item
->text
)
550 HeapFree( SystemHeap
, 0, item
->text
);
553 /***********************************************************************
554 * MENU_FindItemByCoords
556 * Find the item at the specified coordinates (screen coords). Does
557 * not work for child windows and therefore should not be called for
558 * an arbitrary system menu.
560 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
,
561 POINT pt
, UINT
*pos
)
567 if (!GetWindowRect(menu
->hWnd
,&wrect
)) return NULL
;
568 pt
.x
-= wrect
.left
;pt
.y
-= wrect
.top
;
570 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
572 if ((pt
.x
>= item
->rect
.left
) && (pt
.x
< item
->rect
.right
) &&
573 (pt
.y
>= item
->rect
.top
) && (pt
.y
< item
->rect
.bottom
))
583 /***********************************************************************
586 * Find the menu item selected by a key press.
587 * Return item id, -1 if none, -2 if we should close the menu.
589 static UINT
MENU_FindItemByKey( HWND hwndOwner
, HMENU hmenu
,
590 UINT key
, BOOL forceMenuChar
)
592 TRACE(menu
,"\tlooking for '%c' in [%04x]\n", (char)key
, (UINT16
)hmenu
);
594 if (!IsMenu( hmenu
))
596 WND
* w
= WIN_FindWndPtr(hwndOwner
);
597 hmenu
= GetSubMenu(w
->hSysMenu
, 0);
598 WIN_ReleaseWndPtr(w
);
603 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
604 MENUITEM
*item
= menu
->items
;
612 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
614 if (item
->text
&& (IS_STRING_ITEM(item
->fType
)))
616 char *p
= item
->text
- 2;
619 p
= strchr (p
+ 2, '&');
621 while (p
!= NULL
&& p
[1] == '&');
622 if (p
&& (toupper(p
[1]) == key
)) return i
;
626 menuchar
= SendMessageA( hwndOwner
, WM_MENUCHAR
,
627 MAKEWPARAM( key
, menu
->wFlags
), hmenu
);
628 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
629 if (HIWORD(menuchar
) == 1) return (UINT
)(-2);
633 /***********************************************************************
636 * Load the bitmap associated with the magic menu item and its style
639 static HBITMAP
MENU_LoadMagicItem(UINT id
,BOOL hilite
)
641 // Magic menu item id's section
642 // These magic id's are used by windows to insert "standard" mdi
643 // buttons (minimize,restore,close) on menu. Under windows,
644 // these magic id's make sure the right things appear when those
645 // bitmap buttons are pressed/selected/released.
649 case MAGIC_REDUCE
: return (hilite
? hBmpMinimizeD
: hBmpMinimize
);
650 case MAGIC_RESTORE
: return (hilite
? hBmpMaximizeD
: hBmpMaximize
);
651 case MAGIC_CLOSE
: return (hilite
? hBmpCloseD
: hBmpClose
);
657 /***********************************************************************
660 * Calculate the size of the menu item and store it in lpitem->rect.
662 static void MENU_CalcItemSize( HDC hdc
, MENUITEM
*lpitem
, HWND hwndOwner
,
663 INT orgX
, INT orgY
, BOOL menuBar
)
668 TRACE(menu
, "HDC 0x%x at (%d,%d)\n",
670 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem
,
671 (menuBar
? " (MenuBar)" : ""));
673 SetRect( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
675 if (lpitem
->fType
& MF_OWNERDRAW
)
677 MEASUREITEMSTRUCT mis
;
678 mis
.CtlType
= ODT_MENU
;
679 mis
.itemID
= lpitem
->wID
;
680 mis
.itemData
= (DWORD
)lpitem
->text
;
683 SendMessageA( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
684 lpitem
->rect
.bottom
+= mis
.itemHeight
;
685 lpitem
->rect
.right
+= mis
.itemWidth
;
686 TRACE(menu
, "%08x %dx%d\n",
687 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
691 if (lpitem
->fType
& MF_SEPARATOR
)
693 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
699 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
700 if (lpitem
->fType
& MF_POPUP
)
701 lpitem
->rect
.right
+= arrow_bitmap_width
;
704 if (lpitem
->fType
& MF_BITMAP
)
709 // Check if there is a magic menu item associated with this item
710 if((LOWORD((int)lpitem
->text
))<6)
712 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
,
713 (lpitem
->fType
& MF_HILITE
));
716 resBmp
= (HBITMAP
)lpitem
->text
;
718 if (GetObjectA(resBmp
, sizeof(bm
), &bm
))
720 lpitem
->rect
.right
+= bm
.bmWidth
;
721 lpitem
->rect
.bottom
+= bm
.bmHeight
;
729 /* If we get here, then it must be a text item */
731 if (IS_STRING_ITEM( lpitem
->fType
))
733 dwSize
= GetTextExtent16( hdc
, lpitem
->text
, strlen(lpitem
->text
) );
734 lpitem
->rect
.right
+= LOWORD(dwSize
);
735 if (TWEAK_WineLook
== WIN31_LOOK
)
736 lpitem
->rect
.bottom
+= MAX( HIWORD(dwSize
), SYSMETRICS_CYMENU
);
738 lpitem
->rect
.bottom
+= MAX (HIWORD(dwSize
), sysMetrics
[SM_CYMENU
]- 1);
741 if (menuBar
) lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
742 else if ((p
= strchr( lpitem
->text
, '\t' )) != NULL
)
744 /* Item contains a tab (only meaningful in popup menus) */
745 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+
746 LOWORD( GetTextExtent16( hdc
, lpitem
->text
,
747 (int)(p
- lpitem
->text
) ));
748 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
752 if (strchr( lpitem
->text
, '\b' ))
753 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
754 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
755 - arrow_bitmap_width
;
761 /***********************************************************************
762 * MENU_PopupMenuCalcSize
764 * Calculate the size of a popup menu.
766 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND hwndOwner
)
771 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
773 lppop
->Width
= lppop
->Height
= 0;
774 if (lppop
->nItems
== 0) return;
777 maxX
= SYSMETRICS_CXBORDER
;
778 while (start
< lppop
->nItems
)
780 lpitem
= &lppop
->items
[start
];
782 orgY
= SYSMETRICS_CYBORDER
;
784 maxTab
= maxTabWidth
= 0;
786 /* Parse items until column break or end of menu */
787 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
790 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
792 if (TWEAK_WineLook
> WIN31_LOOK
)
795 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
797 if (lpitem
->fType
& MF_MENUBARBREAK
) orgX
++;
798 maxX
= MAX( maxX
, lpitem
->rect
.right
);
799 orgY
= lpitem
->rect
.bottom
;
800 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
802 maxTab
= MAX( maxTab
, lpitem
->xTab
);
803 maxTabWidth
= MAX(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
807 /* Finish the column (set all items to the largest width found) */
808 maxX
= MAX( maxX
, maxTab
+ maxTabWidth
);
809 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
811 lpitem
->rect
.right
= maxX
;
812 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
813 lpitem
->xTab
= maxTab
;
815 lppop
->Height
= MAX( lppop
->Height
, orgY
);
818 if(TWEAK_WineLook
> WIN31_LOOK
)
826 /***********************************************************************
827 * MENU_MenuBarCalcSize
829 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
830 * height is off by 1 pixel which causes lengthy window relocations when
831 * active document window is maximized/restored.
833 * Calculate the size of the menu bar.
835 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
,
836 LPPOPUPMENU lppop
, HWND hwndOwner
)
839 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
841 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
842 if (lppop
->nItems
== 0) return;
843 TRACE(menu
,"left=%d top=%d right=%d bottom=%d\n",
844 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
845 lppop
->Width
= lprect
->right
- lprect
->left
;
850 while (start
< lppop
->nItems
)
852 lpitem
= &lppop
->items
[start
];
856 /* Parse items until line break or end of menu */
857 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
859 if ((helpPos
== -1) && (lpitem
->fType
& MF_HELP
)) helpPos
= i
;
861 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
863 TRACE(menu
, "calling MENU_CalcItemSize org=(%d, %d)\n",
865 debug_print_menuitem (" item: ", lpitem
, "");
866 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
868 if (lpitem
->rect
.right
> lprect
->right
)
870 if (i
!= start
) break;
871 else lpitem
->rect
.right
= lprect
->right
;
873 maxY
= MAX( maxY
, lpitem
->rect
.bottom
);
874 orgX
= lpitem
->rect
.right
;
877 /* Finish the line (set all items to the largest height found) */
878 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
881 lprect
->bottom
= maxY
;
882 lppop
->Height
= lprect
->bottom
- lprect
->top
;
884 /* Flush right all items between the MF_HELP and the last item */
885 /* (if several lines, only move the last line) */
888 lpitem
= &lppop
->items
[lppop
->nItems
-1];
889 orgY
= lpitem
->rect
.top
;
890 orgX
= lprect
->right
;
891 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--)
893 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
894 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
895 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
896 lpitem
->rect
.right
= orgX
;
897 orgX
= lpitem
->rect
.left
;
902 /***********************************************************************
905 * Draw a single menu item.
907 static void MENU_DrawMenuItem( HWND hwnd
, HDC hdc
, MENUITEM
*lpitem
,
908 UINT height
, BOOL menuBar
, UINT odaction
)
912 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem
, "");
914 if (lpitem
->fType
& MF_SYSMENU
)
916 if( !IsIconic(hwnd
) ) {
917 if (TWEAK_WineLook
> WIN31_LOOK
)
918 NC_DrawSysButton95( hwnd
, hdc
,
920 (MF_HILITE
| MF_MOUSESELECT
) );
922 NC_DrawSysButton( hwnd
, hdc
,
924 (MF_HILITE
| MF_MOUSESELECT
) );
930 if (lpitem
->fType
& MF_OWNERDRAW
)
934 dis
.CtlType
= ODT_MENU
;
935 dis
.itemID
= lpitem
->wID
;
936 dis
.itemData
= (DWORD
)lpitem
->text
;
938 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
939 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
;
940 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
941 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
944 dis
.rcItem
= lpitem
->rect
;
945 TRACE(menu
, "Ownerdraw: itemID=%d, itemState=%d, itemAction=%d, "
946 "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n",dis
.itemID
,
947 dis
.itemState
, dis
.itemAction
, dis
.hwndItem
, dis
.hDC
,
948 dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
950 SendMessageA( GetWindow(hwnd
,GW_OWNER
), WM_DRAWITEM
, 0, (LPARAM
)&dis
);
954 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
957 /* Draw the background */
958 if (TWEAK_WineLook
> WIN31_LOOK
) {
968 InflateRect32( &rect, -1, -1 );
972 if ((lpitem
->fState
& MF_HILITE
) && !(lpitem
->fType
& MF_BITMAP
) )
973 FillRect( hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
) );
975 FillRect( hdc
, &rect
, GetSysColorBrush(COLOR_MENU
) );
977 SetBkMode( hdc
, TRANSPARENT
);
979 /* Draw the separator bar (if any) */
981 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
983 /* vertical separator */
984 if (TWEAK_WineLook
> WIN31_LOOK
) {
987 rc
.bottom
= height
- 3;
988 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
991 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
992 MoveTo16( hdc
, rect
.left
, 0 );
993 LineTo( hdc
, rect
.left
, height
);
996 if (lpitem
->fType
& MF_SEPARATOR
)
998 /* horizontal separator */
999 if (TWEAK_WineLook
> WIN31_LOOK
) {
1003 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1004 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1007 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1008 MoveTo16( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
1009 LineTo( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
1017 if ((lpitem
->fState
& MF_HILITE
) && !(lpitem
->fType
& MF_BITMAP
) )
1019 if (lpitem
->fState
& MF_GRAYED
)
1020 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1022 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
1023 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
1027 if (lpitem
->fState
& MF_GRAYED
)
1028 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1030 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1031 SetBkColor( hdc
, GetSysColor( COLOR_MENU
) );
1036 INT y
= rect
.top
+ rect
.bottom
;
1038 /* Draw the check mark
1041 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1044 if (lpitem
->fState
& MF_CHECKED
)
1047 lpitem
->hCheckBit
? lpitem
->hCheckBit
:
1048 ((lpitem
->fType
& MFT_RADIOCHECK
)
1049 ? hStdRadioCheck
: hStdCheck
);
1050 HDC hdcMem
= CreateCompatibleDC( hdc
);
1052 SelectObject( hdcMem
, bm
);
1053 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1054 check_bitmap_width
, check_bitmap_height
,
1055 hdcMem
, 0, 0, SRCCOPY
);
1057 } else if (lpitem
->hUnCheckBit
) {
1058 HDC hdcMem
= CreateCompatibleDC( hdc
);
1060 SelectObject( hdcMem
, lpitem
->hUnCheckBit
);
1061 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1062 check_bitmap_width
, check_bitmap_height
,
1063 hdcMem
, 0, 0, SRCCOPY
);
1067 /* Draw the popup-menu arrow */
1069 if (lpitem
->fType
& MF_POPUP
)
1071 HDC hdcMem
= CreateCompatibleDC( hdc
);
1073 SelectObject( hdcMem
, hStdMnArrow
);
1074 BitBlt( hdc
, rect
.right
- arrow_bitmap_width
- 1,
1075 (y
- arrow_bitmap_height
) / 2,
1076 arrow_bitmap_width
, arrow_bitmap_height
,
1077 hdcMem
, 0, 0, SRCCOPY
);
1081 rect
.left
+= check_bitmap_width
;
1082 rect
.right
-= arrow_bitmap_width
;
1085 /* Draw the item text or bitmap */
1087 if (lpitem
->fType
& MF_BITMAP
)
1091 HDC hdcMem
= CreateCompatibleDC( hdc
);
1093 // Check if there is a magic menu item associated with this item
1094 // and load the appropriate bitmap
1095 if((LOWORD((int)lpitem
->text
)) < 6)
1097 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
,
1098 (lpitem
->fState
& MF_HILITE
));
1101 resBmp
= (HBITMAP
)lpitem
->text
;
1103 SelectObject(hdcMem
,resBmp
);
1104 BitBlt( hdc
, rect
.left
, rect
.top
+3, rect
.right
- rect
.left
+3,
1105 rect
.bottom
- rect
.top
, hdcMem
, 0, 0, SRCCOPY
);
1111 /* No bitmap - process text if present */
1112 else if (IS_STRING_ITEM(lpitem
->fType
))
1118 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1119 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1120 i
= strlen( lpitem
->text
);
1124 for (i
= 0; lpitem
->text
[i
]; i
++)
1125 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
1129 if((TWEAK_WineLook
== WIN31_LOOK
) || !(lpitem
->fState
& MF_GRAYED
)) {
1130 DrawTextA( hdc
, lpitem
->text
, i
, &rect
,
1131 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
1134 if (!(lpitem
->fState
& MF_HILITE
))
1140 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1141 DrawTextA( hdc
, lpitem
->text
, i
, &rect
,
1142 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
1148 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1149 DrawTextA( hdc
, lpitem
->text
, i
, &rect
,
1150 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
1153 if (lpitem
->text
[i
]) /* There's a tab or flush-right char */
1155 if (lpitem
->text
[i
] == '\t')
1157 rect
.left
= lpitem
->xTab
;
1158 DrawTextA( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
,
1159 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
1161 else DrawTextA( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
,
1162 DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
);
1168 /***********************************************************************
1169 * MENU_DrawPopupMenu
1171 * Paint a popup menu.
1173 static void MENU_DrawPopupMenu( HWND hwnd
, HDC hdc
, HMENU hmenu
)
1175 HBRUSH hPrevBrush
= 0;
1178 GetClientRect( hwnd
, &rect
);
1180 /* if(!TWEAK_Win95Look) { */
1181 rect
.bottom
-= POPUP_YSHADE
* SYSMETRICS_CYBORDER
;
1182 rect
.right
-= POPUP_XSHADE
* SYSMETRICS_CXBORDER
;
1185 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) )))
1189 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1191 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1197 /* draw 3-d shade */
1198 if(TWEAK_WineLook
== WIN31_LOOK
) {
1199 SelectObject( hdc
, hShadeBrush
);
1200 SetBkMode( hdc
, TRANSPARENT
);
1201 ropPrev
= SetROP2( hdc
, R2_MASKPEN
);
1203 i
= rect
.right
; /* why SetBrushOrg() doesn't? */
1204 PatBlt( hdc
, i
& 0xfffffffe,
1205 rect
.top
+ POPUP_YSHADE
*SYSMETRICS_CYBORDER
,
1206 i
%2 + POPUP_XSHADE
*SYSMETRICS_CXBORDER
,
1207 rect
.bottom
- rect
.top
, 0x00a000c9 );
1209 PatBlt( hdc
, rect
.left
+ POPUP_XSHADE
*SYSMETRICS_CXBORDER
,
1210 i
& 0xfffffffe,rect
.right
- rect
.left
,
1211 i
%2 + POPUP_YSHADE
*SYSMETRICS_CYBORDER
, 0x00a000c9 );
1212 SelectObject( hdc
, hPrevPen
);
1213 SelectObject( hdc
, hPrevBrush
);
1214 SetROP2( hdc
, ropPrev
);
1217 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1219 /* draw menu items */
1221 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1222 if (menu
&& menu
->nItems
)
1227 for (u
= menu
->nItems
, item
= menu
->items
; u
> 0; u
--, item
++)
1228 MENU_DrawMenuItem( hwnd
, hdc
, item
, menu
->Height
, FALSE
,
1232 } else SelectObject( hdc
, hPrevBrush
);
1237 /***********************************************************************
1240 * Paint a menu bar. Returns the height of the menu bar.
1242 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1247 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1249 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( (HMENU16
)wndPtr
->wIDmenu
);
1250 if (lppop
== NULL
|| lprect
== NULL
)
1252 retvalue
= SYSMETRICS_CYMENU
;
1255 TRACE(menu
,"(%04x, %p, %p); !\n",
1256 hDC
, lprect
, lppop
);
1257 if (lppop
->Height
== 0) MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
1258 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
1261 retvalue
= lppop
->Height
;
1265 FillRect(hDC
, lprect
, GetSysColorBrush(COLOR_MENU
) );
1267 if (TWEAK_WineLook
== WIN31_LOOK
) {
1268 SelectObject( hDC
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1269 MoveTo16( hDC
, lprect
->left
, lprect
->bottom
);
1270 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1273 SelectObject( hDC
, GetSysColorPen(COLOR_3DFACE
));
1274 MoveTo16( hDC
, lprect
->left
, lprect
->bottom
);
1275 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1278 if (lppop
->nItems
== 0)
1280 retvalue
= SYSMETRICS_CYMENU
;
1283 for (i
= 0; i
< lppop
->nItems
; i
++)
1285 MENU_DrawMenuItem( hwnd
, hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
,
1288 retvalue
= lppop
->Height
;
1290 WIN_ReleaseWndPtr(wndPtr
);
1295 /***********************************************************************
1296 * MENU_PatchResidentPopup
1298 BOOL
MENU_PatchResidentPopup( HQUEUE16 checkQueue
, WND
* checkWnd
)
1300 WND
*pTPWnd
= MENU_GetTopPopupWnd();
1306 TRACE(menu
,"patching resident popup: %04x %04x [%04x %04x]\n",
1307 checkQueue
, checkWnd
? checkWnd
->hwndSelf
: 0, pTPWnd
->hmemTaskQ
,
1308 pTPWnd
->owner
? pTPWnd
->owner
->hwndSelf
: 0);
1310 switch( checkQueue
)
1312 case 0: /* checkWnd is the new popup owner */
1315 pTPWnd
->owner
= checkWnd
;
1316 if( pTPWnd
->hmemTaskQ
!= checkWnd
->hmemTaskQ
)
1317 hTask
= QUEUE_GetQueueTask( checkWnd
->hmemTaskQ
);
1321 case 0xFFFF: /* checkWnd is destroyed */
1322 if( pTPWnd
->owner
== checkWnd
)
1323 pTPWnd
->owner
= NULL
;
1324 MENU_ReleaseTopPopupWnd();
1327 default: /* checkQueue is exiting */
1328 if( pTPWnd
->hmemTaskQ
== checkQueue
)
1330 hTask
= QUEUE_GetQueueTask( pTPWnd
->hmemTaskQ
);
1331 hTask
= TASK_GetNextTask( hTask
);
1338 TDB
* task
= (TDB
*)GlobalLock16( hTask
);
1341 pTPWnd
->hInstance
= task
->hInstance
;
1342 pTPWnd
->hmemTaskQ
= task
->hQueue
;
1343 MENU_ReleaseTopPopupWnd();
1346 else WARN(menu
,"failed to patch resident popup.\n");
1349 MENU_ReleaseTopPopupWnd();
1353 /***********************************************************************
1356 * Display a popup menu.
1358 static BOOL
MENU_ShowPopup( HWND hwndOwner
, HMENU hmenu
, UINT id
,
1359 INT x
, INT y
, INT xanchor
, INT yanchor
)
1362 WND
*wndOwner
= NULL
;
1364 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
1365 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1367 menu
->items
[menu
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1368 menu
->FocusedItem
= NO_SELECTED_ITEM
;
1371 if( (wndOwner
= WIN_FindWndPtr( hwndOwner
)) )
1375 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
1377 /* adjust popup menu pos so that it fits within the desktop */
1379 width
= menu
->Width
+ SYSMETRICS_CXBORDER
;
1380 height
= menu
->Height
+ SYSMETRICS_CYBORDER
;
1382 if( x
+ width
> SYSMETRICS_CXSCREEN
)
1385 x
-= width
- xanchor
;
1386 if( x
+ width
> SYSMETRICS_CXSCREEN
)
1387 x
= SYSMETRICS_CXSCREEN
- width
;
1391 if( y
+ height
> SYSMETRICS_CYSCREEN
)
1394 y
-= height
+ yanchor
;
1395 if( y
+ height
> SYSMETRICS_CYSCREEN
)
1396 y
= SYSMETRICS_CYSCREEN
- height
;
1400 width
+= POPUP_XSHADE
* SYSMETRICS_CXBORDER
; /* add space for shading */
1401 height
+= POPUP_YSHADE
* SYSMETRICS_CYBORDER
;
1403 /* NOTE: In Windows, top menu popup is not owned. */
1404 if (!pTopPopupWnd
) /* create top level popup menu window */
1406 assert( uSubPWndLevel
== 0 );
1408 pTopPopupWnd
= WIN_FindWndPtr(CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1409 WS_POPUP
, x
, y
, width
, height
,
1410 hwndOwner
, 0, wndOwner
->hInstance
,
1414 WIN_ReleaseWndPtr(wndOwner
);
1417 menu
->hWnd
= pTopPopupWnd
->hwndSelf
;
1418 MENU_ReleaseTopPopupWnd();
1423 /* create a new window for the submenu */
1425 menu
->hWnd
= CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1426 WS_POPUP
, x
, y
, width
, height
,
1427 menu
->hWnd
, 0, wndOwner
->hInstance
,
1431 WIN_ReleaseWndPtr(wndOwner
);
1435 else /* top level popup menu window already exists */
1437 WND
*pTPWnd
= MENU_GetTopPopupWnd();
1438 menu
->hWnd
= pTPWnd
->hwndSelf
;
1440 MENU_PatchResidentPopup( 0, wndOwner
);
1441 SendMessage16( pTPWnd
->hwndSelf
, MM_SETMENUHANDLE
, (WPARAM16
)hmenu
, 0L);
1443 /* adjust its size */
1445 SetWindowPos( menu
->hWnd
, 0, x
, y
, width
, height
,
1446 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_NOREDRAW
);
1447 MENU_ReleaseTopPopupWnd();
1450 uSubPWndLevel
++; /* menu level counter */
1452 /* Display the window */
1454 SetWindowPos( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
1455 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1456 UpdateWindow( menu
->hWnd
);
1457 WIN_ReleaseWndPtr(wndOwner
);
1464 /***********************************************************************
1467 static void MENU_SelectItem( HWND hwndOwner
, HMENU hmenu
, UINT wIndex
,
1468 BOOL sendMenuSelect
)
1473 lppop
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1474 if (!lppop
->nItems
) return;
1476 if ((wIndex
!= NO_SELECTED_ITEM
) &&
1477 (lppop
->items
[wIndex
].fType
& MF_SEPARATOR
))
1478 wIndex
= NO_SELECTED_ITEM
;
1480 if (lppop
->FocusedItem
== wIndex
) return;
1481 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC( lppop
->hWnd
);
1482 else hdc
= GetDCEx( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1484 /* Clear previous highlighted item */
1485 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1487 lppop
->items
[lppop
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1488 MENU_DrawMenuItem(lppop
->hWnd
,hdc
,&lppop
->items
[lppop
->FocusedItem
],
1489 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
),
1493 /* Highlight new item (if any) */
1494 lppop
->FocusedItem
= wIndex
;
1495 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1497 lppop
->items
[lppop
->FocusedItem
].fState
|= MF_HILITE
;
1498 MENU_DrawMenuItem( lppop
->hWnd
, hdc
, &lppop
->items
[lppop
->FocusedItem
],
1499 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
),
1503 MENUITEM
*ip
= &lppop
->items
[lppop
->FocusedItem
];
1504 SendMessage16( hwndOwner
, WM_MENUSELECT
, ip
->wID
,
1505 MAKELONG(ip
->fType
| (ip
->fState
| MF_MOUSESELECT
),
1509 else if (sendMenuSelect
) {
1510 SendMessage16( hwndOwner
, WM_MENUSELECT
, hmenu
,
1511 MAKELONG( lppop
->wFlags
| MF_MOUSESELECT
, hmenu
) );
1513 ReleaseDC( lppop
->hWnd
, hdc
);
1517 /***********************************************************************
1518 * MENU_MoveSelection
1520 * Moves currently selected item according to the offset parameter.
1521 * If there is no selection then it should select the last item if
1522 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1524 static void MENU_MoveSelection( HWND hwndOwner
, HMENU hmenu
, INT offset
)
1529 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1530 if (!menu
->items
) return;
1532 if ( menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1534 if( menu
->nItems
== 1 ) return; else
1535 for (i
= menu
->FocusedItem
+ offset
; i
>= 0 && i
< menu
->nItems
1537 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1539 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
1544 for ( i
= (offset
> 0) ? 0 : menu
->nItems
- 1;
1545 i
>= 0 && i
< menu
->nItems
; i
+= offset
)
1546 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1548 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
1554 /**********************************************************************
1557 * Set an item flags, id and text ptr. Called by InsertMenu() and
1560 static BOOL
MENU_SetItemData( MENUITEM
*item
, UINT flags
, UINT id
,
1563 LPSTR prevText
= IS_STRING_ITEM(item
->fType
) ? item
->text
: NULL
;
1565 debug_print_menuitem("MENU_SetItemData from: ", item
, "");
1567 if (IS_STRING_ITEM(flags
))
1571 flags
|= MF_SEPARATOR
;
1577 /* Item beginning with a backspace is a help item */
1583 if (!(text
= HEAP_strdupA( SystemHeap
, 0, str
))) return FALSE
;
1587 else if (flags
& MF_BITMAP
) item
->text
= (LPSTR
)(HBITMAP
)LOWORD(str
);
1588 else item
->text
= NULL
;
1590 if (flags
& MF_OWNERDRAW
)
1591 item
->dwItemData
= (DWORD
)str
;
1593 item
->dwItemData
= 0;
1595 if ((item
->fType
& MF_POPUP
) && (flags
& MF_POPUP
) && (item
->hSubMenu
!= id
) )
1596 DestroyMenu( item
->hSubMenu
); /* ModifyMenu() spec */
1598 if (flags
& MF_POPUP
)
1600 POPUPMENU
*menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR((UINT16
)id
);
1601 if (IS_A_MENU(menu
)) menu
->wFlags
|= MF_POPUP
;
1613 if (flags
& MF_POPUP
)
1614 item
->hSubMenu
= id
;
1616 if ((item
->fType
& MF_POPUP
) && !(flags
& MF_POPUP
) )
1617 flags
|= MF_POPUP
; /* keep popup */
1619 item
->fType
= flags
& TYPE_MASK
;
1620 item
->fState
= (flags
& STATE_MASK
) &
1621 ~(MF_HILITE
| MF_MOUSESELECT
| MF_BYPOSITION
);
1624 /* Don't call SetRectEmpty here! */
1627 if (prevText
) HeapFree( SystemHeap
, 0, prevText
);
1629 debug_print_menuitem("MENU_SetItemData to : ", item
, "");
1634 /**********************************************************************
1637 * Insert a new item into a menu.
1639 static MENUITEM
*MENU_InsertItem( HMENU hMenu
, UINT pos
, UINT flags
)
1644 if (!(menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
)))
1646 WARN(menu
, "%04x not a menu handle\n",
1651 /* Find where to insert new item */
1653 if ((flags
& MF_BYPOSITION
) &&
1654 ((pos
== (UINT
)-1) || (pos
== menu
->nItems
)))
1656 /* Special case: append to menu */
1657 /* Some programs specify the menu length to do that */
1662 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
1664 WARN(menu
, "item %x not found\n",
1668 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
)))
1670 WARN(menu
,"%04x not a menu handle\n",
1676 /* Create new items array */
1678 newItems
= HeapAlloc( SystemHeap
, 0, sizeof(MENUITEM
) * (menu
->nItems
+1) );
1681 WARN(menu
, "allocation failed\n" );
1684 if (menu
->nItems
> 0)
1686 /* Copy the old array into the new */
1687 if (pos
> 0) memcpy( newItems
, menu
->items
, pos
* sizeof(MENUITEM
) );
1688 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &menu
->items
[pos
],
1689 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
1690 HeapFree( SystemHeap
, 0, menu
->items
);
1692 menu
->items
= newItems
;
1694 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
1695 return &newItems
[pos
];
1699 /**********************************************************************
1700 * MENU_ParseResource
1702 * Parse a standard menu resource and add items to the menu.
1703 * Return a pointer to the end of the resource.
1705 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1712 flags
= GET_WORD(res
);
1713 res
+= sizeof(WORD
);
1714 if (!(flags
& MF_POPUP
))
1717 res
+= sizeof(WORD
);
1719 if (!IS_STRING_ITEM(flags
))
1720 ERR(menu
, "not a string item %04x\n", flags
);
1722 if (!unicode
) res
+= strlen(str
) + 1;
1723 else res
+= (lstrlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1724 if (flags
& MF_POPUP
)
1726 HMENU hSubMenu
= CreatePopupMenu();
1727 if (!hSubMenu
) return NULL
;
1728 if (!(res
= MENU_ParseResource( res
, hSubMenu
, unicode
)))
1730 if (!unicode
) AppendMenuA( hMenu
, flags
, (UINT
)hSubMenu
, str
);
1731 else AppendMenuW( hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1733 else /* Not a popup */
1735 if (!unicode
) AppendMenuA( hMenu
, flags
, id
, *str
? str
: NULL
);
1736 else AppendMenuW( hMenu
, flags
, id
,
1737 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1739 } while (!(flags
& MF_END
));
1744 /**********************************************************************
1745 * MENUEX_ParseResource
1747 * Parse an extended menu resource and add items to the menu.
1748 * Return a pointer to the end of the resource.
1750 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
1756 mii
.cbSize
= sizeof(mii
);
1757 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
1758 mii
.fType
= GET_DWORD(res
);
1759 res
+= sizeof(DWORD
);
1760 mii
.fState
= GET_DWORD(res
);
1761 res
+= sizeof(DWORD
);
1762 mii
.wID
= GET_DWORD(res
);
1763 res
+= sizeof(DWORD
);
1764 resinfo
= GET_WORD(res
); /* FIXME: for 16-bit apps this is a byte. */
1765 res
+= sizeof(WORD
);
1766 /* Align the text on a word boundary. */
1767 res
+= (~((int)res
- 1)) & 1;
1768 mii
.dwTypeData
= (LPWSTR
) res
;
1769 res
+= (1 + lstrlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
1770 /* Align the following fields on a dword boundary. */
1771 res
+= (~((int)res
- 1)) & 3;
1773 /* FIXME: This is inefficient and cannot be optimised away by gcc. */
1775 LPSTR newstr
= HEAP_strdupWtoA(GetProcessHeap(),
1777 TRACE(menu
, "Menu item: [%08x,%08x,%04x,%04x,%s]\n",
1778 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, newstr
);
1779 HeapFree( GetProcessHeap(), 0, newstr
);
1782 if (resinfo
& 1) { /* Pop-up? */
1783 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
1784 res
+= sizeof(DWORD
);
1785 mii
.hSubMenu
= CreatePopupMenu();
1788 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
1789 DestroyMenu(mii
.hSubMenu
);
1792 mii
.fMask
|= MIIM_SUBMENU
;
1793 mii
.fType
|= MF_POPUP
;
1795 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
1796 } while (!(resinfo
& MF_END
));
1801 /***********************************************************************
1804 * Return the handle of the selected sub-popup menu (if any).
1806 static HMENU
MENU_GetSubPopup( HMENU hmenu
)
1811 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1813 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return 0;
1815 item
= &menu
->items
[menu
->FocusedItem
];
1816 if ((item
->fType
& MF_POPUP
) && (item
->fState
& MF_MOUSESELECT
))
1817 return item
->hSubMenu
;
1822 /***********************************************************************
1823 * MENU_HideSubPopups
1825 * Hide the sub-popup menus of this menu.
1827 static void MENU_HideSubPopups( HWND hwndOwner
, HMENU hmenu
,
1828 BOOL sendMenuSelect
)
1830 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);;
1832 if (menu
&& uSubPWndLevel
)
1838 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1840 item
= &menu
->items
[menu
->FocusedItem
];
1841 if (!(item
->fType
& MF_POPUP
) ||
1842 !(item
->fState
& MF_MOUSESELECT
)) return;
1843 item
->fState
&= ~MF_MOUSESELECT
;
1844 hsubmenu
= item
->hSubMenu
;
1847 submenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hsubmenu
);
1848 MENU_HideSubPopups( hwndOwner
, hsubmenu
, FALSE
);
1849 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, sendMenuSelect
);
1851 if (submenu
->hWnd
== MENU_GetTopPopupWnd()->hwndSelf
)
1853 ShowWindow( submenu
->hWnd
, SW_HIDE
);
1858 DestroyWindow( submenu
->hWnd
);
1861 MENU_ReleaseTopPopupWnd();
1866 /***********************************************************************
1869 * Display the sub-menu of the selected item of this menu.
1870 * Return the handle of the submenu, or hmenu if no submenu to display.
1872 static HMENU
MENU_ShowSubPopup( HWND hwndOwner
, HMENU hmenu
,
1881 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return hmenu
;
1883 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
)) ||
1884 (menu
->FocusedItem
== NO_SELECTED_ITEM
))
1886 WIN_ReleaseWndPtr(wndPtr
);
1890 item
= &menu
->items
[menu
->FocusedItem
];
1891 if (!(item
->fType
& MF_POPUP
) ||
1892 (item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
1894 WIN_ReleaseWndPtr(wndPtr
);
1898 /* message must be send before using item,
1899 because nearly everything may by changed by the application ! */
1901 SendMessage16( hwndOwner
, WM_INITMENUPOPUP
, (WPARAM16
)item
->hSubMenu
,
1902 MAKELONG( menu
->FocusedItem
, IS_SYSTEM_MENU(menu
) ));
1904 item
= &menu
->items
[menu
->FocusedItem
];
1907 /* correct item if modified as a reaction to WM_INITMENUPOPUP-message */
1908 if (!(item
->fState
& MF_HILITE
))
1910 if (menu
->wFlags
& MF_POPUP
) hdc
= GetDC( menu
->hWnd
);
1911 else hdc
= GetDCEx( menu
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1912 item
->fState
|= MF_HILITE
;
1913 MENU_DrawMenuItem( menu
->hWnd
, hdc
, item
, menu
->Height
, !(menu
->wFlags
& MF_POPUP
), ODA_DRAWENTIRE
);
1914 ReleaseDC( menu
->hWnd
, hdc
);
1916 if (!item
->rect
.top
&& !item
->rect
.left
&& !item
->rect
.bottom
&& !item
->rect
.right
)
1919 item
->fState
|= MF_MOUSESELECT
;
1921 if (IS_SYSTEM_MENU(menu
))
1923 MENU_InitSysMenuPopup(item
->hSubMenu
, wndPtr
->dwStyle
, wndPtr
->class->style
);
1925 NC_GetSysPopupPos( wndPtr
, &rect
);
1926 rect
.top
= rect
.bottom
;
1927 rect
.right
= SYSMETRICS_CXSIZE
;
1928 rect
.bottom
= SYSMETRICS_CYSIZE
;
1932 if (menu
->wFlags
& MF_POPUP
)
1934 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.right
-arrow_bitmap_width
;
1935 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.top
;
1936 rect
.right
= item
->rect
.left
- item
->rect
.right
+ 2*arrow_bitmap_width
;
1937 rect
.bottom
= item
->rect
.top
- item
->rect
.bottom
;
1941 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.left
;
1942 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.bottom
;
1943 rect
.right
= item
->rect
.right
- item
->rect
.left
;
1944 rect
.bottom
= item
->rect
.bottom
- item
->rect
.top
;
1948 MENU_ShowPopup( hwndOwner
, item
->hSubMenu
, menu
->FocusedItem
,
1949 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1951 MENU_MoveSelection( hwndOwner
, item
->hSubMenu
, ITEM_NEXT
);
1952 WIN_ReleaseWndPtr(wndPtr
);
1953 return item
->hSubMenu
;
1956 /***********************************************************************
1959 * Walks menu chain trying to find a menu pt maps to.
1961 static HMENU
MENU_PtMenu( HMENU hMenu
, POINT16 pt
)
1963 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hMenu
);
1964 register UINT ht
= menu
->FocusedItem
;
1966 /* try subpopup first (if any) */
1967 ht
= (ht
!= NO_SELECTED_ITEM
&&
1968 (menu
->items
[ht
].fType
& MF_POPUP
) &&
1969 (menu
->items
[ht
].fState
& MF_MOUSESELECT
))
1970 ? (UINT
) MENU_PtMenu(menu
->items
[ht
].hSubMenu
, pt
) : 0;
1972 if( !ht
) /* check the current window (avoiding WM_HITTEST) */
1974 ht
= (UINT
)NC_HandleNCHitTest( menu
->hWnd
, pt
);
1975 if( menu
->wFlags
& MF_POPUP
)
1976 ht
= (ht
!= (UINT
)HTNOWHERE
&&
1977 ht
!= (UINT
)HTERROR
) ? (UINT
)hMenu
: 0;
1980 WND
* wndPtr
= WIN_FindWndPtr(menu
->hWnd
);
1982 ht
= ( ht
== HTSYSMENU
) ? (UINT
)(wndPtr
->hSysMenu
)
1983 : ( ht
== HTMENU
) ? (UINT
)(wndPtr
->wIDmenu
) : 0;
1984 WIN_ReleaseWndPtr(wndPtr
);
1989 /***********************************************************************
1990 * MENU_ExecFocusedItem
1992 * Execute a menu item (for instance when user pressed Enter).
1993 * Return the wID of the executed item. Otherwise, zero indicating
1994 * that no menu item wase executed;
1996 static INT
MENU_ExecFocusedItem( MTRACKER
* pmt
, HMENU hMenu
)
1999 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hMenu
);
2000 if (!menu
|| !menu
->nItems
||
2001 (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return 0;
2003 item
= &menu
->items
[menu
->FocusedItem
];
2005 TRACE(menu
, "%08x %08x %08x\n",
2006 hMenu
, item
->wID
, item
->hSubMenu
);
2008 if (!(item
->fType
& MF_POPUP
))
2010 if (!(item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
2012 if( menu
->wFlags
& MF_SYSMENU
)
2014 PostMessage16( pmt
->hOwnerWnd
, WM_SYSCOMMAND
, item
->wID
,
2015 MAKELPARAM((INT16
)pmt
->pt
.x
, (INT16
)pmt
->pt
.y
) );
2019 PostMessage16( pmt
->hOwnerWnd
, WM_COMMAND
, item
->wID
, 0 );
2027 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hMenu
, TRUE
);
2032 /***********************************************************************
2033 * MENU_SwitchTracking
2035 * Helper function for menu navigation routines.
2037 static void MENU_SwitchTracking( MTRACKER
* pmt
, HMENU hPtMenu
, UINT id
)
2039 POPUPMENU
*ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
2040 POPUPMENU
*topmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( pmt
->hTopMenu
);
2042 if( pmt
->hTopMenu
!= hPtMenu
&&
2043 !((ptmenu
->wFlags
| topmenu
->wFlags
) & MF_POPUP
) )
2045 /* both are top level menus (system and menu-bar) */
2047 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2048 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
);
2049 pmt
->hTopMenu
= hPtMenu
;
2051 else MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
2052 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, id
, TRUE
);
2056 /***********************************************************************
2059 * Return TRUE if we can go on with menu tracking.
2061 static BOOL
MENU_ButtonDown( MTRACKER
* pmt
, HMENU hPtMenu
)
2066 POPUPMENU
*ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
2069 if( IS_SYSTEM_MENU(ptmenu
) )
2070 item
= ptmenu
->items
;
2072 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2076 if( ptmenu
->FocusedItem
== id
)
2078 /* nothing to do with already selected non-popup */
2079 if( !(item
->fType
& MF_POPUP
) ) return TRUE
;
2081 if( item
->fState
& MF_MOUSESELECT
)
2083 if( ptmenu
->wFlags
& MF_POPUP
)
2085 /* hide selected subpopup */
2087 MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, TRUE
);
2088 pmt
->hCurrentMenu
= hPtMenu
;
2091 return FALSE
; /* shouldn't get here */
2094 else MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2096 /* try to display a subpopup */
2098 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
2101 else WARN(menu
, "\tunable to find clicked item!\n");
2106 /***********************************************************************
2109 * Return the the value of MENU_ExecFocusedItem if
2110 * the selected item was not a popup
2111 * 1 if the item was a popup
2113 * A zero return value indicates that we can't go on with menu tracking.
2115 static INT
MENU_ButtonUp( MTRACKER
* pmt
, HMENU hPtMenu
)
2120 POPUPMENU
*ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
2123 if( IS_SYSTEM_MENU(ptmenu
) )
2124 item
= ptmenu
->items
;
2126 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2128 if( item
&& (ptmenu
->FocusedItem
== id
))
2130 if( !(item
->fType
& MF_POPUP
) )
2131 return MENU_ExecFocusedItem( pmt
, hPtMenu
);
2132 hPtMenu
= item
->hSubMenu
;
2133 if( hPtMenu
== pmt
->hCurrentMenu
)
2135 /* Select first item of sub-popup */
2137 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, NO_SELECTED_ITEM
, FALSE
);
2138 MENU_MoveSelection( pmt
->hOwnerWnd
, hPtMenu
, ITEM_NEXT
);
2147 /***********************************************************************
2150 * Return TRUE if we can go on with menu tracking.
2152 static BOOL
MENU_MouseMove( MTRACKER
* pmt
, HMENU hPtMenu
)
2154 UINT id
= NO_SELECTED_ITEM
;
2155 POPUPMENU
*ptmenu
= NULL
;
2159 ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
2160 if( IS_SYSTEM_MENU(ptmenu
) )
2163 MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2166 if( id
== NO_SELECTED_ITEM
)
2168 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2169 NO_SELECTED_ITEM
, TRUE
);
2171 else if( ptmenu
->FocusedItem
!= id
)
2173 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2174 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
2180 /***********************************************************************
2183 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2185 static LRESULT
MENU_DoNextMenu( MTRACKER
* pmt
, UINT vk
)
2187 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( pmt
->hTopMenu
);
2189 if( (vk
== VK_LEFT
&& menu
->FocusedItem
== 0 ) ||
2190 (vk
== VK_RIGHT
&& menu
->FocusedItem
== menu
->nItems
- 1))
2196 LRESULT l
= SendMessage16( pmt
->hOwnerWnd
, WM_NEXTMENU
, (WPARAM16
)vk
,
2197 (IS_SYSTEM_MENU(menu
)) ? GetSubMenu16(pmt
->hTopMenu
,0) : pmt
->hTopMenu
);
2199 TRACE(menu
,"%04x [%04x] -> %04x [%04x]\n",
2200 (UINT16
)pmt
->hCurrentMenu
, (UINT16
)pmt
->hOwnerWnd
, LOWORD(l
), HIWORD(l
) );
2204 wndPtr
= WIN_FindWndPtr(pmt
->hOwnerWnd
);
2206 hNewWnd
= pmt
->hOwnerWnd
;
2207 if( IS_SYSTEM_MENU(menu
) )
2209 /* switch to the menu bar */
2211 if( wndPtr
->dwStyle
& WS_CHILD
|| !wndPtr
->wIDmenu
)
2213 WIN_ReleaseWndPtr(wndPtr
);
2217 hNewMenu
= wndPtr
->wIDmenu
;
2220 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hNewMenu
);
2221 id
= menu
->nItems
- 1;
2224 else if( wndPtr
->dwStyle
& WS_SYSMENU
)
2226 /* switch to the system menu */
2227 hNewMenu
= wndPtr
->hSysMenu
;
2231 WIN_ReleaseWndPtr(wndPtr
);
2234 WIN_ReleaseWndPtr(wndPtr
);
2236 else /* application returned a new menu to switch to */
2238 hNewMenu
= LOWORD(l
); hNewWnd
= HIWORD(l
);
2240 if( IsMenu(hNewMenu
) && IsWindow(hNewWnd
) )
2242 wndPtr
= WIN_FindWndPtr(hNewWnd
);
2244 if( wndPtr
->dwStyle
& WS_SYSMENU
&&
2245 GetSubMenu16(wndPtr
->hSysMenu
, 0) == hNewMenu
)
2247 /* get the real system menu */
2248 hNewMenu
= wndPtr
->hSysMenu
;
2250 else if( wndPtr
->dwStyle
& WS_CHILD
|| wndPtr
->wIDmenu
!= hNewMenu
)
2252 /* FIXME: Not sure what to do here, perhaps,
2253 * try to track hNewMenu as a popup? */
2255 TRACE(menu
," -- got confused.\n");
2256 WIN_ReleaseWndPtr(wndPtr
);
2259 WIN_ReleaseWndPtr(wndPtr
);
2264 if( hNewMenu
!= pmt
->hTopMenu
)
2266 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
);
2267 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2268 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2271 if( hNewWnd
!= pmt
->hOwnerWnd
)
2274 pmt
->hOwnerWnd
= hNewWnd
;
2275 EVENT_Capture( pmt
->hOwnerWnd
, HTMENU
);
2278 pmt
->hTopMenu
= pmt
->hCurrentMenu
= hNewMenu
; /* all subpopups are hidden */
2279 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, id
, TRUE
);
2286 /***********************************************************************
2289 * The idea is not to show the popup if the next input message is
2290 * going to hide it anyway.
2292 static BOOL
MENU_SuspendPopup( MTRACKER
* pmt
, UINT16 uMsg
)
2296 msg
.hwnd
= pmt
->hOwnerWnd
;
2298 PeekMessage16( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2299 pmt
->trackFlags
|= TF_SKIPREMOVE
;
2304 PeekMessage16( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2305 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
2307 PeekMessage16( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2308 PeekMessage16( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2309 if( msg
.message
== WM_KEYDOWN
&&
2310 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
2312 pmt
->trackFlags
|= TF_SUSPENDPOPUP
;
2319 /* failures go through this */
2320 pmt
->trackFlags
&= ~TF_SUSPENDPOPUP
;
2324 /***********************************************************************
2327 * Handle a VK_LEFT key event in a menu.
2329 static void MENU_KeyLeft( MTRACKER
* pmt
)
2332 HMENU hmenutmp
, hmenuprev
;
2335 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
2336 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenutmp
);
2338 /* Try to move 1 column left (if possible) */
2339 if( (prevcol
= MENU_GetStartOfPrevColumn( pmt
->hCurrentMenu
)) !=
2340 NO_SELECTED_ITEM
) {
2342 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2347 /* close topmost popup */
2348 while (hmenutmp
!= pmt
->hCurrentMenu
)
2350 hmenuprev
= hmenutmp
;
2351 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
2354 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
);
2355 pmt
->hCurrentMenu
= hmenuprev
;
2357 if ( (hmenuprev
== pmt
->hTopMenu
) && !(menu
->wFlags
& MF_POPUP
) )
2359 /* move menu bar selection if no more popups are left */
2361 if( !MENU_DoNextMenu( pmt
, VK_LEFT
) )
2362 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_PREV
);
2364 if ( hmenuprev
!= hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2366 /* A sublevel menu was displayed - display the next one
2367 * unless there is another displacement coming up */
2369 if( !MENU_SuspendPopup( pmt
, WM_KEYDOWN
) )
2370 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
,
2371 pmt
->hTopMenu
, TRUE
);
2377 /***********************************************************************
2380 * Handle a VK_RIGHT key event in a menu.
2382 static void MENU_KeyRight( MTRACKER
* pmt
)
2385 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( pmt
->hTopMenu
);
2388 TRACE(menu
, "MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2390 ((POPUPMENU
*)USER_HEAP_LIN_ADDR(pmt
->hCurrentMenu
))->
2392 pmt
->hTopMenu
, menu
->items
[0].text
);
2394 if ( (menu
->wFlags
& MF_POPUP
) || (pmt
->hCurrentMenu
!= pmt
->hTopMenu
))
2396 /* If already displaying a popup, try to display sub-popup */
2398 hmenutmp
= pmt
->hCurrentMenu
;
2399 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hmenutmp
, TRUE
);
2401 /* if subpopup was displayed then we are done */
2402 if (hmenutmp
!= pmt
->hCurrentMenu
) return;
2405 /* Check to see if there's another column */
2406 if( (nextcol
= MENU_GetStartOfNextColumn( pmt
->hCurrentMenu
)) !=
2407 NO_SELECTED_ITEM
) {
2408 TRACE(menu
, "Going to %d.\n", nextcol
);
2409 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2414 if (!(menu
->wFlags
& MF_POPUP
)) /* menu bar tracking */
2416 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2418 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2419 hmenutmp
= pmt
->hCurrentMenu
= pmt
->hTopMenu
;
2420 } else hmenutmp
= 0;
2422 /* try to move to the next item */
2423 if( !MENU_DoNextMenu( pmt
, VK_RIGHT
) )
2424 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_NEXT
);
2426 if( hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2427 if( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
2428 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
,
2429 pmt
->hTopMenu
, TRUE
);
2433 /***********************************************************************
2436 * Menu tracking code.
2438 static INT
MENU_TrackMenu( HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
2439 HWND hwnd
, const RECT
*lprect
)
2444 INT executedMenuId
= 0;
2445 MTRACKER mt
= { 0, hmenu
, hmenu
, hwnd
, {x
, y
} }; /* control struct */
2448 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
2450 if (wFlags
& TPM_BUTTONDOWN
) MENU_ButtonDown( &mt
, hmenu
);
2452 EVENT_Capture( mt
.hOwnerWnd
, HTMENU
);
2456 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( mt
.hCurrentMenu
);
2457 msg
.hwnd
= (wFlags
& TPM_ENTERIDLEEX
&& menu
->wFlags
& MF_POPUP
) ? menu
->hWnd
: 0;
2459 /* we have to keep the message in the queue until it's
2460 * clear that menu loop is not over yet. */
2462 if (!MSG_InternalGetMessage( &msg
, msg
.hwnd
, mt
.hOwnerWnd
,
2463 MSGF_MENU
, PM_NOREMOVE
, TRUE
)) break;
2465 TranslateMessage( &msg
);
2469 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
2471 /* Find a menu for this mouse event */
2473 CONV_POINT32TO16( &msg
.pt
, &pt16
);
2474 hmenu
= MENU_PtMenu( mt
.hTopMenu
, pt16
);
2478 /* no WM_NC... messages in captured state */
2480 case WM_RBUTTONDBLCLK
:
2481 case WM_RBUTTONDOWN
:
2482 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2484 case WM_LBUTTONDBLCLK
:
2485 case WM_LBUTTONDOWN
:
2486 fEndMenu
|= !MENU_ButtonDown( &mt
, hmenu
);
2490 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2493 /* Check if a menu was selected by the mouse */
2496 executedMenuId
= MENU_ButtonUp( &mt
, hmenu
);
2498 /* the executedMenuId higher than one means that it contains
2499 the id of the selected item so we have to put the fEndMenu to TRUE.
2500 Otherwise, it contains a continue
2501 flag returned by MENU_ButtonUp indicating if we can continue with
2502 menu tracking or not*/
2503 fEndMenu
= ((executedMenuId
> 1) ? TRUE
: FALSE
);
2506 /* No menu was selected by the mouse */
2507 /* if the function was called by TrackPopupMenu, continue
2508 with the menu tracking. If not, stop it */
2510 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
2515 /* In win95 winelook, the selected menu item must be changed every time the
2516 mouse moves. In Win31 winelook, the mouse button has to be held down */
2518 if ( (TWEAK_WineLook
> WIN31_LOOK
) ||
2519 ( (msg
.wParam
& MK_LBUTTON
) ||
2520 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
.wParam
& MK_RBUTTON
))) )
2522 fEndMenu
|= !MENU_MouseMove( &mt
, hmenu
);
2524 } /* switch(msg.message) - mouse */
2526 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
2528 fRemove
= TRUE
; /* Keyboard messages are always removed */
2536 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2537 NO_SELECTED_ITEM
, FALSE
);
2540 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2541 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
2544 case VK_DOWN
: /* If on menu bar, pull-down the menu */
2546 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( mt
.hCurrentMenu
);
2547 if (!(menu
->wFlags
& MF_POPUP
))
2548 mt
.hCurrentMenu
= MENU_ShowSubPopup( mt
.hOwnerWnd
, mt
.hTopMenu
, TRUE
);
2549 else /* otherwise try to move selection */
2550 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
, ITEM_NEXT
);
2554 MENU_KeyLeft( &mt
);
2558 MENU_KeyRight( &mt
);
2568 break; /* WM_KEYDOWN */
2578 break; /* WM_SYSKEYDOWN */
2584 if (msg
.wParam
== '\r' || msg
.wParam
== ' ')
2586 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
);
2587 fEndMenu
= ((executedMenuId
!= 0) ? TRUE
:FALSE
);
2592 /* Hack to avoid control chars. */
2593 /* We will find a better way real soon... */
2594 if ((msg
.wParam
<= 32) || (msg
.wParam
>= 127)) break;
2596 pos
= MENU_FindItemByKey( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2597 LOWORD(msg
.wParam
), FALSE
);
2598 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
2599 else if (pos
== (UINT
)-1) MessageBeep(0);
2602 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
, pos
, TRUE
);
2603 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
);
2604 fEndMenu
= ((executedMenuId
!= 0) ? TRUE
:FALSE
);
2608 } /* switch(msg.message) - kbd */
2612 DispatchMessageA( &msg
);
2615 if (!fEndMenu
) fRemove
= TRUE
;
2617 /* finally remove message from the queue */
2619 if (fRemove
&& !(mt
.trackFlags
& TF_SKIPREMOVE
) )
2620 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2621 else mt
.trackFlags
&= ~TF_SKIPREMOVE
;
2625 if( IsWindow( mt
.hOwnerWnd
) )
2627 MENU_HideSubPopups( mt
.hOwnerWnd
, mt
.hTopMenu
, FALSE
);
2629 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( mt
.hTopMenu
);
2630 if (menu
&& menu
->wFlags
& MF_POPUP
)
2632 ShowWindow( menu
->hWnd
, SW_HIDE
);
2635 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hTopMenu
, NO_SELECTED_ITEM
, FALSE
);
2636 SendMessage16( mt
.hOwnerWnd
, WM_MENUSELECT
, 0, MAKELONG( 0xffff, 0 ) );
2639 /* returning the id of the selected menu.
2640 The return value is only used by TrackPopupMenu */
2641 return executedMenuId
;
2644 /***********************************************************************
2647 static BOOL
MENU_InitTracking(HWND hWnd
, HMENU hMenu
)
2650 SendMessage16( hWnd
, WM_ENTERMENULOOP
, 0, 0 );
2651 SendMessage16( hWnd
, WM_SETCURSOR
, hWnd
, HTCAPTION
);
2652 SendMessage16( hWnd
, WM_INITMENU
, hMenu
, 0 );
2656 /***********************************************************************
2657 * MENU_TrackMouseMenuBar
2659 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2661 void MENU_TrackMouseMenuBar( WND
* wndPtr
, INT ht
, POINT pt
)
2663 HWND hWnd
= wndPtr
->hwndSelf
;
2664 HMENU hMenu
= (ht
== HTSYSMENU
) ? wndPtr
->hSysMenu
: wndPtr
->wIDmenu
;
2668 MENU_InitTracking( hWnd
, hMenu
);
2669 MENU_TrackMenu( hMenu
, TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
|
2670 TPM_LEFTALIGN
| TPM_LEFTBUTTON
, pt
.x
, pt
.y
, hWnd
, NULL
);
2672 SendMessage16( hWnd
, WM_EXITMENULOOP
, 0, 0 );
2678 /***********************************************************************
2679 * MENU_TrackKbdMenuBar
2681 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
2683 void MENU_TrackKbdMenuBar( WND
* wndPtr
, UINT wParam
, INT vkey
)
2685 UINT uItem
= NO_SELECTED_ITEM
;
2688 /* find window that has a menu */
2690 while( wndPtr
->dwStyle
& WS_CHILD
&& !(wndPtr
->dwStyle
& WS_SYSMENU
) )
2691 if( !(wndPtr
= wndPtr
->parent
) ) return;
2693 /* check if we have to track a system menu */
2695 if( (wndPtr
->dwStyle
& (WS_CHILD
| WS_MINIMIZE
)) ||
2696 !wndPtr
->wIDmenu
|| vkey
== VK_SPACE
)
2698 if( !(wndPtr
->dwStyle
& WS_SYSMENU
) ) return;
2699 hTrackMenu
= wndPtr
->hSysMenu
;
2701 wParam
|= HTSYSMENU
; /* prevent item lookup */
2704 hTrackMenu
= wndPtr
->wIDmenu
;
2706 if (IsMenu( hTrackMenu
))
2708 MENU_InitTracking( wndPtr
->hwndSelf
, hTrackMenu
);
2710 if( vkey
&& vkey
!= VK_SPACE
)
2712 uItem
= MENU_FindItemByKey( wndPtr
->hwndSelf
, hTrackMenu
,
2713 vkey
, (wParam
& HTSYSMENU
) );
2714 if( uItem
>= (UINT
)(-2) )
2716 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
2723 MENU_SelectItem( wndPtr
->hwndSelf
, hTrackMenu
, uItem
, TRUE
);
2725 if( uItem
== NO_SELECTED_ITEM
)
2726 MENU_MoveSelection( wndPtr
->hwndSelf
, hTrackMenu
, ITEM_NEXT
);
2728 PostMessage16( wndPtr
->hwndSelf
, WM_KEYDOWN
, VK_DOWN
, 0L );
2730 MENU_TrackMenu( hTrackMenu
, TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
2731 0, 0, wndPtr
->hwndSelf
, NULL
);
2733 SendMessage16( wndPtr
->hwndSelf
, WM_EXITMENULOOP
, 0, 0 );
2739 /**********************************************************************
2740 * TrackPopupMenu16 (USER.416)
2742 BOOL16 WINAPI
TrackPopupMenu16( HMENU16 hMenu
, UINT16 wFlags
, INT16 x
, INT16 y
,
2743 INT16 nReserved
, HWND16 hWnd
, const RECT16
*lpRect
)
2747 CONV_RECT16TO32( lpRect
, &r
);
2748 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, nReserved
, hWnd
,
2749 lpRect
? &r
: NULL
);
2753 /**********************************************************************
2754 * TrackPopupMenu32 (USER32.549)
2756 BOOL WINAPI
TrackPopupMenu( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
2757 INT nReserved
, HWND hWnd
, const RECT
*lpRect
)
2762 SendMessage16( hWnd
, WM_INITMENUPOPUP
, (WPARAM16
)hMenu
, 0);
2763 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
, 0, 0 ))
2764 ret
= MENU_TrackMenu( hMenu
, wFlags
| TPM_POPUPMENU
, 0, 0, hWnd
, lpRect
);
2769 /**********************************************************************
2770 * TrackPopupMenuEx (USER32.550)
2772 BOOL WINAPI
TrackPopupMenuEx( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
2773 HWND hWnd
, LPTPMPARAMS lpTpm
)
2775 FIXME(menu
, "not fully implemented\n" );
2776 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, 0, hWnd
,
2777 lpTpm
? &lpTpm
->rcExclude
: NULL
);
2780 /***********************************************************************
2783 * NOTE: Windows has totally different (and undocumented) popup wndproc.
2785 LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
,
2788 WND
* wndPtr
= WIN_FindWndPtr(hwnd
);
2795 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*)lParam
;
2796 SetWindowLongA( hwnd
, 0, (LONG
)cs
->lpCreateParams
);
2801 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2802 retvalue
= MA_NOACTIVATE
;
2808 BeginPaint( hwnd
, &ps
);
2809 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
2810 (HMENU
)GetWindowLongA( hwnd
, 0 ) );
2811 EndPaint( hwnd
, &ps
);
2821 /* zero out global pointer in case resident popup window
2822 * was somehow destroyed. */
2824 if(MENU_GetTopPopupWnd() )
2826 if( hwnd
== pTopPopupWnd
->hwndSelf
)
2828 ERR(menu
, "resident popup destroyed!\n");
2830 MENU_DestroyTopPopupWnd();
2835 MENU_ReleaseTopPopupWnd();
2843 if( !(*(HMENU
*)wndPtr
->wExtra
) )
2844 ERR(menu
,"no menu to display\n");
2847 *(HMENU
*)wndPtr
->wExtra
= 0;
2850 case MM_SETMENUHANDLE
:
2852 *(HMENU
*)wndPtr
->wExtra
= (HMENU
)wParam
;
2855 case MM_GETMENUHANDLE
:
2857 retvalue
= *(HMENU
*)wndPtr
->wExtra
;
2861 retvalue
= DefWindowProcA( hwnd
, message
, wParam
, lParam
);
2866 WIN_ReleaseWndPtr(wndPtr
);
2871 /***********************************************************************
2872 * MENU_GetMenuBarHeight
2874 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
2876 UINT
MENU_GetMenuBarHeight( HWND hwnd
, UINT menubarWidth
,
2877 INT orgX
, INT orgY
)
2885 TRACE(menu
, "HWND 0x%x, width %d, "
2886 "at (%d, %d).\n", hwnd
, menubarWidth
, orgX
, orgY
);
2888 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
2889 if (!(lppop
= (LPPOPUPMENU
)USER_HEAP_LIN_ADDR((HMENU16
)wndPtr
->wIDmenu
)))
2891 WIN_ReleaseWndPtr(wndPtr
);
2894 hdc
= GetDCEx( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2895 SetRect(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+SYSMETRICS_CYMENU
);
2896 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
2897 ReleaseDC( hwnd
, hdc
);
2898 retvalue
= lppop
->Height
;
2899 WIN_ReleaseWndPtr(wndPtr
);
2904 /*******************************************************************
2905 * ChangeMenu16 (USER.153)
2907 BOOL16 WINAPI
ChangeMenu16( HMENU16 hMenu
, UINT16 pos
, SEGPTR data
,
2908 UINT16 id
, UINT16 flags
)
2910 TRACE(menu
,"menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
2911 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2912 if (flags
& MF_APPEND
) return AppendMenu16( hMenu
, flags
& ~MF_APPEND
,
2915 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
2916 /* for MF_DELETE. We should check the parameters for all others */
2917 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
2919 if (flags
& MF_DELETE
) return DeleteMenu16(hMenu
, pos
, flags
& ~MF_DELETE
);
2920 if (flags
& MF_CHANGE
) return ModifyMenu16(hMenu
, pos
, flags
& ~MF_CHANGE
,
2922 if (flags
& MF_REMOVE
) return RemoveMenu16(hMenu
,
2923 flags
& MF_BYPOSITION
? pos
: id
,
2924 flags
& ~MF_REMOVE
);
2925 /* Default: MF_INSERT */
2926 return InsertMenu16( hMenu
, pos
, flags
, id
, data
);
2930 /*******************************************************************
2931 * ChangeMenu32A (USER32.23)
2933 BOOL WINAPI
ChangeMenuA( HMENU hMenu
, UINT pos
, LPCSTR data
,
2934 UINT id
, UINT flags
)
2936 TRACE(menu
,"menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2937 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2938 if (flags
& MF_APPEND
) return AppendMenuA( hMenu
, flags
& ~MF_APPEND
,
2940 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
2941 if (flags
& MF_CHANGE
) return ModifyMenuA(hMenu
, pos
, flags
& ~MF_CHANGE
,
2943 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
2944 flags
& MF_BYPOSITION
? pos
: id
,
2945 flags
& ~MF_REMOVE
);
2946 /* Default: MF_INSERT */
2947 return InsertMenuA( hMenu
, pos
, flags
, id
, data
);
2951 /*******************************************************************
2952 * ChangeMenu32W (USER32.24)
2954 BOOL WINAPI
ChangeMenuW( HMENU hMenu
, UINT pos
, LPCWSTR data
,
2955 UINT id
, UINT flags
)
2957 TRACE(menu
,"menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2958 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2959 if (flags
& MF_APPEND
) return AppendMenuW( hMenu
, flags
& ~MF_APPEND
,
2961 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
2962 if (flags
& MF_CHANGE
) return ModifyMenuW(hMenu
, pos
, flags
& ~MF_CHANGE
,
2964 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
2965 flags
& MF_BYPOSITION
? pos
: id
,
2966 flags
& ~MF_REMOVE
);
2967 /* Default: MF_INSERT */
2968 return InsertMenuW( hMenu
, pos
, flags
, id
, data
);
2972 /*******************************************************************
2973 * CheckMenuItem16 (USER.154)
2975 BOOL16 WINAPI
CheckMenuItem16( HMENU16 hMenu
, UINT16 id
, UINT16 flags
)
2977 return (BOOL16
)CheckMenuItem( hMenu
, id
, flags
);
2981 /*******************************************************************
2982 * CheckMenuItem32 (USER32.46)
2984 DWORD WINAPI
CheckMenuItem( HMENU hMenu
, UINT id
, UINT flags
)
2989 TRACE(menu
,"%04x %04x %04x\n", hMenu
, id
, flags
);
2990 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
2991 ret
= item
->fState
& MF_CHECKED
;
2992 if (flags
& MF_CHECKED
) item
->fState
|= MF_CHECKED
;
2993 else item
->fState
&= ~MF_CHECKED
;
2998 /**********************************************************************
2999 * EnableMenuItem16 (USER.155)
3001 UINT16 WINAPI
EnableMenuItem16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3003 return EnableMenuItem( hMenu
, wItemID
, wFlags
);
3007 /**********************************************************************
3008 * EnableMenuItem32 (USER32.170)
3010 UINT WINAPI
EnableMenuItem( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3015 TRACE(menu
,"(%04x, %04X, %04X) !\n",
3016 hMenu
, wItemID
, wFlags
);
3018 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
)))
3021 oldflags
= item
->fState
& (MF_GRAYED
| MF_DISABLED
);
3022 item
->fState
^= (oldflags
^ wFlags
) & (MF_GRAYED
| MF_DISABLED
);
3027 /*******************************************************************
3028 * GetMenuString16 (USER.161)
3030 INT16 WINAPI
GetMenuString16( HMENU16 hMenu
, UINT16 wItemID
,
3031 LPSTR str
, INT16 nMaxSiz
, UINT16 wFlags
)
3033 return GetMenuStringA( hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3037 /*******************************************************************
3038 * GetMenuString32A (USER32.268)
3040 INT WINAPI
GetMenuStringA( HMENU hMenu
, UINT wItemID
,
3041 LPSTR str
, INT nMaxSiz
, UINT wFlags
)
3045 TRACE(menu
, "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3046 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3047 if (!str
|| !nMaxSiz
) return 0;
3049 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3050 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3051 lstrcpynA( str
, item
->text
, nMaxSiz
);
3052 TRACE(menu
, "returning '%s'\n", str
);
3057 /*******************************************************************
3058 * GetMenuString32W (USER32.269)
3060 INT WINAPI
GetMenuStringW( HMENU hMenu
, UINT wItemID
,
3061 LPWSTR str
, INT nMaxSiz
, UINT wFlags
)
3065 TRACE(menu
, "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3066 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3067 if (!str
|| !nMaxSiz
) return 0;
3069 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3070 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3071 lstrcpynAtoW( str
, item
->text
, nMaxSiz
);
3072 return lstrlenW(str
);
3076 /**********************************************************************
3077 * HiliteMenuItem16 (USER.162)
3079 BOOL16 WINAPI
HiliteMenuItem16( HWND16 hWnd
, HMENU16 hMenu
, UINT16 wItemID
,
3082 return HiliteMenuItem( hWnd
, hMenu
, wItemID
, wHilite
);
3086 /**********************************************************************
3087 * HiliteMenuItem32 (USER32.318)
3089 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
3093 TRACE(menu
,"(%04x, %04x, %04x, %04x);\n",
3094 hWnd
, hMenu
, wItemID
, wHilite
);
3095 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
3096 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
3097 if (menu
->FocusedItem
== wItemID
) return TRUE
;
3098 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
3099 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
);
3104 /**********************************************************************
3105 * GetMenuState16 (USER.250)
3107 UINT16 WINAPI
GetMenuState16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3109 return GetMenuState( hMenu
, wItemID
, wFlags
);
3113 /**********************************************************************
3114 * GetMenuState32 (USER32.267)
3116 UINT WINAPI
GetMenuState( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3119 TRACE(menu
,"(%04x, %04x, %04x);\n",
3120 hMenu
, wItemID
, wFlags
);
3121 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
3122 debug_print_menuitem (" item: ", item
, "");
3123 if (item
->fType
& MF_POPUP
)
3125 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( item
->hSubMenu
);
3126 if (!menu
) return -1;
3127 else return (menu
->nItems
<< 8) | ((item
->fState
|item
->fType
) & 0xff);
3131 /* We used to (from way back then) mask the result to 0xff. */
3132 /* I don't know why and it seems wrong as the documented */
3133 /* return flag MF_SEPARATOR is outside that mask. */
3134 return (item
->fType
| item
->fState
);
3139 /**********************************************************************
3140 * GetMenuItemCount16 (USER.263)
3142 INT16 WINAPI
GetMenuItemCount16( HMENU16 hMenu
)
3144 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3145 if (!IS_A_MENU(menu
)) return -1;
3146 TRACE(menu
,"(%04x) returning %d\n",
3147 hMenu
, menu
->nItems
);
3148 return menu
->nItems
;
3152 /**********************************************************************
3153 * GetMenuItemCount32 (USER32.262)
3155 INT WINAPI
GetMenuItemCount( HMENU hMenu
)
3157 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3158 if (!IS_A_MENU(menu
)) return -1;
3159 TRACE(menu
,"(%04x) returning %d\n",
3160 hMenu
, menu
->nItems
);
3161 return menu
->nItems
;
3165 /**********************************************************************
3166 * GetMenuItemID16 (USER.264)
3168 UINT16 WINAPI
GetMenuItemID16( HMENU16 hMenu
, INT16 nPos
)
3172 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
3173 if ((nPos
< 0) || ((UINT16
) nPos
>= menu
->nItems
)) return -1;
3174 if (menu
->items
[nPos
].fType
& MF_POPUP
) return -1;
3175 return menu
->items
[nPos
].wID
;
3179 /**********************************************************************
3180 * GetMenuItemID32 (USER32.263)
3182 UINT WINAPI
GetMenuItemID( HMENU hMenu
, INT nPos
)
3186 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
3187 if ((nPos
< 0) || (nPos
>= menu
->nItems
)) return -1;
3188 if (menu
->items
[nPos
].fType
& MF_POPUP
) return -1;
3189 return menu
->items
[nPos
].wID
;
3193 /*******************************************************************
3194 * InsertMenu16 (USER.410)
3196 BOOL16 WINAPI
InsertMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3197 UINT16 id
, SEGPTR data
)
3199 UINT pos32
= (UINT
)pos
;
3200 if ((pos
== (UINT16
)-1) && (flags
& MF_BYPOSITION
)) pos32
= (UINT
)-1;
3201 if (IS_STRING_ITEM(flags
) && data
)
3202 return InsertMenuA( hMenu
, pos32
, flags
, id
,
3203 (LPSTR
)PTR_SEG_TO_LIN(data
) );
3204 return InsertMenuA( hMenu
, pos32
, flags
, id
, (LPSTR
)data
);
3208 /*******************************************************************
3209 * InsertMenu32A (USER32.322)
3211 BOOL WINAPI
InsertMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3212 UINT id
, LPCSTR str
)
3216 if (IS_STRING_ITEM(flags
) && str
)
3217 TRACE(menu
, "hMenu %04x, pos %d, flags %08x, "
3218 "id %04x, str '%s'\n",
3219 hMenu
, pos
, flags
, id
, str
);
3220 else TRACE(menu
, "hMenu %04x, pos %d, flags %08x, "
3221 "id %04x, str %08lx (not a string)\n",
3222 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3224 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
3226 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
3228 RemoveMenu( hMenu
, pos
, flags
);
3232 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
3233 ((POPUPMENU
*)USER_HEAP_LIN_ADDR((HMENU16
)id
))->wFlags
|= MF_POPUP
;
3235 item
->hCheckBit
= item
->hUnCheckBit
= 0;
3240 /*******************************************************************
3241 * InsertMenu32W (USER32.325)
3243 BOOL WINAPI
InsertMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3244 UINT id
, LPCWSTR str
)
3248 if (IS_STRING_ITEM(flags
) && str
)
3250 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
3251 ret
= InsertMenuA( hMenu
, pos
, flags
, id
, newstr
);
3252 HeapFree( GetProcessHeap(), 0, newstr
);
3255 else return InsertMenuA( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
3259 /*******************************************************************
3260 * AppendMenu16 (USER.411)
3262 BOOL16 WINAPI
AppendMenu16(HMENU16 hMenu
, UINT16 flags
, UINT16 id
, SEGPTR data
)
3264 return InsertMenu16( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3268 /*******************************************************************
3269 * AppendMenu32A (USER32.5)
3271 BOOL WINAPI
AppendMenuA( HMENU hMenu
, UINT flags
,
3272 UINT id
, LPCSTR data
)
3274 return InsertMenuA( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3278 /*******************************************************************
3279 * AppendMenu32W (USER32.6)
3281 BOOL WINAPI
AppendMenuW( HMENU hMenu
, UINT flags
,
3282 UINT id
, LPCWSTR data
)
3284 return InsertMenuW( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3288 /**********************************************************************
3289 * RemoveMenu16 (USER.412)
3291 BOOL16 WINAPI
RemoveMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3293 return RemoveMenu( hMenu
, nPos
, wFlags
);
3297 /**********************************************************************
3298 * RemoveMenu32 (USER32.441)
3300 BOOL WINAPI
RemoveMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3305 TRACE(menu
,"(%04x, %04x, %04x)\n",hMenu
, nPos
, wFlags
);
3306 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3307 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
3311 MENU_FreeItemData( item
);
3313 if (--menu
->nItems
== 0)
3315 HeapFree( SystemHeap
, 0, menu
->items
);
3320 while(nPos
< menu
->nItems
)
3326 menu
->items
= HeapReAlloc( SystemHeap
, 0, menu
->items
,
3327 menu
->nItems
* sizeof(MENUITEM
) );
3333 /**********************************************************************
3334 * DeleteMenu16 (USER.413)
3336 BOOL16 WINAPI
DeleteMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3338 return DeleteMenu( hMenu
, nPos
, wFlags
);
3342 /**********************************************************************
3343 * DeleteMenu32 (USER32.129)
3345 BOOL WINAPI
DeleteMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3347 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
3348 if (!item
) return FALSE
;
3349 if (item
->fType
& MF_POPUP
) DestroyMenu( item
->hSubMenu
);
3350 /* nPos is now the position of the item */
3351 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
3356 /*******************************************************************
3357 * ModifyMenu16 (USER.414)
3359 BOOL16 WINAPI
ModifyMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3360 UINT16 id
, SEGPTR data
)
3362 if (IS_STRING_ITEM(flags
))
3363 return ModifyMenuA( hMenu
, pos
, flags
, id
,
3364 (LPSTR
)PTR_SEG_TO_LIN(data
) );
3365 return ModifyMenuA( hMenu
, pos
, flags
, id
, (LPSTR
)data
);
3369 /*******************************************************************
3370 * ModifyMenu32A (USER32.397)
3372 BOOL WINAPI
ModifyMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3373 UINT id
, LPCSTR str
)
3377 if (IS_STRING_ITEM(flags
))
3379 TRACE(menu
, "%04x %d %04x %04x '%s'\n",
3380 hMenu
, pos
, flags
, id
, str
? str
: "#NULL#" );
3381 if (!str
) return FALSE
;
3385 TRACE(menu
, "%04x %d %04x %04x %08lx\n",
3386 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3389 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
3390 return MENU_SetItemData( item
, flags
, id
, str
);
3394 /*******************************************************************
3395 * ModifyMenu32W (USER32.398)
3397 BOOL WINAPI
ModifyMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3398 UINT id
, LPCWSTR str
)
3402 if (IS_STRING_ITEM(flags
) && str
)
3404 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
3405 ret
= ModifyMenuA( hMenu
, pos
, flags
, id
, newstr
);
3406 HeapFree( GetProcessHeap(), 0, newstr
);
3409 else return ModifyMenuA( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
3413 /**********************************************************************
3414 * CreatePopupMenu16 (USER.415)
3416 HMENU16 WINAPI
CreatePopupMenu16(void)
3418 return CreatePopupMenu();
3422 /**********************************************************************
3423 * CreatePopupMenu32 (USER32.82)
3425 HMENU WINAPI
CreatePopupMenu(void)
3430 if (!(hmenu
= CreateMenu())) return 0;
3431 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
3432 menu
->wFlags
|= MF_POPUP
;
3437 /**********************************************************************
3438 * GetMenuCheckMarkDimensions (USER.417) (USER32.258)
3440 DWORD WINAPI
GetMenuCheckMarkDimensions(void)
3442 return MAKELONG( check_bitmap_width
, check_bitmap_height
);
3446 /**********************************************************************
3447 * SetMenuItemBitmaps16 (USER.418)
3449 BOOL16 WINAPI
SetMenuItemBitmaps16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
,
3450 HBITMAP16 hNewUnCheck
, HBITMAP16 hNewCheck
)
3452 return SetMenuItemBitmaps( hMenu
, nPos
, wFlags
, hNewUnCheck
, hNewCheck
);
3456 /**********************************************************************
3457 * SetMenuItemBitmaps32 (USER32.490)
3459 BOOL WINAPI
SetMenuItemBitmaps( HMENU hMenu
, UINT nPos
, UINT wFlags
,
3460 HBITMAP hNewUnCheck
, HBITMAP hNewCheck
)
3463 TRACE(menu
,"(%04x, %04x, %04x, %04x, %04x)\n",
3464 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
3465 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3467 if (!hNewCheck
&& !hNewUnCheck
)
3469 item
->fState
&= ~MF_USECHECKBITMAPS
;
3471 else /* Install new bitmaps */
3473 item
->hCheckBit
= hNewCheck
;
3474 item
->hUnCheckBit
= hNewUnCheck
;
3475 item
->fState
|= MF_USECHECKBITMAPS
;
3481 /**********************************************************************
3482 * CreateMenu16 (USER.151)
3484 HMENU16 WINAPI
CreateMenu16(void)
3486 return CreateMenu();
3490 /**********************************************************************
3491 * CreateMenu32 (USER32.81)
3493 HMENU WINAPI
CreateMenu(void)
3497 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) ))) return 0;
3498 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3500 menu
->wMagic
= MENU_MAGIC
;
3507 menu
->FocusedItem
= NO_SELECTED_ITEM
;
3508 TRACE(menu
, "return %04x\n", hMenu
);
3513 /**********************************************************************
3514 * DestroyMenu16 (USER.152)
3516 BOOL16 WINAPI
DestroyMenu16( HMENU16 hMenu
)
3518 return DestroyMenu( hMenu
);
3522 /**********************************************************************
3523 * DestroyMenu32 (USER32.134)
3525 BOOL WINAPI
DestroyMenu( HMENU hMenu
)
3527 TRACE(menu
,"(%04x)\n", hMenu
);
3529 /* Silently ignore attempts to destroy default system popup */
3531 if (hMenu
&& hMenu
!= MENU_DefSysPopup
)
3533 LPPOPUPMENU lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3534 WND
*pTPWnd
= MENU_GetTopPopupWnd();
3536 if( pTPWnd
&& (hMenu
== *(HMENU
*)pTPWnd
->wExtra
) )
3537 *(UINT
*)pTPWnd
->wExtra
= 0;
3539 if (IS_A_MENU( lppop
))
3541 lppop
->wMagic
= 0; /* Mark it as destroyed */
3543 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
&&
3544 (!pTPWnd
|| (lppop
->hWnd
!= pTPWnd
->hwndSelf
)))
3545 DestroyWindow( lppop
->hWnd
);
3547 MENU_ReleaseTopPopupWnd();
3549 if (lppop
->items
) /* recursively destroy submenus */
3552 MENUITEM
*item
= lppop
->items
;
3553 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
3555 if (item
->fType
& MF_POPUP
) DestroyMenu(item
->hSubMenu
);
3556 MENU_FreeItemData( item
);
3558 HeapFree( SystemHeap
, 0, lppop
->items
);
3560 USER_HEAP_FREE( hMenu
);
3564 return (hMenu
!= MENU_DefSysPopup
);
3568 /**********************************************************************
3569 * GetSystemMenu16 (USER.156)
3571 HMENU16 WINAPI
GetSystemMenu16( HWND16 hWnd
, BOOL16 bRevert
)
3573 return GetSystemMenu( hWnd
, bRevert
);
3577 /**********************************************************************
3578 * GetSystemMenu32 (USER32.291)
3580 HMENU WINAPI
GetSystemMenu( HWND hWnd
, BOOL bRevert
)
3582 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
3586 if( wndPtr
->hSysMenu
)
3590 DestroyMenu(wndPtr
->hSysMenu
);
3591 wndPtr
->hSysMenu
= 0;
3595 POPUPMENU
*menu
= (POPUPMENU
*)
3596 USER_HEAP_LIN_ADDR(wndPtr
->hSysMenu
);
3597 if( menu
->items
[0].hSubMenu
== MENU_DefSysPopup
)
3598 menu
->items
[0].hSubMenu
= MENU_CopySysPopup();
3602 if(!wndPtr
->hSysMenu
&& (wndPtr
->dwStyle
& WS_SYSMENU
) )
3603 wndPtr
->hSysMenu
= MENU_GetSysMenu( hWnd
, (HMENU
)(-1) );
3605 if( wndPtr
->hSysMenu
)
3607 HMENU retvalue
= GetSubMenu16(wndPtr
->hSysMenu
, 0);
3608 WIN_ReleaseWndPtr(wndPtr
);
3611 WIN_ReleaseWndPtr(wndPtr
);
3617 /*******************************************************************
3618 * SetSystemMenu16 (USER.280)
3620 BOOL16 WINAPI
SetSystemMenu16( HWND16 hwnd
, HMENU16 hMenu
)
3622 return SetSystemMenu( hwnd
, hMenu
);
3626 /*******************************************************************
3627 * SetSystemMenu32 (USER32.508)
3629 BOOL WINAPI
SetSystemMenu( HWND hwnd
, HMENU hMenu
)
3631 WND
*wndPtr
= WIN_FindWndPtr(hwnd
);
3635 if (wndPtr
->hSysMenu
) DestroyMenu( wndPtr
->hSysMenu
);
3636 wndPtr
->hSysMenu
= MENU_GetSysMenu( hwnd
, hMenu
);
3637 WIN_ReleaseWndPtr(wndPtr
);
3644 /**********************************************************************
3645 * GetMenu16 (USER.157)
3647 HMENU16 WINAPI
GetMenu16( HWND16 hWnd
)
3650 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
3651 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
3653 retvalue
= (HMENU16
)wndPtr
->wIDmenu
;
3658 WIN_ReleaseWndPtr(wndPtr
);
3663 /**********************************************************************
3664 * GetMenu32 (USER32.257)
3666 HMENU WINAPI
GetMenu( HWND hWnd
)
3669 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
3670 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
3672 retvalue
= (HMENU
)wndPtr
->wIDmenu
;
3677 WIN_ReleaseWndPtr(wndPtr
);
3682 /**********************************************************************
3683 * SetMenu16 (USER.158)
3685 BOOL16 WINAPI
SetMenu16( HWND16 hWnd
, HMENU16 hMenu
)
3687 return SetMenu( hWnd
, hMenu
);
3691 /**********************************************************************
3692 * SetMenu32 (USER32.487)
3694 BOOL WINAPI
SetMenu( HWND hWnd
, HMENU hMenu
)
3696 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
3698 TRACE(menu
,"(%04x, %04x);\n", hWnd
, hMenu
);
3700 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
3702 if (GetCapture() == hWnd
) ReleaseCapture();
3704 wndPtr
->wIDmenu
= (UINT
)hMenu
;
3709 if (!(lpmenu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
)))
3711 WIN_ReleaseWndPtr(wndPtr
);
3714 lpmenu
->hWnd
= hWnd
;
3715 lpmenu
->wFlags
&= ~MF_POPUP
; /* Can't be a popup */
3716 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
3718 if (IsWindowVisible(hWnd
))
3719 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3720 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3721 WIN_ReleaseWndPtr(wndPtr
);
3724 WIN_ReleaseWndPtr(wndPtr
);
3730 /**********************************************************************
3731 * GetSubMenu16 (USER.159)
3733 HMENU16 WINAPI
GetSubMenu16( HMENU16 hMenu
, INT16 nPos
)
3735 return GetSubMenu( hMenu
, nPos
);
3739 /**********************************************************************
3740 * GetSubMenu32 (USER32.288)
3742 HMENU WINAPI
GetSubMenu( HMENU hMenu
, INT nPos
)
3746 if (!(lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return 0;
3747 if ((UINT
)nPos
>= lppop
->nItems
) return 0;
3748 if (!(lppop
->items
[nPos
].fType
& MF_POPUP
)) return 0;
3749 return lppop
->items
[nPos
].hSubMenu
;
3753 /**********************************************************************
3754 * DrawMenuBar16 (USER.160)
3756 void WINAPI
DrawMenuBar16( HWND16 hWnd
)
3758 DrawMenuBar( hWnd
);
3762 /**********************************************************************
3763 * DrawMenuBar32 (USER32.161)
3765 BOOL WINAPI
DrawMenuBar( HWND hWnd
)
3768 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
3769 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
) && wndPtr
->wIDmenu
)
3771 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR((HMENU16
)wndPtr
->wIDmenu
);
3774 WIN_ReleaseWndPtr(wndPtr
);
3778 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
3779 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3780 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3781 WIN_ReleaseWndPtr(wndPtr
);
3784 WIN_ReleaseWndPtr(wndPtr
);
3789 /***********************************************************************
3790 * EndMenu (USER.187) (USER32.175)
3792 void WINAPI
EndMenu(void)
3798 /***********************************************************************
3799 * LookupMenuHandle (USER.217)
3801 HMENU16 WINAPI
LookupMenuHandle16( HMENU16 hmenu
, INT16 id
)
3803 HMENU hmenu32
= hmenu
;
3805 if (!MENU_FindItem( &hmenu32
, &id32
, MF_BYCOMMAND
)) return 0;
3806 else return hmenu32
;
3810 /**********************************************************************
3811 * LoadMenu16 (USER.150)
3813 HMENU16 WINAPI
LoadMenu16( HINSTANCE16 instance
, SEGPTR name
)
3821 char *str
= (char *)PTR_SEG_TO_LIN( name
);
3822 TRACE(menu
, "(%04x,'%s')\n", instance
, str
);
3823 if (str
[0] == '#') name
= (SEGPTR
)atoi( str
+ 1 );
3826 TRACE(resource
,"(%04x,%04x)\n",instance
,LOWORD(name
));
3828 if (!name
) return 0;
3830 /* check for Win32 module */
3831 if (HIWORD(instance
))
3832 return LoadMenuA(instance
,PTR_SEG_TO_LIN(name
));
3833 instance
= GetExePtr( instance
);
3835 if (!(hRsrc
= FindResource16( instance
, name
, RT_MENU16
))) return 0;
3836 if (!(handle
= LoadResource16( instance
, hRsrc
))) return 0;
3837 hMenu
= LoadMenuIndirect16(LockResource16(handle
));
3838 FreeResource16( handle
);
3843 /*****************************************************************
3844 * LoadMenu32A (USER32.370)
3846 HMENU WINAPI
LoadMenuA( HINSTANCE instance
, LPCSTR name
)
3848 HRSRC hrsrc
= FindResourceA( instance
, name
, RT_MENUA
);
3849 if (!hrsrc
) return 0;
3850 return LoadMenuIndirectA( (LPCVOID
)LoadResource( instance
, hrsrc
));
3854 /*****************************************************************
3855 * LoadMenu32W (USER32.373)
3857 HMENU WINAPI
LoadMenuW( HINSTANCE instance
, LPCWSTR name
)
3859 HRSRC hrsrc
= FindResourceW( instance
, name
, RT_MENUW
);
3860 if (!hrsrc
) return 0;
3861 return LoadMenuIndirectW( (LPCVOID
)LoadResource( instance
, hrsrc
));
3865 /**********************************************************************
3866 * LoadMenuIndirect16 (USER.220)
3868 HMENU16 WINAPI
LoadMenuIndirect16( LPCVOID
template )
3871 WORD version
, offset
;
3872 LPCSTR p
= (LPCSTR
)template;
3874 TRACE(menu
,"(%p)\n", template );
3875 version
= GET_WORD(p
);
3879 WARN(menu
, "version must be 0 for Win16\n" );
3882 offset
= GET_WORD(p
);
3883 p
+= sizeof(WORD
) + offset
;
3884 if (!(hMenu
= CreateMenu())) return 0;
3885 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
3887 DestroyMenu( hMenu
);
3894 /**********************************************************************
3895 * LoadMenuIndirect32A (USER32.371)
3897 HMENU WINAPI
LoadMenuIndirectA( LPCVOID
template )
3900 WORD version
, offset
;
3901 LPCSTR p
= (LPCSTR
)template;
3903 TRACE(menu
,"%p\n", template );
3904 version
= GET_WORD(p
);
3909 offset
= GET_WORD(p
);
3910 p
+= sizeof(WORD
) + offset
;
3911 if (!(hMenu
= CreateMenu())) return 0;
3912 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
3914 DestroyMenu( hMenu
);
3919 offset
= GET_WORD(p
);
3920 p
+= sizeof(WORD
) + offset
;
3921 if (!(hMenu
= CreateMenu())) return 0;
3922 if (!MENUEX_ParseResource( p
, hMenu
))
3924 DestroyMenu( hMenu
);
3929 ERR(menu
, "version %d not supported.\n", version
);
3935 /**********************************************************************
3936 * LoadMenuIndirect32W (USER32.372)
3938 HMENU WINAPI
LoadMenuIndirectW( LPCVOID
template )
3940 /* FIXME: is there anything different between A and W? */
3941 return LoadMenuIndirectA( template );
3945 /**********************************************************************
3946 * IsMenu16 (USER.358)
3948 BOOL16 WINAPI
IsMenu16( HMENU16 hmenu
)
3950 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
3951 return IS_A_MENU(menu
);
3955 /**********************************************************************
3956 * IsMenu32 (USER32.346)
3958 BOOL WINAPI
IsMenu(HMENU hmenu
)
3960 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
3961 return IS_A_MENU(menu
);
3964 /**********************************************************************
3965 * GetMenuItemInfo32_common
3968 static BOOL
GetMenuItemInfo_common ( HMENU hmenu
, UINT item
,
3970 LPMENUITEMINFOA lpmii
,
3973 MENUITEM
*menu
= MENU_FindItem (&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0);
3974 debug_print_menuitem("GetMenuItemInfo32_common: ", menu
, "");
3978 if (lpmii
->fMask
& MIIM_TYPE
) {
3979 lpmii
->fType
= menu
->fType
;
3980 switch (MENU_ITEM_TYPE(menu
->fType
)) {
3982 if (menu
->text
&& lpmii
->dwTypeData
&& lpmii
->cch
) {
3984 lstrcpynAtoW((LPWSTR
) lpmii
->dwTypeData
,
3988 lstrcpynA(lpmii
->dwTypeData
,
3995 lpmii
->dwTypeData
= menu
->text
;
4001 if (lpmii
->fMask
& MIIM_STATE
)
4002 lpmii
->fState
= menu
->fState
;
4004 if (lpmii
->fMask
& MIIM_ID
)
4005 lpmii
->wID
= menu
->wID
;
4007 if (lpmii
->fMask
& MIIM_SUBMENU
)
4008 lpmii
->hSubMenu
= menu
->hSubMenu
;
4010 if (lpmii
->fMask
& MIIM_CHECKMARKS
) {
4011 lpmii
->hbmpChecked
= menu
->hCheckBit
;
4012 lpmii
->hbmpUnchecked
= menu
->hUnCheckBit
;
4014 if (lpmii
->fMask
& MIIM_DATA
)
4015 lpmii
->dwItemData
= menu
->dwItemData
;
4020 /**********************************************************************
4021 * GetMenuItemInfo32A (USER32.264)
4023 BOOL WINAPI
GetMenuItemInfoA( HMENU hmenu
, UINT item
, BOOL bypos
,
4024 LPMENUITEMINFOA lpmii
)
4026 return GetMenuItemInfo_common (hmenu
, item
, bypos
, lpmii
, FALSE
);
4029 /**********************************************************************
4030 * GetMenuItemInfo32W (USER32.265)
4032 BOOL WINAPI
GetMenuItemInfoW( HMENU hmenu
, UINT item
, BOOL bypos
,
4033 LPMENUITEMINFOW lpmii
)
4035 return GetMenuItemInfo_common (hmenu
, item
, bypos
,
4036 (LPMENUITEMINFOA
)lpmii
, TRUE
);
4039 /**********************************************************************
4040 * SetMenuItemInfo32_common
4043 static BOOL
SetMenuItemInfo_common(MENUITEM
* menu
,
4044 const MENUITEMINFOA
*lpmii
,
4047 if (!menu
) return FALSE
;
4049 if (lpmii
->fMask
& MIIM_TYPE
) {
4050 /* Get rid of old string. */
4051 if (IS_STRING_ITEM(menu
->fType
) && menu
->text
)
4052 HeapFree(SystemHeap
, 0, menu
->text
);
4054 menu
->fType
= lpmii
->fType
;
4055 menu
->text
= lpmii
->dwTypeData
;
4056 if (IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4059 ? HEAP_strdupWtoA(SystemHeap
, 0,
4060 (LPWSTR
) lpmii
->dwTypeData
)
4061 : HEAP_strdupA(SystemHeap
, 0, lpmii
->dwTypeData
);
4064 if (lpmii
->fMask
& MIIM_STATE
)
4065 menu
->fState
= lpmii
->fState
;
4067 if (lpmii
->fMask
& MIIM_ID
)
4068 menu
->wID
= lpmii
->wID
;
4070 if (lpmii
->fMask
& MIIM_SUBMENU
) {
4071 menu
->hSubMenu
= lpmii
->hSubMenu
;
4072 if (menu
->hSubMenu
) {
4073 POPUPMENU
*subMenu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR((UINT16
)menu
->hSubMenu
);
4074 if (IS_A_MENU(subMenu
)) {
4075 subMenu
->wFlags
|= MF_POPUP
;
4076 menu
->fType
|= MF_POPUP
;
4079 /* FIXME: Return an error ? */
4080 menu
->fType
&= ~MF_POPUP
;
4083 menu
->fType
&= ~MF_POPUP
;
4086 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
4088 menu
->hCheckBit
= lpmii
->hbmpChecked
;
4089 menu
->hUnCheckBit
= lpmii
->hbmpUnchecked
;
4091 if (lpmii
->fMask
& MIIM_DATA
)
4092 menu
->dwItemData
= lpmii
->dwItemData
;
4094 debug_print_menuitem("SetMenuItemInfo32_common: ", menu
, "");
4098 /**********************************************************************
4099 * SetMenuItemInfo32A (USER32.491)
4101 BOOL WINAPI
SetMenuItemInfoA(HMENU hmenu
, UINT item
, BOOL bypos
,
4102 const MENUITEMINFOA
*lpmii
)
4104 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4108 /**********************************************************************
4109 * SetMenuItemInfo32W (USER32.492)
4111 BOOL WINAPI
SetMenuItemInfoW(HMENU hmenu
, UINT item
, BOOL bypos
,
4112 const MENUITEMINFOW
*lpmii
)
4114 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4115 (const MENUITEMINFOA
*)lpmii
, TRUE
);
4118 /**********************************************************************
4119 * SetMenuDefaultItem32 (USER32.489)
4121 BOOL WINAPI
SetMenuDefaultItem(HMENU hmenu
, UINT item
, UINT bypos
)
4123 MENUITEM
*menuitem
= MENU_FindItem(&hmenu
, &item
, bypos
);
4126 if (!menuitem
) return FALSE
;
4127 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hmenu
))) return FALSE
;
4129 menu
->defitem
= item
; /* position */
4131 debug_print_menuitem("SetMenuDefaultItem32: ", menuitem
, "");
4132 FIXME(menu
, "(0x%x,%d,%d), empty stub!\n",
4133 hmenu
, item
, bypos
);
4137 /**********************************************************************
4138 * GetMenuDefaultItem32 (USER32.260)
4140 UINT WINAPI
GetMenuDefaultItem(HMENU hmenu
, UINT bypos
, UINT flags
)
4144 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hmenu
)))
4147 FIXME(menu
, "(0x%x,%d,%d), stub!\n", hmenu
, bypos
, flags
);
4148 if (bypos
& MF_BYPOSITION
)
4149 return menu
->defitem
;
4151 FIXME (menu
, "default item 0x%x\n", menu
->defitem
);
4152 if ((menu
->defitem
> 0) && (menu
->defitem
< menu
->nItems
))
4153 return menu
->items
[menu
->defitem
].wID
;
4158 /*******************************************************************
4159 * InsertMenuItem16 (USER.441)
4163 BOOL16 WINAPI
InsertMenuItem16( HMENU16 hmenu
, UINT16 pos
, BOOL16 byposition
,
4164 const MENUITEMINFO16
*mii
)
4168 miia
.cbSize
= sizeof(miia
);
4169 miia
.fMask
= mii
->fMask
;
4170 miia
.dwTypeData
= mii
->dwTypeData
;
4171 miia
.fType
= mii
->fType
;
4172 miia
.fState
= mii
->fState
;
4173 miia
.wID
= mii
->wID
;
4174 miia
.hSubMenu
= mii
->hSubMenu
;
4175 miia
.hbmpChecked
= mii
->hbmpChecked
;
4176 miia
.hbmpUnchecked
= mii
->hbmpUnchecked
;
4177 miia
.dwItemData
= mii
->dwItemData
;
4178 miia
.cch
= mii
->cch
;
4179 if (IS_STRING_ITEM(miia
.fType
))
4180 miia
.dwTypeData
= PTR_SEG_TO_LIN(miia
.dwTypeData
);
4181 return InsertMenuItemA( hmenu
, pos
, byposition
, &miia
);
4185 /**********************************************************************
4186 * InsertMenuItem32A (USER32.323)
4188 BOOL WINAPI
InsertMenuItemA(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4189 const MENUITEMINFOA
*lpmii
)
4191 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4192 return SetMenuItemInfo_common(item
, lpmii
, FALSE
);
4196 /**********************************************************************
4197 * InsertMenuItem32W (USER32.324)
4199 BOOL WINAPI
InsertMenuItemW(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4200 const MENUITEMINFOW
*lpmii
)
4202 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4203 return SetMenuItemInfo_common(item
, (const MENUITEMINFOA
*)lpmii
, TRUE
);
4206 /**********************************************************************
4207 * CheckMenuRadioItem32 (USER32.47)
4210 BOOL WINAPI
CheckMenuRadioItem(HMENU hMenu
,
4211 UINT first
, UINT last
, UINT check
,
4214 MENUITEM
*mifirst
, *milast
, *micheck
;
4215 HMENU mfirst
= hMenu
, mlast
= hMenu
, mcheck
= hMenu
;
4217 TRACE(menu
, "ox%x: %d-%d, check %d, bypos=%d\n",
4218 hMenu
, first
, last
, check
, bypos
);
4220 mifirst
= MENU_FindItem (&mfirst
, &first
, bypos
);
4221 milast
= MENU_FindItem (&mlast
, &last
, bypos
);
4222 micheck
= MENU_FindItem (&mcheck
, &check
, bypos
);
4224 if (mifirst
== NULL
|| milast
== NULL
|| micheck
== NULL
||
4225 mifirst
> milast
|| mfirst
!= mlast
|| mfirst
!= mcheck
||
4226 micheck
> milast
|| micheck
< mifirst
)
4229 while (mifirst
<= milast
)
4231 if (mifirst
== micheck
)
4233 mifirst
->fType
|= MFT_RADIOCHECK
;
4234 mifirst
->fState
|= MFS_CHECKED
;
4236 mifirst
->fType
&= ~MFT_RADIOCHECK
;
4237 mifirst
->fState
&= ~MFS_CHECKED
;
4245 /**********************************************************************
4246 * CheckMenuRadioItem16 (not a Windows API)
4249 BOOL16 WINAPI
CheckMenuRadioItem16(HMENU16 hMenu
,
4250 UINT16 first
, UINT16 last
, UINT16 check
,
4253 return CheckMenuRadioItem (hMenu
, first
, last
, check
, bypos
);
4256 /**********************************************************************
4257 * GetMenuItemRect32 (USER32.266)
4259 * ATTENTION: Here, the returned values in rect are the screen
4260 * coordinates of the item just like if the menu was
4261 * always on the upper left side of the application.
4264 BOOL WINAPI
GetMenuItemRect (HWND hwnd
, HMENU hMenu
, UINT uItem
,
4267 POPUPMENU
*itemMenu
;
4271 TRACE(menu
, "(0x%x,0x%x,%d,%p)\n", hwnd
, hMenu
, uItem
, rect
);
4273 item
= MENU_FindItem (&hMenu
, &uItem
, MF_BYPOSITION
);
4274 referenceHwnd
= hwnd
;
4278 itemMenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
4279 if (itemMenu
== NULL
)
4282 if(itemMenu
->hWnd
== 0)
4284 referenceHwnd
= itemMenu
->hWnd
;
4287 if ((rect
== NULL
) || (item
== NULL
))
4292 MapWindowPoints(referenceHwnd
, 0, (LPPOINT
)rect
, 2);
4297 /**********************************************************************
4298 * GetMenuItemRect16 (USER.665)
4301 BOOL16 WINAPI
GetMenuItemRect16 (HWND16 hwnd
, HMENU16 hMenu
, UINT16 uItem
,
4307 if (!rect
) return FALSE
;
4308 res
= GetMenuItemRect (hwnd
, hMenu
, uItem
, &r32
);
4309 CONV_RECT32TO16 (&r32
, rect
);
4313 /**********************************************************************
4314 * SetMenuContextHelpId16 (USER.384)
4316 BOOL16 WINAPI
SetMenuContextHelpId16( HMENU16 hMenu
, DWORD dwContextHelpId
)
4318 return SetMenuContextHelpId( hMenu
, dwContextHelpId
);
4322 /**********************************************************************
4323 * SetMenuContextHelpId32 (USER32.488)
4325 BOOL WINAPI
SetMenuContextHelpId( HMENU hMenu
, DWORD dwContextHelpId
)
4327 FIXME(menu
, "SetMenuContextHelpId, stub\n");
4331 /**********************************************************************
4332 * GetMenuContextHelpId16 (USER.385)
4334 DWORD WINAPI
GetMenuContextHelpId16( HMENU16 hMenu
)
4336 return GetMenuContextHelpId16( hMenu
);
4339 /**********************************************************************
4340 * GetMenuContextHelpId32 (USER32.488)
4342 DWORD WINAPI
GetMenuContextHelpId( HMENU hMenu
)
4344 FIXME(menu
, "GetMenuContextHelpId, stub\n");