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.
14 #define NO_TRANSITION_TYPES /* This file is Win32-clean */
21 #include "sysmetrics.h"
28 #include "nonclient.h"
36 /* Menu item structure */
39 UINT32 item_flags
; /* Item flags */
40 UINT32 item_id
; /* Item or popup id */
41 RECT32 rect
; /* Item area (relative to menu window) */
42 UINT32 xTab
; /* X position of text after Tab */
43 HBITMAP32 hCheckBit
; /* Bitmap for checked item */
44 HBITMAP32 hUnCheckBit
; /* Bitmap for unchecked item */
45 LPSTR text
; /* Item text or bitmap handle */
48 /* Popup menu structure */
51 WORD wFlags
; /* Menu flags (MF_POPUP, MF_SYSMENU) */
52 WORD wMagic
; /* Magic number */
53 HQUEUE16 hTaskQ
; /* Task queue for this menu */
54 WORD Width
; /* Width of the whole menu */
55 WORD Height
; /* Height of the whole menu */
56 WORD nItems
; /* Number of items in the menu */
57 HWND32 hWnd
; /* Window containing the menu */
58 MENUITEM
*items
; /* Array of menu items */
59 UINT32 FocusedItem
; /* Currently focused item */
60 } POPUPMENU
, *LPPOPUPMENU
;
62 #define MENU_MAGIC 0x554d /* 'MU' */
67 /* Dimension of the menu bitmaps */
68 static WORD check_bitmap_width
= 0, check_bitmap_height
= 0;
69 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
71 /* Flag set by EndMenu() to force an exit from menu tracking */
72 static BOOL32 fEndMenuCalled
= FALSE
;
74 /* Space between 2 menu bar items */
75 #define MENU_BAR_ITEMS_SPACE 16
77 /* Minimum width of a tab character */
78 #define MENU_TAB_SPACE 8
80 /* Height of a separator item */
81 #define SEPARATOR_HEIGHT 5
83 /* Values for menu->FocusedItem */
84 /* (other values give the position of the focused item) */
85 #define NO_SELECTED_ITEM 0xffff
86 #define SYSMENU_SELECTED 0xfffe /* Only valid on menu-bars */
88 #define IS_STRING_ITEM(flags) \
89 (!((flags) & (MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)))
91 static HBITMAP32 hStdCheck
= 0;
92 static HBITMAP32 hStdMnArrow
= 0;
93 static HMENU32 MENU_DefSysMenu
= 0; /* Default system menu */
96 /* we _can_ use global popup window because there's no way 2 menues can
97 * be tracked at the same time.
100 static WND
* pTopPWnd
= 0;
101 static UINT32 uSubPWndLevel
= 0;
104 /**********************************************************************
107 * Load a copy of the system menu.
109 static HMENU32
MENU_CopySysMenu(void)
114 if (!(hMenu
= LoadMenuIndirect32A( SYSRES_GetResPtr(SYSRES_MENU_SYSMENU
))))
116 dprintf_menu(stddeb
,"No SYSMENU\n");
119 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
120 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
121 dprintf_menu(stddeb
,"CopySysMenu hMenu=%04x !\n", hMenu
);
126 /***********************************************************************
129 * Menus initialisation.
137 if (!(hStdCheck
= LoadBitmap32A( 0, (LPSTR
)MAKEINTRESOURCE(OBM_CHECK
) )))
139 GetObject32A( hStdCheck
, sizeof(bm
), &bm
);
140 check_bitmap_width
= bm
.bmWidth
;
141 check_bitmap_height
= bm
.bmHeight
;
142 if (!(hStdMnArrow
= LoadBitmap32A(0,(LPSTR
)MAKEINTRESOURCE(OBM_MNARROW
))))
144 GetObject32A( hStdMnArrow
, sizeof(bm
), &bm
);
145 arrow_bitmap_width
= bm
.bmWidth
;
146 arrow_bitmap_height
= bm
.bmHeight
;
148 if (!(MENU_DefSysMenu
= MENU_CopySysMenu()))
150 fprintf( stderr
, "Unable to create default system menu\n" );
157 /***********************************************************************
160 * Return the default system menu.
162 HMENU32
MENU_GetDefSysMenu(void)
164 return MENU_DefSysMenu
;
168 /***********************************************************************
171 * Check whether the window owning the menu bar has a system menu.
173 static BOOL32
MENU_HasSysMenu( POPUPMENU
*menu
)
177 if (menu
->wFlags
& MF_POPUP
) return FALSE
;
178 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return FALSE
;
179 return (wndPtr
->dwStyle
& WS_SYSMENU
) != 0;
183 /***********************************************************************
186 * Check whether the point (in screen coords) is in the system menu
187 * of the window owning the given menu.
189 static BOOL32
MENU_IsInSysMenu( POPUPMENU
*menu
, POINT32 pt
)
193 if (menu
->wFlags
& MF_POPUP
) return FALSE
;
194 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return FALSE
;
195 if (!(wndPtr
->dwStyle
& WS_SYSMENU
)) return FALSE
;
196 if ((pt
.x
< wndPtr
->rectClient
.left
) ||
197 (pt
.x
>= wndPtr
->rectClient
.left
+SYSMETRICS_CXSIZE
+SYSMETRICS_CXBORDER
))
199 if ((pt
.y
>= wndPtr
->rectClient
.top
- menu
->Height
) ||
200 (pt
.y
< wndPtr
->rectClient
.top
- menu
->Height
-
201 SYSMETRICS_CYSIZE
- SYSMETRICS_CYBORDER
)) return FALSE
;
206 /***********************************************************************
207 * MENU_InitSysMenuPopup
209 * Grey the appropriate items in System menu.
211 void MENU_InitSysMenuPopup( HMENU32 hmenu
, DWORD style
, DWORD clsStyle
)
215 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
216 EnableMenuItem32( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
217 gray
= ((style
& WS_MAXIMIZE
) != 0);
218 EnableMenuItem32( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
219 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
220 EnableMenuItem32( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
221 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
222 EnableMenuItem32( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
223 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
224 EnableMenuItem32( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
225 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
226 EnableMenuItem32( hmenu
, SC_CLOSE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
230 /***********************************************************************
233 * Find a menu item. Return a pointer on the item, and modifies *hmenu
234 * in case the item was in a sub-menu.
236 static MENUITEM
*MENU_FindItem( HMENU32
*hmenu
, UINT32
*nPos
, UINT32 wFlags
)
241 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(*hmenu
))) return NULL
;
242 if (wFlags
& MF_BYPOSITION
)
244 if (*nPos
>= menu
->nItems
) return NULL
;
245 return &menu
->items
[*nPos
];
249 MENUITEM
*item
= menu
->items
;
250 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
252 if (item
->item_id
== *nPos
)
257 else if (item
->item_flags
& MF_POPUP
)
259 HMENU32 hsubmenu
= (HMENU32
)item
->item_id
;
260 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
273 /***********************************************************************
274 * MENU_FindItemByCoords
276 * Find the item at the specified coordinates (screen coords).
278 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
, INT32 x
, INT32 y
,
285 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return NULL
;
286 x
-= wndPtr
->rectWindow
.left
;
287 y
-= wndPtr
->rectWindow
.top
;
289 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
291 if ((x
>= item
->rect
.left
) && (x
< item
->rect
.right
) &&
292 (y
>= item
->rect
.top
) && (y
< item
->rect
.bottom
))
302 /***********************************************************************
305 * Find the menu item selected by a key press.
306 * Return item id, -1 if none, -2 if we should close the menu.
308 static UINT32
MENU_FindItemByKey( HWND32 hwndOwner
, HMENU32 hmenu
, UINT32 key
)
315 if (!IsMenu32( hmenu
)) hmenu
= WIN_FindWndPtr(hwndOwner
)->hSysMenu
;
316 if (!hmenu
) return -1;
318 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
321 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
323 if (IS_STRING_ITEM(item
->item_flags
))
325 char *p
= strchr( item
->text
, '&' );
326 if (p
&& (p
[1] != '&') && (toupper(p
[1]) == key
)) return i
;
329 menuchar
= SendMessage32A( hwndOwner
, WM_MENUCHAR
,
330 MAKEWPARAM( key
, menu
->wFlags
), hmenu
);
331 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
332 if (HIWORD(menuchar
) == 1) return -2;
337 /***********************************************************************
340 * Calculate the size of the menu item and store it in lpitem->rect.
342 static void MENU_CalcItemSize( HDC32 hdc
, MENUITEM
*lpitem
, HWND32 hwndOwner
,
343 INT32 orgX
, INT32 orgY
, BOOL32 menuBar
)
348 SetRect32( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
350 if (lpitem
->item_flags
& MF_OWNERDRAW
)
352 MEASUREITEMSTRUCT32 mis
;
353 mis
.CtlType
= ODT_MENU
;
354 mis
.itemID
= lpitem
->item_id
;
355 mis
.itemData
= (DWORD
)lpitem
->text
;
358 SendMessage32A( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
359 lpitem
->rect
.bottom
+= mis
.itemHeight
;
360 lpitem
->rect
.right
+= mis
.itemWidth
;
361 dprintf_menu( stddeb
, "DrawMenuItem: MeasureItem %04x %dx%d!\n",
362 lpitem
->item_id
, mis
.itemWidth
, mis
.itemHeight
);
366 if (lpitem
->item_flags
& MF_SEPARATOR
)
368 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
374 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
375 if (lpitem
->item_flags
& MF_POPUP
)
376 lpitem
->rect
.right
+= arrow_bitmap_width
;
379 if (lpitem
->item_flags
& MF_BITMAP
)
382 if (GetObject32A( (HBITMAP32
)lpitem
->text
, sizeof(bm
), &bm
))
384 lpitem
->rect
.right
+= bm
.bmWidth
;
385 lpitem
->rect
.bottom
+= bm
.bmHeight
;
390 /* If we get here, then it must be a text item */
392 if (IS_STRING_ITEM( lpitem
->item_flags
))
394 dwSize
= GetTextExtent( hdc
, lpitem
->text
, strlen(lpitem
->text
) );
395 lpitem
->rect
.right
+= LOWORD(dwSize
);
396 lpitem
->rect
.bottom
+= MAX( HIWORD(dwSize
), SYSMETRICS_CYMENU
);
399 if (menuBar
) lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
400 else if ((p
= strchr( lpitem
->text
, '\t' )) != NULL
)
402 /* Item contains a tab (only meaningful in popup menus) */
403 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+
404 LOWORD( GetTextExtent( hdc
, lpitem
->text
,
405 (int)(p
- lpitem
->text
) ));
406 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
410 if (strchr( lpitem
->text
, '\b' ))
411 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
412 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
413 - arrow_bitmap_width
;
419 /***********************************************************************
420 * MENU_PopupMenuCalcSize
422 * Calculate the size of a popup menu.
424 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND32 hwndOwner
)
429 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
431 lppop
->Width
= lppop
->Height
= 0;
432 if (lppop
->nItems
== 0) return;
435 while (start
< lppop
->nItems
)
437 lpitem
= &lppop
->items
[start
];
440 maxTab
= maxTabWidth
= 0;
442 /* Parse items until column break or end of menu */
443 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
446 (lpitem
->item_flags
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
447 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
448 if (lpitem
->item_flags
& MF_MENUBARBREAK
) orgX
++;
449 maxX
= MAX( maxX
, lpitem
->rect
.right
);
450 orgY
= lpitem
->rect
.bottom
;
451 if (IS_STRING_ITEM(lpitem
->item_flags
) && lpitem
->xTab
)
453 maxTab
= MAX( maxTab
, lpitem
->xTab
);
454 maxTabWidth
= MAX(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
458 /* Finish the column (set all items to the largest width found) */
459 maxX
= MAX( maxX
, maxTab
+ maxTabWidth
);
460 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
462 lpitem
->rect
.right
= maxX
;
463 if (IS_STRING_ITEM(lpitem
->item_flags
) && lpitem
->xTab
)
464 lpitem
->xTab
= maxTab
;
466 lppop
->Height
= MAX( lppop
->Height
, orgY
);
470 ReleaseDC32( 0, hdc
);
474 /***********************************************************************
475 * MENU_MenuBarCalcSize
477 * Calculate the size of the menu bar.
479 static void MENU_MenuBarCalcSize( HDC32 hdc
, LPRECT32 lprect
,
480 LPPOPUPMENU lppop
, HWND32 hwndOwner
)
483 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
485 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
486 if (lppop
->nItems
== 0) return;
487 dprintf_menu(stddeb
,"MENU_MenuBarCalcSize left=%d top=%d right=%d bottom=%d\n",
488 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
489 lppop
->Width
= lprect
->right
- lprect
->left
;
494 while (start
< lppop
->nItems
)
496 lpitem
= &lppop
->items
[start
];
500 /* Parse items until line break or end of menu */
501 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
503 if ((helpPos
== -1) && (lpitem
->item_flags
& MF_HELP
)) helpPos
= i
;
505 (lpitem
->item_flags
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
506 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
507 if (lpitem
->rect
.right
> lprect
->right
)
509 if (i
!= start
) break;
510 else lpitem
->rect
.right
= lprect
->right
;
512 maxY
= MAX( maxY
, lpitem
->rect
.bottom
);
513 orgX
= lpitem
->rect
.right
;
516 /* Finish the line (set all items to the largest height found) */
517 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
520 lprect
->bottom
= maxY
;
521 lppop
->Height
= lprect
->bottom
- lprect
->top
;
523 /* Flush right all items between the MF_HELP and the last item */
524 /* (if several lines, only move the last line) */
527 lpitem
= &lppop
->items
[lppop
->nItems
-1];
528 orgY
= lpitem
->rect
.top
;
529 orgX
= lprect
->right
;
530 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--)
532 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
533 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
534 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
535 lpitem
->rect
.right
= orgX
;
536 orgX
= lpitem
->rect
.left
;
542 /***********************************************************************
545 * Draw a single menu item.
547 static void MENU_DrawMenuItem( HWND32 hwnd
, HDC32 hdc
, MENUITEM
*lpitem
,
548 UINT32 height
, BOOL32 menuBar
)
552 if (lpitem
->item_flags
& MF_OWNERDRAW
)
554 DRAWITEMSTRUCT32 dis
;
556 dprintf_menu( stddeb
, "DrawMenuItem: Ownerdraw!\n" );
557 dis
.CtlType
= ODT_MENU
;
558 dis
.itemID
= lpitem
->item_id
;
559 dis
.itemData
= (DWORD
)lpitem
->text
;
561 if (lpitem
->item_flags
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
562 if (lpitem
->item_flags
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
;
563 if (lpitem
->item_flags
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
564 dis
.itemAction
= ODA_DRAWENTIRE
| ODA_SELECT
| ODA_FOCUS
;
567 dis
.rcItem
= lpitem
->rect
;
568 SendMessage32A( hwnd
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
572 if (menuBar
&& (lpitem
->item_flags
& MF_SEPARATOR
)) return;
575 /* Draw the background */
577 if (lpitem
->item_flags
& MF_HILITE
)
578 FillRect32( hdc
, &rect
, sysColorObjects
.hbrushHighlight
);
579 else FillRect32( hdc
, &rect
, sysColorObjects
.hbrushMenu
);
580 SetBkMode32( hdc
, TRANSPARENT
);
582 /* Draw the separator bar (if any) */
584 if (!menuBar
&& (lpitem
->item_flags
& MF_MENUBARBREAK
))
586 SelectObject32( hdc
, sysColorObjects
.hpenWindowFrame
);
587 MoveTo( hdc
, rect
.left
, 0 );
588 LineTo32( hdc
, rect
.left
, height
);
590 if (lpitem
->item_flags
& MF_SEPARATOR
)
592 SelectObject32( hdc
, sysColorObjects
.hpenWindowFrame
);
593 MoveTo( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
594 LineTo32( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
600 if (lpitem
->item_flags
& MF_HILITE
)
602 if (lpitem
->item_flags
& MF_GRAYED
)
603 SetTextColor( hdc
, GetSysColor32( COLOR_GRAYTEXT
) );
605 SetTextColor( hdc
, GetSysColor32( COLOR_HIGHLIGHTTEXT
) );
606 SetBkColor( hdc
, GetSysColor32( COLOR_HIGHLIGHT
) );
610 if (lpitem
->item_flags
& MF_GRAYED
)
611 SetTextColor( hdc
, GetSysColor32( COLOR_GRAYTEXT
) );
613 SetTextColor( hdc
, GetSysColor32( COLOR_MENUTEXT
) );
614 SetBkColor( hdc
, GetSysColor32( COLOR_MENU
) );
619 /* Draw the check mark */
621 if (lpitem
->item_flags
& MF_CHECKED
)
623 GRAPH_DrawBitmap(hdc
, lpitem
->hCheckBit
? lpitem
->hCheckBit
:
624 hStdCheck
, rect
.left
,
625 (rect
.top
+rect
.bottom
-check_bitmap_height
) / 2,
626 0, 0, check_bitmap_width
, check_bitmap_height
);
628 else if (lpitem
->hUnCheckBit
!= 0) /* Not checked */
630 GRAPH_DrawBitmap(hdc
, lpitem
->hUnCheckBit
, rect
.left
,
631 (rect
.top
+rect
.bottom
-check_bitmap_height
) / 2,
632 0, 0, check_bitmap_width
, check_bitmap_height
);
635 /* Draw the popup-menu arrow */
637 if (lpitem
->item_flags
& MF_POPUP
)
639 GRAPH_DrawBitmap( hdc
, hStdMnArrow
,
640 rect
.right
-arrow_bitmap_width
-1,
641 (rect
.top
+rect
.bottom
-arrow_bitmap_height
) / 2,
642 0, 0, arrow_bitmap_width
, arrow_bitmap_height
);
645 rect
.left
+= check_bitmap_width
;
646 rect
.right
-= arrow_bitmap_width
;
649 /* Draw the item text or bitmap */
651 if (lpitem
->item_flags
& MF_BITMAP
)
653 GRAPH_DrawBitmap( hdc
, (HBITMAP32
)lpitem
->text
,
654 rect
.left
, rect
.top
, 0, 0,
655 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
);
658 /* No bitmap - process text if present */
659 else if (IS_STRING_ITEM(lpitem
->item_flags
))
665 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
666 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
667 i
= strlen( lpitem
->text
);
671 for (i
= 0; lpitem
->text
[i
]; i
++)
672 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
676 DrawText32A( hdc
, lpitem
->text
, i
, &rect
,
677 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
679 if (lpitem
->text
[i
]) /* There's a tab or flush-right char */
681 if (lpitem
->text
[i
] == '\t')
683 rect
.left
= lpitem
->xTab
;
684 DrawText32A( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
,
685 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
687 else DrawText32A( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
,
688 DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
);
694 /***********************************************************************
697 * Paint a popup menu.
699 static void MENU_DrawPopupMenu( HWND32 hwnd
, HDC32 hdc
, HMENU32 hmenu
)
706 GetClientRect32( hwnd
, &rect
);
707 FillRect32( hdc
, &rect
, sysColorObjects
.hbrushMenu
);
708 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
709 if (!menu
|| !menu
->nItems
) return;
710 for (i
= menu
->nItems
, item
= menu
->items
; i
> 0; i
--, item
++)
711 MENU_DrawMenuItem( hwnd
, hdc
, item
, menu
->Height
, FALSE
);
715 /***********************************************************************
718 * Paint a menu bar. Returns the height of the menu bar.
720 UINT32
MENU_DrawMenuBar( HDC32 hDC
, LPRECT32 lprect
, HWND32 hwnd
,
721 BOOL32 suppress_draw
)
725 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
727 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( (HMENU16
)wndPtr
->wIDmenu
);
728 if (lppop
== NULL
|| lprect
== NULL
) return SYSMETRICS_CYMENU
;
729 dprintf_menu(stddeb
,"MENU_DrawMenuBar(%04x, %p, %p); !\n",
731 if (lppop
->Height
== 0) MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
732 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
733 if (suppress_draw
) return lppop
->Height
;
735 FillRect32(hDC
, lprect
, sysColorObjects
.hbrushMenu
);
736 SelectObject32( hDC
, sysColorObjects
.hpenWindowFrame
);
737 MoveTo( hDC
, lprect
->left
, lprect
->bottom
);
738 LineTo32( hDC
, lprect
->right
, lprect
->bottom
);
740 if (lppop
->nItems
== 0) return SYSMETRICS_CYMENU
;
741 for (i
= 0; i
< lppop
->nItems
; i
++)
743 MENU_DrawMenuItem( hwnd
, hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
);
745 return lppop
->Height
;
749 /***********************************************************************
752 BOOL32
MENU_SwitchTPWndTo( HTASK16 hTask
)
754 /* This is supposed to be called when popup is hidden.
755 * AppExit() calls with hTask == 0, so we get the next to current.
760 if( !pTopPWnd
) return 0;
764 task
= (TDB
*)GlobalLock16( (hTask
= GetCurrentTask()) );
765 if( task
&& task
->hQueue
== pTopPWnd
->hmemTaskQ
)
766 hTask
= TASK_GetNextTask(hTask
);
770 task
= (TDB
*)GlobalLock16(hTask
);
771 if( !task
) return 0;
773 /* if this task got as far as menu tracking it must have a queue */
775 pTopPWnd
->hInstance
= task
->hInstance
;
776 pTopPWnd
->hmemTaskQ
= task
->hQueue
;
780 /***********************************************************************
783 * Display a popup menu.
785 static BOOL32
MENU_ShowPopup( HWND32 hwndOwner
, HMENU32 hmenu
, UINT32 id
,
786 INT32 x
, INT32 y
, INT32 xanchor
, INT32 yanchor
)
790 BOOL32 skip_init
= 0;
791 UINT32 width
, height
;
793 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
794 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
796 menu
->items
[menu
->FocusedItem
].item_flags
&= ~(MF_HILITE
|MF_MOUSESELECT
);
797 menu
->FocusedItem
= NO_SELECTED_ITEM
;
799 SendMessage16( hwndOwner
, WM_INITMENUPOPUP
, (WPARAM16
)hmenu
,
800 MAKELONG( id
, (menu
->wFlags
& MF_SYSMENU
) ? 1 : 0 ));
801 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
803 /* adjust popup menu pos so that it fits within the desktop */
805 width
= menu
->Width
+ 2*SYSMETRICS_CXBORDER
;
806 height
= menu
->Height
+ 2*SYSMETRICS_CYBORDER
;
808 if( x
+ width
> SYSMETRICS_CXSCREEN
)
811 x
-= width
- xanchor
;
812 if( x
+ width
> SYSMETRICS_CXSCREEN
)
813 x
= SYSMETRICS_CXSCREEN
- width
;
818 if( y
+ height
> SYSMETRICS_CYSCREEN
)
821 y
-= height
+ yanchor
;
822 if( y
+ height
> SYSMETRICS_CYSCREEN
)
823 y
= SYSMETRICS_CYSCREEN
- height
;
828 wndPtr
= WIN_FindWndPtr( hwndOwner
);
829 if (!wndPtr
) return FALSE
;
833 pTopPWnd
= WIN_FindWndPtr(CreateWindow32A( POPUPMENU_CLASS_ATOM
, NULL
,
834 WS_POPUP
| WS_BORDER
, x
, y
,
836 hwndOwner
, 0, wndPtr
->hInstance
,
838 if (!pTopPWnd
) return FALSE
;
844 /* create new window for the submenu */
845 HWND32 hWnd
= CreateWindow32A( POPUPMENU_CLASS_ATOM
, NULL
,
846 WS_POPUP
| WS_BORDER
, x
, y
,
848 menu
->hWnd
, 0, wndPtr
->hInstance
,
850 if( !hWnd
) return FALSE
;
857 MENU_SwitchTPWndTo(GetCurrentTask());
858 SendMessage16( pTopPWnd
->hwndSelf
, WM_USER
, (WPARAM16
)hmenu
, 0L);
860 menu
->hWnd
= pTopPWnd
->hwndSelf
;
865 wndPtr
= WIN_FindWndPtr( menu
->hWnd
);
867 SetWindowPos32(menu
->hWnd
, 0, x
, y
, width
, height
,
868 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_NOREDRAW
);
869 /* Display the window */
871 SetWindowPos32( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
872 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
873 UpdateWindow( menu
->hWnd
);
878 /***********************************************************************
881 static void MENU_SelectItem( HWND32 hwndOwner
, HMENU32 hmenu
, UINT32 wIndex
,
882 BOOL32 sendMenuSelect
)
887 lppop
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
888 if (!lppop
->nItems
) return;
889 if ((wIndex
!= NO_SELECTED_ITEM
) &&
890 (wIndex
!= SYSMENU_SELECTED
) &&
891 (lppop
->items
[wIndex
].item_flags
& MF_SEPARATOR
))
892 wIndex
= NO_SELECTED_ITEM
;
893 if (lppop
->FocusedItem
== wIndex
) return;
894 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC32( lppop
->hWnd
);
895 else hdc
= GetDCEx32( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
897 /* Clear previous highlighted item */
898 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
900 if (lppop
->FocusedItem
== SYSMENU_SELECTED
)
901 NC_DrawSysButton( lppop
->hWnd
, hdc
, FALSE
);
904 lppop
->items
[lppop
->FocusedItem
].item_flags
&=~(MF_HILITE
|MF_MOUSESELECT
);
905 MENU_DrawMenuItem(lppop
->hWnd
,hdc
,&lppop
->items
[lppop
->FocusedItem
],
906 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
) );
910 /* Highlight new item (if any) */
911 lppop
->FocusedItem
= wIndex
;
912 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
914 if (lppop
->FocusedItem
== SYSMENU_SELECTED
)
916 NC_DrawSysButton( lppop
->hWnd
, hdc
, TRUE
);
918 SendMessage16( hwndOwner
, WM_MENUSELECT
,
919 WIN_FindWndPtr(lppop
->hWnd
)->hSysMenu
,
920 MAKELONG(lppop
->wFlags
| MF_MOUSESELECT
, hmenu
));
924 lppop
->items
[lppop
->FocusedItem
].item_flags
|= MF_HILITE
;
925 MENU_DrawMenuItem( lppop
->hWnd
, hdc
, &lppop
->items
[lppop
->FocusedItem
],
926 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
) );
928 SendMessage16( hwndOwner
, WM_MENUSELECT
,
929 lppop
->items
[lppop
->FocusedItem
].item_id
,
930 MAKELONG( lppop
->items
[lppop
->FocusedItem
].item_flags
| MF_MOUSESELECT
, hmenu
));
933 else if (sendMenuSelect
)
934 SendMessage16( hwndOwner
, WM_MENUSELECT
, hmenu
,
935 MAKELONG( lppop
->wFlags
| MF_MOUSESELECT
, hmenu
) );
937 ReleaseDC32( lppop
->hWnd
, hdc
);
941 /***********************************************************************
945 static void MENU_SelectItemRel( HWND32 hwndOwner
, HMENU32 hmenu
, INT32 offset
)
950 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
951 if (!menu
->items
) return;
952 if ((menu
->FocusedItem
!= NO_SELECTED_ITEM
) &&
953 (menu
->FocusedItem
!= SYSMENU_SELECTED
))
955 for (i
= menu
->FocusedItem
+ offset
; i
>= 0 && i
< menu
->nItems
958 if (!(menu
->items
[i
].item_flags
& MF_SEPARATOR
))
960 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
965 if (MENU_HasSysMenu( menu
))
967 MENU_SelectItem( hwndOwner
, hmenu
, SYSMENU_SELECTED
, TRUE
);
972 if( offset
> 0 ) { i
= 0; min
= -1; }
973 else i
= menu
->nItems
- 1;
975 for ( ; i
> min
&& i
< menu
->nItems
; i
+= offset
)
977 if (!(menu
->items
[i
].item_flags
& MF_SEPARATOR
))
979 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
983 if (MENU_HasSysMenu( menu
))
984 MENU_SelectItem( hwndOwner
, hmenu
, SYSMENU_SELECTED
, TRUE
);
988 /**********************************************************************
991 * Set an item flags, id and text ptr.
993 static BOOL32
MENU_SetItemData( MENUITEM
*item
, UINT32 flags
, UINT32 id
,
996 LPSTR prevText
= IS_STRING_ITEM(item
->item_flags
) ? item
->text
: NULL
;
998 if (IS_STRING_ITEM(flags
))
1002 flags
|= MF_SEPARATOR
;
1008 /* Item beginning with a backspace is a help item */
1014 if (!(text
= HEAP_strdupA( SystemHeap
, 0, str
))) return FALSE
;
1018 else if (flags
& MF_BITMAP
) item
->text
= (LPSTR
)(HBITMAP32
)LOWORD(str
);
1019 else if (flags
& MF_OWNERDRAW
) item
->text
= (LPSTR
)str
;
1020 else item
->text
= NULL
;
1022 item
->item_flags
= flags
& ~(MF_HILITE
| MF_MOUSESELECT
);
1024 SetRectEmpty32( &item
->rect
);
1025 if (prevText
) HeapFree( SystemHeap
, 0, prevText
);
1030 /**********************************************************************
1033 * Insert a new item into a menu.
1035 static MENUITEM
*MENU_InsertItem( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
)
1040 if (!(menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
)))
1042 dprintf_menu( stddeb
, "MENU_InsertItem: %04x not a menu handle\n",
1047 /* Find where to insert new item */
1049 if ((flags
& MF_BYPOSITION
) &&
1050 ((pos
== (UINT32
)-1) || (pos
== menu
->nItems
)))
1052 /* Special case: append to menu */
1053 /* Some programs specify the menu length to do that */
1058 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
1060 dprintf_menu( stddeb
, "MENU_InsertItem: item %x not found\n",
1064 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
)))
1066 dprintf_menu(stddeb
,"MENU_InsertItem: %04x not a menu handle\n",
1072 /* Create new items array */
1074 newItems
= HeapAlloc( SystemHeap
, 0, sizeof(MENUITEM
) * (menu
->nItems
+1) );
1077 dprintf_menu( stddeb
, "MENU_InsertItem: allocation failed\n" );
1080 if (menu
->nItems
> 0)
1082 /* Copy the old array into the new */
1083 if (pos
> 0) memcpy( newItems
, menu
->items
, pos
* sizeof(MENUITEM
) );
1084 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &menu
->items
[pos
],
1085 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
1086 HeapFree( SystemHeap
, 0, menu
->items
);
1088 menu
->items
= newItems
;
1090 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
1091 return &newItems
[pos
];
1095 /**********************************************************************
1096 * MENU_ParseResource
1098 * Parse a standard menu resource and add items to the menu.
1099 * Return a pointer to the end of the resource.
1101 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU32 hMenu
, BOOL32 unicode
)
1108 flags
= GET_WORD(res
);
1109 res
+= sizeof(WORD
);
1110 if (!(flags
& MF_POPUP
))
1113 res
+= sizeof(WORD
);
1115 if (!IS_STRING_ITEM(flags
))
1116 fprintf( stderr
, "MENU_ParseResource: not a string item %04x\n",
1119 if (!unicode
) res
+= strlen(str
) + 1;
1120 else res
+= (lstrlen32W((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1121 if (flags
& MF_POPUP
)
1123 HMENU32 hSubMenu
= CreatePopupMenu32();
1124 if (!hSubMenu
) return NULL
;
1125 if (!(res
= MENU_ParseResource( res
, hSubMenu
, unicode
)))
1127 if (!unicode
) AppendMenu32A( hMenu
, flags
, (UINT32
)hSubMenu
, str
);
1128 else AppendMenu32W( hMenu
, flags
, (UINT32
)hSubMenu
, (LPCWSTR
)str
);
1130 else /* Not a popup */
1132 if (!unicode
) AppendMenu32A( hMenu
, flags
, id
, *str
? str
: NULL
);
1133 else AppendMenu32W( hMenu
, flags
, id
,
1134 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1136 } while (!(flags
& MF_END
));
1141 /***********************************************************************
1144 * Return the handle of the selected sub-popup menu (if any).
1146 static HMENU32
MENU_GetSubPopup( HMENU32 hmenu
)
1151 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1152 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return 0;
1153 else if (menu
->FocusedItem
== SYSMENU_SELECTED
)
1154 return WIN_FindWndPtr(menu
->hWnd
)->hSysMenu
;
1156 item
= &menu
->items
[menu
->FocusedItem
];
1157 if (!(item
->item_flags
& MF_POPUP
) || !(item
->item_flags
& MF_MOUSESELECT
))
1159 return (HMENU32
)item
->item_id
;
1163 /***********************************************************************
1164 * MENU_HideSubPopups
1166 * Hide the sub-popup menus of this menu.
1168 static void MENU_HideSubPopups( HWND32 hwndOwner
, HMENU32 hmenu
,
1169 BOOL32 sendMenuSelect
)
1172 POPUPMENU
*menu
, *submenu
;
1175 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return;
1176 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return;
1177 if (menu
->FocusedItem
== SYSMENU_SELECTED
)
1179 hsubmenu
= WIN_FindWndPtr(menu
->hWnd
)->hSysMenu
;
1183 item
= &menu
->items
[menu
->FocusedItem
];
1184 if (!(item
->item_flags
& MF_POPUP
) ||
1185 !(item
->item_flags
& MF_MOUSESELECT
)) return;
1186 item
->item_flags
&= ~MF_MOUSESELECT
;
1187 hsubmenu
= (HMENU32
)item
->item_id
;
1189 submenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hsubmenu
);
1190 MENU_HideSubPopups( hwndOwner
, hsubmenu
, FALSE
);
1191 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, sendMenuSelect
);
1192 if (submenu
->hWnd
== pTopPWnd
->hwndSelf
)
1194 ShowWindow32( submenu
->hWnd
, SW_HIDE
);
1199 DestroyWindow32( submenu
->hWnd
);
1205 /***********************************************************************
1208 * Display the sub-menu of the selected item of this menu.
1209 * Return the handle of the submenu, or hmenu if no submenu to display.
1211 static HMENU32
MENU_ShowSubPopup( HWND32 hwndOwner
, HMENU32 hmenu
,
1212 BOOL32 selectFirst
)
1218 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return hmenu
;
1219 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return hmenu
;
1220 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return hmenu
;
1221 if (menu
->FocusedItem
== SYSMENU_SELECTED
)
1223 MENU_InitSysMenuPopup(wndPtr
->hSysMenu
, wndPtr
->dwStyle
,
1224 wndPtr
->class->style
);
1225 MENU_ShowPopup(hwndOwner
, wndPtr
->hSysMenu
, 0, wndPtr
->rectClient
.left
,
1226 wndPtr
->rectClient
.top
- menu
->Height
- 2*SYSMETRICS_CYBORDER
,
1227 SYSMETRICS_CXSIZE
, SYSMETRICS_CYSIZE
);
1229 MENU_SelectItemRel( hwndOwner
, wndPtr
->hSysMenu
, ITEM_NEXT
);
1230 return wndPtr
->hSysMenu
;
1232 item
= &menu
->items
[menu
->FocusedItem
];
1233 if (!(item
->item_flags
& MF_POPUP
) ||
1234 (item
->item_flags
& (MF_GRAYED
| MF_DISABLED
))) return hmenu
;
1235 item
->item_flags
|= MF_MOUSESELECT
;
1236 if (menu
->wFlags
& MF_POPUP
)
1238 MENU_ShowPopup( hwndOwner
, (HMENU16
)item
->item_id
, menu
->FocusedItem
,
1239 wndPtr
->rectWindow
.left
+ item
->rect
.right
-arrow_bitmap_width
,
1240 wndPtr
->rectWindow
.top
+ item
->rect
.top
,
1241 item
->rect
.left
- item
->rect
.right
+ 2*arrow_bitmap_width
,
1242 item
->rect
.top
- item
->rect
.bottom
);
1246 MENU_ShowPopup( hwndOwner
, (HMENU16
)item
->item_id
, menu
->FocusedItem
,
1247 wndPtr
->rectWindow
.left
+ item
->rect
.left
,
1248 wndPtr
->rectWindow
.top
+ item
->rect
.bottom
,
1249 item
->rect
.right
- item
->rect
.left
,
1250 item
->rect
.bottom
- item
->rect
.top
);
1253 MENU_SelectItemRel( hwndOwner
, (HMENU32
)item
->item_id
, ITEM_NEXT
);
1254 return (HMENU32
)item
->item_id
;
1258 /***********************************************************************
1259 * MENU_FindMenuByCoords
1261 * Find the menu containing a given point (in screen coords).
1263 static HMENU32
MENU_FindMenuByCoords( HMENU32 hmenu
, POINT32 pt
)
1268 if (!(hwnd
= WindowFromPoint32( pt
))) return 0;
1271 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1272 if (menu
->hWnd
== hwnd
)
1274 if (!(menu
->wFlags
& MF_POPUP
))
1276 /* Make sure it's in the menu bar (or in system menu) */
1277 WND
*wndPtr
= WIN_FindWndPtr( menu
->hWnd
);
1278 if ((pt
.x
< wndPtr
->rectClient
.left
) ||
1279 (pt
.x
>= wndPtr
->rectClient
.right
) ||
1280 (pt
.y
>= wndPtr
->rectClient
.top
)) return 0;
1281 if (pt
.y
< wndPtr
->rectClient
.top
- menu
->Height
)
1283 if (!MENU_IsInSysMenu( menu
, pt
)) return 0;
1285 /* else it's in the menu bar */
1289 hmenu
= MENU_GetSubPopup( hmenu
);
1295 /***********************************************************************
1296 * MENU_ExecFocusedItem
1298 * Execute a menu item (for instance when user pressed Enter).
1299 * Return TRUE if we can go on with menu tracking.
1301 static BOOL32
MENU_ExecFocusedItem( HWND32 hwndOwner
, HMENU32 hmenu
,
1302 HMENU32
*hmenuCurrent
)
1305 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1306 if (!menu
|| !menu
->nItems
|| (menu
->FocusedItem
== NO_SELECTED_ITEM
) ||
1307 (menu
->FocusedItem
== SYSMENU_SELECTED
)) return TRUE
;
1308 item
= &menu
->items
[menu
->FocusedItem
];
1309 if (!(item
->item_flags
& MF_POPUP
))
1311 if (!(item
->item_flags
& (MF_GRAYED
| MF_DISABLED
)))
1313 PostMessage( hwndOwner
, (menu
->wFlags
& MF_SYSMENU
) ?
1314 WM_SYSCOMMAND
: WM_COMMAND
, item
->item_id
, 0 );
1321 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, TRUE
);
1327 /***********************************************************************
1330 * Handle a button-down event in a menu. Point is in screen coords.
1331 * hmenuCurrent is the top-most visible popup.
1332 * Return TRUE if we can go on with menu tracking.
1334 static BOOL32
MENU_ButtonDown( HWND32 hwndOwner
, HMENU32 hmenu
,
1335 HMENU32
*hmenuCurrent
, POINT32 pt
)
1341 if (!hmenu
) return FALSE
; /* Outside all menus */
1342 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1343 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1344 if (!item
) /* Maybe in system menu */
1346 if (!MENU_IsInSysMenu( menu
, pt
)) return FALSE
;
1347 id
= SYSMENU_SELECTED
;
1350 if (menu
->FocusedItem
== id
)
1352 if (id
== SYSMENU_SELECTED
) return FALSE
;
1353 if (item
->item_flags
& MF_POPUP
)
1355 if (item
->item_flags
& MF_MOUSESELECT
)
1357 if (menu
->wFlags
& MF_POPUP
)
1359 MENU_HideSubPopups( hwndOwner
, hmenu
, TRUE
);
1360 *hmenuCurrent
= hmenu
;
1364 else *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1369 MENU_HideSubPopups( hwndOwner
, hmenu
, FALSE
);
1370 MENU_SelectItem( hwndOwner
, hmenu
, id
, TRUE
);
1371 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1377 /***********************************************************************
1380 * Handle a button-up event in a menu. Point is in screen coords.
1381 * hmenuCurrent is the top-most visible popup.
1382 * Return TRUE if we can go on with menu tracking.
1384 static BOOL32
MENU_ButtonUp( HWND32 hwndOwner
, HMENU32 hmenu
,
1385 HMENU32
*hmenuCurrent
, POINT32 pt
)
1389 HMENU32 hsubmenu
= 0;
1392 if (!hmenu
) return FALSE
; /* Outside all menus */
1393 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1394 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1395 if (!item
) /* Maybe in system menu */
1397 if (!MENU_IsInSysMenu( menu
, pt
)) return FALSE
;
1398 id
= SYSMENU_SELECTED
;
1399 hsubmenu
= WIN_FindWndPtr(menu
->hWnd
)->hSysMenu
;
1402 if (menu
->FocusedItem
!= id
) return FALSE
;
1404 if (id
!= SYSMENU_SELECTED
)
1406 if (!(item
->item_flags
& MF_POPUP
))
1408 return MENU_ExecFocusedItem( hwndOwner
, hmenu
, hmenuCurrent
);
1410 hsubmenu
= (HMENU32
)item
->item_id
;
1412 /* Select first item of sub-popup */
1413 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, FALSE
);
1414 MENU_SelectItemRel( hwndOwner
, hsubmenu
, ITEM_NEXT
);
1419 /***********************************************************************
1422 * Handle a motion event in a menu. Point is in screen coords.
1423 * hmenuCurrent is the top-most visible popup.
1424 * Return TRUE if we can go on with menu tracking.
1426 static BOOL32
MENU_MouseMove( HWND32 hwndOwner
, HMENU32 hmenu
,
1427 HMENU32
*hmenuCurrent
, POINT32 pt
)
1430 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1431 UINT32 id
= NO_SELECTED_ITEM
;
1435 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1436 if (!item
) /* Maybe in system menu */
1438 if (!MENU_IsInSysMenu( menu
, pt
))
1439 id
= NO_SELECTED_ITEM
; /* Outside all items */
1440 else id
= SYSMENU_SELECTED
;
1443 if (id
== NO_SELECTED_ITEM
)
1445 MENU_SelectItem( hwndOwner
, *hmenuCurrent
, NO_SELECTED_ITEM
, TRUE
);
1447 else if (menu
->FocusedItem
!= id
)
1449 MENU_HideSubPopups( hwndOwner
, hmenu
, FALSE
);
1450 MENU_SelectItem( hwndOwner
, hmenu
, id
, TRUE
);
1451 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1457 /***********************************************************************
1460 static LRESULT
MENU_DoNextMenu( HWND32
* hwndOwner
, HMENU32
* hmenu
,
1461 HMENU32
*hmenuCurrent
, UINT32 vk
)
1463 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( *hmenu
);
1466 if( (vk
== VK_LEFT
&& !menu
->FocusedItem
)
1467 || (vk
== VK_RIGHT
&& menu
->FocusedItem
== menu
->nItems
- 1)
1468 || menu
->FocusedItem
== SYSMENU_SELECTED
1469 || ((menu
->wFlags
& (MF_POPUP
| MF_SYSMENU
)) == (MF_POPUP
| MF_SYSMENU
)))
1471 LRESULT l
= SendMessage16( *hwndOwner
, WM_NEXTMENU
, (WPARAM16
)vk
,
1472 (LPARAM
)((menu
->FocusedItem
== SYSMENU_SELECTED
)
1473 ? GetSystemMenu32( *hwndOwner
, 0)
1476 if( l
== 0 || !IsMenu32(LOWORD(l
)) || !IsWindow(HIWORD(l
)) ) return 0;
1478 /* shutdown current menu -
1479 * all these checks for system popup window are needed
1480 * only because Wine system menu tracking is unsuitable
1481 * for a lot of things (esp. when we do not have wIDmenu to fall back on).
1484 MENU_SelectItem( *hwndOwner
, *hmenu
, NO_SELECTED_ITEM
, FALSE
);
1486 if( (menu
->wFlags
& (MF_POPUP
| MF_SYSMENU
)) == (MF_POPUP
| MF_SYSMENU
) )
1488 ShowWindow32( menu
->hWnd
, SW_HIDE
);
1491 if( !IsIconic32( *hwndOwner
) )
1493 HDC32 hdc
= GetDCEx32( *hwndOwner
, 0, DCX_CACHE
| DCX_WINDOW
);
1494 NC_DrawSysButton( *hwndOwner
, hdc
, FALSE
);
1495 ReleaseDC32( *hwndOwner
, hdc
);
1500 *hwndOwner
= HIWORD(l
);
1502 SetCapture32( *hwndOwner
);
1504 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( *hmenu
);
1506 /* init next menu */
1508 if( (menu
->wFlags
& (MF_POPUP
| MF_SYSMENU
)) == (MF_POPUP
| MF_SYSMENU
) )
1511 WND
* wndPtr
= WIN_FindWndPtr( *hwndOwner
);
1513 /* stupid kludge, see above */
1515 if( wndPtr
->wIDmenu
&& !(wndPtr
->dwStyle
& WS_CHILD
) )
1517 *hmenu
= wndPtr
->wIDmenu
;
1518 id
= SYSMENU_SELECTED
;
1522 if( NC_GetSysPopupPos( wndPtr
, &rect
) )
1523 MENU_ShowPopup( *hwndOwner
, *hmenu
, 0, rect
.left
, rect
.bottom
,
1524 SYSMETRICS_CXSIZE
, SYSMETRICS_CYSIZE
);
1526 if( !IsIconic32( *hwndOwner
) )
1528 HDC32 hdc
= GetDCEx32( *hwndOwner
, 0, DCX_CACHE
| DCX_WINDOW
);
1529 NC_DrawSysButton( *hwndOwner
, hdc
, TRUE
);
1530 ReleaseDC32( *hwndOwner
, hdc
);
1535 MENU_SelectItem( *hwndOwner
, *hmenu
, id
, TRUE
);
1541 /***********************************************************************
1544 * Handle a VK_LEFT key event in a menu.
1545 * hmenuCurrent is the top-most visible popup.
1547 static void MENU_KeyLeft( HWND32
* hwndOwner
, HMENU32
* hmenu
,
1548 HMENU32
*hmenuCurrent
)
1551 HMENU32 hmenutmp
, hmenuprev
;
1553 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( *hmenu
);
1554 hmenuprev
= hmenutmp
= *hmenu
;
1555 while (hmenutmp
!= *hmenuCurrent
)
1557 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
1558 if (hmenutmp
!= *hmenuCurrent
) hmenuprev
= hmenutmp
;
1560 MENU_HideSubPopups( *hwndOwner
, hmenuprev
, TRUE
);
1563 if ( (hmenuprev
== *hmenu
) &&
1564 ((menu
->wFlags
& MF_SYSMENU
) || !(menu
->wFlags
& MF_POPUP
)) )
1566 /* send WM_NEXTMENU */
1568 if( !MENU_DoNextMenu( hwndOwner
, hmenu
, hmenuCurrent
, VK_LEFT
) )
1569 MENU_SelectItemRel( *hwndOwner
, *hmenu
, ITEM_PREV
);
1570 else *hmenuCurrent
= *hmenu
;
1572 if (*hmenuCurrent
!= hmenutmp
)
1574 /* A sublevel menu was displayed -> display the next one */
1575 *hmenuCurrent
= MENU_ShowSubPopup( *hwndOwner
, *hmenu
, TRUE
);
1578 else *hmenuCurrent
= hmenuprev
;
1582 /***********************************************************************
1585 * Handle a VK_RIGHT key event in a menu.
1586 * hmenuCurrent is the top-most visible popup.
1588 static void MENU_KeyRight( HWND32
* hwndOwner
, HMENU32
* hmenu
,
1589 HMENU32
*hmenuCurrent
)
1594 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( *hmenu
);
1596 if ((menu
->wFlags
& MF_POPUP
) || (*hmenuCurrent
!= *hmenu
))
1598 /* If already displaying a popup, try to display sub-popup */
1599 hmenutmp
= MENU_ShowSubPopup( *hwndOwner
, *hmenuCurrent
, TRUE
);
1600 if (hmenutmp
!= *hmenuCurrent
) /* Sub-popup displayed */
1602 *hmenuCurrent
= hmenutmp
;
1607 /* If menu-bar tracking, go to next item */
1609 if (!(menu
->wFlags
& MF_POPUP
) || (menu
->wFlags
& MF_SYSMENU
))
1611 MENU_HideSubPopups( *hwndOwner
, *hmenu
, FALSE
);
1614 /* Send WM_NEXTMENU */
1616 if( !MENU_DoNextMenu( hwndOwner
, hmenu
, hmenuCurrent
, VK_RIGHT
) )
1617 MENU_SelectItemRel( *hwndOwner
, *hmenu
, ITEM_NEXT
);
1618 else *hmenuCurrent
= *hmenu
;
1620 if (*hmenuCurrent
!= hmenutmp
)
1622 /* A sublevel menu was displayed -> display the next one */
1623 *hmenuCurrent
= MENU_ShowSubPopup( *hwndOwner
, *hmenu
, TRUE
);
1626 else if (*hmenuCurrent
!= *hmenu
) /* Hide last level popup */
1629 hmenuprev
= hmenutmp
= *hmenu
;
1630 while (hmenutmp
!= *hmenuCurrent
)
1632 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
1633 if (hmenutmp
!= *hmenuCurrent
) hmenuprev
= hmenutmp
;
1635 MENU_HideSubPopups( *hwndOwner
, hmenuprev
, TRUE
);
1636 *hmenuCurrent
= hmenuprev
;
1641 /***********************************************************************
1644 * Menu tracking code.
1645 * If 'x' and 'y' are not 0, we simulate a button-down event at (x,y)
1646 * before beginning tracking. This is to help menu-bar tracking.
1648 static BOOL32
MENU_TrackMenu( HMENU32 hmenu
, UINT32 wFlags
, INT32 x
, INT32 y
,
1649 HWND32 hwnd
, const RECT32
*lprect
)
1653 HMENU32 hmenuCurrent
= hmenu
;
1654 BOOL32 fClosed
= FALSE
, fRemove
;
1658 fEndMenuCalled
= FALSE
;
1659 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
1664 MENU_ButtonDown( hwnd
, hmenu
, &hmenuCurrent
, pt
);
1667 EVENT_Capture( hwnd
, HTMENU
);
1671 /* we have to keep the message in the queue until it's
1672 * clear that menu loop is not over yet.
1675 if (!MSG_InternalGetMessage( &msg
, 0, hwnd
, MSGF_MENU
,
1676 PM_NOREMOVE
, TRUE
))
1679 TranslateMessage16( &msg
);
1680 CONV_POINT16TO32( &msg
.pt
, &pt
);
1683 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
1685 /* Find the sub-popup for this mouse event (if any) */
1687 HMENU32 hsubmenu
= MENU_FindMenuByCoords( hmenu
, pt
);
1691 /* no WM_NC... messages in captured state */
1693 case WM_RBUTTONDBLCLK
:
1694 case WM_RBUTTONDOWN
:
1695 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
1698 case WM_LBUTTONDBLCLK
:
1699 case WM_LBUTTONDOWN
:
1700 fClosed
= !MENU_ButtonDown( hwnd
, hsubmenu
,
1701 &hmenuCurrent
, pt
);
1705 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
1709 /* If outside all menus but inside lprect, ignore it */
1710 if (!hsubmenu
&& lprect
&& PtInRect32(lprect
, pt
)) break;
1711 fClosed
= !MENU_ButtonUp( hwnd
, hsubmenu
,
1712 &hmenuCurrent
, pt
);
1713 fRemove
= TRUE
; /* Remove event even if outside menu */
1717 if ((msg
.wParam
& MK_LBUTTON
) ||
1718 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
.wParam
& MK_RBUTTON
)))
1720 fClosed
= !MENU_MouseMove( hwnd
, hsubmenu
,
1721 &hmenuCurrent
, pt
);
1726 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
1728 fRemove
= TRUE
; /* Keyboard messages are always removed */
1736 MENU_SelectItem( hwnd
, hmenuCurrent
, NO_SELECTED_ITEM
, FALSE
);
1740 MENU_SelectItemRel( hwnd
, hmenuCurrent
,
1741 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
1744 case VK_DOWN
: /* If on menu bar, pull-down the menu */
1746 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1747 if (!(menu
->wFlags
& MF_POPUP
) && (hmenuCurrent
== hmenu
))
1748 hmenuCurrent
= MENU_ShowSubPopup( hwnd
, hmenu
, TRUE
);
1750 MENU_SelectItemRel( hwnd
, hmenuCurrent
, ITEM_NEXT
);
1754 MENU_KeyLeft( &hwnd
, &hmenu
, &hmenuCurrent
);
1758 MENU_KeyRight( &hwnd
, &hmenu
, &hmenuCurrent
);
1763 fClosed
= !MENU_ExecFocusedItem( hwnd
, hmenuCurrent
,
1774 break; /* WM_KEYDOWN */
1784 break; /* WM_SYSKEYDOWN */
1788 /* Hack to avoid control chars. */
1789 /* We will find a better way real soon... */
1790 if ((msg
.wParam
<= 32) || (msg
.wParam
>= 127)) break;
1791 pos
= MENU_FindItemByKey( hwnd
, hmenuCurrent
, msg
.wParam
);
1792 if (pos
== (UINT32
)-2) fClosed
= TRUE
;
1793 else if (pos
== (UINT32
)-1) MessageBeep32(0);
1796 MENU_SelectItem( hwnd
, hmenuCurrent
, pos
, TRUE
);
1797 fClosed
= !MENU_ExecFocusedItem( hwnd
, hmenuCurrent
,
1802 break; /* WM_CHAR */
1803 } /* switch(msg.message) */
1807 DispatchMessage16( &msg
);
1809 if (fEndMenuCalled
) fClosed
= TRUE
;
1810 if (!fClosed
) fRemove
= TRUE
;
1812 if (fRemove
) /* Remove the message from the queue */
1813 PeekMessage16( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
1817 MENU_HideSubPopups( hwnd
, hmenu
, FALSE
);
1818 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1819 if (menu
&& menu
->wFlags
& MF_POPUP
)
1821 ShowWindow32( menu
->hWnd
, SW_HIDE
);
1824 MENU_SelectItem( hwnd
, hmenu
, NO_SELECTED_ITEM
, FALSE
);
1825 SendMessage16( hwnd
, WM_MENUSELECT
, 0, MAKELONG( 0xffff, 0 ) );
1826 fEndMenuCalled
= FALSE
;
1830 /***********************************************************************
1831 * MENU_TrackSysPopup
1833 static void MENU_TrackSysPopup( WND
* pWnd
)
1836 HMENU32 hMenu
= pWnd
->hSysMenu
;
1839 /* track the system menu like a normal popup menu */
1843 HWND32 hWnd
= pWnd
->hwndSelf
;
1844 if (!(pWnd
->dwStyle
& WS_MINIMIZE
))
1846 hDC
= GetWindowDC32( hWnd
);
1847 NC_DrawSysButton( hWnd
, hDC
, TRUE
);
1849 NC_GetSysPopupPos( pWnd
, &rect
);
1850 MENU_InitSysMenuPopup( hMenu
, pWnd
->dwStyle
,
1851 pWnd
->class->style
);
1852 TrackPopupMenu32( hMenu
, TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
1853 rect
.left
, rect
.bottom
, 0, hWnd
, &rect
);
1854 if (!(pWnd
->dwStyle
& WS_MINIMIZE
))
1856 NC_DrawSysButton( hWnd
, hDC
, FALSE
);
1857 ReleaseDC32( hWnd
, hDC
);
1862 /***********************************************************************
1863 * MENU_TrackMouseMenuBar
1865 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
1867 void MENU_TrackMouseMenuBar( WND
* wndPtr
, INT32 ht
, POINT32 pt
)
1869 BOOL32 bTrackSys
= ((ht
== HTSYSMENU
&& !wndPtr
->wIDmenu
) ||
1870 (wndPtr
->dwStyle
& (WS_MINIMIZE
| WS_CHILD
)));
1871 HWND32 hWnd
= wndPtr
->hwndSelf
;
1872 HMENU32 hMenu
= (bTrackSys
) ? wndPtr
->hSysMenu
: wndPtr
->wIDmenu
;
1874 if (IsMenu32(hMenu
))
1877 SendMessage16( hWnd
, WM_ENTERMENULOOP
, 0, 0 );
1878 SendMessage16( hWnd
, WM_INITMENU
, hMenu
, 0 );
1880 MENU_TrackSysPopup( wndPtr
);
1882 MENU_TrackMenu( hMenu
, TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
1883 pt
.x
, pt
.y
, hWnd
, NULL
);
1884 SendMessage16( hWnd
, WM_EXITMENULOOP
, 0, 0 );
1890 /***********************************************************************
1891 * MENU_TrackKbdMenuBar
1893 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
1895 void MENU_TrackKbdMenuBar( WND
* wndPtr
, UINT32 wParam
, INT32 vkey
)
1898 UINT32 uItem
= NO_SELECTED_ITEM
;
1901 /* find window that has a menu */
1903 while( wndPtr
->dwStyle
& WS_CHILD
&& !(wndPtr
->dwStyle
& WS_SYSMENU
) )
1904 if( !(wndPtr
= wndPtr
->parent
) ) return;
1906 if( !wndPtr
->wIDmenu
&& !(wndPtr
->dwStyle
& WS_SYSMENU
) ) return;
1908 htMenu
= ((wndPtr
->dwStyle
& (WS_CHILD
| WS_MINIMIZE
)) ||
1909 !wndPtr
->wIDmenu
) ? HTSYSMENU
: HTMENU
;
1910 hTrackMenu
= ( htMenu
== HTSYSMENU
) ? wndPtr
->hSysMenu
: wndPtr
->wIDmenu
;
1912 if (IsMenu32( hTrackMenu
))
1915 SendMessage16( wndPtr
->hwndSelf
, WM_ENTERMENULOOP
, 0, 0 );
1916 SendMessage16( wndPtr
->hwndSelf
, WM_INITMENU
, hTrackMenu
, 0 );
1918 /* find suitable menu entry */
1920 if( vkey
== VK_SPACE
)
1921 uItem
= SYSMENU_SELECTED
;
1924 uItem
= ( htMenu
== HTSYSMENU
)
1925 ? 0xFFFE /* only VK_SPACE in this case */
1926 : MENU_FindItemByKey( wndPtr
->hwndSelf
, wndPtr
->wIDmenu
, vkey
);
1927 if( uItem
>= 0xFFFE )
1929 if( uItem
== 0xFFFF ) MessageBeep32(0);
1937 MENU_SelectItem( wndPtr
->hwndSelf
, hTrackMenu
, uItem
, TRUE
);
1938 if( uItem
== NO_SELECTED_ITEM
)
1939 MENU_SelectItemRel( wndPtr
->hwndSelf
, hTrackMenu
, ITEM_NEXT
);
1941 PostMessage( wndPtr
->hwndSelf
, WM_KEYDOWN
, VK_DOWN
, 0L );
1943 MENU_TrackMenu( hTrackMenu
, TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
1944 0, 0, wndPtr
->hwndSelf
, NULL
);
1948 MENU_TrackSysPopup( wndPtr
);
1951 SendMessage16( wndPtr
->hwndSelf
, WM_EXITMENULOOP
, 0, 0 );
1957 /**********************************************************************
1958 * TrackPopupMenu16 (USER.416)
1960 BOOL16
TrackPopupMenu16( HMENU16 hMenu
, UINT16 wFlags
, INT16 x
, INT16 y
,
1961 INT16 nReserved
, HWND16 hWnd
, const RECT16
*lpRect
)
1965 CONV_RECT16TO32( lpRect
, &r
);
1966 return TrackPopupMenu32( hMenu
, wFlags
, x
, y
, nReserved
, hWnd
,
1967 lpRect
? &r
: NULL
);
1971 /**********************************************************************
1972 * TrackPopupMenu32 (USER32.548)
1974 BOOL32
TrackPopupMenu32( HMENU32 hMenu
, UINT32 wFlags
, INT32 x
, INT32 y
,
1975 INT32 nReserved
, HWND32 hWnd
, const RECT32
*lpRect
)
1980 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
, 0, 0 ))
1981 ret
= MENU_TrackMenu( hMenu
, wFlags
, 0, 0, hWnd
, lpRect
);
1986 /**********************************************************************
1987 * TrackPopupMenuEx (USER32.549)
1989 BOOL32
TrackPopupMenuEx( HMENU32 hMenu
, UINT32 wFlags
, INT32 x
, INT32 y
,
1990 HWND32 hWnd
, LPTPMPARAMS lpTpm
)
1992 fprintf( stderr
, "TrackPopupMenuEx: not fully implemented\n" );
1993 return TrackPopupMenu32( hMenu
, wFlags
, x
, y
, 0, hWnd
,
1994 lpTpm
? &lpTpm
->rcExclude
: NULL
);
1997 /***********************************************************************
2000 LRESULT
PopupMenuWndProc( HWND32 hwnd
, UINT32 message
, WPARAM32 wParam
,
2007 CREATESTRUCT32A
*cs
= (CREATESTRUCT32A
*)lParam
;
2008 SetWindowLong32A( hwnd
, 0, (LONG
)cs
->lpCreateParams
);
2012 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2013 return MA_NOACTIVATE
;
2018 BeginPaint32( hwnd
, &ps
);
2019 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
2020 (HMENU32
)GetWindowLong32A( hwnd
, 0 ) );
2021 EndPaint32( hwnd
, &ps
);
2026 /* zero out global pointer in case system popup
2027 * was destroyed by AppExit
2030 if( hwnd
== pTopPWnd
->hwndSelf
)
2031 { pTopPWnd
= NULL
; uSubPWndLevel
= 0; }
2037 if (wParam
) SetWindowLong32A( hwnd
, 0, (HMENU16
)wParam
);
2040 return DefWindowProc32A( hwnd
, message
, wParam
, lParam
);
2046 /***********************************************************************
2047 * MENU_GetMenuBarHeight
2049 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
2051 UINT32
MENU_GetMenuBarHeight( HWND32 hwnd
, UINT32 menubarWidth
,
2052 INT32 orgX
, INT32 orgY
)
2059 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
2060 if (!(lppop
= (LPPOPUPMENU
)USER_HEAP_LIN_ADDR((HMENU16
)wndPtr
->wIDmenu
)))
2062 hdc
= GetDCEx32( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2063 SetRect32(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+SYSMETRICS_CYMENU
);
2064 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
2065 ReleaseDC32( hwnd
, hdc
);
2066 return lppop
->Height
;
2070 /*******************************************************************
2071 * ChangeMenu16 (USER.153)
2073 BOOL16
ChangeMenu16( HMENU16 hMenu
, UINT16 pos
, SEGPTR data
,
2074 UINT16 id
, UINT16 flags
)
2076 dprintf_menu( stddeb
,"ChangeMenu16: menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
2077 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2078 if (flags
& MF_APPEND
) return AppendMenu16( hMenu
, flags
& ~MF_APPEND
,
2080 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
2081 /* for MF_DELETE. We should check the parameters for all others */
2082 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
2083 if (flags
& MF_DELETE
) return DeleteMenu16(hMenu
, pos
, flags
& ~MF_DELETE
);
2084 if (flags
& MF_CHANGE
) return ModifyMenu16(hMenu
, pos
, flags
& ~MF_CHANGE
,
2086 if (flags
& MF_REMOVE
) return RemoveMenu16(hMenu
,
2087 flags
& MF_BYPOSITION
? pos
: id
,
2088 flags
& ~MF_REMOVE
);
2089 /* Default: MF_INSERT */
2090 return InsertMenu16( hMenu
, pos
, flags
, id
, data
);
2094 /*******************************************************************
2095 * ChangeMenu32A (USER32.22)
2097 BOOL32
ChangeMenu32A( HMENU32 hMenu
, UINT32 pos
, LPCSTR data
,
2098 UINT32 id
, UINT32 flags
)
2100 dprintf_menu( stddeb
,"ChangeMenu32A: menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2101 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2102 if (flags
& MF_APPEND
) return AppendMenu32A( hMenu
, flags
& ~MF_APPEND
,
2104 if (flags
& MF_DELETE
) return DeleteMenu32(hMenu
, pos
, flags
& ~MF_DELETE
);
2105 if (flags
& MF_CHANGE
) return ModifyMenu32A(hMenu
, pos
, flags
& ~MF_CHANGE
,
2107 if (flags
& MF_REMOVE
) return RemoveMenu32( hMenu
,
2108 flags
& MF_BYPOSITION
? pos
: id
,
2109 flags
& ~MF_REMOVE
);
2110 /* Default: MF_INSERT */
2111 return InsertMenu32A( hMenu
, pos
, flags
, id
, data
);
2115 /*******************************************************************
2116 * ChangeMenu32W (USER32.23)
2118 BOOL32
ChangeMenu32W( HMENU32 hMenu
, UINT32 pos
, LPCWSTR data
,
2119 UINT32 id
, UINT32 flags
)
2121 dprintf_menu( stddeb
,"ChangeMenu32W: menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2122 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2123 if (flags
& MF_APPEND
) return AppendMenu32W( hMenu
, flags
& ~MF_APPEND
,
2125 if (flags
& MF_DELETE
) return DeleteMenu32(hMenu
, pos
, flags
& ~MF_DELETE
);
2126 if (flags
& MF_CHANGE
) return ModifyMenu32W(hMenu
, pos
, flags
& ~MF_CHANGE
,
2128 if (flags
& MF_REMOVE
) return RemoveMenu32( hMenu
,
2129 flags
& MF_BYPOSITION
? pos
: id
,
2130 flags
& ~MF_REMOVE
);
2131 /* Default: MF_INSERT */
2132 return InsertMenu32W( hMenu
, pos
, flags
, id
, data
);
2136 /*******************************************************************
2137 * CheckMenuItem16 (USER.154)
2139 BOOL16
CheckMenuItem16( HMENU16 hMenu
, UINT16 id
, UINT16 flags
)
2141 return (BOOL16
)CheckMenuItem32( hMenu
, id
, flags
);
2145 /*******************************************************************
2146 * CheckMenuItem32 (USER32.45)
2148 DWORD
CheckMenuItem32( HMENU32 hMenu
, UINT32 id
, UINT32 flags
)
2153 dprintf_menu( stddeb
,"CheckMenuItem: %04x %04x %04x\n", hMenu
, id
, flags
);
2154 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
2155 ret
= item
->item_flags
& MF_CHECKED
;
2156 if (flags
& MF_CHECKED
) item
->item_flags
|= MF_CHECKED
;
2157 else item
->item_flags
&= ~MF_CHECKED
;
2162 /**********************************************************************
2163 * EnableMenuItem16 (USER.155)
2165 BOOL16
EnableMenuItem16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
2167 return EnableMenuItem32( hMenu
, wItemID
, wFlags
);
2171 /**********************************************************************
2172 * EnableMenuItem32 (USER32.169)
2174 BOOL32
EnableMenuItem32( HMENU32 hMenu
, UINT32 wItemID
, UINT32 wFlags
)
2177 dprintf_menu(stddeb
,"EnableMenuItem (%04x, %04X, %04X) !\n",
2178 hMenu
, wItemID
, wFlags
);
2179 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return FALSE
;
2181 /* We can't have MF_GRAYED and MF_DISABLED together */
2182 if (wFlags
& MF_GRAYED
)
2184 item
->item_flags
= (item
->item_flags
& ~MF_DISABLED
) | MF_GRAYED
;
2186 else if (wFlags
& MF_DISABLED
)
2188 item
->item_flags
= (item
->item_flags
& ~MF_GRAYED
) | MF_DISABLED
;
2190 else /* MF_ENABLED */
2192 item
->item_flags
&= ~(MF_GRAYED
| MF_DISABLED
);
2198 /*******************************************************************
2199 * GetMenuString16 (USER.161)
2201 INT16
GetMenuString16( HMENU16 hMenu
, UINT16 wItemID
,
2202 LPSTR str
, INT16 nMaxSiz
, UINT16 wFlags
)
2204 return GetMenuString32A( hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
2208 /*******************************************************************
2209 * GetMenuString32A (USER32.267)
2211 INT32
GetMenuString32A( HMENU32 hMenu
, UINT32 wItemID
,
2212 LPSTR str
, INT32 nMaxSiz
, UINT32 wFlags
)
2216 dprintf_menu( stddeb
, "GetMenuString32A: menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
2217 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
2218 if (!str
|| !nMaxSiz
) return 0;
2220 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
2221 if (!IS_STRING_ITEM(item
->item_flags
)) return 0;
2222 lstrcpyn32A( str
, item
->text
, nMaxSiz
);
2223 dprintf_menu( stddeb
, "GetMenuString32A: returning '%s'\n", str
);
2228 /*******************************************************************
2229 * GetMenuString32W (USER32.268)
2231 INT32
GetMenuString32W( HMENU32 hMenu
, UINT32 wItemID
,
2232 LPWSTR str
, INT32 nMaxSiz
, UINT32 wFlags
)
2236 dprintf_menu( stddeb
, "GetMenuString32W: menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
2237 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
2238 if (!str
|| !nMaxSiz
) return 0;
2240 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
2241 if (!IS_STRING_ITEM(item
->item_flags
)) return 0;
2242 lstrcpynAtoW( str
, item
->text
, nMaxSiz
);
2243 return lstrlen32W(str
);
2247 /**********************************************************************
2248 * HiliteMenuItem16 (USER.162)
2250 BOOL16
HiliteMenuItem16( HWND16 hWnd
, HMENU16 hMenu
, UINT16 wItemID
,
2253 return HiliteMenuItem32( hWnd
, hMenu
, wItemID
, wHilite
);
2257 /**********************************************************************
2258 * HiliteMenuItem32 (USER32.317)
2260 BOOL32
HiliteMenuItem32( HWND32 hWnd
, HMENU32 hMenu
, UINT32 wItemID
,
2264 dprintf_menu(stddeb
,"HiliteMenuItem(%04x, %04x, %04x, %04x);\n",
2265 hWnd
, hMenu
, wItemID
, wHilite
);
2266 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
2267 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
2268 if (menu
->FocusedItem
== wItemID
) return TRUE
;
2269 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
2270 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
);
2275 /**********************************************************************
2276 * GetMenuState16 (USER.250)
2278 UINT16
GetMenuState16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
2280 return GetMenuState32( hMenu
, wItemID
, wFlags
);
2284 /**********************************************************************
2285 * GetMenuState32 (USER32.266)
2287 UINT32
GetMenuState32( HMENU32 hMenu
, UINT32 wItemID
, UINT32 wFlags
)
2290 dprintf_menu(stddeb
,"GetMenuState(%04x, %04x, %04x);\n",
2291 hMenu
, wItemID
, wFlags
);
2292 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
2293 if (item
->item_flags
& MF_POPUP
)
2295 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( (HMENU16
)item
->item_id
);
2296 if (!menu
) return -1;
2297 else return (menu
->nItems
<< 8) | (menu
->wFlags
& 0xff);
2299 else return item
->item_flags
;
2303 /**********************************************************************
2304 * GetMenuItemCount16 (USER.263)
2306 INT16
GetMenuItemCount16( HMENU16 hMenu
)
2308 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2309 if (!menu
|| (menu
->wMagic
!= MENU_MAGIC
)) return -1;
2310 dprintf_menu( stddeb
,"GetMenuItemCount16(%04x) returning %d\n",
2311 hMenu
, menu
->nItems
);
2312 return menu
->nItems
;
2316 /**********************************************************************
2317 * GetMenuItemCount32 (USER32.261)
2319 INT32
GetMenuItemCount32( HMENU32 hMenu
)
2321 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2322 if (!menu
|| (menu
->wMagic
!= MENU_MAGIC
)) return -1;
2323 dprintf_menu( stddeb
,"GetMenuItemCount32(%04x) returning %d\n",
2324 hMenu
, menu
->nItems
);
2325 return menu
->nItems
;
2329 /**********************************************************************
2330 * GetMenuItemID16 (USER.264)
2332 UINT16
GetMenuItemID16( HMENU16 hMenu
, INT16 nPos
)
2336 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
2337 if ((nPos
< 0) || (nPos
>= menu
->nItems
)) return -1;
2338 if (menu
->items
[nPos
].item_flags
& MF_POPUP
) return -1;
2339 return menu
->items
[nPos
].item_id
;
2343 /**********************************************************************
2344 * GetMenuItemID32 (USER32.262)
2346 UINT32
GetMenuItemID32( HMENU32 hMenu
, INT32 nPos
)
2350 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
2351 if ((nPos
< 0) || (nPos
>= menu
->nItems
)) return -1;
2352 if (menu
->items
[nPos
].item_flags
& MF_POPUP
) return -1;
2353 return menu
->items
[nPos
].item_id
;
2357 /*******************************************************************
2358 * InsertMenu16 (USER.410)
2360 BOOL16
InsertMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
2361 UINT16 id
, SEGPTR data
)
2363 UINT32 pos32
= (UINT32
)pos
;
2364 if ((pos
== (UINT16
)-1) && (flags
& MF_BYPOSITION
)) pos32
= (UINT32
)-1;
2365 if (IS_STRING_ITEM(flags
) && data
)
2366 return InsertMenu32A( hMenu
, pos32
, flags
, id
,
2367 (LPSTR
)PTR_SEG_TO_LIN(data
) );
2368 return InsertMenu32A( hMenu
, pos32
, flags
, id
, (LPSTR
)data
);
2372 /*******************************************************************
2373 * InsertMenu32A (USER32.321)
2375 BOOL32
InsertMenu32A( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2376 UINT32 id
, LPCSTR str
)
2380 if (IS_STRING_ITEM(flags
) && str
)
2381 dprintf_menu( stddeb
, "InsertMenu: %04x %d %04x %04x '%s'\n",
2382 hMenu
, pos
, flags
, id
, str
);
2383 else dprintf_menu( stddeb
, "InsertMenu: %04x %d %04x %04x %08lx\n",
2384 hMenu
, pos
, flags
, id
, (DWORD
)str
);
2386 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
2388 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
2390 RemoveMenu32( hMenu
, pos
, flags
);
2394 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
2395 ((POPUPMENU
*)USER_HEAP_LIN_ADDR((HMENU16
)id
))->wFlags
|= MF_POPUP
;
2397 item
->hCheckBit
= hStdCheck
;
2398 item
->hUnCheckBit
= 0;
2403 /*******************************************************************
2404 * InsertMenu32W (USER32.324)
2406 BOOL32
InsertMenu32W( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2407 UINT32 id
, LPCWSTR str
)
2411 if (IS_STRING_ITEM(flags
) && str
)
2413 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
2414 ret
= InsertMenu32A( hMenu
, pos
, flags
, id
, newstr
);
2415 HeapFree( GetProcessHeap(), 0, newstr
);
2418 else return InsertMenu32A( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
2422 /*******************************************************************
2423 * AppendMenu16 (USER.411)
2425 BOOL16
AppendMenu16( HMENU16 hMenu
, UINT16 flags
, UINT16 id
, SEGPTR data
)
2427 return InsertMenu16( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
2431 /*******************************************************************
2432 * AppendMenu32A (USER32.4)
2434 BOOL32
AppendMenu32A( HMENU32 hMenu
, UINT32 flags
, UINT32 id
, LPCSTR data
)
2436 return InsertMenu32A( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
2440 /*******************************************************************
2441 * AppendMenu32W (USER32.5)
2443 BOOL32
AppendMenu32W( HMENU32 hMenu
, UINT32 flags
, UINT32 id
, LPCWSTR data
)
2445 return InsertMenu32W( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
2449 /**********************************************************************
2450 * RemoveMenu16 (USER.412)
2452 BOOL16
RemoveMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
2454 return RemoveMenu32( hMenu
, nPos
, wFlags
);
2458 /**********************************************************************
2459 * RemoveMenu32 (USER32.440)
2461 BOOL32
RemoveMenu32( HMENU32 hMenu
, UINT32 nPos
, UINT32 wFlags
)
2466 dprintf_menu(stddeb
,"RemoveMenu (%04x, %04x, %04x)\n",hMenu
, nPos
, wFlags
);
2467 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
2468 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
2472 if (IS_STRING_ITEM(item
->item_flags
) && item
->text
)
2473 HeapFree( SystemHeap
, 0, item
->text
);
2474 if (--menu
->nItems
== 0)
2476 HeapFree( SystemHeap
, 0, menu
->items
);
2481 while(nPos
< menu
->nItems
)
2487 menu
->items
= HeapReAlloc( SystemHeap
, 0, menu
->items
,
2488 menu
->nItems
* sizeof(MENUITEM
) );
2494 /**********************************************************************
2495 * DeleteMenu16 (USER.413)
2497 BOOL16
DeleteMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
2499 return DeleteMenu32( hMenu
, nPos
, wFlags
);
2503 /**********************************************************************
2504 * DeleteMenu32 (USER32.128)
2506 BOOL32
DeleteMenu32( HMENU32 hMenu
, UINT32 nPos
, UINT32 wFlags
)
2508 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
2509 if (!item
) return FALSE
;
2510 if (item
->item_flags
& MF_POPUP
) DestroyMenu32( (HMENU32
)item
->item_id
);
2511 /* nPos is now the position of the item */
2512 RemoveMenu32( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
2517 /*******************************************************************
2518 * ModifyMenu16 (USER.414)
2520 BOOL16
ModifyMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
2521 UINT16 id
, SEGPTR data
)
2523 if (IS_STRING_ITEM(flags
))
2524 return ModifyMenu32A( hMenu
, pos
, flags
, id
,
2525 (LPSTR
)PTR_SEG_TO_LIN(data
) );
2526 return ModifyMenu32A( hMenu
, pos
, flags
, id
, (LPSTR
)data
);
2530 /*******************************************************************
2531 * ModifyMenu32A (USER32.396)
2533 BOOL32
ModifyMenu32A( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2534 UINT32 id
, LPCSTR str
)
2538 if (IS_STRING_ITEM(flags
))
2540 dprintf_menu( stddeb
, "ModifyMenu: %04x %d %04x %04x '%s'\n",
2541 hMenu
, pos
, flags
, id
, str
? str
: "#NULL#" );
2542 if (!str
) return FALSE
;
2546 dprintf_menu( stddeb
, "ModifyMenu: %04x %d %04x %04x %08lx\n",
2547 hMenu
, pos
, flags
, id
, (DWORD
)str
);
2550 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
2551 return MENU_SetItemData( item
, flags
, id
, str
);
2555 /*******************************************************************
2556 * ModifyMenu32W (USER32.397)
2558 BOOL32
ModifyMenu32W( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2559 UINT32 id
, LPCWSTR str
)
2563 if (IS_STRING_ITEM(flags
) && str
)
2565 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
2566 ret
= ModifyMenu32A( hMenu
, pos
, flags
, id
, newstr
);
2567 HeapFree( GetProcessHeap(), 0, newstr
);
2570 else return ModifyMenu32A( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
2574 /**********************************************************************
2575 * CreatePopupMenu16 (USER.415)
2577 HMENU16
CreatePopupMenu16(void)
2579 return CreatePopupMenu32();
2583 /**********************************************************************
2584 * CreatePopupMenu32 (USER32.81)
2586 HMENU32
CreatePopupMenu32(void)
2591 if (!(hmenu
= CreateMenu32())) return 0;
2592 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
2593 menu
->wFlags
|= MF_POPUP
;
2598 /**********************************************************************
2599 * GetMenuCheckMarkDimensions (USER.417) (USER32.257)
2601 DWORD
GetMenuCheckMarkDimensions(void)
2603 return MAKELONG( check_bitmap_width
, check_bitmap_height
);
2607 /**********************************************************************
2608 * SetMenuItemBitmaps16 (USER.418)
2610 BOOL16
SetMenuItemBitmaps16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
,
2611 HBITMAP16 hNewUnCheck
, HBITMAP16 hNewCheck
)
2613 return SetMenuItemBitmaps32( hMenu
, nPos
, wFlags
, hNewUnCheck
, hNewCheck
);
2617 /**********************************************************************
2618 * SetMenuItemBitmaps32 (USER32.489)
2620 BOOL32
SetMenuItemBitmaps32( HMENU32 hMenu
, UINT32 nPos
, UINT32 wFlags
,
2621 HBITMAP32 hNewUnCheck
, HBITMAP32 hNewCheck
)
2624 dprintf_menu(stddeb
,"SetMenuItemBitmaps(%04x, %04x, %04x, %04x, %04x)\n",
2625 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
2626 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
2628 if (!hNewCheck
&& !hNewUnCheck
)
2630 /* If both are NULL, restore default bitmaps */
2631 item
->hCheckBit
= hStdCheck
;
2632 item
->hUnCheckBit
= 0;
2633 item
->item_flags
&= ~MF_USECHECKBITMAPS
;
2635 else /* Install new bitmaps */
2637 item
->hCheckBit
= hNewCheck
;
2638 item
->hUnCheckBit
= hNewUnCheck
;
2639 item
->item_flags
|= MF_USECHECKBITMAPS
;
2645 /**********************************************************************
2646 * CreateMenu16 (USER.151)
2648 HMENU16
CreateMenu16(void)
2650 return CreateMenu32();
2654 /**********************************************************************
2655 * CreateMenu32 (USER32.80)
2657 HMENU32
CreateMenu32(void)
2661 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) ))) return 0;
2662 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2664 menu
->wMagic
= MENU_MAGIC
;
2671 menu
->FocusedItem
= NO_SELECTED_ITEM
;
2672 dprintf_menu( stddeb
, "CreateMenu: return %04x\n", hMenu
);
2677 /**********************************************************************
2678 * DestroyMenu16 (USER.152)
2680 BOOL16
DestroyMenu16( HMENU16 hMenu
)
2682 return DestroyMenu32( hMenu
);
2686 /**********************************************************************
2687 * DestroyMenu32 (USER32.133)
2689 BOOL32
DestroyMenu32( HMENU32 hMenu
)
2692 dprintf_menu(stddeb
,"DestroyMenu(%04x)\n", hMenu
);
2694 if (hMenu
== 0) return FALSE
;
2695 /* Silently ignore attempts to destroy default system menu */
2696 if (hMenu
== MENU_DefSysMenu
) return TRUE
;
2697 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2698 if (!lppop
|| (lppop
->wMagic
!= MENU_MAGIC
)) return FALSE
;
2699 lppop
->wMagic
= 0; /* Mark it as destroyed */
2700 if ((lppop
->wFlags
& MF_POPUP
) &&
2702 (!pTopPWnd
|| (lppop
->hWnd
!= pTopPWnd
->hwndSelf
)))
2703 DestroyWindow32( lppop
->hWnd
);
2708 MENUITEM
*item
= lppop
->items
;
2709 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
2711 if (item
->item_flags
& MF_POPUP
)
2712 DestroyMenu32( (HMENU32
)item
->item_id
);
2713 if (IS_STRING_ITEM(item
->item_flags
) && item
->text
)
2714 HeapFree( SystemHeap
, 0, item
->text
);
2716 HeapFree( SystemHeap
, 0, lppop
->items
);
2718 USER_HEAP_FREE( hMenu
);
2723 /**********************************************************************
2724 * GetSystemMenu16 (USER.156)
2726 HMENU16
GetSystemMenu16( HWND16 hWnd
, BOOL16 bRevert
)
2728 return GetSystemMenu32( hWnd
, bRevert
);
2732 /**********************************************************************
2733 * GetSystemMenu32 (USER32.290)
2735 HMENU32
GetSystemMenu32( HWND32 hWnd
, BOOL32 bRevert
)
2737 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
2738 if (!wndPtr
) return 0;
2740 if (!wndPtr
->hSysMenu
|| (wndPtr
->hSysMenu
== MENU_DefSysMenu
))
2742 wndPtr
->hSysMenu
= MENU_CopySysMenu();
2743 return wndPtr
->hSysMenu
;
2745 if (!bRevert
) return wndPtr
->hSysMenu
;
2746 if (wndPtr
->hSysMenu
) DestroyMenu32(wndPtr
->hSysMenu
);
2747 wndPtr
->hSysMenu
= MENU_CopySysMenu();
2748 return wndPtr
->hSysMenu
;
2752 /*******************************************************************
2753 * SetSystemMenu16 (USER.280)
2755 BOOL16
SetSystemMenu16( HWND16 hwnd
, HMENU16 hMenu
)
2757 return SetSystemMenu32( hwnd
, hMenu
);
2761 /*******************************************************************
2762 * SetSystemMenu32 (USER32.507)
2764 BOOL32
SetSystemMenu32( HWND32 hwnd
, HMENU32 hMenu
)
2768 if (!(wndPtr
= WIN_FindWndPtr(hwnd
))) return FALSE
;
2769 if (wndPtr
->hSysMenu
&& (wndPtr
->hSysMenu
!= MENU_DefSysMenu
))
2770 DestroyMenu32( wndPtr
->hSysMenu
);
2771 wndPtr
->hSysMenu
= hMenu
;
2776 /**********************************************************************
2777 * GetMenu16 (USER.157)
2779 HMENU16
GetMenu16( HWND16 hWnd
)
2781 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
2782 if (wndPtr
) return (HMENU16
)wndPtr
->wIDmenu
;
2787 /**********************************************************************
2788 * GetMenu32 (USER32.256)
2790 HMENU32
GetMenu32( HWND32 hWnd
)
2792 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
2793 if (wndPtr
) return (HMENU32
)wndPtr
->wIDmenu
;
2798 /**********************************************************************
2799 * SetMenu16 (USER.158)
2801 BOOL16
SetMenu16( HWND16 hWnd
, HMENU16 hMenu
)
2803 return SetMenu32( hWnd
, hMenu
);
2807 /**********************************************************************
2808 * SetMenu32 (USER32.486)
2810 BOOL32
SetMenu32( HWND32 hWnd
, HMENU32 hMenu
)
2813 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
2814 if (!wndPtr
) return FALSE
;
2815 dprintf_menu(stddeb
,"SetMenu(%04x, %04x);\n", hWnd
, hMenu
);
2816 if (GetCapture32() == hWnd
) ReleaseCapture();
2817 wndPtr
->wIDmenu
= (UINT32
)hMenu
;
2820 if (!(lpmenu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
2821 lpmenu
->hWnd
= hWnd
;
2822 lpmenu
->wFlags
&= ~MF_POPUP
; /* Can't be a popup */
2823 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
2825 if (IsWindowVisible32(hWnd
))
2826 SetWindowPos32( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
2827 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
2833 /**********************************************************************
2834 * GetSubMenu16 (USER.159)
2836 HMENU16
GetSubMenu16( HMENU16 hMenu
, INT16 nPos
)
2838 return GetSubMenu32( hMenu
, nPos
);
2842 /**********************************************************************
2843 * GetSubMenu32 (USER32.287)
2845 HMENU32
GetSubMenu32( HMENU32 hMenu
, INT32 nPos
)
2849 if (!(lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return 0;
2850 if ((UINT32
)nPos
>= lppop
->nItems
) return 0;
2851 if (!(lppop
->items
[nPos
].item_flags
& MF_POPUP
)) return 0;
2852 return (HMENU32
)lppop
->items
[nPos
].item_id
;
2856 /**********************************************************************
2857 * DrawMenuBar16 (USER.160)
2859 void DrawMenuBar16( HWND16 hWnd
)
2861 DrawMenuBar32( hWnd
);
2865 /**********************************************************************
2866 * DrawMenuBar32 (USER32.160)
2868 BOOL32
DrawMenuBar32( HWND32 hWnd
)
2871 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
2872 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
) && wndPtr
->wIDmenu
)
2874 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR((HMENU16
)wndPtr
->wIDmenu
);
2875 if (lppop
== NULL
) return FALSE
;
2877 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
2878 SetWindowPos32( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
2879 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
2886 /***********************************************************************
2887 * EndMenu (USER.187) (USER32.174)
2891 /* FIXME: this won't work when we have multiple tasks... */
2892 fEndMenuCalled
= TRUE
;
2896 /***********************************************************************
2897 * LookupMenuHandle (USER.217)
2899 HMENU16
LookupMenuHandle( HMENU16 hmenu
, INT16 id
)
2901 HMENU32 hmenu32
= hmenu
;
2903 if (!MENU_FindItem( &hmenu32
, &id32
, MF_BYCOMMAND
)) return 0;
2904 else return hmenu32
;
2908 /**********************************************************************
2909 * LoadMenu16 (USER.150)
2911 HMENU16
LoadMenu16( HINSTANCE16 instance
, SEGPTR name
)
2919 char *str
= (char *)PTR_SEG_TO_LIN( name
);
2920 dprintf_menu( stddeb
, "LoadMenu(%04x,'%s')\n", instance
, str
);
2921 if (str
[0] == '#') name
= (SEGPTR
)atoi( str
+ 1 );
2924 dprintf_resource(stddeb
,"LoadMenu(%04x,%04x)\n",instance
,LOWORD(name
));
2926 if (!name
) return 0;
2928 /* check for Win32 module */
2929 instance
= GetExePtr( instance
);
2930 if (MODULE_GetPtr(instance
)->flags
& NE_FFLAGS_WIN32
)
2931 return LoadMenu32A(instance
,PTR_SEG_TO_LIN(name
));
2933 if (!(hRsrc
= FindResource16( instance
, name
, RT_MENU
))) return 0;
2934 if (!(handle
= LoadResource16( instance
, hRsrc
))) return 0;
2935 hMenu
= LoadMenuIndirect16(LockResource16(handle
));
2936 FreeResource16( handle
);
2941 /*****************************************************************
2942 * LoadMenu32A (USER32.370)
2944 HMENU32
LoadMenu32A( HINSTANCE32 instance
, LPCSTR name
)
2946 HRSRC32 hrsrc
= FindResource32A( instance
, name
, (LPSTR
)RT_MENU
);
2947 if (!hrsrc
) return 0;
2948 return LoadMenuIndirect32A( (LPCVOID
)LoadResource32( instance
, hrsrc
));
2952 /*****************************************************************
2953 * LoadMenu32W (USER32.372)
2955 HMENU32
LoadMenu32W( HINSTANCE32 instance
, LPCWSTR name
)
2957 HRSRC32 hrsrc
= FindResource32W( instance
, name
, (LPWSTR
)RT_MENU
);
2958 if (!hrsrc
) return 0;
2959 return LoadMenuIndirect32W( (LPCVOID
)LoadResource32( instance
, hrsrc
));
2963 /**********************************************************************
2964 * LoadMenuIndirect16 (USER.220)
2966 HMENU16
LoadMenuIndirect16( LPCVOID
template )
2969 WORD version
, offset
;
2970 LPCSTR p
= (LPCSTR
)template;
2972 dprintf_menu(stddeb
,"LoadMenuIndirect16: %p\n", template );
2973 version
= GET_WORD(p
);
2977 fprintf( stderr
, "LoadMenuIndirect16: version must be 0 for Win16\n" );
2980 offset
= GET_WORD(p
);
2981 p
+= sizeof(WORD
) + offset
;
2982 if (!(hMenu
= CreateMenu32())) return 0;
2983 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
2985 DestroyMenu32( hMenu
);
2992 /**********************************************************************
2993 * LoadMenuIndirect32A (USER32.370)
2995 HMENU32
LoadMenuIndirect32A( LPCVOID
template )
2998 WORD version
, offset
;
2999 LPCSTR p
= (LPCSTR
)template;
3001 dprintf_menu(stddeb
,"LoadMenuIndirect16: %p\n", template );
3002 version
= GET_WORD(p
);
3006 fprintf( stderr
, "LoadMenuIndirect32A: version %d not supported.\n",
3010 offset
= GET_WORD(p
);
3011 p
+= sizeof(WORD
) + offset
;
3012 if (!(hMenu
= CreateMenu32())) return 0;
3013 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
3015 DestroyMenu32( hMenu
);
3022 /**********************************************************************
3023 * LoadMenuIndirect32W (USER32.371)
3025 HMENU32
LoadMenuIndirect32W( LPCVOID
template )
3027 /* FIXME: is there anything different between A and W? */
3028 return LoadMenuIndirect32A( template );
3032 /**********************************************************************
3033 * IsMenu16 (USER.358)
3035 BOOL16
IsMenu16( HMENU16 hmenu
)
3038 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
3039 return (menu
->wMagic
== MENU_MAGIC
);
3043 /**********************************************************************
3044 * IsMenu32 (USER32.345)
3046 BOOL32
IsMenu32( HMENU32 hmenu
)
3049 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
3050 return (menu
->wMagic
== MENU_MAGIC
);