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"
27 #include "nonclient.h"
35 /* Menu item structure */
38 UINT32 item_flags
; /* Item flags */
39 UINT32 item_id
; /* Item or popup id */
40 RECT32 rect
; /* Item area (relative to menu window) */
41 UINT32 xTab
; /* X position of text after Tab */
42 HBITMAP32 hCheckBit
; /* Bitmap for checked item */
43 HBITMAP32 hUnCheckBit
; /* Bitmap for unchecked item */
44 LPSTR text
; /* Item text or bitmap handle */
47 /* Popup menu structure */
50 WORD wFlags
; /* Menu flags (MF_POPUP, MF_SYSMENU) */
51 WORD wMagic
; /* Magic number */
52 HQUEUE16 hTaskQ
; /* Task queue for this menu */
53 WORD Width
; /* Width of the whole menu */
54 WORD Height
; /* Height of the whole menu */
55 WORD nItems
; /* Number of items in the menu */
56 HWND32 hWnd
; /* Window containing the menu */
57 MENUITEM
*items
; /* Array of menu items */
58 UINT32 FocusedItem
; /* Currently focused item */
59 } POPUPMENU
, *LPPOPUPMENU
;
61 #define MENU_MAGIC 0x554d /* 'MU' */
66 /* Dimension of the menu bitmaps */
67 static WORD check_bitmap_width
= 0, check_bitmap_height
= 0;
68 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
70 /* Flag set by EndMenu() to force an exit from menu tracking */
71 static BOOL32 fEndMenuCalled
= FALSE
;
73 /* Space between 2 menu bar items */
74 #define MENU_BAR_ITEMS_SPACE 16
76 /* Minimum width of a tab character */
77 #define MENU_TAB_SPACE 8
79 /* Height of a separator item */
80 #define SEPARATOR_HEIGHT 5
82 /* Values for menu->FocusedItem */
83 /* (other values give the position of the focused item) */
84 #define NO_SELECTED_ITEM 0xffff
85 #define SYSMENU_SELECTED 0xfffe /* Only valid on menu-bars */
87 #define IS_STRING_ITEM(flags) \
88 (!((flags) & (MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)))
90 static HBITMAP32 hStdCheck
= 0;
91 static HBITMAP32 hStdMnArrow
= 0;
92 static HMENU32 MENU_DefSysMenu
= 0; /* Default system menu */
95 /* we _can_ use global popup window because there's no way 2 menues can
96 * be tracked at the same time.
99 static WND
* pTopPWnd
= 0;
100 static UINT32 uSubPWndLevel
= 0;
103 /**********************************************************************
106 * Load a copy of the system menu.
108 static HMENU32
MENU_CopySysMenu(void)
113 if (!(hMenu
= LoadMenuIndirect32A( SYSRES_GetResPtr(SYSRES_MENU_SYSMENU
))))
115 dprintf_menu(stddeb
,"No SYSMENU\n");
118 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
119 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
120 dprintf_menu(stddeb
,"CopySysMenu hMenu=%04x !\n", hMenu
);
125 /***********************************************************************
128 * Menus initialisation.
136 if (!(hStdCheck
= LoadBitmap32A( 0, (LPSTR
)MAKEINTRESOURCE(OBM_CHECK
) )))
138 GetObject32A( hStdCheck
, sizeof(bm
), &bm
);
139 check_bitmap_width
= bm
.bmWidth
;
140 check_bitmap_height
= bm
.bmHeight
;
141 if (!(hStdMnArrow
= LoadBitmap32A(0,(LPSTR
)MAKEINTRESOURCE(OBM_MNARROW
))))
143 GetObject32A( hStdMnArrow
, sizeof(bm
), &bm
);
144 arrow_bitmap_width
= bm
.bmWidth
;
145 arrow_bitmap_height
= bm
.bmHeight
;
147 if (!(MENU_DefSysMenu
= MENU_CopySysMenu()))
149 fprintf( stderr
, "Unable to create default system menu\n" );
156 /***********************************************************************
159 * Return the default system menu.
161 HMENU32
MENU_GetDefSysMenu(void)
163 return MENU_DefSysMenu
;
167 /***********************************************************************
170 * Check whether the window owning the menu bar has a system menu.
172 static BOOL32
MENU_HasSysMenu( POPUPMENU
*menu
)
176 if (menu
->wFlags
& MF_POPUP
) return FALSE
;
177 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return FALSE
;
178 return (wndPtr
->dwStyle
& WS_SYSMENU
) != 0;
182 /***********************************************************************
185 * Check whether the point (in screen coords) is in the system menu
186 * of the window owning the given menu.
188 static BOOL32
MENU_IsInSysMenu( POPUPMENU
*menu
, POINT32 pt
)
192 if (menu
->wFlags
& MF_POPUP
) return FALSE
;
193 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return FALSE
;
194 if (!(wndPtr
->dwStyle
& WS_SYSMENU
)) return FALSE
;
195 if ((pt
.x
< wndPtr
->rectClient
.left
) ||
196 (pt
.x
>= wndPtr
->rectClient
.left
+SYSMETRICS_CXSIZE
+SYSMETRICS_CXBORDER
))
198 if ((pt
.y
>= wndPtr
->rectClient
.top
- menu
->Height
) ||
199 (pt
.y
< wndPtr
->rectClient
.top
- menu
->Height
-
200 SYSMETRICS_CYSIZE
- SYSMETRICS_CYBORDER
)) return FALSE
;
205 /***********************************************************************
206 * MENU_InitSysMenuPopup
208 * Grey the appropriate items in System menu.
210 void MENU_InitSysMenuPopup( HMENU32 hmenu
, DWORD style
, DWORD clsStyle
)
214 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
215 EnableMenuItem32( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
216 gray
= ((style
& WS_MAXIMIZE
) != 0);
217 EnableMenuItem32( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
218 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
219 EnableMenuItem32( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
220 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
221 EnableMenuItem32( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
222 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
223 EnableMenuItem32( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
224 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
225 EnableMenuItem32( hmenu
, SC_CLOSE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
229 /***********************************************************************
232 * Find a menu item. Return a pointer on the item, and modifies *hmenu
233 * in case the item was in a sub-menu.
235 static MENUITEM
*MENU_FindItem( HMENU32
*hmenu
, UINT32
*nPos
, UINT32 wFlags
)
240 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(*hmenu
))) return NULL
;
241 if (wFlags
& MF_BYPOSITION
)
243 if (*nPos
>= menu
->nItems
) return NULL
;
244 return &menu
->items
[*nPos
];
248 MENUITEM
*item
= menu
->items
;
249 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
251 if (item
->item_id
== *nPos
)
256 else if (item
->item_flags
& MF_POPUP
)
258 HMENU32 hsubmenu
= (HMENU32
)item
->item_id
;
259 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
272 /***********************************************************************
273 * MENU_FindItemByCoords
275 * Find the item at the specified coordinates (screen coords).
277 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
, INT32 x
, INT32 y
,
284 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return NULL
;
285 x
-= wndPtr
->rectWindow
.left
;
286 y
-= wndPtr
->rectWindow
.top
;
288 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
290 if ((x
>= item
->rect
.left
) && (x
< item
->rect
.right
) &&
291 (y
>= item
->rect
.top
) && (y
< item
->rect
.bottom
))
301 /***********************************************************************
304 * Find the menu item selected by a key press.
305 * Return item id, -1 if none, -2 if we should close the menu.
307 static UINT32
MENU_FindItemByKey( HWND32 hwndOwner
, HMENU32 hmenu
,
308 UINT32 key
, BOOL32 forceMenuChar
)
310 dprintf_menu(stddeb
,"\tlooking for '%c' in [%04x]\n", (char)key
, (UINT16
)hmenu
);
312 if (!IsMenu32( hmenu
)) hmenu
= WIN_FindWndPtr(hwndOwner
)->hSysMenu
;
316 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
317 MENUITEM
*item
= menu
->items
;
325 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
327 if (IS_STRING_ITEM(item
->item_flags
))
329 char *p
= strchr( item
->text
, '&' );
330 if (p
&& (p
[1] != '&') && (toupper(p
[1]) == key
)) return i
;
334 menuchar
= SendMessage32A( hwndOwner
, WM_MENUCHAR
,
335 MAKEWPARAM( key
, menu
->wFlags
), hmenu
);
336 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
337 if (HIWORD(menuchar
) == 1) return (UINT32
)(-2);
343 /***********************************************************************
346 * Calculate the size of the menu item and store it in lpitem->rect.
348 static void MENU_CalcItemSize( HDC32 hdc
, MENUITEM
*lpitem
, HWND32 hwndOwner
,
349 INT32 orgX
, INT32 orgY
, BOOL32 menuBar
)
354 SetRect32( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
356 if (lpitem
->item_flags
& MF_OWNERDRAW
)
358 MEASUREITEMSTRUCT32 mis
;
359 mis
.CtlType
= ODT_MENU
;
360 mis
.itemID
= lpitem
->item_id
;
361 mis
.itemData
= (DWORD
)lpitem
->text
;
364 SendMessage32A( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
365 lpitem
->rect
.bottom
+= mis
.itemHeight
;
366 lpitem
->rect
.right
+= mis
.itemWidth
;
367 dprintf_menu( stddeb
, "DrawMenuItem: MeasureItem %04x %dx%d!\n",
368 lpitem
->item_id
, mis
.itemWidth
, mis
.itemHeight
);
372 if (lpitem
->item_flags
& MF_SEPARATOR
)
374 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
380 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
381 if (lpitem
->item_flags
& MF_POPUP
)
382 lpitem
->rect
.right
+= arrow_bitmap_width
;
385 if (lpitem
->item_flags
& MF_BITMAP
)
388 if (GetObject32A( (HBITMAP32
)lpitem
->text
, sizeof(bm
), &bm
))
390 lpitem
->rect
.right
+= bm
.bmWidth
;
391 lpitem
->rect
.bottom
+= bm
.bmHeight
;
396 /* If we get here, then it must be a text item */
398 if (IS_STRING_ITEM( lpitem
->item_flags
))
400 dwSize
= GetTextExtent( hdc
, lpitem
->text
, strlen(lpitem
->text
) );
401 lpitem
->rect
.right
+= LOWORD(dwSize
);
402 lpitem
->rect
.bottom
+= MAX( HIWORD(dwSize
), SYSMETRICS_CYMENU
);
405 if (menuBar
) lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
406 else if ((p
= strchr( lpitem
->text
, '\t' )) != NULL
)
408 /* Item contains a tab (only meaningful in popup menus) */
409 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+
410 LOWORD( GetTextExtent( hdc
, lpitem
->text
,
411 (int)(p
- lpitem
->text
) ));
412 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
416 if (strchr( lpitem
->text
, '\b' ))
417 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
418 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
419 - arrow_bitmap_width
;
425 /***********************************************************************
426 * MENU_PopupMenuCalcSize
428 * Calculate the size of a popup menu.
430 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND32 hwndOwner
)
435 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
437 lppop
->Width
= lppop
->Height
= 0;
438 if (lppop
->nItems
== 0) return;
441 while (start
< lppop
->nItems
)
443 lpitem
= &lppop
->items
[start
];
446 maxTab
= maxTabWidth
= 0;
448 /* Parse items until column break or end of menu */
449 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
452 (lpitem
->item_flags
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
453 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
454 if (lpitem
->item_flags
& MF_MENUBARBREAK
) orgX
++;
455 maxX
= MAX( maxX
, lpitem
->rect
.right
);
456 orgY
= lpitem
->rect
.bottom
;
457 if (IS_STRING_ITEM(lpitem
->item_flags
) && lpitem
->xTab
)
459 maxTab
= MAX( maxTab
, lpitem
->xTab
);
460 maxTabWidth
= MAX(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
464 /* Finish the column (set all items to the largest width found) */
465 maxX
= MAX( maxX
, maxTab
+ maxTabWidth
);
466 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
468 lpitem
->rect
.right
= maxX
;
469 if (IS_STRING_ITEM(lpitem
->item_flags
) && lpitem
->xTab
)
470 lpitem
->xTab
= maxTab
;
472 lppop
->Height
= MAX( lppop
->Height
, orgY
);
476 ReleaseDC32( 0, hdc
);
480 /***********************************************************************
481 * MENU_MenuBarCalcSize
483 * Calculate the size of the menu bar.
485 static void MENU_MenuBarCalcSize( HDC32 hdc
, LPRECT32 lprect
,
486 LPPOPUPMENU lppop
, HWND32 hwndOwner
)
489 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
491 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
492 if (lppop
->nItems
== 0) return;
493 dprintf_menu(stddeb
,"MENU_MenuBarCalcSize left=%d top=%d right=%d bottom=%d\n",
494 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
495 lppop
->Width
= lprect
->right
- lprect
->left
;
500 while (start
< lppop
->nItems
)
502 lpitem
= &lppop
->items
[start
];
506 /* Parse items until line break or end of menu */
507 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
509 if ((helpPos
== -1) && (lpitem
->item_flags
& MF_HELP
)) helpPos
= i
;
511 (lpitem
->item_flags
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
512 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
513 if (lpitem
->rect
.right
> lprect
->right
)
515 if (i
!= start
) break;
516 else lpitem
->rect
.right
= lprect
->right
;
518 maxY
= MAX( maxY
, lpitem
->rect
.bottom
);
519 orgX
= lpitem
->rect
.right
;
522 /* Finish the line (set all items to the largest height found) */
523 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
526 lprect
->bottom
= maxY
;
527 lppop
->Height
= lprect
->bottom
- lprect
->top
;
529 /* Flush right all items between the MF_HELP and the last item */
530 /* (if several lines, only move the last line) */
533 lpitem
= &lppop
->items
[lppop
->nItems
-1];
534 orgY
= lpitem
->rect
.top
;
535 orgX
= lprect
->right
;
536 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--)
538 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
539 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
540 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
541 lpitem
->rect
.right
= orgX
;
542 orgX
= lpitem
->rect
.left
;
548 /***********************************************************************
551 * Draw a single menu item.
553 static void MENU_DrawMenuItem( HWND32 hwnd
, HDC32 hdc
, MENUITEM
*lpitem
,
554 UINT32 height
, BOOL32 menuBar
)
558 if (lpitem
->item_flags
& MF_OWNERDRAW
)
560 DRAWITEMSTRUCT32 dis
;
562 dprintf_menu( stddeb
, "DrawMenuItem: Ownerdraw!\n" );
563 dis
.CtlType
= ODT_MENU
;
564 dis
.itemID
= lpitem
->item_id
;
565 dis
.itemData
= (DWORD
)lpitem
->text
;
567 if (lpitem
->item_flags
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
568 if (lpitem
->item_flags
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
;
569 if (lpitem
->item_flags
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
570 dis
.itemAction
= ODA_DRAWENTIRE
| ODA_SELECT
| ODA_FOCUS
;
573 dis
.rcItem
= lpitem
->rect
;
574 SendMessage32A( hwnd
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
578 if (menuBar
&& (lpitem
->item_flags
& MF_SEPARATOR
)) return;
581 /* Draw the background */
583 if (lpitem
->item_flags
& MF_HILITE
)
584 FillRect32( hdc
, &rect
, sysColorObjects
.hbrushHighlight
);
585 else FillRect32( hdc
, &rect
, sysColorObjects
.hbrushMenu
);
586 SetBkMode32( hdc
, TRANSPARENT
);
588 /* Draw the separator bar (if any) */
590 if (!menuBar
&& (lpitem
->item_flags
& MF_MENUBARBREAK
))
592 SelectObject32( hdc
, sysColorObjects
.hpenWindowFrame
);
593 MoveTo( hdc
, rect
.left
, 0 );
594 LineTo32( hdc
, rect
.left
, height
);
596 if (lpitem
->item_flags
& MF_SEPARATOR
)
598 SelectObject32( hdc
, sysColorObjects
.hpenWindowFrame
);
599 MoveTo( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
600 LineTo32( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
606 if (lpitem
->item_flags
& MF_HILITE
)
608 if (lpitem
->item_flags
& MF_GRAYED
)
609 SetTextColor32( hdc
, GetSysColor32( COLOR_GRAYTEXT
) );
611 SetTextColor32( hdc
, GetSysColor32( COLOR_HIGHLIGHTTEXT
) );
612 SetBkColor32( hdc
, GetSysColor32( COLOR_HIGHLIGHT
) );
616 if (lpitem
->item_flags
& MF_GRAYED
)
617 SetTextColor32( hdc
, GetSysColor32( COLOR_GRAYTEXT
) );
619 SetTextColor32( hdc
, GetSysColor32( COLOR_MENUTEXT
) );
620 SetBkColor32( hdc
, GetSysColor32( COLOR_MENU
) );
625 /* Draw the check mark */
627 if (lpitem
->item_flags
& MF_CHECKED
)
629 GRAPH_DrawBitmap(hdc
, lpitem
->hCheckBit
? lpitem
->hCheckBit
:
630 hStdCheck
, rect
.left
,
631 (rect
.top
+rect
.bottom
-check_bitmap_height
) / 2,
632 0, 0, check_bitmap_width
, check_bitmap_height
);
634 else if (lpitem
->hUnCheckBit
!= 0) /* Not checked */
636 GRAPH_DrawBitmap(hdc
, lpitem
->hUnCheckBit
, rect
.left
,
637 (rect
.top
+rect
.bottom
-check_bitmap_height
) / 2,
638 0, 0, check_bitmap_width
, check_bitmap_height
);
641 /* Draw the popup-menu arrow */
643 if (lpitem
->item_flags
& MF_POPUP
)
645 GRAPH_DrawBitmap( hdc
, hStdMnArrow
,
646 rect
.right
-arrow_bitmap_width
-1,
647 (rect
.top
+rect
.bottom
-arrow_bitmap_height
) / 2,
648 0, 0, arrow_bitmap_width
, arrow_bitmap_height
);
651 rect
.left
+= check_bitmap_width
;
652 rect
.right
-= arrow_bitmap_width
;
655 /* Draw the item text or bitmap */
657 if (lpitem
->item_flags
& MF_BITMAP
)
659 GRAPH_DrawBitmap( hdc
, (HBITMAP32
)lpitem
->text
,
660 rect
.left
, rect
.top
, 0, 0,
661 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
);
664 /* No bitmap - process text if present */
665 else if (IS_STRING_ITEM(lpitem
->item_flags
))
671 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
672 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
673 i
= strlen( lpitem
->text
);
677 for (i
= 0; lpitem
->text
[i
]; i
++)
678 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
682 DrawText32A( hdc
, lpitem
->text
, i
, &rect
,
683 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
685 if (lpitem
->text
[i
]) /* There's a tab or flush-right char */
687 if (lpitem
->text
[i
] == '\t')
689 rect
.left
= lpitem
->xTab
;
690 DrawText32A( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
,
691 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
693 else DrawText32A( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
,
694 DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
);
700 /***********************************************************************
703 * Paint a popup menu.
705 static void MENU_DrawPopupMenu( HWND32 hwnd
, HDC32 hdc
, HMENU32 hmenu
)
712 GetClientRect32( hwnd
, &rect
);
713 FillRect32( hdc
, &rect
, sysColorObjects
.hbrushMenu
);
714 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
715 if (!menu
|| !menu
->nItems
) return;
716 for (i
= menu
->nItems
, item
= menu
->items
; i
> 0; i
--, item
++)
717 MENU_DrawMenuItem( hwnd
, hdc
, item
, menu
->Height
, FALSE
);
721 /***********************************************************************
724 * Paint a menu bar. Returns the height of the menu bar.
726 UINT32
MENU_DrawMenuBar( HDC32 hDC
, LPRECT32 lprect
, HWND32 hwnd
,
727 BOOL32 suppress_draw
)
731 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
733 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( (HMENU16
)wndPtr
->wIDmenu
);
734 if (lppop
== NULL
|| lprect
== NULL
) return SYSMETRICS_CYMENU
;
735 dprintf_menu(stddeb
,"MENU_DrawMenuBar(%04x, %p, %p); !\n",
737 if (lppop
->Height
== 0) MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
738 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
739 if (suppress_draw
) return lppop
->Height
;
741 FillRect32(hDC
, lprect
, sysColorObjects
.hbrushMenu
);
742 SelectObject32( hDC
, sysColorObjects
.hpenWindowFrame
);
743 MoveTo( hDC
, lprect
->left
, lprect
->bottom
);
744 LineTo32( hDC
, lprect
->right
, lprect
->bottom
);
746 if (lppop
->nItems
== 0) return SYSMETRICS_CYMENU
;
747 for (i
= 0; i
< lppop
->nItems
; i
++)
749 MENU_DrawMenuItem( hwnd
, hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
);
751 return lppop
->Height
;
755 /***********************************************************************
758 BOOL32
MENU_SwitchTPWndTo( HTASK16 hTask
)
760 /* This is supposed to be called when popup is hidden.
761 * AppExit() calls with hTask == 0, so we get the next to current.
766 if( !pTopPWnd
) return 0;
770 task
= (TDB
*)GlobalLock16( (hTask
= GetCurrentTask()) );
771 if( task
&& task
->hQueue
== pTopPWnd
->hmemTaskQ
)
772 hTask
= TASK_GetNextTask(hTask
);
776 task
= (TDB
*)GlobalLock16(hTask
);
777 if( !task
) return 0;
779 /* if this task got as far as menu tracking it must have a queue */
781 pTopPWnd
->hInstance
= task
->hInstance
;
782 pTopPWnd
->hmemTaskQ
= task
->hQueue
;
786 /***********************************************************************
789 * Display a popup menu.
791 static BOOL32
MENU_ShowPopup( HWND32 hwndOwner
, HMENU32 hmenu
, UINT32 id
,
792 INT32 x
, INT32 y
, INT32 xanchor
, INT32 yanchor
)
796 BOOL32 skip_init
= 0;
797 UINT32 width
, height
;
799 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
800 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
802 menu
->items
[menu
->FocusedItem
].item_flags
&= ~(MF_HILITE
|MF_MOUSESELECT
);
803 menu
->FocusedItem
= NO_SELECTED_ITEM
;
805 SendMessage16( hwndOwner
, WM_INITMENUPOPUP
, (WPARAM16
)hmenu
,
806 MAKELONG( id
, (menu
->wFlags
& MF_SYSMENU
) ? 1 : 0 ));
807 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
809 /* adjust popup menu pos so that it fits within the desktop */
811 width
= menu
->Width
+ 2*SYSMETRICS_CXBORDER
;
812 height
= menu
->Height
+ 2*SYSMETRICS_CYBORDER
;
814 if( x
+ width
> SYSMETRICS_CXSCREEN
)
817 x
-= width
- xanchor
;
818 if( x
+ width
> SYSMETRICS_CXSCREEN
)
819 x
= SYSMETRICS_CXSCREEN
- width
;
824 if( y
+ height
> SYSMETRICS_CYSCREEN
)
827 y
-= height
+ yanchor
;
828 if( y
+ height
> SYSMETRICS_CYSCREEN
)
829 y
= SYSMETRICS_CYSCREEN
- height
;
834 wndPtr
= WIN_FindWndPtr( hwndOwner
);
835 if (!wndPtr
) return FALSE
;
839 pTopPWnd
= WIN_FindWndPtr(CreateWindow32A( POPUPMENU_CLASS_ATOM
, NULL
,
840 WS_POPUP
| WS_BORDER
, x
, y
,
842 hwndOwner
, 0, wndPtr
->hInstance
,
844 if (!pTopPWnd
) return FALSE
;
850 /* create new window for the submenu */
851 HWND32 hWnd
= CreateWindow32A( POPUPMENU_CLASS_ATOM
, NULL
,
852 WS_POPUP
| WS_BORDER
, x
, y
,
854 menu
->hWnd
, 0, wndPtr
->hInstance
,
856 if( !hWnd
) return FALSE
;
863 MENU_SwitchTPWndTo(GetCurrentTask());
864 SendMessage16( pTopPWnd
->hwndSelf
, WM_USER
, (WPARAM16
)hmenu
, 0L);
866 menu
->hWnd
= pTopPWnd
->hwndSelf
;
871 wndPtr
= WIN_FindWndPtr( menu
->hWnd
);
873 SetWindowPos32(menu
->hWnd
, 0, x
, y
, width
, height
,
874 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_NOREDRAW
);
875 /* Display the window */
877 SetWindowPos32( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
878 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
879 UpdateWindow32( menu
->hWnd
);
884 /***********************************************************************
887 static void MENU_SelectItem( HWND32 hwndOwner
, HMENU32 hmenu
, UINT32 wIndex
,
888 BOOL32 sendMenuSelect
)
893 lppop
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
894 if (!lppop
->nItems
) return;
895 if ((wIndex
!= NO_SELECTED_ITEM
) &&
896 (wIndex
!= SYSMENU_SELECTED
) &&
897 (lppop
->items
[wIndex
].item_flags
& MF_SEPARATOR
))
898 wIndex
= NO_SELECTED_ITEM
;
899 if (lppop
->FocusedItem
== wIndex
) return;
900 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC32( lppop
->hWnd
);
901 else hdc
= GetDCEx32( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
903 /* Clear previous highlighted item */
904 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
906 if (lppop
->FocusedItem
== SYSMENU_SELECTED
)
907 NC_DrawSysButton( lppop
->hWnd
, hdc
, FALSE
);
910 lppop
->items
[lppop
->FocusedItem
].item_flags
&=~(MF_HILITE
|MF_MOUSESELECT
);
911 MENU_DrawMenuItem(lppop
->hWnd
,hdc
,&lppop
->items
[lppop
->FocusedItem
],
912 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
) );
916 /* Highlight new item (if any) */
917 lppop
->FocusedItem
= wIndex
;
918 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
920 if (lppop
->FocusedItem
== SYSMENU_SELECTED
)
922 NC_DrawSysButton( lppop
->hWnd
, hdc
, TRUE
);
924 SendMessage16( hwndOwner
, WM_MENUSELECT
,
925 WIN_FindWndPtr(lppop
->hWnd
)->hSysMenu
,
926 MAKELONG(lppop
->wFlags
| MF_MOUSESELECT
, hmenu
));
930 lppop
->items
[lppop
->FocusedItem
].item_flags
|= MF_HILITE
;
931 MENU_DrawMenuItem( lppop
->hWnd
, hdc
, &lppop
->items
[lppop
->FocusedItem
],
932 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
) );
934 SendMessage16( hwndOwner
, WM_MENUSELECT
,
935 lppop
->items
[lppop
->FocusedItem
].item_id
,
936 MAKELONG( lppop
->items
[lppop
->FocusedItem
].item_flags
| MF_MOUSESELECT
, hmenu
));
939 else if (sendMenuSelect
)
940 SendMessage16( hwndOwner
, WM_MENUSELECT
, hmenu
,
941 MAKELONG( lppop
->wFlags
| MF_MOUSESELECT
, hmenu
) );
943 ReleaseDC32( lppop
->hWnd
, hdc
);
947 /***********************************************************************
951 static void MENU_SelectItemRel( HWND32 hwndOwner
, HMENU32 hmenu
, INT32 offset
)
956 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
957 if (!menu
->items
) return;
958 if ((menu
->FocusedItem
!= NO_SELECTED_ITEM
) &&
959 (menu
->FocusedItem
!= SYSMENU_SELECTED
))
961 for (i
= menu
->FocusedItem
+ offset
; i
>= 0 && i
< menu
->nItems
964 if (!(menu
->items
[i
].item_flags
& MF_SEPARATOR
))
966 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
971 if (MENU_HasSysMenu( menu
))
973 MENU_SelectItem( hwndOwner
, hmenu
, SYSMENU_SELECTED
, TRUE
);
978 if( offset
> 0 ) { i
= 0; min
= -1; }
979 else i
= menu
->nItems
- 1;
981 for ( ; i
> min
&& i
< menu
->nItems
; i
+= offset
)
983 if (!(menu
->items
[i
].item_flags
& MF_SEPARATOR
))
985 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
989 if (MENU_HasSysMenu( menu
))
990 MENU_SelectItem( hwndOwner
, hmenu
, SYSMENU_SELECTED
, TRUE
);
994 /**********************************************************************
997 * Set an item flags, id and text ptr.
999 static BOOL32
MENU_SetItemData( MENUITEM
*item
, UINT32 flags
, UINT32 id
,
1002 LPSTR prevText
= IS_STRING_ITEM(item
->item_flags
) ? item
->text
: NULL
;
1004 if (IS_STRING_ITEM(flags
))
1008 flags
|= MF_SEPARATOR
;
1014 /* Item beginning with a backspace is a help item */
1020 if (!(text
= HEAP_strdupA( SystemHeap
, 0, str
))) return FALSE
;
1024 else if (flags
& MF_BITMAP
) item
->text
= (LPSTR
)(HBITMAP32
)LOWORD(str
);
1025 else if (flags
& MF_OWNERDRAW
) item
->text
= (LPSTR
)str
;
1026 else item
->text
= NULL
;
1028 item
->item_flags
= flags
& ~(MF_HILITE
| MF_MOUSESELECT
);
1030 SetRectEmpty32( &item
->rect
);
1031 if (prevText
) HeapFree( SystemHeap
, 0, prevText
);
1036 /**********************************************************************
1039 * Insert a new item into a menu.
1041 static MENUITEM
*MENU_InsertItem( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
)
1046 if (!(menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
)))
1048 dprintf_menu( stddeb
, "MENU_InsertItem: %04x not a menu handle\n",
1053 /* Find where to insert new item */
1055 if ((flags
& MF_BYPOSITION
) &&
1056 ((pos
== (UINT32
)-1) || (pos
== menu
->nItems
)))
1058 /* Special case: append to menu */
1059 /* Some programs specify the menu length to do that */
1064 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
1066 dprintf_menu( stddeb
, "MENU_InsertItem: item %x not found\n",
1070 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
)))
1072 dprintf_menu(stddeb
,"MENU_InsertItem: %04x not a menu handle\n",
1078 /* Create new items array */
1080 newItems
= HeapAlloc( SystemHeap
, 0, sizeof(MENUITEM
) * (menu
->nItems
+1) );
1083 dprintf_menu( stddeb
, "MENU_InsertItem: allocation failed\n" );
1086 if (menu
->nItems
> 0)
1088 /* Copy the old array into the new */
1089 if (pos
> 0) memcpy( newItems
, menu
->items
, pos
* sizeof(MENUITEM
) );
1090 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &menu
->items
[pos
],
1091 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
1092 HeapFree( SystemHeap
, 0, menu
->items
);
1094 menu
->items
= newItems
;
1096 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
1097 return &newItems
[pos
];
1101 /**********************************************************************
1102 * MENU_ParseResource
1104 * Parse a standard menu resource and add items to the menu.
1105 * Return a pointer to the end of the resource.
1107 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU32 hMenu
, BOOL32 unicode
)
1114 flags
= GET_WORD(res
);
1115 res
+= sizeof(WORD
);
1116 if (!(flags
& MF_POPUP
))
1119 res
+= sizeof(WORD
);
1121 if (!IS_STRING_ITEM(flags
))
1122 fprintf( stderr
, "MENU_ParseResource: not a string item %04x\n",
1125 if (!unicode
) res
+= strlen(str
) + 1;
1126 else res
+= (lstrlen32W((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1127 if (flags
& MF_POPUP
)
1129 HMENU32 hSubMenu
= CreatePopupMenu32();
1130 if (!hSubMenu
) return NULL
;
1131 if (!(res
= MENU_ParseResource( res
, hSubMenu
, unicode
)))
1133 if (!unicode
) AppendMenu32A( hMenu
, flags
, (UINT32
)hSubMenu
, str
);
1134 else AppendMenu32W( hMenu
, flags
, (UINT32
)hSubMenu
, (LPCWSTR
)str
);
1136 else /* Not a popup */
1138 if (!unicode
) AppendMenu32A( hMenu
, flags
, id
, *str
? str
: NULL
);
1139 else AppendMenu32W( hMenu
, flags
, id
,
1140 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1142 } while (!(flags
& MF_END
));
1147 /***********************************************************************
1150 * Return the handle of the selected sub-popup menu (if any).
1152 static HMENU32
MENU_GetSubPopup( HMENU32 hmenu
)
1157 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1158 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return 0;
1159 else if (menu
->FocusedItem
== SYSMENU_SELECTED
)
1160 return WIN_FindWndPtr(menu
->hWnd
)->hSysMenu
;
1162 item
= &menu
->items
[menu
->FocusedItem
];
1163 if (!(item
->item_flags
& MF_POPUP
) || !(item
->item_flags
& MF_MOUSESELECT
))
1165 return (HMENU32
)item
->item_id
;
1169 /***********************************************************************
1170 * MENU_HideSubPopups
1172 * Hide the sub-popup menus of this menu.
1174 static void MENU_HideSubPopups( HWND32 hwndOwner
, HMENU32 hmenu
,
1175 BOOL32 sendMenuSelect
)
1178 POPUPMENU
*menu
, *submenu
;
1181 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return;
1182 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return;
1183 if (menu
->FocusedItem
== SYSMENU_SELECTED
)
1185 hsubmenu
= WIN_FindWndPtr(menu
->hWnd
)->hSysMenu
;
1189 item
= &menu
->items
[menu
->FocusedItem
];
1190 if (!(item
->item_flags
& MF_POPUP
) ||
1191 !(item
->item_flags
& MF_MOUSESELECT
)) return;
1192 item
->item_flags
&= ~MF_MOUSESELECT
;
1193 hsubmenu
= (HMENU32
)item
->item_id
;
1195 submenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hsubmenu
);
1196 MENU_HideSubPopups( hwndOwner
, hsubmenu
, FALSE
);
1197 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, sendMenuSelect
);
1198 if (submenu
->hWnd
== pTopPWnd
->hwndSelf
)
1200 ShowWindow32( submenu
->hWnd
, SW_HIDE
);
1205 DestroyWindow32( submenu
->hWnd
);
1211 /***********************************************************************
1214 * Display the sub-menu of the selected item of this menu.
1215 * Return the handle of the submenu, or hmenu if no submenu to display.
1217 static HMENU32
MENU_ShowSubPopup( HWND32 hwndOwner
, HMENU32 hmenu
,
1218 BOOL32 selectFirst
)
1224 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return hmenu
;
1225 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return hmenu
;
1226 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return hmenu
;
1227 if (menu
->FocusedItem
== SYSMENU_SELECTED
)
1229 MENU_InitSysMenuPopup(wndPtr
->hSysMenu
, wndPtr
->dwStyle
,
1230 wndPtr
->class->style
);
1231 MENU_ShowPopup(hwndOwner
, wndPtr
->hSysMenu
, 0, wndPtr
->rectClient
.left
,
1232 wndPtr
->rectClient
.top
- menu
->Height
- 2*SYSMETRICS_CYBORDER
,
1233 SYSMETRICS_CXSIZE
, SYSMETRICS_CYSIZE
);
1235 MENU_SelectItemRel( hwndOwner
, wndPtr
->hSysMenu
, ITEM_NEXT
);
1236 return wndPtr
->hSysMenu
;
1238 item
= &menu
->items
[menu
->FocusedItem
];
1239 if (!(item
->item_flags
& MF_POPUP
) ||
1240 (item
->item_flags
& (MF_GRAYED
| MF_DISABLED
))) return hmenu
;
1241 item
->item_flags
|= MF_MOUSESELECT
;
1242 if (menu
->wFlags
& MF_POPUP
)
1244 MENU_ShowPopup( hwndOwner
, (HMENU16
)item
->item_id
, menu
->FocusedItem
,
1245 wndPtr
->rectWindow
.left
+ item
->rect
.right
-arrow_bitmap_width
,
1246 wndPtr
->rectWindow
.top
+ item
->rect
.top
,
1247 item
->rect
.left
- item
->rect
.right
+ 2*arrow_bitmap_width
,
1248 item
->rect
.top
- item
->rect
.bottom
);
1252 MENU_ShowPopup( hwndOwner
, (HMENU16
)item
->item_id
, menu
->FocusedItem
,
1253 wndPtr
->rectWindow
.left
+ item
->rect
.left
,
1254 wndPtr
->rectWindow
.top
+ item
->rect
.bottom
,
1255 item
->rect
.right
- item
->rect
.left
,
1256 item
->rect
.bottom
- item
->rect
.top
);
1259 MENU_SelectItemRel( hwndOwner
, (HMENU32
)item
->item_id
, ITEM_NEXT
);
1260 return (HMENU32
)item
->item_id
;
1264 /***********************************************************************
1265 * MENU_FindMenuByCoords
1267 * Find the menu containing a given point (in screen coords).
1269 static HMENU32
MENU_FindMenuByCoords( HMENU32 hmenu
, POINT32 pt
)
1274 if (!(hwnd
= WindowFromPoint32( pt
))) return 0;
1277 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1278 if (menu
->hWnd
== hwnd
)
1280 if (!(menu
->wFlags
& MF_POPUP
))
1282 /* Make sure it's in the menu bar (or in system menu) */
1283 WND
*wndPtr
= WIN_FindWndPtr( menu
->hWnd
);
1284 if ((pt
.x
< wndPtr
->rectClient
.left
) ||
1285 (pt
.x
>= wndPtr
->rectClient
.right
) ||
1286 (pt
.y
>= wndPtr
->rectClient
.top
)) return 0;
1287 if (pt
.y
< wndPtr
->rectClient
.top
- menu
->Height
)
1289 if (!MENU_IsInSysMenu( menu
, pt
)) return 0;
1291 /* else it's in the menu bar */
1295 hmenu
= MENU_GetSubPopup( hmenu
);
1301 /***********************************************************************
1302 * MENU_ExecFocusedItem
1304 * Execute a menu item (for instance when user pressed Enter).
1305 * Return TRUE if we can go on with menu tracking.
1307 static BOOL32
MENU_ExecFocusedItem( HWND32 hwndOwner
, HMENU32 hmenu
,
1308 HMENU32
*hmenuCurrent
)
1311 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1312 if (!menu
|| !menu
->nItems
|| (menu
->FocusedItem
== NO_SELECTED_ITEM
) ||
1313 (menu
->FocusedItem
== SYSMENU_SELECTED
)) return TRUE
;
1314 item
= &menu
->items
[menu
->FocusedItem
];
1315 if (!(item
->item_flags
& MF_POPUP
))
1317 if (!(item
->item_flags
& (MF_GRAYED
| MF_DISABLED
)))
1319 PostMessage16( hwndOwner
, (menu
->wFlags
& MF_SYSMENU
) ?
1320 WM_SYSCOMMAND
: WM_COMMAND
, item
->item_id
, 0 );
1327 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, TRUE
);
1333 /***********************************************************************
1336 * Handle a button-down event in a menu. Point is in screen coords.
1337 * hmenuCurrent is the top-most visible popup.
1338 * Return TRUE if we can go on with menu tracking.
1340 static BOOL32
MENU_ButtonDown( HWND32 hwndOwner
, HMENU32 hmenu
,
1341 HMENU32
*hmenuCurrent
, POINT32 pt
)
1347 if (!hmenu
) return FALSE
; /* Outside all menus */
1348 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1349 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1350 if (!item
) /* Maybe in system menu */
1352 if (!MENU_IsInSysMenu( menu
, pt
)) return FALSE
;
1353 id
= SYSMENU_SELECTED
;
1356 if (menu
->FocusedItem
== id
)
1358 if (id
== SYSMENU_SELECTED
) return FALSE
;
1359 if (item
->item_flags
& MF_POPUP
)
1361 if (item
->item_flags
& MF_MOUSESELECT
)
1363 if (menu
->wFlags
& MF_POPUP
)
1365 MENU_HideSubPopups( hwndOwner
, hmenu
, TRUE
);
1366 *hmenuCurrent
= hmenu
;
1370 else *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1375 MENU_HideSubPopups( hwndOwner
, hmenu
, FALSE
);
1376 MENU_SelectItem( hwndOwner
, hmenu
, id
, TRUE
);
1377 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1383 /***********************************************************************
1386 * Handle a button-up event in a menu. Point is in screen coords.
1387 * hmenuCurrent is the top-most visible popup.
1388 * Return TRUE if we can go on with menu tracking.
1390 static BOOL32
MENU_ButtonUp( HWND32 hwndOwner
, HMENU32 hmenu
,
1391 HMENU32
*hmenuCurrent
, POINT32 pt
)
1395 HMENU32 hsubmenu
= 0;
1398 if (!hmenu
) return FALSE
; /* Outside all menus */
1399 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1400 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1401 if (!item
) /* Maybe in system menu */
1403 if (!MENU_IsInSysMenu( menu
, pt
)) return FALSE
;
1404 id
= SYSMENU_SELECTED
;
1405 hsubmenu
= WIN_FindWndPtr(menu
->hWnd
)->hSysMenu
;
1408 if (menu
->FocusedItem
!= id
) return FALSE
;
1410 if (id
!= SYSMENU_SELECTED
)
1412 if (!(item
->item_flags
& MF_POPUP
))
1414 return MENU_ExecFocusedItem( hwndOwner
, hmenu
, hmenuCurrent
);
1416 hsubmenu
= (HMENU32
)item
->item_id
;
1418 /* Select first item of sub-popup */
1419 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, FALSE
);
1420 MENU_SelectItemRel( hwndOwner
, hsubmenu
, ITEM_NEXT
);
1425 /***********************************************************************
1428 * Handle a motion event in a menu. Point is in screen coords.
1429 * hmenuCurrent is the top-most visible popup.
1430 * Return TRUE if we can go on with menu tracking.
1432 static BOOL32
MENU_MouseMove( HWND32 hwndOwner
, HMENU32 hmenu
,
1433 HMENU32
*hmenuCurrent
, POINT32 pt
)
1436 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1437 UINT32 id
= NO_SELECTED_ITEM
;
1441 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1442 if (!item
) /* Maybe in system menu */
1444 if (!MENU_IsInSysMenu( menu
, pt
))
1445 id
= NO_SELECTED_ITEM
; /* Outside all items */
1446 else id
= SYSMENU_SELECTED
;
1449 if (id
== NO_SELECTED_ITEM
)
1451 MENU_SelectItem( hwndOwner
, *hmenuCurrent
, NO_SELECTED_ITEM
, TRUE
);
1453 else if (menu
->FocusedItem
!= id
)
1455 MENU_HideSubPopups( hwndOwner
, hmenu
, FALSE
);
1456 MENU_SelectItem( hwndOwner
, hmenu
, id
, TRUE
);
1457 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1463 /***********************************************************************
1466 static LRESULT
MENU_DoNextMenu( HWND32
* hwndOwner
, HMENU32
* hmenu
,
1467 HMENU32
*hmenuCurrent
, UINT32 vk
)
1469 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( *hmenu
);
1472 if( (vk
== VK_LEFT
&& !menu
->FocusedItem
)
1473 || (vk
== VK_RIGHT
&& menu
->FocusedItem
== menu
->nItems
- 1)
1474 || menu
->FocusedItem
== SYSMENU_SELECTED
1475 || ((menu
->wFlags
& (MF_POPUP
| MF_SYSMENU
)) == (MF_POPUP
| MF_SYSMENU
)))
1477 LRESULT l
= SendMessage16( *hwndOwner
, WM_NEXTMENU
, (WPARAM16
)vk
,
1478 (LPARAM
)((menu
->FocusedItem
== SYSMENU_SELECTED
)
1479 ? GetSystemMenu32( *hwndOwner
, 0)
1482 if( l
== 0 || !IsMenu32(LOWORD(l
)) || !IsWindow32(HIWORD(l
)) ) return 0;
1484 /* shutdown current menu -
1485 * all these checks for system popup window are needed
1486 * only because Wine system menu tracking is unsuitable
1487 * for a lot of things (esp. when we do not have wIDmenu to fall back on).
1490 MENU_SelectItem( *hwndOwner
, *hmenu
, NO_SELECTED_ITEM
, FALSE
);
1492 if( (menu
->wFlags
& (MF_POPUP
| MF_SYSMENU
)) == (MF_POPUP
| MF_SYSMENU
) )
1494 ShowWindow32( menu
->hWnd
, SW_HIDE
);
1497 if( !IsIconic32( *hwndOwner
) )
1499 HDC32 hdc
= GetDCEx32( *hwndOwner
, 0, DCX_CACHE
| DCX_WINDOW
);
1500 NC_DrawSysButton( *hwndOwner
, hdc
, FALSE
);
1501 ReleaseDC32( *hwndOwner
, hdc
);
1506 *hwndOwner
= HIWORD(l
);
1508 SetCapture32( *hwndOwner
);
1510 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( *hmenu
);
1512 /* init next menu */
1514 if( (menu
->wFlags
& (MF_POPUP
| MF_SYSMENU
)) == (MF_POPUP
| MF_SYSMENU
) )
1517 WND
* wndPtr
= WIN_FindWndPtr( *hwndOwner
);
1519 /* stupid kludge, see above */
1521 if( wndPtr
->wIDmenu
&& !(wndPtr
->dwStyle
& WS_CHILD
) )
1523 *hmenu
= wndPtr
->wIDmenu
;
1524 id
= SYSMENU_SELECTED
;
1528 if( NC_GetSysPopupPos( wndPtr
, &rect
) )
1529 MENU_ShowPopup( *hwndOwner
, *hmenu
, 0, rect
.left
, rect
.bottom
,
1530 SYSMETRICS_CXSIZE
, SYSMETRICS_CYSIZE
);
1532 if( !IsIconic32( *hwndOwner
) )
1534 HDC32 hdc
= GetDCEx32( *hwndOwner
, 0, DCX_CACHE
| DCX_WINDOW
);
1535 NC_DrawSysButton( *hwndOwner
, hdc
, TRUE
);
1536 ReleaseDC32( *hwndOwner
, hdc
);
1541 MENU_SelectItem( *hwndOwner
, *hmenu
, id
, TRUE
);
1547 /***********************************************************************
1550 * Handle a VK_LEFT key event in a menu.
1551 * hmenuCurrent is the top-most visible popup.
1553 static void MENU_KeyLeft( HWND32
* hwndOwner
, HMENU32
* hmenu
,
1554 HMENU32
*hmenuCurrent
)
1557 HMENU32 hmenutmp
, hmenuprev
;
1559 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( *hmenu
);
1560 hmenuprev
= hmenutmp
= *hmenu
;
1561 while (hmenutmp
!= *hmenuCurrent
)
1563 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
1564 if (hmenutmp
!= *hmenuCurrent
) hmenuprev
= hmenutmp
;
1566 MENU_HideSubPopups( *hwndOwner
, hmenuprev
, TRUE
);
1569 if ( (hmenuprev
== *hmenu
) &&
1570 ((menu
->wFlags
& MF_SYSMENU
) || !(menu
->wFlags
& MF_POPUP
)) )
1572 /* send WM_NEXTMENU */
1574 if( !MENU_DoNextMenu( hwndOwner
, hmenu
, hmenuCurrent
, VK_LEFT
) )
1575 MENU_SelectItemRel( *hwndOwner
, *hmenu
, ITEM_PREV
);
1576 else *hmenuCurrent
= *hmenu
;
1578 if (*hmenuCurrent
!= hmenutmp
)
1580 /* A sublevel menu was displayed -> display the next one */
1581 *hmenuCurrent
= MENU_ShowSubPopup( *hwndOwner
, *hmenu
, TRUE
);
1584 else *hmenuCurrent
= hmenuprev
;
1588 /***********************************************************************
1591 * Handle a VK_RIGHT key event in a menu.
1592 * hmenuCurrent is the top-most visible popup.
1594 static void MENU_KeyRight( HWND32
* hwndOwner
, HMENU32
* hmenu
,
1595 HMENU32
*hmenuCurrent
)
1600 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( *hmenu
);
1602 if ((menu
->wFlags
& MF_POPUP
) || (*hmenuCurrent
!= *hmenu
))
1604 /* If already displaying a popup, try to display sub-popup */
1605 hmenutmp
= MENU_ShowSubPopup( *hwndOwner
, *hmenuCurrent
, TRUE
);
1606 if (hmenutmp
!= *hmenuCurrent
) /* Sub-popup displayed */
1608 *hmenuCurrent
= hmenutmp
;
1613 /* If menu-bar tracking, go to next item */
1615 if (!(menu
->wFlags
& MF_POPUP
) || (menu
->wFlags
& MF_SYSMENU
))
1617 MENU_HideSubPopups( *hwndOwner
, *hmenu
, FALSE
);
1620 /* Send WM_NEXTMENU */
1622 if( !MENU_DoNextMenu( hwndOwner
, hmenu
, hmenuCurrent
, VK_RIGHT
) )
1623 MENU_SelectItemRel( *hwndOwner
, *hmenu
, ITEM_NEXT
);
1624 else *hmenuCurrent
= *hmenu
;
1626 if (*hmenuCurrent
!= hmenutmp
)
1628 /* A sublevel menu was displayed -> display the next one */
1629 *hmenuCurrent
= MENU_ShowSubPopup( *hwndOwner
, *hmenu
, TRUE
);
1632 else if (*hmenuCurrent
!= *hmenu
) /* Hide last level popup */
1635 hmenuprev
= hmenutmp
= *hmenu
;
1636 while (hmenutmp
!= *hmenuCurrent
)
1638 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
1639 if (hmenutmp
!= *hmenuCurrent
) hmenuprev
= hmenutmp
;
1641 MENU_HideSubPopups( *hwndOwner
, hmenuprev
, TRUE
);
1642 *hmenuCurrent
= hmenuprev
;
1647 /***********************************************************************
1650 * Menu tracking code.
1651 * If 'x' and 'y' are not 0, we simulate a button-down event at (x,y)
1652 * before beginning tracking. This is to help menu-bar tracking.
1654 static BOOL32
MENU_TrackMenu( HMENU32 hmenu
, UINT32 wFlags
, INT32 x
, INT32 y
,
1655 HWND32 hwnd
, const RECT32
*lprect
)
1659 HMENU32 hmenuCurrent
= hmenu
;
1660 BOOL32 fClosed
= FALSE
, fRemove
;
1664 fEndMenuCalled
= FALSE
;
1665 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
1670 MENU_ButtonDown( hwnd
, hmenu
, &hmenuCurrent
, pt
);
1673 EVENT_Capture( hwnd
, HTMENU
);
1677 /* we have to keep the message in the queue until it's
1678 * clear that menu loop is not over yet.
1681 if (!MSG_InternalGetMessage( &msg
, 0, hwnd
, MSGF_MENU
,
1682 PM_NOREMOVE
, TRUE
))
1685 TranslateMessage16( &msg
);
1686 CONV_POINT16TO32( &msg
.pt
, &pt
);
1689 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
1691 /* Find the sub-popup for this mouse event (if any) */
1693 HMENU32 hsubmenu
= MENU_FindMenuByCoords( hmenu
, pt
);
1697 /* no WM_NC... messages in captured state */
1699 case WM_RBUTTONDBLCLK
:
1700 case WM_RBUTTONDOWN
:
1701 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
1704 case WM_LBUTTONDBLCLK
:
1705 case WM_LBUTTONDOWN
:
1706 fClosed
= !MENU_ButtonDown( hwnd
, hsubmenu
,
1707 &hmenuCurrent
, pt
);
1711 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
1715 /* If outside all menus but inside lprect, ignore it */
1716 if (!hsubmenu
&& lprect
&& PtInRect32(lprect
, pt
)) break;
1717 fClosed
= !MENU_ButtonUp( hwnd
, hsubmenu
,
1718 &hmenuCurrent
, pt
);
1719 fRemove
= TRUE
; /* Remove event even if outside menu */
1723 if ((msg
.wParam
& MK_LBUTTON
) ||
1724 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
.wParam
& MK_RBUTTON
)))
1726 fClosed
= !MENU_MouseMove( hwnd
, hsubmenu
,
1727 &hmenuCurrent
, pt
);
1732 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
1734 fRemove
= TRUE
; /* Keyboard messages are always removed */
1742 MENU_SelectItem( hwnd
, hmenuCurrent
, NO_SELECTED_ITEM
, FALSE
);
1746 MENU_SelectItemRel( hwnd
, hmenuCurrent
,
1747 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
1750 case VK_DOWN
: /* If on menu bar, pull-down the menu */
1752 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1753 if (!(menu
->wFlags
& MF_POPUP
) && (hmenuCurrent
== hmenu
))
1754 hmenuCurrent
= MENU_ShowSubPopup( hwnd
, hmenu
, TRUE
);
1756 MENU_SelectItemRel( hwnd
, hmenuCurrent
, ITEM_NEXT
);
1760 MENU_KeyLeft( &hwnd
, &hmenu
, &hmenuCurrent
);
1764 MENU_KeyRight( &hwnd
, &hmenu
, &hmenuCurrent
);
1769 fClosed
= !MENU_ExecFocusedItem( hwnd
, hmenuCurrent
,
1780 break; /* WM_KEYDOWN */
1790 break; /* WM_SYSKEYDOWN */
1794 /* Hack to avoid control chars. */
1795 /* We will find a better way real soon... */
1796 if ((msg
.wParam
<= 32) || (msg
.wParam
>= 127)) break;
1797 pos
= MENU_FindItemByKey( hwnd
, hmenuCurrent
, msg
.wParam
, FALSE
);
1798 if (pos
== (UINT32
)-2) fClosed
= TRUE
;
1799 else if (pos
== (UINT32
)-1) MessageBeep32(0);
1802 MENU_SelectItem( hwnd
, hmenuCurrent
, pos
, TRUE
);
1803 fClosed
= !MENU_ExecFocusedItem( hwnd
, hmenuCurrent
,
1808 break; /* WM_CHAR */
1809 } /* switch(msg.message) */
1813 DispatchMessage16( &msg
);
1815 if (fEndMenuCalled
) fClosed
= TRUE
;
1816 if (!fClosed
) fRemove
= TRUE
;
1818 if (fRemove
) /* Remove the message from the queue */
1819 PeekMessage16( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
1823 MENU_HideSubPopups( hwnd
, hmenu
, FALSE
);
1824 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1825 if (menu
&& menu
->wFlags
& MF_POPUP
)
1827 ShowWindow32( menu
->hWnd
, SW_HIDE
);
1830 MENU_SelectItem( hwnd
, hmenu
, NO_SELECTED_ITEM
, FALSE
);
1831 SendMessage16( hwnd
, WM_MENUSELECT
, 0, MAKELONG( 0xffff, 0 ) );
1832 fEndMenuCalled
= FALSE
;
1836 /***********************************************************************
1837 * MENU_TrackSysPopup
1839 static void MENU_TrackSysPopup( WND
* pWnd
)
1842 HMENU32 hMenu
= pWnd
->hSysMenu
;
1845 /* track the system menu like a normal popup menu */
1849 HWND32 hWnd
= pWnd
->hwndSelf
;
1850 if (!(pWnd
->dwStyle
& WS_MINIMIZE
))
1852 hDC
= GetWindowDC32( hWnd
);
1853 NC_DrawSysButton( hWnd
, hDC
, TRUE
);
1855 NC_GetSysPopupPos( pWnd
, &rect
);
1856 MENU_InitSysMenuPopup( hMenu
, pWnd
->dwStyle
,
1857 pWnd
->class->style
);
1858 TrackPopupMenu32( hMenu
, TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
1859 rect
.left
, rect
.bottom
, 0, hWnd
, &rect
);
1860 if (!(pWnd
->dwStyle
& WS_MINIMIZE
))
1862 NC_DrawSysButton( hWnd
, hDC
, FALSE
);
1863 ReleaseDC32( hWnd
, hDC
);
1868 /***********************************************************************
1871 static BOOL32
MENU_InitTracking(HWND32 hWnd
, HMENU32 hMenu
)
1874 SendMessage16( hWnd
, WM_ENTERMENULOOP
, 0, 0 );
1875 SendMessage16( hWnd
, WM_SETCURSOR
, hWnd
, HTCAPTION
);
1876 SendMessage16( hWnd
, WM_INITMENU
, hMenu
, 0 );
1880 /***********************************************************************
1881 * MENU_TrackMouseMenuBar
1883 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
1885 void MENU_TrackMouseMenuBar( WND
* wndPtr
, INT32 ht
, POINT32 pt
)
1887 BOOL32 bTrackSys
= ((ht
== HTSYSMENU
&& !wndPtr
->wIDmenu
) ||
1888 (wndPtr
->dwStyle
& (WS_MINIMIZE
| WS_CHILD
)));
1889 HWND32 hWnd
= wndPtr
->hwndSelf
;
1890 HMENU32 hMenu
= (bTrackSys
) ? wndPtr
->hSysMenu
: wndPtr
->wIDmenu
;
1892 if (IsMenu32(hMenu
))
1894 MENU_InitTracking( hWnd
, hMenu
);
1896 MENU_TrackSysPopup( wndPtr
);
1898 MENU_TrackMenu( hMenu
, TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
1899 pt
.x
, pt
.y
, hWnd
, NULL
);
1900 SendMessage16( hWnd
, WM_EXITMENULOOP
, 0, 0 );
1906 /***********************************************************************
1907 * MENU_TrackKbdMenuBar
1909 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
1911 void MENU_TrackKbdMenuBar( WND
* wndPtr
, UINT32 wParam
, INT32 vkey
)
1914 UINT32 uItem
= NO_SELECTED_ITEM
;
1917 /* find window that has a menu */
1919 while( wndPtr
->dwStyle
& WS_CHILD
&& !(wndPtr
->dwStyle
& WS_SYSMENU
) )
1920 if( !(wndPtr
= wndPtr
->parent
) ) return;
1922 if( !wndPtr
->wIDmenu
&& !(wndPtr
->dwStyle
& WS_SYSMENU
) ) return;
1924 if((wndPtr
->dwStyle
& (WS_CHILD
| WS_MINIMIZE
)) || !wndPtr
->wIDmenu
)
1926 hTrackMenu
= wndPtr
->hSysMenu
;
1931 hTrackMenu
= wndPtr
->wIDmenu
;
1935 if (IsMenu32( hTrackMenu
))
1937 MENU_InitTracking( wndPtr
->hwndSelf
, hTrackMenu
);
1939 if( vkey
== VK_SPACE
)
1940 uItem
= SYSMENU_SELECTED
;
1943 uItem
= MENU_FindItemByKey( wndPtr
->hwndSelf
, hTrackMenu
,
1944 vkey
, (htMenu
== HTSYSMENU
) );
1945 if( uItem
>= (UINT32
)(-2) )
1947 if( uItem
== (UINT32
)(-1) ) MessageBeep32(0);
1955 MENU_SelectItem( wndPtr
->hwndSelf
, hTrackMenu
, uItem
, TRUE
);
1956 if( uItem
== NO_SELECTED_ITEM
)
1957 MENU_SelectItemRel( wndPtr
->hwndSelf
, hTrackMenu
, ITEM_NEXT
);
1959 PostMessage16( wndPtr
->hwndSelf
, WM_KEYDOWN
, VK_DOWN
, 0L );
1961 MENU_TrackMenu( hTrackMenu
, TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
1962 0, 0, wndPtr
->hwndSelf
, NULL
);
1966 MENU_TrackSysPopup( wndPtr
);
1969 SendMessage16( wndPtr
->hwndSelf
, WM_EXITMENULOOP
, 0, 0 );
1975 /**********************************************************************
1976 * TrackPopupMenu16 (USER.416)
1978 BOOL16
TrackPopupMenu16( HMENU16 hMenu
, UINT16 wFlags
, INT16 x
, INT16 y
,
1979 INT16 nReserved
, HWND16 hWnd
, const RECT16
*lpRect
)
1983 CONV_RECT16TO32( lpRect
, &r
);
1984 return TrackPopupMenu32( hMenu
, wFlags
, x
, y
, nReserved
, hWnd
,
1985 lpRect
? &r
: NULL
);
1989 /**********************************************************************
1990 * TrackPopupMenu32 (USER32.548)
1992 BOOL32
TrackPopupMenu32( HMENU32 hMenu
, UINT32 wFlags
, INT32 x
, INT32 y
,
1993 INT32 nReserved
, HWND32 hWnd
, const RECT32
*lpRect
)
1998 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
, 0, 0 ))
1999 ret
= MENU_TrackMenu( hMenu
, wFlags
, 0, 0, hWnd
, lpRect
);
2004 /**********************************************************************
2005 * TrackPopupMenuEx (USER32.549)
2007 BOOL32
TrackPopupMenuEx( HMENU32 hMenu
, UINT32 wFlags
, INT32 x
, INT32 y
,
2008 HWND32 hWnd
, LPTPMPARAMS lpTpm
)
2010 fprintf( stderr
, "TrackPopupMenuEx: not fully implemented\n" );
2011 return TrackPopupMenu32( hMenu
, wFlags
, x
, y
, 0, hWnd
,
2012 lpTpm
? &lpTpm
->rcExclude
: NULL
);
2015 /***********************************************************************
2018 LRESULT
PopupMenuWndProc( HWND32 hwnd
, UINT32 message
, WPARAM32 wParam
,
2025 CREATESTRUCT32A
*cs
= (CREATESTRUCT32A
*)lParam
;
2026 SetWindowLong32A( hwnd
, 0, (LONG
)cs
->lpCreateParams
);
2030 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2031 return MA_NOACTIVATE
;
2036 BeginPaint32( hwnd
, &ps
);
2037 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
2038 (HMENU32
)GetWindowLong32A( hwnd
, 0 ) );
2039 EndPaint32( hwnd
, &ps
);
2044 /* zero out global pointer in case system popup
2045 * was destroyed by AppExit
2048 if( hwnd
== pTopPWnd
->hwndSelf
)
2049 { pTopPWnd
= NULL
; uSubPWndLevel
= 0; }
2055 if (wParam
) SetWindowLong32A( hwnd
, 0, (HMENU16
)wParam
);
2058 return DefWindowProc32A( hwnd
, message
, wParam
, lParam
);
2064 /***********************************************************************
2065 * MENU_GetMenuBarHeight
2067 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
2069 UINT32
MENU_GetMenuBarHeight( HWND32 hwnd
, UINT32 menubarWidth
,
2070 INT32 orgX
, INT32 orgY
)
2077 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
2078 if (!(lppop
= (LPPOPUPMENU
)USER_HEAP_LIN_ADDR((HMENU16
)wndPtr
->wIDmenu
)))
2080 hdc
= GetDCEx32( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2081 SetRect32(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+SYSMETRICS_CYMENU
);
2082 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
2083 ReleaseDC32( hwnd
, hdc
);
2084 return lppop
->Height
;
2088 /*******************************************************************
2089 * ChangeMenu16 (USER.153)
2091 BOOL16
ChangeMenu16( HMENU16 hMenu
, UINT16 pos
, SEGPTR data
,
2092 UINT16 id
, UINT16 flags
)
2094 dprintf_menu( stddeb
,"ChangeMenu16: menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
2095 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2096 if (flags
& MF_APPEND
) return AppendMenu16( hMenu
, flags
& ~MF_APPEND
,
2098 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
2099 /* for MF_DELETE. We should check the parameters for all others */
2100 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
2101 if (flags
& MF_DELETE
) return DeleteMenu16(hMenu
, pos
, flags
& ~MF_DELETE
);
2102 if (flags
& MF_CHANGE
) return ModifyMenu16(hMenu
, pos
, flags
& ~MF_CHANGE
,
2104 if (flags
& MF_REMOVE
) return RemoveMenu16(hMenu
,
2105 flags
& MF_BYPOSITION
? pos
: id
,
2106 flags
& ~MF_REMOVE
);
2107 /* Default: MF_INSERT */
2108 return InsertMenu16( hMenu
, pos
, flags
, id
, data
);
2112 /*******************************************************************
2113 * ChangeMenu32A (USER32.22)
2115 BOOL32
ChangeMenu32A( HMENU32 hMenu
, UINT32 pos
, LPCSTR data
,
2116 UINT32 id
, UINT32 flags
)
2118 dprintf_menu( stddeb
,"ChangeMenu32A: menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2119 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2120 if (flags
& MF_APPEND
) return AppendMenu32A( hMenu
, flags
& ~MF_APPEND
,
2122 if (flags
& MF_DELETE
) return DeleteMenu32(hMenu
, pos
, flags
& ~MF_DELETE
);
2123 if (flags
& MF_CHANGE
) return ModifyMenu32A(hMenu
, pos
, flags
& ~MF_CHANGE
,
2125 if (flags
& MF_REMOVE
) return RemoveMenu32( hMenu
,
2126 flags
& MF_BYPOSITION
? pos
: id
,
2127 flags
& ~MF_REMOVE
);
2128 /* Default: MF_INSERT */
2129 return InsertMenu32A( hMenu
, pos
, flags
, id
, data
);
2133 /*******************************************************************
2134 * ChangeMenu32W (USER32.23)
2136 BOOL32
ChangeMenu32W( HMENU32 hMenu
, UINT32 pos
, LPCWSTR data
,
2137 UINT32 id
, UINT32 flags
)
2139 dprintf_menu( stddeb
,"ChangeMenu32W: menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2140 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2141 if (flags
& MF_APPEND
) return AppendMenu32W( hMenu
, flags
& ~MF_APPEND
,
2143 if (flags
& MF_DELETE
) return DeleteMenu32(hMenu
, pos
, flags
& ~MF_DELETE
);
2144 if (flags
& MF_CHANGE
) return ModifyMenu32W(hMenu
, pos
, flags
& ~MF_CHANGE
,
2146 if (flags
& MF_REMOVE
) return RemoveMenu32( hMenu
,
2147 flags
& MF_BYPOSITION
? pos
: id
,
2148 flags
& ~MF_REMOVE
);
2149 /* Default: MF_INSERT */
2150 return InsertMenu32W( hMenu
, pos
, flags
, id
, data
);
2154 /*******************************************************************
2155 * CheckMenuItem16 (USER.154)
2157 BOOL16
CheckMenuItem16( HMENU16 hMenu
, UINT16 id
, UINT16 flags
)
2159 return (BOOL16
)CheckMenuItem32( hMenu
, id
, flags
);
2163 /*******************************************************************
2164 * CheckMenuItem32 (USER32.45)
2166 DWORD
CheckMenuItem32( HMENU32 hMenu
, UINT32 id
, UINT32 flags
)
2171 dprintf_menu( stddeb
,"CheckMenuItem: %04x %04x %04x\n", hMenu
, id
, flags
);
2172 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
2173 ret
= item
->item_flags
& MF_CHECKED
;
2174 if (flags
& MF_CHECKED
) item
->item_flags
|= MF_CHECKED
;
2175 else item
->item_flags
&= ~MF_CHECKED
;
2180 /**********************************************************************
2181 * EnableMenuItem16 (USER.155)
2183 BOOL16
EnableMenuItem16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
2185 return EnableMenuItem32( hMenu
, wItemID
, wFlags
);
2189 /**********************************************************************
2190 * EnableMenuItem32 (USER32.169)
2192 BOOL32
EnableMenuItem32( HMENU32 hMenu
, UINT32 wItemID
, UINT32 wFlags
)
2194 BOOL32 bRet
= FALSE
;
2195 MENUITEM
*item
, *first
= NULL
;
2197 dprintf_menu(stddeb
,"EnableMenuItem (%04x, %04X, %04X) !\n",
2198 hMenu
, wItemID
, wFlags
);
2200 while( (item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
)) )
2202 if( !(item
->item_flags
& MF_POPUP
) )
2204 /* We can't have MF_GRAYED and MF_DISABLED together */
2205 if (wFlags
& MF_GRAYED
)
2207 item
->item_flags
= (item
->item_flags
& ~MF_DISABLED
) | MF_GRAYED
;
2209 else if (wFlags
& MF_DISABLED
)
2211 item
->item_flags
= (item
->item_flags
& ~MF_GRAYED
) | MF_DISABLED
;
2213 else /* MF_ENABLED */
2215 item
->item_flags
&= ~(MF_GRAYED
| MF_DISABLED
);
2220 if( !first
) first
= item
;
2221 else if( first
== item
) break;
2227 /*******************************************************************
2228 * GetMenuString16 (USER.161)
2230 INT16
GetMenuString16( HMENU16 hMenu
, UINT16 wItemID
,
2231 LPSTR str
, INT16 nMaxSiz
, UINT16 wFlags
)
2233 return GetMenuString32A( hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
2237 /*******************************************************************
2238 * GetMenuString32A (USER32.267)
2240 INT32
GetMenuString32A( HMENU32 hMenu
, UINT32 wItemID
,
2241 LPSTR str
, INT32 nMaxSiz
, UINT32 wFlags
)
2245 dprintf_menu( stddeb
, "GetMenuString32A: menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
2246 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
2247 if (!str
|| !nMaxSiz
) return 0;
2249 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
2250 if (!IS_STRING_ITEM(item
->item_flags
)) return 0;
2251 lstrcpyn32A( str
, item
->text
, nMaxSiz
);
2252 dprintf_menu( stddeb
, "GetMenuString32A: returning '%s'\n", str
);
2257 /*******************************************************************
2258 * GetMenuString32W (USER32.268)
2260 INT32
GetMenuString32W( HMENU32 hMenu
, UINT32 wItemID
,
2261 LPWSTR str
, INT32 nMaxSiz
, UINT32 wFlags
)
2265 dprintf_menu( stddeb
, "GetMenuString32W: menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
2266 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
2267 if (!str
|| !nMaxSiz
) return 0;
2269 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
2270 if (!IS_STRING_ITEM(item
->item_flags
)) return 0;
2271 lstrcpynAtoW( str
, item
->text
, nMaxSiz
);
2272 return lstrlen32W(str
);
2276 /**********************************************************************
2277 * HiliteMenuItem16 (USER.162)
2279 BOOL16
HiliteMenuItem16( HWND16 hWnd
, HMENU16 hMenu
, UINT16 wItemID
,
2282 return HiliteMenuItem32( hWnd
, hMenu
, wItemID
, wHilite
);
2286 /**********************************************************************
2287 * HiliteMenuItem32 (USER32.317)
2289 BOOL32
HiliteMenuItem32( HWND32 hWnd
, HMENU32 hMenu
, UINT32 wItemID
,
2293 dprintf_menu(stddeb
,"HiliteMenuItem(%04x, %04x, %04x, %04x);\n",
2294 hWnd
, hMenu
, wItemID
, wHilite
);
2295 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
2296 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
2297 if (menu
->FocusedItem
== wItemID
) return TRUE
;
2298 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
2299 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
);
2304 /**********************************************************************
2305 * GetMenuState16 (USER.250)
2307 UINT16
GetMenuState16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
2309 return GetMenuState32( hMenu
, wItemID
, wFlags
);
2313 /**********************************************************************
2314 * GetMenuState32 (USER32.266)
2316 UINT32
GetMenuState32( HMENU32 hMenu
, UINT32 wItemID
, UINT32 wFlags
)
2319 dprintf_menu(stddeb
,"GetMenuState(%04x, %04x, %04x);\n",
2320 hMenu
, wItemID
, wFlags
);
2321 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
2322 if (item
->item_flags
& MF_POPUP
)
2324 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( (HMENU16
)item
->item_id
);
2325 if (!menu
) return -1;
2326 else return (menu
->nItems
<< 8) | (menu
->wFlags
& 0xff);
2329 /* Non POPUP Menus only return flags in the lower byte */
2330 return (item
->item_flags
& 0x00ff);
2334 /**********************************************************************
2335 * GetMenuItemCount16 (USER.263)
2337 INT16
GetMenuItemCount16( HMENU16 hMenu
)
2339 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2340 if (!menu
|| (menu
->wMagic
!= MENU_MAGIC
)) return -1;
2341 dprintf_menu( stddeb
,"GetMenuItemCount16(%04x) returning %d\n",
2342 hMenu
, menu
->nItems
);
2343 return menu
->nItems
;
2347 /**********************************************************************
2348 * GetMenuItemCount32 (USER32.261)
2350 INT32
GetMenuItemCount32( HMENU32 hMenu
)
2352 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2353 if (!menu
|| (menu
->wMagic
!= MENU_MAGIC
)) return -1;
2354 dprintf_menu( stddeb
,"GetMenuItemCount32(%04x) returning %d\n",
2355 hMenu
, menu
->nItems
);
2356 return menu
->nItems
;
2360 /**********************************************************************
2361 * GetMenuItemID16 (USER.264)
2363 UINT16
GetMenuItemID16( HMENU16 hMenu
, INT16 nPos
)
2367 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
2368 if ((nPos
< 0) || (nPos
>= menu
->nItems
)) return -1;
2369 if (menu
->items
[nPos
].item_flags
& MF_POPUP
) return -1;
2370 return menu
->items
[nPos
].item_id
;
2374 /**********************************************************************
2375 * GetMenuItemID32 (USER32.262)
2377 UINT32
GetMenuItemID32( HMENU32 hMenu
, INT32 nPos
)
2381 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
2382 if ((nPos
< 0) || (nPos
>= menu
->nItems
)) return -1;
2383 if (menu
->items
[nPos
].item_flags
& MF_POPUP
) return -1;
2384 return menu
->items
[nPos
].item_id
;
2388 /*******************************************************************
2389 * InsertMenu16 (USER.410)
2391 BOOL16
InsertMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
2392 UINT16 id
, SEGPTR data
)
2394 UINT32 pos32
= (UINT32
)pos
;
2395 if ((pos
== (UINT16
)-1) && (flags
& MF_BYPOSITION
)) pos32
= (UINT32
)-1;
2396 if (IS_STRING_ITEM(flags
) && data
)
2397 return InsertMenu32A( hMenu
, pos32
, flags
, id
,
2398 (LPSTR
)PTR_SEG_TO_LIN(data
) );
2399 return InsertMenu32A( hMenu
, pos32
, flags
, id
, (LPSTR
)data
);
2403 /*******************************************************************
2404 * InsertMenu32A (USER32.321)
2406 BOOL32
InsertMenu32A( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2407 UINT32 id
, LPCSTR str
)
2411 if (IS_STRING_ITEM(flags
) && str
)
2412 dprintf_menu( stddeb
, "InsertMenu: %04x %d %04x %04x '%s'\n",
2413 hMenu
, pos
, flags
, id
, str
);
2414 else dprintf_menu( stddeb
, "InsertMenu: %04x %d %04x %04x %08lx\n",
2415 hMenu
, pos
, flags
, id
, (DWORD
)str
);
2417 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
2419 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
2421 RemoveMenu32( hMenu
, pos
, flags
);
2425 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
2426 ((POPUPMENU
*)USER_HEAP_LIN_ADDR((HMENU16
)id
))->wFlags
|= MF_POPUP
;
2428 item
->hCheckBit
= hStdCheck
;
2429 item
->hUnCheckBit
= 0;
2434 /*******************************************************************
2435 * InsertMenu32W (USER32.324)
2437 BOOL32
InsertMenu32W( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2438 UINT32 id
, LPCWSTR str
)
2442 if (IS_STRING_ITEM(flags
) && str
)
2444 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
2445 ret
= InsertMenu32A( hMenu
, pos
, flags
, id
, newstr
);
2446 HeapFree( GetProcessHeap(), 0, newstr
);
2449 else return InsertMenu32A( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
2453 /*******************************************************************
2454 * AppendMenu16 (USER.411)
2456 BOOL16
AppendMenu16( HMENU16 hMenu
, UINT16 flags
, UINT16 id
, SEGPTR data
)
2458 return InsertMenu16( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
2462 /*******************************************************************
2463 * AppendMenu32A (USER32.4)
2465 BOOL32
AppendMenu32A( HMENU32 hMenu
, UINT32 flags
, UINT32 id
, LPCSTR data
)
2467 return InsertMenu32A( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
2471 /*******************************************************************
2472 * AppendMenu32W (USER32.5)
2474 BOOL32
AppendMenu32W( HMENU32 hMenu
, UINT32 flags
, UINT32 id
, LPCWSTR data
)
2476 return InsertMenu32W( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
2480 /**********************************************************************
2481 * RemoveMenu16 (USER.412)
2483 BOOL16
RemoveMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
2485 return RemoveMenu32( hMenu
, nPos
, wFlags
);
2489 /**********************************************************************
2490 * RemoveMenu32 (USER32.440)
2492 BOOL32
RemoveMenu32( HMENU32 hMenu
, UINT32 nPos
, UINT32 wFlags
)
2497 dprintf_menu(stddeb
,"RemoveMenu (%04x, %04x, %04x)\n",hMenu
, nPos
, wFlags
);
2498 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
2499 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
2503 if (IS_STRING_ITEM(item
->item_flags
) && item
->text
)
2504 HeapFree( SystemHeap
, 0, item
->text
);
2505 if (--menu
->nItems
== 0)
2507 HeapFree( SystemHeap
, 0, menu
->items
);
2512 while(nPos
< menu
->nItems
)
2518 menu
->items
= HeapReAlloc( SystemHeap
, 0, menu
->items
,
2519 menu
->nItems
* sizeof(MENUITEM
) );
2525 /**********************************************************************
2526 * DeleteMenu16 (USER.413)
2528 BOOL16
DeleteMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
2530 return DeleteMenu32( hMenu
, nPos
, wFlags
);
2534 /**********************************************************************
2535 * DeleteMenu32 (USER32.128)
2537 BOOL32
DeleteMenu32( HMENU32 hMenu
, UINT32 nPos
, UINT32 wFlags
)
2539 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
2540 if (!item
) return FALSE
;
2541 if (item
->item_flags
& MF_POPUP
) DestroyMenu32( (HMENU32
)item
->item_id
);
2542 /* nPos is now the position of the item */
2543 RemoveMenu32( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
2548 /*******************************************************************
2549 * ModifyMenu16 (USER.414)
2551 BOOL16
ModifyMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
2552 UINT16 id
, SEGPTR data
)
2554 if (IS_STRING_ITEM(flags
))
2555 return ModifyMenu32A( hMenu
, pos
, flags
, id
,
2556 (LPSTR
)PTR_SEG_TO_LIN(data
) );
2557 return ModifyMenu32A( hMenu
, pos
, flags
, id
, (LPSTR
)data
);
2561 /*******************************************************************
2562 * ModifyMenu32A (USER32.396)
2564 BOOL32
ModifyMenu32A( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2565 UINT32 id
, LPCSTR str
)
2569 if (IS_STRING_ITEM(flags
))
2571 dprintf_menu( stddeb
, "ModifyMenu: %04x %d %04x %04x '%s'\n",
2572 hMenu
, pos
, flags
, id
, str
? str
: "#NULL#" );
2573 if (!str
) return FALSE
;
2577 dprintf_menu( stddeb
, "ModifyMenu: %04x %d %04x %04x %08lx\n",
2578 hMenu
, pos
, flags
, id
, (DWORD
)str
);
2581 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
2582 return MENU_SetItemData( item
, flags
, id
, str
);
2586 /*******************************************************************
2587 * ModifyMenu32W (USER32.397)
2589 BOOL32
ModifyMenu32W( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2590 UINT32 id
, LPCWSTR str
)
2594 if (IS_STRING_ITEM(flags
) && str
)
2596 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
2597 ret
= ModifyMenu32A( hMenu
, pos
, flags
, id
, newstr
);
2598 HeapFree( GetProcessHeap(), 0, newstr
);
2601 else return ModifyMenu32A( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
2605 /**********************************************************************
2606 * CreatePopupMenu16 (USER.415)
2608 HMENU16
CreatePopupMenu16(void)
2610 return CreatePopupMenu32();
2614 /**********************************************************************
2615 * CreatePopupMenu32 (USER32.81)
2617 HMENU32
CreatePopupMenu32(void)
2622 if (!(hmenu
= CreateMenu32())) return 0;
2623 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
2624 menu
->wFlags
|= MF_POPUP
;
2629 /**********************************************************************
2630 * GetMenuCheckMarkDimensions (USER.417) (USER32.257)
2632 DWORD
GetMenuCheckMarkDimensions(void)
2634 return MAKELONG( check_bitmap_width
, check_bitmap_height
);
2638 /**********************************************************************
2639 * SetMenuItemBitmaps16 (USER.418)
2641 BOOL16
SetMenuItemBitmaps16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
,
2642 HBITMAP16 hNewUnCheck
, HBITMAP16 hNewCheck
)
2644 return SetMenuItemBitmaps32( hMenu
, nPos
, wFlags
, hNewUnCheck
, hNewCheck
);
2648 /**********************************************************************
2649 * SetMenuItemBitmaps32 (USER32.489)
2651 BOOL32
SetMenuItemBitmaps32( HMENU32 hMenu
, UINT32 nPos
, UINT32 wFlags
,
2652 HBITMAP32 hNewUnCheck
, HBITMAP32 hNewCheck
)
2655 dprintf_menu(stddeb
,"SetMenuItemBitmaps(%04x, %04x, %04x, %04x, %04x)\n",
2656 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
2657 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
2659 if (!hNewCheck
&& !hNewUnCheck
)
2661 /* If both are NULL, restore default bitmaps */
2662 item
->hCheckBit
= hStdCheck
;
2663 item
->hUnCheckBit
= 0;
2664 item
->item_flags
&= ~MF_USECHECKBITMAPS
;
2666 else /* Install new bitmaps */
2668 item
->hCheckBit
= hNewCheck
;
2669 item
->hUnCheckBit
= hNewUnCheck
;
2670 item
->item_flags
|= MF_USECHECKBITMAPS
;
2676 /**********************************************************************
2677 * CreateMenu16 (USER.151)
2679 HMENU16
CreateMenu16(void)
2681 return CreateMenu32();
2685 /**********************************************************************
2686 * CreateMenu32 (USER32.80)
2688 HMENU32
CreateMenu32(void)
2692 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) ))) return 0;
2693 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2695 menu
->wMagic
= MENU_MAGIC
;
2702 menu
->FocusedItem
= NO_SELECTED_ITEM
;
2703 dprintf_menu( stddeb
, "CreateMenu: return %04x\n", hMenu
);
2708 /**********************************************************************
2709 * DestroyMenu16 (USER.152)
2711 BOOL16
DestroyMenu16( HMENU16 hMenu
)
2713 return DestroyMenu32( hMenu
);
2717 /**********************************************************************
2718 * DestroyMenu32 (USER32.133)
2720 BOOL32
DestroyMenu32( HMENU32 hMenu
)
2723 dprintf_menu(stddeb
,"DestroyMenu(%04x)\n", hMenu
);
2725 if (hMenu
== 0) return FALSE
;
2726 /* Silently ignore attempts to destroy default system menu */
2727 if (hMenu
== MENU_DefSysMenu
) return TRUE
;
2728 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2729 if (!lppop
|| (lppop
->wMagic
!= MENU_MAGIC
)) return FALSE
;
2730 lppop
->wMagic
= 0; /* Mark it as destroyed */
2731 if ((lppop
->wFlags
& MF_POPUP
) &&
2733 (!pTopPWnd
|| (lppop
->hWnd
!= pTopPWnd
->hwndSelf
)))
2734 DestroyWindow32( lppop
->hWnd
);
2739 MENUITEM
*item
= lppop
->items
;
2740 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
2742 if (item
->item_flags
& MF_POPUP
)
2743 DestroyMenu32( (HMENU32
)item
->item_id
);
2744 if (IS_STRING_ITEM(item
->item_flags
) && item
->text
)
2745 HeapFree( SystemHeap
, 0, item
->text
);
2747 HeapFree( SystemHeap
, 0, lppop
->items
);
2749 USER_HEAP_FREE( hMenu
);
2754 /**********************************************************************
2755 * GetSystemMenu16 (USER.156)
2757 HMENU16
GetSystemMenu16( HWND16 hWnd
, BOOL16 bRevert
)
2759 return GetSystemMenu32( hWnd
, bRevert
);
2763 /**********************************************************************
2764 * GetSystemMenu32 (USER32.290)
2766 HMENU32
GetSystemMenu32( HWND32 hWnd
, BOOL32 bRevert
)
2768 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
2769 if (!wndPtr
) return 0;
2771 if (!wndPtr
->hSysMenu
|| (wndPtr
->hSysMenu
== MENU_DefSysMenu
))
2773 wndPtr
->hSysMenu
= MENU_CopySysMenu();
2774 return wndPtr
->hSysMenu
;
2776 if (!bRevert
) return wndPtr
->hSysMenu
;
2777 if (wndPtr
->hSysMenu
) DestroyMenu32(wndPtr
->hSysMenu
);
2778 wndPtr
->hSysMenu
= MENU_CopySysMenu();
2779 return wndPtr
->hSysMenu
;
2783 /*******************************************************************
2784 * SetSystemMenu16 (USER.280)
2786 BOOL16
SetSystemMenu16( HWND16 hwnd
, HMENU16 hMenu
)
2788 return SetSystemMenu32( hwnd
, hMenu
);
2792 /*******************************************************************
2793 * SetSystemMenu32 (USER32.507)
2795 BOOL32
SetSystemMenu32( HWND32 hwnd
, HMENU32 hMenu
)
2799 if (!(wndPtr
= WIN_FindWndPtr(hwnd
))) return FALSE
;
2800 if (wndPtr
->hSysMenu
&& (wndPtr
->hSysMenu
!= MENU_DefSysMenu
))
2801 DestroyMenu32( wndPtr
->hSysMenu
);
2802 wndPtr
->hSysMenu
= hMenu
;
2807 /**********************************************************************
2808 * GetMenu16 (USER.157)
2810 HMENU16
GetMenu16( HWND16 hWnd
)
2812 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
2813 if (wndPtr
) return (HMENU16
)wndPtr
->wIDmenu
;
2818 /**********************************************************************
2819 * GetMenu32 (USER32.256)
2821 HMENU32
GetMenu32( HWND32 hWnd
)
2823 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
2824 if (wndPtr
) return (HMENU32
)wndPtr
->wIDmenu
;
2829 /**********************************************************************
2830 * SetMenu16 (USER.158)
2832 BOOL16
SetMenu16( HWND16 hWnd
, HMENU16 hMenu
)
2834 return SetMenu32( hWnd
, hMenu
);
2838 /**********************************************************************
2839 * SetMenu32 (USER32.486)
2841 BOOL32
SetMenu32( HWND32 hWnd
, HMENU32 hMenu
)
2844 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
2845 if (!wndPtr
) return FALSE
;
2846 dprintf_menu(stddeb
,"SetMenu(%04x, %04x);\n", hWnd
, hMenu
);
2847 if (GetCapture32() == hWnd
) ReleaseCapture();
2848 wndPtr
->wIDmenu
= (UINT32
)hMenu
;
2851 if (!(lpmenu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
2852 lpmenu
->hWnd
= hWnd
;
2853 lpmenu
->wFlags
&= ~MF_POPUP
; /* Can't be a popup */
2854 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
2856 if (IsWindowVisible32(hWnd
))
2857 SetWindowPos32( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
2858 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
2864 /**********************************************************************
2865 * GetSubMenu16 (USER.159)
2867 HMENU16
GetSubMenu16( HMENU16 hMenu
, INT16 nPos
)
2869 return GetSubMenu32( hMenu
, nPos
);
2873 /**********************************************************************
2874 * GetSubMenu32 (USER32.287)
2876 HMENU32
GetSubMenu32( HMENU32 hMenu
, INT32 nPos
)
2880 if (!(lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return 0;
2881 if ((UINT32
)nPos
>= lppop
->nItems
) return 0;
2882 if (!(lppop
->items
[nPos
].item_flags
& MF_POPUP
)) return 0;
2883 return (HMENU32
)lppop
->items
[nPos
].item_id
;
2887 /**********************************************************************
2888 * DrawMenuBar16 (USER.160)
2890 void DrawMenuBar16( HWND16 hWnd
)
2892 DrawMenuBar32( hWnd
);
2896 /**********************************************************************
2897 * DrawMenuBar32 (USER32.160)
2899 BOOL32
DrawMenuBar32( HWND32 hWnd
)
2902 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
2903 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
) && wndPtr
->wIDmenu
)
2905 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR((HMENU16
)wndPtr
->wIDmenu
);
2906 if (lppop
== NULL
) return FALSE
;
2908 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
2909 SetWindowPos32( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
2910 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
2917 /***********************************************************************
2918 * EndMenu (USER.187) (USER32.174)
2922 /* FIXME: this won't work when we have multiple tasks... */
2923 fEndMenuCalled
= TRUE
;
2927 /***********************************************************************
2928 * LookupMenuHandle (USER.217)
2930 HMENU16
LookupMenuHandle( HMENU16 hmenu
, INT16 id
)
2932 HMENU32 hmenu32
= hmenu
;
2934 if (!MENU_FindItem( &hmenu32
, &id32
, MF_BYCOMMAND
)) return 0;
2935 else return hmenu32
;
2939 /**********************************************************************
2940 * LoadMenu16 (USER.150)
2942 HMENU16
LoadMenu16( HINSTANCE16 instance
, SEGPTR name
)
2950 char *str
= (char *)PTR_SEG_TO_LIN( name
);
2951 dprintf_menu( stddeb
, "LoadMenu(%04x,'%s')\n", instance
, str
);
2952 if (str
[0] == '#') name
= (SEGPTR
)atoi( str
+ 1 );
2955 dprintf_resource(stddeb
,"LoadMenu(%04x,%04x)\n",instance
,LOWORD(name
));
2957 if (!name
) return 0;
2959 /* check for Win32 module */
2960 instance
= GetExePtr( instance
);
2961 if (MODULE_GetPtr(instance
)->flags
& NE_FFLAGS_WIN32
)
2962 return LoadMenu32A(instance
,PTR_SEG_TO_LIN(name
));
2964 if (!(hRsrc
= FindResource16( instance
, name
, RT_MENU
))) return 0;
2965 if (!(handle
= LoadResource16( instance
, hRsrc
))) return 0;
2966 hMenu
= LoadMenuIndirect16(LockResource16(handle
));
2967 FreeResource16( handle
);
2972 /*****************************************************************
2973 * LoadMenu32A (USER32.370)
2975 HMENU32
LoadMenu32A( HINSTANCE32 instance
, LPCSTR name
)
2977 HRSRC32 hrsrc
= FindResource32A( instance
, name
, (LPSTR
)RT_MENU
);
2978 if (!hrsrc
) return 0;
2979 return LoadMenuIndirect32A( (LPCVOID
)LoadResource32( instance
, hrsrc
));
2983 /*****************************************************************
2984 * LoadMenu32W (USER32.372)
2986 HMENU32
LoadMenu32W( HINSTANCE32 instance
, LPCWSTR name
)
2988 HRSRC32 hrsrc
= FindResource32W( instance
, name
, (LPWSTR
)RT_MENU
);
2989 if (!hrsrc
) return 0;
2990 return LoadMenuIndirect32W( (LPCVOID
)LoadResource32( instance
, hrsrc
));
2994 /**********************************************************************
2995 * LoadMenuIndirect16 (USER.220)
2997 HMENU16
LoadMenuIndirect16( LPCVOID
template )
3000 WORD version
, offset
;
3001 LPCSTR p
= (LPCSTR
)template;
3003 dprintf_menu(stddeb
,"LoadMenuIndirect16: %p\n", template );
3004 version
= GET_WORD(p
);
3008 fprintf( stderr
, "LoadMenuIndirect16: version must be 0 for Win16\n" );
3011 offset
= GET_WORD(p
);
3012 p
+= sizeof(WORD
) + offset
;
3013 if (!(hMenu
= CreateMenu32())) return 0;
3014 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
3016 DestroyMenu32( hMenu
);
3023 /**********************************************************************
3024 * LoadMenuIndirect32A (USER32.370)
3026 HMENU32
LoadMenuIndirect32A( LPCVOID
template )
3029 WORD version
, offset
;
3030 LPCSTR p
= (LPCSTR
)template;
3032 dprintf_menu(stddeb
,"LoadMenuIndirect16: %p\n", template );
3033 version
= GET_WORD(p
);
3037 fprintf( stderr
, "LoadMenuIndirect32A: version %d not supported.\n",
3041 offset
= GET_WORD(p
);
3042 p
+= sizeof(WORD
) + offset
;
3043 if (!(hMenu
= CreateMenu32())) return 0;
3044 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
3046 DestroyMenu32( hMenu
);
3053 /**********************************************************************
3054 * LoadMenuIndirect32W (USER32.371)
3056 HMENU32
LoadMenuIndirect32W( LPCVOID
template )
3058 /* FIXME: is there anything different between A and W? */
3059 return LoadMenuIndirect32A( template );
3063 /**********************************************************************
3064 * IsMenu16 (USER.358)
3066 BOOL16
IsMenu16( HMENU16 hmenu
)
3069 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
3070 return (menu
->wMagic
== MENU_MAGIC
);
3074 /**********************************************************************
3075 * IsMenu32 (USER32.345)
3077 BOOL32
IsMenu32( HMENU32 hmenu
)
3080 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
3081 return (menu
->wMagic
== MENU_MAGIC
);