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)
57 HBITMAP32 hUnCheckBit
;
58 } CBITMAPS
, *PCBITMAPS
;
60 /* Menu item structure */
63 UINT32 item_flags
; /* Item flags */
64 UINT32 item_id
; /* Item or popup id */
65 RECT32 rect
; /* Item area (relative to menu window) */
66 UINT32 xTab
; /* X position of text after Tab */
67 PCBITMAPS pCB
; /* checkmark bitmaps */
68 LPSTR text
; /* Item text or bitmap handle */
71 /* Popup menu structure */
74 WORD wFlags
; /* Menu flags (MF_POPUP, MF_SYSMENU) */
75 WORD wMagic
; /* Magic number */
76 HQUEUE16 hTaskQ
; /* Task queue for this menu */
77 WORD Width
; /* Width of the whole menu */
78 WORD Height
; /* Height of the whole menu */
79 WORD nItems
; /* Number of items in the menu */
80 HWND32 hWnd
; /* Window containing the menu */
81 MENUITEM
*items
; /* Array of menu items */
82 UINT32 FocusedItem
; /* Currently focused item */
83 } POPUPMENU
, *LPPOPUPMENU
;
85 /* internal flags for menu tracking */
87 #define TF_ENDMENU 0x0001
88 #define TF_SUSPENDPOPUP 0x0002
89 #define TF_SKIPREMOVE 0x0004
94 HMENU32 hCurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
95 HMENU32 hTopMenu
; /* initial menu */
96 HWND32 hOwnerWnd
; /* where notifications are sent */
100 #define MENU_MAGIC 0x554d /* 'MU' */
105 /* Internal MENU_TrackMenu() flags */
106 #define TPM_INTERNAL 0xF0000000
107 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
108 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
110 /* popup menu shade thickness */
111 #define POPUP_XSHADE 4
112 #define POPUP_YSHADE 4
114 /* Space between 2 menu bar items */
115 int MENU_BAR_ITEMS_SPACE
= 12;
117 /* Minimum width of a tab character */
118 int MENU_TAB_SPACE
= 8;
120 /* Height of a separator item */
121 int SEPARATOR_HEIGHT
= 5;
123 /* (other menu->FocusedItem values give the position of the focused item) */
124 #define NO_SELECTED_ITEM 0xffff
126 #define IS_STRING_ITEM(flags) \
127 (!((flags) & (MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)))
128 #define IS_SYSTEM_MENU(menu) \
129 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
130 #define IS_SYSTEM_POPUP(menu) \
131 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
133 /* Dimension of the menu bitmaps */
134 static WORD check_bitmap_width
= 0, check_bitmap_height
= 0;
135 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
137 static HBITMAP32 hStdCheck
= 0;
138 static HBITMAP32 hStdMnArrow
= 0;
139 static HBRUSH32 hShadeBrush
= 0;
140 static HMENU32 MENU_DefSysPopup
= 0; /* Default system menu popup */
142 /* Use global popup window because there's no way 2 menus can
143 * be tracked at the same time. */
145 static WND
* pTopPopupWnd
= 0;
146 static UINT32 uSubPWndLevel
= 0;
148 /* Flag set by EndMenu() to force an exit from menu tracking */
149 static BOOL32 fEndMenu
= FALSE
;
152 /***********************************************************************
155 * Return the default system menu.
157 static HMENU32
MENU_CopySysPopup(void)
159 HMENU32 hMenu
= LoadMenuIndirect32A(SYSRES_GetResPtr(SYSRES_MENU_SYSMENU
));
162 POPUPMENU
* menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
163 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
167 fprintf( stderr
, "Unable to load default system menu\n" );
170 dprintf_menu( stddeb
, "MENU_CopySysPopup: returning %ld.\n", hMenu
);
176 /**********************************************************************
179 * Create a copy of the system menu. System menu in Windows is
180 * a special menu-bar with the single entry - system menu popup.
181 * This popup is presented to the outside world as a "system menu".
182 * However, the real system menu handle is sometimes seen in the
183 * WM_MENUSELECT paramemters (and Word 6 likes it this way).
185 HMENU32
MENU_GetSysMenu( HWND32 hWnd
, HMENU32 hPopupMenu
)
189 if ((hMenu
= CreateMenu32()))
191 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
192 menu
->wFlags
= MF_SYSMENU
;
195 if (hPopupMenu
== (HMENU32
)(-1))
196 hPopupMenu
= MENU_CopySysPopup();
197 else if( !hPopupMenu
) hPopupMenu
= MENU_DefSysPopup
;
201 InsertMenu32A( hMenu
, -1, MF_SYSMENU
| MF_POPUP
| MF_BYPOSITION
, hPopupMenu
, NULL
);
203 menu
->items
[0].item_flags
= MF_SYSMENU
| MF_POPUP
;
204 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hPopupMenu
);
205 menu
->wFlags
|= MF_SYSMENU
;
207 dprintf_menu(stddeb
,"GetSysMenu hMenu=%04x (%04x)\n", hMenu
, hPopupMenu
);
210 DestroyMenu32( hMenu
);
212 fprintf(stderr
, "failed to load system menu!\n");
217 /***********************************************************************
220 * Menus initialisation.
224 /* Load menu bitmaps */
226 if ((hStdCheck
= LoadBitmap32A( 0, (LPSTR
)MAKEINTRESOURCE(OBM_CHECK
) )))
230 GetObject32A( hStdCheck
, sizeof(bm
), &bm
);
231 check_bitmap_width
= bm
.bmWidth
;
232 check_bitmap_height
= bm
.bmHeight
;
234 if ((hStdMnArrow
= LoadBitmap32A(0,(LPSTR
)MAKEINTRESOURCE(OBM_MNARROW
))))
237 static unsigned char shade_bits
[16] = { 0x55, 0, 0xAA, 0,
241 GetObject32A( hStdMnArrow
, sizeof(bm
), &bm
);
242 arrow_bitmap_width
= bm
.bmWidth
;
243 arrow_bitmap_height
= bm
.bmHeight
;
245 if((hBitmap
= CreateBitmap32( 8, 8, 1, 1, shade_bits
)))
247 if((hShadeBrush
= CreatePatternBrush32( hBitmap
)))
249 DeleteObject32( hBitmap
);
250 if((MENU_DefSysPopup
= MENU_CopySysPopup())) return TRUE
;
255 return FALSE
; /* failure */
258 /***********************************************************************
259 * MENU_InitSysMenuPopup
261 * Grey the appropriate items in System menu.
263 void MENU_InitSysMenuPopup( HMENU32 hmenu
, DWORD style
, DWORD clsStyle
)
267 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
268 EnableMenuItem32( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
269 gray
= ((style
& WS_MAXIMIZE
) != 0);
270 EnableMenuItem32( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
271 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
272 EnableMenuItem32( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
273 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
274 EnableMenuItem32( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
275 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
276 EnableMenuItem32( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
277 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
278 EnableMenuItem32( hmenu
, SC_CLOSE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
282 /***********************************************************************
285 * Find a menu item. Return a pointer on the item, and modifies *hmenu
286 * in case the item was in a sub-menu.
288 static MENUITEM
*MENU_FindItem( HMENU32
*hmenu
, UINT32
*nPos
, UINT32 wFlags
)
293 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(*hmenu
))) return NULL
;
294 if (wFlags
& MF_BYPOSITION
)
296 if (*nPos
>= menu
->nItems
) return NULL
;
297 return &menu
->items
[*nPos
];
301 MENUITEM
*item
= menu
->items
;
302 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
304 if (item
->item_id
== *nPos
)
309 else if (item
->item_flags
& MF_POPUP
)
311 HMENU32 hsubmenu
= (HMENU32
)item
->item_id
;
312 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
324 /***********************************************************************
327 static void MENU_FreeItemData( MENUITEM
* item
)
331 if (IS_STRING_ITEM(item
->item_flags
) && item
->text
)
332 HeapFree( SystemHeap
, 0, item
->text
);
334 /* delete checkmark stuff */
336 if (item
->pCB
) HeapFree( SystemHeap
, 0, item
->pCB
);
339 /***********************************************************************
340 * MENU_FindItemByCoords
342 * Find the item at the specified coordinates (screen coords). Does
343 * not work for child windows and therefore should not be called for
344 * an arbitrary system menu.
346 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
,
347 POINT32 pt
, UINT32
*pos
)
353 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return NULL
;
354 pt
.x
-= wndPtr
->rectWindow
.left
;
355 pt
.y
-= wndPtr
->rectWindow
.top
;
357 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
359 if ((pt
.x
>= item
->rect
.left
) && (pt
.x
< item
->rect
.right
) &&
360 (pt
.y
>= item
->rect
.top
) && (pt
.y
< item
->rect
.bottom
))
370 /***********************************************************************
373 * Find the menu item selected by a key press.
374 * Return item id, -1 if none, -2 if we should close the menu.
376 static UINT32
MENU_FindItemByKey( HWND32 hwndOwner
, HMENU32 hmenu
,
377 UINT32 key
, BOOL32 forceMenuChar
)
379 dprintf_menu(stddeb
,"\tlooking for '%c' in [%04x]\n", (char)key
, (UINT16
)hmenu
);
381 if (!IsMenu32( hmenu
))
383 WND
* w
= WIN_FindWndPtr(hwndOwner
);
384 hmenu
= GetSubMenu32(w
->hSysMenu
, 0);
389 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
390 MENUITEM
*item
= menu
->items
;
398 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
400 if (IS_STRING_ITEM(item
->item_flags
))
402 char *p
= strchr( item
->text
, '&' );
403 if (p
&& (p
[1] != '&') && (toupper(p
[1]) == key
)) return i
;
407 menuchar
= SendMessage32A( hwndOwner
, WM_MENUCHAR
,
408 MAKEWPARAM( key
, menu
->wFlags
), hmenu
);
409 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
410 if (HIWORD(menuchar
) == 1) return (UINT32
)(-2);
416 /***********************************************************************
419 * Calculate the size of the menu item and store it in lpitem->rect.
421 static void MENU_CalcItemSize( HDC32 hdc
, MENUITEM
*lpitem
, HWND32 hwndOwner
,
422 INT32 orgX
, INT32 orgY
, BOOL32 menuBar
)
427 dprintf_menu( stddeb
, "MENU_CalcItemSize: HDC 0x%lx, item '%s', at "
428 "(%d, %d) %s\n", hdc
, lpitem
->text
, orgX
, orgY
,
429 menuBar
? "(MenuBar)" : "" );
431 SetRect32( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
433 if (lpitem
->item_flags
& MF_OWNERDRAW
)
435 MEASUREITEMSTRUCT32 mis
;
436 mis
.CtlType
= ODT_MENU
;
437 mis
.itemID
= lpitem
->item_id
;
438 mis
.itemData
= (DWORD
)lpitem
->text
;
441 SendMessage32A( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
442 lpitem
->rect
.bottom
+= mis
.itemHeight
;
443 lpitem
->rect
.right
+= mis
.itemWidth
;
444 dprintf_menu( stddeb
, "DrawMenuItem: MeasureItem %04x %dx%d!\n",
445 lpitem
->item_id
, mis
.itemWidth
, mis
.itemHeight
);
449 if (lpitem
->item_flags
& MF_SEPARATOR
)
451 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
457 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
458 if (lpitem
->item_flags
& MF_POPUP
)
459 lpitem
->rect
.right
+= arrow_bitmap_width
;
462 if (lpitem
->item_flags
& MF_BITMAP
)
465 if (GetObject32A( (HBITMAP32
)lpitem
->text
, sizeof(bm
), &bm
))
467 lpitem
->rect
.right
+= bm
.bmWidth
;
468 lpitem
->rect
.bottom
+= bm
.bmHeight
;
473 /* If we get here, then it must be a text item */
475 if (IS_STRING_ITEM( lpitem
->item_flags
))
477 dwSize
= GetTextExtent( hdc
, lpitem
->text
, strlen(lpitem
->text
) );
478 lpitem
->rect
.right
+= LOWORD(dwSize
);
479 lpitem
->rect
.bottom
+= MAX( HIWORD(dwSize
), SYSMETRICS_CYMENU
);
482 if (menuBar
) lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
483 else if ((p
= strchr( lpitem
->text
, '\t' )) != NULL
)
485 /* Item contains a tab (only meaningful in popup menus) */
486 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+
487 LOWORD( GetTextExtent( hdc
, lpitem
->text
,
488 (int)(p
- lpitem
->text
) ));
489 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
493 if (strchr( lpitem
->text
, '\b' ))
494 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
495 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
496 - arrow_bitmap_width
;
502 /***********************************************************************
503 * MENU_PopupMenuCalcSize
505 * Calculate the size of a popup menu.
507 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND32 hwndOwner
)
512 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
514 lppop
->Width
= lppop
->Height
= 0;
515 if (lppop
->nItems
== 0) return;
518 maxX
= SYSMETRICS_CXBORDER
;
519 while (start
< lppop
->nItems
)
521 lpitem
= &lppop
->items
[start
];
523 orgY
= SYSMETRICS_CYBORDER
;
524 maxTab
= maxTabWidth
= 0;
526 /* Parse items until column break or end of menu */
527 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
530 (lpitem
->item_flags
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
532 dprintf_menu( stddeb
, "MENU_PopupMenuCalcSize: calling "
533 "MENU_CalcItemSize on '%s', org=(%d, %d)\n",
534 lpitem
->text
, orgX
, orgY
);
538 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
539 if (lpitem
->item_flags
& MF_MENUBARBREAK
) orgX
++;
540 maxX
= MAX( maxX
, lpitem
->rect
.right
);
541 orgY
= lpitem
->rect
.bottom
;
542 if (IS_STRING_ITEM(lpitem
->item_flags
) && lpitem
->xTab
)
544 maxTab
= MAX( maxTab
, lpitem
->xTab
);
545 maxTabWidth
= MAX(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
549 /* Finish the column (set all items to the largest width found) */
550 maxX
= MAX( maxX
, maxTab
+ maxTabWidth
);
551 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
553 lpitem
->rect
.right
= maxX
;
554 if (IS_STRING_ITEM(lpitem
->item_flags
) && lpitem
->xTab
)
555 lpitem
->xTab
= maxTab
;
557 lppop
->Height
= MAX( lppop
->Height
, orgY
);
561 ReleaseDC32( 0, hdc
);
565 /***********************************************************************
566 * MENU_MenuBarCalcSize
568 * FIXME: Word 6 implements it's own MDI and it's 'close window' bitmap
569 * height is off by 1 pixel which causes lengthy window relocations when
570 * active document window is maximized/restored.
572 * Calculate the size of the menu bar.
574 static void MENU_MenuBarCalcSize( HDC32 hdc
, LPRECT32 lprect
,
575 LPPOPUPMENU lppop
, HWND32 hwndOwner
)
578 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
580 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
581 if (lppop
->nItems
== 0) return;
582 dprintf_menu(stddeb
,"MENU_MenuBarCalcSize left=%d top=%d right=%d bottom=%d\n",
583 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
584 lppop
->Width
= lprect
->right
- lprect
->left
;
589 while (start
< lppop
->nItems
)
591 lpitem
= &lppop
->items
[start
];
595 /* Parse items until line break or end of menu */
596 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
598 if ((helpPos
== -1) && (lpitem
->item_flags
& MF_HELP
)) helpPos
= i
;
600 (lpitem
->item_flags
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
603 dprintf_menu( stddeb
, "MENU_MenuBarCalcSize: calling "
604 "MENU_CalcItemSize on item '%s', org=(%d, %d)\n",
605 lpitem
->text
, orgX
, orgY
);
606 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
607 if (lpitem
->rect
.right
> lprect
->right
)
609 if (i
!= start
) break;
610 else lpitem
->rect
.right
= lprect
->right
;
612 maxY
= MAX( maxY
, lpitem
->rect
.bottom
);
613 orgX
= lpitem
->rect
.right
;
616 /* Finish the line (set all items to the largest height found) */
617 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
620 lprect
->bottom
= maxY
;
621 lppop
->Height
= lprect
->bottom
- lprect
->top
;
623 /* Flush right all items between the MF_HELP and the last item */
624 /* (if several lines, only move the last line) */
627 lpitem
= &lppop
->items
[lppop
->nItems
-1];
628 orgY
= lpitem
->rect
.top
;
629 orgX
= lprect
->right
;
630 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--)
632 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
633 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
634 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
635 lpitem
->rect
.right
= orgX
;
636 orgX
= lpitem
->rect
.left
;
641 /***********************************************************************
644 * Draw a single menu item.
646 static void MENU_DrawMenuItem( HWND32 hwnd
, HDC32 hdc
, MENUITEM
*lpitem
,
647 UINT32 height
, BOOL32 menuBar
)
651 if (lpitem
->item_flags
& MF_SYSMENU
)
653 if( !IsIconic32(hwnd
) ) {
655 NC_DrawSysButton95( hwnd
, hdc
,
657 (MF_HILITE
| MF_MOUSESELECT
) );
659 NC_DrawSysButton( hwnd
, hdc
,
661 (MF_HILITE
| MF_MOUSESELECT
) );
667 if (lpitem
->item_flags
& MF_OWNERDRAW
)
669 DRAWITEMSTRUCT32 dis
;
671 dprintf_menu( stddeb
, "DrawMenuItem: Ownerdraw!\n" );
672 dis
.CtlType
= ODT_MENU
;
673 dis
.itemID
= lpitem
->item_id
;
674 dis
.itemData
= (DWORD
)lpitem
->text
;
676 if (lpitem
->item_flags
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
677 if (lpitem
->item_flags
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
;
678 if (lpitem
->item_flags
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
679 dis
.itemAction
= ODA_DRAWENTIRE
| ODA_SELECT
| ODA_FOCUS
;
682 dis
.rcItem
= lpitem
->rect
;
683 SendMessage32A( hwnd
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
687 if (menuBar
&& (lpitem
->item_flags
& MF_SEPARATOR
)) return;
690 /* Draw the background */
691 if(TWEAK_Win95Look
) {
697 InflateRect32( &rect
, -1, -1 );
700 if (lpitem
->item_flags
& MF_HILITE
) {
702 r
.top
+= MENU_HighlightTopNudge
;
703 r
.bottom
+= MENU_HighlightBottomNudge
;
704 r
.left
+= MENU_HighlightLeftNudge
;
705 r
.right
+= MENU_HighlightRightNudge
;
706 FillRect32( hdc
, &r
, sysColorObjects
.hbrushHighlight
);
710 r
.top
+= MENU_HighlightTopNudge
;
711 r
.bottom
+= MENU_HighlightBottomNudge
;
712 r
.left
+= MENU_HighlightLeftNudge
;
713 r
.right
+= MENU_HighlightRightNudge
;
714 FillRect32( hdc
, &r
, sysColorObjects
.hbrushMenu
);
717 SetBkMode32( hdc
, TRANSPARENT
);
719 /* Draw the separator bar (if any) */
721 if (!menuBar
&& (lpitem
->item_flags
& MF_MENUBARBREAK
))
723 SelectObject32( hdc
, sysColorObjects
.hpenWindowFrame
);
724 MoveTo( hdc
, rect
.left
, 0 );
725 LineTo32( hdc
, rect
.left
, height
);
727 if (lpitem
->item_flags
& MF_SEPARATOR
)
730 TWEAK_DrawMenuSeparator95(hdc
, rect
.left
+ 1,
731 rect
.top
+ SEPARATOR_HEIGHT
/ 2 + 1,
734 SelectObject32( hdc
, sysColorObjects
.hpenWindowFrame
);
735 MoveTo( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
736 LineTo32( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
744 if (lpitem
->item_flags
& MF_HILITE
)
746 if (lpitem
->item_flags
& MF_GRAYED
)
747 SetTextColor32( hdc
, GetSysColor32( COLOR_GRAYTEXT
) );
749 SetTextColor32( hdc
, GetSysColor32( COLOR_HIGHLIGHTTEXT
) );
750 SetBkColor32( hdc
, GetSysColor32( COLOR_HIGHLIGHT
) );
754 if (lpitem
->item_flags
& MF_GRAYED
)
755 SetTextColor32( hdc
, GetSysColor32( COLOR_GRAYTEXT
) );
757 SetTextColor32( hdc
, GetSysColor32( COLOR_MENUTEXT
) );
758 SetBkColor32( hdc
, GetSysColor32( COLOR_MENU
) );
763 INT32 y
= rect
.top
+ rect
.bottom
;
765 /* Draw the check mark
767 * Custom checkmark bitmaps are monochrome but not always 1bpp.
768 * In this case we want GRAPH_DrawBitmap() to copy a plane which
769 * is 1 for a white pixel and 0 for a black one.
772 if (lpitem
->item_flags
& MF_CHECKED
)
773 GRAPH_DrawBitmap( hdc
, lpitem
->pCB
? lpitem
->pCB
->hCheckBit
774 : hStdCheck
, rect
.left
, (y
- check_bitmap_height
) / 2,
775 0, 0, check_bitmap_width
, check_bitmap_height
, TRUE
);
776 else if (lpitem
->pCB
)
777 GRAPH_DrawBitmap( hdc
, lpitem
->pCB
->hUnCheckBit
, rect
.left
,
778 (y
- check_bitmap_height
) / 2, 0, 0,
779 check_bitmap_width
, check_bitmap_height
, TRUE
);
781 /* Draw the popup-menu arrow */
783 if (lpitem
->item_flags
& MF_POPUP
)
785 GRAPH_DrawBitmap( hdc
, hStdMnArrow
,
786 rect
.right
-arrow_bitmap_width
-1,
787 (y
- arrow_bitmap_height
) / 2, 0, 0,
788 arrow_bitmap_width
, arrow_bitmap_height
, FALSE
);
791 rect
.left
+= check_bitmap_width
;
792 rect
.right
-= arrow_bitmap_width
;
795 /* Draw the item text or bitmap */
797 if (lpitem
->item_flags
& MF_BITMAP
)
799 GRAPH_DrawBitmap( hdc
, (HBITMAP32
)lpitem
->text
,
800 rect
.left
, rect
.top
, 0, 0,
801 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
, FALSE
);
804 /* No bitmap - process text if present */
805 else if (IS_STRING_ITEM(lpitem
->item_flags
))
811 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
812 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
813 i
= strlen( lpitem
->text
);
815 rect
.top
+= MENU_BarItemTopNudge
;
816 rect
.left
+= MENU_BarItemLeftNudge
;
820 for (i
= 0; lpitem
->text
[i
]; i
++)
821 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
824 rect
.top
+= MENU_ItemTopNudge
;
825 rect
.left
+= MENU_ItemLeftNudge
;
828 if(!TWEAK_Win95Look
|| !(lpitem
->item_flags
& MF_GRAYED
)) {
829 DrawText32A( hdc
, lpitem
->text
, i
, &rect
,
830 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
837 SetTextColor32(hdc
, RGB(0xff, 0xff, 0xff));
838 DrawText32A( hdc
, lpitem
->text
, i
, &rect
,
839 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
844 SetTextColor32(hdc
, RGB(0x80, 0x80, 0x80));
845 DrawText32A( hdc
, lpitem
->text
, i
, &rect
,
846 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
849 if (lpitem
->text
[i
]) /* There's a tab or flush-right char */
851 if (lpitem
->text
[i
] == '\t')
853 rect
.left
= lpitem
->xTab
;
854 DrawText32A( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
,
855 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
857 else DrawText32A( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
,
858 DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
);
864 /***********************************************************************
867 * Paint a popup menu.
869 static void MENU_DrawPopupMenu( HWND32 hwnd
, HDC32 hdc
, HMENU32 hmenu
)
871 HBRUSH32 hPrevBrush
= 0;
874 GetClientRect32( hwnd
, &rect
);
875 rect
.bottom
-= POPUP_YSHADE
* SYSMETRICS_CYBORDER
;
876 rect
.right
-= POPUP_XSHADE
* SYSMETRICS_CXBORDER
;
878 if((hPrevBrush
= SelectObject32( hdc
, sysColorObjects
.hbrushMenu
)))
882 Rectangle32( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
884 hPrevPen
= SelectObject32( hdc
, GetStockObject32( NULL_PEN
) );
891 if(!TWEAK_Win95Look
) {
892 SelectObject32( hdc
, hShadeBrush
);
893 SetBkMode32( hdc
, TRANSPARENT
);
894 ropPrev
= SetROP232( hdc
, R2_MASKPEN
);
896 i
= rect
.right
; /* why SetBrushOrg() doesn't? */
897 PatBlt32( hdc
, i
& 0xfffffffe,
898 rect
.top
+ POPUP_YSHADE
*SYSMETRICS_CYBORDER
,
899 i
%2 + POPUP_XSHADE
*SYSMETRICS_CXBORDER
,
900 rect
.bottom
- rect
.top
, 0x00a000c9 );
902 PatBlt32( hdc
, rect
.left
+ POPUP_XSHADE
*SYSMETRICS_CXBORDER
,
903 i
& 0xfffffffe,rect
.right
- rect
.left
,
904 i
%2 + POPUP_YSHADE
*SYSMETRICS_CYBORDER
, 0x00a000c9 );
905 SelectObject32( hdc
, hPrevPen
);
906 SelectObject32( hdc
, hPrevBrush
);
907 SetROP232( hdc
, ropPrev
);
910 TWEAK_DrawReliefRect95(hdc
, &rect
);
912 /* draw menu items */
914 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
915 if (menu
&& menu
->nItems
)
920 for (u
= menu
->nItems
, item
= menu
->items
; u
> 0; u
--, item
++)
921 MENU_DrawMenuItem( hwnd
, hdc
, item
, menu
->Height
, FALSE
);
924 } else SelectObject32( hdc
, hPrevBrush
);
929 /***********************************************************************
932 * Paint a menu bar. Returns the height of the menu bar.
934 UINT32
MENU_DrawMenuBar( HDC32 hDC
, LPRECT32 lprect
, HWND32 hwnd
,
935 BOOL32 suppress_draw
)
939 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
941 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( (HMENU16
)wndPtr
->wIDmenu
);
942 if (lppop
== NULL
|| lprect
== NULL
) return SYSMETRICS_CYMENU
;
943 dprintf_menu(stddeb
,"MENU_DrawMenuBar(%04x, %p, %p); !\n",
945 if (lppop
->Height
== 0) MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
946 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
947 if (suppress_draw
) return lppop
->Height
;
952 FillRect32(hDC
, lprect
, sysColorObjects
.hbrushMenu
);
954 if(!TWEAK_Win95Look
) {
955 SelectObject32( hDC
, sysColorObjects
.hpenWindowFrame
);
956 MoveTo( hDC
, lprect
->left
, lprect
->bottom
);
957 LineTo32( hDC
, lprect
->right
, lprect
->bottom
);
960 if (lppop
->nItems
== 0) return SYSMETRICS_CYMENU
;
961 for (i
= 0; i
< lppop
->nItems
; i
++)
963 MENU_DrawMenuItem( hwnd
, hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
);
965 return lppop
->Height
;
969 /***********************************************************************
970 * MENU_PatchResidentPopup
972 BOOL32
MENU_PatchResidentPopup( HQUEUE16 checkQueue
, WND
* wndOwner
)
974 /* checkQueue tells us whether we have to disconnect top
975 * popup from the wndOwner or (if the latter is NULL) from
976 * the checkQueue. If checkQueue is 0 then we need to set
977 * popup owner to the wndOwner.
979 * This is supposed to be called when top popup is hidden. */
985 dprintf_menu(stddeb
,"patching resident popup: %04x, %08x\n",
986 checkQueue
, (unsigned) wndOwner
);
989 if( pTopPopupWnd
->owner
== wndOwner
)
991 if( checkQueue
) pTopPopupWnd
->owner
= NULL
;
995 /* switch to the new owner */
997 if( wndOwner
->hmemTaskQ
== pTopPopupWnd
->hmemTaskQ
)
999 hTask
= QUEUE_GetQueueTask( wndOwner
->hmemTaskQ
);
1001 else if( pTopPopupWnd
->hmemTaskQ
== checkQueue
)
1003 /* switch to the different task */
1005 hTask
= QUEUE_GetQueueTask( pTopPopupWnd
->hmemTaskQ
);
1006 hTask
= TASK_GetNextTask( hTask
);
1011 TDB
* task
= (TDB
*)GlobalLock16( hTask
);
1013 pTopPopupWnd
->owner
= wndOwner
;
1016 pTopPopupWnd
->hInstance
= task
->hInstance
;
1017 pTopPopupWnd
->hmemTaskQ
= task
->hQueue
;
1020 else dprintf_menu(stddeb
,"failed to patch resident popup.\n");
1026 /***********************************************************************
1029 * Display a popup menu.
1031 static BOOL32
MENU_ShowPopup( HWND32 hwndOwner
, HMENU32 hmenu
, UINT32 id
,
1032 INT32 x
, INT32 y
, INT32 xanchor
, INT32 yanchor
)
1035 WND
*wndOwner
= NULL
;
1037 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
1038 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1040 menu
->items
[menu
->FocusedItem
].item_flags
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1041 menu
->FocusedItem
= NO_SELECTED_ITEM
;
1044 SendMessage16( hwndOwner
, WM_INITMENUPOPUP
, (WPARAM16
)hmenu
,
1045 MAKELONG( id
, (menu
->wFlags
& MF_SYSMENU
) ? 1 : 0 ));
1047 if( (wndOwner
= WIN_FindWndPtr( hwndOwner
)) )
1049 UINT32 width
, height
;
1051 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
1053 /* adjust popup menu pos so that it fits within the desktop */
1055 width
= menu
->Width
+ SYSMETRICS_CXBORDER
;
1056 height
= menu
->Height
+ SYSMETRICS_CYBORDER
;
1058 if( x
+ width
> SYSMETRICS_CXSCREEN
)
1061 x
-= width
- xanchor
;
1062 if( x
+ width
> SYSMETRICS_CXSCREEN
)
1063 x
= SYSMETRICS_CXSCREEN
- width
;
1067 if( y
+ height
> SYSMETRICS_CYSCREEN
)
1070 y
-= height
+ yanchor
;
1071 if( y
+ height
> SYSMETRICS_CYSCREEN
)
1072 y
= SYSMETRICS_CYSCREEN
- height
;
1076 width
+= POPUP_XSHADE
* SYSMETRICS_CXBORDER
; /* add space for shading */
1077 height
+= POPUP_YSHADE
* SYSMETRICS_CYBORDER
;
1079 /* NOTE: In Windows, top menu popup is not owned. */
1080 if (!pTopPopupWnd
) /* create top level popup menu window */
1082 assert( uSubPWndLevel
== 0 );
1084 pTopPopupWnd
= WIN_FindWndPtr(CreateWindow32A( POPUPMENU_CLASS_ATOM
, NULL
,
1085 WS_POPUP
, x
, y
, width
, height
,
1086 hwndOwner
, 0, wndOwner
->hInstance
,
1088 if (!pTopPopupWnd
) return FALSE
;
1089 menu
->hWnd
= pTopPopupWnd
->hwndSelf
;
1094 /* create a new window for the submenu */
1096 menu
->hWnd
= CreateWindow32A( POPUPMENU_CLASS_ATOM
, NULL
,
1097 WS_POPUP
, x
, y
, width
, height
,
1098 menu
->hWnd
, 0, wndOwner
->hInstance
,
1100 if( !menu
->hWnd
) return FALSE
;
1102 else /* top level popup menu window already exists */
1104 menu
->hWnd
= pTopPopupWnd
->hwndSelf
;
1106 MENU_PatchResidentPopup( 0, wndOwner
);
1107 SendMessage16( pTopPopupWnd
->hwndSelf
, MM_SETMENUHANDLE
, (WPARAM16
)hmenu
, 0L);
1109 /* adjust its size */
1111 SetWindowPos32( menu
->hWnd
, 0, x
, y
, width
, height
,
1112 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_NOREDRAW
);
1115 uSubPWndLevel
++; /* menu level counter */
1117 /* Display the window */
1119 SetWindowPos32( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
1120 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1121 UpdateWindow32( menu
->hWnd
);
1128 /***********************************************************************
1131 static void MENU_SelectItem( HWND32 hwndOwner
, HMENU32 hmenu
, UINT32 wIndex
,
1132 BOOL32 sendMenuSelect
)
1137 lppop
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1138 if (!lppop
->nItems
) return;
1140 if ((wIndex
!= NO_SELECTED_ITEM
) &&
1141 (lppop
->items
[wIndex
].item_flags
& MF_SEPARATOR
))
1142 wIndex
= NO_SELECTED_ITEM
;
1144 if (lppop
->FocusedItem
== wIndex
) return;
1145 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC32( lppop
->hWnd
);
1146 else hdc
= GetDCEx32( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1148 /* Clear previous highlighted item */
1149 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1151 lppop
->items
[lppop
->FocusedItem
].item_flags
&=~(MF_HILITE
|MF_MOUSESELECT
);
1152 MENU_DrawMenuItem(lppop
->hWnd
,hdc
,&lppop
->items
[lppop
->FocusedItem
],
1153 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
) );
1156 /* Highlight new item (if any) */
1157 lppop
->FocusedItem
= wIndex
;
1158 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1160 lppop
->items
[lppop
->FocusedItem
].item_flags
|= MF_HILITE
;
1161 MENU_DrawMenuItem( lppop
->hWnd
, hdc
, &lppop
->items
[lppop
->FocusedItem
],
1162 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
) );
1164 SendMessage16( hwndOwner
, WM_MENUSELECT
,
1165 lppop
->items
[lppop
->FocusedItem
].item_id
,
1166 MAKELONG( lppop
->items
[lppop
->FocusedItem
].item_flags
| MF_MOUSESELECT
, hmenu
));
1168 else if (sendMenuSelect
)
1169 SendMessage16( hwndOwner
, WM_MENUSELECT
, hmenu
,
1170 MAKELONG( lppop
->wFlags
| MF_MOUSESELECT
, hmenu
) );
1172 ReleaseDC32( lppop
->hWnd
, hdc
);
1176 /***********************************************************************
1177 * MENU_MoveSelection
1179 * Moves currently selected item according to the offset parameter.
1180 * If there is no selection then it should select the last item if
1181 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1183 static void MENU_MoveSelection( HWND32 hwndOwner
, HMENU32 hmenu
, INT32 offset
)
1188 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1189 if (!menu
->items
) return;
1191 if ( menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1193 if( menu
->nItems
== 1 ) return; else
1194 for (i
= menu
->FocusedItem
+ offset
; i
>= 0 && i
< menu
->nItems
1196 if (!(menu
->items
[i
].item_flags
& MF_SEPARATOR
))
1198 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
1203 for ( i
= (offset
> 0) ? 0 : menu
->nItems
- 1;
1204 i
>= 0 && i
< menu
->nItems
; i
+= offset
)
1205 if (!(menu
->items
[i
].item_flags
& MF_SEPARATOR
))
1207 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
1213 /**********************************************************************
1216 * Set an item flags, id and text ptr. Called by InsertMenu() and
1219 static BOOL32
MENU_SetItemData( MENUITEM
*item
, UINT32 flags
, UINT32 id
,
1222 LPSTR prevText
= IS_STRING_ITEM(item
->item_flags
) ? item
->text
: NULL
;
1224 dprintf_menu(stddeb
,"SetItemData: %04x [%08x] '%s' -> %04x [%08x] '%s'\n",
1225 item
->item_flags
, item
->item_id
, prevText
? prevText
: "",
1226 flags
, id
, (IS_STRING_ITEM(flags
) && str
) ? str
: "" );
1228 if (IS_STRING_ITEM(flags
))
1232 flags
|= MF_SEPARATOR
;
1238 /* Item beginning with a backspace is a help item */
1244 if (!(text
= HEAP_strdupA( SystemHeap
, 0, str
))) return FALSE
;
1248 else if (flags
& MF_BITMAP
) item
->text
= (LPSTR
)(HBITMAP32
)LOWORD(str
);
1249 else if (flags
& MF_OWNERDRAW
) item
->text
= (LPSTR
)str
;
1250 else item
->text
= NULL
;
1252 if (item
->item_flags
& MF_POPUP
&& item
->item_id
!= id
)
1253 DestroyMenu32( (HMENU32
)item
->item_id
); /* ModifyMenu() spec */
1255 if (flags
& MF_POPUP
)
1257 POPUPMENU
* menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR((UINT16
)id
);
1258 if( menu
&& menu
->wMagic
== MENU_MAGIC
) menu
->wFlags
|= MF_POPUP
;
1260 return (item
->item_id
= item
->item_flags
= FALSE
);
1263 item
->item_flags
= flags
& ~(MF_HILITE
| MF_MOUSESELECT
);
1266 SetRectEmpty32( &item
->rect
);
1267 if (prevText
) HeapFree( SystemHeap
, 0, prevText
);
1272 /**********************************************************************
1275 * Insert a new item into a menu.
1277 static MENUITEM
*MENU_InsertItem( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
)
1282 if (!(menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
)))
1284 dprintf_menu( stddeb
, "MENU_InsertItem: %04x not a menu handle\n",
1289 /* Find where to insert new item */
1291 if ((flags
& MF_BYPOSITION
) &&
1292 ((pos
== (UINT32
)-1) || (pos
== menu
->nItems
)))
1294 /* Special case: append to menu */
1295 /* Some programs specify the menu length to do that */
1300 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
1302 dprintf_menu( stddeb
, "MENU_InsertItem: item %x not found\n",
1306 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
)))
1308 dprintf_menu(stddeb
,"MENU_InsertItem: %04x not a menu handle\n",
1314 /* Create new items array */
1316 newItems
= HeapAlloc( SystemHeap
, 0, sizeof(MENUITEM
) * (menu
->nItems
+1) );
1319 dprintf_menu( stddeb
, "MENU_InsertItem: allocation failed\n" );
1322 if (menu
->nItems
> 0)
1324 /* Copy the old array into the new */
1325 if (pos
> 0) memcpy( newItems
, menu
->items
, pos
* sizeof(MENUITEM
) );
1326 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &menu
->items
[pos
],
1327 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
1328 HeapFree( SystemHeap
, 0, menu
->items
);
1330 menu
->items
= newItems
;
1332 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
1333 return &newItems
[pos
];
1337 /**********************************************************************
1338 * MENU_ParseResource
1340 * Parse a standard menu resource and add items to the menu.
1341 * Return a pointer to the end of the resource.
1343 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU32 hMenu
, BOOL32 unicode
)
1350 flags
= GET_WORD(res
);
1351 res
+= sizeof(WORD
);
1352 if (!(flags
& MF_POPUP
))
1355 res
+= sizeof(WORD
);
1357 if (!IS_STRING_ITEM(flags
))
1358 fprintf( stderr
, "MENU_ParseResource: not a string item %04x\n",
1361 if (!unicode
) res
+= strlen(str
) + 1;
1362 else res
+= (lstrlen32W((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1363 if (flags
& MF_POPUP
)
1365 HMENU32 hSubMenu
= CreatePopupMenu32();
1366 if (!hSubMenu
) return NULL
;
1367 if (!(res
= MENU_ParseResource( res
, hSubMenu
, unicode
)))
1369 if (!unicode
) AppendMenu32A( hMenu
, flags
, (UINT32
)hSubMenu
, str
);
1370 else AppendMenu32W( hMenu
, flags
, (UINT32
)hSubMenu
, (LPCWSTR
)str
);
1372 else /* Not a popup */
1374 if (!unicode
) AppendMenu32A( hMenu
, flags
, id
, *str
? str
: NULL
);
1375 else AppendMenu32W( hMenu
, flags
, id
,
1376 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1378 } while (!(flags
& MF_END
));
1383 /***********************************************************************
1386 * Return the handle of the selected sub-popup menu (if any).
1388 static HMENU32
MENU_GetSubPopup( HMENU32 hmenu
)
1393 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1395 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return 0;
1397 item
= &menu
->items
[menu
->FocusedItem
];
1398 if ((item
->item_flags
& (MF_POPUP
| MF_MOUSESELECT
))
1399 == (MF_POPUP
| MF_MOUSESELECT
))
1400 return (HMENU32
)item
->item_id
;
1405 /***********************************************************************
1406 * MENU_HideSubPopups
1408 * Hide the sub-popup menus of this menu.
1410 static void MENU_HideSubPopups( HWND32 hwndOwner
, HMENU32 hmenu
,
1411 BOOL32 sendMenuSelect
)
1413 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);;
1415 if (menu
&& uSubPWndLevel
)
1421 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1423 item
= &menu
->items
[menu
->FocusedItem
];
1424 if (!(item
->item_flags
& MF_POPUP
) ||
1425 !(item
->item_flags
& MF_MOUSESELECT
)) return;
1426 item
->item_flags
&= ~MF_MOUSESELECT
;
1427 hsubmenu
= (HMENU32
)item
->item_id
;
1430 submenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hsubmenu
);
1431 MENU_HideSubPopups( hwndOwner
, hsubmenu
, FALSE
);
1432 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, sendMenuSelect
);
1434 if (submenu
->hWnd
== pTopPopupWnd
->hwndSelf
)
1436 ShowWindow32( submenu
->hWnd
, SW_HIDE
);
1441 DestroyWindow32( submenu
->hWnd
);
1448 /***********************************************************************
1451 * Display the sub-menu of the selected item of this menu.
1452 * Return the handle of the submenu, or hmenu if no submenu to display.
1454 static HMENU32
MENU_ShowSubPopup( HWND32 hwndOwner
, HMENU32 hmenu
,
1455 BOOL32 selectFirst
)
1462 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return hmenu
;
1464 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
)) ||
1465 (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return hmenu
;
1467 item
= &menu
->items
[menu
->FocusedItem
];
1468 if (!(item
->item_flags
& MF_POPUP
) ||
1469 (item
->item_flags
& (MF_GRAYED
| MF_DISABLED
))) return hmenu
;
1470 item
->item_flags
|= MF_MOUSESELECT
;
1472 if (IS_SYSTEM_MENU(menu
))
1474 MENU_InitSysMenuPopup((HMENU16
)item
->item_id
, wndPtr
->dwStyle
, wndPtr
->class->style
);
1476 NC_GetSysPopupPos( wndPtr
, &rect
);
1477 rect
.top
= rect
.bottom
;
1478 rect
.right
= SYSMETRICS_CXSIZE
; rect
.bottom
= SYSMETRICS_CYSIZE
;
1482 if (menu
->wFlags
& MF_POPUP
)
1484 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.right
-arrow_bitmap_width
;
1485 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.top
;
1486 rect
.right
= item
->rect
.left
- item
->rect
.right
+ 2*arrow_bitmap_width
;
1487 rect
.bottom
= item
->rect
.top
- item
->rect
.bottom
;
1491 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.left
;
1492 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.bottom
;
1493 rect
.right
= item
->rect
.right
- item
->rect
.left
;
1494 rect
.bottom
= item
->rect
.bottom
- item
->rect
.top
;
1498 MENU_ShowPopup( hwndOwner
, (HMENU16
)item
->item_id
, menu
->FocusedItem
,
1499 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1501 MENU_MoveSelection( hwndOwner
, (HMENU32
)item
->item_id
, ITEM_NEXT
);
1502 return (HMENU32
)item
->item_id
;
1505 /***********************************************************************
1508 * Walks menu chain trying to find a menu pt maps to.
1510 static HMENU32
MENU_PtMenu( HMENU32 hMenu
, POINT16 pt
)
1512 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hMenu
);
1513 register UINT32 ht
= menu
->FocusedItem
;
1515 #define HAS_POPUP(item) (((item).item_flags & (MF_POPUP | MF_MOUSESELECT)) \
1516 == (MF_POPUP | MF_MOUSESELECT))
1517 /* try subpopup first (if any) */
1518 ht
= (ht
!= NO_SELECTED_ITEM
&& HAS_POPUP(menu
->items
[ht
]))
1519 ? (UINT32
)MENU_PtMenu( menu
->items
[ht
].item_id
, pt
) : 0;
1522 if( !ht
) /* check the current window (avoiding WM_HITTEST) */
1524 ht
= (UINT32
)NC_HandleNCHitTest( menu
->hWnd
, pt
);
1525 if( menu
->wFlags
& MF_POPUP
)
1526 ht
= (ht
!= (UINT32
)HTNOWHERE
&&
1527 ht
!= (UINT32
)HTERROR
) ? (UINT32
)hMenu
: 0;
1530 WND
* wndPtr
= WIN_FindWndPtr(menu
->hWnd
);
1532 ht
= ( ht
== HTSYSMENU
) ? (UINT32
)(wndPtr
->hSysMenu
)
1533 : ( ht
== HTMENU
) ? (UINT32
)(wndPtr
->wIDmenu
) : 0;
1539 /***********************************************************************
1540 * MENU_ExecFocusedItem
1542 * Execute a menu item (for instance when user pressed Enter).
1543 * Return TRUE if we can go on with menu tracking.
1545 static BOOL32
MENU_ExecFocusedItem( MTRACKER
* pmt
, HMENU32 hMenu
)
1548 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hMenu
);
1549 if (!menu
|| !menu
->nItems
||
1550 (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return TRUE
;
1552 item
= &menu
->items
[menu
->FocusedItem
];
1553 if (!(item
->item_flags
& MF_POPUP
))
1555 if (!(item
->item_flags
& (MF_GRAYED
| MF_DISABLED
)))
1557 if( menu
->wFlags
& MF_SYSMENU
)
1559 PostMessage16( pmt
->hOwnerWnd
, WM_SYSCOMMAND
, item
->item_id
,
1560 MAKELPARAM((INT16
)pmt
->pt
.x
, (INT16
)pmt
->pt
.y
) );
1563 PostMessage16( pmt
->hOwnerWnd
, WM_COMMAND
,
1571 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hMenu
, TRUE
);
1577 /***********************************************************************
1578 * MENU_SwitchTracking
1580 * Helper function for menu navigation routines.
1582 static void MENU_SwitchTracking( MTRACKER
* pmt
, HMENU32 hPtMenu
, UINT32 id
)
1584 POPUPMENU
*ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
1585 POPUPMENU
*topmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( pmt
->hTopMenu
);
1587 if( pmt
->hTopMenu
!= hPtMenu
&&
1588 !((ptmenu
->wFlags
| topmenu
->wFlags
) & MF_POPUP
) )
1590 /* both are top level menus (system and menu-bar) */
1592 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
1593 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
);
1594 pmt
->hTopMenu
= hPtMenu
;
1596 else MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
1597 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, id
, TRUE
);
1601 /***********************************************************************
1604 * Return TRUE if we can go on with menu tracking.
1606 static BOOL32
MENU_ButtonDown( MTRACKER
* pmt
, HMENU32 hPtMenu
)
1611 POPUPMENU
*ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
1614 if( IS_SYSTEM_MENU(ptmenu
) )
1615 item
= ptmenu
->items
;
1617 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
1621 if( ptmenu
->FocusedItem
== id
)
1623 /* nothing to do with already selected non-popup */
1624 if( !(item
->item_flags
& MF_POPUP
) ) return TRUE
;
1626 if( item
->item_flags
& MF_MOUSESELECT
)
1628 if( ptmenu
->wFlags
& MF_POPUP
)
1630 /* hide selected subpopup */
1632 MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, TRUE
);
1633 pmt
->hCurrentMenu
= hPtMenu
;
1636 return FALSE
; /* shouldn't get here */
1639 else MENU_SwitchTracking( pmt
, hPtMenu
, id
);
1641 /* try to display a subpopup */
1643 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
1646 else dprintf_menu(stddeb
,"\tunable to find clicked item!\n");
1651 /***********************************************************************
1654 * Return TRUE if we can go on with menu tracking.
1656 static BOOL32
MENU_ButtonUp( MTRACKER
* pmt
, HMENU32 hPtMenu
)
1661 POPUPMENU
*ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
1664 if( IS_SYSTEM_MENU(ptmenu
) )
1665 item
= ptmenu
->items
;
1667 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
1669 if( ptmenu
->FocusedItem
== id
)
1671 if( !(item
->item_flags
& MF_POPUP
) )
1672 return MENU_ExecFocusedItem( pmt
, hPtMenu
);
1673 hPtMenu
= (HMENU32
)item
->item_id
;
1674 if( hPtMenu
== pmt
->hCurrentMenu
)
1676 /* Select first item of sub-popup */
1678 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, NO_SELECTED_ITEM
, FALSE
);
1679 MENU_MoveSelection( pmt
->hOwnerWnd
, hPtMenu
, ITEM_NEXT
);
1688 /***********************************************************************
1691 * Return TRUE if we can go on with menu tracking.
1693 static BOOL32
MENU_MouseMove( MTRACKER
* pmt
, HMENU32 hPtMenu
)
1695 UINT32 id
= NO_SELECTED_ITEM
;
1696 POPUPMENU
*ptmenu
= NULL
;
1700 ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
1701 if( IS_SYSTEM_MENU(ptmenu
) )
1704 MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
1707 if( id
== NO_SELECTED_ITEM
)
1709 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
1710 NO_SELECTED_ITEM
, TRUE
);
1712 else if( ptmenu
->FocusedItem
!= id
)
1714 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
1715 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
1721 /***********************************************************************
1724 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
1726 static LRESULT
MENU_DoNextMenu( MTRACKER
* pmt
, UINT32 vk
)
1728 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( pmt
->hTopMenu
);
1730 if( (vk
== VK_LEFT
&& menu
->FocusedItem
== 0 ) ||
1731 (vk
== VK_RIGHT
&& menu
->FocusedItem
== menu
->nItems
- 1))
1737 LRESULT l
= SendMessage16( pmt
->hOwnerWnd
, WM_NEXTMENU
, (WPARAM16
)vk
,
1738 (IS_SYSTEM_MENU(menu
)) ? GetSubMenu16(pmt
->hTopMenu
,0) : pmt
->hTopMenu
);
1740 dprintf_menu(stddeb
,"NextMenu: %04x [%04x] -> %04x [%04x]\n",
1741 (UINT16
)pmt
->hCurrentMenu
, (UINT16
)pmt
->hOwnerWnd
, LOWORD(l
), HIWORD(l
) );
1745 wndPtr
= WIN_FindWndPtr(pmt
->hOwnerWnd
);
1747 hNewWnd
= pmt
->hOwnerWnd
;
1748 if( IS_SYSTEM_MENU(menu
) )
1750 /* switch to the menu bar */
1752 if( wndPtr
->dwStyle
& WS_CHILD
|| !wndPtr
->wIDmenu
)
1755 hNewMenu
= wndPtr
->wIDmenu
;
1758 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hNewMenu
);
1759 id
= menu
->nItems
- 1;
1762 else if( wndPtr
->dwStyle
& WS_SYSMENU
)
1764 /* switch to the system menu */
1765 hNewMenu
= wndPtr
->hSysMenu
;
1769 else /* application returned a new menu to switch to */
1771 hNewMenu
= LOWORD(l
); hNewWnd
= HIWORD(l
);
1773 if( IsMenu32(hNewMenu
) && IsWindow32(hNewWnd
) )
1775 wndPtr
= WIN_FindWndPtr(hNewWnd
);
1777 if( wndPtr
->dwStyle
& WS_SYSMENU
&&
1778 GetSubMenu16(wndPtr
->hSysMenu
, 0) == hNewMenu
)
1780 /* get the real system menu */
1781 hNewMenu
= wndPtr
->hSysMenu
;
1783 else if( wndPtr
->dwStyle
& WS_CHILD
|| wndPtr
->wIDmenu
!= hNewMenu
)
1785 /* FIXME: Not sure what to do here, perhaps,
1786 * try to track hNewMenu as a popup? */
1788 dprintf_menu(stddeb
,"MENU_DoNextMenu() got confused.\n");
1795 if( hNewMenu
!= pmt
->hTopMenu
)
1797 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
);
1798 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
1799 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
1802 if( hNewWnd
!= pmt
->hOwnerWnd
)
1805 pmt
->hOwnerWnd
= hNewWnd
;
1806 EVENT_Capture( pmt
->hOwnerWnd
, HTMENU
);
1809 pmt
->hTopMenu
= pmt
->hCurrentMenu
= hNewMenu
; /* all subpopups are hidden */
1810 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, id
, TRUE
);
1817 /***********************************************************************
1820 * The idea is not to show the popup if the next input message is
1821 * going to hide it anyway.
1823 static BOOL32
MENU_SuspendPopup( MTRACKER
* pmt
, UINT16 uMsg
)
1827 msg
.hwnd
= pmt
->hOwnerWnd
;
1829 PeekMessage16( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
1830 pmt
->trackFlags
|= TF_SKIPREMOVE
;
1835 PeekMessage16( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
1836 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
1838 PeekMessage16( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
1839 PeekMessage16( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
1840 if( msg
.message
== WM_KEYDOWN
&&
1841 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
1843 pmt
->trackFlags
|= TF_SUSPENDPOPUP
;
1850 /* failures go through this */
1851 pmt
->trackFlags
&= ~TF_SUSPENDPOPUP
;
1855 /***********************************************************************
1858 * Handle a VK_LEFT key event in a menu.
1860 static void MENU_KeyLeft( MTRACKER
* pmt
)
1863 HMENU32 hmenutmp
, hmenuprev
;
1865 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
1866 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenutmp
);
1868 /* close topmost popup */
1869 while (hmenutmp
!= pmt
->hCurrentMenu
)
1871 hmenuprev
= hmenutmp
;
1872 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
1875 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
);
1876 pmt
->hCurrentMenu
= hmenuprev
;
1878 if ( (hmenuprev
== pmt
->hTopMenu
) && !(menu
->wFlags
& MF_POPUP
) )
1880 /* move menu bar selection if no more popups are left */
1882 if( !MENU_DoNextMenu( pmt
, VK_LEFT
) )
1883 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_PREV
);
1885 if ( hmenuprev
!= hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
1887 /* A sublevel menu was displayed - display the next one
1888 * unless there is another displacement coming up */
1890 if( !MENU_SuspendPopup( pmt
, WM_KEYDOWN
) )
1891 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
,
1892 pmt
->hTopMenu
, TRUE
);
1898 /***********************************************************************
1901 * Handle a VK_RIGHT key event in a menu.
1903 static void MENU_KeyRight( MTRACKER
* pmt
)
1906 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( pmt
->hTopMenu
);
1908 if ( (menu
->wFlags
& MF_POPUP
) || (pmt
->hCurrentMenu
!= pmt
->hTopMenu
))
1910 /* If already displaying a popup, try to display sub-popup */
1912 hmenutmp
= pmt
->hCurrentMenu
;
1913 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hmenutmp
, TRUE
);
1915 /* if subpopup was displayed then we are done */
1916 if (hmenutmp
!= pmt
->hCurrentMenu
) return;
1919 if (!(menu
->wFlags
& MF_POPUP
)) /* menu bar tracking */
1921 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
1923 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
1924 hmenutmp
= pmt
->hCurrentMenu
= pmt
->hTopMenu
;
1925 } else hmenutmp
= 0;
1927 /* try to move to the next item */
1928 if( !MENU_DoNextMenu( pmt
, VK_RIGHT
) )
1929 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_NEXT
);
1931 if( hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
1932 if( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
1933 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
,
1934 pmt
->hTopMenu
, TRUE
);
1939 /***********************************************************************
1942 * Menu tracking code.
1944 static BOOL32
MENU_TrackMenu( HMENU32 hmenu
, UINT32 wFlags
, INT32 x
, INT32 y
,
1945 HWND32 hwnd
, const RECT32
*lprect
)
1950 MTRACKER mt
= { 0, hmenu
, hmenu
, hwnd
, {x
, y
} }; /* control struct */
1953 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
1955 if (wFlags
& TPM_BUTTONDOWN
) MENU_ButtonDown( &mt
, hmenu
);
1957 EVENT_Capture( mt
.hOwnerWnd
, HTMENU
);
1961 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( mt
.hCurrentMenu
);
1962 msg
.hwnd
= (wFlags
& TPM_ENTERIDLEEX
&& menu
->wFlags
& MF_POPUP
) ? menu
->hWnd
: 0;
1964 /* we have to keep the message in the queue until it's
1965 * clear that menu loop is not over yet. */
1967 if (!MSG_InternalGetMessage( &msg
, msg
.hwnd
, mt
.hOwnerWnd
,
1968 MSGF_MENU
, PM_NOREMOVE
, TRUE
)) break;
1970 TranslateMessage16( &msg
);
1971 CONV_POINT16TO32( &msg
.pt
, &mt
.pt
);
1974 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
1976 /* Find a menu for this mouse event */
1978 hmenu
= MENU_PtMenu( mt
.hTopMenu
, msg
.pt
);
1982 /* no WM_NC... messages in captured state */
1984 case WM_RBUTTONDBLCLK
:
1985 case WM_RBUTTONDOWN
:
1986 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
1988 case WM_LBUTTONDBLCLK
:
1989 case WM_LBUTTONDOWN
:
1990 fEndMenu
|= !MENU_ButtonDown( &mt
, hmenu
);
1994 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
1997 /* If outside all menus but inside lprect, ignore it */
1998 if (hmenu
|| !lprect
|| !PtInRect32(lprect
, mt
.pt
))
2000 fEndMenu
|= !MENU_ButtonUp( &mt
, hmenu
);
2006 if ((msg
.wParam
& MK_LBUTTON
) || ((wFlags
& TPM_RIGHTBUTTON
)
2007 && (msg
.wParam
& MK_RBUTTON
)))
2009 fEndMenu
|= !MENU_MouseMove( &mt
, hmenu
);
2011 } /* switch(msg.message) - mouse */
2013 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
2015 fRemove
= TRUE
; /* Keyboard messages are always removed */
2023 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2024 NO_SELECTED_ITEM
, FALSE
);
2027 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2028 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
2031 case VK_DOWN
: /* If on menu bar, pull-down the menu */
2033 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( mt
.hCurrentMenu
);
2034 if (!(menu
->wFlags
& MF_POPUP
))
2035 mt
.hCurrentMenu
= MENU_ShowSubPopup( mt
.hOwnerWnd
, mt
.hTopMenu
, TRUE
);
2036 else /* otherwise try to move selection */
2037 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
, ITEM_NEXT
);
2041 MENU_KeyLeft( &mt
);
2045 MENU_KeyRight( &mt
);
2050 fEndMenu
|= !MENU_ExecFocusedItem( &mt
, mt
.hCurrentMenu
);
2060 break; /* WM_KEYDOWN */
2070 break; /* WM_SYSKEYDOWN */
2076 /* Hack to avoid control chars. */
2077 /* We will find a better way real soon... */
2078 if ((msg
.wParam
<= 32) || (msg
.wParam
>= 127)) break;
2080 pos
= MENU_FindItemByKey( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2081 msg
.wParam
, FALSE
);
2082 if (pos
== (UINT32
)-2) fEndMenu
= TRUE
;
2083 else if (pos
== (UINT32
)-1) MessageBeep32(0);
2086 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
, pos
, TRUE
);
2087 fEndMenu
|= !MENU_ExecFocusedItem( &mt
, mt
.hCurrentMenu
);
2091 } /* switch(msg.message) - kbd */
2095 DispatchMessage16( &msg
);
2098 if (!fEndMenu
) fRemove
= TRUE
;
2100 /* finally remove message from the queue */
2102 if (fRemove
&& !(mt
.trackFlags
& TF_SKIPREMOVE
) )
2103 PeekMessage16( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2104 else mt
.trackFlags
&= ~TF_SKIPREMOVE
;
2108 if( IsWindow32( mt
.hOwnerWnd
) )
2110 MENU_HideSubPopups( mt
.hOwnerWnd
, mt
.hTopMenu
, FALSE
);
2112 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( mt
.hTopMenu
);
2113 if (menu
&& menu
->wFlags
& MF_POPUP
)
2115 ShowWindow32( menu
->hWnd
, SW_HIDE
);
2118 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hTopMenu
, NO_SELECTED_ITEM
, FALSE
);
2119 SendMessage16( mt
.hOwnerWnd
, WM_MENUSELECT
, 0, MAKELONG( 0xffff, 0 ) );
2125 /***********************************************************************
2128 static BOOL32
MENU_InitTracking(HWND32 hWnd
, HMENU32 hMenu
)
2131 SendMessage16( hWnd
, WM_ENTERMENULOOP
, 0, 0 );
2132 SendMessage16( hWnd
, WM_SETCURSOR
, hWnd
, HTCAPTION
);
2133 SendMessage16( hWnd
, WM_INITMENU
, hMenu
, 0 );
2137 /***********************************************************************
2138 * MENU_TrackMouseMenuBar
2140 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2142 void MENU_TrackMouseMenuBar( WND
* wndPtr
, INT32 ht
, POINT32 pt
)
2144 HWND32 hWnd
= wndPtr
->hwndSelf
;
2145 HMENU32 hMenu
= (ht
== HTSYSMENU
) ? wndPtr
->hSysMenu
: wndPtr
->wIDmenu
;
2147 if (IsMenu32(hMenu
))
2149 MENU_InitTracking( hWnd
, hMenu
);
2150 MENU_TrackMenu( hMenu
, TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
|
2151 TPM_LEFTALIGN
| TPM_LEFTBUTTON
, pt
.x
, pt
.y
, hWnd
, NULL
);
2153 SendMessage16( hWnd
, WM_EXITMENULOOP
, 0, 0 );
2159 /***********************************************************************
2160 * MENU_TrackKbdMenuBar
2162 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
2164 void MENU_TrackKbdMenuBar( WND
* wndPtr
, UINT32 wParam
, INT32 vkey
)
2166 UINT32 uItem
= NO_SELECTED_ITEM
;
2169 /* find window that has a menu */
2171 while( wndPtr
->dwStyle
& WS_CHILD
&& !(wndPtr
->dwStyle
& WS_SYSMENU
) )
2172 if( !(wndPtr
= wndPtr
->parent
) ) return;
2174 /* check if we have to track a system menu */
2176 if( (wndPtr
->dwStyle
& (WS_CHILD
| WS_MINIMIZE
)) ||
2177 !wndPtr
->wIDmenu
|| vkey
== VK_SPACE
)
2179 if( !(wndPtr
->dwStyle
& WS_SYSMENU
) ) return;
2180 hTrackMenu
= wndPtr
->hSysMenu
;
2182 wParam
|= HTSYSMENU
; /* prevent item lookup */
2185 hTrackMenu
= wndPtr
->wIDmenu
;
2187 if (IsMenu32( hTrackMenu
))
2189 MENU_InitTracking( wndPtr
->hwndSelf
, hTrackMenu
);
2191 if( vkey
&& vkey
!= VK_SPACE
)
2193 uItem
= MENU_FindItemByKey( wndPtr
->hwndSelf
, hTrackMenu
,
2194 vkey
, (wParam
& HTSYSMENU
) );
2195 if( uItem
>= (UINT32
)(-2) )
2197 if( uItem
== (UINT32
)(-1) ) MessageBeep32(0);
2204 MENU_SelectItem( wndPtr
->hwndSelf
, hTrackMenu
, uItem
, TRUE
);
2206 if( uItem
== NO_SELECTED_ITEM
)
2207 MENU_MoveSelection( wndPtr
->hwndSelf
, hTrackMenu
, ITEM_NEXT
);
2209 PostMessage16( wndPtr
->hwndSelf
, WM_KEYDOWN
, VK_DOWN
, 0L );
2211 MENU_TrackMenu( hTrackMenu
, TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
2212 0, 0, wndPtr
->hwndSelf
, NULL
);
2214 SendMessage16( wndPtr
->hwndSelf
, WM_EXITMENULOOP
, 0, 0 );
2220 /**********************************************************************
2221 * TrackPopupMenu16 (USER.416)
2223 BOOL16
TrackPopupMenu16( HMENU16 hMenu
, UINT16 wFlags
, INT16 x
, INT16 y
,
2224 INT16 nReserved
, HWND16 hWnd
, const RECT16
*lpRect
)
2228 CONV_RECT16TO32( lpRect
, &r
);
2229 return TrackPopupMenu32( hMenu
, wFlags
, x
, y
, nReserved
, hWnd
,
2230 lpRect
? &r
: NULL
);
2234 /**********************************************************************
2235 * TrackPopupMenu32 (USER32.548)
2237 BOOL32
TrackPopupMenu32( HMENU32 hMenu
, UINT32 wFlags
, INT32 x
, INT32 y
,
2238 INT32 nReserved
, HWND32 hWnd
, const RECT32
*lpRect
)
2243 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
, 0, 0 ))
2244 ret
= MENU_TrackMenu( hMenu
, wFlags
& ~TPM_INTERNAL
, 0, 0, hWnd
, lpRect
);
2249 /**********************************************************************
2250 * TrackPopupMenuEx (USER32.549)
2252 BOOL32
TrackPopupMenuEx( HMENU32 hMenu
, UINT32 wFlags
, INT32 x
, INT32 y
,
2253 HWND32 hWnd
, LPTPMPARAMS lpTpm
)
2255 fprintf( stderr
, "TrackPopupMenuEx: not fully implemented\n" );
2256 return TrackPopupMenu32( hMenu
, wFlags
, x
, y
, 0, hWnd
,
2257 lpTpm
? &lpTpm
->rcExclude
: NULL
);
2260 /***********************************************************************
2263 * NOTE: Windows has totally different (and undocumented) popup wndproc.
2265 LRESULT
PopupMenuWndProc( HWND32 hwnd
, UINT32 message
, WPARAM32 wParam
,
2268 WND
* wndPtr
= WIN_FindWndPtr(hwnd
);
2274 CREATESTRUCT32A
*cs
= (CREATESTRUCT32A
*)lParam
;
2275 SetWindowLong32A( hwnd
, 0, (LONG
)cs
->lpCreateParams
);
2279 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2280 return MA_NOACTIVATE
;
2285 BeginPaint32( hwnd
, &ps
);
2286 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
2287 (HMENU32
)GetWindowLong32A( hwnd
, 0 ) );
2288 EndPaint32( hwnd
, &ps
);
2296 /* zero out global pointer in case resident popup window
2297 * was somehow destroyed. */
2299 if( hwnd
== pTopPopupWnd
->hwndSelf
)
2301 dprintf_menu(stddeb
,"resident popup destroyed!\n");
2303 pTopPopupWnd
= NULL
;
2314 if( !(*(HMENU32
*)wndPtr
->wExtra
) )
2315 fprintf(stderr
,"MenuWndProc: no menu to display\n");
2318 *(HMENU32
*)wndPtr
->wExtra
= 0;
2321 case MM_SETMENUHANDLE
:
2323 *(HMENU32
*)wndPtr
->wExtra
= (HMENU32
)wParam
;
2326 case MM_GETMENUHANDLE
:
2328 return *(HMENU32
*)wndPtr
->wExtra
;
2331 return DefWindowProc32A( hwnd
, message
, wParam
, lParam
);
2337 /***********************************************************************
2338 * MENU_GetMenuBarHeight
2340 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
2342 UINT32
MENU_GetMenuBarHeight( HWND32 hwnd
, UINT32 menubarWidth
,
2343 INT32 orgX
, INT32 orgY
)
2350 dprintf_menu( stddeb
, "MENU_GetMenuBarHeight: HWND 0x%lx, width %d, "
2351 "at (%d, %d).\n", hwnd
, menubarWidth
, orgX
, orgY
);
2353 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
2354 if (!(lppop
= (LPPOPUPMENU
)USER_HEAP_LIN_ADDR((HMENU16
)wndPtr
->wIDmenu
)))
2356 hdc
= GetDCEx32( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2357 SetRect32(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+SYSMETRICS_CYMENU
);
2358 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
2359 ReleaseDC32( hwnd
, hdc
);
2360 return lppop
->Height
;
2364 /*******************************************************************
2365 * ChangeMenu16 (USER.153)
2367 BOOL16
ChangeMenu16( HMENU16 hMenu
, UINT16 pos
, SEGPTR data
,
2368 UINT16 id
, UINT16 flags
)
2370 dprintf_menu( stddeb
,"ChangeMenu16: menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
2371 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2372 if (flags
& MF_APPEND
) return AppendMenu16( hMenu
, flags
& ~MF_APPEND
,
2375 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
2376 /* for MF_DELETE. We should check the parameters for all others */
2377 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
2379 if (flags
& MF_DELETE
) return DeleteMenu16(hMenu
, pos
, flags
& ~MF_DELETE
);
2380 if (flags
& MF_CHANGE
) return ModifyMenu16(hMenu
, pos
, flags
& ~MF_CHANGE
,
2382 if (flags
& MF_REMOVE
) return RemoveMenu16(hMenu
,
2383 flags
& MF_BYPOSITION
? pos
: id
,
2384 flags
& ~MF_REMOVE
);
2385 /* Default: MF_INSERT */
2386 return InsertMenu16( hMenu
, pos
, flags
, id
, data
);
2390 /*******************************************************************
2391 * ChangeMenu32A (USER32.22)
2393 BOOL32
ChangeMenu32A( HMENU32 hMenu
, UINT32 pos
, LPCSTR data
,
2394 UINT32 id
, UINT32 flags
)
2396 dprintf_menu( stddeb
,"ChangeMenu32A: menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2397 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2398 if (flags
& MF_APPEND
) return AppendMenu32A( hMenu
, flags
& ~MF_APPEND
,
2400 if (flags
& MF_DELETE
) return DeleteMenu32(hMenu
, pos
, flags
& ~MF_DELETE
);
2401 if (flags
& MF_CHANGE
) return ModifyMenu32A(hMenu
, pos
, flags
& ~MF_CHANGE
,
2403 if (flags
& MF_REMOVE
) return RemoveMenu32( hMenu
,
2404 flags
& MF_BYPOSITION
? pos
: id
,
2405 flags
& ~MF_REMOVE
);
2406 /* Default: MF_INSERT */
2407 return InsertMenu32A( hMenu
, pos
, flags
, id
, data
);
2411 /*******************************************************************
2412 * ChangeMenu32W (USER32.23)
2414 BOOL32
ChangeMenu32W( HMENU32 hMenu
, UINT32 pos
, LPCWSTR data
,
2415 UINT32 id
, UINT32 flags
)
2417 dprintf_menu( stddeb
,"ChangeMenu32W: menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2418 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2419 if (flags
& MF_APPEND
) return AppendMenu32W( hMenu
, flags
& ~MF_APPEND
,
2421 if (flags
& MF_DELETE
) return DeleteMenu32(hMenu
, pos
, flags
& ~MF_DELETE
);
2422 if (flags
& MF_CHANGE
) return ModifyMenu32W(hMenu
, pos
, flags
& ~MF_CHANGE
,
2424 if (flags
& MF_REMOVE
) return RemoveMenu32( hMenu
,
2425 flags
& MF_BYPOSITION
? pos
: id
,
2426 flags
& ~MF_REMOVE
);
2427 /* Default: MF_INSERT */
2428 return InsertMenu32W( hMenu
, pos
, flags
, id
, data
);
2432 /*******************************************************************
2433 * CheckMenuItem16 (USER.154)
2435 BOOL16
CheckMenuItem16( HMENU16 hMenu
, UINT16 id
, UINT16 flags
)
2437 return (BOOL16
)CheckMenuItem32( hMenu
, id
, flags
);
2441 /*******************************************************************
2442 * CheckMenuItem32 (USER32.45)
2444 DWORD
CheckMenuItem32( HMENU32 hMenu
, UINT32 id
, UINT32 flags
)
2449 dprintf_menu( stddeb
,"CheckMenuItem: %04x %04x %04x\n", hMenu
, id
, flags
);
2450 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
2451 ret
= item
->item_flags
& MF_CHECKED
;
2452 if (flags
& MF_CHECKED
) item
->item_flags
|= MF_CHECKED
;
2453 else item
->item_flags
&= ~MF_CHECKED
;
2458 /**********************************************************************
2459 * EnableMenuItem16 (USER.155)
2461 BOOL16
EnableMenuItem16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
2463 return EnableMenuItem32( hMenu
, wItemID
, wFlags
);
2467 /**********************************************************************
2468 * EnableMenuItem32 (USER32.169)
2470 BOOL32
EnableMenuItem32( HMENU32 hMenu
, UINT32 wItemID
, UINT32 wFlags
)
2472 BOOL32 bRet
= FALSE
;
2473 MENUITEM
*item
, *first
= NULL
;
2475 dprintf_menu(stddeb
,"EnableMenuItem (%04x, %04X, %04X) !\n",
2476 hMenu
, wItemID
, wFlags
);
2478 while( (item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
)) )
2480 if( !(item
->item_flags
& MF_POPUP
) )
2482 /* We can't have MF_GRAYED and MF_DISABLED together */
2483 if (wFlags
& MF_GRAYED
)
2485 item
->item_flags
= (item
->item_flags
& ~MF_DISABLED
) | MF_GRAYED
;
2487 else if (wFlags
& MF_DISABLED
)
2489 item
->item_flags
= (item
->item_flags
& ~MF_GRAYED
) | MF_DISABLED
;
2491 else /* MF_ENABLED */
2493 item
->item_flags
&= ~(MF_GRAYED
| MF_DISABLED
);
2498 if( !first
) first
= item
;
2499 else if( first
== item
) break;
2505 /*******************************************************************
2506 * GetMenuString16 (USER.161)
2508 INT16
GetMenuString16( HMENU16 hMenu
, UINT16 wItemID
,
2509 LPSTR str
, INT16 nMaxSiz
, UINT16 wFlags
)
2511 return GetMenuString32A( hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
2515 /*******************************************************************
2516 * GetMenuString32A (USER32.267)
2518 INT32
GetMenuString32A( HMENU32 hMenu
, UINT32 wItemID
,
2519 LPSTR str
, INT32 nMaxSiz
, UINT32 wFlags
)
2523 dprintf_menu( stddeb
, "GetMenuString32A: menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
2524 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
2525 if (!str
|| !nMaxSiz
) return 0;
2527 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
2528 if (!IS_STRING_ITEM(item
->item_flags
)) return 0;
2529 lstrcpyn32A( str
, item
->text
, nMaxSiz
);
2530 dprintf_menu( stddeb
, "GetMenuString32A: returning '%s'\n", str
);
2535 /*******************************************************************
2536 * GetMenuString32W (USER32.268)
2538 INT32
GetMenuString32W( HMENU32 hMenu
, UINT32 wItemID
,
2539 LPWSTR str
, INT32 nMaxSiz
, UINT32 wFlags
)
2543 dprintf_menu( stddeb
, "GetMenuString32W: menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
2544 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
2545 if (!str
|| !nMaxSiz
) return 0;
2547 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
2548 if (!IS_STRING_ITEM(item
->item_flags
)) return 0;
2549 lstrcpynAtoW( str
, item
->text
, nMaxSiz
);
2550 return lstrlen32W(str
);
2554 /**********************************************************************
2555 * HiliteMenuItem16 (USER.162)
2557 BOOL16
HiliteMenuItem16( HWND16 hWnd
, HMENU16 hMenu
, UINT16 wItemID
,
2560 return HiliteMenuItem32( hWnd
, hMenu
, wItemID
, wHilite
);
2564 /**********************************************************************
2565 * HiliteMenuItem32 (USER32.317)
2567 BOOL32
HiliteMenuItem32( HWND32 hWnd
, HMENU32 hMenu
, UINT32 wItemID
,
2571 dprintf_menu(stddeb
,"HiliteMenuItem(%04x, %04x, %04x, %04x);\n",
2572 hWnd
, hMenu
, wItemID
, wHilite
);
2573 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
2574 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
2575 if (menu
->FocusedItem
== wItemID
) return TRUE
;
2576 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
2577 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
);
2582 /**********************************************************************
2583 * GetMenuState16 (USER.250)
2585 UINT16
GetMenuState16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
2587 return GetMenuState32( hMenu
, wItemID
, wFlags
);
2591 /**********************************************************************
2592 * GetMenuState32 (USER32.266)
2594 UINT32
GetMenuState32( HMENU32 hMenu
, UINT32 wItemID
, UINT32 wFlags
)
2597 dprintf_menu(stddeb
,"GetMenuState(%04x, %04x, %04x);\n",
2598 hMenu
, wItemID
, wFlags
);
2599 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
2600 if (item
->item_flags
& MF_POPUP
)
2602 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( (HMENU16
)item
->item_id
);
2603 if (!menu
) return -1;
2604 else return (menu
->nItems
<< 8) | (menu
->wFlags
& 0xff);
2607 /* Non POPUP Menus only return flags in the lower byte */
2608 return (item
->item_flags
& 0x00ff);
2612 /**********************************************************************
2613 * GetMenuItemCount16 (USER.263)
2615 INT16
GetMenuItemCount16( HMENU16 hMenu
)
2617 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2618 if (!menu
|| (menu
->wMagic
!= MENU_MAGIC
)) return -1;
2619 dprintf_menu( stddeb
,"GetMenuItemCount16(%04x) returning %d\n",
2620 hMenu
, menu
->nItems
);
2621 return menu
->nItems
;
2625 /**********************************************************************
2626 * GetMenuItemCount32 (USER32.261)
2628 INT32
GetMenuItemCount32( HMENU32 hMenu
)
2630 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2631 if (!menu
|| (menu
->wMagic
!= MENU_MAGIC
)) return -1;
2632 dprintf_menu( stddeb
,"GetMenuItemCount32(%04x) returning %d\n",
2633 hMenu
, menu
->nItems
);
2634 return menu
->nItems
;
2638 /**********************************************************************
2639 * GetMenuItemID16 (USER.264)
2641 UINT16
GetMenuItemID16( HMENU16 hMenu
, INT16 nPos
)
2645 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
2646 if ((nPos
< 0) || ((UINT16
) nPos
>= menu
->nItems
)) return -1;
2647 if (menu
->items
[nPos
].item_flags
& MF_POPUP
) return -1;
2648 return menu
->items
[nPos
].item_id
;
2652 /**********************************************************************
2653 * GetMenuItemID32 (USER32.262)
2655 UINT32
GetMenuItemID32( HMENU32 hMenu
, INT32 nPos
)
2659 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
2660 if ((nPos
< 0) || (nPos
>= menu
->nItems
)) return -1;
2661 if (menu
->items
[nPos
].item_flags
& MF_POPUP
) return -1;
2662 return menu
->items
[nPos
].item_id
;
2666 /*******************************************************************
2667 * InsertMenu16 (USER.410)
2669 BOOL16
InsertMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
2670 UINT16 id
, SEGPTR data
)
2672 UINT32 pos32
= (UINT32
)pos
;
2673 if ((pos
== (UINT16
)-1) && (flags
& MF_BYPOSITION
)) pos32
= (UINT32
)-1;
2674 if (IS_STRING_ITEM(flags
) && data
)
2675 return InsertMenu32A( hMenu
, pos32
, flags
, id
,
2676 (LPSTR
)PTR_SEG_TO_LIN(data
) );
2677 return InsertMenu32A( hMenu
, pos32
, flags
, id
, (LPSTR
)data
);
2681 /*******************************************************************
2682 * InsertMenu32A (USER32.321)
2684 BOOL32
InsertMenu32A( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2685 UINT32 id
, LPCSTR str
)
2689 if (IS_STRING_ITEM(flags
) && str
)
2690 dprintf_menu( stddeb
, "InsertMenu: hMenu %04x, pos %d, flags %04x, "
2691 "id %04x, str '%s'\n",
2692 hMenu
, pos
, flags
, id
, str
);
2693 else dprintf_menu( stddeb
, "InsertMenu: hMenu %04x, pos %d, flags %04x, "
2694 "id %04x, str %08lx (not a string)\n",
2695 hMenu
, pos
, flags
, id
, (DWORD
)str
);
2697 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
2699 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
2701 RemoveMenu32( hMenu
, pos
, flags
);
2705 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
2706 ((POPUPMENU
*)USER_HEAP_LIN_ADDR((HMENU16
)id
))->wFlags
|= MF_POPUP
;
2713 /*******************************************************************
2714 * InsertMenu32W (USER32.324)
2716 BOOL32
InsertMenu32W( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2717 UINT32 id
, LPCWSTR str
)
2721 if (IS_STRING_ITEM(flags
) && str
)
2723 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
2724 ret
= InsertMenu32A( hMenu
, pos
, flags
, id
, newstr
);
2725 HeapFree( GetProcessHeap(), 0, newstr
);
2728 else return InsertMenu32A( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
2732 /*******************************************************************
2733 * AppendMenu16 (USER.411)
2735 BOOL16
AppendMenu16( HMENU16 hMenu
, UINT16 flags
, UINT16 id
, SEGPTR data
)
2737 return InsertMenu16( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
2741 /*******************************************************************
2742 * AppendMenu32A (USER32.4)
2744 BOOL32
AppendMenu32A( HMENU32 hMenu
, UINT32 flags
, UINT32 id
, LPCSTR data
)
2746 return InsertMenu32A( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
2750 /*******************************************************************
2751 * AppendMenu32W (USER32.5)
2753 BOOL32
AppendMenu32W( HMENU32 hMenu
, UINT32 flags
, UINT32 id
, LPCWSTR data
)
2755 return InsertMenu32W( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
2759 /**********************************************************************
2760 * RemoveMenu16 (USER.412)
2762 BOOL16
RemoveMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
2764 return RemoveMenu32( hMenu
, nPos
, wFlags
);
2768 /**********************************************************************
2769 * RemoveMenu32 (USER32.440)
2771 BOOL32
RemoveMenu32( HMENU32 hMenu
, UINT32 nPos
, UINT32 wFlags
)
2776 dprintf_menu(stddeb
,"RemoveMenu (%04x, %04x, %04x)\n",hMenu
, nPos
, wFlags
);
2777 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
2778 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
2782 MENU_FreeItemData( item
);
2784 if (--menu
->nItems
== 0)
2786 HeapFree( SystemHeap
, 0, menu
->items
);
2791 while(nPos
< menu
->nItems
)
2797 menu
->items
= HeapReAlloc( SystemHeap
, 0, menu
->items
,
2798 menu
->nItems
* sizeof(MENUITEM
) );
2804 /**********************************************************************
2805 * DeleteMenu16 (USER.413)
2807 BOOL16
DeleteMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
2809 return DeleteMenu32( hMenu
, nPos
, wFlags
);
2813 /**********************************************************************
2814 * DeleteMenu32 (USER32.128)
2816 BOOL32
DeleteMenu32( HMENU32 hMenu
, UINT32 nPos
, UINT32 wFlags
)
2818 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
2819 if (!item
) return FALSE
;
2820 if (item
->item_flags
& MF_POPUP
) DestroyMenu32( (HMENU32
)item
->item_id
);
2821 /* nPos is now the position of the item */
2822 RemoveMenu32( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
2827 /*******************************************************************
2828 * ModifyMenu16 (USER.414)
2830 BOOL16
ModifyMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
2831 UINT16 id
, SEGPTR data
)
2833 if (IS_STRING_ITEM(flags
))
2834 return ModifyMenu32A( hMenu
, pos
, flags
, id
,
2835 (LPSTR
)PTR_SEG_TO_LIN(data
) );
2836 return ModifyMenu32A( hMenu
, pos
, flags
, id
, (LPSTR
)data
);
2840 /*******************************************************************
2841 * ModifyMenu32A (USER32.396)
2843 BOOL32
ModifyMenu32A( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2844 UINT32 id
, LPCSTR str
)
2848 if (IS_STRING_ITEM(flags
))
2850 dprintf_menu( stddeb
, "ModifyMenu: %04x %d %04x %04x '%s'\n",
2851 hMenu
, pos
, flags
, id
, str
? str
: "#NULL#" );
2852 if (!str
) return FALSE
;
2856 dprintf_menu( stddeb
, "ModifyMenu: %04x %d %04x %04x %08lx\n",
2857 hMenu
, pos
, flags
, id
, (DWORD
)str
);
2860 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
2861 return MENU_SetItemData( item
, flags
, id
, str
);
2865 /*******************************************************************
2866 * ModifyMenu32W (USER32.397)
2868 BOOL32
ModifyMenu32W( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2869 UINT32 id
, LPCWSTR str
)
2873 if (IS_STRING_ITEM(flags
) && str
)
2875 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
2876 ret
= ModifyMenu32A( hMenu
, pos
, flags
, id
, newstr
);
2877 HeapFree( GetProcessHeap(), 0, newstr
);
2880 else return ModifyMenu32A( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
2884 /**********************************************************************
2885 * CreatePopupMenu16 (USER.415)
2887 HMENU16
CreatePopupMenu16(void)
2889 return CreatePopupMenu32();
2893 /**********************************************************************
2894 * CreatePopupMenu32 (USER32.81)
2896 HMENU32
CreatePopupMenu32(void)
2901 if (!(hmenu
= CreateMenu32())) return 0;
2902 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
2903 menu
->wFlags
|= MF_POPUP
;
2908 /**********************************************************************
2909 * GetMenuCheckMarkDimensions (USER.417) (USER32.257)
2911 DWORD
GetMenuCheckMarkDimensions(void)
2913 return MAKELONG( check_bitmap_width
, check_bitmap_height
);
2917 /**********************************************************************
2918 * SetMenuItemBitmaps16 (USER.418)
2920 BOOL16
SetMenuItemBitmaps16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
,
2921 HBITMAP16 hNewUnCheck
, HBITMAP16 hNewCheck
)
2923 return SetMenuItemBitmaps32( hMenu
, nPos
, wFlags
, hNewUnCheck
, hNewCheck
);
2927 /**********************************************************************
2928 * SetMenuItemBitmaps32 (USER32.489)
2930 BOOL32
SetMenuItemBitmaps32( HMENU32 hMenu
, UINT32 nPos
, UINT32 wFlags
,
2931 HBITMAP32 hNewUnCheck
, HBITMAP32 hNewCheck
)
2934 dprintf_menu(stddeb
,"SetMenuItemBitmaps(%04x, %04x, %04x, %04x, %04x)\n",
2935 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
2936 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
2938 if (!hNewCheck
&& !hNewUnCheck
)
2940 if( item
->pCB
) HeapFree( SystemHeap
, 0, item
->pCB
);
2942 item
->item_flags
&= ~MF_USECHECKBITMAPS
;
2944 else /* Install new bitmaps */
2946 if( item
->pCB
== NULL
)
2947 item
->pCB
= HeapAlloc( SystemHeap
, 0, sizeof(CBITMAPS
));
2948 item
->pCB
->hCheckBit
= hNewCheck
;
2949 item
->pCB
->hUnCheckBit
= hNewUnCheck
;
2950 item
->item_flags
|= MF_USECHECKBITMAPS
;
2956 /**********************************************************************
2957 * CreateMenu16 (USER.151)
2959 HMENU16
CreateMenu16(void)
2961 return CreateMenu32();
2965 /**********************************************************************
2966 * CreateMenu32 (USER32.80)
2968 HMENU32
CreateMenu32(void)
2972 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) ))) return 0;
2973 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2975 menu
->wMagic
= MENU_MAGIC
;
2982 menu
->FocusedItem
= NO_SELECTED_ITEM
;
2983 dprintf_menu( stddeb
, "CreateMenu: return %04x\n", hMenu
);
2988 /**********************************************************************
2989 * DestroyMenu16 (USER.152)
2991 BOOL16
DestroyMenu16( HMENU16 hMenu
)
2993 return DestroyMenu32( hMenu
);
2997 /**********************************************************************
2998 * DestroyMenu32 (USER32.133)
3000 BOOL32
DestroyMenu32( HMENU32 hMenu
)
3002 dprintf_menu(stddeb
,"DestroyMenu(%04x)\n", hMenu
);
3004 /* Silently ignore attempts to destroy default system popup */
3006 if (hMenu
&& hMenu
!= MENU_DefSysPopup
)
3008 LPPOPUPMENU lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3010 if( pTopPopupWnd
&& (hMenu
== *(HMENU32
*)pTopPopupWnd
->wExtra
) )
3011 *(UINT32
*)pTopPopupWnd
->wExtra
= 0;
3013 if (lppop
&& (lppop
->wMagic
== MENU_MAGIC
))
3015 lppop
->wMagic
= 0; /* Mark it as destroyed */
3017 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
&&
3018 (!pTopPopupWnd
|| (lppop
->hWnd
!= pTopPopupWnd
->hwndSelf
)))
3019 DestroyWindow32( lppop
->hWnd
);
3021 if (lppop
->items
) /* recursively destroy submenus */
3024 MENUITEM
*item
= lppop
->items
;
3025 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
3027 if (item
->item_flags
& MF_POPUP
)
3028 DestroyMenu32( (HMENU32
)item
->item_id
);
3029 MENU_FreeItemData( item
);
3031 HeapFree( SystemHeap
, 0, lppop
->items
);
3033 USER_HEAP_FREE( hMenu
);
3037 return (hMenu
!= MENU_DefSysPopup
);
3041 /**********************************************************************
3042 * GetSystemMenu16 (USER.156)
3044 HMENU16
GetSystemMenu16( HWND16 hWnd
, BOOL16 bRevert
)
3046 return GetSystemMenu32( hWnd
, bRevert
);
3050 /**********************************************************************
3051 * GetSystemMenu32 (USER32.290)
3053 HMENU32
GetSystemMenu32( HWND32 hWnd
, BOOL32 bRevert
)
3055 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
3059 if( wndPtr
->hSysMenu
)
3063 DestroyMenu32(wndPtr
->hSysMenu
);
3064 wndPtr
->hSysMenu
= 0;
3068 POPUPMENU
*menu
= (POPUPMENU
*)
3069 USER_HEAP_LIN_ADDR(wndPtr
->hSysMenu
);
3070 if( menu
->items
[0].item_id
== MENU_DefSysPopup
)
3071 menu
->items
[0].item_id
= MENU_CopySysPopup();
3075 if(!wndPtr
->hSysMenu
&& (wndPtr
->dwStyle
& WS_SYSMENU
) )
3076 wndPtr
->hSysMenu
= MENU_GetSysMenu( hWnd
, (HMENU32
)(-1) );
3078 if( wndPtr
->hSysMenu
)
3079 return GetSubMenu16(wndPtr
->hSysMenu
, 0);
3085 /*******************************************************************
3086 * SetSystemMenu16 (USER.280)
3088 BOOL16
SetSystemMenu16( HWND16 hwnd
, HMENU16 hMenu
)
3090 return SetSystemMenu32( hwnd
, hMenu
);
3094 /*******************************************************************
3095 * SetSystemMenu32 (USER32.507)
3097 BOOL32
SetSystemMenu32( HWND32 hwnd
, HMENU32 hMenu
)
3099 WND
*wndPtr
= WIN_FindWndPtr(hwnd
);
3103 if (wndPtr
->hSysMenu
) DestroyMenu32( wndPtr
->hSysMenu
);
3104 wndPtr
->hSysMenu
= MENU_GetSysMenu( hwnd
, hMenu
);
3111 /**********************************************************************
3112 * GetMenu16 (USER.157)
3114 HMENU16
GetMenu16( HWND16 hWnd
)
3116 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
3117 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
3118 return (HMENU16
)wndPtr
->wIDmenu
;
3123 /**********************************************************************
3124 * GetMenu32 (USER32.256)
3126 HMENU32
GetMenu32( HWND32 hWnd
)
3128 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
3129 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
3130 return (HMENU32
)wndPtr
->wIDmenu
;
3135 /**********************************************************************
3136 * SetMenu16 (USER.158)
3138 BOOL16
SetMenu16( HWND16 hWnd
, HMENU16 hMenu
)
3140 return SetMenu32( hWnd
, hMenu
);
3144 /**********************************************************************
3145 * SetMenu32 (USER32.486)
3147 BOOL32
SetMenu32( HWND32 hWnd
, HMENU32 hMenu
)
3149 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
3151 dprintf_menu(stddeb
,"SetMenu(%04x, %04x);\n", hWnd
, hMenu
);
3153 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
3155 if (GetCapture32() == hWnd
) ReleaseCapture();
3157 wndPtr
->wIDmenu
= (UINT32
)hMenu
;
3162 if (!(lpmenu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
3163 lpmenu
->hWnd
= hWnd
;
3164 lpmenu
->wFlags
&= ~MF_POPUP
; /* Can't be a popup */
3165 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
3167 if (IsWindowVisible32(hWnd
))
3168 SetWindowPos32( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3169 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3177 /**********************************************************************
3178 * GetSubMenu16 (USER.159)
3180 HMENU16
GetSubMenu16( HMENU16 hMenu
, INT16 nPos
)
3182 return GetSubMenu32( hMenu
, nPos
);
3186 /**********************************************************************
3187 * GetSubMenu32 (USER32.287)
3189 HMENU32
GetSubMenu32( HMENU32 hMenu
, INT32 nPos
)
3193 if (!(lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return 0;
3194 if ((UINT32
)nPos
>= lppop
->nItems
) return 0;
3195 if (!(lppop
->items
[nPos
].item_flags
& MF_POPUP
)) return 0;
3196 return (HMENU32
)lppop
->items
[nPos
].item_id
;
3200 /**********************************************************************
3201 * DrawMenuBar16 (USER.160)
3203 void DrawMenuBar16( HWND16 hWnd
)
3205 DrawMenuBar32( hWnd
);
3209 /**********************************************************************
3210 * DrawMenuBar32 (USER32.160)
3212 BOOL32
DrawMenuBar32( HWND32 hWnd
)
3215 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
3216 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
) && wndPtr
->wIDmenu
)
3218 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR((HMENU16
)wndPtr
->wIDmenu
);
3219 if (lppop
== NULL
) return FALSE
;
3221 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
3222 SetWindowPos32( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3223 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3230 /***********************************************************************
3231 * EndMenu (USER.187) (USER32.174)
3239 /***********************************************************************
3240 * LookupMenuHandle (USER.217)
3242 HMENU16
LookupMenuHandle( HMENU16 hmenu
, INT16 id
)
3244 HMENU32 hmenu32
= hmenu
;
3246 if (!MENU_FindItem( &hmenu32
, &id32
, MF_BYCOMMAND
)) return 0;
3247 else return hmenu32
;
3251 /**********************************************************************
3252 * LoadMenu16 (USER.150)
3254 HMENU16
LoadMenu16( HINSTANCE16 instance
, SEGPTR name
)
3262 char *str
= (char *)PTR_SEG_TO_LIN( name
);
3263 dprintf_menu( stddeb
, "LoadMenu(%04x,'%s')\n", instance
, str
);
3264 if (str
[0] == '#') name
= (SEGPTR
)atoi( str
+ 1 );
3267 dprintf_resource(stddeb
,"LoadMenu(%04x,%04x)\n",instance
,LOWORD(name
));
3269 if (!name
) return 0;
3271 /* check for Win32 module */
3272 instance
= GetExePtr( instance
);
3273 if (MODULE_GetPtr(instance
)->flags
& NE_FFLAGS_WIN32
)
3274 return LoadMenu32A(instance
,PTR_SEG_TO_LIN(name
));
3276 if (!(hRsrc
= FindResource16( instance
, name
, RT_MENU
))) return 0;
3277 if (!(handle
= LoadResource16( instance
, hRsrc
))) return 0;
3278 hMenu
= LoadMenuIndirect16(LockResource16(handle
));
3279 FreeResource16( handle
);
3284 /*****************************************************************
3285 * LoadMenu32A (USER32.370)
3287 HMENU32
LoadMenu32A( HINSTANCE32 instance
, LPCSTR name
)
3289 HRSRC32 hrsrc
= FindResource32A( instance
, name
, (LPSTR
)RT_MENU
);
3290 if (!hrsrc
) return 0;
3291 return LoadMenuIndirect32A( (LPCVOID
)LoadResource32( instance
, hrsrc
));
3295 /*****************************************************************
3296 * LoadMenu32W (USER32.372)
3298 HMENU32
LoadMenu32W( HINSTANCE32 instance
, LPCWSTR name
)
3300 HRSRC32 hrsrc
= FindResource32W( instance
, name
, (LPWSTR
)RT_MENU
);
3301 if (!hrsrc
) return 0;
3302 return LoadMenuIndirect32W( (LPCVOID
)LoadResource32( instance
, hrsrc
));
3306 /**********************************************************************
3307 * LoadMenuIndirect16 (USER.220)
3309 HMENU16
LoadMenuIndirect16( LPCVOID
template )
3312 WORD version
, offset
;
3313 LPCSTR p
= (LPCSTR
)template;
3315 dprintf_menu(stddeb
,"LoadMenuIndirect16: %p\n", template );
3316 version
= GET_WORD(p
);
3320 fprintf( stderr
, "LoadMenuIndirect16: version must be 0 for Win16\n" );
3323 offset
= GET_WORD(p
);
3324 p
+= sizeof(WORD
) + offset
;
3325 if (!(hMenu
= CreateMenu32())) return 0;
3326 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
3328 DestroyMenu32( hMenu
);
3335 /**********************************************************************
3336 * LoadMenuIndirect32A (USER32.370)
3338 HMENU32
LoadMenuIndirect32A( LPCVOID
template )
3341 WORD version
, offset
;
3342 LPCSTR p
= (LPCSTR
)template;
3344 dprintf_menu(stddeb
,"LoadMenuIndirect16: %p\n", template );
3345 version
= GET_WORD(p
);
3349 fprintf( stderr
, "LoadMenuIndirect32A: version %d not supported.\n",
3353 offset
= GET_WORD(p
);
3354 p
+= sizeof(WORD
) + offset
;
3355 if (!(hMenu
= CreateMenu32())) return 0;
3356 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
3358 DestroyMenu32( hMenu
);
3365 /**********************************************************************
3366 * LoadMenuIndirect32W (USER32.371)
3368 HMENU32
LoadMenuIndirect32W( LPCVOID
template )
3370 /* FIXME: is there anything different between A and W? */
3371 return LoadMenuIndirect32A( template );
3375 /**********************************************************************
3376 * IsMenu16 (USER.358)
3378 BOOL16
IsMenu16( HMENU16 hmenu
)
3381 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
3382 return (menu
->wMagic
== MENU_MAGIC
);
3386 /**********************************************************************
3387 * IsMenu32 (USER32.345)
3389 BOOL32
IsMenu32( HMENU32 hmenu
)
3392 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
3393 return (menu
->wMagic
== MENU_MAGIC
);