4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
9 * Note: the style MF_MOUSESELECT is used to mark popup items that
10 * have been selected, i.e. their popup menu is currently displayed.
11 * This is probably not the meaning this style has in MS-Windows.
23 #include "sysmetrics.h"
30 #include "nonclient.h"
40 UINT32 MENU_BarItemTopNudge
;
41 UINT32 MENU_BarItemLeftNudge
;
42 UINT32 MENU_ItemTopNudge
;
43 UINT32 MENU_ItemLeftNudge
;
44 UINT32 MENU_HighlightTopNudge
;
45 UINT32 MENU_HighlightLeftNudge
;
46 UINT32 MENU_HighlightBottomNudge
;
47 UINT32 MENU_HighlightRightNudge
;
49 /* internal popup menu window messages */
51 #define MM_SETMENUHANDLE (WM_USER + 0)
52 #define MM_GETMENUHANDLE (WM_USER + 1)
54 /* Menu item structure */
56 /* ----------- MENUITEMINFO Stuff ----------- */
57 UINT32 fType
; /* Item type. */
58 UINT32 fState
; /* Item state. */
59 UINT32 wID
; /* Item id. */
60 HMENU32 hSubMenu
; /* Pop-up menu. */
61 HBITMAP32 hCheckBit
; /* Bitmap when checked. */
62 HBITMAP32 hUnCheckBit
; /* Bitmap when unchecked. */
63 LPSTR text
; /* Item text or bitmap handle. */
64 DWORD dwItemData
; /* Application defined. */
65 /* ----------- Wine stuff ----------- */
66 RECT32 rect
; /* Item area (relative to menu window) */
67 UINT32 xTab
; /* X position of text after Tab */
70 /* Popup menu structure */
72 WORD wFlags
; /* Menu flags (MF_POPUP, MF_SYSMENU) */
73 WORD wMagic
; /* Magic number */
74 HQUEUE16 hTaskQ
; /* Task queue for this menu */
75 WORD Width
; /* Width of the whole menu */
76 WORD Height
; /* Height of the whole menu */
77 WORD nItems
; /* Number of items in the menu */
78 HWND32 hWnd
; /* Window containing the menu */
79 MENUITEM
*items
; /* Array of menu items */
80 UINT32 FocusedItem
; /* Currently focused item */
81 } POPUPMENU
, *LPPOPUPMENU
;
83 /* internal flags for menu tracking */
85 #define TF_ENDMENU 0x0001
86 #define TF_SUSPENDPOPUP 0x0002
87 #define TF_SKIPREMOVE 0x0004
92 HMENU32 hCurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
93 HMENU32 hTopMenu
; /* initial menu */
94 HWND32 hOwnerWnd
; /* where notifications are sent */
98 #define MENU_MAGIC 0x554d /* 'MU' */
99 #define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
104 /* Internal MENU_TrackMenu() flags */
105 #define TPM_INTERNAL 0xF0000000
106 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
107 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
109 /* popup menu shade thickness */
110 #define POPUP_XSHADE 4
111 #define POPUP_YSHADE 4
113 /* Space between 2 menu bar items */
114 #define MENU_BAR_ITEMS_SPACE 12
116 /* Minimum width of a tab character */
117 #define MENU_TAB_SPACE 8
119 /* Height of a separator item */
120 #define SEPARATOR_HEIGHT 5
122 /* (other menu->FocusedItem values give the position of the focused item) */
123 #define NO_SELECTED_ITEM 0xffff
125 #define MENU_ITEM_TYPE(flags) \
126 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
128 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
130 #define IS_SYSTEM_MENU(menu) \
131 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
132 #define IS_SYSTEM_POPUP(menu) \
133 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
135 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
136 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
137 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
138 MF_POPUP | MF_SYSMENU | MF_HELP)
139 #define STATE_MASK (~TYPE_MASK)
141 /* Dimension of the menu bitmaps */
142 static WORD check_bitmap_width
= 0, check_bitmap_height
= 0;
143 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
145 static HBITMAP32 hStdCheck
= 0;
146 static HBITMAP32 hStdMnArrow
= 0;
147 static HBRUSH32 hShadeBrush
= 0;
148 static HMENU32 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 UINT32 uSubPWndLevel
= 0;
156 /* Flag set by EndMenu() to force an exit from menu tracking */
157 static BOOL32 fEndMenu
= FALSE
;
160 /***********************************************************************
161 * debug_print_menuitem
163 * Print a menuitem in readable form.
166 #define MENUOUT(text) \
167 dprintf_menu (stddeb, "%s%s", (count++ ? "," : ""), (text))
169 #define MENUFLAG(bit,text) \
171 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
174 static void debug_print_menuitem(const char *prefix
, MENUITEM
* mp
, const char *postfix
)
176 dprintf_menu(stddeb
, "%s", prefix
);
178 UINT32 flags
= mp
->fType
;
179 int typ
= MENU_ITEM_TYPE(flags
);
180 dprintf_menu(stddeb
, "{ ID=0x%x", mp
->wID
);
181 if (flags
& MF_POPUP
)
182 dprintf_menu(stddeb
, ", Sub=0x%x", mp
->hSubMenu
);
185 dprintf_menu(stddeb
, ", Typ=");
186 if (typ
== MFT_STRING
)
188 else if (typ
== MFT_SEPARATOR
)
190 else if (typ
== MFT_OWNERDRAW
)
192 else if (typ
== MFT_BITMAP
)
198 MENUFLAG(MF_POPUP
, "pop");
199 MENUFLAG(MFT_MENUBARBREAK
, "barbrk");
200 MENUFLAG(MFT_MENUBREAK
, "brk");
201 MENUFLAG(MFT_RADIOCHECK
, "radio");
202 MENUFLAG(MFT_RIGHTORDER
, "rorder");
203 MENUFLAG(MF_SYSMENU
, "sys");
204 MENUFLAG(MFT_RIGHTJUSTIFY
, "right");
207 dprintf_menu(stddeb
, "+0x%x", flags
);
212 dprintf_menu(stddeb
, ", State=");
213 MENUFLAG(MFS_GRAYED
, "grey");
214 MENUFLAG(MFS_DISABLED
, "dis");
215 MENUFLAG(MFS_CHECKED
, "check");
216 MENUFLAG(MFS_HILITE
, "hi");
217 MENUFLAG(MF_USECHECKBITMAPS
, "usebit");
218 MENUFLAG(MF_MOUSESELECT
, "mouse");
220 dprintf_menu(stddeb
, "+0x%x", flags
);
223 dprintf_menu(stddeb
, ", Chk=0x%x", mp
->hCheckBit
);
225 dprintf_menu(stddeb
, ", Unc=0x%x", mp
->hUnCheckBit
);
227 if (typ
== MFT_STRING
) {
229 dprintf_menu(stddeb
, ", Text=\"%s\"", mp
->text
);
231 dprintf_menu(stddeb
, ", Text=Null");
232 } else if (mp
->text
== NULL
)
235 dprintf_menu(stddeb
, ", Text=%p", mp
->text
);
236 dprintf_menu(stddeb
, " }");
238 dprintf_menu(stddeb
, "NULL");
240 dprintf_menu(stddeb
, "%s", postfix
);
246 /***********************************************************************
249 * Return the default system menu.
251 static HMENU32
MENU_CopySysPopup(void)
253 HMENU32 hMenu
= LoadMenuIndirect32A(SYSRES_GetResPtr(SYSRES_MENU_SYSMENU
));
256 POPUPMENU
* menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
257 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
261 fprintf( stderr
, "Unable to load default system menu\n" );
264 dprintf_menu( stddeb
, "MENU_CopySysPopup: returning %x.\n", hMenu
);
270 /**********************************************************************
273 * Create a copy of the system menu. System menu in Windows is
274 * a special menu-bar with the single entry - system menu popup.
275 * This popup is presented to the outside world as a "system menu".
276 * However, the real system menu handle is sometimes seen in the
277 * WM_MENUSELECT paramemters (and Word 6 likes it this way).
279 HMENU32
MENU_GetSysMenu( HWND32 hWnd
, HMENU32 hPopupMenu
)
283 if ((hMenu
= CreateMenu32()))
285 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
286 menu
->wFlags
= MF_SYSMENU
;
289 if (hPopupMenu
== (HMENU32
)(-1))
290 hPopupMenu
= MENU_CopySysPopup();
291 else if( !hPopupMenu
) hPopupMenu
= MENU_DefSysPopup
;
295 InsertMenu32A( hMenu
, -1, MF_SYSMENU
| MF_POPUP
| MF_BYPOSITION
, hPopupMenu
, NULL
);
297 menu
->items
[0].fType
= MF_SYSMENU
| MF_POPUP
;
298 menu
->items
[0].fState
= 0;
299 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hPopupMenu
);
300 menu
->wFlags
|= MF_SYSMENU
;
302 dprintf_menu(stddeb
,"GetSysMenu hMenu=%04x (%04x)\n", hMenu
, hPopupMenu
);
305 DestroyMenu32( hMenu
);
307 fprintf(stderr
, "failed to load system menu!\n");
312 /***********************************************************************
315 * Menus initialisation.
319 /* Load menu bitmaps */
321 if ((hStdCheck
= LoadBitmap32A( 0, (LPSTR
)MAKEINTRESOURCE(OBM_CHECK
) )))
325 GetObject32A( hStdCheck
, sizeof(bm
), &bm
);
326 check_bitmap_width
= bm
.bmWidth
;
327 check_bitmap_height
= bm
.bmHeight
;
329 if ((hStdMnArrow
= LoadBitmap32A(0,(LPSTR
)MAKEINTRESOURCE(OBM_MNARROW
))))
332 static unsigned char shade_bits
[16] = { 0x55, 0, 0xAA, 0,
336 GetObject32A( hStdMnArrow
, sizeof(bm
), &bm
);
337 arrow_bitmap_width
= bm
.bmWidth
;
338 arrow_bitmap_height
= bm
.bmHeight
;
340 if((hBitmap
= CreateBitmap32( 8, 8, 1, 1, shade_bits
)))
342 if((hShadeBrush
= CreatePatternBrush32( hBitmap
)))
344 DeleteObject32( hBitmap
);
345 if((MENU_DefSysPopup
= MENU_CopySysPopup())) return TRUE
;
350 return FALSE
; /* failure */
353 /***********************************************************************
354 * MENU_InitSysMenuPopup
356 * Grey the appropriate items in System menu.
358 static void MENU_InitSysMenuPopup( HMENU32 hmenu
, DWORD style
, DWORD clsStyle
)
362 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
363 EnableMenuItem32( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
364 gray
= ((style
& WS_MAXIMIZE
) != 0);
365 EnableMenuItem32( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
366 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
367 EnableMenuItem32( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
368 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
369 EnableMenuItem32( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
370 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
371 EnableMenuItem32( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
372 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
373 EnableMenuItem32( hmenu
, SC_CLOSE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
377 /******************************************************************************
379 * UINT32 MENU_GetStartOfNextColumn(
382 *****************************************************************************/
384 static UINT32
MENU_GetStartOfNextColumn(
387 POPUPMENU
*menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
388 UINT32 i
= menu
->FocusedItem
+ 1;
391 return NO_SELECTED_ITEM
;
393 if( i
== NO_SELECTED_ITEM
)
396 for( ; i
< menu
->nItems
; ++i
) {
397 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
401 return NO_SELECTED_ITEM
;
405 /******************************************************************************
407 * UINT32 MENU_GetStartOfPrevColumn(
410 *****************************************************************************/
412 static UINT32
MENU_GetStartOfPrevColumn(
415 POPUPMENU
const *menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
419 return NO_SELECTED_ITEM
;
421 if( menu
->FocusedItem
== 0 || menu
->FocusedItem
== NO_SELECTED_ITEM
)
422 return NO_SELECTED_ITEM
;
424 /* Find the start of the column */
426 for(i
= menu
->FocusedItem
; i
!= 0 &&
427 !(menu
->items
[i
].fType
& MF_MENUBARBREAK
);
431 return NO_SELECTED_ITEM
;
433 for(--i
; i
!= 0; --i
) {
434 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
438 dprintf_menu( stddeb
, "MENU_GetStartOfPrevColumn: ret %d.\n", i
);
445 /***********************************************************************
448 * Find a menu item. Return a pointer on the item, and modifies *hmenu
449 * in case the item was in a sub-menu.
451 static MENUITEM
*MENU_FindItem( HMENU32
*hmenu
, UINT32
*nPos
, UINT32 wFlags
)
456 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(*hmenu
))) return NULL
;
457 if (wFlags
& MF_BYPOSITION
)
459 if (*nPos
>= menu
->nItems
) return NULL
;
460 return &menu
->items
[*nPos
];
464 MENUITEM
*item
= menu
->items
;
465 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
467 if (item
->wID
== *nPos
)
472 else if (item
->fType
& MF_POPUP
)
474 HMENU32 hsubmenu
= item
->hSubMenu
;
475 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
487 /***********************************************************************
490 static void MENU_FreeItemData( MENUITEM
* item
)
493 if (IS_STRING_ITEM(item
->fType
) && item
->text
)
494 HeapFree( SystemHeap
, 0, item
->text
);
497 /***********************************************************************
498 * MENU_FindItemByCoords
500 * Find the item at the specified coordinates (screen coords). Does
501 * not work for child windows and therefore should not be called for
502 * an arbitrary system menu.
504 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
,
505 POINT32 pt
, UINT32
*pos
)
511 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return NULL
;
512 pt
.x
-= wndPtr
->rectWindow
.left
;
513 pt
.y
-= wndPtr
->rectWindow
.top
;
515 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
517 if ((pt
.x
>= item
->rect
.left
) && (pt
.x
< item
->rect
.right
) &&
518 (pt
.y
>= item
->rect
.top
) && (pt
.y
< item
->rect
.bottom
))
528 /***********************************************************************
531 * Find the menu item selected by a key press.
532 * Return item id, -1 if none, -2 if we should close the menu.
534 static UINT32
MENU_FindItemByKey( HWND32 hwndOwner
, HMENU32 hmenu
,
535 UINT32 key
, BOOL32 forceMenuChar
)
537 dprintf_menu(stddeb
,"\tlooking for '%c' in [%04x]\n", (char)key
, (UINT16
)hmenu
);
539 if (!IsMenu32( hmenu
))
541 WND
* w
= WIN_FindWndPtr(hwndOwner
);
542 hmenu
= GetSubMenu32(w
->hSysMenu
, 0);
547 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
548 MENUITEM
*item
= menu
->items
;
556 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
558 if (IS_STRING_ITEM(item
->fType
))
560 char *p
= strchr( item
->text
, '&' );
561 if (p
&& (p
[1] != '&') && (toupper(p
[1]) == key
)) return i
;
565 menuchar
= SendMessage32A( hwndOwner
, WM_MENUCHAR
,
566 MAKEWPARAM( key
, menu
->wFlags
), hmenu
);
567 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
568 if (HIWORD(menuchar
) == 1) return (UINT32
)(-2);
574 /***********************************************************************
577 * Calculate the size of the menu item and store it in lpitem->rect.
579 static void MENU_CalcItemSize( HDC32 hdc
, MENUITEM
*lpitem
, HWND32 hwndOwner
,
580 INT32 orgX
, INT32 orgY
, BOOL32 menuBar
)
585 dprintf_menu(stddeb
, "MENU_CalcItemSize: HDC 0x%x at (%d,%d): ",
587 debug_print_menuitem("", lpitem
, (menuBar
? " (MenuBar)\n" : "\n"));
589 SetRect32( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
591 if (lpitem
->fType
& MF_OWNERDRAW
)
593 MEASUREITEMSTRUCT32 mis
;
594 mis
.CtlType
= ODT_MENU
;
595 mis
.itemID
= lpitem
->wID
;
596 mis
.itemData
= (DWORD
)lpitem
->text
;
599 SendMessage32A( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
600 lpitem
->rect
.bottom
+= mis
.itemHeight
;
601 lpitem
->rect
.right
+= mis
.itemWidth
;
602 dprintf_menu(stddeb
, "MENU_CalcItemSize: %08x %dx%d\n",
603 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
607 if (lpitem
->fType
& MF_SEPARATOR
)
609 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
615 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
616 if (lpitem
->fType
& MF_POPUP
)
617 lpitem
->rect
.right
+= arrow_bitmap_width
;
620 if (lpitem
->fType
& MF_BITMAP
)
623 if (GetObject32A( (HBITMAP32
)lpitem
->text
, sizeof(bm
), &bm
))
625 lpitem
->rect
.right
+= bm
.bmWidth
;
626 lpitem
->rect
.bottom
+= bm
.bmHeight
;
631 /* If we get here, then it must be a text item */
633 if (IS_STRING_ITEM( lpitem
->fType
))
635 dwSize
= GetTextExtent( hdc
, lpitem
->text
, strlen(lpitem
->text
) );
636 lpitem
->rect
.right
+= LOWORD(dwSize
);
637 lpitem
->rect
.bottom
+= MAX( HIWORD(dwSize
), SYSMETRICS_CYMENU
);
640 if (menuBar
) lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
641 else if ((p
= strchr( lpitem
->text
, '\t' )) != NULL
)
643 /* Item contains a tab (only meaningful in popup menus) */
644 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+
645 LOWORD( GetTextExtent( hdc
, lpitem
->text
,
646 (int)(p
- lpitem
->text
) ));
647 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
651 if (strchr( lpitem
->text
, '\b' ))
652 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
653 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
654 - arrow_bitmap_width
;
660 /***********************************************************************
661 * MENU_PopupMenuCalcSize
663 * Calculate the size of a popup menu.
665 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND32 hwndOwner
)
670 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
672 lppop
->Width
= lppop
->Height
= 0;
673 if (lppop
->nItems
== 0) return;
676 maxX
= SYSMETRICS_CXBORDER
;
677 while (start
< lppop
->nItems
)
679 lpitem
= &lppop
->items
[start
];
681 orgY
= SYSMETRICS_CYBORDER
;
682 maxTab
= maxTabWidth
= 0;
684 /* Parse items until column break or end of menu */
685 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
688 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
693 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
694 if (lpitem
->fType
& MF_MENUBARBREAK
) orgX
++;
695 maxX
= MAX( maxX
, lpitem
->rect
.right
);
696 orgY
= lpitem
->rect
.bottom
;
697 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
699 maxTab
= MAX( maxTab
, lpitem
->xTab
);
700 maxTabWidth
= MAX(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
704 /* Finish the column (set all items to the largest width found) */
705 maxX
= MAX( maxX
, maxTab
+ maxTabWidth
);
706 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
708 lpitem
->rect
.right
= maxX
;
709 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
710 lpitem
->xTab
= maxTab
;
712 lppop
->Height
= MAX( lppop
->Height
, orgY
);
716 ReleaseDC32( 0, hdc
);
720 /***********************************************************************
721 * MENU_MenuBarCalcSize
723 * FIXME: Word 6 implements it's own MDI and it's 'close window' bitmap
724 * height is off by 1 pixel which causes lengthy window relocations when
725 * active document window is maximized/restored.
727 * Calculate the size of the menu bar.
729 static void MENU_MenuBarCalcSize( HDC32 hdc
, LPRECT32 lprect
,
730 LPPOPUPMENU lppop
, HWND32 hwndOwner
)
733 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
735 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
736 if (lppop
->nItems
== 0) return;
737 dprintf_menu(stddeb
,"MENU_MenuBarCalcSize left=%d top=%d right=%d bottom=%d\n",
738 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
739 lppop
->Width
= lprect
->right
- lprect
->left
;
744 while (start
< lppop
->nItems
)
746 lpitem
= &lppop
->items
[start
];
750 /* Parse items until line break or end of menu */
751 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
753 if ((helpPos
== -1) && (lpitem
->fType
& MF_HELP
)) helpPos
= i
;
755 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
758 dprintf_menu( stddeb
, "MENU_MenuBarCalcSize: calling "
759 "MENU_CalcItemSize on item '%s', org=(%d, %d)\n",
760 lpitem
->text
, orgX
, orgY
);
761 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
762 if (lpitem
->rect
.right
> lprect
->right
)
764 if (i
!= start
) break;
765 else lpitem
->rect
.right
= lprect
->right
;
767 maxY
= MAX( maxY
, lpitem
->rect
.bottom
);
768 orgX
= lpitem
->rect
.right
;
771 /* Finish the line (set all items to the largest height found) */
772 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
775 lprect
->bottom
= maxY
;
776 lppop
->Height
= lprect
->bottom
- lprect
->top
;
778 /* Flush right all items between the MF_HELP and the last item */
779 /* (if several lines, only move the last line) */
782 lpitem
= &lppop
->items
[lppop
->nItems
-1];
783 orgY
= lpitem
->rect
.top
;
784 orgX
= lprect
->right
;
785 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--)
787 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
788 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
789 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
790 lpitem
->rect
.right
= orgX
;
791 orgX
= lpitem
->rect
.left
;
796 /***********************************************************************
799 * Draw a single menu item.
801 static void MENU_DrawMenuItem( HWND32 hwnd
, HDC32 hdc
, MENUITEM
*lpitem
,
802 UINT32 height
, BOOL32 menuBar
)
806 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem
, "\n");
808 if (lpitem
->fType
& MF_SYSMENU
)
810 if( !IsIconic32(hwnd
) ) {
812 NC_DrawSysButton95( hwnd
, hdc
,
814 (MF_HILITE
| MF_MOUSESELECT
) );
816 NC_DrawSysButton( hwnd
, hdc
,
818 (MF_HILITE
| MF_MOUSESELECT
) );
824 if (lpitem
->fType
& MF_OWNERDRAW
)
826 DRAWITEMSTRUCT32 dis
;
828 dprintf_menu( stddeb
, "DrawMenuItem: Ownerdraw!\n" );
829 dis
.CtlType
= ODT_MENU
;
830 dis
.itemID
= lpitem
->wID
;
831 dis
.itemData
= (DWORD
)lpitem
->text
;
833 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
834 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
;
835 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
836 dis
.itemAction
= ODA_DRAWENTIRE
| ODA_SELECT
| ODA_FOCUS
;
839 dis
.rcItem
= lpitem
->rect
;
840 SendMessage32A( hwnd
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
844 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
847 /* Draw the background */
848 if(TWEAK_Win95Look
) {
858 InflateRect32( &rect, -1, -1 );
862 if (lpitem
->fState
& MF_HILITE
) {
864 r
.top
+= MENU_HighlightTopNudge
;
865 r
.bottom
+= MENU_HighlightBottomNudge
;
866 r
.left
+= MENU_HighlightLeftNudge
;
867 r
.right
+= MENU_HighlightRightNudge
;
868 FillRect32( hdc
, &r
, sysColorObjects
.hbrushHighlight
);
872 r
.top
+= MENU_HighlightTopNudge
;
873 r
.bottom
+= MENU_HighlightBottomNudge
;
874 r
.left
+= MENU_HighlightLeftNudge
;
875 r
.right
+= MENU_HighlightRightNudge
;
876 FillRect32( hdc
, &r
, sysColorObjects
.hbrushMenu
);
879 SetBkMode32( hdc
, TRANSPARENT
);
881 /* Draw the separator bar (if any) */
883 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
886 TWEAK_DrawMenuSeparatorVert95(hdc
, rect
.left
- 1, 3, height
- 3);
888 SelectObject32( hdc
, sysColorObjects
.hpenWindowFrame
);
889 MoveTo( hdc
, rect
.left
, 0 );
890 LineTo32( hdc
, rect
.left
, height
);
893 if (lpitem
->fType
& MF_SEPARATOR
)
896 TWEAK_DrawMenuSeparatorHoriz95(hdc
, rect
.left
+ 1,
897 rect
.top
+ SEPARATOR_HEIGHT
/ 2 + 1,
900 SelectObject32( hdc
, sysColorObjects
.hpenWindowFrame
);
901 MoveTo( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
902 LineTo32( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
910 if (lpitem
->fState
& MF_HILITE
)
912 if (lpitem
->fState
& MF_GRAYED
)
913 SetTextColor32( hdc
, GetSysColor32( COLOR_GRAYTEXT
) );
915 SetTextColor32( hdc
, GetSysColor32( COLOR_HIGHLIGHTTEXT
) );
916 SetBkColor32( hdc
, GetSysColor32( COLOR_HIGHLIGHT
) );
920 if (lpitem
->fState
& MF_GRAYED
)
921 SetTextColor32( hdc
, GetSysColor32( COLOR_GRAYTEXT
) );
923 SetTextColor32( hdc
, GetSysColor32( COLOR_MENUTEXT
) );
924 SetBkColor32( hdc
, GetSysColor32( COLOR_MENU
) );
929 INT32 y
= rect
.top
+ rect
.bottom
;
931 /* Draw the check mark
933 * Custom checkmark bitmaps are monochrome but not always 1bpp.
934 * In this case we want GRAPH_DrawBitmap() to copy a plane which
935 * is 1 for a white pixel and 0 for a black one.
938 if (lpitem
->fState
& MF_CHECKED
)
939 GRAPH_DrawBitmap( hdc
, lpitem
->hCheckBit
? lpitem
->hCheckBit
940 : hStdCheck
, rect
.left
, (y
- check_bitmap_height
) / 2,
941 0, 0, check_bitmap_width
, check_bitmap_height
, TRUE
);
942 else if (lpitem
->hUnCheckBit
)
943 GRAPH_DrawBitmap( hdc
, lpitem
->hUnCheckBit
, rect
.left
,
944 (y
- check_bitmap_height
) / 2, 0, 0,
945 check_bitmap_width
, check_bitmap_height
, TRUE
);
947 /* Draw the popup-menu arrow */
949 if (lpitem
->fType
& MF_POPUP
)
951 GRAPH_DrawBitmap( hdc
, hStdMnArrow
,
952 rect
.right
-arrow_bitmap_width
-1,
953 (y
- arrow_bitmap_height
) / 2, 0, 0,
954 arrow_bitmap_width
, arrow_bitmap_height
, FALSE
);
957 rect
.left
+= check_bitmap_width
;
958 rect
.right
-= arrow_bitmap_width
;
961 /* Draw the item text or bitmap */
963 if (lpitem
->fType
& MF_BITMAP
)
965 GRAPH_DrawBitmap( hdc
, (HBITMAP32
)lpitem
->text
,
966 rect
.left
, rect
.top
, 0, 0,
967 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
, FALSE
);
970 /* No bitmap - process text if present */
971 else if (IS_STRING_ITEM(lpitem
->fType
))
977 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
978 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
979 i
= strlen( lpitem
->text
);
981 rect
.top
+= MENU_BarItemTopNudge
;
982 rect
.left
+= MENU_BarItemLeftNudge
;
986 for (i
= 0; lpitem
->text
[i
]; i
++)
987 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
990 rect
.top
+= MENU_ItemTopNudge
;
991 rect
.left
+= MENU_ItemLeftNudge
;
994 if(!TWEAK_Win95Look
|| !(lpitem
->fState
& MF_GRAYED
)) {
995 DrawText32A( hdc
, lpitem
->text
, i
, &rect
,
996 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
999 if (!(lpitem
->fState
& MF_HILITE
))
1005 SetTextColor32(hdc
, RGB(0xff, 0xff, 0xff));
1006 DrawText32A( hdc
, lpitem
->text
, i
, &rect
,
1007 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
1013 SetTextColor32(hdc
, RGB(0x80, 0x80, 0x80));
1014 DrawText32A( hdc
, lpitem
->text
, i
, &rect
,
1015 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
1018 if (lpitem
->text
[i
]) /* There's a tab or flush-right char */
1020 if (lpitem
->text
[i
] == '\t')
1022 rect
.left
= lpitem
->xTab
;
1023 DrawText32A( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
,
1024 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
1026 else DrawText32A( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
,
1027 DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
);
1033 /***********************************************************************
1034 * MENU_DrawPopupMenu
1036 * Paint a popup menu.
1038 static void MENU_DrawPopupMenu( HWND32 hwnd
, HDC32 hdc
, HMENU32 hmenu
)
1040 HBRUSH32 hPrevBrush
= 0;
1043 GetClientRect32( hwnd
, &rect
);
1045 /* if(!TWEAK_Win95Look) { */
1046 rect
.bottom
-= POPUP_YSHADE
* SYSMETRICS_CYBORDER
;
1047 rect
.right
-= POPUP_XSHADE
* SYSMETRICS_CXBORDER
;
1050 if((hPrevBrush
= SelectObject32( hdc
, sysColorObjects
.hbrushMenu
)))
1054 Rectangle32( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1056 hPrevPen
= SelectObject32( hdc
, GetStockObject32( NULL_PEN
) );
1062 /* draw 3-d shade */
1063 if(!TWEAK_Win95Look
) {
1064 SelectObject32( hdc
, hShadeBrush
);
1065 SetBkMode32( hdc
, TRANSPARENT
);
1066 ropPrev
= SetROP232( hdc
, R2_MASKPEN
);
1068 i
= rect
.right
; /* why SetBrushOrg() doesn't? */
1069 PatBlt32( hdc
, i
& 0xfffffffe,
1070 rect
.top
+ POPUP_YSHADE
*SYSMETRICS_CYBORDER
,
1071 i
%2 + POPUP_XSHADE
*SYSMETRICS_CXBORDER
,
1072 rect
.bottom
- rect
.top
, 0x00a000c9 );
1074 PatBlt32( hdc
, rect
.left
+ POPUP_XSHADE
*SYSMETRICS_CXBORDER
,
1075 i
& 0xfffffffe,rect
.right
- rect
.left
,
1076 i
%2 + POPUP_YSHADE
*SYSMETRICS_CYBORDER
, 0x00a000c9 );
1077 SelectObject32( hdc
, hPrevPen
);
1078 SelectObject32( hdc
, hPrevBrush
);
1079 SetROP232( hdc
, ropPrev
);
1082 TWEAK_DrawReliefRect95(hdc
, &rect
);
1084 /* draw menu items */
1086 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1087 if (menu
&& menu
->nItems
)
1092 for (u
= menu
->nItems
, item
= menu
->items
; u
> 0; u
--, item
++)
1093 MENU_DrawMenuItem( hwnd
, hdc
, item
, menu
->Height
, FALSE
);
1096 } else SelectObject32( hdc
, hPrevBrush
);
1101 /***********************************************************************
1104 * Paint a menu bar. Returns the height of the menu bar.
1106 UINT32
MENU_DrawMenuBar( HDC32 hDC
, LPRECT32 lprect
, HWND32 hwnd
,
1107 BOOL32 suppress_draw
)
1111 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1113 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( (HMENU16
)wndPtr
->wIDmenu
);
1114 if (lppop
== NULL
|| lprect
== NULL
) return SYSMETRICS_CYMENU
;
1115 dprintf_menu(stddeb
,"MENU_DrawMenuBar(%04x, %p, %p); !\n",
1116 hDC
, lprect
, lppop
);
1117 if (lppop
->Height
== 0) MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
1118 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
1119 if (suppress_draw
) return lppop
->Height
;
1124 FillRect32(hDC
, lprect
, sysColorObjects
.hbrushMenu
);
1126 if(!TWEAK_Win95Look
) {
1127 SelectObject32( hDC
, sysColorObjects
.hpenWindowFrame
);
1128 MoveTo( hDC
, lprect
->left
, lprect
->bottom
);
1129 LineTo32( hDC
, lprect
->right
, lprect
->bottom
);
1132 if (lppop
->nItems
== 0) return SYSMETRICS_CYMENU
;
1133 for (i
= 0; i
< lppop
->nItems
; i
++)
1135 MENU_DrawMenuItem( hwnd
, hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
);
1137 return lppop
->Height
;
1141 /***********************************************************************
1142 * MENU_PatchResidentPopup
1144 BOOL32
MENU_PatchResidentPopup( HQUEUE16 checkQueue
, WND
* checkWnd
)
1150 dprintf_menu(stddeb
,"patching resident popup: %04x %04x [%04x %04x]\n",
1151 checkQueue
, checkWnd
? checkWnd
->hwndSelf
: 0, pTopPopupWnd
->hmemTaskQ
,
1152 pTopPopupWnd
->owner
? pTopPopupWnd
->owner
->hwndSelf
: 0);
1154 switch( checkQueue
)
1156 case 0: /* checkWnd is the new popup owner */
1159 pTopPopupWnd
->owner
= checkWnd
;
1160 if( pTopPopupWnd
->hmemTaskQ
!= checkWnd
->hmemTaskQ
)
1161 hTask
= QUEUE_GetQueueTask( checkWnd
->hmemTaskQ
);
1165 case 0xFFFF: /* checkWnd is destroyed */
1166 if( pTopPopupWnd
->owner
== checkWnd
)
1167 pTopPopupWnd
->owner
= NULL
;
1170 default: /* checkQueue is exiting */
1171 if( pTopPopupWnd
->hmemTaskQ
== checkQueue
)
1173 hTask
= QUEUE_GetQueueTask( pTopPopupWnd
->hmemTaskQ
);
1174 hTask
= TASK_GetNextTask( hTask
);
1181 TDB
* task
= (TDB
*)GlobalLock16( hTask
);
1184 pTopPopupWnd
->hInstance
= task
->hInstance
;
1185 pTopPopupWnd
->hmemTaskQ
= task
->hQueue
;
1188 else dprintf_menu(stddeb
,"failed to patch resident popup.\n");
1194 /***********************************************************************
1197 * Display a popup menu.
1199 static BOOL32
MENU_ShowPopup( HWND32 hwndOwner
, HMENU32 hmenu
, UINT32 id
,
1200 INT32 x
, INT32 y
, INT32 xanchor
, INT32 yanchor
)
1203 WND
*wndOwner
= NULL
;
1205 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
1206 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1208 menu
->items
[menu
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1209 menu
->FocusedItem
= NO_SELECTED_ITEM
;
1212 SendMessage16( hwndOwner
, WM_INITMENUPOPUP
, (WPARAM16
)hmenu
,
1213 MAKELONG( id
, (menu
->wFlags
& MF_SYSMENU
) ? 1 : 0 ));
1215 if( (wndOwner
= WIN_FindWndPtr( hwndOwner
)) )
1217 UINT32 width
, height
;
1219 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
1221 /* adjust popup menu pos so that it fits within the desktop */
1223 width
= menu
->Width
+ SYSMETRICS_CXBORDER
;
1224 height
= menu
->Height
+ SYSMETRICS_CYBORDER
;
1226 if( x
+ width
> SYSMETRICS_CXSCREEN
)
1229 x
-= width
- xanchor
;
1230 if( x
+ width
> SYSMETRICS_CXSCREEN
)
1231 x
= SYSMETRICS_CXSCREEN
- width
;
1235 if( y
+ height
> SYSMETRICS_CYSCREEN
)
1238 y
-= height
+ yanchor
;
1239 if( y
+ height
> SYSMETRICS_CYSCREEN
)
1240 y
= SYSMETRICS_CYSCREEN
- height
;
1244 width
+= POPUP_XSHADE
* SYSMETRICS_CXBORDER
; /* add space for shading */
1245 height
+= POPUP_YSHADE
* SYSMETRICS_CYBORDER
;
1247 /* NOTE: In Windows, top menu popup is not owned. */
1248 if (!pTopPopupWnd
) /* create top level popup menu window */
1250 assert( uSubPWndLevel
== 0 );
1252 pTopPopupWnd
= WIN_FindWndPtr(CreateWindow32A( POPUPMENU_CLASS_ATOM
, NULL
,
1253 WS_POPUP
, x
, y
, width
, height
,
1254 hwndOwner
, 0, wndOwner
->hInstance
,
1256 if (!pTopPopupWnd
) return FALSE
;
1257 menu
->hWnd
= pTopPopupWnd
->hwndSelf
;
1262 /* create a new window for the submenu */
1264 menu
->hWnd
= CreateWindow32A( POPUPMENU_CLASS_ATOM
, NULL
,
1265 WS_POPUP
, x
, y
, width
, height
,
1266 menu
->hWnd
, 0, wndOwner
->hInstance
,
1268 if( !menu
->hWnd
) return FALSE
;
1270 else /* top level popup menu window already exists */
1272 menu
->hWnd
= pTopPopupWnd
->hwndSelf
;
1274 MENU_PatchResidentPopup( 0, wndOwner
);
1275 SendMessage16( pTopPopupWnd
->hwndSelf
, MM_SETMENUHANDLE
, (WPARAM16
)hmenu
, 0L);
1277 /* adjust its size */
1279 SetWindowPos32( menu
->hWnd
, 0, x
, y
, width
, height
,
1280 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_NOREDRAW
);
1283 uSubPWndLevel
++; /* menu level counter */
1285 /* Display the window */
1287 SetWindowPos32( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
1288 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1289 UpdateWindow32( menu
->hWnd
);
1296 /***********************************************************************
1299 static void MENU_SelectItem( HWND32 hwndOwner
, HMENU32 hmenu
, UINT32 wIndex
,
1300 BOOL32 sendMenuSelect
)
1305 lppop
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1306 if (!lppop
->nItems
) return;
1308 if ((wIndex
!= NO_SELECTED_ITEM
) &&
1309 (lppop
->items
[wIndex
].fType
& MF_SEPARATOR
))
1310 wIndex
= NO_SELECTED_ITEM
;
1312 if (lppop
->FocusedItem
== wIndex
) return;
1313 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC32( lppop
->hWnd
);
1314 else hdc
= GetDCEx32( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1316 /* Clear previous highlighted item */
1317 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1319 lppop
->items
[lppop
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1320 MENU_DrawMenuItem(lppop
->hWnd
,hdc
,&lppop
->items
[lppop
->FocusedItem
],
1321 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
) );
1324 /* Highlight new item (if any) */
1325 lppop
->FocusedItem
= wIndex
;
1326 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1328 lppop
->items
[lppop
->FocusedItem
].fState
|= MF_HILITE
;
1329 MENU_DrawMenuItem( lppop
->hWnd
, hdc
, &lppop
->items
[lppop
->FocusedItem
],
1330 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
) );
1333 MENUITEM
*ip
= &lppop
->items
[lppop
->FocusedItem
];
1334 SendMessage16( hwndOwner
, WM_MENUSELECT
, ip
->wID
,
1335 MAKELONG(ip
->fType
| (ip
->fState
| MF_MOUSESELECT
),
1339 else if (sendMenuSelect
)
1340 SendMessage16( hwndOwner
, WM_MENUSELECT
, hmenu
,
1341 MAKELONG( lppop
->wFlags
| MF_MOUSESELECT
, hmenu
) );
1343 ReleaseDC32( lppop
->hWnd
, hdc
);
1347 /***********************************************************************
1348 * MENU_MoveSelection
1350 * Moves currently selected item according to the offset parameter.
1351 * If there is no selection then it should select the last item if
1352 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1354 static void MENU_MoveSelection( HWND32 hwndOwner
, HMENU32 hmenu
, INT32 offset
)
1359 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1360 if (!menu
->items
) return;
1362 if ( menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1364 if( menu
->nItems
== 1 ) return; else
1365 for (i
= menu
->FocusedItem
+ offset
; i
>= 0 && i
< menu
->nItems
1367 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1369 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
1374 for ( i
= (offset
> 0) ? 0 : menu
->nItems
- 1;
1375 i
>= 0 && i
< menu
->nItems
; i
+= offset
)
1376 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1378 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
1384 /**********************************************************************
1387 * Set an item flags, id and text ptr. Called by InsertMenu() and
1390 static BOOL32
MENU_SetItemData( MENUITEM
*item
, UINT32 flags
, UINT32 id
,
1393 LPSTR prevText
= IS_STRING_ITEM(item
->fType
) ? item
->text
: NULL
;
1395 debug_print_menuitem("MENU_SetItemData from: ", item
, "\n");
1397 if (IS_STRING_ITEM(flags
))
1401 flags
|= MF_SEPARATOR
;
1407 /* Item beginning with a backspace is a help item */
1413 if (!(text
= HEAP_strdupA( SystemHeap
, 0, str
))) return FALSE
;
1417 else if (flags
& MF_BITMAP
) item
->text
= (LPSTR
)(HBITMAP32
)LOWORD(str
);
1418 else if (flags
& MF_OWNERDRAW
) item
->text
= (LPSTR
)str
;
1419 else item
->text
= NULL
;
1421 if (item
->fType
& MF_POPUP
&& item
->hSubMenu
!= id
)
1422 DestroyMenu32( item
->hSubMenu
); /* ModifyMenu() spec */
1424 if (flags
& MF_POPUP
)
1426 POPUPMENU
*menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR((UINT16
)id
);
1427 if (IS_A_MENU(menu
)) menu
->wFlags
|= MF_POPUP
;
1438 item
->fType
= flags
& TYPE_MASK
;
1439 item
->fState
= (flags
& STATE_MASK
) &
1440 ~(MF_HILITE
| MF_MOUSESELECT
| MF_BYPOSITION
);
1441 item
->wID
= item
->hSubMenu
= id
;
1443 SetRectEmpty32( &item
->rect
);
1444 if (prevText
) HeapFree( SystemHeap
, 0, prevText
);
1446 debug_print_menuitem("MENU_SetItemData to : ", item
, "\n");
1451 /**********************************************************************
1454 * Insert a new item into a menu.
1456 static MENUITEM
*MENU_InsertItem( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
)
1461 if (!(menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
)))
1463 dprintf_menu( stddeb
, "MENU_InsertItem: %04x not a menu handle\n",
1468 /* Find where to insert new item */
1470 if ((flags
& MF_BYPOSITION
) &&
1471 ((pos
== (UINT32
)-1) || (pos
== menu
->nItems
)))
1473 /* Special case: append to menu */
1474 /* Some programs specify the menu length to do that */
1479 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
1481 dprintf_menu( stddeb
, "MENU_InsertItem: item %x not found\n",
1485 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
)))
1487 dprintf_menu(stddeb
,"MENU_InsertItem: %04x not a menu handle\n",
1493 /* Create new items array */
1495 newItems
= HeapAlloc( SystemHeap
, 0, sizeof(MENUITEM
) * (menu
->nItems
+1) );
1498 dprintf_menu( stddeb
, "MENU_InsertItem: allocation failed\n" );
1501 if (menu
->nItems
> 0)
1503 /* Copy the old array into the new */
1504 if (pos
> 0) memcpy( newItems
, menu
->items
, pos
* sizeof(MENUITEM
) );
1505 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &menu
->items
[pos
],
1506 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
1507 HeapFree( SystemHeap
, 0, menu
->items
);
1509 menu
->items
= newItems
;
1511 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
1512 return &newItems
[pos
];
1516 /**********************************************************************
1517 * MENU_ParseResource
1519 * Parse a standard menu resource and add items to the menu.
1520 * Return a pointer to the end of the resource.
1522 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU32 hMenu
, BOOL32 unicode
)
1529 flags
= GET_WORD(res
);
1530 res
+= sizeof(WORD
);
1531 if (!(flags
& MF_POPUP
))
1534 res
+= sizeof(WORD
);
1536 if (!IS_STRING_ITEM(flags
))
1537 fprintf( stderr
, "MENU_ParseResource: not a string item %04x\n",
1540 if (!unicode
) res
+= strlen(str
) + 1;
1541 else res
+= (lstrlen32W((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1542 if (flags
& MF_POPUP
)
1544 HMENU32 hSubMenu
= CreatePopupMenu32();
1545 if (!hSubMenu
) return NULL
;
1546 if (!(res
= MENU_ParseResource( res
, hSubMenu
, unicode
)))
1548 if (!unicode
) AppendMenu32A( hMenu
, flags
, (UINT32
)hSubMenu
, str
);
1549 else AppendMenu32W( hMenu
, flags
, (UINT32
)hSubMenu
, (LPCWSTR
)str
);
1551 else /* Not a popup */
1553 if (!unicode
) AppendMenu32A( hMenu
, flags
, id
, *str
? str
: NULL
);
1554 else AppendMenu32W( hMenu
, flags
, id
,
1555 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1557 } while (!(flags
& MF_END
));
1562 /**********************************************************************
1563 * MENUEX_ParseResource
1565 * Parse an extended menu resource and add items to the menu.
1566 * Return a pointer to the end of the resource.
1568 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU32 hMenu
)
1572 MENUITEMINFO32W mii
;
1574 mii
.cbSize
= sizeof(mii
);
1575 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
1576 mii
.fType
= GET_DWORD(res
);
1577 res
+= sizeof(DWORD
);
1578 mii
.fState
= GET_DWORD(res
);
1579 res
+= sizeof(DWORD
);
1580 mii
.wID
= GET_DWORD(res
);
1581 res
+= sizeof(DWORD
);
1582 resinfo
= GET_WORD(res
); /* FIXME: for 16-bit apps this is a byte. */
1583 res
+= sizeof(WORD
);
1584 /* Align the text on a word boundary. */
1585 res
+= (~((int)res
- 1)) & 1;
1586 mii
.dwTypeData
= (LPWSTR
) res
;
1587 res
+= (1 + lstrlen32W(mii
.dwTypeData
)) * sizeof(WCHAR
);
1588 /* Align the following fields on a dword boundary. */
1589 res
+= (~((int)res
- 1)) & 3;
1591 /* FIXME: This is inefficient and cannot be optimised away by gcc. */
1593 LPSTR newstr
= HEAP_strdupWtoA(GetProcessHeap(),
1595 dprintf_menu(stddeb
, "Menu item: [%08x,%08x,%04x,%04x,%s]\n",
1596 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, newstr
);
1597 HeapFree( GetProcessHeap(), 0, newstr
);
1600 if (resinfo
& 1) { /* Pop-up? */
1601 DWORD helpid
= GET_DWORD(res
); /* FIXME: use this. */
1602 res
+= sizeof(DWORD
);
1603 mii
.hSubMenu
= CreatePopupMenu32();
1606 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
1607 DestroyMenu32(mii
.hSubMenu
);
1610 mii
.fMask
|= MIIM_SUBMENU
;
1611 mii
.fType
|= MF_POPUP
;
1613 InsertMenuItem32W(hMenu
, -1, MF_BYPOSITION
, &mii
);
1614 } while (!(resinfo
& MF_END
));
1619 /***********************************************************************
1622 * Return the handle of the selected sub-popup menu (if any).
1624 static HMENU32
MENU_GetSubPopup( HMENU32 hmenu
)
1629 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1631 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return 0;
1633 item
= &menu
->items
[menu
->FocusedItem
];
1634 if ((item
->fType
& MF_POPUP
) && (item
->fState
& MF_MOUSESELECT
))
1635 return item
->hSubMenu
;
1640 /***********************************************************************
1641 * MENU_HideSubPopups
1643 * Hide the sub-popup menus of this menu.
1645 static void MENU_HideSubPopups( HWND32 hwndOwner
, HMENU32 hmenu
,
1646 BOOL32 sendMenuSelect
)
1648 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);;
1650 if (menu
&& uSubPWndLevel
)
1656 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1658 item
= &menu
->items
[menu
->FocusedItem
];
1659 if (!(item
->fType
& MF_POPUP
) ||
1660 !(item
->fState
& MF_MOUSESELECT
)) return;
1661 item
->fState
&= ~MF_MOUSESELECT
;
1662 hsubmenu
= item
->hSubMenu
;
1665 submenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hsubmenu
);
1666 MENU_HideSubPopups( hwndOwner
, hsubmenu
, FALSE
);
1667 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, sendMenuSelect
);
1669 if (submenu
->hWnd
== pTopPopupWnd
->hwndSelf
)
1671 ShowWindow32( submenu
->hWnd
, SW_HIDE
);
1676 DestroyWindow32( submenu
->hWnd
);
1683 /***********************************************************************
1686 * Display the sub-menu of the selected item of this menu.
1687 * Return the handle of the submenu, or hmenu if no submenu to display.
1689 static HMENU32
MENU_ShowSubPopup( HWND32 hwndOwner
, HMENU32 hmenu
,
1690 BOOL32 selectFirst
)
1697 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return hmenu
;
1699 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
)) ||
1700 (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return hmenu
;
1702 item
= &menu
->items
[menu
->FocusedItem
];
1703 if (!(item
->fType
& MF_POPUP
) ||
1704 (item
->fState
& (MF_GRAYED
| MF_DISABLED
))) return hmenu
;
1705 item
->fState
|= MF_MOUSESELECT
;
1707 if (IS_SYSTEM_MENU(menu
))
1709 MENU_InitSysMenuPopup(item
->hSubMenu
, wndPtr
->dwStyle
, wndPtr
->class->style
);
1711 NC_GetSysPopupPos( wndPtr
, &rect
);
1712 rect
.top
= rect
.bottom
;
1713 rect
.right
= SYSMETRICS_CXSIZE
;
1714 rect
.bottom
= SYSMETRICS_CYSIZE
;
1718 if (menu
->wFlags
& MF_POPUP
)
1720 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.right
-arrow_bitmap_width
;
1721 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.top
;
1722 rect
.right
= item
->rect
.left
- item
->rect
.right
+ 2*arrow_bitmap_width
;
1723 rect
.bottom
= item
->rect
.top
- item
->rect
.bottom
;
1727 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.left
;
1728 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.bottom
;
1729 rect
.right
= item
->rect
.right
- item
->rect
.left
;
1730 rect
.bottom
= item
->rect
.bottom
- item
->rect
.top
;
1734 MENU_ShowPopup( hwndOwner
, item
->hSubMenu
, menu
->FocusedItem
,
1735 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1737 MENU_MoveSelection( hwndOwner
, item
->hSubMenu
, ITEM_NEXT
);
1738 return item
->hSubMenu
;
1741 /***********************************************************************
1744 * Walks menu chain trying to find a menu pt maps to.
1746 static HMENU32
MENU_PtMenu( HMENU32 hMenu
, POINT16 pt
)
1748 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hMenu
);
1749 register UINT32 ht
= menu
->FocusedItem
;
1751 /* try subpopup first (if any) */
1752 ht
= (ht
!= NO_SELECTED_ITEM
&&
1753 (menu
->items
[ht
].fType
& MF_POPUP
) &&
1754 (menu
->items
[ht
].fState
& MF_MOUSESELECT
))
1755 ? (UINT32
) MENU_PtMenu(menu
->items
[ht
].hSubMenu
, pt
) : 0;
1757 if( !ht
) /* check the current window (avoiding WM_HITTEST) */
1759 ht
= (UINT32
)NC_HandleNCHitTest( menu
->hWnd
, pt
);
1760 if( menu
->wFlags
& MF_POPUP
)
1761 ht
= (ht
!= (UINT32
)HTNOWHERE
&&
1762 ht
!= (UINT32
)HTERROR
) ? (UINT32
)hMenu
: 0;
1765 WND
* wndPtr
= WIN_FindWndPtr(menu
->hWnd
);
1767 ht
= ( ht
== HTSYSMENU
) ? (UINT32
)(wndPtr
->hSysMenu
)
1768 : ( ht
== HTMENU
) ? (UINT32
)(wndPtr
->wIDmenu
) : 0;
1774 /***********************************************************************
1775 * MENU_ExecFocusedItem
1777 * Execute a menu item (for instance when user pressed Enter).
1778 * Return TRUE if we can go on with menu tracking.
1780 static BOOL32
MENU_ExecFocusedItem( MTRACKER
* pmt
, HMENU32 hMenu
)
1783 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hMenu
);
1784 if (!menu
|| !menu
->nItems
||
1785 (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return TRUE
;
1787 item
= &menu
->items
[menu
->FocusedItem
];
1789 dprintf_menu(stddeb
, "MENU_ExecFocusedItem: %08x %08x %08x\n",
1790 hMenu
, item
->wID
, item
->hSubMenu
);
1792 if (!(item
->fType
& MF_POPUP
))
1794 if (!(item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
1796 if( menu
->wFlags
& MF_SYSMENU
)
1798 PostMessage16( pmt
->hOwnerWnd
, WM_SYSCOMMAND
, item
->hSubMenu
,
1799 MAKELPARAM((INT16
)pmt
->pt
.x
, (INT16
)pmt
->pt
.y
) );
1802 PostMessage16( pmt
->hOwnerWnd
, WM_COMMAND
, item
->wID
, 0 );
1809 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hMenu
, TRUE
);
1815 /***********************************************************************
1816 * MENU_SwitchTracking
1818 * Helper function for menu navigation routines.
1820 static void MENU_SwitchTracking( MTRACKER
* pmt
, HMENU32 hPtMenu
, UINT32 id
)
1822 POPUPMENU
*ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
1823 POPUPMENU
*topmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( pmt
->hTopMenu
);
1825 if( pmt
->hTopMenu
!= hPtMenu
&&
1826 !((ptmenu
->wFlags
| topmenu
->wFlags
) & MF_POPUP
) )
1828 /* both are top level menus (system and menu-bar) */
1830 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
1831 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
);
1832 pmt
->hTopMenu
= hPtMenu
;
1834 else MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
1835 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, id
, TRUE
);
1839 /***********************************************************************
1842 * Return TRUE if we can go on with menu tracking.
1844 static BOOL32
MENU_ButtonDown( MTRACKER
* pmt
, HMENU32 hPtMenu
)
1849 POPUPMENU
*ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
1852 if( IS_SYSTEM_MENU(ptmenu
) )
1853 item
= ptmenu
->items
;
1855 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
1859 if( ptmenu
->FocusedItem
== id
)
1861 /* nothing to do with already selected non-popup */
1862 if( !(item
->fType
& MF_POPUP
) ) return TRUE
;
1864 if( item
->fState
& MF_MOUSESELECT
)
1866 if( ptmenu
->wFlags
& MF_POPUP
)
1868 /* hide selected subpopup */
1870 MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, TRUE
);
1871 pmt
->hCurrentMenu
= hPtMenu
;
1874 return FALSE
; /* shouldn't get here */
1877 else MENU_SwitchTracking( pmt
, hPtMenu
, id
);
1879 /* try to display a subpopup */
1881 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
1884 else dprintf_menu(stddeb
,"\tunable to find clicked item!\n");
1889 /***********************************************************************
1892 * Return TRUE if we can go on with menu tracking.
1894 static BOOL32
MENU_ButtonUp( MTRACKER
* pmt
, HMENU32 hPtMenu
)
1899 POPUPMENU
*ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
1902 if( IS_SYSTEM_MENU(ptmenu
) )
1903 item
= ptmenu
->items
;
1905 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
1907 if( ptmenu
->FocusedItem
== id
)
1909 if( !(item
->fType
& MF_POPUP
) )
1910 return MENU_ExecFocusedItem( pmt
, hPtMenu
);
1911 hPtMenu
= item
->hSubMenu
;
1912 if( hPtMenu
== pmt
->hCurrentMenu
)
1914 /* Select first item of sub-popup */
1916 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, NO_SELECTED_ITEM
, FALSE
);
1917 MENU_MoveSelection( pmt
->hOwnerWnd
, hPtMenu
, ITEM_NEXT
);
1926 /***********************************************************************
1929 * Return TRUE if we can go on with menu tracking.
1931 static BOOL32
MENU_MouseMove( MTRACKER
* pmt
, HMENU32 hPtMenu
)
1933 UINT32 id
= NO_SELECTED_ITEM
;
1934 POPUPMENU
*ptmenu
= NULL
;
1938 ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
1939 if( IS_SYSTEM_MENU(ptmenu
) )
1942 MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
1945 if( id
== NO_SELECTED_ITEM
)
1947 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
1948 NO_SELECTED_ITEM
, TRUE
);
1950 else if( ptmenu
->FocusedItem
!= id
)
1952 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
1953 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
1959 /***********************************************************************
1962 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
1964 static LRESULT
MENU_DoNextMenu( MTRACKER
* pmt
, UINT32 vk
)
1966 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( pmt
->hTopMenu
);
1968 if( (vk
== VK_LEFT
&& menu
->FocusedItem
== 0 ) ||
1969 (vk
== VK_RIGHT
&& menu
->FocusedItem
== menu
->nItems
- 1))
1975 LRESULT l
= SendMessage16( pmt
->hOwnerWnd
, WM_NEXTMENU
, (WPARAM16
)vk
,
1976 (IS_SYSTEM_MENU(menu
)) ? GetSubMenu16(pmt
->hTopMenu
,0) : pmt
->hTopMenu
);
1978 dprintf_menu(stddeb
,"NextMenu: %04x [%04x] -> %04x [%04x]\n",
1979 (UINT16
)pmt
->hCurrentMenu
, (UINT16
)pmt
->hOwnerWnd
, LOWORD(l
), HIWORD(l
) );
1983 wndPtr
= WIN_FindWndPtr(pmt
->hOwnerWnd
);
1985 hNewWnd
= pmt
->hOwnerWnd
;
1986 if( IS_SYSTEM_MENU(menu
) )
1988 /* switch to the menu bar */
1990 if( wndPtr
->dwStyle
& WS_CHILD
|| !wndPtr
->wIDmenu
)
1993 hNewMenu
= wndPtr
->wIDmenu
;
1996 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hNewMenu
);
1997 id
= menu
->nItems
- 1;
2000 else if( wndPtr
->dwStyle
& WS_SYSMENU
)
2002 /* switch to the system menu */
2003 hNewMenu
= wndPtr
->hSysMenu
;
2007 else /* application returned a new menu to switch to */
2009 hNewMenu
= LOWORD(l
); hNewWnd
= HIWORD(l
);
2011 if( IsMenu32(hNewMenu
) && IsWindow32(hNewWnd
) )
2013 wndPtr
= WIN_FindWndPtr(hNewWnd
);
2015 if( wndPtr
->dwStyle
& WS_SYSMENU
&&
2016 GetSubMenu16(wndPtr
->hSysMenu
, 0) == hNewMenu
)
2018 /* get the real system menu */
2019 hNewMenu
= wndPtr
->hSysMenu
;
2021 else if( wndPtr
->dwStyle
& WS_CHILD
|| wndPtr
->wIDmenu
!= hNewMenu
)
2023 /* FIXME: Not sure what to do here, perhaps,
2024 * try to track hNewMenu as a popup? */
2026 dprintf_menu(stddeb
,"MENU_DoNextMenu() got confused.\n");
2033 if( hNewMenu
!= pmt
->hTopMenu
)
2035 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
);
2036 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2037 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2040 if( hNewWnd
!= pmt
->hOwnerWnd
)
2043 pmt
->hOwnerWnd
= hNewWnd
;
2044 EVENT_Capture( pmt
->hOwnerWnd
, HTMENU
);
2047 pmt
->hTopMenu
= pmt
->hCurrentMenu
= hNewMenu
; /* all subpopups are hidden */
2048 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, id
, TRUE
);
2055 /***********************************************************************
2058 * The idea is not to show the popup if the next input message is
2059 * going to hide it anyway.
2061 static BOOL32
MENU_SuspendPopup( MTRACKER
* pmt
, UINT16 uMsg
)
2065 msg
.hwnd
= pmt
->hOwnerWnd
;
2067 PeekMessage16( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2068 pmt
->trackFlags
|= TF_SKIPREMOVE
;
2073 PeekMessage16( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2074 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
2076 PeekMessage16( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2077 PeekMessage16( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2078 if( msg
.message
== WM_KEYDOWN
&&
2079 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
2081 pmt
->trackFlags
|= TF_SUSPENDPOPUP
;
2088 /* failures go through this */
2089 pmt
->trackFlags
&= ~TF_SUSPENDPOPUP
;
2093 /***********************************************************************
2096 * Handle a VK_LEFT key event in a menu.
2098 static void MENU_KeyLeft( MTRACKER
* pmt
)
2101 HMENU32 hmenutmp
, hmenuprev
;
2104 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
2105 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenutmp
);
2107 /* Try to move 1 column left (if possible) */
2108 if( (prevcol
= MENU_GetStartOfPrevColumn( pmt
->hCurrentMenu
)) !=
2109 NO_SELECTED_ITEM
) {
2111 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2116 /* close topmost popup */
2117 while (hmenutmp
!= pmt
->hCurrentMenu
)
2119 hmenuprev
= hmenutmp
;
2120 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
2123 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
);
2124 pmt
->hCurrentMenu
= hmenuprev
;
2126 if ( (hmenuprev
== pmt
->hTopMenu
) && !(menu
->wFlags
& MF_POPUP
) )
2128 /* move menu bar selection if no more popups are left */
2130 if( !MENU_DoNextMenu( pmt
, VK_LEFT
) )
2131 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_PREV
);
2133 if ( hmenuprev
!= hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2135 /* A sublevel menu was displayed - display the next one
2136 * unless there is another displacement coming up */
2138 if( !MENU_SuspendPopup( pmt
, WM_KEYDOWN
) )
2139 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
,
2140 pmt
->hTopMenu
, TRUE
);
2146 /***********************************************************************
2149 * Handle a VK_RIGHT key event in a menu.
2151 static void MENU_KeyRight( MTRACKER
* pmt
)
2154 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( pmt
->hTopMenu
);
2157 dprintf_menu( stddeb
, "MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2159 ((POPUPMENU
*)USER_HEAP_LIN_ADDR(pmt
->hCurrentMenu
))->
2161 pmt
->hTopMenu
, menu
->items
[0].text
);
2163 if ( (menu
->wFlags
& MF_POPUP
) || (pmt
->hCurrentMenu
!= pmt
->hTopMenu
))
2165 /* If already displaying a popup, try to display sub-popup */
2167 hmenutmp
= pmt
->hCurrentMenu
;
2168 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hmenutmp
, TRUE
);
2170 /* if subpopup was displayed then we are done */
2171 if (hmenutmp
!= pmt
->hCurrentMenu
) return;
2174 /* Check to see if there's another column */
2175 if( (nextcol
= MENU_GetStartOfNextColumn( pmt
->hCurrentMenu
)) !=
2176 NO_SELECTED_ITEM
) {
2177 dprintf_menu( stddeb
, "KeyRight: Going to %d.\n", nextcol
);
2178 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2183 if (!(menu
->wFlags
& MF_POPUP
)) /* menu bar tracking */
2185 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2187 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2188 hmenutmp
= pmt
->hCurrentMenu
= pmt
->hTopMenu
;
2189 } else hmenutmp
= 0;
2191 /* try to move to the next item */
2192 if( !MENU_DoNextMenu( pmt
, VK_RIGHT
) )
2193 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_NEXT
);
2195 if( hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2196 if( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
2197 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
,
2198 pmt
->hTopMenu
, TRUE
);
2203 /***********************************************************************
2206 * Menu tracking code.
2208 static BOOL32
MENU_TrackMenu( HMENU32 hmenu
, UINT32 wFlags
, INT32 x
, INT32 y
,
2209 HWND32 hwnd
, const RECT32
*lprect
)
2214 MTRACKER mt
= { 0, hmenu
, hmenu
, hwnd
, {x
, y
} }; /* control struct */
2217 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
2219 if (wFlags
& TPM_BUTTONDOWN
) MENU_ButtonDown( &mt
, hmenu
);
2221 EVENT_Capture( mt
.hOwnerWnd
, HTMENU
);
2225 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( mt
.hCurrentMenu
);
2226 msg
.hwnd
= (wFlags
& TPM_ENTERIDLEEX
&& menu
->wFlags
& MF_POPUP
) ? menu
->hWnd
: 0;
2228 /* we have to keep the message in the queue until it's
2229 * clear that menu loop is not over yet. */
2231 if (!MSG_InternalGetMessage( &msg
, msg
.hwnd
, mt
.hOwnerWnd
,
2232 MSGF_MENU
, PM_NOREMOVE
, TRUE
)) break;
2234 TranslateMessage16( &msg
);
2235 CONV_POINT16TO32( &msg
.pt
, &mt
.pt
);
2238 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
2240 /* Find a menu for this mouse event */
2242 hmenu
= MENU_PtMenu( mt
.hTopMenu
, msg
.pt
);
2246 /* no WM_NC... messages in captured state */
2248 case WM_RBUTTONDBLCLK
:
2249 case WM_RBUTTONDOWN
:
2250 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2252 case WM_LBUTTONDBLCLK
:
2253 case WM_LBUTTONDOWN
:
2254 fEndMenu
|= !MENU_ButtonDown( &mt
, hmenu
);
2258 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2261 /* If outside all menus but inside lprect, ignore it */
2262 if (hmenu
|| !lprect
|| !PtInRect32(lprect
, mt
.pt
))
2264 fEndMenu
|= !MENU_ButtonUp( &mt
, hmenu
);
2270 if ((msg
.wParam
& MK_LBUTTON
) || ((wFlags
& TPM_RIGHTBUTTON
)
2271 && (msg
.wParam
& MK_RBUTTON
)))
2273 fEndMenu
|= !MENU_MouseMove( &mt
, hmenu
);
2275 } /* switch(msg.message) - mouse */
2277 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
2279 fRemove
= TRUE
; /* Keyboard messages are always removed */
2287 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2288 NO_SELECTED_ITEM
, FALSE
);
2291 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2292 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
2295 case VK_DOWN
: /* If on menu bar, pull-down the menu */
2297 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( mt
.hCurrentMenu
);
2298 if (!(menu
->wFlags
& MF_POPUP
))
2299 mt
.hCurrentMenu
= MENU_ShowSubPopup( mt
.hOwnerWnd
, mt
.hTopMenu
, TRUE
);
2300 else /* otherwise try to move selection */
2301 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
, ITEM_NEXT
);
2305 MENU_KeyLeft( &mt
);
2309 MENU_KeyRight( &mt
);
2314 fEndMenu
|= !MENU_ExecFocusedItem( &mt
, mt
.hCurrentMenu
);
2324 break; /* WM_KEYDOWN */
2334 break; /* WM_SYSKEYDOWN */
2340 /* Hack to avoid control chars. */
2341 /* We will find a better way real soon... */
2342 if ((msg
.wParam
<= 32) || (msg
.wParam
>= 127)) break;
2344 pos
= MENU_FindItemByKey( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2345 msg
.wParam
, FALSE
);
2346 if (pos
== (UINT32
)-2) fEndMenu
= TRUE
;
2347 else if (pos
== (UINT32
)-1) MessageBeep32(0);
2350 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
, pos
, TRUE
);
2351 fEndMenu
|= !MENU_ExecFocusedItem( &mt
, mt
.hCurrentMenu
);
2355 } /* switch(msg.message) - kbd */
2359 DispatchMessage16( &msg
);
2362 if (!fEndMenu
) fRemove
= TRUE
;
2364 /* finally remove message from the queue */
2366 if (fRemove
&& !(mt
.trackFlags
& TF_SKIPREMOVE
) )
2367 PeekMessage16( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2368 else mt
.trackFlags
&= ~TF_SKIPREMOVE
;
2372 if( IsWindow32( mt
.hOwnerWnd
) )
2374 MENU_HideSubPopups( mt
.hOwnerWnd
, mt
.hTopMenu
, FALSE
);
2376 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( mt
.hTopMenu
);
2377 if (menu
&& menu
->wFlags
& MF_POPUP
)
2379 ShowWindow32( menu
->hWnd
, SW_HIDE
);
2382 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hTopMenu
, NO_SELECTED_ITEM
, FALSE
);
2383 SendMessage16( mt
.hOwnerWnd
, WM_MENUSELECT
, 0, MAKELONG( 0xffff, 0 ) );
2389 /***********************************************************************
2392 static BOOL32
MENU_InitTracking(HWND32 hWnd
, HMENU32 hMenu
)
2395 SendMessage16( hWnd
, WM_ENTERMENULOOP
, 0, 0 );
2396 SendMessage16( hWnd
, WM_SETCURSOR
, hWnd
, HTCAPTION
);
2397 SendMessage16( hWnd
, WM_INITMENU
, hMenu
, 0 );
2401 /***********************************************************************
2402 * MENU_TrackMouseMenuBar
2404 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2406 void MENU_TrackMouseMenuBar( WND
* wndPtr
, INT32 ht
, POINT32 pt
)
2408 HWND32 hWnd
= wndPtr
->hwndSelf
;
2409 HMENU32 hMenu
= (ht
== HTSYSMENU
) ? wndPtr
->hSysMenu
: wndPtr
->wIDmenu
;
2411 if (IsMenu32(hMenu
))
2413 MENU_InitTracking( hWnd
, hMenu
);
2414 MENU_TrackMenu( hMenu
, TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
|
2415 TPM_LEFTALIGN
| TPM_LEFTBUTTON
, pt
.x
, pt
.y
, hWnd
, NULL
);
2417 SendMessage16( hWnd
, WM_EXITMENULOOP
, 0, 0 );
2423 /***********************************************************************
2424 * MENU_TrackKbdMenuBar
2426 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
2428 void MENU_TrackKbdMenuBar( WND
* wndPtr
, UINT32 wParam
, INT32 vkey
)
2430 UINT32 uItem
= NO_SELECTED_ITEM
;
2433 /* find window that has a menu */
2435 while( wndPtr
->dwStyle
& WS_CHILD
&& !(wndPtr
->dwStyle
& WS_SYSMENU
) )
2436 if( !(wndPtr
= wndPtr
->parent
) ) return;
2438 /* check if we have to track a system menu */
2440 if( (wndPtr
->dwStyle
& (WS_CHILD
| WS_MINIMIZE
)) ||
2441 !wndPtr
->wIDmenu
|| vkey
== VK_SPACE
)
2443 if( !(wndPtr
->dwStyle
& WS_SYSMENU
) ) return;
2444 hTrackMenu
= wndPtr
->hSysMenu
;
2446 wParam
|= HTSYSMENU
; /* prevent item lookup */
2449 hTrackMenu
= wndPtr
->wIDmenu
;
2451 if (IsMenu32( hTrackMenu
))
2453 MENU_InitTracking( wndPtr
->hwndSelf
, hTrackMenu
);
2455 if( vkey
&& vkey
!= VK_SPACE
)
2457 uItem
= MENU_FindItemByKey( wndPtr
->hwndSelf
, hTrackMenu
,
2458 vkey
, (wParam
& HTSYSMENU
) );
2459 if( uItem
>= (UINT32
)(-2) )
2461 if( uItem
== (UINT32
)(-1) ) MessageBeep32(0);
2468 MENU_SelectItem( wndPtr
->hwndSelf
, hTrackMenu
, uItem
, TRUE
);
2470 if( uItem
== NO_SELECTED_ITEM
)
2471 MENU_MoveSelection( wndPtr
->hwndSelf
, hTrackMenu
, ITEM_NEXT
);
2473 PostMessage16( wndPtr
->hwndSelf
, WM_KEYDOWN
, VK_DOWN
, 0L );
2475 MENU_TrackMenu( hTrackMenu
, TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
2476 0, 0, wndPtr
->hwndSelf
, NULL
);
2478 SendMessage16( wndPtr
->hwndSelf
, WM_EXITMENULOOP
, 0, 0 );
2484 /**********************************************************************
2485 * TrackPopupMenu16 (USER.416)
2487 BOOL16 WINAPI
TrackPopupMenu16( HMENU16 hMenu
, UINT16 wFlags
, INT16 x
, INT16 y
,
2488 INT16 nReserved
, HWND16 hWnd
, const RECT16
*lpRect
)
2492 CONV_RECT16TO32( lpRect
, &r
);
2493 return TrackPopupMenu32( hMenu
, wFlags
, x
, y
, nReserved
, hWnd
,
2494 lpRect
? &r
: NULL
);
2498 /**********************************************************************
2499 * TrackPopupMenu32 (USER32.548)
2501 BOOL32 WINAPI
TrackPopupMenu32( HMENU32 hMenu
, UINT32 wFlags
, INT32 x
, INT32 y
,
2502 INT32 nReserved
, HWND32 hWnd
, const RECT32
*lpRect
)
2507 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
, 0, 0 ))
2508 ret
= MENU_TrackMenu( hMenu
, wFlags
& ~TPM_INTERNAL
, 0, 0, hWnd
, lpRect
);
2513 /**********************************************************************
2514 * TrackPopupMenuEx (USER32.549)
2516 BOOL32 WINAPI
TrackPopupMenuEx( HMENU32 hMenu
, UINT32 wFlags
, INT32 x
, INT32 y
,
2517 HWND32 hWnd
, LPTPMPARAMS lpTpm
)
2519 fprintf( stderr
, "TrackPopupMenuEx: not fully implemented\n" );
2520 return TrackPopupMenu32( hMenu
, wFlags
, x
, y
, 0, hWnd
,
2521 lpTpm
? &lpTpm
->rcExclude
: NULL
);
2524 /***********************************************************************
2527 * NOTE: Windows has totally different (and undocumented) popup wndproc.
2529 LRESULT WINAPI
PopupMenuWndProc( HWND32 hwnd
, UINT32 message
, WPARAM32 wParam
,
2532 WND
* wndPtr
= WIN_FindWndPtr(hwnd
);
2538 CREATESTRUCT32A
*cs
= (CREATESTRUCT32A
*)lParam
;
2539 SetWindowLong32A( hwnd
, 0, (LONG
)cs
->lpCreateParams
);
2543 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2544 return MA_NOACTIVATE
;
2549 BeginPaint32( hwnd
, &ps
);
2550 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
2551 (HMENU32
)GetWindowLong32A( hwnd
, 0 ) );
2552 EndPaint32( hwnd
, &ps
);
2560 /* zero out global pointer in case resident popup window
2561 * was somehow destroyed. */
2563 if( hwnd
== pTopPopupWnd
->hwndSelf
)
2565 dprintf_menu(stddeb
,"resident popup destroyed!\n");
2567 pTopPopupWnd
= NULL
;
2578 if( !(*(HMENU32
*)wndPtr
->wExtra
) )
2579 fprintf(stderr
,"MenuWndProc: no menu to display\n");
2582 *(HMENU32
*)wndPtr
->wExtra
= 0;
2585 case MM_SETMENUHANDLE
:
2587 *(HMENU32
*)wndPtr
->wExtra
= (HMENU32
)wParam
;
2590 case MM_GETMENUHANDLE
:
2592 return *(HMENU32
*)wndPtr
->wExtra
;
2595 return DefWindowProc32A( hwnd
, message
, wParam
, lParam
);
2601 /***********************************************************************
2602 * MENU_GetMenuBarHeight
2604 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
2606 UINT32
MENU_GetMenuBarHeight( HWND32 hwnd
, UINT32 menubarWidth
,
2607 INT32 orgX
, INT32 orgY
)
2614 dprintf_menu( stddeb
, "MENU_GetMenuBarHeight: HWND 0x%x, width %d, "
2615 "at (%d, %d).\n", hwnd
, menubarWidth
, orgX
, orgY
);
2617 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
2618 if (!(lppop
= (LPPOPUPMENU
)USER_HEAP_LIN_ADDR((HMENU16
)wndPtr
->wIDmenu
)))
2620 hdc
= GetDCEx32( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2621 SetRect32(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+SYSMETRICS_CYMENU
);
2622 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
2623 ReleaseDC32( hwnd
, hdc
);
2624 return lppop
->Height
;
2628 /*******************************************************************
2629 * ChangeMenu16 (USER.153)
2631 BOOL16 WINAPI
ChangeMenu16( HMENU16 hMenu
, UINT16 pos
, SEGPTR data
,
2632 UINT16 id
, UINT16 flags
)
2634 dprintf_menu( stddeb
,"ChangeMenu16: menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
2635 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2636 if (flags
& MF_APPEND
) return AppendMenu16( hMenu
, flags
& ~MF_APPEND
,
2639 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
2640 /* for MF_DELETE. We should check the parameters for all others */
2641 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
2643 if (flags
& MF_DELETE
) return DeleteMenu16(hMenu
, pos
, flags
& ~MF_DELETE
);
2644 if (flags
& MF_CHANGE
) return ModifyMenu16(hMenu
, pos
, flags
& ~MF_CHANGE
,
2646 if (flags
& MF_REMOVE
) return RemoveMenu16(hMenu
,
2647 flags
& MF_BYPOSITION
? pos
: id
,
2648 flags
& ~MF_REMOVE
);
2649 /* Default: MF_INSERT */
2650 return InsertMenu16( hMenu
, pos
, flags
, id
, data
);
2654 /*******************************************************************
2655 * ChangeMenu32A (USER32.22)
2657 BOOL32 WINAPI
ChangeMenu32A( HMENU32 hMenu
, UINT32 pos
, LPCSTR data
,
2658 UINT32 id
, UINT32 flags
)
2660 dprintf_menu( stddeb
,"ChangeMenu32A: menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2661 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2662 if (flags
& MF_APPEND
) return AppendMenu32A( hMenu
, flags
& ~MF_APPEND
,
2664 if (flags
& MF_DELETE
) return DeleteMenu32(hMenu
, pos
, flags
& ~MF_DELETE
);
2665 if (flags
& MF_CHANGE
) return ModifyMenu32A(hMenu
, pos
, flags
& ~MF_CHANGE
,
2667 if (flags
& MF_REMOVE
) return RemoveMenu32( hMenu
,
2668 flags
& MF_BYPOSITION
? pos
: id
,
2669 flags
& ~MF_REMOVE
);
2670 /* Default: MF_INSERT */
2671 return InsertMenu32A( hMenu
, pos
, flags
, id
, data
);
2675 /*******************************************************************
2676 * ChangeMenu32W (USER32.23)
2678 BOOL32 WINAPI
ChangeMenu32W( HMENU32 hMenu
, UINT32 pos
, LPCWSTR data
,
2679 UINT32 id
, UINT32 flags
)
2681 dprintf_menu( stddeb
,"ChangeMenu32W: menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2682 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2683 if (flags
& MF_APPEND
) return AppendMenu32W( hMenu
, flags
& ~MF_APPEND
,
2685 if (flags
& MF_DELETE
) return DeleteMenu32(hMenu
, pos
, flags
& ~MF_DELETE
);
2686 if (flags
& MF_CHANGE
) return ModifyMenu32W(hMenu
, pos
, flags
& ~MF_CHANGE
,
2688 if (flags
& MF_REMOVE
) return RemoveMenu32( hMenu
,
2689 flags
& MF_BYPOSITION
? pos
: id
,
2690 flags
& ~MF_REMOVE
);
2691 /* Default: MF_INSERT */
2692 return InsertMenu32W( hMenu
, pos
, flags
, id
, data
);
2696 /*******************************************************************
2697 * CheckMenuItem16 (USER.154)
2699 BOOL16 WINAPI
CheckMenuItem16( HMENU16 hMenu
, UINT16 id
, UINT16 flags
)
2701 return (BOOL16
)CheckMenuItem32( hMenu
, id
, flags
);
2705 /*******************************************************************
2706 * CheckMenuItem32 (USER32.45)
2708 DWORD WINAPI
CheckMenuItem32( HMENU32 hMenu
, UINT32 id
, UINT32 flags
)
2713 dprintf_menu( stddeb
,"CheckMenuItem: %04x %04x %04x\n", hMenu
, id
, flags
);
2714 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
2715 ret
= item
->fState
& MF_CHECKED
;
2716 if (flags
& MF_CHECKED
) item
->fState
|= MF_CHECKED
;
2717 else item
->fState
&= ~MF_CHECKED
;
2722 /**********************************************************************
2723 * EnableMenuItem16 (USER.155)
2725 BOOL16 WINAPI
EnableMenuItem16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
2727 return EnableMenuItem32( hMenu
, wItemID
, wFlags
);
2731 /**********************************************************************
2732 * EnableMenuItem32 (USER32.169)
2734 BOOL32 WINAPI
EnableMenuItem32( HMENU32 hMenu
, UINT32 wItemID
, UINT32 wFlags
)
2736 BOOL32 bRet
= FALSE
;
2737 MENUITEM
*item
, *first
= NULL
;
2739 dprintf_menu(stddeb
,"EnableMenuItem (%04x, %04X, %04X) !\n",
2740 hMenu
, wItemID
, wFlags
);
2742 while( (item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
)) )
2744 if( !(item
->fType
& MF_POPUP
) )
2746 /* We can't have MF_GRAYED and MF_DISABLED together */
2747 if (wFlags
& MF_GRAYED
)
2749 item
->fState
= (item
->fState
& ~MF_DISABLED
) | MF_GRAYED
;
2751 else if (wFlags
& MF_DISABLED
)
2753 item
->fState
= (item
->fState
& ~MF_GRAYED
) | MF_DISABLED
;
2755 else /* MF_ENABLED */
2757 item
->fState
&= ~(MF_GRAYED
| MF_DISABLED
);
2762 if( !first
) first
= item
;
2763 else if( first
== item
) break;
2769 /*******************************************************************
2770 * GetMenuString16 (USER.161)
2772 INT16 WINAPI
GetMenuString16( HMENU16 hMenu
, UINT16 wItemID
,
2773 LPSTR str
, INT16 nMaxSiz
, UINT16 wFlags
)
2775 return GetMenuString32A( hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
2779 /*******************************************************************
2780 * GetMenuString32A (USER32.267)
2782 INT32 WINAPI
GetMenuString32A( HMENU32 hMenu
, UINT32 wItemID
,
2783 LPSTR str
, INT32 nMaxSiz
, UINT32 wFlags
)
2787 dprintf_menu( stddeb
, "GetMenuString32A: menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
2788 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
2789 if (!str
|| !nMaxSiz
) return 0;
2791 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
2792 if (!IS_STRING_ITEM(item
->fType
)) return 0;
2793 lstrcpyn32A( str
, item
->text
, nMaxSiz
);
2794 dprintf_menu( stddeb
, "GetMenuString32A: returning '%s'\n", str
);
2799 /*******************************************************************
2800 * GetMenuString32W (USER32.268)
2802 INT32 WINAPI
GetMenuString32W( HMENU32 hMenu
, UINT32 wItemID
,
2803 LPWSTR str
, INT32 nMaxSiz
, UINT32 wFlags
)
2807 dprintf_menu( stddeb
, "GetMenuString32W: menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
2808 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
2809 if (!str
|| !nMaxSiz
) return 0;
2811 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
2812 if (!IS_STRING_ITEM(item
->fType
)) return 0;
2813 lstrcpynAtoW( str
, item
->text
, nMaxSiz
);
2814 return lstrlen32W(str
);
2818 /**********************************************************************
2819 * HiliteMenuItem16 (USER.162)
2821 BOOL16 WINAPI
HiliteMenuItem16( HWND16 hWnd
, HMENU16 hMenu
, UINT16 wItemID
,
2824 return HiliteMenuItem32( hWnd
, hMenu
, wItemID
, wHilite
);
2828 /**********************************************************************
2829 * HiliteMenuItem32 (USER32.317)
2831 BOOL32 WINAPI
HiliteMenuItem32( HWND32 hWnd
, HMENU32 hMenu
, UINT32 wItemID
,
2835 dprintf_menu(stddeb
,"HiliteMenuItem(%04x, %04x, %04x, %04x);\n",
2836 hWnd
, hMenu
, wItemID
, wHilite
);
2837 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
2838 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
2839 if (menu
->FocusedItem
== wItemID
) return TRUE
;
2840 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
2841 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
);
2846 /**********************************************************************
2847 * GetMenuState16 (USER.250)
2849 UINT16 WINAPI
GetMenuState16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
2851 return GetMenuState32( hMenu
, wItemID
, wFlags
);
2855 /**********************************************************************
2856 * GetMenuState32 (USER32.266)
2858 UINT32 WINAPI
GetMenuState32( HMENU32 hMenu
, UINT32 wItemID
, UINT32 wFlags
)
2861 dprintf_menu(stddeb
,"GetMenuState(%04x, %04x, %04x);\n",
2862 hMenu
, wItemID
, wFlags
);
2863 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
2864 if (item
->fType
& MF_POPUP
)
2866 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( item
->hSubMenu
);
2867 if (!menu
) return -1;
2868 else return (menu
->nItems
<< 8) | (menu
->wFlags
& 0xff);
2871 /* Non POPUP Menus only return flags in the lower byte */
2873 return ((item
->fType
| item
->fState
) & 0x00ff);
2877 /**********************************************************************
2878 * GetMenuItemCount16 (USER.263)
2880 INT16 WINAPI
GetMenuItemCount16( HMENU16 hMenu
)
2882 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2883 if (!IS_A_MENU(menu
)) return -1;
2884 dprintf_menu( stddeb
,"GetMenuItemCount16(%04x) returning %d\n",
2885 hMenu
, menu
->nItems
);
2886 return menu
->nItems
;
2890 /**********************************************************************
2891 * GetMenuItemCount32 (USER32.261)
2893 INT32 WINAPI
GetMenuItemCount32( HMENU32 hMenu
)
2895 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2896 if (!IS_A_MENU(menu
)) return -1;
2897 dprintf_menu( stddeb
,"GetMenuItemCount32(%04x) returning %d\n",
2898 hMenu
, menu
->nItems
);
2899 return menu
->nItems
;
2903 /**********************************************************************
2904 * GetMenuItemID16 (USER.264)
2906 UINT16 WINAPI
GetMenuItemID16( HMENU16 hMenu
, INT16 nPos
)
2910 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
2911 if ((nPos
< 0) || ((UINT16
) nPos
>= menu
->nItems
)) return -1;
2912 if (menu
->items
[nPos
].fType
& MF_POPUP
) return -1;
2913 return menu
->items
[nPos
].wID
;
2917 /**********************************************************************
2918 * GetMenuItemID32 (USER32.262)
2920 UINT32 WINAPI
GetMenuItemID32( HMENU32 hMenu
, INT32 nPos
)
2924 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
2925 if ((nPos
< 0) || (nPos
>= menu
->nItems
)) return -1;
2926 /* FIXME: Now that submenus can have ids, is this still right? */
2927 if (menu
->items
[nPos
].fType
& MF_POPUP
) return -1;
2928 return menu
->items
[nPos
].wID
;
2932 /*******************************************************************
2933 * InsertMenu16 (USER.410)
2935 BOOL16 WINAPI
InsertMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
2936 UINT16 id
, SEGPTR data
)
2938 UINT32 pos32
= (UINT32
)pos
;
2939 if ((pos
== (UINT16
)-1) && (flags
& MF_BYPOSITION
)) pos32
= (UINT32
)-1;
2940 if (IS_STRING_ITEM(flags
) && data
)
2941 return InsertMenu32A( hMenu
, pos32
, flags
, id
,
2942 (LPSTR
)PTR_SEG_TO_LIN(data
) );
2943 return InsertMenu32A( hMenu
, pos32
, flags
, id
, (LPSTR
)data
);
2947 /*******************************************************************
2948 * InsertMenu32A (USER32.321)
2950 BOOL32 WINAPI
InsertMenu32A( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2951 UINT32 id
, LPCSTR str
)
2955 if (IS_STRING_ITEM(flags
) && str
)
2956 dprintf_menu( stddeb
, "InsertMenu: hMenu %04x, pos %d, flags %08x, "
2957 "id %04x, str '%s'\n",
2958 hMenu
, pos
, flags
, id
, str
);
2959 else dprintf_menu( stddeb
, "InsertMenu: hMenu %04x, pos %d, flags %08x, "
2960 "id %04x, str %08lx (not a string)\n",
2961 hMenu
, pos
, flags
, id
, (DWORD
)str
);
2963 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
2965 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
2967 RemoveMenu32( hMenu
, pos
, flags
);
2971 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
2972 ((POPUPMENU
*)USER_HEAP_LIN_ADDR((HMENU16
)id
))->wFlags
|= MF_POPUP
;
2974 item
->hCheckBit
= item
->hUnCheckBit
= 0;
2975 item
->dwItemData
= 0;
2980 /*******************************************************************
2981 * InsertMenu32W (USER32.324)
2983 BOOL32 WINAPI
InsertMenu32W( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2984 UINT32 id
, LPCWSTR str
)
2988 if (IS_STRING_ITEM(flags
) && str
)
2990 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
2991 ret
= InsertMenu32A( hMenu
, pos
, flags
, id
, newstr
);
2992 HeapFree( GetProcessHeap(), 0, newstr
);
2995 else return InsertMenu32A( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
2999 /*******************************************************************
3000 * AppendMenu16 (USER.411)
3002 BOOL16 WINAPI
AppendMenu16(HMENU16 hMenu
, UINT16 flags
, UINT16 id
, SEGPTR data
)
3004 return InsertMenu16( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3008 /*******************************************************************
3009 * AppendMenu32A (USER32.4)
3011 BOOL32 WINAPI
AppendMenu32A( HMENU32 hMenu
, UINT32 flags
,
3012 UINT32 id
, LPCSTR data
)
3014 return InsertMenu32A( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3018 /*******************************************************************
3019 * AppendMenu32W (USER32.5)
3021 BOOL32 WINAPI
AppendMenu32W( HMENU32 hMenu
, UINT32 flags
,
3022 UINT32 id
, LPCWSTR data
)
3024 return InsertMenu32W( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3028 /**********************************************************************
3029 * RemoveMenu16 (USER.412)
3031 BOOL16 WINAPI
RemoveMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3033 return RemoveMenu32( hMenu
, nPos
, wFlags
);
3037 /**********************************************************************
3038 * RemoveMenu32 (USER32.440)
3040 BOOL32 WINAPI
RemoveMenu32( HMENU32 hMenu
, UINT32 nPos
, UINT32 wFlags
)
3045 dprintf_menu(stddeb
,"RemoveMenu (%04x, %04x, %04x)\n",hMenu
, nPos
, wFlags
);
3046 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3047 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
3051 MENU_FreeItemData( item
);
3053 if (--menu
->nItems
== 0)
3055 HeapFree( SystemHeap
, 0, menu
->items
);
3060 while(nPos
< menu
->nItems
)
3066 menu
->items
= HeapReAlloc( SystemHeap
, 0, menu
->items
,
3067 menu
->nItems
* sizeof(MENUITEM
) );
3073 /**********************************************************************
3074 * DeleteMenu16 (USER.413)
3076 BOOL16 WINAPI
DeleteMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3078 return DeleteMenu32( hMenu
, nPos
, wFlags
);
3082 /**********************************************************************
3083 * DeleteMenu32 (USER32.128)
3085 BOOL32 WINAPI
DeleteMenu32( HMENU32 hMenu
, UINT32 nPos
, UINT32 wFlags
)
3087 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
3088 if (!item
) return FALSE
;
3089 if (item
->fType
& MF_POPUP
) DestroyMenu32( item
->hSubMenu
);
3090 /* nPos is now the position of the item */
3091 RemoveMenu32( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
3096 /*******************************************************************
3097 * ModifyMenu16 (USER.414)
3099 BOOL16 WINAPI
ModifyMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3100 UINT16 id
, SEGPTR data
)
3102 if (IS_STRING_ITEM(flags
))
3103 return ModifyMenu32A( hMenu
, pos
, flags
, id
,
3104 (LPSTR
)PTR_SEG_TO_LIN(data
) );
3105 return ModifyMenu32A( hMenu
, pos
, flags
, id
, (LPSTR
)data
);
3109 /*******************************************************************
3110 * ModifyMenu32A (USER32.396)
3112 BOOL32 WINAPI
ModifyMenu32A( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
3113 UINT32 id
, LPCSTR str
)
3117 if (IS_STRING_ITEM(flags
))
3119 dprintf_menu( stddeb
, "ModifyMenu: %04x %d %04x %04x '%s'\n",
3120 hMenu
, pos
, flags
, id
, str
? str
: "#NULL#" );
3121 if (!str
) return FALSE
;
3125 dprintf_menu( stddeb
, "ModifyMenu: %04x %d %04x %04x %08lx\n",
3126 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3129 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
3130 return MENU_SetItemData( item
, flags
, id
, str
);
3134 /*******************************************************************
3135 * ModifyMenu32W (USER32.397)
3137 BOOL32 WINAPI
ModifyMenu32W( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
3138 UINT32 id
, LPCWSTR str
)
3142 if (IS_STRING_ITEM(flags
) && str
)
3144 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
3145 ret
= ModifyMenu32A( hMenu
, pos
, flags
, id
, newstr
);
3146 HeapFree( GetProcessHeap(), 0, newstr
);
3149 else return ModifyMenu32A( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
3153 /**********************************************************************
3154 * CreatePopupMenu16 (USER.415)
3156 HMENU16 WINAPI
CreatePopupMenu16(void)
3158 return CreatePopupMenu32();
3162 /**********************************************************************
3163 * CreatePopupMenu32 (USER32.81)
3165 HMENU32 WINAPI
CreatePopupMenu32(void)
3170 if (!(hmenu
= CreateMenu32())) return 0;
3171 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
3172 menu
->wFlags
|= MF_POPUP
;
3177 /**********************************************************************
3178 * GetMenuCheckMarkDimensions (USER.417) (USER32.257)
3180 DWORD WINAPI
GetMenuCheckMarkDimensions(void)
3182 return MAKELONG( check_bitmap_width
, check_bitmap_height
);
3186 /**********************************************************************
3187 * SetMenuItemBitmaps16 (USER.418)
3189 BOOL16 WINAPI
SetMenuItemBitmaps16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
,
3190 HBITMAP16 hNewUnCheck
, HBITMAP16 hNewCheck
)
3192 return SetMenuItemBitmaps32( hMenu
, nPos
, wFlags
, hNewUnCheck
, hNewCheck
);
3196 /**********************************************************************
3197 * SetMenuItemBitmaps32 (USER32.489)
3199 BOOL32 WINAPI
SetMenuItemBitmaps32( HMENU32 hMenu
, UINT32 nPos
, UINT32 wFlags
,
3200 HBITMAP32 hNewUnCheck
, HBITMAP32 hNewCheck
)
3203 dprintf_menu(stddeb
,"SetMenuItemBitmaps(%04x, %04x, %04x, %04x, %04x)\n",
3204 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
3205 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3207 if (!hNewCheck
&& !hNewUnCheck
)
3209 item
->fState
&= ~MF_USECHECKBITMAPS
;
3211 else /* Install new bitmaps */
3213 item
->hCheckBit
= hNewCheck
;
3214 item
->hUnCheckBit
= hNewUnCheck
;
3215 item
->fState
|= MF_USECHECKBITMAPS
;
3221 /**********************************************************************
3222 * CreateMenu16 (USER.151)
3224 HMENU16 WINAPI
CreateMenu16(void)
3226 return CreateMenu32();
3230 /**********************************************************************
3231 * CreateMenu32 (USER32.80)
3233 HMENU32 WINAPI
CreateMenu32(void)
3237 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) ))) return 0;
3238 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3240 menu
->wMagic
= MENU_MAGIC
;
3247 menu
->FocusedItem
= NO_SELECTED_ITEM
;
3248 dprintf_menu( stddeb
, "CreateMenu: return %04x\n", hMenu
);
3253 /**********************************************************************
3254 * DestroyMenu16 (USER.152)
3256 BOOL16 WINAPI
DestroyMenu16( HMENU16 hMenu
)
3258 return DestroyMenu32( hMenu
);
3262 /**********************************************************************
3263 * DestroyMenu32 (USER32.133)
3265 BOOL32 WINAPI
DestroyMenu32( HMENU32 hMenu
)
3267 dprintf_menu(stddeb
,"DestroyMenu(%04x)\n", hMenu
);
3269 /* Silently ignore attempts to destroy default system popup */
3271 if (hMenu
&& hMenu
!= MENU_DefSysPopup
)
3273 LPPOPUPMENU lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3275 if( pTopPopupWnd
&& (hMenu
== *(HMENU32
*)pTopPopupWnd
->wExtra
) )
3276 *(UINT32
*)pTopPopupWnd
->wExtra
= 0;
3278 if (IS_A_MENU( lppop
))
3280 lppop
->wMagic
= 0; /* Mark it as destroyed */
3282 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
&&
3283 (!pTopPopupWnd
|| (lppop
->hWnd
!= pTopPopupWnd
->hwndSelf
)))
3284 DestroyWindow32( lppop
->hWnd
);
3286 if (lppop
->items
) /* recursively destroy submenus */
3289 MENUITEM
*item
= lppop
->items
;
3290 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
3292 if (item
->fType
& MF_POPUP
) DestroyMenu32(item
->hSubMenu
);
3293 MENU_FreeItemData( item
);
3295 HeapFree( SystemHeap
, 0, lppop
->items
);
3297 USER_HEAP_FREE( hMenu
);
3301 return (hMenu
!= MENU_DefSysPopup
);
3305 /**********************************************************************
3306 * GetSystemMenu16 (USER.156)
3308 HMENU16 WINAPI
GetSystemMenu16( HWND16 hWnd
, BOOL16 bRevert
)
3310 return GetSystemMenu32( hWnd
, bRevert
);
3314 /**********************************************************************
3315 * GetSystemMenu32 (USER32.290)
3317 HMENU32 WINAPI
GetSystemMenu32( HWND32 hWnd
, BOOL32 bRevert
)
3319 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
3323 if( wndPtr
->hSysMenu
)
3327 DestroyMenu32(wndPtr
->hSysMenu
);
3328 wndPtr
->hSysMenu
= 0;
3332 POPUPMENU
*menu
= (POPUPMENU
*)
3333 USER_HEAP_LIN_ADDR(wndPtr
->hSysMenu
);
3334 if( menu
->items
[0].hSubMenu
== MENU_DefSysPopup
)
3335 menu
->items
[0].hSubMenu
= MENU_CopySysPopup();
3339 if(!wndPtr
->hSysMenu
&& (wndPtr
->dwStyle
& WS_SYSMENU
) )
3340 wndPtr
->hSysMenu
= MENU_GetSysMenu( hWnd
, (HMENU32
)(-1) );
3342 if( wndPtr
->hSysMenu
)
3343 return GetSubMenu16(wndPtr
->hSysMenu
, 0);
3349 /*******************************************************************
3350 * SetSystemMenu16 (USER.280)
3352 BOOL16 WINAPI
SetSystemMenu16( HWND16 hwnd
, HMENU16 hMenu
)
3354 return SetSystemMenu32( hwnd
, hMenu
);
3358 /*******************************************************************
3359 * SetSystemMenu32 (USER32.507)
3361 BOOL32 WINAPI
SetSystemMenu32( HWND32 hwnd
, HMENU32 hMenu
)
3363 WND
*wndPtr
= WIN_FindWndPtr(hwnd
);
3367 if (wndPtr
->hSysMenu
) DestroyMenu32( wndPtr
->hSysMenu
);
3368 wndPtr
->hSysMenu
= MENU_GetSysMenu( hwnd
, hMenu
);
3375 /**********************************************************************
3376 * GetMenu16 (USER.157)
3378 HMENU16 WINAPI
GetMenu16( HWND16 hWnd
)
3380 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
3381 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
3382 return (HMENU16
)wndPtr
->wIDmenu
;
3387 /**********************************************************************
3388 * GetMenu32 (USER32.256)
3390 HMENU32 WINAPI
GetMenu32( HWND32 hWnd
)
3392 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
3393 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
3394 return (HMENU32
)wndPtr
->wIDmenu
;
3399 /**********************************************************************
3400 * SetMenu16 (USER.158)
3402 BOOL16 WINAPI
SetMenu16( HWND16 hWnd
, HMENU16 hMenu
)
3404 return SetMenu32( hWnd
, hMenu
);
3408 /**********************************************************************
3409 * SetMenu32 (USER32.486)
3411 BOOL32 WINAPI
SetMenu32( HWND32 hWnd
, HMENU32 hMenu
)
3413 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
3415 dprintf_menu(stddeb
,"SetMenu(%04x, %04x);\n", hWnd
, hMenu
);
3417 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
3419 if (GetCapture32() == hWnd
) ReleaseCapture();
3421 wndPtr
->wIDmenu
= (UINT32
)hMenu
;
3426 if (!(lpmenu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
3427 lpmenu
->hWnd
= hWnd
;
3428 lpmenu
->wFlags
&= ~MF_POPUP
; /* Can't be a popup */
3429 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
3431 if (IsWindowVisible32(hWnd
))
3432 SetWindowPos32( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3433 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3441 /**********************************************************************
3442 * GetSubMenu16 (USER.159)
3444 HMENU16 WINAPI
GetSubMenu16( HMENU16 hMenu
, INT16 nPos
)
3446 return GetSubMenu32( hMenu
, nPos
);
3450 /**********************************************************************
3451 * GetSubMenu32 (USER32.287)
3453 HMENU32 WINAPI
GetSubMenu32( HMENU32 hMenu
, INT32 nPos
)
3457 if (!(lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return 0;
3458 if ((UINT32
)nPos
>= lppop
->nItems
) return 0;
3459 if (!(lppop
->items
[nPos
].fType
& MF_POPUP
)) return 0;
3460 return lppop
->items
[nPos
].hSubMenu
;
3464 /**********************************************************************
3465 * DrawMenuBar16 (USER.160)
3467 void WINAPI
DrawMenuBar16( HWND16 hWnd
)
3469 DrawMenuBar32( hWnd
);
3473 /**********************************************************************
3474 * DrawMenuBar32 (USER32.160)
3476 BOOL32 WINAPI
DrawMenuBar32( HWND32 hWnd
)
3479 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
3480 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
) && wndPtr
->wIDmenu
)
3482 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR((HMENU16
)wndPtr
->wIDmenu
);
3483 if (lppop
== NULL
) return FALSE
;
3485 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
3486 SetWindowPos32( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3487 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3494 /***********************************************************************
3495 * EndMenu (USER.187) (USER32.174)
3497 void WINAPI
EndMenu(void)
3503 /***********************************************************************
3504 * LookupMenuHandle (USER.217)
3506 HMENU16 WINAPI
LookupMenuHandle( HMENU16 hmenu
, INT16 id
)
3508 HMENU32 hmenu32
= hmenu
;
3510 if (!MENU_FindItem( &hmenu32
, &id32
, MF_BYCOMMAND
)) return 0;
3511 else return hmenu32
;
3515 /**********************************************************************
3516 * LoadMenu16 (USER.150)
3518 HMENU16 WINAPI
LoadMenu16( HINSTANCE16 instance
, SEGPTR name
)
3526 char *str
= (char *)PTR_SEG_TO_LIN( name
);
3527 dprintf_menu( stddeb
, "LoadMenu(%04x,'%s')\n", instance
, str
);
3528 if (str
[0] == '#') name
= (SEGPTR
)atoi( str
+ 1 );
3531 dprintf_resource(stddeb
,"LoadMenu(%04x,%04x)\n",instance
,LOWORD(name
));
3533 if (!name
) return 0;
3535 /* check for Win32 module */
3536 if (HIWORD(instance
))
3537 return LoadMenu32A(instance
,PTR_SEG_TO_LIN(name
));
3538 instance
= GetExePtr( instance
);
3540 if (!(hRsrc
= FindResource16( instance
, name
, RT_MENU
))) return 0;
3541 if (!(handle
= LoadResource16( instance
, hRsrc
))) return 0;
3542 hMenu
= LoadMenuIndirect16(LockResource16(handle
));
3543 FreeResource16( handle
);
3548 /*****************************************************************
3549 * LoadMenu32A (USER32.370)
3551 HMENU32 WINAPI
LoadMenu32A( HINSTANCE32 instance
, LPCSTR name
)
3553 HRSRC32 hrsrc
= FindResource32A( instance
, name
, (LPSTR
)RT_MENU
);
3554 if (!hrsrc
) return 0;
3555 return LoadMenuIndirect32A( (LPCVOID
)LoadResource32( instance
, hrsrc
));
3559 /*****************************************************************
3560 * LoadMenu32W (USER32.372)
3562 HMENU32 WINAPI
LoadMenu32W( HINSTANCE32 instance
, LPCWSTR name
)
3564 HRSRC32 hrsrc
= FindResource32W( instance
, name
, (LPWSTR
)RT_MENU
);
3565 if (!hrsrc
) return 0;
3566 return LoadMenuIndirect32W( (LPCVOID
)LoadResource32( instance
, hrsrc
));
3570 /**********************************************************************
3571 * LoadMenuIndirect16 (USER.220)
3573 HMENU16 WINAPI
LoadMenuIndirect16( LPCVOID
template )
3576 WORD version
, offset
;
3577 LPCSTR p
= (LPCSTR
)template;
3579 dprintf_menu(stddeb
,"LoadMenuIndirect16: %p\n", template );
3580 version
= GET_WORD(p
);
3584 fprintf( stderr
, "LoadMenuIndirect16: version must be 0 for Win16\n" );
3587 offset
= GET_WORD(p
);
3588 p
+= sizeof(WORD
) + offset
;
3589 if (!(hMenu
= CreateMenu32())) return 0;
3590 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
3592 DestroyMenu32( hMenu
);
3599 /**********************************************************************
3600 * LoadMenuIndirect32A (USER32.370)
3602 HMENU32 WINAPI
LoadMenuIndirect32A( LPCVOID
template )
3605 WORD version
, offset
;
3606 LPCSTR p
= (LPCSTR
)template;
3608 dprintf_menu(stddeb
,"LoadMenuIndirect32A: %p\n", template );
3609 version
= GET_WORD(p
);
3614 offset
= GET_WORD(p
);
3615 p
+= sizeof(WORD
) + offset
;
3616 if (!(hMenu
= CreateMenu32())) return 0;
3617 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
3619 DestroyMenu32( hMenu
);
3624 offset
= GET_WORD(p
);
3625 p
+= sizeof(WORD
) + offset
;
3626 if (!(hMenu
= CreateMenu32())) return 0;
3627 if (!MENUEX_ParseResource( p
, hMenu
))
3629 DestroyMenu32( hMenu
);
3634 fprintf( stderr
, "LoadMenuIndirect32A: version %d not supported.\n",
3641 /**********************************************************************
3642 * LoadMenuIndirect32W (USER32.371)
3644 HMENU32 WINAPI
LoadMenuIndirect32W( LPCVOID
template )
3646 /* FIXME: is there anything different between A and W? */
3647 return LoadMenuIndirect32A( template );
3651 /**********************************************************************
3652 * IsMenu16 (USER.358)
3654 BOOL16 WINAPI
IsMenu16( HMENU16 hmenu
)
3656 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
3657 return IS_A_MENU(menu
);
3661 /**********************************************************************
3662 * IsMenu32 (USER32.345)
3664 BOOL32 WINAPI
IsMenu32(HMENU32 hmenu
)
3666 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
3667 return IS_A_MENU(menu
);
3670 /**********************************************************************
3671 * GetMenuItemInfo32_common
3674 static BOOL32
GetMenuItemInfo32_common ( HMENU32 hmenu
, UINT32 item
,
3676 LPMENUITEMINFO32A lpmii
,
3679 MENUITEM
*menu
= MENU_FindItem (&hmenu
, &item
, bypos
);
3680 debug_print_menuitem("GetMenuItemInfo32_common: ", menu
, "\n");
3684 if (lpmii
->fMask
& MIIM_TYPE
) {
3685 lpmii
->fType
= menu
->fType
;
3686 switch (MENU_ITEM_TYPE(menu
->fType
)) {
3688 if (menu
->text
&& lpmii
->dwTypeData
&& lpmii
->cch
) {
3690 lstrcpynAtoW((LPWSTR
) lpmii
->dwTypeData
,
3694 lstrcpyn32A(lpmii
->dwTypeData
,
3701 lpmii
->dwTypeData
= menu
->text
;
3707 if (lpmii
->fMask
& MIIM_STATE
)
3708 lpmii
->fState
= menu
->fState
;
3710 if (lpmii
->fMask
& MIIM_ID
)
3711 lpmii
->wID
= menu
->wID
;
3713 if (lpmii
->fMask
& MIIM_SUBMENU
)
3714 lpmii
->hSubMenu
= menu
->hSubMenu
;
3716 if (lpmii
->fMask
& MIIM_CHECKMARKS
) {
3717 lpmii
->hbmpChecked
= menu
->hCheckBit
;
3718 lpmii
->hbmpUnchecked
= menu
->hUnCheckBit
;
3720 if (lpmii
->fMask
& MIIM_DATA
)
3721 lpmii
->dwItemData
= menu
->dwItemData
;
3726 /**********************************************************************
3727 * GetMenuItemInfo32A (USER32.263)
3729 BOOL32 WINAPI
GetMenuItemInfo32A( HMENU32 hmenu
, UINT32 item
, BOOL32 bypos
,
3730 LPMENUITEMINFO32A lpmii
)
3732 return GetMenuItemInfo32_common (hmenu
, item
, bypos
, lpmii
, FALSE
);
3735 /**********************************************************************
3736 * GetMenuItemInfo32W (USER32.264)
3738 BOOL32 WINAPI
GetMenuItemInfo32W( HMENU32 hmenu
, UINT32 item
, BOOL32 bypos
,
3739 LPMENUITEMINFO32W lpmii
)
3741 return GetMenuItemInfo32_common (hmenu
, item
, bypos
,
3742 (LPMENUITEMINFO32A
)lpmii
, TRUE
);
3745 /**********************************************************************
3746 * SetMenuItemInfo32_common
3749 static BOOL32
SetMenuItemInfo32_common(MENUITEM
* menu
,
3750 const MENUITEMINFO32A
*lpmii
,
3753 if (!menu
) return FALSE
;
3755 if (lpmii
->fMask
& MIIM_TYPE
) {
3756 /* Get rid of old string. */
3757 if (IS_STRING_ITEM(menu
->fType
) && menu
->text
)
3758 HeapFree(SystemHeap
, 0, menu
->text
);
3760 menu
->fType
= lpmii
->fType
;
3761 menu
->text
= lpmii
->dwTypeData
;
3762 if (IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
3765 ? HEAP_strdupWtoA(SystemHeap
, 0,
3766 (LPWSTR
) lpmii
->dwTypeData
)
3767 : HEAP_strdupA(SystemHeap
, 0, lpmii
->dwTypeData
);
3770 if (lpmii
->fMask
& MIIM_STATE
)
3771 menu
->fState
= lpmii
->fState
;
3773 if (lpmii
->fMask
& MIIM_ID
)
3774 menu
->wID
= lpmii
->wID
;
3776 if (lpmii
->fMask
& MIIM_SUBMENU
)
3777 menu
->hSubMenu
= lpmii
->hSubMenu
;
3779 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
3781 menu
->hCheckBit
= lpmii
->hbmpChecked
;
3782 menu
->hUnCheckBit
= lpmii
->hbmpUnchecked
;
3784 if (lpmii
->fMask
& MIIM_DATA
)
3785 menu
->dwItemData
= lpmii
->dwItemData
;
3787 debug_print_menuitem("SetMenuItemInfo32_common: ", menu
, "\n");
3791 /**********************************************************************
3792 * SetMenuItemInfo32A (USER32.490)
3794 BOOL32 WINAPI
SetMenuItemInfo32A(HMENU32 hmenu
, UINT32 item
, BOOL32 bypos
,
3795 const MENUITEMINFO32A
*lpmii
)
3797 return SetMenuItemInfo32_common(MENU_FindItem(&hmenu
, &item
, bypos
),
3801 /**********************************************************************
3802 * SetMenuItemInfo32W (USER32.491)
3804 BOOL32 WINAPI
SetMenuItemInfo32W(HMENU32 hmenu
, UINT32 item
, BOOL32 bypos
,
3805 const MENUITEMINFO32W
*lpmii
)
3807 return SetMenuItemInfo32_common(MENU_FindItem(&hmenu
, &item
, bypos
),
3808 (const MENUITEMINFO32A
*)lpmii
, TRUE
);
3811 /**********************************************************************
3812 * SetMenuDefaultItem32 (USER32.488)
3814 BOOL32 WINAPI
SetMenuDefaultItem32(HMENU32 hmenu
, UINT32 item
, BOOL32 bypos
)
3816 MENUITEM
*menu
= MENU_FindItem(&hmenu
, &item
, bypos
);
3817 if (!menu
) return FALSE
;
3818 debug_print_menuitem("SetMenuDefaultItem32: ", menu
, "\n");
3819 fprintf(stdnimp
, "SetMenuDefaultItem32 (0x%x,%d,%d), empty stub!\n",
3820 hmenu
, item
, bypos
);
3824 /*******************************************************************
3825 * InsertMenuItem16 (USER.441)
3829 BOOL16 WINAPI
InsertMenuItem16( HMENU16 hmenu
, UINT16 pos
, BOOL16 byposition
,
3830 const MENUITEMINFO16
*mii
)
3832 MENUITEMINFO32A miia
;
3834 miia
.cbSize
= sizeof(miia
);
3835 miia
.fMask
= mii
->fMask
;
3836 miia
.dwTypeData
= mii
->dwTypeData
;
3837 miia
.fType
= mii
->fType
;
3838 miia
.fState
= mii
->fState
;
3839 miia
.wID
= mii
->wID
;
3840 miia
.hSubMenu
= mii
->hSubMenu
;
3841 miia
.hbmpChecked
= mii
->hbmpChecked
;
3842 miia
.hbmpUnchecked
= mii
->hbmpUnchecked
;
3843 miia
.dwItemData
= mii
->dwItemData
;
3844 miia
.cch
= mii
->cch
;
3845 if (IS_STRING_ITEM(miia
.fType
))
3846 miia
.dwTypeData
= PTR_SEG_TO_LIN(miia
.dwTypeData
);
3847 return InsertMenuItem32A( hmenu
, pos
, byposition
, &miia
);
3851 /**********************************************************************
3852 * InsertMenuItem32A (USER32.322)
3854 BOOL32 WINAPI
InsertMenuItem32A(HMENU32 hMenu
, UINT32 uItem
, BOOL32 bypos
,
3855 const MENUITEMINFO32A
*lpmii
)
3857 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
);
3858 return SetMenuItemInfo32_common(item
, lpmii
, FALSE
);
3862 /**********************************************************************
3863 * InsertMenuItem32W (USER32.323)
3865 BOOL32 WINAPI
InsertMenuItem32W(HMENU32 hMenu
, UINT32 uItem
, BOOL32 bypos
,
3866 const MENUITEMINFO32W
*lpmii
)
3868 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
);
3869 return SetMenuItemInfo32_common(item
, (const MENUITEMINFO32A
*)lpmii
, TRUE
);