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"
29 #include "stackframe.h"
33 /* Dimension of the menu bitmaps */
34 static WORD check_bitmap_width
= 0, check_bitmap_height
= 0;
35 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
37 /* Flag set by EndMenu() to force an exit from menu tracking */
38 static BOOL fEndMenuCalled
= FALSE
;
40 /* Space between 2 menu bar items */
41 #define MENU_BAR_ITEMS_SPACE 16
43 /* Minimum width of a tab character */
44 #define MENU_TAB_SPACE 8
46 /* Height of a separator item */
47 #define SEPARATOR_HEIGHT 5
49 /* Values for menu->FocusedItem */
50 /* (other values give the position of the focused item) */
51 #define NO_SELECTED_ITEM 0xffff
52 #define SYSMENU_SELECTED 0xfffe /* Only valid on menu-bars */
54 #define IS_STRING_ITEM(flags) (!((flags) & (MF_BITMAP | MF_OWNERDRAW | \
55 MF_MENUBARBREAK | MF_MENUBREAK | MF_SEPARATOR)))
57 #define SET_OWNERDRAW_DATA(item,data) \
58 ((item)->hText = LOWORD((DWORD)(data)), (item)->xTab = HIWORD((DWORD)(data)))
60 #define GET_OWNERDRAW_DATA(item) \
61 ((DWORD)MAKELONG( (WORD)(item)->hText, (item)->xTab ))
63 extern void NC_DrawSysButton(HWND hwnd
, HDC hdc
, BOOL down
); /* nonclient.c */
65 static HBITMAP hStdCheck
= 0;
66 static HBITMAP hStdMnArrow
= 0;
69 /***********************************************************************
72 * Menus initialisation.
80 if (!(hStdCheck
= LoadBitmap( 0, MAKEINTRESOURCE(OBM_CHECK
) )))
82 GetObject( hStdCheck
, sizeof(BITMAP
), (LPSTR
)&bm
);
83 check_bitmap_width
= bm
.bmWidth
;
84 check_bitmap_height
= bm
.bmHeight
;
85 if (!(hStdMnArrow
= LoadBitmap( 0, MAKEINTRESOURCE(OBM_MNARROW
) )))
87 GetObject( hStdMnArrow
, sizeof(BITMAP
), (LPSTR
)&bm
);
88 arrow_bitmap_width
= bm
.bmWidth
;
89 arrow_bitmap_height
= bm
.bmHeight
;
95 /***********************************************************************
98 * Check whether the window owning the menu bar has a system menu.
100 static BOOL
MENU_HasSysMenu( POPUPMENU
*menu
)
104 if (menu
->wFlags
& MF_POPUP
) return FALSE
;
105 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return FALSE
;
106 return (wndPtr
->dwStyle
& WS_SYSMENU
) != 0;
110 /**********************************************************************
113 static HMENU
MENU_CopySysMenu(void)
119 if (!(handle
= SYSRES_LoadResource( SYSRES_MENU_SYSMENU
))) return 0;
120 hMenu
= LoadMenuIndirect( WIN16_GlobalLock( handle
) );
121 SYSRES_FreeResource( handle
);
124 dprintf_menu(stddeb
,"No SYSMENU\n");
127 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
128 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
129 dprintf_menu(stddeb
,"CopySysMenu hMenu="NPFMT
" !\n", hMenu
);
134 /***********************************************************************
137 * Check whether the point (in screen coords) is in the system menu
138 * of the window owning the given menu.
140 static BOOL
MENU_IsInSysMenu( POPUPMENU
*menu
, POINT pt
)
144 if (menu
->wFlags
& MF_POPUP
) return FALSE
;
145 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return FALSE
;
146 if (!(wndPtr
->dwStyle
& WS_SYSMENU
)) return FALSE
;
147 if ((pt
.x
< wndPtr
->rectClient
.left
) ||
148 (pt
.x
>= wndPtr
->rectClient
.left
+SYSMETRICS_CXSIZE
+SYSMETRICS_CXBORDER
))
150 if ((pt
.y
>= wndPtr
->rectClient
.top
- menu
->Height
) ||
151 (pt
.y
< wndPtr
->rectClient
.top
- menu
->Height
-
152 SYSMETRICS_CYSIZE
- SYSMETRICS_CYBORDER
)) return FALSE
;
157 /***********************************************************************
160 * Find a menu item. Return a pointer on the item, and modifies *hmenu
161 * in case the item was in a sub-menu.
163 static MENUITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
169 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(*hmenu
))) return NULL
;
170 item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
171 if (wFlags
& MF_BYPOSITION
)
173 if (*nPos
>= menu
->nItems
) return NULL
;
178 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
180 if (item
->item_id
== *nPos
)
185 else if (item
->item_flags
& MF_POPUP
)
187 HMENU hsubmenu
= (HMENU
)item
->item_id
;
188 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
201 /***********************************************************************
202 * MENU_FindItemByCoords
204 * Find the item at the specified coordinates (screen coords).
206 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
, int x
, int y
, UINT
*pos
)
212 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return NULL
;
213 x
-= wndPtr
->rectWindow
.left
;
214 y
-= wndPtr
->rectWindow
.top
;
215 item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
216 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
218 if ((x
>= item
->rect
.left
) && (x
< item
->rect
.right
) &&
219 (y
>= item
->rect
.top
) && (y
< item
->rect
.bottom
))
229 /***********************************************************************
232 * Find the menu item selected by a key press.
233 * Return item id, -1 if none, -2 if we should close the menu.
235 static UINT
MENU_FindItemByKey( HWND hwndOwner
, HMENU hmenu
, UINT key
)
242 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
243 lpitem
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
245 for (i
= 0; i
< menu
->nItems
; i
++, lpitem
++)
247 if (IS_STRING_ITEM(lpitem
->item_flags
))
249 char *p
= strchr( (char *)USER_HEAP_LIN_ADDR(lpitem
->hText
), '&' );
250 if (p
&& (p
[1] != '&') && (toupper(p
[1]) == key
)) return i
;
254 menuchar
= SendMessage( hwndOwner
, WM_MENUCHAR
,
255 MAKEWPARAM(key
,menu
->wFlags
), (LPARAM
)hmenu
);
257 menuchar
= SendMessage( hwndOwner
, WM_MENUCHAR
, key
,
258 MAKELONG( menu
->wFlags
, hmenu
) );
260 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
261 if (HIWORD(menuchar
) == 1) return -2;
266 /***********************************************************************
269 * Calculate the size of the menu item and store it in lpitem->rect.
271 static void MENU_CalcItemSize( HDC hdc
, LPMENUITEM lpitem
, HWND hwndOwner
,
272 int orgX
, int orgY
, BOOL menuBar
)
277 SetRect( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
279 if (lpitem
->item_flags
& MF_OWNERDRAW
)
281 MEASUREITEMSTRUCT mis
;
282 mis
.CtlType
= ODT_MENU
;
283 mis
.itemID
= lpitem
->item_id
;
284 mis
.itemData
= GET_OWNERDRAW_DATA(lpitem
);
287 SendMessage( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)MAKE_SEGPTR(&mis
) );
288 lpitem
->rect
.bottom
+= mis
.itemHeight
;
289 lpitem
->rect
.right
+= mis
.itemWidth
;
290 dprintf_menu( stddeb
, "DrawMenuItem: MeasureItem %04x %dx%d!\n",
291 lpitem
->item_id
, mis
.itemWidth
, mis
.itemHeight
);
295 if (lpitem
->item_flags
& MF_SEPARATOR
)
297 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
303 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
304 if (lpitem
->item_flags
& MF_POPUP
)
305 lpitem
->rect
.right
+= arrow_bitmap_width
;
308 if (lpitem
->item_flags
& MF_BITMAP
)
311 if (GetObject( (HBITMAP
)lpitem
->hText
, sizeof(BITMAP
), (LPSTR
)&bm
))
313 lpitem
->rect
.right
+= bm
.bmWidth
;
314 lpitem
->rect
.bottom
+= bm
.bmHeight
;
319 /* If we get here, then it must be a text item */
321 if (IS_STRING_ITEM( lpitem
->item_flags
))
323 const char *text
= (const char *)USER_HEAP_LIN_ADDR( lpitem
->hText
);
324 dwSize
= GetTextExtent( hdc
, text
, strlen(text
) );
325 lpitem
->rect
.right
+= LOWORD(dwSize
);
326 lpitem
->rect
.bottom
+= MAX( HIWORD(dwSize
), SYSMETRICS_CYMENU
);
329 if (menuBar
) lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
330 else if ((p
= strchr( text
, '\t' )) != NULL
)
332 /* Item contains a tab (only meaningful in popup menus) */
333 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+
334 LOWORD( GetTextExtent( hdc
, text
, (int)(p
- text
) ));
335 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
339 if (strchr( text
, '\b' )) lpitem
->rect
.right
+= MENU_TAB_SPACE
;
340 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
341 - arrow_bitmap_width
;
347 /***********************************************************************
348 * MENU_PopupMenuCalcSize
350 * Calculate the size of a popup menu.
352 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND hwndOwner
)
354 LPMENUITEM items
, lpitem
;
357 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
359 lppop
->Width
= lppop
->Height
= 0;
360 if (lppop
->nItems
== 0) return;
361 items
= (MENUITEM
*)USER_HEAP_LIN_ADDR( lppop
->hItems
);
364 while (start
< lppop
->nItems
)
366 lpitem
= &items
[start
];
369 maxTab
= maxTabWidth
= 0;
371 /* Parse items until column break or end of menu */
372 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
375 (lpitem
->item_flags
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
376 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
377 if (lpitem
->item_flags
& MF_MENUBARBREAK
) orgX
++;
378 maxX
= MAX( maxX
, lpitem
->rect
.right
);
379 orgY
= lpitem
->rect
.bottom
;
380 if (IS_STRING_ITEM(lpitem
->item_flags
) && lpitem
->xTab
)
382 maxTab
= MAX( maxTab
, lpitem
->xTab
);
383 maxTabWidth
= MAX(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
387 /* Finish the column (set all items to the largest width found) */
388 maxX
= MAX( maxX
, maxTab
+ maxTabWidth
);
389 for (lpitem
= &items
[start
]; start
< i
; start
++, lpitem
++)
391 lpitem
->rect
.right
= maxX
;
392 if (IS_STRING_ITEM(lpitem
->item_flags
) && lpitem
->xTab
)
393 lpitem
->xTab
= maxTab
;
395 lppop
->Height
= MAX( lppop
->Height
, orgY
);
403 /***********************************************************************
404 * MENU_MenuBarCalcSize
406 * Calculate the size of the menu bar.
408 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
, LPPOPUPMENU lppop
,
411 LPMENUITEM lpitem
, items
;
412 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
414 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
415 if (lppop
->nItems
== 0) return;
416 dprintf_menu(stddeb
,"MENU_MenuBarCalcSize left=%ld top=%ld right=%ld bottom=%ld !\n",
417 (LONG
)lprect
->left
, (LONG
)lprect
->top
, (LONG
)lprect
->right
, (LONG
)lprect
->bottom
);
418 items
= (MENUITEM
*)USER_HEAP_LIN_ADDR( lppop
->hItems
);
419 lppop
->Width
= lprect
->right
- lprect
->left
;
424 while (start
< lppop
->nItems
)
426 lpitem
= &items
[start
];
430 /* Parse items until line break or end of menu */
431 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
433 if ((helpPos
== -1) && (lpitem
->item_flags
& MF_HELP
)) helpPos
= i
;
435 (lpitem
->item_flags
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
436 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
437 if (lpitem
->rect
.right
> lprect
->right
)
439 if (i
!= start
) break;
440 else lpitem
->rect
.right
= lprect
->right
;
442 maxY
= MAX( maxY
, lpitem
->rect
.bottom
);
443 orgX
= lpitem
->rect
.right
;
446 /* Finish the line (set all items to the largest height found) */
447 while (start
< i
) items
[start
++].rect
.bottom
= maxY
;
450 lprect
->bottom
= maxY
;
451 lppop
->Height
= lprect
->bottom
- lprect
->top
;
453 /* Flush right all items between the MF_HELP and the last item */
454 /* (if several lines, only move the last line) */
457 lpitem
= &items
[lppop
->nItems
-1];
458 orgY
= lpitem
->rect
.top
;
459 orgX
= lprect
->right
;
460 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--)
462 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
463 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
464 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
465 lpitem
->rect
.right
= orgX
;
466 orgX
= lpitem
->rect
.left
;
472 /***********************************************************************
475 * Draw a single menu item.
477 static void MENU_DrawMenuItem( HWND hwnd
, HDC hdc
, LPMENUITEM lpitem
,
478 UINT height
, BOOL menuBar
)
482 if (lpitem
->item_flags
& MF_OWNERDRAW
)
486 dprintf_menu( stddeb
, "DrawMenuItem: Ownerdraw!\n" );
487 dis
.CtlType
= ODT_MENU
;
488 dis
.itemID
= lpitem
->item_id
;
489 dis
.itemData
= GET_OWNERDRAW_DATA(lpitem
);
491 if (lpitem
->item_flags
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
492 if (lpitem
->item_flags
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
;
493 if (lpitem
->item_flags
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
494 dis
.itemAction
= ODA_DRAWENTIRE
| ODA_SELECT
| ODA_FOCUS
;
497 dis
.rcItem
= lpitem
->rect
;
498 SendMessage( hwnd
, WM_DRAWITEM
, 0, MAKE_SEGPTR(&dis
) );
502 if (menuBar
&& (lpitem
->item_flags
& MF_SEPARATOR
)) return;
505 /* Draw the background */
507 if (lpitem
->item_flags
& MF_HILITE
)
508 FillRect( hdc
, &rect
, sysColorObjects
.hbrushHighlight
);
509 else FillRect( hdc
, &rect
, sysColorObjects
.hbrushMenu
);
510 SetBkMode( hdc
, TRANSPARENT
);
512 /* Draw the separator bar (if any) */
514 if (!menuBar
&& (lpitem
->item_flags
& MF_MENUBARBREAK
))
516 SelectObject( hdc
, sysColorObjects
.hpenWindowFrame
);
517 MoveTo( hdc
, rect
.left
, 0 );
518 LineTo( hdc
, rect
.left
, height
);
520 if (lpitem
->item_flags
& MF_SEPARATOR
)
522 SelectObject( hdc
, sysColorObjects
.hpenWindowFrame
);
523 MoveTo( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
524 LineTo( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
530 if (lpitem
->item_flags
& MF_HILITE
)
532 if (lpitem
->item_flags
& MF_GRAYED
)
533 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
535 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
536 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
540 if (lpitem
->item_flags
& MF_GRAYED
)
541 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
543 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
544 SetBkColor( hdc
, GetSysColor( COLOR_MENU
) );
549 /* Draw the check mark */
551 if (lpitem
->item_flags
& MF_CHECKED
)
553 GRAPH_DrawBitmap(hdc
, lpitem
->hCheckBit
? lpitem
->hCheckBit
:
554 hStdCheck
, rect
.left
,
555 (rect
.top
+rect
.bottom
-check_bitmap_height
) / 2,
556 0, 0, check_bitmap_width
, check_bitmap_height
);
558 else if (lpitem
->hUnCheckBit
!= 0) /* Not checked */
560 GRAPH_DrawBitmap(hdc
, lpitem
->hUnCheckBit
, rect
.left
,
561 (rect
.top
+rect
.bottom
-check_bitmap_height
) / 2,
562 0, 0, check_bitmap_width
, check_bitmap_height
);
565 /* Draw the popup-menu arrow */
567 if (lpitem
->item_flags
& MF_POPUP
)
569 GRAPH_DrawBitmap( hdc
, hStdMnArrow
,
570 rect
.right
-arrow_bitmap_width
-1,
571 (rect
.top
+rect
.bottom
-arrow_bitmap_height
) / 2,
572 0, 0, arrow_bitmap_width
, arrow_bitmap_height
);
575 rect
.left
+= check_bitmap_width
;
576 rect
.right
-= arrow_bitmap_width
;
579 /* Draw the item text or bitmap */
581 if (lpitem
->item_flags
& MF_BITMAP
)
583 GRAPH_DrawBitmap( hdc
, (HBITMAP
)lpitem
->hText
, rect
.left
, rect
.top
,
584 0, 0, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
);
587 /* No bitmap - process text if present */
588 else if (IS_STRING_ITEM(lpitem
->item_flags
))
591 const char *text
= (const char *)USER_HEAP_LIN_ADDR( lpitem
->hText
);
595 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
596 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
601 for (i
= 0; text
[i
]; i
++)
602 if ((text
[i
] == '\t') || (text
[i
] == '\b')) break;
605 DrawText( hdc
, text
, i
, &rect
, DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
607 if (text
[i
]) /* There's a tab or flush-right char */
611 rect
.left
= lpitem
->xTab
;
612 DrawText( hdc
, text
+ i
+ 1, -1, &rect
,
613 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
615 else DrawText( hdc
, text
+ i
+ 1, -1, &rect
,
616 DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
);
622 /***********************************************************************
625 * Paint a popup menu.
627 static void MENU_DrawPopupMenu( HWND hwnd
, HDC hdc
, HMENU hmenu
)
634 GetClientRect( hwnd
, &rect
);
635 FillRect( hdc
, &rect
, sysColorObjects
.hbrushMenu
);
636 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
637 if (!menu
|| !menu
->nItems
) return;
638 item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
639 for (i
= menu
->nItems
; i
> 0; i
--, item
++)
640 MENU_DrawMenuItem( hwnd
, hdc
, item
, menu
->Height
, FALSE
);
644 /***********************************************************************
647 * Paint a menu bar. Returns the height of the menu bar.
649 UINT
MENU_DrawMenuBar(HDC hDC
, LPRECT lprect
, HWND hwnd
, BOOL suppress_draw
)
654 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
656 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( (HMENU
)wndPtr
->wIDmenu
);
657 if (lppop
== NULL
|| lprect
== NULL
) return SYSMETRICS_CYMENU
;
658 dprintf_menu(stddeb
,"MENU_DrawMenuBar("NPFMT
", %p, %p); !\n",
660 if (lppop
->Height
== 0) MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
661 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
662 if (suppress_draw
) return lppop
->Height
;
664 FillRect(hDC
, lprect
, sysColorObjects
.hbrushMenu
);
665 SelectObject( hDC
, sysColorObjects
.hpenWindowFrame
);
666 MoveTo( hDC
, lprect
->left
, lprect
->bottom
);
667 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
669 if (lppop
->nItems
== 0) return SYSMETRICS_CYMENU
;
670 lpitem
= (MENUITEM
*) USER_HEAP_LIN_ADDR( lppop
->hItems
);
671 for (i
= 0; i
< lppop
->nItems
; i
++, lpitem
++)
673 MENU_DrawMenuItem( hwnd
, hDC
, lpitem
, lppop
->Height
, TRUE
);
675 return lppop
->Height
;
679 /***********************************************************************
682 * Display a popup menu.
684 static BOOL
MENU_ShowPopup(HWND hwndOwner
, HMENU hmenu
, UINT id
, int x
, int y
)
688 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
689 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
691 MENUITEM
*item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
692 item
[menu
->FocusedItem
].item_flags
&= ~(MF_HILITE
| MF_MOUSESELECT
);
693 menu
->FocusedItem
= NO_SELECTED_ITEM
;
695 SendMessage( hwndOwner
, WM_INITMENUPOPUP
, (WPARAM
)hmenu
,
696 MAKELONG( id
, (menu
->wFlags
& MF_SYSMENU
) ? 1 : 0 ));
697 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
700 WND
*wndPtr
= WIN_FindWndPtr( hwndOwner
);
701 if (!wndPtr
) return FALSE
;
702 menu
->hWnd
= CreateWindow( POPUPMENU_CLASS_ATOM
, (SEGPTR
)0,
703 WS_POPUP
| WS_BORDER
, x
, y
,
704 menu
->Width
+ 2*SYSMETRICS_CXBORDER
,
705 menu
->Height
+ 2*SYSMETRICS_CYBORDER
,
706 0, 0, wndPtr
->hInstance
, (SEGPTR
)hmenu
);
707 if (!menu
->hWnd
) return FALSE
;
709 else SetWindowPos( menu
->hWnd
, 0, x
, y
,
710 menu
->Width
+ 2*SYSMETRICS_CXBORDER
,
711 menu
->Height
+ 2*SYSMETRICS_CYBORDER
,
712 SWP_NOACTIVATE
| SWP_NOZORDER
);
714 /* Display the window */
716 SetWindowPos( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
717 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
718 UpdateWindow( menu
->hWnd
);
723 /***********************************************************************
726 static void MENU_SelectItem( HWND hwndOwner
, HMENU hmenu
, UINT wIndex
)
732 lppop
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
733 if (!lppop
->nItems
) return;
734 items
= (MENUITEM
*) USER_HEAP_LIN_ADDR( lppop
->hItems
);
735 if ((wIndex
!= NO_SELECTED_ITEM
) &&
736 (wIndex
!= SYSMENU_SELECTED
) &&
737 (items
[wIndex
].item_flags
& MF_SEPARATOR
))
738 wIndex
= NO_SELECTED_ITEM
;
739 if (lppop
->FocusedItem
== wIndex
) return;
740 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC( lppop
->hWnd
);
741 else hdc
= GetDCEx( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
743 /* Clear previous highlighted item */
744 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
746 if (lppop
->FocusedItem
== SYSMENU_SELECTED
)
747 NC_DrawSysButton( lppop
->hWnd
, hdc
, FALSE
);
750 items
[lppop
->FocusedItem
].item_flags
&=~(MF_HILITE
|MF_MOUSESELECT
);
751 MENU_DrawMenuItem( lppop
->hWnd
, hdc
, &items
[lppop
->FocusedItem
], lppop
->Height
,
752 !(lppop
->wFlags
& MF_POPUP
) );
756 /* Highlight new item (if any) */
757 lppop
->FocusedItem
= wIndex
;
758 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
760 if (lppop
->FocusedItem
== SYSMENU_SELECTED
)
762 NC_DrawSysButton( lppop
->hWnd
, hdc
, TRUE
);
765 SendMessage( hwndOwner
, WM_MENUSELECT
,
766 MAKEWPARAM( (DWORD
)GetSystemMenu( lppop
->hWnd
, FALSE
),
767 lppop
->wFlags
| MF_MOUSESELECT
),
770 SendMessage( hwndOwner
, WM_MENUSELECT
,
771 GetSystemMenu( lppop
->hWnd
, FALSE
),
772 MAKELONG( lppop
->wFlags
| MF_MOUSESELECT
, hmenu
) );
777 items
[lppop
->FocusedItem
].item_flags
|= MF_HILITE
;
778 MENU_DrawMenuItem( lppop
->hWnd
, hdc
, &items
[lppop
->FocusedItem
], lppop
->Height
,
779 !(lppop
->wFlags
& MF_POPUP
) );
781 SendMessage( hwndOwner
, WM_MENUSELECT
,
782 MAKEWPARAM( items
[lppop
->FocusedItem
].item_id
,
783 items
[lppop
->FocusedItem
].item_flags
|
787 SendMessage( hwndOwner
, WM_MENUSELECT
,
788 items
[lppop
->FocusedItem
].item_id
,
789 MAKELONG( items
[lppop
->FocusedItem
].item_flags
| MF_MOUSESELECT
, hmenu
));
795 else SendMessage( hwndOwner
, WM_MENUSELECT
,
796 MAKEWPARAM( (DWORD
)hmenu
, lppop
->wFlags
| MF_MOUSESELECT
),
799 else SendMessage( hwndOwner
, WM_MENUSELECT
, hmenu
,
800 MAKELONG( lppop
->wFlags
| MF_MOUSESELECT
, hmenu
) );
803 ReleaseDC( lppop
->hWnd
, hdc
);
807 /***********************************************************************
808 * MENU_SelectNextItem
810 static void MENU_SelectNextItem( HWND hwndOwner
, HMENU hmenu
)
816 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
817 if (!menu
->nItems
) return;
818 items
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
819 if ((menu
->FocusedItem
!= NO_SELECTED_ITEM
) &&
820 (menu
->FocusedItem
!= SYSMENU_SELECTED
))
822 for (i
= menu
->FocusedItem
+1; i
< menu
->nItems
; i
++)
824 if (!(items
[i
].item_flags
& MF_SEPARATOR
))
826 MENU_SelectItem( hwndOwner
, hmenu
, i
);
830 if (MENU_HasSysMenu( menu
))
832 MENU_SelectItem( hwndOwner
, hmenu
, SYSMENU_SELECTED
);
836 for (i
= 0; i
< menu
->nItems
; i
++)
838 if (!(items
[i
].item_flags
& MF_SEPARATOR
))
840 MENU_SelectItem( hwndOwner
, hmenu
, i
);
844 if (MENU_HasSysMenu( menu
))
845 MENU_SelectItem( hwndOwner
, hmenu
, SYSMENU_SELECTED
);
849 /***********************************************************************
850 * MENU_SelectPrevItem
852 static void MENU_SelectPrevItem( HWND hwndOwner
, HMENU hmenu
)
858 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
859 if (!menu
->nItems
) return;
860 items
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
861 if ((menu
->FocusedItem
!= NO_SELECTED_ITEM
) &&
862 (menu
->FocusedItem
!= SYSMENU_SELECTED
))
864 for (i
= menu
->FocusedItem
- 1; i
>= 0; i
--)
866 if (!(items
[i
].item_flags
& MF_SEPARATOR
))
868 MENU_SelectItem( hwndOwner
, hmenu
, i
);
872 if (MENU_HasSysMenu( menu
))
874 MENU_SelectItem( hwndOwner
, hmenu
, SYSMENU_SELECTED
);
878 for (i
= menu
->nItems
- 1; i
> 0; i
--)
880 if (!(items
[i
].item_flags
& MF_SEPARATOR
))
882 MENU_SelectItem( hwndOwner
, hmenu
, i
);
886 if (MENU_HasSysMenu( menu
))
887 MENU_SelectItem( hwndOwner
, hmenu
, SYSMENU_SELECTED
);
891 /**********************************************************************
894 * Set an item flags, id and text ptr.
896 static BOOL
MENU_SetItemData( MENUITEM
*item
, UINT flags
, UINT id
, SEGPTR data
)
898 HANDLE hPrevText
= IS_STRING_ITEM(item
->item_flags
) ? item
->hText
: 0;
900 if (IS_STRING_ITEM(flags
))
904 flags
|= MF_SEPARATOR
;
909 char *str
= (char *)PTR_SEG_TO_LIN(data
);
912 /* Item beginning with a backspace is a help item */
918 if (!(hText
= USER_HEAP_ALLOC( strlen(str
)+1 ))) return FALSE
;
920 strcpy( (char *)USER_HEAP_LIN_ADDR( hText
), str
);
923 else if (flags
& MF_BITMAP
) item
->hText
= (HANDLE
)(DWORD
)data
;
924 else if (flags
& MF_OWNERDRAW
) SET_OWNERDRAW_DATA( item
, data
);
925 else item
->hText
= 0;
927 item
->item_flags
= flags
& ~(MF_HILITE
| MF_MOUSESELECT
);
929 SetRectEmpty( &item
->rect
);
930 if (hPrevText
) USER_HEAP_FREE( hPrevText
);
935 /**********************************************************************
938 * Insert a new item into a menu.
940 static MENUITEM
*MENU_InsertItem( HMENU hMenu
, UINT pos
, UINT flags
)
946 if (!(menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
)))
948 dprintf_menu( stddeb
, "MENU_InsertItem: "NPFMT
" not a menu handle\n",
953 /* Find where to insert new item */
955 if ((flags
& MF_BYPOSITION
) &&
956 ((pos
== (UINT
)-1) || (pos
== menu
->nItems
)))
958 /* Special case: append to menu */
959 /* Some programs specify the menu length to do that */
964 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
966 dprintf_menu( stddeb
, "MENU_InsertItem: item %x not found\n",
970 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
)))
972 dprintf_menu(stddeb
,"MENU_InsertItem: "NPFMT
" not a menu handle\n",
978 /* Create new items array */
980 hNewItems
= USER_HEAP_ALLOC( sizeof(MENUITEM
) * (menu
->nItems
+1) );
983 dprintf_menu( stddeb
, "MENU_InsertMenu: allocation failed\n" );
986 newItems
= (MENUITEM
*) USER_HEAP_LIN_ADDR( hNewItems
);
987 if (menu
->nItems
> 0)
989 /* Copy the old array into the new */
990 MENUITEM
*oldItems
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
991 if (pos
> 0) memcpy( newItems
, oldItems
, pos
* sizeof(MENUITEM
) );
992 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &oldItems
[pos
],
993 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
995 USER_HEAP_FREE( menu
->hItems
);
997 menu
->hItems
= hNewItems
;
999 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
1000 return &newItems
[pos
];
1004 /**********************************************************************
1005 * MENU_ParseResource
1007 * Parse a menu resource and add items to the menu.
1008 * Return a pointer to the end of the resource.
1010 static SEGPTR
MENU_ParseResource( SEGPTR res
, HMENU hMenu
)
1017 flags
= *(WORD
*)PTR_SEG_TO_LIN( res
);
1018 res
+= sizeof(WORD
);
1019 if (!(flags
& MF_POPUP
))
1021 id
= *(WORD
*)PTR_SEG_TO_LIN( res
);
1022 res
+= sizeof(WORD
);
1025 res
+= strlen( (char *)PTR_SEG_TO_LIN(data
) ) + 1;
1026 if (!IS_STRING_ITEM(flags
))
1027 fprintf( stderr
, "MENU_ParseResource: not a string item %04x\n",
1029 if (flags
& MF_POPUP
)
1031 HMENU hSubMenu
= CreatePopupMenu();
1032 if (!hSubMenu
) return (SEGPTR
)0;
1033 if (!(res
= MENU_ParseResource( res
, hSubMenu
))) return (SEGPTR
)0;
1034 AppendMenu( hMenu
, flags
, (UINT
)hSubMenu
, data
);
1038 if (!*(char *)PTR_SEG_TO_LIN(data
)) data
= 0;
1039 AppendMenu( hMenu
, flags
, id
, data
);
1041 } while (!(flags
& MF_END
));
1046 /***********************************************************************
1049 * Return the handle of the selected sub-popup menu (if any).
1051 static HMENU
MENU_GetSubPopup( HMENU hmenu
)
1056 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1057 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return 0;
1058 else if (menu
->FocusedItem
== SYSMENU_SELECTED
)
1059 return GetSystemMenu( menu
->hWnd
, FALSE
);
1061 item
= ((MENUITEM
*)USER_HEAP_LIN_ADDR(menu
->hItems
)) + menu
->FocusedItem
;
1062 if (!(item
->item_flags
& MF_POPUP
) || !(item
->item_flags
& MF_MOUSESELECT
))
1064 return (HMENU
)item
->item_id
;
1068 /***********************************************************************
1069 * MENU_HideSubPopups
1071 * Hide the sub-popup menus of this menu.
1073 static void MENU_HideSubPopups( HWND hwndOwner
, HMENU hmenu
)
1076 POPUPMENU
*menu
, *submenu
;
1079 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return;
1080 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return;
1081 if (menu
->FocusedItem
== SYSMENU_SELECTED
)
1083 hsubmenu
= GetSystemMenu( menu
->hWnd
, FALSE
);
1087 item
= ((MENUITEM
*)USER_HEAP_LIN_ADDR(menu
->hItems
)) + menu
->FocusedItem
;
1088 if (!(item
->item_flags
& MF_POPUP
) ||
1089 !(item
->item_flags
& MF_MOUSESELECT
)) return;
1090 item
->item_flags
&= ~MF_MOUSESELECT
;
1091 hsubmenu
= (HMENU
)item
->item_id
;
1093 submenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hsubmenu
);
1094 MENU_HideSubPopups( hwndOwner
, hsubmenu
);
1095 if (submenu
->hWnd
) ShowWindow( submenu
->hWnd
, SW_HIDE
);
1096 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
);
1100 /***********************************************************************
1103 * Display the sub-menu of the selected item of this menu.
1104 * Return the handle of the submenu, or hmenu if no submenu to display.
1106 static HMENU
MENU_ShowSubPopup( HWND hwndOwner
, HMENU hmenu
, BOOL selectFirst
)
1112 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return hmenu
;
1113 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return hmenu
;
1114 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return hmenu
;
1115 if (menu
->FocusedItem
== SYSMENU_SELECTED
)
1117 MENU_ShowPopup(hwndOwner
, wndPtr
->hSysMenu
, 0, wndPtr
->rectClient
.left
,
1118 wndPtr
->rectClient
.top
- menu
->Height
- 2*SYSMETRICS_CYBORDER
);
1119 if (selectFirst
) MENU_SelectNextItem( hwndOwner
, wndPtr
->hSysMenu
);
1120 return wndPtr
->hSysMenu
;
1122 item
= ((MENUITEM
*)USER_HEAP_LIN_ADDR(menu
->hItems
)) + menu
->FocusedItem
;
1123 if (!(item
->item_flags
& MF_POPUP
) ||
1124 (item
->item_flags
& (MF_GRAYED
| MF_DISABLED
))) return hmenu
;
1125 item
->item_flags
|= MF_MOUSESELECT
;
1126 if (menu
->wFlags
& MF_POPUP
)
1128 MENU_ShowPopup( hwndOwner
, (HMENU
)item
->item_id
, menu
->FocusedItem
,
1129 wndPtr
->rectWindow
.left
+ item
->rect
.right
-arrow_bitmap_width
,
1130 wndPtr
->rectWindow
.top
+ item
->rect
.top
);
1134 MENU_ShowPopup( hwndOwner
, (HMENU
)item
->item_id
, menu
->FocusedItem
,
1135 wndPtr
->rectWindow
.left
+ item
->rect
.left
,
1136 wndPtr
->rectWindow
.top
+ item
->rect
.bottom
);
1138 if (selectFirst
) MENU_SelectNextItem( hwndOwner
, (HMENU
)item
->item_id
);
1139 return (HMENU
)item
->item_id
;
1143 /***********************************************************************
1144 * MENU_FindMenuByCoords
1146 * Find the menu containing a given point (in screen coords).
1148 static HMENU
MENU_FindMenuByCoords( HMENU hmenu
, POINT pt
)
1153 if (!(hwnd
= WindowFromPoint( pt
))) return 0;
1156 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1157 if (menu
->hWnd
== hwnd
)
1159 if (!(menu
->wFlags
& MF_POPUP
))
1161 /* Make sure it's in the menu bar (or in system menu) */
1162 WND
*wndPtr
= WIN_FindWndPtr( menu
->hWnd
);
1163 if ((pt
.x
< wndPtr
->rectClient
.left
) ||
1164 (pt
.x
>= wndPtr
->rectClient
.right
) ||
1165 (pt
.y
>= wndPtr
->rectClient
.top
)) return 0;
1166 if (pt
.y
< wndPtr
->rectClient
.top
- menu
->Height
)
1168 if (!MENU_IsInSysMenu( menu
, pt
)) return 0;
1170 /* else it's in the menu bar */
1174 hmenu
= MENU_GetSubPopup( hmenu
);
1180 /***********************************************************************
1181 * MENU_ExecFocusedItem
1183 * Execute a menu item (for instance when user pressed Enter).
1184 * Return TRUE if we can go on with menu tracking.
1186 static BOOL
MENU_ExecFocusedItem( HWND hwndOwner
, HMENU hmenu
,
1187 HMENU
*hmenuCurrent
)
1190 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1191 if (!menu
|| !menu
->nItems
|| (menu
->FocusedItem
== NO_SELECTED_ITEM
) ||
1192 (menu
->FocusedItem
== SYSMENU_SELECTED
)) return TRUE
;
1193 item
= ((MENUITEM
*)USER_HEAP_LIN_ADDR(menu
->hItems
)) + menu
->FocusedItem
;
1194 if (!(item
->item_flags
& MF_POPUP
))
1196 if (!(item
->item_flags
& (MF_GRAYED
| MF_DISABLED
)))
1198 PostMessage( hwndOwner
, (menu
->wFlags
& MF_SYSMENU
) ?
1199 WM_SYSCOMMAND
: WM_COMMAND
, item
->item_id
, 0 );
1206 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, TRUE
);
1212 /***********************************************************************
1215 * Handle a button-down event in a menu. Point is in screen coords.
1216 * hmenuCurrent is the top-most visible popup.
1217 * Return TRUE if we can go on with menu tracking.
1219 static BOOL
MENU_ButtonDown( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
,
1226 if (!hmenu
) return FALSE
; /* Outside all menus */
1227 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1228 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1229 if (!item
) /* Maybe in system menu */
1231 if (!MENU_IsInSysMenu( menu
, pt
)) return FALSE
;
1232 id
= SYSMENU_SELECTED
;
1235 if (menu
->FocusedItem
== id
)
1237 if (id
== SYSMENU_SELECTED
) return FALSE
;
1238 if (item
->item_flags
& MF_POPUP
)
1240 if (item
->item_flags
& MF_MOUSESELECT
)
1242 if (menu
->wFlags
& MF_POPUP
)
1244 MENU_HideSubPopups( hwndOwner
, hmenu
);
1245 *hmenuCurrent
= hmenu
;
1249 else *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1254 MENU_HideSubPopups( hwndOwner
, hmenu
);
1255 MENU_SelectItem( hwndOwner
, hmenu
, id
);
1256 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1262 /***********************************************************************
1265 * Handle a button-up event in a menu. Point is in screen coords.
1266 * hmenuCurrent is the top-most visible popup.
1267 * Return TRUE if we can go on with menu tracking.
1269 static BOOL
MENU_ButtonUp( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
,
1277 if (!hmenu
) return FALSE
; /* Outside all menus */
1278 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1279 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1280 if (!item
) /* Maybe in system menu */
1282 if (!MENU_IsInSysMenu( menu
, pt
)) return FALSE
;
1283 id
= SYSMENU_SELECTED
;
1284 hsubmenu
= GetSystemMenu( menu
->hWnd
, FALSE
);
1287 if (menu
->FocusedItem
!= id
) return FALSE
;
1289 if (id
!= SYSMENU_SELECTED
)
1291 if (!(item
->item_flags
& MF_POPUP
))
1293 return MENU_ExecFocusedItem( hwndOwner
, hmenu
, hmenuCurrent
);
1295 hsubmenu
= (HMENU
)item
->item_id
;
1297 /* Select first item of sub-popup */
1298 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
);
1299 MENU_SelectNextItem( hwndOwner
, hsubmenu
);
1304 /***********************************************************************
1307 * Handle a motion event in a menu. Point is in screen coords.
1308 * hmenuCurrent is the top-most visible popup.
1309 * Return TRUE if we can go on with menu tracking.
1311 static BOOL
MENU_MouseMove( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
,
1315 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1316 UINT id
= NO_SELECTED_ITEM
;
1320 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1321 if (!item
) /* Maybe in system menu */
1323 if (!MENU_IsInSysMenu( menu
, pt
))
1324 id
= NO_SELECTED_ITEM
; /* Outside all items */
1325 else id
= SYSMENU_SELECTED
;
1328 if (id
== NO_SELECTED_ITEM
)
1330 MENU_SelectItem( hwndOwner
, *hmenuCurrent
, NO_SELECTED_ITEM
);
1332 else if (menu
->FocusedItem
!= id
)
1334 MENU_HideSubPopups( hwndOwner
, hmenu
);
1335 MENU_SelectItem( hwndOwner
, hmenu
, id
);
1336 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1342 /***********************************************************************
1345 * Handle a VK_LEFT key event in a menu.
1346 * hmenuCurrent is the top-most visible popup.
1348 static void MENU_KeyLeft( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
)
1351 HMENU hmenutmp
, hmenuprev
;
1353 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1354 hmenuprev
= hmenutmp
= hmenu
;
1355 while (hmenutmp
!= *hmenuCurrent
)
1357 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
1358 if (hmenutmp
!= *hmenuCurrent
) hmenuprev
= hmenutmp
;
1360 MENU_HideSubPopups( hwndOwner
, hmenuprev
);
1362 if ((hmenuprev
== hmenu
) && !(menu
->wFlags
& MF_POPUP
))
1364 /* Select previous item on the menu bar */
1365 MENU_SelectPrevItem( hwndOwner
, hmenu
);
1366 if (*hmenuCurrent
!= hmenu
)
1368 /* A popup menu was displayed -> display the next one */
1369 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, TRUE
);
1372 else *hmenuCurrent
= hmenuprev
;
1376 /***********************************************************************
1379 * Handle a VK_RIGHT key event in a menu.
1380 * hmenuCurrent is the top-most visible popup.
1382 static void MENU_KeyRight( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
)
1387 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1389 if ((menu
->wFlags
& MF_POPUP
) || (*hmenuCurrent
!= hmenu
))
1391 /* If already displaying a popup, try to display sub-popup */
1392 hmenutmp
= MENU_ShowSubPopup( hwndOwner
, *hmenuCurrent
, TRUE
);
1393 if (hmenutmp
!= *hmenuCurrent
) /* Sub-popup displayed */
1395 *hmenuCurrent
= hmenutmp
;
1400 /* If on menu-bar, go to next item */
1401 if (!(menu
->wFlags
& MF_POPUP
))
1403 MENU_HideSubPopups( hwndOwner
, hmenu
);
1404 MENU_SelectNextItem( hwndOwner
, hmenu
);
1405 if (*hmenuCurrent
!= hmenu
)
1407 /* A popup menu was displayed -> display the next one */
1408 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, TRUE
);
1411 else if (*hmenuCurrent
!= hmenu
) /* Hide last level popup */
1414 hmenuprev
= hmenutmp
= hmenu
;
1415 while (hmenutmp
!= *hmenuCurrent
)
1417 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
1418 if (hmenutmp
!= *hmenuCurrent
) hmenuprev
= hmenutmp
;
1420 MENU_HideSubPopups( hwndOwner
, hmenuprev
);
1421 *hmenuCurrent
= hmenuprev
;
1426 /***********************************************************************
1429 * Menu tracking code.
1430 * If 'x' and 'y' are not 0, we simulate a button-down event at (x,y)
1431 * before beginning tracking. This is to help menu-bar tracking.
1433 static BOOL
MENU_TrackMenu( HMENU hmenu
, UINT wFlags
, int x
, int y
,
1434 HWND hwnd
, LPRECT lprect
)
1439 HMENU hmenuCurrent
= hmenu
;
1440 BOOL fClosed
= FALSE
, fRemove
;
1443 fEndMenuCalled
= FALSE
;
1444 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
1447 POINT pt
= { x
, y
};
1448 MENU_ButtonDown( hwnd
, hmenu
, &hmenuCurrent
, pt
);
1451 hMsg
= USER_HEAP_ALLOC( sizeof(MSG
) );
1452 msg
= (MSG
*)USER_HEAP_LIN_ADDR( hMsg
);
1455 if (!MSG_InternalGetMessage( (SEGPTR
)USER_HEAP_SEG_ADDR(hMsg
), 0,
1456 hwnd
, MSGF_MENU
, 0, TRUE
))
1460 if ((msg
->message
>= WM_MOUSEFIRST
) && (msg
->message
<= WM_MOUSELAST
))
1462 /* Find the sub-popup for this mouse event (if any) */
1463 HMENU hsubmenu
= MENU_FindMenuByCoords( hmenu
, msg
->pt
);
1465 switch(msg
->message
)
1467 case WM_RBUTTONDOWN
:
1468 case WM_NCRBUTTONDOWN
:
1469 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
1471 case WM_LBUTTONDOWN
:
1472 case WM_NCLBUTTONDOWN
:
1473 fClosed
= !MENU_ButtonDown( hwnd
, hsubmenu
,
1474 &hmenuCurrent
, msg
->pt
);
1478 case WM_NCRBUTTONUP
:
1479 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
1482 case WM_NCLBUTTONUP
:
1483 /* If outside all menus but inside lprect, ignore it */
1484 if (!hsubmenu
&& lprect
&& PtInRect( lprect
, msg
->pt
)) break;
1485 fClosed
= !MENU_ButtonUp( hwnd
, hsubmenu
,
1486 &hmenuCurrent
, msg
->pt
);
1487 fRemove
= TRUE
; /* Remove event even if outside menu */
1491 case WM_NCMOUSEMOVE
:
1492 if ((msg
->wParam
& MK_LBUTTON
) ||
1493 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
->wParam
& MK_RBUTTON
)))
1495 fClosed
= !MENU_MouseMove( hwnd
, hsubmenu
,
1496 &hmenuCurrent
, msg
->pt
);
1501 else if ((msg
->message
>= WM_KEYFIRST
) && (msg
->message
<= WM_KEYLAST
))
1503 fRemove
= TRUE
; /* Keyboard messages are always removed */
1504 switch(msg
->message
)
1510 MENU_SelectItem( hwnd
, hmenuCurrent
, NO_SELECTED_ITEM
);
1511 MENU_SelectNextItem( hwnd
, hmenuCurrent
);
1515 MENU_SelectItem( hwnd
, hmenuCurrent
, NO_SELECTED_ITEM
);
1516 MENU_SelectPrevItem( hwnd
, hmenuCurrent
);
1520 MENU_SelectPrevItem( hwnd
, hmenuCurrent
);
1524 /* If on menu bar, pull-down the menu */
1525 if (!(menu
->wFlags
& MF_POPUP
) && (hmenuCurrent
== hmenu
))
1526 hmenuCurrent
= MENU_ShowSubPopup( hwnd
, hmenu
, TRUE
);
1528 MENU_SelectNextItem( hwnd
, hmenuCurrent
);
1532 MENU_KeyLeft( hwnd
, hmenu
, &hmenuCurrent
);
1536 MENU_KeyRight( hwnd
, hmenu
, &hmenuCurrent
);
1541 fClosed
= !MENU_ExecFocusedItem( hwnd
, hmenuCurrent
,
1552 break; /* WM_KEYDOWN */
1562 break; /* WM_SYSKEYDOWN */
1566 /* Hack to avoid control chars. */
1567 /* We will find a better way real soon... */
1568 if ((msg
->wParam
<= 32) || (msg
->wParam
>= 127)) break;
1569 pos
= MENU_FindItemByKey( hwnd
, hmenuCurrent
, msg
->wParam
);
1570 if (pos
== (UINT
)-2) fClosed
= TRUE
;
1571 else if (pos
== (UINT
)-1) MessageBeep(0);
1574 MENU_SelectItem( hwnd
, hmenuCurrent
, pos
);
1575 fClosed
= !MENU_ExecFocusedItem( hwnd
, hmenuCurrent
,
1580 break; /* WM_CHAR */
1581 } /* switch(msg->message) */
1585 DispatchMessage( msg
);
1587 if (fEndMenuCalled
) fClosed
= TRUE
;
1588 if (!fClosed
) fRemove
= TRUE
;
1590 if (fRemove
) /* Remove the message from the queue */
1591 PeekMessage( msg
, 0, msg
->message
, msg
->message
, PM_REMOVE
);
1593 USER_HEAP_FREE( hMsg
);
1595 MENU_HideSubPopups( hwnd
, hmenu
);
1596 if (menu
->wFlags
& MF_POPUP
) ShowWindow( menu
->hWnd
, SW_HIDE
);
1597 MENU_SelectItem( hwnd
, hmenu
, NO_SELECTED_ITEM
);
1598 SendMessage( hwnd
, WM_MENUSELECT
, 0, MAKELONG( 0xffff, 0 ) );
1599 fEndMenuCalled
= FALSE
;
1604 /***********************************************************************
1605 * MENU_TrackMouseMenuBar
1607 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
1609 void MENU_TrackMouseMenuBar( HWND hwnd
, POINT pt
)
1611 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1613 SendMessage( hwnd
, WM_ENTERMENULOOP
, 0, 0 );
1614 SendMessage( hwnd
, WM_INITMENU
, wndPtr
->wIDmenu
, 0 );
1615 MENU_TrackMenu( (HMENU
)wndPtr
->wIDmenu
, TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
1616 pt
.x
, pt
.y
, hwnd
, NULL
);
1617 SendMessage( hwnd
, WM_EXITMENULOOP
, 0, 0 );
1622 /***********************************************************************
1623 * MENU_TrackKbdMenuBar
1625 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
1627 void MENU_TrackKbdMenuBar( HWND hwnd
, UINT wParam
)
1629 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1630 if (!wndPtr
->wIDmenu
) return;
1632 SendMessage( hwnd
, WM_ENTERMENULOOP
, 0, 0 );
1633 SendMessage( hwnd
, WM_INITMENU
, wndPtr
->wIDmenu
, 0 );
1634 /* Select first selectable item */
1635 MENU_SelectItem( hwnd
, (HMENU
)wndPtr
->wIDmenu
, NO_SELECTED_ITEM
);
1636 MENU_SelectNextItem( hwnd
, (HMENU
)wndPtr
->wIDmenu
);
1637 MENU_TrackMenu( (HMENU
)wndPtr
->wIDmenu
, TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
1639 SendMessage( hwnd
, WM_EXITMENULOOP
, 0, 0 );
1644 /**********************************************************************
1645 * TrackPopupMenu (USER.416)
1647 BOOL
TrackPopupMenu( HMENU hMenu
, UINT wFlags
, short x
, short y
,
1648 short nReserved
, HWND hWnd
, LPRECT lpRect
)
1652 if (!MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
))
1655 ret
= MENU_TrackMenu( hMenu
, wFlags
, 0, 0, hWnd
, lpRect
);
1661 /***********************************************************************
1664 LRESULT
PopupMenuWndProc(HWND hwnd
,UINT message
,WPARAM wParam
,LPARAM lParam
)
1670 CREATESTRUCT
*createStruct
= (CREATESTRUCT
*)PTR_SEG_TO_LIN(lParam
);
1672 HMENU hmenu
= (HMENU
) (createStruct
->lpCreateParams
);
1673 SetWindowLong( hwnd
, 0, (LONG
)hmenu
);
1675 HMENU hmenu
= (HMENU
) ((int)createStruct
->lpCreateParams
& 0xffff);
1676 SetWindowWord( hwnd
, 0, hmenu
);
1681 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1682 return MA_NOACTIVATE
;
1687 BeginPaint( hwnd
, &ps
);
1688 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
1690 (HMENU
)GetWindowLong( hwnd
, 0 )
1692 (HMENU
)GetWindowWord( hwnd
, 0 )
1695 EndPaint( hwnd
, &ps
);
1700 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
1706 /***********************************************************************
1707 * MENU_GetMenuBarHeight
1709 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
1711 UINT
MENU_GetMenuBarHeight( HWND hwnd
, UINT menubarWidth
, int orgX
, int orgY
)
1718 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
1719 if (!(lppop
= (LPPOPUPMENU
)USER_HEAP_LIN_ADDR((HMENU
)wndPtr
->wIDmenu
)))
1721 hdc
= GetDC( hwnd
);
1722 SetRect( &rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+SYSMETRICS_CYMENU
);
1723 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
1724 ReleaseDC( hwnd
, hdc
);
1725 return lppop
->Height
;
1729 /*******************************************************************
1730 * ChangeMenu (USER.153)
1732 BOOL
ChangeMenu( HMENU hMenu
, UINT pos
, SEGPTR data
, UINT id
, UINT flags
)
1734 dprintf_menu( stddeb
,"ChangeMenu: menu="NPFMT
" pos=%d data=%08lx id=%04x flags=%04x\n",
1735 hMenu
, pos
, data
, id
, flags
);
1736 if (flags
& MF_APPEND
)
1738 return AppendMenu( hMenu
, flags
& ~MF_APPEND
, id
, data
);
1740 if (flags
& MF_DELETE
)
1742 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
1743 /* for MF_DELETE. We should check the parameters for all others */
1744 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
1745 return DeleteMenu( hMenu
, pos
, flags
& ~MF_DELETE
);
1747 if (flags
& MF_CHANGE
)
1749 return ModifyMenu( hMenu
, pos
, flags
& ~MF_CHANGE
, id
, data
);
1751 if (flags
& MF_REMOVE
)
1753 return RemoveMenu( hMenu
, flags
& MF_BYPOSITION
? pos
: id
,
1754 flags
& ~MF_REMOVE
);
1756 /* Default: MF_INSERT */
1757 return InsertMenu( hMenu
, pos
, flags
, id
, data
);
1761 /*******************************************************************
1762 * CheckMenuItem (USER.154)
1764 INT
CheckMenuItem( HMENU hMenu
, UINT id
, UINT flags
)
1769 dprintf_menu( stddeb
,"CheckMenuItem: "NPFMT
" %04x %04x\n",
1771 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
1772 ret
= item
->item_flags
& MF_CHECKED
;
1773 if (flags
& MF_CHECKED
) item
->item_flags
|= MF_CHECKED
;
1774 else item
->item_flags
&= ~MF_CHECKED
;
1779 /**********************************************************************
1780 * EnableMenuItem [USER.155]
1782 BOOL
EnableMenuItem(HMENU hMenu
, UINT wItemID
, UINT wFlags
)
1785 dprintf_menu(stddeb
,"EnableMenuItem ("NPFMT
", %04X, %04X) !\n",
1786 hMenu
, wItemID
, wFlags
);
1787 if (!(lpitem
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return FALSE
;
1789 /* We can't have MF_GRAYED and MF_DISABLED together */
1790 if (wFlags
& MF_GRAYED
)
1792 lpitem
->item_flags
= (lpitem
->item_flags
& ~MF_DISABLED
) | MF_GRAYED
;
1794 else if (wFlags
& MF_DISABLED
)
1796 lpitem
->item_flags
= (lpitem
->item_flags
& ~MF_GRAYED
) | MF_DISABLED
;
1798 else /* MF_ENABLED */
1800 lpitem
->item_flags
&= ~(MF_GRAYED
| MF_DISABLED
);
1806 /*******************************************************************
1807 * GetMenuString (USER.161)
1809 int GetMenuString( HMENU hMenu
, UINT wItemID
,
1810 LPSTR str
, short nMaxSiz
, UINT wFlags
)
1814 dprintf_menu( stddeb
, "GetMenuString: menu="NPFMT
" item=%04x ptr=%p len=%d flags=%04x\n",
1815 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
1816 if (!str
|| !nMaxSiz
) return 0;
1818 if (!(lpitem
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
1819 if (!IS_STRING_ITEM(lpitem
->item_flags
)) return 0;
1820 lstrcpyn( str
, (char *)USER_HEAP_LIN_ADDR(lpitem
->hText
), nMaxSiz
);
1821 dprintf_menu( stddeb
, "GetMenuString: returning '%s'\n", str
);
1826 /**********************************************************************
1827 * HiliteMenuItem [USER.162]
1829 BOOL
HiliteMenuItem(HWND hWnd
, HMENU hMenu
, UINT wItemID
, UINT wHilite
)
1833 dprintf_menu(stddeb
,"HiliteMenuItem("NPFMT
", "NPFMT
", %04X, %04X);\n",
1834 hWnd
, hMenu
, wItemID
, wHilite
);
1835 if (!(lpitem
= MENU_FindItem( &hMenu
, &wItemID
, wHilite
))) return FALSE
;
1836 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
1837 if (menu
->FocusedItem
== wItemID
) return TRUE
;
1838 MENU_HideSubPopups( hWnd
, hMenu
);
1839 MENU_SelectItem( hWnd
, hMenu
, wItemID
);
1844 /**********************************************************************
1845 * GetMenuState [USER.250]
1847 UINT
GetMenuState(HMENU hMenu
, UINT wItemID
, UINT wFlags
)
1850 dprintf_menu(stddeb
,"GetMenuState("NPFMT
", %04X, %04X);\n",
1851 hMenu
, wItemID
, wFlags
);
1852 if (!(lpitem
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
1853 if (lpitem
->item_flags
& MF_POPUP
)
1855 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( (HMENU
)lpitem
->item_id
);
1856 if (!menu
) return -1;
1857 else return (menu
->nItems
<< 8) | (menu
->wFlags
& 0xff);
1859 else return lpitem
->item_flags
;
1863 /**********************************************************************
1864 * GetMenuItemCount [USER.263]
1866 INT
GetMenuItemCount(HMENU hMenu
)
1869 dprintf_menu(stddeb
,"GetMenuItemCount("NPFMT
");\n", hMenu
);
1870 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
1871 if (menu
== NULL
) return (UINT
)-1;
1872 dprintf_menu(stddeb
,"GetMenuItemCount("NPFMT
") return %d \n",
1873 hMenu
, menu
->nItems
);
1874 return menu
->nItems
;
1878 /**********************************************************************
1879 * GetMenuItemID [USER.264]
1881 UINT
GetMenuItemID(HMENU hMenu
, int nPos
)
1886 dprintf_menu(stddeb
,"GetMenuItemID("NPFMT
", %d);\n", hMenu
, nPos
);
1887 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
1888 if ((nPos
< 0) || (nPos
>= menu
->nItems
)) return -1;
1889 item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
1890 if (item
[nPos
].item_flags
& MF_POPUP
) return -1;
1891 return item
[nPos
].item_id
;
1895 /*******************************************************************
1896 * InsertMenu (USER.410)
1898 BOOL
InsertMenu( HMENU hMenu
, UINT pos
, UINT flags
, UINT id
, SEGPTR data
)
1902 if (IS_STRING_ITEM(flags
) && data
)
1903 dprintf_menu( stddeb
, "InsertMenu: "NPFMT
" %d %04x %04x '%s'\n",
1904 hMenu
, pos
, flags
, id
, (char *)PTR_SEG_TO_LIN(data
) );
1905 else dprintf_menu( stddeb
, "InsertMenu: "NPFMT
" %d %04x %04x %08lx\n",
1906 hMenu
, pos
, flags
, id
, (DWORD
)data
);
1908 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
1910 if (!(MENU_SetItemData( item
, flags
, id
, data
)))
1912 RemoveMenu( hMenu
, pos
, flags
);
1916 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
1917 ((POPUPMENU
*)USER_HEAP_LIN_ADDR((HMENU
)id
))->wFlags
|= MF_POPUP
;
1919 item
->hCheckBit
= hStdCheck
;
1920 item
->hUnCheckBit
= 0;
1925 /*******************************************************************
1926 * AppendMenu (USER.411)
1928 BOOL
AppendMenu( HMENU hMenu
, UINT flags
, UINT id
, SEGPTR data
)
1930 return InsertMenu( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
1934 /**********************************************************************
1935 * RemoveMenu [USER.412]
1937 BOOL
RemoveMenu(HMENU hMenu
, UINT nPos
, UINT wFlags
)
1941 dprintf_menu(stddeb
,"RemoveMenu ("NPFMT
", %04X, %04X) !\n",
1942 hMenu
, nPos
, wFlags
);
1943 if (!(lpitem
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
1944 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
1948 if (IS_STRING_ITEM(lpitem
->item_flags
) && lpitem
->hText
)
1949 USER_HEAP_FREE(lpitem
->hText
);
1950 if (--menu
->nItems
== 0)
1952 USER_HEAP_FREE( menu
->hItems
);
1957 while(nPos
< menu
->nItems
)
1959 *lpitem
= *(lpitem
+1);
1963 menu
->hItems
= USER_HEAP_REALLOC( menu
->hItems
,
1964 menu
->nItems
* sizeof(MENUITEM
) );
1970 /**********************************************************************
1971 * DeleteMenu [USER.413]
1973 BOOL
DeleteMenu(HMENU hMenu
, UINT nPos
, UINT wFlags
)
1975 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
1976 if (!item
) return FALSE
;
1977 if (item
->item_flags
& MF_POPUP
) DestroyMenu( (HMENU
)item
->item_id
);
1978 /* nPos is now the position of the item */
1979 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
1984 /*******************************************************************
1985 * ModifyMenu (USER.414)
1987 BOOL
ModifyMenu( HMENU hMenu
, UINT pos
, UINT flags
, UINT id
, SEGPTR data
)
1991 if (IS_STRING_ITEM(flags
))
1993 dprintf_menu( stddeb
, "ModifyMenu: "NPFMT
" %d %04x %04x '%s'\n",
1994 hMenu
, pos
, flags
, id
,
1995 data
? (char *)PTR_SEG_TO_LIN(data
) : "#NULL#");
1996 if (!data
) return FALSE
;
1999 dprintf_menu( stddeb
, "ModifyMenu: "NPFMT
" %d %04x %04x %08lx\n",
2000 hMenu
, pos
, flags
, id
, (DWORD
)data
);
2001 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
2003 return MENU_SetItemData( item
, flags
, id
, data
);
2007 /**********************************************************************
2008 * CreatePopupMenu [USER.415]
2010 HMENU
CreatePopupMenu()
2015 if (!(hmenu
= CreateMenu())) return 0;
2016 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
2017 menu
->wFlags
|= MF_POPUP
;
2022 /**********************************************************************
2023 * GetMenuCheckMarkDimensions [USER.417]
2025 DWORD
GetMenuCheckMarkDimensions()
2027 return MAKELONG( check_bitmap_width
, check_bitmap_height
);
2031 /**********************************************************************
2032 * SetMenuItemBitmaps [USER.418]
2034 BOOL
SetMenuItemBitmaps(HMENU hMenu
, UINT nPos
, UINT wFlags
,
2035 HBITMAP hNewUnCheck
, HBITMAP hNewCheck
)
2038 dprintf_menu(stddeb
,"SetMenuItemBitmaps ("NPFMT
", %04X, %04X, "NPFMT
", %08lX) !\n",
2039 hMenu
, nPos
, wFlags
, hNewCheck
, (DWORD
)hNewUnCheck
);
2040 if (!(lpitem
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
2042 if (!hNewCheck
&& !hNewUnCheck
)
2044 /* If both are NULL, restore default bitmaps */
2045 lpitem
->hCheckBit
= hStdCheck
;
2046 lpitem
->hUnCheckBit
= 0;
2047 lpitem
->item_flags
&= ~MF_USECHECKBITMAPS
;
2049 else /* Install new bitmaps */
2051 lpitem
->hCheckBit
= hNewCheck
;
2052 lpitem
->hUnCheckBit
= hNewUnCheck
;
2053 lpitem
->item_flags
|= MF_USECHECKBITMAPS
;
2059 /**********************************************************************
2060 * CreateMenu [USER.151]
2066 dprintf_menu(stddeb
,"CreateMenu !\n");
2067 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) )))
2069 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2072 menu
->wMagic
= MENU_MAGIC
;
2079 menu
->FocusedItem
= NO_SELECTED_ITEM
;
2080 dprintf_menu(stddeb
,"CreateMenu // return "NPFMT
"\n", hMenu
);
2085 /**********************************************************************
2086 * DestroyMenu [USER.152]
2088 BOOL
DestroyMenu(HMENU hMenu
)
2091 dprintf_menu(stddeb
,"DestroyMenu ("NPFMT
") !\n", hMenu
);
2092 if (hMenu
== 0) return FALSE
;
2093 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2094 if (!lppop
|| (lppop
->wMagic
!= MENU_MAGIC
)) return FALSE
;
2095 lppop
->wMagic
= 0; /* Mark it as destroyed */
2096 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
)
2097 DestroyWindow( lppop
->hWnd
);
2102 MENUITEM
*item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( lppop
->hItems
);
2103 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
2105 if (item
->item_flags
& MF_POPUP
)
2106 DestroyMenu( (HMENU
)item
->item_id
);
2107 if (IS_STRING_ITEM(item
->item_flags
) && item
->hText
)
2108 USER_HEAP_FREE(item
->hText
);
2110 USER_HEAP_FREE( lppop
->hItems
);
2112 USER_HEAP_FREE( hMenu
);
2113 dprintf_menu(stddeb
,"DestroyMenu ("NPFMT
") // End !\n", hMenu
);
2117 /**********************************************************************
2118 * GetSystemMenu [USER.156]
2120 HMENU
GetSystemMenu(HWND hWnd
, BOOL bRevert
)
2122 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
2123 if (!wndPtr
) return 0;
2125 if (!bRevert
) return wndPtr
->hSysMenu
;
2126 if (wndPtr
->hSysMenu
) DestroyMenu(wndPtr
->hSysMenu
);
2127 wndPtr
->hSysMenu
= MENU_CopySysMenu();
2128 return wndPtr
->hSysMenu
;
2132 /*******************************************************************
2133 * SetSystemMenu (USER.280)
2135 BOOL
SetSystemMenu( HWND hwnd
, HMENU hMenu
)
2139 if (!(wndPtr
= WIN_FindWndPtr(hwnd
))) return FALSE
;
2140 if (wndPtr
->hSysMenu
) DestroyMenu( wndPtr
->hSysMenu
);
2141 wndPtr
->hSysMenu
= hMenu
;
2146 /**********************************************************************
2147 * GetMenu [USER.157]
2149 HMENU
GetMenu(HWND hWnd
)
2151 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
2152 if (wndPtr
== NULL
) return 0;
2153 return (HMENU
)wndPtr
->wIDmenu
;
2157 /**********************************************************************
2158 * SetMenu [USER.158]
2160 BOOL
SetMenu(HWND hWnd
, HMENU hMenu
)
2163 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
2164 if (wndPtr
== NULL
) {
2165 fprintf(stderr
,"SetMenu("NPFMT
", "NPFMT
") // Bad window handle !\n",
2169 dprintf_menu(stddeb
,"SetMenu("NPFMT
", "NPFMT
");\n", hWnd
, hMenu
);
2170 if (GetCapture() == hWnd
) ReleaseCapture();
2171 wndPtr
->wIDmenu
= (UINT
)hMenu
;
2174 lpmenu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2175 if (lpmenu
== NULL
) {
2176 fprintf(stderr
,"SetMenu("NPFMT
", "NPFMT
") // Bad menu handle !\n",
2180 lpmenu
->hWnd
= hWnd
;
2181 lpmenu
->wFlags
&= ~MF_POPUP
; /* Can't be a popup */
2182 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
2184 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
2185 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
2191 /**********************************************************************
2192 * GetSubMenu [USER.159]
2194 HMENU
GetSubMenu(HMENU hMenu
, short nPos
)
2198 dprintf_menu(stddeb
,"GetSubMenu ("NPFMT
", %04X) !\n", hMenu
, nPos
);
2199 if (!(lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return 0;
2200 if ((UINT
)nPos
>= lppop
->nItems
) return 0;
2201 lpitem
= (MENUITEM
*) USER_HEAP_LIN_ADDR( lppop
->hItems
);
2202 if (!(lpitem
[nPos
].item_flags
& MF_POPUP
)) return 0;
2203 return (HMENU
)lpitem
[nPos
].item_id
;
2207 /**********************************************************************
2208 * DrawMenuBar [USER.160]
2210 void DrawMenuBar(HWND hWnd
)
2214 dprintf_menu(stddeb
,"DrawMenuBar ("NPFMT
")\n", hWnd
);
2215 wndPtr
= WIN_FindWndPtr(hWnd
);
2216 if (wndPtr
!= NULL
&& (wndPtr
->dwStyle
& WS_CHILD
) == 0 &&
2217 wndPtr
->wIDmenu
!= 0) {
2218 dprintf_menu(stddeb
,"DrawMenuBar wIDmenu=%04X \n",
2220 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR((HMENU
)wndPtr
->wIDmenu
);
2221 if (lppop
== NULL
) return;
2223 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
2224 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
2225 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
2230 /***********************************************************************
2231 * EndMenu (USER.187)
2235 /* FIXME: this won't work when we have multiple tasks... */
2236 fEndMenuCalled
= TRUE
;
2240 /***********************************************************************
2241 * LookupMenuHandle (USER.217)
2243 HMENU
LookupMenuHandle( HMENU hmenu
, INT id
)
2245 if (!MENU_FindItem( &hmenu
, &id
, MF_BYCOMMAND
)) return 0;
2250 /**********************************************************************
2251 * LoadMenu (USER.150)
2253 HMENU
LoadMenu( HINSTANCE instance
, SEGPTR name
)
2261 char *str
= (char *)PTR_SEG_TO_LIN( name
);
2262 dprintf_menu( stddeb
, "LoadMenu("NPFMT
",'%s')\n", instance
, str
);
2263 if (str
[0] == '#') name
= (SEGPTR
)atoi( str
+ 1 );
2266 dprintf_resource(stddeb
,"LoadMenu("NPFMT
",%04x)\n",instance
,LOWORD(name
));
2268 if (!name
) return 0;
2270 if (!(hRsrc
= FindResource( instance
, name
, RT_MENU
))) {
2271 /* check for Win32 module */
2272 instance
= GetExePtr( instance
);
2273 if(((NE_MODULE
*)GlobalLock(instance
))->magic
== PE_SIGNATURE
)
2274 return WIN32_LoadMenuA(instance
,PTR_SEG_TO_LIN(name
));
2277 if (!(handle
= LoadResource( instance
, hRsrc
))) return 0;
2278 hMenu
= LoadMenuIndirect( WIN16_LockResource(handle
) );
2279 FreeResource( handle
);
2284 /**********************************************************************
2285 * LoadMenuIndirect (USER.220)
2287 HMENU
LoadMenuIndirect( SEGPTR
template )
2291 dprintf_menu(stddeb
,"LoadMenuIndirect: %08lx\n", (DWORD
)template );
2292 if (!(hMenu
= CreateMenu())) return (HMENU
)0;
2293 template += sizeof(MENU_HEADER
);
2294 if (!MENU_ParseResource( template, hMenu
))
2296 DestroyMenu( hMenu
);
2303 /**********************************************************************
2306 BOOL
IsMenu( HMENU hmenu
)
2309 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
2310 return (menu
->wMagic
== MENU_MAGIC
);