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"
28 /* #define DEBUG_MENU */
29 /* #define DEBUG_MENUCALC */
30 /* #define DEBUG_MENUSHORTCUT */
34 /* Dimension of the menu bitmaps */
35 static WORD check_bitmap_width
= 0, check_bitmap_height
= 0;
36 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
38 /* Flag set by EndMenu() to force an exit from menu tracking */
39 static BOOL fEndMenuCalled
= FALSE
;
41 /* Space between 2 menu bar items */
42 #define MENU_BAR_ITEMS_SPACE 16
44 /* Minimum width of a tab character */
45 #define MENU_TAB_SPACE 8
47 /* Height of a separator item */
48 #define SEPARATOR_HEIGHT 5
50 /* Values for menu->FocusedItem */
51 /* (other values give the position of the focused item) */
52 #define NO_SELECTED_ITEM 0xffff
53 #define SYSMENU_SELECTED 0xfffe /* Only valid on menu-bars */
55 #define IS_STRING_ITEM(flags) (!((flags) & (MF_BITMAP | MF_OWNERDRAW | \
56 MF_MENUBARBREAK | MF_MENUBREAK | MF_SEPARATOR)))
59 extern void NC_DrawSysButton(HWND hwnd
, HDC hdc
, BOOL down
); /* nonclient.c */
61 static HBITMAP hStdCheck
= 0;
62 static HBITMAP hStdMnArrow
= 0;
65 WORD
* ParseMenuResource(WORD
*first_item
, int level
, HMENU hMenu
);
68 /***********************************************************************
71 * Menus initialisation.
79 if (!(hStdCheck
= LoadBitmap( 0, MAKEINTRESOURCE(OBM_CHECK
) )))
81 GetObject( hStdCheck
, sizeof(BITMAP
), (LPSTR
)&bm
);
82 check_bitmap_width
= bm
.bmWidth
;
83 check_bitmap_height
= bm
.bmHeight
;
84 if (!(hStdMnArrow
= LoadBitmap( 0, MAKEINTRESOURCE(OBM_MNARROW
) )))
86 GetObject( hStdMnArrow
, sizeof(BITMAP
), (LPSTR
)&bm
);
87 arrow_bitmap_width
= bm
.bmWidth
;
88 arrow_bitmap_height
= bm
.bmHeight
;
94 /***********************************************************************
97 * Check whether the window owning the menu bar has a system menu.
99 static BOOL
MENU_HasSysMenu( POPUPMENU
*menu
)
103 if (menu
->wFlags
& MF_POPUP
) return FALSE
;
104 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return FALSE
;
105 return (wndPtr
->dwStyle
& WS_SYSMENU
) != 0;
109 /***********************************************************************
112 * Check whether the point (in screen coords) is in the system menu
113 * of the window owning the given menu.
115 static BOOL
MENU_IsInSysMenu( POPUPMENU
*menu
, POINT pt
)
119 if (menu
->wFlags
& MF_POPUP
) return FALSE
;
120 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return FALSE
;
121 if (!(wndPtr
->dwStyle
& WS_SYSMENU
)) return FALSE
;
122 if ((pt
.x
< wndPtr
->rectClient
.left
) ||
123 (pt
.x
>= wndPtr
->rectClient
.left
+SYSMETRICS_CXSIZE
+SYSMETRICS_CXBORDER
))
125 if ((pt
.y
>= wndPtr
->rectClient
.top
- menu
->Height
) ||
126 (pt
.y
< wndPtr
->rectClient
.top
- menu
->Height
-
127 SYSMETRICS_CYSIZE
- SYSMETRICS_CYBORDER
)) return FALSE
;
132 /***********************************************************************
135 * Find a menu item. Return a pointer on the item, and modifies *hmenu
136 * in case the item was in a sub-menu.
138 static MENUITEM
*MENU_FindItem( HMENU
*hmenu
, WORD
*nPos
, WORD wFlags
)
144 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(*hmenu
))) return NULL
;
145 item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
146 if (wFlags
& MF_BYPOSITION
)
148 if (*nPos
>= menu
->nItems
) return NULL
;
153 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
155 if (item
->item_id
== *nPos
)
160 else if (item
->item_flags
& MF_POPUP
)
162 HMENU hsubmenu
= (HMENU
)item
->item_id
;
163 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
176 /***********************************************************************
177 * MENU_FindItemByCoords
179 * Find the item at the specified coordinates (screen coords).
181 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
, int x
, int y
, WORD
*pos
)
187 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return NULL
;
188 x
-= wndPtr
->rectWindow
.left
;
189 y
-= wndPtr
->rectWindow
.top
;
190 item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
191 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
193 if ((x
>= item
->rect
.left
) && (x
< item
->rect
.right
) &&
194 (y
>= item
->rect
.top
) && (y
< item
->rect
.bottom
))
204 /***********************************************************************
207 * Find the menu item selected by a key press.
208 * Return item id, -1 if none, -2 if we should close the menu.
210 static WORD
MENU_FindItemByKey( HWND hwndOwner
, HMENU hmenu
, WORD key
)
217 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
218 lpitem
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
220 for (i
= 0; i
< menu
->nItems
; i
++, lpitem
++)
222 if (IS_STRING_ITEM(lpitem
->item_flags
))
224 char *p
= strchr( lpitem
->item_text
, '&' );
225 if (p
&& (p
[1] != '&') && (toupper(p
[1]) == key
)) return i
;
228 menuchar
= SendMessage( hwndOwner
, WM_MENUCHAR
, key
,
229 MAKELONG( menu
->wFlags
, hmenu
) );
230 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
231 if (HIWORD(menuchar
) == 1) return -2;
236 /***********************************************************************
239 * Calculate the size of the menu item and store it in lpitem->rect.
241 static void MENU_CalcItemSize( HDC hdc
, LPMENUITEM lpitem
, HWND hwndOwner
,
242 int orgX
, int orgY
, BOOL menuBar
)
247 SetRect( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
250 if (lpitem
->item_flags
& MF_SEPARATOR
)
252 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
258 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
259 if (lpitem
->item_flags
& MF_POPUP
)
260 lpitem
->rect
.right
+= arrow_bitmap_width
;
263 if (lpitem
->item_flags
& MF_BITMAP
)
266 GetObject( (HBITMAP
)lpitem
->hText
, sizeof(BITMAP
), (LPSTR
)&bm
);
267 lpitem
->rect
.right
+= bm
.bmWidth
;
268 lpitem
->rect
.bottom
+= bm
.bmHeight
;
272 /* If we get here, then it is a text item */
274 dwSize
= (lpitem
->item_text
== NULL
) ? 0 : GetTextExtent( hdc
, lpitem
->item_text
, strlen(lpitem
->item_text
));
275 lpitem
->rect
.right
+= LOWORD(dwSize
);
276 lpitem
->rect
.bottom
+= max( HIWORD(dwSize
), SYSMETRICS_CYMENU
);
278 if (menuBar
) lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
279 else if ((p
= strchr( lpitem
->item_text
, '\t' )) != NULL
)
281 /* Item contains a tab (only meaningful in popup menus) */
282 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+
283 LOWORD( GetTextExtent( hdc
, lpitem
->item_text
,
284 (int)(p
- lpitem
->item_text
) ));
285 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
289 if (strchr( lpitem
->item_text
, '\b' ))
290 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
291 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
292 - arrow_bitmap_width
;
297 /***********************************************************************
298 * MENU_PopupMenuCalcSize
300 * Calculate the size of a popup menu.
302 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND hwndOwner
)
304 LPMENUITEM items
, lpitem
;
307 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
309 lppop
->Width
= lppop
->Height
= 0;
310 if (lppop
->nItems
== 0) return;
311 items
= (MENUITEM
*)USER_HEAP_LIN_ADDR( lppop
->hItems
);
314 while (start
< lppop
->nItems
)
316 lpitem
= &items
[start
];
319 maxTab
= maxTabWidth
= 0;
321 /* Parse items until column break or end of menu */
322 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
325 (lpitem
->item_flags
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
326 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
327 maxX
= max( maxX
, lpitem
->rect
.right
);
328 orgY
= lpitem
->rect
.bottom
;
331 maxTab
= max( maxTab
, lpitem
->xTab
);
332 maxTabWidth
= max(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
336 /* Finish the column (set all items to the largest width found) */
337 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
338 for (lpitem
= &items
[start
]; start
< i
; start
++, lpitem
++)
340 lpitem
->rect
.right
= maxX
;
341 if (lpitem
->xTab
) lpitem
->xTab
= maxTab
;
343 lppop
->Height
= max( lppop
->Height
, orgY
);
351 /***********************************************************************
352 * MENU_MenuBarCalcSize
354 * Calculate the size of the menu bar.
356 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
, LPPOPUPMENU lppop
,
359 LPMENUITEM lpitem
, items
;
360 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
362 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
363 if (lppop
->nItems
== 0) return;
364 dprintf_menucalc(stddeb
,"MenuBarCalcSize left=%d top=%d right=%d bottom=%d !\n",
365 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
366 items
= (MENUITEM
*)USER_HEAP_LIN_ADDR( lppop
->hItems
);
367 lppop
->Width
= lprect
->right
- lprect
->left
;
372 while (start
< lppop
->nItems
)
374 lpitem
= &items
[start
];
378 /* Parse items until line break or end of menu */
379 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
381 if ((helpPos
== -1) && (lpitem
->item_flags
& MF_HELP
)) helpPos
= i
;
383 (lpitem
->item_flags
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
384 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
385 if (lpitem
->rect
.right
> lprect
->right
)
387 if (i
!= start
) break;
388 else lpitem
->rect
.right
= lprect
->right
;
390 maxY
= max( maxY
, lpitem
->rect
.bottom
);
391 orgX
= lpitem
->rect
.right
;
394 /* Finish the line (set all items to the largest height found) */
395 while (start
< i
) items
[start
++].rect
.bottom
= maxY
;
398 lprect
->bottom
= maxY
;
399 lppop
->Height
= lprect
->bottom
- lprect
->top
;
401 /* Flush right all items between the MF_HELP and the last item */
402 /* (if several lines, only move the last line) */
405 lpitem
= &items
[lppop
->nItems
-1];
406 orgY
= lpitem
->rect
.top
;
407 orgX
= lprect
->right
;
408 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--)
410 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
411 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
412 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
413 lpitem
->rect
.right
= orgX
;
414 orgX
= lpitem
->rect
.left
;
420 /***********************************************************************
423 * Draw a single menu item.
425 static void MENU_DrawMenuItem( HDC hdc
, LPMENUITEM lpitem
,
426 WORD height
, BOOL menuBar
)
430 if (menuBar
&& (lpitem
->item_flags
& MF_SEPARATOR
)) return;
433 /* Draw the background */
435 if (lpitem
->item_flags
& MF_HILITE
)
436 FillRect( hdc
, &rect
, sysColorObjects
.hbrushHighlight
);
437 else FillRect( hdc
, &rect
, sysColorObjects
.hbrushMenu
);
438 SetBkMode( hdc
, TRANSPARENT
);
440 /* Draw the separator bar (if any) */
442 if (!menuBar
&& (lpitem
->item_flags
& MF_MENUBARBREAK
))
444 SelectObject( hdc
, sysColorObjects
.hpenWindowFrame
);
445 MoveTo( hdc
, rect
.left
, 0 );
446 LineTo( hdc
, rect
.left
, height
);
448 if (lpitem
->item_flags
& MF_SEPARATOR
)
450 SelectObject( hdc
, sysColorObjects
.hpenWindowFrame
);
451 MoveTo( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
452 LineTo( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
458 if (lpitem
->item_flags
& MF_HILITE
)
460 if (lpitem
->item_flags
& MF_GRAYED
)
461 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
463 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
464 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
468 if (lpitem
->item_flags
& MF_GRAYED
)
469 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
471 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
472 SetBkColor( hdc
, GetSysColor( COLOR_MENU
) );
477 /* Draw the check mark */
479 if (lpitem
->item_flags
& MF_CHECKED
)
481 GRAPH_DrawBitmap(hdc
, lpitem
->hCheckBit
? lpitem
->hCheckBit
:
482 hStdCheck
, rect
.left
,
483 (rect
.top
+rect
.bottom
-check_bitmap_height
) / 2,
484 0, 0, check_bitmap_width
, check_bitmap_height
);
486 else if (lpitem
->hUnCheckBit
!= 0) /* Not checked */
488 GRAPH_DrawBitmap(hdc
, lpitem
->hUnCheckBit
, rect
.left
,
489 (rect
.top
+rect
.bottom
-check_bitmap_height
) / 2,
490 0, 0, check_bitmap_width
, check_bitmap_height
);
493 /* Draw the popup-menu arrow */
495 if (lpitem
->item_flags
& MF_POPUP
)
497 GRAPH_DrawBitmap( hdc
, hStdMnArrow
,
498 rect
.right
-arrow_bitmap_width
-1,
499 (rect
.top
+rect
.bottom
-arrow_bitmap_height
) / 2,
500 0, 0, arrow_bitmap_width
, arrow_bitmap_height
);
503 rect
.left
+= check_bitmap_width
;
504 rect
.right
-= arrow_bitmap_width
;
507 /* Draw the item text or bitmap */
509 if (lpitem
->item_flags
& MF_BITMAP
)
511 GRAPH_DrawBitmap( hdc
, (HBITMAP
)lpitem
->hText
, rect
.left
, rect
.top
,
512 0, 0, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
);
515 /* No bitmap - process text if present */
516 else if ((lpitem
->item_text
) != ((char *) NULL
))
522 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
523 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
524 i
= strlen( lpitem
->item_text
);
528 for (i
= 0; lpitem
->item_text
[i
]; i
++)
529 if ((lpitem
->item_text
[i
] == '\t') ||
530 (lpitem
->item_text
[i
] == '\b')) break;
533 DrawText( hdc
, lpitem
->item_text
, i
, &rect
,
534 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
536 if (lpitem
->item_text
[i
]) /* There's a tab or flush-right char */
538 if (lpitem
->item_text
[i
] == '\t')
540 rect
.left
= lpitem
->xTab
;
541 DrawText( hdc
, lpitem
->item_text
+ i
+ 1, -1, &rect
,
542 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
544 else DrawText( hdc
, lpitem
->item_text
+ i
+ 1, -1, &rect
,
545 DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
);
551 /***********************************************************************
554 * Paint a popup menu.
556 static void MENU_DrawPopupMenu( HWND hwnd
, HDC hdc
, HMENU hmenu
)
563 GetClientRect( hwnd
, &rect
);
564 FillRect( hdc
, &rect
, sysColorObjects
.hbrushMenu
);
565 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
566 if (!menu
|| !menu
->nItems
) return;
567 item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
568 for (i
= menu
->nItems
; i
> 0; i
--, item
++)
569 MENU_DrawMenuItem( hdc
, item
, menu
->Height
, FALSE
);
573 /***********************************************************************
576 * Paint a menu bar. Returns the height of the menu bar.
578 WORD
MENU_DrawMenuBar(HDC hDC
, LPRECT lprect
, HWND hwnd
, BOOL suppress_draw
)
583 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
585 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( wndPtr
->wIDmenu
);
586 if (lppop
== NULL
|| lprect
== NULL
) return SYSMETRICS_CYMENU
;
587 dprintf_menu(stddeb
,"MENU_DrawMenuBar(%04X, %p, %p); !\n",
589 if (lppop
->Height
== 0) MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
590 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
591 if (suppress_draw
) return lppop
->Height
;
593 FillRect(hDC
, lprect
, sysColorObjects
.hbrushMenu
);
594 SelectObject( hDC
, sysColorObjects
.hpenWindowFrame
);
595 MoveTo( hDC
, lprect
->left
, lprect
->bottom
);
596 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
598 if (lppop
->nItems
== 0) return SYSMETRICS_CYMENU
;
599 lpitem
= (MENUITEM
*) USER_HEAP_LIN_ADDR( lppop
->hItems
);
600 for (i
= 0; i
< lppop
->nItems
; i
++, lpitem
++)
602 MENU_DrawMenuItem( hDC
, lpitem
, lppop
->Height
, TRUE
);
604 return lppop
->Height
;
608 /***********************************************************************
611 * Display a popup menu.
613 static BOOL
MENU_ShowPopup(HWND hwndOwner
, HMENU hmenu
, WORD id
, int x
, int y
)
617 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
618 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
620 MENUITEM
*item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
621 item
[menu
->FocusedItem
].item_flags
&= ~(MF_HILITE
| MF_MOUSESELECT
);
622 menu
->FocusedItem
= NO_SELECTED_ITEM
;
624 SendMessage( hwndOwner
, WM_INITMENUPOPUP
, hmenu
,
625 MAKELONG( id
, (menu
->wFlags
& MF_POPUP
) ? 1 : 0 ));
626 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
629 WND
*wndPtr
= WIN_FindWndPtr( hwndOwner
);
630 if (!wndPtr
) return FALSE
;
631 menu
->hWnd
= CreateWindow( POPUPMENU_CLASS_NAME
, "",
632 WS_POPUP
| WS_BORDER
, x
, y
,
633 menu
->Width
+ 2*SYSMETRICS_CXBORDER
,
634 menu
->Height
+ 2*SYSMETRICS_CYBORDER
,
635 0, 0, wndPtr
->hInstance
, (SEGPTR
)hmenu
);
636 if (!menu
->hWnd
) return FALSE
;
638 else SetWindowPos( menu
->hWnd
, 0, x
, y
,
639 menu
->Width
+ 2*SYSMETRICS_CXBORDER
,
640 menu
->Height
+ 2*SYSMETRICS_CYBORDER
,
641 SWP_NOACTIVATE
| SWP_NOZORDER
);
643 /* Display the window */
645 SetWindowPos( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
646 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
647 UpdateWindow( menu
->hWnd
);
652 /***********************************************************************
655 static void MENU_SelectItem( HMENU hmenu
, WORD wIndex
)
661 lppop
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
662 if (!lppop
->nItems
) return;
663 items
= (MENUITEM
*) USER_HEAP_LIN_ADDR( lppop
->hItems
);
664 if ((wIndex
!= NO_SELECTED_ITEM
) &&
665 (wIndex
!= SYSMENU_SELECTED
) &&
666 (items
[wIndex
].item_flags
& MF_SEPARATOR
))
667 wIndex
= NO_SELECTED_ITEM
;
668 if (lppop
->FocusedItem
== wIndex
) return;
669 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC( lppop
->hWnd
);
670 else hdc
= GetDCEx( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
672 /* Clear previous highlighted item */
673 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
675 if (lppop
->FocusedItem
== SYSMENU_SELECTED
)
676 NC_DrawSysButton( lppop
->hWnd
, hdc
, FALSE
);
679 items
[lppop
->FocusedItem
].item_flags
&=~(MF_HILITE
|MF_MOUSESELECT
);
680 MENU_DrawMenuItem( hdc
, &items
[lppop
->FocusedItem
], lppop
->Height
,
681 !(lppop
->wFlags
& MF_POPUP
) );
685 /* Highlight new item (if any) */
686 lppop
->FocusedItem
= wIndex
;
687 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
689 if (lppop
->FocusedItem
== SYSMENU_SELECTED
)
690 NC_DrawSysButton( lppop
->hWnd
, hdc
, TRUE
);
693 items
[lppop
->FocusedItem
].item_flags
|= MF_HILITE
;
694 MENU_DrawMenuItem( hdc
, &items
[lppop
->FocusedItem
], lppop
->Height
,
695 !(lppop
->wFlags
& MF_POPUP
) );
696 SendMessage(lppop
->hWnd
, WM_MENUSELECT
,
697 items
[lppop
->FocusedItem
].item_id
,
698 MAKELONG( hmenu
, items
[lppop
->FocusedItem
].item_flags
));
701 ReleaseDC( lppop
->hWnd
, hdc
);
705 /***********************************************************************
706 * MENU_SelectNextItem
708 static void MENU_SelectNextItem( HMENU hmenu
)
714 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
715 if (!menu
->nItems
) return;
716 items
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
717 if ((menu
->FocusedItem
!= NO_SELECTED_ITEM
) &&
718 (menu
->FocusedItem
!= SYSMENU_SELECTED
))
720 for (i
= menu
->FocusedItem
+1; i
< menu
->nItems
; i
++)
722 if (!(items
[i
].item_flags
& MF_SEPARATOR
))
724 MENU_SelectItem( hmenu
, i
);
728 if (MENU_HasSysMenu( menu
))
730 MENU_SelectItem( hmenu
, SYSMENU_SELECTED
);
734 for (i
= 0; i
< menu
->nItems
; i
++)
736 if (!(items
[i
].item_flags
& MF_SEPARATOR
))
738 MENU_SelectItem( hmenu
, i
);
742 if (MENU_HasSysMenu( menu
)) MENU_SelectItem( hmenu
, SYSMENU_SELECTED
);
746 /***********************************************************************
747 * MENU_SelectPrevItem
749 static void MENU_SelectPrevItem( HMENU hmenu
)
755 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
756 if (!menu
->nItems
) return;
757 items
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
758 if ((menu
->FocusedItem
!= NO_SELECTED_ITEM
) &&
759 (menu
->FocusedItem
!= SYSMENU_SELECTED
))
761 for (i
= menu
->FocusedItem
- 1; i
>= 0; i
--)
763 if (!(items
[i
].item_flags
& MF_SEPARATOR
))
765 MENU_SelectItem( hmenu
, i
);
769 if (MENU_HasSysMenu( menu
))
771 MENU_SelectItem( hmenu
, SYSMENU_SELECTED
);
775 for (i
= menu
->nItems
- 1; i
> 0; i
--)
777 if (!(items
[i
].item_flags
& MF_SEPARATOR
))
779 MENU_SelectItem( hmenu
, i
);
783 if (MENU_HasSysMenu( menu
)) MENU_SelectItem( hmenu
, SYSMENU_SELECTED
);
787 /***********************************************************************
790 * Return the handle of the selected sub-popup menu (if any).
792 static HMENU
MENU_GetSubPopup( HMENU hmenu
)
797 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
798 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return 0;
799 else if (menu
->FocusedItem
== SYSMENU_SELECTED
)
800 return GetSystemMenu( menu
->hWnd
, FALSE
);
802 item
= ((MENUITEM
*)USER_HEAP_LIN_ADDR(menu
->hItems
)) + menu
->FocusedItem
;
803 if (!(item
->item_flags
& MF_POPUP
) || !(item
->item_flags
& MF_MOUSESELECT
))
805 return item
->item_id
;
809 /***********************************************************************
812 * Hide the sub-popup menus of this menu.
814 static void MENU_HideSubPopups( HMENU hmenu
)
817 POPUPMENU
*menu
, *submenu
;
820 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return;
821 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return;
822 if (menu
->FocusedItem
== SYSMENU_SELECTED
)
824 hsubmenu
= GetSystemMenu( menu
->hWnd
, FALSE
);
828 item
= ((MENUITEM
*)USER_HEAP_LIN_ADDR(menu
->hItems
)) + menu
->FocusedItem
;
829 if (!(item
->item_flags
& MF_POPUP
) ||
830 !(item
->item_flags
& MF_MOUSESELECT
)) return;
831 item
->item_flags
&= ~MF_MOUSESELECT
;
832 hsubmenu
= item
->item_id
;
834 submenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hsubmenu
);
835 MENU_HideSubPopups( hsubmenu
);
836 if (submenu
->hWnd
) ShowWindow( submenu
->hWnd
, SW_HIDE
);
837 MENU_SelectItem( hsubmenu
, NO_SELECTED_ITEM
);
841 /***********************************************************************
844 * Display the sub-menu of the selected item of this menu.
845 * Return the handle of the submenu, or hmenu if no submenu to display.
847 static HMENU
MENU_ShowSubPopup( HWND hwndOwner
, HMENU hmenu
, BOOL selectFirst
)
853 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return hmenu
;
854 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return hmenu
;
855 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return hmenu
;
856 if (menu
->FocusedItem
== SYSMENU_SELECTED
)
858 MENU_ShowPopup(hwndOwner
, wndPtr
->hSysMenu
, 0, wndPtr
->rectClient
.left
,
859 wndPtr
->rectClient
.top
- menu
->Height
- 2*SYSMETRICS_CYBORDER
);
860 if (selectFirst
) MENU_SelectNextItem( wndPtr
->hSysMenu
);
861 return wndPtr
->hSysMenu
;
863 item
= ((MENUITEM
*)USER_HEAP_LIN_ADDR(menu
->hItems
)) + menu
->FocusedItem
;
864 if (!(item
->item_flags
& MF_POPUP
) ||
865 (item
->item_flags
& (MF_GRAYED
| MF_DISABLED
))) return hmenu
;
866 item
->item_flags
|= MF_MOUSESELECT
;
867 if (menu
->wFlags
& MF_POPUP
)
869 MENU_ShowPopup( hwndOwner
, (HMENU
)item
->item_id
, menu
->FocusedItem
,
870 wndPtr
->rectWindow
.left
+ item
->rect
.right
-arrow_bitmap_width
,
871 wndPtr
->rectWindow
.top
+ item
->rect
.top
);
875 MENU_ShowPopup( hwndOwner
, (HMENU
)item
->item_id
, menu
->FocusedItem
,
876 wndPtr
->rectWindow
.left
+ item
->rect
.left
,
877 wndPtr
->rectWindow
.top
+ item
->rect
.bottom
);
879 if (selectFirst
) MENU_SelectNextItem( (HMENU
)item
->item_id
);
880 return (HMENU
)item
->item_id
;
884 /***********************************************************************
885 * MENU_FindMenuByCoords
887 * Find the menu containing a given point (in screen coords).
889 static HMENU
MENU_FindMenuByCoords( HMENU hmenu
, POINT pt
)
894 if (!(hwnd
= WindowFromPoint( pt
))) return 0;
897 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
898 if (menu
->hWnd
== hwnd
)
900 if (!(menu
->wFlags
& MF_POPUP
))
902 /* Make sure it's in the menu bar (or in system menu) */
903 WND
*wndPtr
= WIN_FindWndPtr( menu
->hWnd
);
904 if ((pt
.x
< wndPtr
->rectClient
.left
) ||
905 (pt
.x
>= wndPtr
->rectClient
.right
) ||
906 (pt
.y
>= wndPtr
->rectClient
.top
)) return 0;
907 if (pt
.y
< wndPtr
->rectClient
.top
- menu
->Height
)
909 if (!MENU_IsInSysMenu( menu
, pt
)) return 0;
911 /* else it's in the menu bar */
915 hmenu
= MENU_GetSubPopup( hmenu
);
921 /***********************************************************************
922 * MENU_ExecFocusedItem
924 * Execute a menu item (for instance when user pressed Enter).
925 * Return TRUE if we can go on with menu tracking.
927 static BOOL
MENU_ExecFocusedItem( HWND hwndOwner
, HMENU hmenu
,
928 HMENU
*hmenuCurrent
)
931 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
932 if (!menu
|| !menu
->nItems
|| (menu
->FocusedItem
== NO_SELECTED_ITEM
) ||
933 (menu
->FocusedItem
== SYSMENU_SELECTED
)) return TRUE
;
934 item
= ((MENUITEM
*)USER_HEAP_LIN_ADDR(menu
->hItems
)) + menu
->FocusedItem
;
935 if (!(item
->item_flags
& MF_POPUP
))
937 if (!(item
->item_flags
& (MF_GRAYED
| MF_DISABLED
)))
939 PostMessage( hwndOwner
, (menu
->wFlags
& MF_SYSMENU
) ?
940 WM_SYSCOMMAND
: WM_COMMAND
, item
->item_id
, 0 );
947 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, TRUE
);
953 /***********************************************************************
956 * Handle a button-down event in a menu. Point is in screen coords.
957 * hmenuCurrent is the top-most visible popup.
958 * Return TRUE if we can go on with menu tracking.
960 static BOOL
MENU_ButtonDown( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
,
967 if (!hmenu
) return FALSE
; /* Outside all menus */
968 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
969 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
970 if (!item
) /* Maybe in system menu */
972 if (!MENU_IsInSysMenu( menu
, pt
)) return FALSE
;
973 id
= SYSMENU_SELECTED
;
976 if (menu
->FocusedItem
== id
)
978 if (id
== SYSMENU_SELECTED
) return FALSE
;
979 if (item
->item_flags
& MF_POPUP
)
981 if (item
->item_flags
& MF_MOUSESELECT
)
983 if (menu
->wFlags
& MF_POPUP
)
985 MENU_HideSubPopups( hmenu
);
986 *hmenuCurrent
= hmenu
;
990 else *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
995 MENU_HideSubPopups( hmenu
);
996 MENU_SelectItem( hmenu
, id
);
997 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1003 /***********************************************************************
1006 * Handle a button-up event in a menu. Point is in screen coords.
1007 * hmenuCurrent is the top-most visible popup.
1008 * Return TRUE if we can go on with menu tracking.
1010 static BOOL
MENU_ButtonUp( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
,
1018 if (!hmenu
) return FALSE
; /* Outside all menus */
1019 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1020 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1021 if (!item
) /* Maybe in system menu */
1023 if (!MENU_IsInSysMenu( menu
, pt
)) return FALSE
;
1024 id
= SYSMENU_SELECTED
;
1025 hsubmenu
= GetSystemMenu( menu
->hWnd
, FALSE
);
1028 if (menu
->FocusedItem
!= id
) return FALSE
;
1030 if (id
!= SYSMENU_SELECTED
)
1032 if (!(item
->item_flags
& MF_POPUP
))
1034 return MENU_ExecFocusedItem( hwndOwner
, hmenu
, hmenuCurrent
);
1036 hsubmenu
= item
->item_id
;
1038 /* Select first item of sub-popup */
1039 MENU_SelectItem( hsubmenu
, NO_SELECTED_ITEM
);
1040 MENU_SelectNextItem( hsubmenu
);
1045 /***********************************************************************
1048 * Handle a motion event in a menu. Point is in screen coords.
1049 * hmenuCurrent is the top-most visible popup.
1050 * Return TRUE if we can go on with menu tracking.
1052 static BOOL
MENU_MouseMove( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
,
1056 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1057 WORD id
= NO_SELECTED_ITEM
;
1061 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1062 if (!item
) /* Maybe in system menu */
1064 if (!MENU_IsInSysMenu( menu
, pt
))
1065 id
= NO_SELECTED_ITEM
; /* Outside all items */
1066 else id
= SYSMENU_SELECTED
;
1069 if (id
== NO_SELECTED_ITEM
)
1071 MENU_SelectItem( *hmenuCurrent
, NO_SELECTED_ITEM
);
1073 else if (menu
->FocusedItem
!= id
)
1075 MENU_HideSubPopups( hmenu
);
1076 MENU_SelectItem( hmenu
, id
);
1077 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1083 /***********************************************************************
1086 * Handle a VK_LEFT key event in a menu.
1087 * hmenuCurrent is the top-most visible popup.
1089 static void MENU_KeyLeft( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
)
1092 HMENU hmenutmp
, hmenuprev
;
1094 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1095 hmenuprev
= hmenutmp
= hmenu
;
1096 while (hmenutmp
!= *hmenuCurrent
)
1098 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
1099 if (hmenutmp
!= *hmenuCurrent
) hmenuprev
= hmenutmp
;
1101 MENU_HideSubPopups( hmenuprev
);
1103 if ((hmenuprev
== hmenu
) && !(menu
->wFlags
& MF_POPUP
))
1105 /* Select previous item on the menu bar */
1106 MENU_SelectPrevItem( hmenu
);
1107 if (*hmenuCurrent
!= hmenu
)
1109 /* A popup menu was displayed -> display the next one */
1110 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, TRUE
);
1113 else *hmenuCurrent
= hmenuprev
;
1117 /***********************************************************************
1120 * Handle a VK_RIGHT key event in a menu.
1121 * hmenuCurrent is the top-most visible popup.
1123 static void MENU_KeyRight( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
)
1128 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1130 if ((menu
->wFlags
& MF_POPUP
) || (*hmenuCurrent
!= hmenu
))
1132 /* If already displaying a popup, try to display sub-popup */
1133 hmenutmp
= MENU_ShowSubPopup( hwndOwner
, *hmenuCurrent
, TRUE
);
1134 if (hmenutmp
!= *hmenuCurrent
) /* Sub-popup displayed */
1136 *hmenuCurrent
= hmenutmp
;
1141 /* If on menu-bar, go to next item */
1142 if (!(menu
->wFlags
& MF_POPUP
))
1144 MENU_HideSubPopups( hmenu
);
1145 MENU_SelectNextItem( hmenu
);
1146 if (*hmenuCurrent
!= hmenu
)
1148 /* A popup menu was displayed -> display the next one */
1149 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, TRUE
);
1152 else if (*hmenuCurrent
!= hmenu
) /* Hide last level popup */
1155 hmenuprev
= hmenutmp
= hmenu
;
1156 while (hmenutmp
!= *hmenuCurrent
)
1158 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
1159 if (hmenutmp
!= *hmenuCurrent
) hmenuprev
= hmenutmp
;
1161 MENU_HideSubPopups( hmenuprev
);
1162 *hmenuCurrent
= hmenuprev
;
1167 /***********************************************************************
1170 * Menu tracking code.
1171 * If 'x' and 'y' are not 0, we simulate a button-down event at (x,y)
1172 * before beginning tracking. This is to help menu-bar tracking.
1174 static BOOL
MENU_TrackMenu( HMENU hmenu
, WORD wFlags
, int x
, int y
,
1175 HWND hwnd
, LPRECT lprect
)
1180 HMENU hmenuCurrent
= hmenu
;
1181 BOOL fClosed
= FALSE
, fRemove
;
1184 fEndMenuCalled
= FALSE
;
1185 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
1188 POINT pt
= { x
, y
};
1189 MENU_ButtonDown( hwnd
, hmenu
, &hmenuCurrent
, pt
);
1192 hMsg
= USER_HEAP_ALLOC( sizeof(MSG
) );
1193 msg
= (MSG
*)USER_HEAP_LIN_ADDR( hMsg
);
1196 if (!MSG_InternalGetMessage( USER_HEAP_SEG_ADDR(hMsg
), 0,
1197 hwnd
, MSGF_MENU
, 0, TRUE
))
1201 if ((msg
->message
>= WM_MOUSEFIRST
) && (msg
->message
<= WM_MOUSELAST
))
1203 /* Find the sub-popup for this mouse event (if any) */
1204 HMENU hsubmenu
= MENU_FindMenuByCoords( hmenu
, msg
->pt
);
1206 switch(msg
->message
)
1208 case WM_RBUTTONDOWN
:
1209 case WM_NCRBUTTONDOWN
:
1210 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
1212 case WM_LBUTTONDOWN
:
1213 case WM_NCLBUTTONDOWN
:
1214 fClosed
= !MENU_ButtonDown( hwnd
, hsubmenu
,
1215 &hmenuCurrent
, msg
->pt
);
1219 case WM_NCRBUTTONUP
:
1220 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
1223 case WM_NCLBUTTONUP
:
1224 /* If outside all menus but inside lprect, ignore it */
1225 if (!hsubmenu
&& lprect
&& PtInRect( lprect
, msg
->pt
)) break;
1226 fClosed
= !MENU_ButtonUp( hwnd
, hsubmenu
,
1227 &hmenuCurrent
, msg
->pt
);
1228 fRemove
= TRUE
; /* Remove event even if outside menu */
1232 case WM_NCMOUSEMOVE
:
1233 if ((msg
->wParam
& MK_LBUTTON
) ||
1234 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
->wParam
& MK_RBUTTON
)))
1236 fClosed
= !MENU_MouseMove( hwnd
, hsubmenu
,
1237 &hmenuCurrent
, msg
->pt
);
1242 else if ((msg
->message
>= WM_KEYFIRST
) && (msg
->message
<= WM_KEYLAST
))
1244 fRemove
= TRUE
; /* Keyboard messages are always removed */
1245 switch(msg
->message
)
1251 MENU_SelectItem( hmenuCurrent
, NO_SELECTED_ITEM
);
1252 MENU_SelectNextItem( hmenuCurrent
);
1256 MENU_SelectItem( hmenuCurrent
, NO_SELECTED_ITEM
);
1257 MENU_SelectPrevItem( hmenuCurrent
);
1261 MENU_SelectPrevItem( hmenuCurrent
);
1265 /* If on menu bar, pull-down the menu */
1266 if (!(menu
->wFlags
& MF_POPUP
) && (hmenuCurrent
== hmenu
))
1267 hmenuCurrent
= MENU_ShowSubPopup( hwnd
, hmenu
, TRUE
);
1269 MENU_SelectNextItem( hmenuCurrent
);
1273 MENU_KeyLeft( hwnd
, hmenu
, &hmenuCurrent
);
1277 MENU_KeyRight( hwnd
, hmenu
, &hmenuCurrent
);
1282 fClosed
= !MENU_ExecFocusedItem( hwnd
, hmenuCurrent
,
1293 break; /* WM_KEYDOWN */
1303 break; /* WM_SYSKEYDOWN */
1307 /* Hack to avoid control chars. */
1308 /* We will find a better way real soon... */
1309 if ((msg
->wParam
<= 32) || (msg
->wParam
>= 127)) break;
1310 pos
= MENU_FindItemByKey( hwnd
, hmenuCurrent
, msg
->wParam
);
1311 if (pos
== (WORD
)-2) fClosed
= TRUE
;
1312 else if (pos
== (WORD
)-1) MessageBeep(0);
1315 MENU_SelectItem( hmenuCurrent
, pos
);
1316 fClosed
= !MENU_ExecFocusedItem( hwnd
, hmenuCurrent
,
1321 break; /* WM_CHAR */
1322 } /* switch(msg->message) */
1326 DispatchMessage( msg
);
1328 if (fEndMenuCalled
) fClosed
= TRUE
;
1329 if (!fClosed
) fRemove
= TRUE
;
1331 if (fRemove
) /* Remove the message from the queue */
1332 PeekMessage( msg
, 0, msg
->message
, msg
->message
, PM_REMOVE
);
1334 USER_HEAP_FREE( hMsg
);
1336 MENU_HideSubPopups( hmenu
);
1337 if (menu
->wFlags
& MF_POPUP
) ShowWindow( menu
->hWnd
, SW_HIDE
);
1338 MENU_SelectItem( hmenu
, NO_SELECTED_ITEM
);
1339 fEndMenuCalled
= FALSE
;
1344 /***********************************************************************
1345 * MENU_TrackMouseMenuBar
1347 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
1349 void MENU_TrackMouseMenuBar( HWND hwnd
, POINT pt
)
1351 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1352 SendMessage( hwnd
, WM_ENTERMENULOOP
, 0, 0 );
1353 MENU_TrackMenu( (HMENU
)wndPtr
->wIDmenu
, TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
1354 pt
.x
, pt
.y
, hwnd
, NULL
);
1355 SendMessage( hwnd
, WM_EXITMENULOOP
, 0, 0 );
1359 /***********************************************************************
1360 * MENU_TrackKbdMenuBar
1362 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
1364 void MENU_TrackKbdMenuBar( HWND hwnd
, WORD wParam
)
1366 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1367 if (!wndPtr
->wIDmenu
) return;
1368 SendMessage( hwnd
, WM_ENTERMENULOOP
, 0, 0 );
1369 /* Select first selectable item */
1370 MENU_SelectItem( wndPtr
->wIDmenu
, NO_SELECTED_ITEM
);
1371 MENU_SelectNextItem( (HMENU
)wndPtr
->wIDmenu
);
1372 MENU_TrackMenu( (HMENU
)wndPtr
->wIDmenu
, TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
1374 SendMessage( hwnd
, WM_EXITMENULOOP
, 0, 0 );
1378 /**********************************************************************
1379 * TrackPopupMenu [USER.416]
1381 BOOL
TrackPopupMenu( HMENU hMenu
, WORD wFlags
, short x
, short y
,
1382 short nReserved
, HWND hWnd
, LPRECT lpRect
)
1384 if (!MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
)) return FALSE
;
1385 return MENU_TrackMenu( hMenu
, wFlags
, 0, 0, hWnd
, lpRect
);
1389 /***********************************************************************
1392 LONG
PopupMenuWndProc( HWND hwnd
, WORD message
, WORD wParam
, LONG lParam
)
1398 CREATESTRUCT
*createStruct
= (CREATESTRUCT
*)PTR_SEG_TO_LIN(lParam
);
1399 HMENU hmenu
= (HMENU
) ((int)createStruct
->lpCreateParams
& 0xffff);
1400 SetWindowWord( hwnd
, 0, hmenu
);
1404 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1405 return MA_NOACTIVATE
;
1410 BeginPaint( hwnd
, &ps
);
1411 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
1412 (HMENU
)GetWindowWord( hwnd
, 0 ) );
1413 EndPaint( hwnd
, &ps
);
1418 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
1424 /***********************************************************************
1425 * MENU_GetMenuBarHeight
1427 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
1429 WORD
MENU_GetMenuBarHeight( HWND hwnd
, WORD menubarWidth
, int orgX
, int orgY
)
1436 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
1437 if (!(lppop
= (LPPOPUPMENU
)USER_HEAP_LIN_ADDR(wndPtr
->wIDmenu
))) return 0;
1438 hdc
= GetDC( hwnd
);
1439 SetRect( &rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+SYSMETRICS_CYMENU
);
1440 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
1441 ReleaseDC( hwnd
, hdc
);
1442 return lppop
->Height
;
1446 /**********************************************************************
1447 * ChangeMenu [USER.153]
1449 BOOL
ChangeMenu(HMENU hMenu
, WORD nPos
, LPSTR lpNewItem
,
1450 WORD wItemID
, WORD wFlags
)
1452 dprintf_menu(stddeb
,"ChangeMenu(%04X, %X, '%s', %X, %X)\n",
1453 hMenu
, nPos
, lpNewItem
, wItemID
, wFlags
);
1454 if (wFlags
& MF_APPEND
)
1455 return AppendMenu(hMenu
, wFlags
, wItemID
, lpNewItem
);
1456 if (wFlags
& MF_DELETE
)
1457 return DeleteMenu(hMenu
, wItemID
, wFlags
);
1458 if (wFlags
& MF_CHANGE
)
1459 return ModifyMenu(hMenu
, nPos
, wFlags
, wItemID
, lpNewItem
);
1460 if (wFlags
& MF_REMOVE
)
1461 return RemoveMenu(hMenu
, wItemID
, wFlags
);
1462 /* Default: MF_INSERT */
1463 return InsertMenu(hMenu
, nPos
, wFlags
, wItemID
, lpNewItem
);
1467 /**********************************************************************
1468 * CheckMenuItem [USER.154]
1470 BOOL
CheckMenuItem(HMENU hMenu
, WORD wItemID
, WORD wFlags
)
1473 dprintf_menu(stddeb
,"CheckMenuItem (%04X, %04X, %04X) !\n",
1474 hMenu
, wItemID
, wFlags
);
1475 if (!(lpitem
= MENU_FindItem(&hMenu
, &wItemID
, wFlags
))) return FALSE
;
1476 if (wFlags
& MF_CHECKED
) lpitem
->item_flags
|= MF_CHECKED
;
1477 else lpitem
->item_flags
&= ~MF_CHECKED
;
1482 /**********************************************************************
1483 * EnableMenuItem [USER.155]
1485 BOOL
EnableMenuItem(HMENU hMenu
, WORD wItemID
, WORD wFlags
)
1488 dprintf_menu(stddeb
,"EnableMenuItem (%04X, %04X, %04X) !\n",
1489 hMenu
, wItemID
, wFlags
);
1490 if (!(lpitem
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return FALSE
;
1492 /* We can't have MF_GRAYED and MF_DISABLED together */
1493 if (wFlags
& MF_GRAYED
)
1495 lpitem
->item_flags
= (lpitem
->item_flags
& ~MF_DISABLED
) | MF_GRAYED
;
1497 else if (wFlags
& MF_DISABLED
)
1499 lpitem
->item_flags
= (lpitem
->item_flags
& ~MF_GRAYED
) | MF_DISABLED
;
1501 else /* MF_ENABLED */
1503 lpitem
->item_flags
&= ~(MF_GRAYED
| MF_DISABLED
);
1509 /**********************************************************************
1510 * GetMenuString [USER.161]
1512 int GetMenuString(HMENU hMenu
, WORD wItemID
,
1513 LPSTR str
, short nMaxSiz
, WORD wFlags
)
1517 dprintf_menu(stddeb
,"GetMenuString(%04X, %04X, %p, %d, %04X);\n",
1518 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
1519 if (str
== NULL
) return FALSE
;
1520 lpitem
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
);
1521 if (lpitem
!= NULL
) {
1522 if (lpitem
->item_text
!= NULL
) {
1523 maxsiz
= min(nMaxSiz
- 1, strlen(lpitem
->item_text
));
1524 strncpy(str
, lpitem
->item_text
, maxsiz
+ 1);
1528 dprintf_menu(stddeb
,"GetMenuString // Found !\n");
1535 /**********************************************************************
1536 * HiliteMenuItem [USER.162]
1538 BOOL
HiliteMenuItem(HWND hWnd
, HMENU hMenu
, WORD wItemID
, WORD wHilite
)
1542 dprintf_menu(stddeb
,"HiliteMenuItem(%04X, %04X, %04X, %04X);\n",
1543 hWnd
, hMenu
, wItemID
, wHilite
);
1544 if (!(lpitem
= MENU_FindItem( &hMenu
, &wItemID
, wHilite
))) return FALSE
;
1545 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
1546 if (menu
->FocusedItem
== wItemID
) return TRUE
;
1547 MENU_HideSubPopups( hMenu
);
1548 MENU_SelectItem( hMenu
, wItemID
);
1553 /**********************************************************************
1554 * GetMenuState [USER.250]
1556 WORD
GetMenuState(HMENU hMenu
, WORD wItemID
, WORD wFlags
)
1559 dprintf_menu(stddeb
,"GetMenuState(%04X, %04X, %04X);\n",
1560 hMenu
, wItemID
, wFlags
);
1561 if (!(lpitem
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
1562 if (lpitem
->item_flags
& MF_POPUP
)
1564 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( lpitem
->item_id
);
1565 if (!menu
) return -1;
1566 else return (menu
->nItems
<< 8) | (menu
->wFlags
& 0xff);
1568 else return lpitem
->item_flags
;
1572 /**********************************************************************
1573 * GetMenuItemCount [USER.263]
1575 WORD
GetMenuItemCount(HMENU hMenu
)
1578 dprintf_menu(stddeb
,"GetMenuItemCount(%04X);\n", hMenu
);
1579 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
1580 if (menu
== NULL
) return (WORD
)-1;
1581 dprintf_menu(stddeb
,"GetMenuItemCount(%04X) return %d \n",
1582 hMenu
, menu
->nItems
);
1583 return menu
->nItems
;
1587 /**********************************************************************
1588 * GetMenuItemID [USER.264]
1590 WORD
GetMenuItemID(HMENU hMenu
, int nPos
)
1595 dprintf_menu(stddeb
,"GetMenuItemID(%04X, %d);\n", hMenu
, nPos
);
1596 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
1597 if ((nPos
< 0) || (nPos
>= menu
->nItems
)) return -1;
1598 item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
1599 if (item
[nPos
].item_flags
& MF_POPUP
) return -1;
1600 return item
[nPos
].item_id
;
1604 /**********************************************************************
1605 * InsertMenu [USER.410]
1607 BOOL
InsertMenu(HMENU hMenu
, WORD nPos
, WORD wFlags
, WORD wItemID
, LPSTR lpNewItem
)
1610 MENUITEM
*lpitem
, *newItems
;
1613 if (IS_STRING_ITEM(wFlags
))
1615 dprintf_menu(stddeb
,"InsertMenu (%04X, %04X, %04X, %04X, '%s') !\n",
1616 hMenu
, nPos
, wFlags
, wItemID
, lpNewItem
);
1619 dprintf_menu(stddeb
,"InsertMenu (%04X, %04X, %04X, %04X, %p) !\n",
1620 hMenu
, nPos
, wFlags
, wItemID
, lpNewItem
);
1622 /* Find where to insert new item */
1624 if ((wFlags
& MF_BYPOSITION
) &&
1625 ((nPos
== (WORD
)-1) || (nPos
== GetMenuItemCount(hMenu
))))
1627 /* Special case: append to menu
1628 Some programs specify the menu length to do that */
1629 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
)))
1631 dprintf_menu(stddeb
,"InsertMenu: %04X not a menu handle\n", hMenu
);
1634 nPos
= menu
->nItems
;
1638 if (!MENU_FindItem( &hMenu
, &nPos
, wFlags
))
1640 dprintf_menu(stddeb
,"InsertMenu: Item %X not found\n", nPos
);
1643 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
)))
1645 dprintf_menu(stddeb
,"InsertMenu: %04X not a menu handle\n", hMenu
);
1650 /* Create new items array */
1652 hNewItems
= USER_HEAP_ALLOC( sizeof(MENUITEM
) * (menu
->nItems
+1) );
1655 dprintf_menu(stddeb
,"InsertMenu: allocation failed\n");
1658 newItems
= (MENUITEM
*) USER_HEAP_LIN_ADDR( hNewItems
);
1659 if (menu
->nItems
> 0)
1661 /* Copy the old array into the new */
1662 MENUITEM
*oldItems
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
1663 if (nPos
> 0) memcpy( newItems
, oldItems
, nPos
* sizeof(MENUITEM
) );
1664 if (nPos
< menu
->nItems
) memcpy( &newItems
[nPos
+1], &oldItems
[nPos
],
1665 (menu
->nItems
-nPos
)*sizeof(MENUITEM
) );
1667 USER_HEAP_FREE( menu
->hItems
);
1669 menu
->hItems
= hNewItems
;
1672 /* Store the new item data */
1674 lpitem
= &newItems
[nPos
];
1675 lpitem
->item_flags
= wFlags
& ~(MF_HILITE
| MF_MOUSESELECT
);
1676 lpitem
->item_id
= wItemID
;
1678 if (IS_STRING_ITEM(wFlags
))
1680 /* Item beginning with a backspace is a help item */
1681 if (lpNewItem
[0] == '\b')
1683 lpitem
->item_flags
|= MF_HELP
;
1686 lpitem
->hText
= USER_HEAP_ALLOC( strlen(lpNewItem
)+1 );
1687 lpitem
->item_text
= (char *)USER_HEAP_LIN_ADDR( lpitem
->hText
);
1688 strcpy( lpitem
->item_text
, lpNewItem
);
1690 else if (wFlags
& MF_BITMAP
) lpitem
->hText
= LOWORD((DWORD
)lpNewItem
);
1691 else lpitem
->item_text
= lpNewItem
;
1693 if (wFlags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
1694 ((POPUPMENU
*)USER_HEAP_LIN_ADDR(wItemID
))->wFlags
|= MF_POPUP
;
1696 SetRectEmpty( &lpitem
->rect
);
1697 lpitem
->hCheckBit
= hStdCheck
;
1698 lpitem
->hUnCheckBit
= 0;
1703 /**********************************************************************
1704 * AppendMenu [USER.411]
1706 BOOL
AppendMenu(HMENU hMenu
, WORD wFlags
, WORD wItemID
, LPSTR lpNewItem
)
1708 return InsertMenu( hMenu
, -1, wFlags
| MF_BYPOSITION
, wItemID
, lpNewItem
);
1712 /**********************************************************************
1713 * RemoveMenu [USER.412]
1715 BOOL
RemoveMenu(HMENU hMenu
, WORD nPos
, WORD wFlags
)
1719 dprintf_menu(stddeb
,"RemoveMenu (%04X, %04X, %04X) !\n",
1720 hMenu
, nPos
, wFlags
);
1721 if (!(lpitem
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
1722 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
1726 if (IS_STRING_ITEM(lpitem
->item_flags
)) USER_HEAP_FREE( lpitem
->hText
);
1727 if (--menu
->nItems
== 0)
1729 USER_HEAP_FREE( menu
->hItems
);
1734 while(nPos
< menu
->nItems
)
1736 *lpitem
= *(lpitem
+1);
1740 menu
->hItems
= USER_HEAP_REALLOC( menu
->hItems
,
1741 menu
->nItems
* sizeof(MENUITEM
) );
1747 /**********************************************************************
1748 * DeleteMenu [USER.413]
1750 BOOL
DeleteMenu(HMENU hMenu
, WORD nPos
, WORD wFlags
)
1752 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
1753 if (!item
) return FALSE
;
1754 if (item
->item_flags
& MF_POPUP
) DestroyMenu( item
->item_id
);
1755 /* nPos is now the position of the item */
1756 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
1761 /**********************************************************************
1762 * ModifyMenu [USER.414]
1764 BOOL
ModifyMenu(HMENU hMenu
, WORD nPos
, WORD wFlags
, WORD wItemID
, LPSTR lpNewItem
)
1767 if (IS_STRING_ITEM(wFlags
))
1768 dprintf_menu(stddeb
,"ModifyMenu (%04X, %04X, %04X, %04X, '%s') !\n",
1769 hMenu
, nPos
, wFlags
, wItemID
, lpNewItem
);
1771 dprintf_menu(stddeb
,"ModifyMenu (%04X, %04X, %04X, %04X, %p) !\n",
1772 hMenu
, nPos
, wFlags
, wItemID
, lpNewItem
);
1773 if (!(lpitem
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
1775 if (IS_STRING_ITEM(lpitem
->item_flags
)) USER_HEAP_FREE( lpitem
->hText
);
1776 lpitem
->item_flags
= wFlags
& ~(MF_HILITE
| MF_MOUSESELECT
);
1777 lpitem
->item_id
= wItemID
;
1779 if (IS_STRING_ITEM(wFlags
))
1781 lpitem
->hText
= USER_HEAP_ALLOC( strlen(lpNewItem
)+1 );
1782 lpitem
->item_text
= (char *)USER_HEAP_LIN_ADDR( lpitem
->hText
);
1783 strcpy( lpitem
->item_text
, lpNewItem
);
1785 else if (wFlags
& MF_BITMAP
) lpitem
->hText
= LOWORD((DWORD
)lpNewItem
);
1786 else lpitem
->item_text
= lpNewItem
;
1787 SetRectEmpty( &lpitem
->rect
);
1792 /**********************************************************************
1793 * CreatePopupMenu [USER.415]
1795 HMENU
CreatePopupMenu()
1800 if (!(hmenu
= CreateMenu())) return 0;
1801 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1802 menu
->wFlags
|= MF_POPUP
;
1807 /**********************************************************************
1808 * GetMenuCheckMarkDimensions [USER.417]
1810 DWORD
GetMenuCheckMarkDimensions()
1812 return MAKELONG( check_bitmap_width
, check_bitmap_height
);
1816 /**********************************************************************
1817 * SetMenuItemBitmaps [USER.418]
1819 BOOL
SetMenuItemBitmaps(HMENU hMenu
, WORD nPos
, WORD wFlags
,
1820 HBITMAP hNewCheck
, HBITMAP hNewUnCheck
)
1823 dprintf_menu(stddeb
,"SetMenuItemBitmaps (%04X, %04X, %04X, %04X, %08X) !\n",
1824 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
1825 if (!(lpitem
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
1827 if (!hNewCheck
&& !hNewUnCheck
)
1829 /* If both are NULL, restore default bitmaps */
1830 lpitem
->hCheckBit
= hStdCheck
;
1831 lpitem
->hUnCheckBit
= 0;
1832 lpitem
->item_flags
&= ~MF_USECHECKBITMAPS
;
1834 else /* Install new bitmaps */
1836 lpitem
->hCheckBit
= hNewCheck
;
1837 lpitem
->hUnCheckBit
= hNewUnCheck
;
1838 lpitem
->item_flags
|= MF_USECHECKBITMAPS
;
1844 /**********************************************************************
1845 * CreateMenu [USER.151]
1851 dprintf_menu(stddeb
,"CreateMenu !\n");
1852 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) )))
1854 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
1857 menu
->wMagic
= MENU_MAGIC
;
1864 menu
->FocusedItem
= NO_SELECTED_ITEM
;
1865 dprintf_menu(stddeb
,"CreateMenu // return %04X\n", hMenu
);
1870 /**********************************************************************
1871 * DestroyMenu [USER.152]
1873 BOOL
DestroyMenu(HMENU hMenu
)
1876 dprintf_menu(stddeb
,"DestroyMenu (%04X) !\n", hMenu
);
1877 if (hMenu
== 0) return FALSE
;
1878 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
1879 if (lppop
== NULL
) return FALSE
;
1880 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
)
1881 DestroyWindow( lppop
->hWnd
);
1886 MENUITEM
*item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( lppop
->hItems
);
1887 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
1889 if (item
->item_flags
& MF_POPUP
)
1890 DestroyMenu( item
->item_id
);
1892 USER_HEAP_FREE( lppop
->hItems
);
1894 USER_HEAP_FREE( hMenu
);
1895 dprintf_menu(stddeb
,"DestroyMenu (%04X) // End !\n", hMenu
);
1899 /**********************************************************************
1900 * GetSystemMenu [USER.156]
1902 HMENU
GetSystemMenu(HWND hWnd
, BOOL bRevert
)
1905 wndPtr
= WIN_FindWndPtr(hWnd
);
1907 return wndPtr
->hSysMenu
;
1910 DestroyMenu(wndPtr
->hSysMenu
);
1911 wndPtr
->hSysMenu
= CopySysMenu();
1913 return wndPtr
->hSysMenu
;
1916 /**********************************************************************
1917 * SetSystemMenu [USER.280]
1919 BOOL
SetSystemMenu(HWND hWnd
, HMENU newHmenu
)
1923 if ((wndPtr
= WIN_FindWndPtr(hWnd
)) != NULL
) wndPtr
->hSysMenu
= newHmenu
;
1928 /**********************************************************************
1929 * GetMenu [USER.157]
1931 HMENU
GetMenu(HWND hWnd
)
1933 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
1934 if (wndPtr
== NULL
) return 0;
1935 return wndPtr
->wIDmenu
;
1939 /**********************************************************************
1940 * SetMenu [USER.158]
1942 BOOL
SetMenu(HWND hWnd
, HMENU hMenu
)
1945 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
1946 if (wndPtr
== NULL
) {
1947 fprintf(stderr
,"SetMenu(%04X, %04X) // Bad window handle !\n",
1951 dprintf_menu(stddeb
,"SetMenu(%04X, %04X);\n", hWnd
, hMenu
);
1952 if (GetCapture() == hWnd
) ReleaseCapture();
1953 wndPtr
->wIDmenu
= hMenu
;
1956 lpmenu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
1957 if (lpmenu
== NULL
) {
1958 fprintf(stderr
,"SetMenu(%04X, %04X) // Bad menu handle !\n",
1962 lpmenu
->hWnd
= hWnd
;
1963 lpmenu
->wFlags
&= ~MF_POPUP
; /* Can't be a popup */
1964 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
1966 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
1967 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
1973 /**********************************************************************
1974 * GetSubMenu [USER.159]
1976 HMENU
GetSubMenu(HMENU hMenu
, short nPos
)
1980 dprintf_menu(stddeb
,"GetSubMenu (%04X, %04X) !\n", hMenu
, nPos
);
1981 if (!(lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return 0;
1982 if ((WORD
)nPos
>= lppop
->nItems
) return 0;
1983 lpitem
= (MENUITEM
*) USER_HEAP_LIN_ADDR( lppop
->hItems
);
1984 if (!(lpitem
[nPos
].item_flags
& MF_POPUP
)) return 0;
1985 return lpitem
[nPos
].item_id
;
1989 /**********************************************************************
1990 * DrawMenuBar [USER.160]
1992 void DrawMenuBar(HWND hWnd
)
1996 dprintf_menu(stddeb
,"DrawMenuBar (%04X)\n", hWnd
);
1997 wndPtr
= WIN_FindWndPtr(hWnd
);
1998 if (wndPtr
!= NULL
&& (wndPtr
->dwStyle
& WS_CHILD
) == 0 &&
1999 wndPtr
->wIDmenu
!= 0) {
2000 dprintf_menu(stddeb
,"DrawMenuBar wIDmenu=%04X \n",
2002 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(wndPtr
->wIDmenu
);
2003 if (lppop
== NULL
) return;
2005 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
2006 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
2007 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
2012 /***********************************************************************
2013 * EndMenu (USER.187)
2017 /* Note: this won't work when we have multiple tasks... */
2018 fEndMenuCalled
= TRUE
;
2022 /***********************************************************************
2023 * LookupMenuHandle (USER.217)
2025 HMENU
LookupMenuHandle( HMENU hmenu
, INT id
)
2027 if (!MENU_FindItem( &hmenu
, &id
, MF_BYCOMMAND
)) return 0;
2032 /**********************************************************************
2033 * LoadMenuIndirect [USER.220]
2035 HMENU
LoadMenuIndirect(LPSTR menu_template
)
2038 MENU_HEADER
*menu_desc
;
2039 dprintf_menu(stddeb
,"LoadMenuIndirect: menu_template '%p'\n",
2041 hMenu
= CreateMenu();
2042 menu_desc
= (MENU_HEADER
*)menu_template
;
2043 ParseMenuResource((WORD
*)(menu_desc
+ 1), 0, hMenu
);
2048 /**********************************************************************
2049 * CopySysMenu (Internal)
2055 extern unsigned char sysres_MENU_SYSMENU
[];
2057 hMenu
=LoadMenuIndirect(sysres_MENU_SYSMENU
);
2059 dprintf_menu(stddeb
,"No SYSMENU\n");
2062 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
2063 menu
->wFlags
|= MF_SYSMENU
|MF_POPUP
;
2064 dprintf_menu(stddeb
,"CopySysMenu hMenu=%04X !\n", hMenu
);
2069 /**********************************************************************
2070 * ParseMenuResource (from Resource or Template)
2072 WORD
* ParseMenuResource(WORD
*first_item
, int level
, HMENU hMenu
)
2080 next_item
= first_item
;
2085 if (*item
& MF_POPUP
) {
2086 MENU_POPUPITEM
*popup_item
= (MENU_POPUPITEM
*) item
;
2087 next_item
= (WORD
*) (popup_item
->item_text
+
2088 strlen(popup_item
->item_text
) + 1);
2089 hSubMenu
= CreatePopupMenu();
2090 next_item
= ParseMenuResource(next_item
, level
, hSubMenu
);
2091 AppendMenu(hMenu
, popup_item
->item_flags
,
2092 hSubMenu
, popup_item
->item_text
);
2095 MENUITEMTEMPLATE
*normal_item
= (MENUITEMTEMPLATE
*) item
;
2096 next_item
= (WORD
*) (normal_item
->item_text
+
2097 strlen(normal_item
->item_text
) + 1);
2098 if (strlen(normal_item
->item_text
) == 0 && normal_item
->item_id
== 0)
2099 normal_item
->item_flags
|= MF_SEPARATOR
;
2100 AppendMenu(hMenu
, normal_item
->item_flags
,
2101 normal_item
->item_id
, normal_item
->item_text
);
2104 while (!(*item
& MF_END
));
2109 /**********************************************************************
2112 BOOL
IsMenu( HMENU hmenu
)
2115 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
2116 return (menu
->wMagic
== MENU_MAGIC
);