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.
20 #include "sysmetrics.h"
35 /* Menu item structure */
38 WORD item_flags
; /* Item flags */
39 UINT item_id
; /* Item or popup id */
40 RECT16 rect
; /* Item area (relative to menu window) */
41 WORD xTab
; /* X position of text after Tab */
42 HBITMAP hCheckBit
; /* Bitmap for checked item */
43 HBITMAP hUnCheckBit
; /* Bitmap for unchecked item */
44 LPSTR text
; /* Item text or bitmap handle */
47 /* Popup menu structure */
50 WORD wFlags
; /* Menu flags (MF_POPUP, MF_SYSMENU) */
51 WORD wMagic
; /* Magic number */
52 HANDLE hTaskQ
; /* Task queue for this menu */
53 WORD Width
; /* Width of the whole menu */
54 WORD Height
; /* Height of the whole menu */
55 WORD nItems
; /* Number of items in the menu */
56 HWND hWnd
; /* Window containing the menu */
57 MENUITEM
*items
; /* Array of menu items */
58 UINT FocusedItem
; /* Currently focused item */
59 } POPUPMENU
, *LPPOPUPMENU
;
61 #define MENU_MAGIC 0x554d /* 'MU' */
63 /* Dimension of the menu bitmaps */
64 static WORD check_bitmap_width
= 0, check_bitmap_height
= 0;
65 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
67 /* Flag set by EndMenu() to force an exit from menu tracking */
68 static BOOL fEndMenuCalled
= FALSE
;
70 /* Space between 2 menu bar items */
71 #define MENU_BAR_ITEMS_SPACE 16
73 /* Minimum width of a tab character */
74 #define MENU_TAB_SPACE 8
76 /* Height of a separator item */
77 #define SEPARATOR_HEIGHT 5
79 /* Values for menu->FocusedItem */
80 /* (other values give the position of the focused item) */
81 #define NO_SELECTED_ITEM 0xffff
82 #define SYSMENU_SELECTED 0xfffe /* Only valid on menu-bars */
84 #define IS_STRING_ITEM(flags) (!((flags) & (MF_BITMAP | MF_OWNERDRAW | \
85 MF_MENUBARBREAK | MF_MENUBREAK | MF_SEPARATOR)))
87 extern void NC_DrawSysButton(HWND hwnd
, HDC hdc
, BOOL down
); /* nonclient.c */
89 static HBITMAP hStdCheck
= 0;
90 static HBITMAP hStdMnArrow
= 0;
91 static HMENU MENU_DefSysMenu
= 0; /* Default system menu */
94 /* we _can_ use global popup window because there's no way 2 menues can
95 * be tracked at the same time.
98 static WND
* pTopPWnd
= 0;
99 static UINT uSubPWndLevel
= 0;
102 /**********************************************************************
105 * Load a copy of the system menu.
107 static HMENU
MENU_CopySysMenu(void)
113 if (!(handle
= SYSRES_LoadResource( SYSRES_MENU_SYSMENU
))) return 0;
114 hMenu
= LoadMenuIndirect16( GlobalLock16( handle
) );
115 SYSRES_FreeResource( handle
);
118 dprintf_menu(stddeb
,"No SYSMENU\n");
121 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
122 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
123 dprintf_menu(stddeb
,"CopySysMenu hMenu=%04x !\n", hMenu
);
128 /***********************************************************************
131 * Menus initialisation.
139 if (!(hStdCheck
= LoadBitmap( 0, MAKEINTRESOURCE(OBM_CHECK
) )))
141 GetObject( hStdCheck
, sizeof(BITMAP
), (LPSTR
)&bm
);
142 check_bitmap_width
= bm
.bmWidth
;
143 check_bitmap_height
= bm
.bmHeight
;
144 if (!(hStdMnArrow
= LoadBitmap( 0, MAKEINTRESOURCE(OBM_MNARROW
) )))
146 GetObject( hStdMnArrow
, sizeof(BITMAP
), (LPSTR
)&bm
);
147 arrow_bitmap_width
= bm
.bmWidth
;
148 arrow_bitmap_height
= bm
.bmHeight
;
150 if (!(MENU_DefSysMenu
= MENU_CopySysMenu()))
152 fprintf( stderr
, "Unable to create default system menu\n" );
159 /***********************************************************************
162 * Return the default system menu.
164 HMENU
MENU_GetDefSysMenu(void)
166 return MENU_DefSysMenu
;
170 /***********************************************************************
173 * Check whether the window owning the menu bar has a system menu.
175 static BOOL
MENU_HasSysMenu( POPUPMENU
*menu
)
179 if (menu
->wFlags
& MF_POPUP
) return FALSE
;
180 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return FALSE
;
181 return (wndPtr
->dwStyle
& WS_SYSMENU
) != 0;
185 /***********************************************************************
188 * Check whether the point (in screen coords) is in the system menu
189 * of the window owning the given menu.
191 static BOOL
MENU_IsInSysMenu( POPUPMENU
*menu
, POINT16 pt
)
195 if (menu
->wFlags
& MF_POPUP
) return FALSE
;
196 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return FALSE
;
197 if (!(wndPtr
->dwStyle
& WS_SYSMENU
)) return FALSE
;
198 if ((pt
.x
< wndPtr
->rectClient
.left
) ||
199 (pt
.x
>= wndPtr
->rectClient
.left
+SYSMETRICS_CXSIZE
+SYSMETRICS_CXBORDER
))
201 if ((pt
.y
>= wndPtr
->rectClient
.top
- menu
->Height
) ||
202 (pt
.y
< wndPtr
->rectClient
.top
- menu
->Height
-
203 SYSMETRICS_CYSIZE
- SYSMETRICS_CYBORDER
)) return FALSE
;
208 /***********************************************************************
211 * Find a menu item. Return a pointer on the item, and modifies *hmenu
212 * in case the item was in a sub-menu.
214 static MENUITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
219 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(*hmenu
))) return NULL
;
220 if (wFlags
& MF_BYPOSITION
)
222 if (*nPos
>= menu
->nItems
) return NULL
;
223 return &menu
->items
[*nPos
];
227 MENUITEM
*item
= menu
->items
;
228 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
230 if (item
->item_id
== *nPos
)
235 else if (item
->item_flags
& MF_POPUP
)
237 HMENU hsubmenu
= (HMENU
)item
->item_id
;
238 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
251 /***********************************************************************
252 * MENU_FindItemByCoords
254 * Find the item at the specified coordinates (screen coords).
256 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
, int x
, int y
, UINT
*pos
)
262 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return NULL
;
263 x
-= wndPtr
->rectWindow
.left
;
264 y
-= wndPtr
->rectWindow
.top
;
266 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
268 if ((x
>= item
->rect
.left
) && (x
< item
->rect
.right
) &&
269 (y
>= item
->rect
.top
) && (y
< item
->rect
.bottom
))
279 /***********************************************************************
282 * Find the menu item selected by a key press.
283 * Return item id, -1 if none, -2 if we should close the menu.
285 static UINT
MENU_FindItemByKey( HWND hwndOwner
, HMENU hmenu
, UINT key
)
292 if (!IsMenu( hmenu
)) hmenu
= WIN_FindWndPtr(hwndOwner
)->hSysMenu
;
293 if (!hmenu
) return -1;
295 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
298 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
300 if (IS_STRING_ITEM(item
->item_flags
))
302 char *p
= strchr( item
->text
, '&' );
303 if (p
&& (p
[1] != '&') && (toupper(p
[1]) == key
)) return i
;
307 menuchar
= SendMessage32A( hwndOwner
, WM_MENUCHAR
,
308 MAKEWPARAM(key
,menu
->wFlags
), hmenu
);
310 menuchar
= SendMessage16( hwndOwner
, WM_MENUCHAR
, key
,
311 MAKELONG( menu
->wFlags
, hmenu
) );
313 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
314 if (HIWORD(menuchar
) == 1) return -2;
319 /***********************************************************************
322 * Calculate the size of the menu item and store it in lpitem->rect.
324 static void MENU_CalcItemSize( HDC hdc
, MENUITEM
*lpitem
, HWND hwndOwner
,
325 int orgX
, int orgY
, BOOL menuBar
)
330 SetRect16( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
332 if (lpitem
->item_flags
& MF_OWNERDRAW
)
334 MEASUREITEMSTRUCT
*mis
;
335 if (!(mis
= SEGPTR_NEW(MEASUREITEMSTRUCT
))) return;
336 mis
->CtlType
= ODT_MENU
;
337 mis
->itemID
= lpitem
->item_id
;
338 mis
->itemData
= (DWORD
)lpitem
->text
;
339 mis
->itemHeight
= 16;
341 SendMessage16( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)SEGPTR_GET(mis
) );
342 lpitem
->rect
.bottom
+= mis
->itemHeight
;
343 lpitem
->rect
.right
+= mis
->itemWidth
;
344 dprintf_menu( stddeb
, "DrawMenuItem: MeasureItem %04x %dx%d!\n",
345 lpitem
->item_id
, mis
->itemWidth
, mis
->itemHeight
);
350 if (lpitem
->item_flags
& MF_SEPARATOR
)
352 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
358 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
359 if (lpitem
->item_flags
& MF_POPUP
)
360 lpitem
->rect
.right
+= arrow_bitmap_width
;
363 if (lpitem
->item_flags
& MF_BITMAP
)
366 if (GetObject( (HBITMAP16
)(UINT32
)lpitem
->text
,
367 sizeof(BITMAP
), (LPSTR
)&bm
))
369 lpitem
->rect
.right
+= bm
.bmWidth
;
370 lpitem
->rect
.bottom
+= bm
.bmHeight
;
375 /* If we get here, then it must be a text item */
377 if (IS_STRING_ITEM( lpitem
->item_flags
))
379 dwSize
= GetTextExtent( hdc
, lpitem
->text
, strlen(lpitem
->text
) );
380 lpitem
->rect
.right
+= LOWORD(dwSize
);
381 lpitem
->rect
.bottom
+= MAX( HIWORD(dwSize
), SYSMETRICS_CYMENU
);
384 if (menuBar
) lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
385 else if ((p
= strchr( lpitem
->text
, '\t' )) != NULL
)
387 /* Item contains a tab (only meaningful in popup menus) */
388 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+
389 LOWORD( GetTextExtent( hdc
, lpitem
->text
,
390 (int)(p
- lpitem
->text
) ));
391 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
395 if (strchr( lpitem
->text
, '\b' ))
396 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
397 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
398 - arrow_bitmap_width
;
404 /***********************************************************************
405 * MENU_PopupMenuCalcSize
407 * Calculate the size of a popup menu.
409 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND hwndOwner
)
414 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
416 lppop
->Width
= lppop
->Height
= 0;
417 if (lppop
->nItems
== 0) return;
420 while (start
< lppop
->nItems
)
422 lpitem
= &lppop
->items
[start
];
425 maxTab
= maxTabWidth
= 0;
427 /* Parse items until column break or end of menu */
428 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
431 (lpitem
->item_flags
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
432 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
433 if (lpitem
->item_flags
& MF_MENUBARBREAK
) orgX
++;
434 maxX
= MAX( maxX
, lpitem
->rect
.right
);
435 orgY
= lpitem
->rect
.bottom
;
436 if (IS_STRING_ITEM(lpitem
->item_flags
) && lpitem
->xTab
)
438 maxTab
= MAX( maxTab
, lpitem
->xTab
);
439 maxTabWidth
= MAX(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
443 /* Finish the column (set all items to the largest width found) */
444 maxX
= MAX( maxX
, maxTab
+ maxTabWidth
);
445 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
447 lpitem
->rect
.right
= maxX
;
448 if (IS_STRING_ITEM(lpitem
->item_flags
) && lpitem
->xTab
)
449 lpitem
->xTab
= maxTab
;
451 lppop
->Height
= MAX( lppop
->Height
, orgY
);
459 /***********************************************************************
460 * MENU_MenuBarCalcSize
462 * Calculate the size of the menu bar.
464 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT16 lprect
, LPPOPUPMENU lppop
,
468 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
470 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
471 if (lppop
->nItems
== 0) return;
472 dprintf_menu(stddeb
,"MENU_MenuBarCalcSize left=%d top=%d right=%d bottom=%d\n",
473 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
474 lppop
->Width
= lprect
->right
- lprect
->left
;
479 while (start
< lppop
->nItems
)
481 lpitem
= &lppop
->items
[start
];
485 /* Parse items until line break or end of menu */
486 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
488 if ((helpPos
== -1) && (lpitem
->item_flags
& MF_HELP
)) helpPos
= i
;
490 (lpitem
->item_flags
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
491 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
492 if (lpitem
->rect
.right
> lprect
->right
)
494 if (i
!= start
) break;
495 else lpitem
->rect
.right
= lprect
->right
;
497 maxY
= MAX( maxY
, lpitem
->rect
.bottom
);
498 orgX
= lpitem
->rect
.right
;
501 /* Finish the line (set all items to the largest height found) */
502 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
505 lprect
->bottom
= maxY
;
506 lppop
->Height
= lprect
->bottom
- lprect
->top
;
508 /* Flush right all items between the MF_HELP and the last item */
509 /* (if several lines, only move the last line) */
512 lpitem
= &lppop
->items
[lppop
->nItems
-1];
513 orgY
= lpitem
->rect
.top
;
514 orgX
= lprect
->right
;
515 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--)
517 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
518 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
519 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
520 lpitem
->rect
.right
= orgX
;
521 orgX
= lpitem
->rect
.left
;
527 /***********************************************************************
530 * Draw a single menu item.
532 static void MENU_DrawMenuItem( HWND hwnd
, HDC hdc
, MENUITEM
*lpitem
,
533 UINT height
, BOOL menuBar
)
537 if (lpitem
->item_flags
& MF_OWNERDRAW
)
539 DRAWITEMSTRUCT32 dis
;
541 dprintf_menu( stddeb
, "DrawMenuItem: Ownerdraw!\n" );
542 dis
.CtlType
= ODT_MENU
;
543 dis
.itemID
= lpitem
->item_id
;
544 dis
.itemData
= (DWORD
)lpitem
->text
;
546 if (lpitem
->item_flags
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
547 if (lpitem
->item_flags
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
;
548 if (lpitem
->item_flags
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
549 dis
.itemAction
= ODA_DRAWENTIRE
| ODA_SELECT
| ODA_FOCUS
;
552 CONV_RECT16TO32( &lpitem
->rect
, &dis
.rcItem
);
553 SendMessage32A( hwnd
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
557 if (menuBar
&& (lpitem
->item_flags
& MF_SEPARATOR
)) return;
560 /* Draw the background */
562 if (lpitem
->item_flags
& MF_HILITE
)
563 FillRect16( hdc
, &rect
, sysColorObjects
.hbrushHighlight
);
564 else FillRect16( hdc
, &rect
, sysColorObjects
.hbrushMenu
);
565 SetBkMode( hdc
, TRANSPARENT
);
567 /* Draw the separator bar (if any) */
569 if (!menuBar
&& (lpitem
->item_flags
& MF_MENUBARBREAK
))
571 SelectObject( hdc
, sysColorObjects
.hpenWindowFrame
);
572 MoveTo( hdc
, rect
.left
, 0 );
573 LineTo( hdc
, rect
.left
, height
);
575 if (lpitem
->item_flags
& MF_SEPARATOR
)
577 SelectObject( hdc
, sysColorObjects
.hpenWindowFrame
);
578 MoveTo( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
579 LineTo( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
585 if (lpitem
->item_flags
& MF_HILITE
)
587 if (lpitem
->item_flags
& MF_GRAYED
)
588 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
590 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
591 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
595 if (lpitem
->item_flags
& MF_GRAYED
)
596 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
598 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
599 SetBkColor( hdc
, GetSysColor( COLOR_MENU
) );
604 /* Draw the check mark */
606 if (lpitem
->item_flags
& MF_CHECKED
)
608 GRAPH_DrawBitmap(hdc
, lpitem
->hCheckBit
? lpitem
->hCheckBit
:
609 hStdCheck
, rect
.left
,
610 (rect
.top
+rect
.bottom
-check_bitmap_height
) / 2,
611 0, 0, check_bitmap_width
, check_bitmap_height
);
613 else if (lpitem
->hUnCheckBit
!= 0) /* Not checked */
615 GRAPH_DrawBitmap(hdc
, lpitem
->hUnCheckBit
, rect
.left
,
616 (rect
.top
+rect
.bottom
-check_bitmap_height
) / 2,
617 0, 0, check_bitmap_width
, check_bitmap_height
);
620 /* Draw the popup-menu arrow */
622 if (lpitem
->item_flags
& MF_POPUP
)
624 GRAPH_DrawBitmap( hdc
, hStdMnArrow
,
625 rect
.right
-arrow_bitmap_width
-1,
626 (rect
.top
+rect
.bottom
-arrow_bitmap_height
) / 2,
627 0, 0, arrow_bitmap_width
, arrow_bitmap_height
);
630 rect
.left
+= check_bitmap_width
;
631 rect
.right
-= arrow_bitmap_width
;
634 /* Draw the item text or bitmap */
636 if (lpitem
->item_flags
& MF_BITMAP
)
638 GRAPH_DrawBitmap( hdc
, (HBITMAP16
)(UINT32
)lpitem
->text
,
639 rect
.left
, rect
.top
, 0, 0,
640 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
);
643 /* No bitmap - process text if present */
644 else if (IS_STRING_ITEM(lpitem
->item_flags
))
650 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
651 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
652 i
= strlen( lpitem
->text
);
656 for (i
= 0; lpitem
->text
[i
]; i
++)
657 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
661 DrawText16( hdc
, lpitem
->text
, i
, &rect
,
662 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
664 if (lpitem
->text
[i
]) /* There's a tab or flush-right char */
666 if (lpitem
->text
[i
] == '\t')
668 rect
.left
= lpitem
->xTab
;
669 DrawText16( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
,
670 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
672 else DrawText16( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
,
673 DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
);
679 /***********************************************************************
682 * Paint a popup menu.
684 static void MENU_DrawPopupMenu( HWND hwnd
, HDC hdc
, HMENU hmenu
)
691 GetClientRect16( hwnd
, &rect
);
692 FillRect16( hdc
, &rect
, sysColorObjects
.hbrushMenu
);
693 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
694 if (!menu
|| !menu
->nItems
) return;
695 for (i
= menu
->nItems
, item
= menu
->items
; i
> 0; i
--, item
++)
696 MENU_DrawMenuItem( hwnd
, hdc
, item
, menu
->Height
, FALSE
);
700 /***********************************************************************
703 * Paint a menu bar. Returns the height of the menu bar.
705 UINT
MENU_DrawMenuBar(HDC hDC
, LPRECT16 lprect
, HWND hwnd
, BOOL suppress_draw
)
709 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
711 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( (HMENU
)wndPtr
->wIDmenu
);
712 if (lppop
== NULL
|| lprect
== NULL
) return SYSMETRICS_CYMENU
;
713 dprintf_menu(stddeb
,"MENU_DrawMenuBar(%04x, %p, %p); !\n",
715 if (lppop
->Height
== 0) MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
716 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
717 if (suppress_draw
) return lppop
->Height
;
719 FillRect16(hDC
, lprect
, sysColorObjects
.hbrushMenu
);
720 SelectObject( hDC
, sysColorObjects
.hpenWindowFrame
);
721 MoveTo( hDC
, lprect
->left
, lprect
->bottom
);
722 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
724 if (lppop
->nItems
== 0) return SYSMETRICS_CYMENU
;
725 for (i
= 0; i
< lppop
->nItems
; i
++)
727 MENU_DrawMenuItem( hwnd
, hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
);
729 return lppop
->Height
;
733 /***********************************************************************
736 BOOL
MENU_SwitchTPWndTo( HTASK hTask
)
738 /* This is supposed to be called when popup is hidden */
740 TDB
* task
= (TDB
*)GlobalLock16(hTask
);
742 if( !task
) return 0;
744 /* if this task got as far as menu tracking it must have a queue */
746 pTopPWnd
->hInstance
= task
->hInstance
;
747 pTopPWnd
->hmemTaskQ
= task
->hQueue
;
751 /***********************************************************************
754 * Display a popup menu.
756 static BOOL
MENU_ShowPopup(HWND hwndOwner
, HMENU hmenu
, UINT id
, int x
, int y
)
762 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
763 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
765 menu
->items
[menu
->FocusedItem
].item_flags
&= ~(MF_HILITE
|MF_MOUSESELECT
);
766 menu
->FocusedItem
= NO_SELECTED_ITEM
;
768 SendMessage16( hwndOwner
, WM_INITMENUPOPUP
, (WPARAM
)hmenu
,
769 MAKELONG( id
, (menu
->wFlags
& MF_SYSMENU
) ? 1 : 0 ));
770 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
772 wndPtr
= WIN_FindWndPtr( hwndOwner
);
773 if (!wndPtr
) return FALSE
;
777 pTopPWnd
= WIN_FindWndPtr(CreateWindow16( POPUPMENU_CLASS_ATOM
, (SEGPTR
)0,
778 WS_POPUP
| WS_BORDER
, x
, y
,
779 menu
->Width
+ 2*SYSMETRICS_CXBORDER
,
780 menu
->Height
+ 2*SYSMETRICS_CYBORDER
,
781 0, 0, wndPtr
->hInstance
, (SEGPTR
)hmenu
));
782 if (!pTopPWnd
) return FALSE
;
788 /* create new window for the submenu */
789 HWND hWnd
= CreateWindow16( POPUPMENU_CLASS_ATOM
, (SEGPTR
)0,
790 WS_POPUP
| WS_BORDER
, x
, y
,
791 menu
->Width
+ 2*SYSMETRICS_CXBORDER
,
792 menu
->Height
+ 2*SYSMETRICS_CYBORDER
,
793 menu
->hWnd
, 0, wndPtr
->hInstance
, (SEGPTR
)hmenu
);
794 if( !hWnd
) return FALSE
;
801 MENU_SwitchTPWndTo(GetCurrentTask());
802 SendMessage16( pTopPWnd
->hwndSelf
, WM_USER
, (WPARAM
)hmenu
, 0L);
804 menu
->hWnd
= pTopPWnd
->hwndSelf
;
809 SetWindowPos(menu
->hWnd
, 0, x
, y
, menu
->Width
+ 2*SYSMETRICS_CXBORDER
,
810 menu
->Height
+ 2*SYSMETRICS_CYBORDER
,
811 SWP_NOACTIVATE
| SWP_NOZORDER
);
813 /* Display the window */
815 SetWindowPos( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
816 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
817 UpdateWindow( menu
->hWnd
);
822 /***********************************************************************
825 static void MENU_SelectItem( HWND hwndOwner
, HMENU hmenu
, UINT wIndex
,
826 BOOL sendMenuSelect
)
831 lppop
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
832 if (!lppop
->nItems
) return;
833 if ((wIndex
!= NO_SELECTED_ITEM
) &&
834 (wIndex
!= SYSMENU_SELECTED
) &&
835 (lppop
->items
[wIndex
].item_flags
& MF_SEPARATOR
))
836 wIndex
= NO_SELECTED_ITEM
;
837 if (lppop
->FocusedItem
== wIndex
) return;
838 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC( lppop
->hWnd
);
839 else hdc
= GetDCEx( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
841 /* Clear previous highlighted item */
842 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
844 if (lppop
->FocusedItem
== SYSMENU_SELECTED
)
845 NC_DrawSysButton( lppop
->hWnd
, hdc
, FALSE
);
848 lppop
->items
[lppop
->FocusedItem
].item_flags
&=~(MF_HILITE
|MF_MOUSESELECT
);
849 MENU_DrawMenuItem(lppop
->hWnd
,hdc
,&lppop
->items
[lppop
->FocusedItem
],
850 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
) );
854 /* Highlight new item (if any) */
855 lppop
->FocusedItem
= wIndex
;
856 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
858 if (lppop
->FocusedItem
== SYSMENU_SELECTED
)
860 NC_DrawSysButton( lppop
->hWnd
, hdc
, TRUE
);
864 SendMessage32A( hwndOwner
, WM_MENUSELECT
,
865 MAKEWPARAM( WIN_FindWndPtr(lppop
->hWnd
)->hSysMenu
,
866 lppop
->wFlags
| MF_MOUSESELECT
),
869 SendMessage16( hwndOwner
, WM_MENUSELECT
,
870 WIN_FindWndPtr(lppop
->hWnd
)->hSysMenu
,
871 MAKELONG(lppop
->wFlags
| MF_MOUSESELECT
, hmenu
));
876 lppop
->items
[lppop
->FocusedItem
].item_flags
|= MF_HILITE
;
877 MENU_DrawMenuItem( lppop
->hWnd
, hdc
, &lppop
->items
[lppop
->FocusedItem
],
878 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
) );
881 SendMessage32A( hwndOwner
, WM_MENUSELECT
,
882 MAKEWPARAM( lppop
->items
[lppop
->FocusedItem
].item_id
,
883 lppop
->items
[lppop
->FocusedItem
].item_flags
|
887 SendMessage16( hwndOwner
, WM_MENUSELECT
,
888 lppop
->items
[lppop
->FocusedItem
].item_id
,
889 MAKELONG( lppop
->items
[lppop
->FocusedItem
].item_flags
| MF_MOUSESELECT
, hmenu
));
895 else if (sendMenuSelect
)
896 SendMessage32A( hwndOwner
, WM_MENUSELECT
,
897 MAKEWPARAM( (DWORD
)hmenu
, lppop
->wFlags
| MF_MOUSESELECT
),
900 else if (sendMenuSelect
)
901 SendMessage16( hwndOwner
, WM_MENUSELECT
, hmenu
,
902 MAKELONG( lppop
->wFlags
| MF_MOUSESELECT
, hmenu
) );
905 ReleaseDC( lppop
->hWnd
, hdc
);
909 /***********************************************************************
910 * MENU_SelectNextItem
912 static void MENU_SelectNextItem( HWND hwndOwner
, HMENU hmenu
)
917 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
918 if (!menu
->items
) return;
919 if ((menu
->FocusedItem
!= NO_SELECTED_ITEM
) &&
920 (menu
->FocusedItem
!= SYSMENU_SELECTED
))
922 for (i
= menu
->FocusedItem
+1; i
< menu
->nItems
; i
++)
924 if (!(menu
->items
[i
].item_flags
& MF_SEPARATOR
))
926 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
930 if (MENU_HasSysMenu( menu
))
932 MENU_SelectItem( hwndOwner
, hmenu
, SYSMENU_SELECTED
, TRUE
);
936 for (i
= 0; i
< menu
->nItems
; i
++)
938 if (!(menu
->items
[i
].item_flags
& MF_SEPARATOR
))
940 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
944 if (MENU_HasSysMenu( menu
))
945 MENU_SelectItem( hwndOwner
, hmenu
, SYSMENU_SELECTED
, TRUE
);
949 /***********************************************************************
950 * MENU_SelectPrevItem
952 static void MENU_SelectPrevItem( HWND hwndOwner
, HMENU hmenu
)
957 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
958 if (!menu
->items
) return;
959 if ((menu
->FocusedItem
!= NO_SELECTED_ITEM
) &&
960 (menu
->FocusedItem
!= SYSMENU_SELECTED
))
962 for (i
= menu
->FocusedItem
- 1; i
>= 0; i
--)
964 if (!(menu
->items
[i
].item_flags
& MF_SEPARATOR
))
966 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
970 if (MENU_HasSysMenu( menu
))
972 MENU_SelectItem( hwndOwner
, hmenu
, SYSMENU_SELECTED
, TRUE
);
976 for (i
= menu
->nItems
- 1; i
> 0; i
--)
978 if (!(menu
->items
[i
].item_flags
& MF_SEPARATOR
))
980 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
984 if (MENU_HasSysMenu( menu
))
985 MENU_SelectItem( hwndOwner
, hmenu
, SYSMENU_SELECTED
, TRUE
);
989 /**********************************************************************
992 * Set an item flags, id and text ptr.
994 static BOOL
MENU_SetItemData( MENUITEM
*item
, UINT flags
, UINT id
, LPCSTR str
)
996 LPSTR prevText
= IS_STRING_ITEM(item
->item_flags
) ? item
->text
: NULL
;
998 if (IS_STRING_ITEM(flags
))
1002 flags
|= MF_SEPARATOR
;
1008 /* Item beginning with a backspace is a help item */
1014 if (!(text
= HEAP_strdupA( SystemHeap
, 0, str
))) return FALSE
;
1018 else if ((flags
& MF_BITMAP
) || (flags
& MF_OWNERDRAW
))
1019 item
->text
= (LPSTR
)str
;
1020 else item
->text
= NULL
;
1022 item
->item_flags
= flags
& ~(MF_HILITE
| MF_MOUSESELECT
);
1024 SetRectEmpty16( &item
->rect
);
1025 if (prevText
) HeapFree( SystemHeap
, 0, prevText
);
1030 /**********************************************************************
1033 * Insert a new item into a menu.
1035 static MENUITEM
*MENU_InsertItem( HMENU hMenu
, UINT pos
, UINT flags
)
1040 if (!(menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
)))
1042 dprintf_menu( stddeb
, "MENU_InsertItem: %04x not a menu handle\n",
1047 /* Find where to insert new item */
1049 if ((flags
& MF_BYPOSITION
) &&
1050 ((pos
== (UINT
)-1) || (pos
== menu
->nItems
)))
1052 /* Special case: append to menu */
1053 /* Some programs specify the menu length to do that */
1058 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
1060 dprintf_menu( stddeb
, "MENU_InsertItem: item %x not found\n",
1064 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
)))
1066 dprintf_menu(stddeb
,"MENU_InsertItem: %04x not a menu handle\n",
1072 /* Create new items array */
1074 newItems
= HeapAlloc( SystemHeap
, 0, sizeof(MENUITEM
) * (menu
->nItems
+1) );
1077 dprintf_menu( stddeb
, "MENU_InsertItem: allocation failed\n" );
1080 if (menu
->nItems
> 0)
1082 /* Copy the old array into the new */
1083 if (pos
> 0) memcpy( newItems
, menu
->items
, pos
* sizeof(MENUITEM
) );
1084 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &menu
->items
[pos
],
1085 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
1086 HeapFree( SystemHeap
, 0, menu
->items
);
1088 menu
->items
= newItems
;
1090 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
1091 return &newItems
[pos
];
1095 /**********************************************************************
1096 * MENU_ParseResource
1098 * Parse a standard menu resource and add items to the menu.
1099 * Return a pointer to the end of the resource.
1101 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1108 flags
= GET_WORD(res
);
1109 res
+= sizeof(WORD
);
1110 if (!(flags
& MF_POPUP
))
1113 res
+= sizeof(WORD
);
1115 if (!IS_STRING_ITEM(flags
))
1116 fprintf( stderr
, "MENU_ParseResource: not a string item %04x\n",
1119 if (!unicode
) res
+= strlen(str
) + 1;
1120 else res
+= (STRING32_lstrlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1121 if (flags
& MF_POPUP
)
1123 HMENU hSubMenu
= CreatePopupMenu();
1124 if (!hSubMenu
) return NULL
;
1125 if (!(res
= MENU_ParseResource( res
, hSubMenu
, unicode
)))
1127 if (!unicode
) AppendMenu32A( hMenu
, flags
, (UINT
)hSubMenu
, str
);
1128 else AppendMenu32W( hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1130 else /* Not a popup */
1132 if (!unicode
) AppendMenu32A( hMenu
, flags
, id
, *str
? str
: NULL
);
1133 else AppendMenu32W( hMenu
, flags
, id
,
1134 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1136 } while (!(flags
& MF_END
));
1141 /***********************************************************************
1144 * Return the handle of the selected sub-popup menu (if any).
1146 static HMENU
MENU_GetSubPopup( HMENU hmenu
)
1151 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1152 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return 0;
1153 else if (menu
->FocusedItem
== SYSMENU_SELECTED
)
1154 return WIN_FindWndPtr(menu
->hWnd
)->hSysMenu
;
1156 item
= &menu
->items
[menu
->FocusedItem
];
1157 if (!(item
->item_flags
& MF_POPUP
) || !(item
->item_flags
& MF_MOUSESELECT
))
1159 return (HMENU
)item
->item_id
;
1163 /***********************************************************************
1164 * MENU_HideSubPopups
1166 * Hide the sub-popup menus of this menu.
1168 static void MENU_HideSubPopups( HWND hwndOwner
, HMENU hmenu
,
1169 BOOL sendMenuSelect
)
1172 POPUPMENU
*menu
, *submenu
;
1175 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return;
1176 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return;
1177 if (menu
->FocusedItem
== SYSMENU_SELECTED
)
1179 hsubmenu
= WIN_FindWndPtr(menu
->hWnd
)->hSysMenu
;
1183 item
= &menu
->items
[menu
->FocusedItem
];
1184 if (!(item
->item_flags
& MF_POPUP
) ||
1185 !(item
->item_flags
& MF_MOUSESELECT
)) return;
1186 item
->item_flags
&= ~MF_MOUSESELECT
;
1187 hsubmenu
= (HMENU
)item
->item_id
;
1189 submenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hsubmenu
);
1190 MENU_HideSubPopups( hwndOwner
, hsubmenu
, FALSE
);
1191 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, sendMenuSelect
);
1192 if (submenu
->hWnd
== pTopPWnd
->hwndSelf
)
1194 ShowWindow( submenu
->hWnd
, SW_HIDE
);
1199 DestroyWindow( submenu
->hWnd
);
1205 /***********************************************************************
1208 * Display the sub-menu of the selected item of this menu.
1209 * Return the handle of the submenu, or hmenu if no submenu to display.
1211 static HMENU
MENU_ShowSubPopup( HWND hwndOwner
, HMENU hmenu
, BOOL selectFirst
)
1217 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return hmenu
;
1218 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return hmenu
;
1219 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return hmenu
;
1220 if (menu
->FocusedItem
== SYSMENU_SELECTED
)
1222 MENU_ShowPopup(hwndOwner
, wndPtr
->hSysMenu
, 0, wndPtr
->rectClient
.left
,
1223 wndPtr
->rectClient
.top
- menu
->Height
- 2*SYSMETRICS_CYBORDER
);
1224 if (selectFirst
) MENU_SelectNextItem( hwndOwner
, wndPtr
->hSysMenu
);
1225 return wndPtr
->hSysMenu
;
1227 item
= &menu
->items
[menu
->FocusedItem
];
1228 if (!(item
->item_flags
& MF_POPUP
) ||
1229 (item
->item_flags
& (MF_GRAYED
| MF_DISABLED
))) return hmenu
;
1230 item
->item_flags
|= MF_MOUSESELECT
;
1231 if (menu
->wFlags
& MF_POPUP
)
1233 MENU_ShowPopup( hwndOwner
, (HMENU
)item
->item_id
, menu
->FocusedItem
,
1234 wndPtr
->rectWindow
.left
+ item
->rect
.right
-arrow_bitmap_width
,
1235 wndPtr
->rectWindow
.top
+ item
->rect
.top
);
1239 MENU_ShowPopup( hwndOwner
, (HMENU
)item
->item_id
, menu
->FocusedItem
,
1240 wndPtr
->rectWindow
.left
+ item
->rect
.left
,
1241 wndPtr
->rectWindow
.top
+ item
->rect
.bottom
);
1243 if (selectFirst
) MENU_SelectNextItem( hwndOwner
, (HMENU
)item
->item_id
);
1244 return (HMENU
)item
->item_id
;
1248 /***********************************************************************
1249 * MENU_FindMenuByCoords
1251 * Find the menu containing a given point (in screen coords).
1253 static HMENU
MENU_FindMenuByCoords( HMENU hmenu
, POINT16 pt
)
1258 if (!(hwnd
= WindowFromPoint16( pt
))) return 0;
1261 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1262 if (menu
->hWnd
== hwnd
)
1264 if (!(menu
->wFlags
& MF_POPUP
))
1266 /* Make sure it's in the menu bar (or in system menu) */
1267 WND
*wndPtr
= WIN_FindWndPtr( menu
->hWnd
);
1268 if ((pt
.x
< wndPtr
->rectClient
.left
) ||
1269 (pt
.x
>= wndPtr
->rectClient
.right
) ||
1270 (pt
.y
>= wndPtr
->rectClient
.top
)) return 0;
1271 if (pt
.y
< wndPtr
->rectClient
.top
- menu
->Height
)
1273 if (!MENU_IsInSysMenu( menu
, pt
)) return 0;
1275 /* else it's in the menu bar */
1279 hmenu
= MENU_GetSubPopup( hmenu
);
1285 /***********************************************************************
1286 * MENU_ExecFocusedItem
1288 * Execute a menu item (for instance when user pressed Enter).
1289 * Return TRUE if we can go on with menu tracking.
1291 static BOOL
MENU_ExecFocusedItem( HWND hwndOwner
, HMENU hmenu
,
1292 HMENU
*hmenuCurrent
)
1295 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1296 if (!menu
|| !menu
->nItems
|| (menu
->FocusedItem
== NO_SELECTED_ITEM
) ||
1297 (menu
->FocusedItem
== SYSMENU_SELECTED
)) return TRUE
;
1298 item
= &menu
->items
[menu
->FocusedItem
];
1299 if (!(item
->item_flags
& MF_POPUP
))
1301 if (!(item
->item_flags
& (MF_GRAYED
| MF_DISABLED
)))
1303 PostMessage( hwndOwner
, (menu
->wFlags
& MF_SYSMENU
) ?
1304 WM_SYSCOMMAND
: WM_COMMAND
, item
->item_id
, 0 );
1311 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, TRUE
);
1317 /***********************************************************************
1320 * Handle a button-down event in a menu. Point is in screen coords.
1321 * hmenuCurrent is the top-most visible popup.
1322 * Return TRUE if we can go on with menu tracking.
1324 static BOOL
MENU_ButtonDown( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
,
1331 if (!hmenu
) return FALSE
; /* Outside all menus */
1332 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1333 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1334 if (!item
) /* Maybe in system menu */
1336 if (!MENU_IsInSysMenu( menu
, pt
)) return FALSE
;
1337 id
= SYSMENU_SELECTED
;
1340 if (menu
->FocusedItem
== id
)
1342 if (id
== SYSMENU_SELECTED
) return FALSE
;
1343 if (item
->item_flags
& MF_POPUP
)
1345 if (item
->item_flags
& MF_MOUSESELECT
)
1347 if (menu
->wFlags
& MF_POPUP
)
1349 MENU_HideSubPopups( hwndOwner
, hmenu
, TRUE
);
1350 *hmenuCurrent
= hmenu
;
1354 else *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1359 MENU_HideSubPopups( hwndOwner
, hmenu
, FALSE
);
1360 MENU_SelectItem( hwndOwner
, hmenu
, id
, TRUE
);
1361 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1367 /***********************************************************************
1370 * Handle a button-up event in a menu. Point is in screen coords.
1371 * hmenuCurrent is the top-most visible popup.
1372 * Return TRUE if we can go on with menu tracking.
1374 static BOOL
MENU_ButtonUp( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
,
1382 if (!hmenu
) return FALSE
; /* Outside all menus */
1383 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1384 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1385 if (!item
) /* Maybe in system menu */
1387 if (!MENU_IsInSysMenu( menu
, pt
)) return FALSE
;
1388 id
= SYSMENU_SELECTED
;
1389 hsubmenu
= WIN_FindWndPtr(menu
->hWnd
)->hSysMenu
;
1392 if (menu
->FocusedItem
!= id
) return FALSE
;
1394 if (id
!= SYSMENU_SELECTED
)
1396 if (!(item
->item_flags
& MF_POPUP
))
1398 return MENU_ExecFocusedItem( hwndOwner
, hmenu
, hmenuCurrent
);
1400 hsubmenu
= (HMENU
)item
->item_id
;
1402 /* Select first item of sub-popup */
1403 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, FALSE
);
1404 MENU_SelectNextItem( hwndOwner
, hsubmenu
);
1409 /***********************************************************************
1412 * Handle a motion event in a menu. Point is in screen coords.
1413 * hmenuCurrent is the top-most visible popup.
1414 * Return TRUE if we can go on with menu tracking.
1416 static BOOL
MENU_MouseMove( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
,
1420 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1421 UINT id
= NO_SELECTED_ITEM
;
1425 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1426 if (!item
) /* Maybe in system menu */
1428 if (!MENU_IsInSysMenu( menu
, pt
))
1429 id
= NO_SELECTED_ITEM
; /* Outside all items */
1430 else id
= SYSMENU_SELECTED
;
1433 if (id
== NO_SELECTED_ITEM
)
1435 MENU_SelectItem( hwndOwner
, *hmenuCurrent
, NO_SELECTED_ITEM
, TRUE
);
1437 else if (menu
->FocusedItem
!= id
)
1439 MENU_HideSubPopups( hwndOwner
, hmenu
, FALSE
);
1440 MENU_SelectItem( hwndOwner
, hmenu
, id
, TRUE
);
1441 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1447 /***********************************************************************
1450 * Handle a VK_LEFT key event in a menu.
1451 * hmenuCurrent is the top-most visible popup.
1453 static void MENU_KeyLeft( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
)
1456 HMENU hmenutmp
, hmenuprev
;
1458 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1459 hmenuprev
= hmenutmp
= hmenu
;
1460 while (hmenutmp
!= *hmenuCurrent
)
1462 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
1463 if (hmenutmp
!= *hmenuCurrent
) hmenuprev
= hmenutmp
;
1465 MENU_HideSubPopups( hwndOwner
, hmenuprev
, TRUE
);
1467 if ((hmenuprev
== hmenu
) && !(menu
->wFlags
& MF_POPUP
))
1469 /* Select previous item on the menu bar */
1470 MENU_SelectPrevItem( hwndOwner
, hmenu
);
1471 if (*hmenuCurrent
!= hmenu
)
1473 /* A popup menu was displayed -> display the next one */
1474 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, TRUE
);
1477 else *hmenuCurrent
= hmenuprev
;
1481 /***********************************************************************
1484 * Handle a VK_RIGHT key event in a menu.
1485 * hmenuCurrent is the top-most visible popup.
1487 static void MENU_KeyRight( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
)
1492 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1494 if ((menu
->wFlags
& MF_POPUP
) || (*hmenuCurrent
!= hmenu
))
1496 /* If already displaying a popup, try to display sub-popup */
1497 hmenutmp
= MENU_ShowSubPopup( hwndOwner
, *hmenuCurrent
, TRUE
);
1498 if (hmenutmp
!= *hmenuCurrent
) /* Sub-popup displayed */
1500 *hmenuCurrent
= hmenutmp
;
1505 /* If on menu-bar, go to next item */
1506 if (!(menu
->wFlags
& MF_POPUP
))
1508 MENU_HideSubPopups( hwndOwner
, hmenu
, FALSE
);
1509 MENU_SelectNextItem( hwndOwner
, hmenu
);
1510 if (*hmenuCurrent
!= hmenu
)
1512 /* A popup menu was displayed -> display the next one */
1513 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, TRUE
);
1516 else if (*hmenuCurrent
!= hmenu
) /* Hide last level popup */
1519 hmenuprev
= hmenutmp
= hmenu
;
1520 while (hmenutmp
!= *hmenuCurrent
)
1522 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
1523 if (hmenutmp
!= *hmenuCurrent
) hmenuprev
= hmenutmp
;
1525 MENU_HideSubPopups( hwndOwner
, hmenuprev
, TRUE
);
1526 *hmenuCurrent
= hmenuprev
;
1531 /***********************************************************************
1534 * Menu tracking code.
1535 * If 'x' and 'y' are not 0, we simulate a button-down event at (x,y)
1536 * before beginning tracking. This is to help menu-bar tracking.
1538 static BOOL
MENU_TrackMenu( HMENU hmenu
, UINT wFlags
, int x
, int y
,
1539 HWND hwnd
, const RECT16
*lprect
)
1544 HMENU hmenuCurrent
= hmenu
;
1545 BOOL fClosed
= FALSE
, fRemove
;
1548 fEndMenuCalled
= FALSE
;
1549 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
1552 POINT16 pt
= { x
, y
};
1553 MENU_ButtonDown( hwnd
, hmenu
, &hmenuCurrent
, pt
);
1556 hMsg
= USER_HEAP_ALLOC( sizeof(MSG
) );
1557 msg
= (MSG
*)USER_HEAP_LIN_ADDR( hMsg
);
1560 if (!MSG_InternalGetMessage( (SEGPTR
)USER_HEAP_SEG_ADDR(hMsg
), 0,
1561 hwnd
, MSGF_MENU
, 0, TRUE
))
1565 if ((msg
->message
>= WM_MOUSEFIRST
) && (msg
->message
<= WM_MOUSELAST
))
1567 /* Find the sub-popup for this mouse event (if any) */
1568 HMENU hsubmenu
= MENU_FindMenuByCoords( hmenu
, msg
->pt
);
1570 switch(msg
->message
)
1572 case WM_RBUTTONDOWN
:
1573 case WM_NCRBUTTONDOWN
:
1574 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
1576 case WM_LBUTTONDOWN
:
1577 case WM_NCLBUTTONDOWN
:
1578 fClosed
= !MENU_ButtonDown( hwnd
, hsubmenu
,
1579 &hmenuCurrent
, msg
->pt
);
1583 case WM_NCRBUTTONUP
:
1584 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
1587 case WM_NCLBUTTONUP
:
1588 /* If outside all menus but inside lprect, ignore it */
1589 if (!hsubmenu
&& lprect
&& PtInRect16(lprect
, msg
->pt
)) break;
1590 fClosed
= !MENU_ButtonUp( hwnd
, hsubmenu
,
1591 &hmenuCurrent
, msg
->pt
);
1592 fRemove
= TRUE
; /* Remove event even if outside menu */
1596 case WM_NCMOUSEMOVE
:
1597 if ((msg
->wParam
& MK_LBUTTON
) ||
1598 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
->wParam
& MK_RBUTTON
)))
1600 fClosed
= !MENU_MouseMove( hwnd
, hsubmenu
,
1601 &hmenuCurrent
, msg
->pt
);
1606 else if ((msg
->message
>= WM_KEYFIRST
) && (msg
->message
<= WM_KEYLAST
))
1608 fRemove
= TRUE
; /* Keyboard messages are always removed */
1609 switch(msg
->message
)
1615 MENU_SelectItem( hwnd
, hmenuCurrent
, NO_SELECTED_ITEM
, FALSE
);
1616 MENU_SelectNextItem( hwnd
, hmenuCurrent
);
1620 MENU_SelectItem( hwnd
, hmenuCurrent
, NO_SELECTED_ITEM
, FALSE
);
1621 MENU_SelectPrevItem( hwnd
, hmenuCurrent
);
1625 MENU_SelectPrevItem( hwnd
, hmenuCurrent
);
1629 /* If on menu bar, pull-down the menu */
1630 if (!(menu
->wFlags
& MF_POPUP
) && (hmenuCurrent
== hmenu
))
1631 hmenuCurrent
= MENU_ShowSubPopup( hwnd
, hmenu
, TRUE
);
1633 MENU_SelectNextItem( hwnd
, hmenuCurrent
);
1637 MENU_KeyLeft( hwnd
, hmenu
, &hmenuCurrent
);
1641 MENU_KeyRight( hwnd
, hmenu
, &hmenuCurrent
);
1646 fClosed
= !MENU_ExecFocusedItem( hwnd
, hmenuCurrent
,
1657 break; /* WM_KEYDOWN */
1667 break; /* WM_SYSKEYDOWN */
1671 /* Hack to avoid control chars. */
1672 /* We will find a better way real soon... */
1673 if ((msg
->wParam
<= 32) || (msg
->wParam
>= 127)) break;
1674 pos
= MENU_FindItemByKey( hwnd
, hmenuCurrent
, msg
->wParam
);
1675 if (pos
== (UINT
)-2) fClosed
= TRUE
;
1676 else if (pos
== (UINT
)-1) MessageBeep(0);
1679 MENU_SelectItem( hwnd
, hmenuCurrent
, pos
, TRUE
);
1680 fClosed
= !MENU_ExecFocusedItem( hwnd
, hmenuCurrent
,
1685 break; /* WM_CHAR */
1686 } /* switch(msg->message) */
1690 DispatchMessage( msg
);
1692 if (fEndMenuCalled
) fClosed
= TRUE
;
1693 if (!fClosed
) fRemove
= TRUE
;
1695 if (fRemove
) /* Remove the message from the queue */
1696 PeekMessage( msg
, 0, msg
->message
, msg
->message
, PM_REMOVE
);
1698 USER_HEAP_FREE( hMsg
);
1700 MENU_HideSubPopups( hwnd
, hmenu
, FALSE
);
1701 if (menu
->wFlags
& MF_POPUP
)
1703 ShowWindow( menu
->hWnd
, SW_HIDE
);
1706 MENU_SelectItem( hwnd
, hmenu
, NO_SELECTED_ITEM
, FALSE
);
1707 SendMessage16( hwnd
, WM_MENUSELECT
, 0, MAKELONG( 0xffff, 0 ) );
1708 fEndMenuCalled
= FALSE
;
1713 /***********************************************************************
1714 * MENU_TrackMouseMenuBar
1716 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
1718 void MENU_TrackMouseMenuBar( HWND hwnd
, POINT16 pt
)
1720 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1722 SendMessage16( hwnd
, WM_ENTERMENULOOP
, 0, 0 );
1723 SendMessage16( hwnd
, WM_INITMENU
, wndPtr
->wIDmenu
, 0 );
1724 MENU_TrackMenu( (HMENU
)wndPtr
->wIDmenu
, TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
1725 pt
.x
, pt
.y
, hwnd
, NULL
);
1726 SendMessage16( hwnd
, WM_EXITMENULOOP
, 0, 0 );
1731 /***********************************************************************
1732 * MENU_TrackKbdMenuBar
1734 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
1736 void MENU_TrackKbdMenuBar( WND
* wndPtr
, UINT wParam
, INT vkey
)
1738 UINT uItem
= NO_SELECTED_ITEM
;
1741 /* find window that has a menu
1744 if( !(wndPtr
->dwStyle
& WS_CHILD
) )
1746 wndPtr
= WIN_FindWndPtr( GetActiveWindow() );
1747 if( !wndPtr
) return;
1750 while( wndPtr
->dwStyle
& WS_CHILD
&&
1751 !(wndPtr
->dwStyle
& WS_SYSMENU
) )
1752 if( !(wndPtr
= wndPtr
->parent
) ) return;
1754 if( wndPtr
->dwStyle
& WS_CHILD
|| !wndPtr
->wIDmenu
)
1755 if( !(wndPtr
->dwStyle
& WS_SYSMENU
) )
1758 hTrackMenu
= ( IsMenu( wndPtr
->wIDmenu
) )? wndPtr
->wIDmenu
:
1762 SendMessage16( wndPtr
->hwndSelf
, WM_ENTERMENULOOP
, 0, 0 );
1763 SendMessage16( wndPtr
->hwndSelf
, WM_INITMENU
, wndPtr
->wIDmenu
, 0 );
1765 /* find suitable menu entry
1768 if( vkey
== VK_SPACE
)
1769 uItem
= SYSMENU_SELECTED
;
1772 uItem
= MENU_FindItemByKey( wndPtr
->hwndSelf
, wndPtr
->wIDmenu
, vkey
);
1773 if( uItem
>= 0xFFFE )
1775 if( uItem
== 0xFFFF )
1777 SendMessage16( wndPtr
->hwndSelf
, WM_EXITMENULOOP
, 0, 0 );
1783 MENU_SelectItem( wndPtr
->hwndSelf
, hTrackMenu
, uItem
, TRUE
);
1784 if( uItem
== NO_SELECTED_ITEM
)
1785 MENU_SelectNextItem( wndPtr
->hwndSelf
, hTrackMenu
);
1787 PostMessage( wndPtr
->hwndSelf
, WM_KEYDOWN
, VK_DOWN
, 0L );
1789 MENU_TrackMenu( hTrackMenu
, TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
1790 0, 0, wndPtr
->hwndSelf
, NULL
);
1792 SendMessage16( wndPtr
->hwndSelf
, WM_EXITMENULOOP
, 0, 0 );
1797 /**********************************************************************
1798 * TrackPopupMenu16 (USER.416)
1800 BOOL16
TrackPopupMenu16( HMENU16 hMenu
, UINT16 wFlags
, INT16 x
, INT16 y
,
1801 INT16 nReserved
, HWND16 hWnd
, const RECT16
*lpRect
)
1806 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
))
1807 ret
= MENU_TrackMenu( hMenu
, wFlags
, 0, 0, hWnd
, lpRect
);
1813 /**********************************************************************
1814 * TrackPopupMenu32 (USER32.548)
1816 BOOL32
TrackPopupMenu32( HMENU32 hMenu
, UINT32 wFlags
, INT32 x
, INT32 y
,
1817 INT32 nReserved
, HWND32 hWnd
, const RECT32
*lpRect
)
1820 CONV_RECT32TO16( lpRect
, &r
);
1821 return TrackPopupMenu16( hMenu
, wFlags
, x
, y
, nReserved
, hWnd
, &r
);
1825 /***********************************************************************
1828 LRESULT
PopupMenuWndProc(HWND hwnd
,UINT message
,WPARAM wParam
,LPARAM lParam
)
1834 CREATESTRUCT16
*cs
= (CREATESTRUCT16
*)PTR_SEG_TO_LIN(lParam
);
1836 HMENU hmenu
= (HMENU
) (cs
->lpCreateParams
);
1837 SetWindowLong( hwnd
, 0, hmenu
);
1839 HMENU hmenu
= (HMENU
) ((int)cs
->lpCreateParams
& 0xffff);
1840 SetWindowWord( hwnd
, 0, hmenu
);
1845 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1846 return MA_NOACTIVATE
;
1851 BeginPaint16( hwnd
, &ps
);
1852 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
1854 (HMENU
)GetWindowLong( hwnd
, 0 )
1856 (HMENU
)GetWindowWord( hwnd
, 0 )
1859 EndPaint16( hwnd
, &ps
);
1864 /* zero out global pointer in case system popup
1865 * was destroyed by AppExit
1868 if( hwnd
== pTopPWnd
->hwndSelf
)
1877 SetWindowLong( hwnd
, 0, (HMENU
)wParam
);
1879 SetWindowWord( hwnd
, 0, (HMENU
)wParam
);
1883 return DefWindowProc16(hwnd
, message
, wParam
, lParam
);
1889 /***********************************************************************
1890 * MENU_GetMenuBarHeight
1892 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
1894 UINT
MENU_GetMenuBarHeight( HWND hwnd
, UINT menubarWidth
, int orgX
, int orgY
)
1901 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
1902 if (!(lppop
= (LPPOPUPMENU
)USER_HEAP_LIN_ADDR((HMENU
)wndPtr
->wIDmenu
)))
1904 hdc
= GetDC( hwnd
);
1905 SetRect16(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+SYSMETRICS_CYMENU
);
1906 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
1907 ReleaseDC( hwnd
, hdc
);
1908 return lppop
->Height
;
1912 /*******************************************************************
1913 * ChangeMenu16 (USER.153)
1915 BOOL16
ChangeMenu16( HMENU16 hMenu
, UINT16 pos
, SEGPTR data
,
1916 UINT16 id
, UINT16 flags
)
1918 dprintf_menu( stddeb
,"ChangeMenu16: menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
1919 hMenu
, pos
, (DWORD
)data
, id
, flags
);
1920 if (flags
& MF_APPEND
) return AppendMenu16( hMenu
, flags
& ~MF_APPEND
,
1922 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
1923 /* for MF_DELETE. We should check the parameters for all others */
1924 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
1925 if (flags
& MF_DELETE
) return DeleteMenu( hMenu
, pos
, flags
& ~MF_DELETE
);
1926 if (flags
& MF_CHANGE
) return ModifyMenu16( hMenu
, pos
, flags
& ~MF_CHANGE
,
1928 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
1929 flags
& MF_BYPOSITION
? pos
: id
,
1930 flags
& ~MF_REMOVE
);
1931 /* Default: MF_INSERT */
1932 return InsertMenu16( hMenu
, pos
, flags
, id
, data
);
1936 /*******************************************************************
1937 * ChangeMenu32A (USER32.22)
1939 BOOL32
ChangeMenu32A( HMENU32 hMenu
, UINT32 pos
, LPCSTR data
,
1940 UINT32 id
, UINT32 flags
)
1942 dprintf_menu( stddeb
,"ChangeMenu32A: menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
1943 hMenu
, pos
, (DWORD
)data
, id
, flags
);
1944 if (flags
& MF_APPEND
) return AppendMenu32A( hMenu
, flags
& ~MF_APPEND
,
1946 if (flags
& MF_DELETE
) return DeleteMenu( hMenu
, pos
, flags
& ~MF_DELETE
);
1947 if (flags
& MF_CHANGE
) return ModifyMenu32A(hMenu
, pos
, flags
& ~MF_CHANGE
,
1949 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
1950 flags
& MF_BYPOSITION
? pos
: id
,
1951 flags
& ~MF_REMOVE
);
1952 /* Default: MF_INSERT */
1953 return InsertMenu32A( hMenu
, pos
, flags
, id
, data
);
1957 /*******************************************************************
1958 * ChangeMenu32W (USER32.23)
1960 BOOL32
ChangeMenu32W( HMENU32 hMenu
, UINT32 pos
, LPCWSTR data
,
1961 UINT32 id
, UINT32 flags
)
1963 dprintf_menu( stddeb
,"ChangeMenu32W: menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
1964 hMenu
, pos
, (DWORD
)data
, id
, flags
);
1965 if (flags
& MF_APPEND
) return AppendMenu32W( hMenu
, flags
& ~MF_APPEND
,
1967 if (flags
& MF_DELETE
) return DeleteMenu( hMenu
, pos
, flags
& ~MF_DELETE
);
1968 if (flags
& MF_CHANGE
) return ModifyMenu32W(hMenu
, pos
, flags
& ~MF_CHANGE
,
1970 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
1971 flags
& MF_BYPOSITION
? pos
: id
,
1972 flags
& ~MF_REMOVE
);
1973 /* Default: MF_INSERT */
1974 return InsertMenu32W( hMenu
, pos
, flags
, id
, data
);
1978 /*******************************************************************
1979 * CheckMenuItem (USER.154)
1981 INT
CheckMenuItem( HMENU hMenu
, UINT id
, UINT flags
)
1986 dprintf_menu( stddeb
,"CheckMenuItem: %04x %04x %04x\n", hMenu
, id
, flags
);
1987 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
1988 ret
= item
->item_flags
& MF_CHECKED
;
1989 if (flags
& MF_CHECKED
) item
->item_flags
|= MF_CHECKED
;
1990 else item
->item_flags
&= ~MF_CHECKED
;
1995 /**********************************************************************
1996 * EnableMenuItem [USER.155]
1998 BOOL
EnableMenuItem(HMENU hMenu
, UINT wItemID
, UINT wFlags
)
2001 dprintf_menu(stddeb
,"EnableMenuItem (%04x, %04X, %04X) !\n",
2002 hMenu
, wItemID
, wFlags
);
2003 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return FALSE
;
2005 /* We can't have MF_GRAYED and MF_DISABLED together */
2006 if (wFlags
& MF_GRAYED
)
2008 item
->item_flags
= (item
->item_flags
& ~MF_DISABLED
) | MF_GRAYED
;
2010 else if (wFlags
& MF_DISABLED
)
2012 item
->item_flags
= (item
->item_flags
& ~MF_GRAYED
) | MF_DISABLED
;
2014 else /* MF_ENABLED */
2016 item
->item_flags
&= ~(MF_GRAYED
| MF_DISABLED
);
2022 /*******************************************************************
2023 * GetMenuString (USER.161)
2025 int GetMenuString( HMENU hMenu
, UINT wItemID
,
2026 LPSTR str
, short nMaxSiz
, UINT wFlags
)
2030 dprintf_menu( stddeb
, "GetMenuString: menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
2031 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
2032 if (!str
|| !nMaxSiz
) return 0;
2034 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
2035 if (!IS_STRING_ITEM(item
->item_flags
)) return 0;
2036 lstrcpyn( str
, item
->text
, nMaxSiz
);
2037 dprintf_menu( stddeb
, "GetMenuString: returning '%s'\n", str
);
2042 /**********************************************************************
2043 * HiliteMenuItem [USER.162]
2045 BOOL
HiliteMenuItem(HWND hWnd
, HMENU hMenu
, UINT wItemID
, UINT wHilite
)
2048 dprintf_menu(stddeb
,"HiliteMenuItem(%04x, %04x, %04x, %04x);\n",
2049 hWnd
, hMenu
, wItemID
, wHilite
);
2050 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
2051 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
2052 if (menu
->FocusedItem
== wItemID
) return TRUE
;
2053 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
2054 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
);
2059 /**********************************************************************
2060 * GetMenuState [USER.250]
2062 UINT
GetMenuState(HMENU hMenu
, UINT wItemID
, UINT wFlags
)
2065 dprintf_menu(stddeb
,"GetMenuState(%04x, %04x, %04x);\n",
2066 hMenu
, wItemID
, wFlags
);
2067 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
2068 if (item
->item_flags
& MF_POPUP
)
2070 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( (HMENU
)item
->item_id
);
2071 if (!menu
) return -1;
2072 else return (menu
->nItems
<< 8) | (menu
->wFlags
& 0xff);
2074 else return item
->item_flags
;
2078 /**********************************************************************
2079 * GetMenuItemCount [USER.263]
2081 INT
GetMenuItemCount(HMENU hMenu
)
2084 dprintf_menu(stddeb
,"GetMenuItemCount(%04x);\n", hMenu
);
2085 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2086 if (menu
== NULL
) return (UINT
)-1;
2087 dprintf_menu(stddeb
,"GetMenuItemCount(%04x) return %d \n",
2088 hMenu
, menu
->nItems
);
2089 return menu
->nItems
;
2093 /**********************************************************************
2094 * GetMenuItemID [USER.264]
2096 UINT
GetMenuItemID(HMENU hMenu
, int nPos
)
2100 dprintf_menu(stddeb
,"GetMenuItemID(%04x, %d);\n", hMenu
, nPos
);
2101 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
2102 if ((nPos
< 0) || (nPos
>= menu
->nItems
)) return -1;
2103 if (menu
->items
[nPos
].item_flags
& MF_POPUP
) return -1;
2104 return menu
->items
[nPos
].item_id
;
2108 /*******************************************************************
2109 * InsertMenu16 (USER.410)
2111 BOOL16
InsertMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
2112 UINT16 id
, SEGPTR data
)
2114 if (IS_STRING_ITEM(flags
) && data
)
2115 return InsertMenu32A( hMenu
, (INT32
)(INT16
)pos
, flags
, id
,
2116 (LPSTR
)PTR_SEG_TO_LIN(data
) );
2117 return InsertMenu32A( hMenu
, (INT32
)(INT16
)pos
, flags
, id
, (LPSTR
)data
);
2121 /*******************************************************************
2122 * InsertMenu32A (USER32.321)
2124 BOOL32
InsertMenu32A( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2125 UINT32 id
, LPCSTR str
)
2129 if (IS_STRING_ITEM(flags
) && str
)
2130 dprintf_menu( stddeb
, "InsertMenu: %04x %d %04x %04x '%s'\n",
2131 hMenu
, pos
, flags
, id
, str
);
2132 else dprintf_menu( stddeb
, "InsertMenu: %04x %d %04x %04x %08lx\n",
2133 hMenu
, pos
, flags
, id
, (DWORD
)str
);
2135 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
2137 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
2139 RemoveMenu( hMenu
, pos
, flags
);
2143 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
2144 ((POPUPMENU
*)USER_HEAP_LIN_ADDR((HMENU
)id
))->wFlags
|= MF_POPUP
;
2146 item
->hCheckBit
= hStdCheck
;
2147 item
->hUnCheckBit
= 0;
2152 /*******************************************************************
2153 * InsertMenu32W (USER32.324)
2155 BOOL32
InsertMenu32W( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2156 UINT32 id
, LPCWSTR str
)
2160 if (IS_STRING_ITEM(flags
) && str
)
2162 LPSTR newstr
= STRING32_DupUniToAnsi( str
);
2163 ret
= InsertMenu32A( hMenu
, pos
, flags
, id
, newstr
);
2167 else return InsertMenu32A( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
2171 /*******************************************************************
2172 * AppendMenu16 (USER.411)
2174 BOOL16
AppendMenu16( HMENU16 hMenu
, UINT16 flags
, UINT16 id
, SEGPTR data
)
2176 return InsertMenu16( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
2180 /*******************************************************************
2181 * AppendMenu32A (USER32.4)
2183 BOOL32
AppendMenu32A( HMENU32 hMenu
, UINT32 flags
, UINT32 id
, LPCSTR data
)
2185 return InsertMenu32A( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
2189 /*******************************************************************
2190 * AppendMenu32W (USER32.5)
2192 BOOL32
AppendMenu32W( HMENU32 hMenu
, UINT32 flags
, UINT32 id
, LPCWSTR data
)
2194 return InsertMenu32W( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
2198 /**********************************************************************
2199 * RemoveMenu [USER.412]
2201 BOOL
RemoveMenu(HMENU hMenu
, UINT nPos
, UINT wFlags
)
2206 dprintf_menu(stddeb
,"RemoveMenu (%04x, %04x, %04x)\n",hMenu
, nPos
, wFlags
);
2207 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
2208 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
2212 if (IS_STRING_ITEM(item
->item_flags
) && item
->text
)
2213 HeapFree( SystemHeap
, 0, item
->text
);
2214 if (--menu
->nItems
== 0)
2216 HeapFree( SystemHeap
, 0, menu
->items
);
2221 while(nPos
< menu
->nItems
)
2227 menu
->items
= HeapReAlloc( SystemHeap
, 0, menu
->items
,
2228 menu
->nItems
* sizeof(MENUITEM
) );
2234 /**********************************************************************
2235 * DeleteMenu [USER.413]
2237 BOOL
DeleteMenu(HMENU hMenu
, UINT nPos
, UINT wFlags
)
2239 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
2240 if (!item
) return FALSE
;
2241 if (item
->item_flags
& MF_POPUP
) DestroyMenu( (HMENU
)item
->item_id
);
2242 /* nPos is now the position of the item */
2243 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
2248 /*******************************************************************
2249 * ModifyMenu16 (USER.414)
2251 BOOL16
ModifyMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
2252 UINT16 id
, SEGPTR data
)
2254 if (IS_STRING_ITEM(flags
))
2255 return ModifyMenu32A( hMenu
, (INT32
)(INT16
)pos
, flags
, id
,
2256 (LPSTR
)PTR_SEG_TO_LIN(data
) );
2257 return ModifyMenu32A( hMenu
, (INT32
)(INT16
)pos
, flags
, id
, (LPSTR
)data
);
2261 /*******************************************************************
2262 * ModifyMenu32A (USER32.396)
2264 BOOL32
ModifyMenu32A( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2265 UINT32 id
, LPCSTR str
)
2268 HMENU hMenu16
= hMenu
;
2271 if (IS_STRING_ITEM(flags
))
2273 dprintf_menu( stddeb
, "ModifyMenu: %04x %d %04x %04x '%s'\n",
2274 hMenu
, pos
, flags
, id
, str
? str
: "#NULL#" );
2275 if (!str
) return FALSE
;
2279 dprintf_menu( stddeb
, "ModifyMenu: %04x %d %04x %04x %08lx\n",
2280 hMenu
, pos
, flags
, id
, (DWORD
)str
);
2283 if (!(item
= MENU_FindItem( &hMenu16
, &pos16
, flags
))) return FALSE
;
2284 return MENU_SetItemData( item
, flags
, id
, str
);
2288 /*******************************************************************
2289 * ModifyMenu32W (USER32.397)
2291 BOOL32
ModifyMenu32W( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2292 UINT32 id
, LPCWSTR str
)
2296 if (IS_STRING_ITEM(flags
) && str
)
2298 LPSTR newstr
= STRING32_DupUniToAnsi( str
);
2299 ret
= ModifyMenu32A( hMenu
, pos
, flags
, id
, newstr
);
2303 else return ModifyMenu32A( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
2307 /**********************************************************************
2308 * CreatePopupMenu [USER.415]
2310 HMENU
CreatePopupMenu()
2315 if (!(hmenu
= CreateMenu())) return 0;
2316 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
2317 menu
->wFlags
|= MF_POPUP
;
2322 /**********************************************************************
2323 * GetMenuCheckMarkDimensions [USER.417]
2325 DWORD
GetMenuCheckMarkDimensions()
2327 return MAKELONG( check_bitmap_width
, check_bitmap_height
);
2331 /**********************************************************************
2332 * SetMenuItemBitmaps [USER.418]
2334 BOOL
SetMenuItemBitmaps(HMENU hMenu
, UINT nPos
, UINT wFlags
,
2335 HBITMAP hNewUnCheck
, HBITMAP hNewCheck
)
2338 dprintf_menu(stddeb
,"SetMenuItemBitmaps(%04x, %04x, %04x, %04x, %04x)\n",
2339 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
2340 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
2342 if (!hNewCheck
&& !hNewUnCheck
)
2344 /* If both are NULL, restore default bitmaps */
2345 item
->hCheckBit
= hStdCheck
;
2346 item
->hUnCheckBit
= 0;
2347 item
->item_flags
&= ~MF_USECHECKBITMAPS
;
2349 else /* Install new bitmaps */
2351 item
->hCheckBit
= hNewCheck
;
2352 item
->hUnCheckBit
= hNewUnCheck
;
2353 item
->item_flags
|= MF_USECHECKBITMAPS
;
2359 /**********************************************************************
2360 * CreateMenu [USER.151]
2366 dprintf_menu(stddeb
,"CreateMenu !\n");
2367 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) )))
2369 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2371 menu
->wMagic
= MENU_MAGIC
;
2378 menu
->FocusedItem
= NO_SELECTED_ITEM
;
2379 dprintf_menu(stddeb
,"CreateMenu // return %04x\n", hMenu
);
2384 /**********************************************************************
2385 * DestroyMenu [USER.152]
2387 BOOL
DestroyMenu(HMENU hMenu
)
2390 dprintf_menu(stddeb
,"DestroyMenu (%04x) !\n", hMenu
);
2392 if (hMenu
== 0) return FALSE
;
2393 /* Silently ignore attempts to destroy default system menu */
2394 if (hMenu
== MENU_DefSysMenu
) return TRUE
;
2395 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2396 if (!lppop
|| (lppop
->wMagic
!= MENU_MAGIC
)) return FALSE
;
2397 lppop
->wMagic
= 0; /* Mark it as destroyed */
2398 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
&& lppop
->hWnd
!= pTopPWnd
->hwndSelf
)
2399 DestroyWindow( lppop
->hWnd
);
2404 MENUITEM
*item
= lppop
->items
;
2405 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
2407 if (item
->item_flags
& MF_POPUP
)
2408 DestroyMenu( (HMENU
)item
->item_id
);
2409 if (IS_STRING_ITEM(item
->item_flags
) && item
->text
)
2410 HeapFree( SystemHeap
, 0, item
->text
);
2412 HeapFree( SystemHeap
, 0, lppop
->items
);
2414 USER_HEAP_FREE( hMenu
);
2415 dprintf_menu(stddeb
,"DestroyMenu (%04x) // End !\n", hMenu
);
2419 /**********************************************************************
2420 * GetSystemMenu [USER.156]
2422 HMENU
GetSystemMenu(HWND hWnd
, BOOL bRevert
)
2424 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
2425 if (!wndPtr
) return 0;
2427 if (!wndPtr
->hSysMenu
|| (wndPtr
->hSysMenu
== MENU_DefSysMenu
))
2429 wndPtr
->hSysMenu
= MENU_CopySysMenu();
2430 return wndPtr
->hSysMenu
;
2432 if (!bRevert
) return wndPtr
->hSysMenu
;
2433 if (wndPtr
->hSysMenu
) DestroyMenu(wndPtr
->hSysMenu
);
2434 wndPtr
->hSysMenu
= MENU_CopySysMenu();
2435 return wndPtr
->hSysMenu
;
2439 /*******************************************************************
2440 * SetSystemMenu (USER.280)
2442 BOOL
SetSystemMenu( HWND hwnd
, HMENU hMenu
)
2446 if (!(wndPtr
= WIN_FindWndPtr(hwnd
))) return FALSE
;
2447 if (wndPtr
->hSysMenu
&& (wndPtr
->hSysMenu
!= MENU_DefSysMenu
))
2448 DestroyMenu( wndPtr
->hSysMenu
);
2449 wndPtr
->hSysMenu
= hMenu
;
2454 /**********************************************************************
2455 * GetMenu [USER.157]
2457 HMENU
GetMenu(HWND hWnd
)
2459 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
2460 if (wndPtr
== NULL
) return 0;
2461 return (HMENU
)wndPtr
->wIDmenu
;
2465 /**********************************************************************
2466 * SetMenu [USER.158]
2468 BOOL
SetMenu(HWND hWnd
, HMENU hMenu
)
2471 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
2472 if (wndPtr
== NULL
) {
2473 fprintf(stderr
,"SetMenu(%04x, %04x) // Bad window handle !\n",
2477 dprintf_menu(stddeb
,"SetMenu(%04x, %04x);\n", hWnd
, hMenu
);
2478 if (GetCapture() == hWnd
) ReleaseCapture();
2479 wndPtr
->wIDmenu
= (UINT
)hMenu
;
2482 lpmenu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2483 if (lpmenu
== NULL
) {
2484 fprintf(stderr
,"SetMenu(%04x, %04x) // Bad menu handle !\n",
2488 lpmenu
->hWnd
= hWnd
;
2489 lpmenu
->wFlags
&= ~MF_POPUP
; /* Can't be a popup */
2490 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
2492 if (IsWindowVisible(hWnd
))
2493 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
2494 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
2500 /**********************************************************************
2501 * GetSubMenu [USER.159]
2503 HMENU
GetSubMenu(HMENU hMenu
, short nPos
)
2507 dprintf_menu(stddeb
,"GetSubMenu (%04x, %04X) !\n", hMenu
, nPos
);
2508 if (!(lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return 0;
2509 if ((UINT
)nPos
>= lppop
->nItems
) return 0;
2510 if (!(lppop
->items
[nPos
].item_flags
& MF_POPUP
)) return 0;
2511 return (HMENU
)lppop
->items
[nPos
].item_id
;
2515 /**********************************************************************
2516 * DrawMenuBar [USER.160]
2518 void DrawMenuBar(HWND hWnd
)
2522 dprintf_menu(stddeb
,"DrawMenuBar (%04x)\n", hWnd
);
2523 wndPtr
= WIN_FindWndPtr(hWnd
);
2524 if (wndPtr
!= NULL
&& (wndPtr
->dwStyle
& WS_CHILD
) == 0 &&
2525 wndPtr
->wIDmenu
!= 0) {
2526 dprintf_menu(stddeb
,"DrawMenuBar wIDmenu=%04X \n",
2528 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR((HMENU
)wndPtr
->wIDmenu
);
2529 if (lppop
== NULL
) return;
2531 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
2532 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
2533 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
2538 /***********************************************************************
2539 * EndMenu (USER.187)
2543 /* FIXME: this won't work when we have multiple tasks... */
2544 fEndMenuCalled
= TRUE
;
2548 /***********************************************************************
2549 * LookupMenuHandle (USER.217)
2551 HMENU
LookupMenuHandle( HMENU hmenu
, INT id
)
2553 if (!MENU_FindItem( &hmenu
, &id
, MF_BYCOMMAND
)) return 0;
2558 /**********************************************************************
2559 * LoadMenu (USER.150)
2561 HMENU
LoadMenu( HINSTANCE instance
, SEGPTR name
)
2569 char *str
= (char *)PTR_SEG_TO_LIN( name
);
2570 dprintf_menu( stddeb
, "LoadMenu(%04x,'%s')\n", instance
, str
);
2571 if (str
[0] == '#') name
= (SEGPTR
)atoi( str
+ 1 );
2574 dprintf_resource(stddeb
,"LoadMenu(%04x,%04x)\n",instance
,LOWORD(name
));
2576 if (!name
) return 0;
2578 /* check for Win32 module */
2579 instance
= GetExePtr( instance
);
2580 if (MODULE_GetPtr(instance
)->flags
& NE_FFLAGS_WIN32
)
2581 return WIN32_LoadMenuA(instance
,PTR_SEG_TO_LIN(name
));
2583 if (!(hRsrc
= FindResource( instance
, name
, RT_MENU
))) return 0;
2584 if (!(handle
= LoadResource( instance
, hRsrc
))) return 0;
2585 hMenu
= LoadMenuIndirect16( LockResource(handle
) );
2586 FreeResource( handle
);
2591 /**********************************************************************
2592 * LoadMenuIndirect16 (USER.220)
2594 HMENU16
LoadMenuIndirect16( LPCVOID
template )
2597 WORD version
, offset
;
2598 LPCSTR p
= (LPCSTR
)template;
2600 dprintf_menu(stddeb
,"LoadMenuIndirect32A: %p\n", template );
2601 version
= GET_WORD(p
);
2605 fprintf( stderr
, "LoadMenuIndirect16: version must be 0 for Win16\n" );
2608 offset
= GET_WORD(p
);
2609 p
+= sizeof(WORD
) + offset
;
2610 if (!(hMenu
= CreateMenu())) return 0;
2611 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
2613 DestroyMenu( hMenu
);
2620 /**********************************************************************
2621 * LoadMenuIndirect32A (USER32.370)
2623 HMENU32
LoadMenuIndirect32A( LPCVOID
template )
2626 WORD version
, offset
;
2627 LPCSTR p
= (LPCSTR
)template;
2629 dprintf_menu(stddeb
,"LoadMenuIndirect32A: %p\n", template );
2630 version
= GET_WORD(p
);
2634 fprintf( stderr
, "LoadMenuIndirect32A: version %d not supported.\n",
2638 offset
= GET_WORD(p
);
2639 p
+= sizeof(WORD
) + offset
;
2640 if (!(hMenu
= CreateMenu())) return 0;
2641 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
2643 DestroyMenu( hMenu
);
2650 /**********************************************************************
2651 * LoadMenuIndirect32W (USER32.371)
2653 HMENU32
LoadMenuIndirect32W( LPCVOID
template )
2655 /* FIXME: is there anything different between A and W? */
2656 return LoadMenuIndirect32A( template );
2660 /**********************************************************************
2663 BOOL
IsMenu( HMENU hmenu
)
2666 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
2667 return (menu
->wMagic
== MENU_MAGIC
);