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"
34 /* Menu item structure */
37 WORD item_flags
; /* Item flags */
38 UINT item_id
; /* Item or popup id */
39 RECT16 rect
; /* Item area (relative to menu window) */
40 WORD xTab
; /* X position of text after Tab */
41 HBITMAP16 hCheckBit
; /* Bitmap for checked item */
42 HBITMAP16 hUnCheckBit
; /* Bitmap for unchecked item */
43 LPSTR text
; /* Item text or bitmap handle */
46 /* Popup menu structure */
49 WORD wFlags
; /* Menu flags (MF_POPUP, MF_SYSMENU) */
50 WORD wMagic
; /* Magic number */
51 HQUEUE16 hTaskQ
; /* Task queue for this menu */
52 WORD Width
; /* Width of the whole menu */
53 WORD Height
; /* Height of the whole menu */
54 WORD nItems
; /* Number of items in the menu */
55 HWND hWnd
; /* Window containing the menu */
56 MENUITEM
*items
; /* Array of menu items */
57 UINT FocusedItem
; /* Currently focused item */
58 } POPUPMENU
, *LPPOPUPMENU
;
60 #define MENU_MAGIC 0x554d /* 'MU' */
65 /* Dimension of the menu bitmaps */
66 static WORD check_bitmap_width
= 0, check_bitmap_height
= 0;
67 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
69 /* Flag set by EndMenu() to force an exit from menu tracking */
70 static BOOL fEndMenuCalled
= FALSE
;
72 /* Space between 2 menu bar items */
73 #define MENU_BAR_ITEMS_SPACE 16
75 /* Minimum width of a tab character */
76 #define MENU_TAB_SPACE 8
78 /* Height of a separator item */
79 #define SEPARATOR_HEIGHT 5
81 /* Values for menu->FocusedItem */
82 /* (other values give the position of the focused item) */
83 #define NO_SELECTED_ITEM 0xffff
84 #define SYSMENU_SELECTED 0xfffe /* Only valid on menu-bars */
86 #define IS_STRING_ITEM(flags) \
87 (!((flags) & (MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)))
89 extern void NC_DrawSysButton(HWND hwnd
, HDC32 hdc
, BOOL down
); /*nonclient.c*/
90 extern BOOL
NC_GetSysPopupPos(WND
* wndPtr
, RECT16
* rect
);
91 extern HTASK16
TASK_GetNextTask(HTASK16
);
93 static HBITMAP16 hStdCheck
= 0;
94 static HBITMAP16 hStdMnArrow
= 0;
95 static HMENU16 MENU_DefSysMenu
= 0; /* Default system menu */
98 /* we _can_ use global popup window because there's no way 2 menues can
99 * be tracked at the same time.
102 static WND
* pTopPWnd
= 0;
103 static UINT uSubPWndLevel
= 0;
106 /**********************************************************************
109 * Load a copy of the system menu.
111 static HMENU16
MENU_CopySysMenu(void)
117 if (!(handle
= SYSRES_LoadResource( SYSRES_MENU_SYSMENU
))) return 0;
118 hMenu
= LoadMenuIndirect16( GlobalLock16( handle
) );
119 SYSRES_FreeResource( handle
);
122 dprintf_menu(stddeb
,"No SYSMENU\n");
125 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
126 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
127 dprintf_menu(stddeb
,"CopySysMenu hMenu=%04x !\n", hMenu
);
132 /***********************************************************************
135 * Menus initialisation.
143 if (!(hStdCheck
= LoadBitmap16( 0, MAKEINTRESOURCE(OBM_CHECK
) )))
145 GetObject16( hStdCheck
, sizeof(bm
), &bm
);
146 check_bitmap_width
= bm
.bmWidth
;
147 check_bitmap_height
= bm
.bmHeight
;
148 if (!(hStdMnArrow
= LoadBitmap16( 0, MAKEINTRESOURCE(OBM_MNARROW
) )))
150 GetObject16( hStdMnArrow
, sizeof(bm
), &bm
);
151 arrow_bitmap_width
= bm
.bmWidth
;
152 arrow_bitmap_height
= bm
.bmHeight
;
154 if (!(MENU_DefSysMenu
= MENU_CopySysMenu()))
156 fprintf( stderr
, "Unable to create default system menu\n" );
163 /***********************************************************************
166 * Return the default system menu.
168 HMENU16
MENU_GetDefSysMenu(void)
170 return MENU_DefSysMenu
;
174 /***********************************************************************
177 * Check whether the window owning the menu bar has a system menu.
179 static BOOL
MENU_HasSysMenu( POPUPMENU
*menu
)
183 if (menu
->wFlags
& MF_POPUP
) return FALSE
;
184 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return FALSE
;
185 return (wndPtr
->dwStyle
& WS_SYSMENU
) != 0;
189 /***********************************************************************
192 * Check whether the point (in screen coords) is in the system menu
193 * of the window owning the given menu.
195 static BOOL
MENU_IsInSysMenu( POPUPMENU
*menu
, POINT16 pt
)
199 if (menu
->wFlags
& MF_POPUP
) return FALSE
;
200 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return FALSE
;
201 if (!(wndPtr
->dwStyle
& WS_SYSMENU
)) return FALSE
;
202 if ((pt
.x
< wndPtr
->rectClient
.left
) ||
203 (pt
.x
>= wndPtr
->rectClient
.left
+SYSMETRICS_CXSIZE
+SYSMETRICS_CXBORDER
))
205 if ((pt
.y
>= wndPtr
->rectClient
.top
- menu
->Height
) ||
206 (pt
.y
< wndPtr
->rectClient
.top
- menu
->Height
-
207 SYSMETRICS_CYSIZE
- SYSMETRICS_CYBORDER
)) return FALSE
;
212 /***********************************************************************
213 * MENU_InitSysMenuPopup
215 * Grey the appropriate items in System menu.
217 void MENU_InitSysMenuPopup(HMENU16 hmenu
, DWORD style
, DWORD clsStyle
)
221 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
222 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
223 gray
= ((style
& WS_MAXIMIZE
) != 0);
224 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
225 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
226 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
227 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
228 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
229 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
230 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
231 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
232 EnableMenuItem( hmenu
, SC_CLOSE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
236 /***********************************************************************
239 * Find a menu item. Return a pointer on the item, and modifies *hmenu
240 * in case the item was in a sub-menu.
242 static MENUITEM
*MENU_FindItem( HMENU16
*hmenu
, UINT
*nPos
, UINT wFlags
)
247 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(*hmenu
))) return NULL
;
248 if (wFlags
& MF_BYPOSITION
)
250 if (*nPos
>= menu
->nItems
) return NULL
;
251 return &menu
->items
[*nPos
];
255 MENUITEM
*item
= menu
->items
;
256 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
258 if (item
->item_id
== *nPos
)
263 else if (item
->item_flags
& MF_POPUP
)
265 HMENU16 hsubmenu
= (HMENU16
)item
->item_id
;
266 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
279 /***********************************************************************
280 * MENU_FindItemByCoords
282 * Find the item at the specified coordinates (screen coords).
284 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
, int x
, int y
, UINT
*pos
)
290 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return NULL
;
291 x
-= wndPtr
->rectWindow
.left
;
292 y
-= wndPtr
->rectWindow
.top
;
294 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
296 if ((x
>= item
->rect
.left
) && (x
< item
->rect
.right
) &&
297 (y
>= item
->rect
.top
) && (y
< item
->rect
.bottom
))
307 /***********************************************************************
310 * Find the menu item selected by a key press.
311 * Return item id, -1 if none, -2 if we should close the menu.
313 static UINT
MENU_FindItemByKey( HWND hwndOwner
, HMENU16 hmenu
, UINT key
)
320 if (!IsMenu( hmenu
)) hmenu
= WIN_FindWndPtr(hwndOwner
)->hSysMenu
;
321 if (!hmenu
) return -1;
323 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
326 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
328 if (IS_STRING_ITEM(item
->item_flags
))
330 char *p
= strchr( item
->text
, '&' );
331 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 -2;
342 /***********************************************************************
345 * Calculate the size of the menu item and store it in lpitem->rect.
347 static void MENU_CalcItemSize( HDC32 hdc
, MENUITEM
*lpitem
, HWND hwndOwner
,
348 int orgX
, int orgY
, BOOL menuBar
)
353 SetRect16( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
355 if (lpitem
->item_flags
& MF_OWNERDRAW
)
357 MEASUREITEMSTRUCT16
*mis
;
358 if (!(mis
= SEGPTR_NEW(MEASUREITEMSTRUCT16
))) return;
359 mis
->CtlType
= ODT_MENU
;
360 mis
->itemID
= lpitem
->item_id
;
361 mis
->itemData
= (DWORD
)lpitem
->text
;
362 mis
->itemHeight
= 16;
364 SendMessage16( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)SEGPTR_GET(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
);
373 if (lpitem
->item_flags
& MF_SEPARATOR
)
375 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
381 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
382 if (lpitem
->item_flags
& MF_POPUP
)
383 lpitem
->rect
.right
+= arrow_bitmap_width
;
386 if (lpitem
->item_flags
& MF_BITMAP
)
389 if (GetObject16( (HBITMAP16
)(UINT32
)lpitem
->text
, sizeof(bm
), &bm
))
391 lpitem
->rect
.right
+= bm
.bmWidth
;
392 lpitem
->rect
.bottom
+= bm
.bmHeight
;
397 /* If we get here, then it must be a text item */
399 if (IS_STRING_ITEM( lpitem
->item_flags
))
401 dwSize
= GetTextExtent( hdc
, lpitem
->text
, strlen(lpitem
->text
) );
402 lpitem
->rect
.right
+= LOWORD(dwSize
);
403 lpitem
->rect
.bottom
+= MAX( HIWORD(dwSize
), SYSMETRICS_CYMENU
);
406 if (menuBar
) lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
407 else if ((p
= strchr( lpitem
->text
, '\t' )) != NULL
)
409 /* Item contains a tab (only meaningful in popup menus) */
410 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+
411 LOWORD( GetTextExtent( hdc
, lpitem
->text
,
412 (int)(p
- lpitem
->text
) ));
413 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
417 if (strchr( lpitem
->text
, '\b' ))
418 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
419 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
420 - arrow_bitmap_width
;
426 /***********************************************************************
427 * MENU_PopupMenuCalcSize
429 * Calculate the size of a popup menu.
431 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND hwndOwner
)
436 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
438 lppop
->Width
= lppop
->Height
= 0;
439 if (lppop
->nItems
== 0) return;
442 while (start
< lppop
->nItems
)
444 lpitem
= &lppop
->items
[start
];
447 maxTab
= maxTabWidth
= 0;
449 /* Parse items until column break or end of menu */
450 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
453 (lpitem
->item_flags
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
454 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
455 if (lpitem
->item_flags
& MF_MENUBARBREAK
) orgX
++;
456 maxX
= MAX( maxX
, lpitem
->rect
.right
);
457 orgY
= lpitem
->rect
.bottom
;
458 if (IS_STRING_ITEM(lpitem
->item_flags
) && lpitem
->xTab
)
460 maxTab
= MAX( maxTab
, lpitem
->xTab
);
461 maxTabWidth
= MAX(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
465 /* Finish the column (set all items to the largest width found) */
466 maxX
= MAX( maxX
, maxTab
+ maxTabWidth
);
467 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
469 lpitem
->rect
.right
= maxX
;
470 if (IS_STRING_ITEM(lpitem
->item_flags
) && lpitem
->xTab
)
471 lpitem
->xTab
= maxTab
;
473 lppop
->Height
= MAX( lppop
->Height
, orgY
);
477 ReleaseDC32( 0, hdc
);
481 /***********************************************************************
482 * MENU_MenuBarCalcSize
484 * Calculate the size of the menu bar.
486 static void MENU_MenuBarCalcSize( HDC32 hdc
, LPRECT16 lprect
,
487 LPPOPUPMENU lppop
, HWND hwndOwner
)
490 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
492 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
493 if (lppop
->nItems
== 0) return;
494 dprintf_menu(stddeb
,"MENU_MenuBarCalcSize left=%d top=%d right=%d bottom=%d\n",
495 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
496 lppop
->Width
= lprect
->right
- lprect
->left
;
501 while (start
< lppop
->nItems
)
503 lpitem
= &lppop
->items
[start
];
507 /* Parse items until line break or end of menu */
508 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
510 if ((helpPos
== -1) && (lpitem
->item_flags
& MF_HELP
)) helpPos
= i
;
512 (lpitem
->item_flags
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
513 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
514 if (lpitem
->rect
.right
> lprect
->right
)
516 if (i
!= start
) break;
517 else lpitem
->rect
.right
= lprect
->right
;
519 maxY
= MAX( maxY
, lpitem
->rect
.bottom
);
520 orgX
= lpitem
->rect
.right
;
523 /* Finish the line (set all items to the largest height found) */
524 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
527 lprect
->bottom
= maxY
;
528 lppop
->Height
= lprect
->bottom
- lprect
->top
;
530 /* Flush right all items between the MF_HELP and the last item */
531 /* (if several lines, only move the last line) */
534 lpitem
= &lppop
->items
[lppop
->nItems
-1];
535 orgY
= lpitem
->rect
.top
;
536 orgX
= lprect
->right
;
537 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--)
539 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
540 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
541 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
542 lpitem
->rect
.right
= orgX
;
543 orgX
= lpitem
->rect
.left
;
549 /***********************************************************************
552 * Draw a single menu item.
554 static void MENU_DrawMenuItem( HWND hwnd
, HDC32 hdc
, MENUITEM
*lpitem
,
555 UINT height
, BOOL menuBar
)
559 if (lpitem
->item_flags
& MF_OWNERDRAW
)
561 DRAWITEMSTRUCT32 dis
;
563 dprintf_menu( stddeb
, "DrawMenuItem: Ownerdraw!\n" );
564 dis
.CtlType
= ODT_MENU
;
565 dis
.itemID
= lpitem
->item_id
;
566 dis
.itemData
= (DWORD
)lpitem
->text
;
568 if (lpitem
->item_flags
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
569 if (lpitem
->item_flags
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
;
570 if (lpitem
->item_flags
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
571 dis
.itemAction
= ODA_DRAWENTIRE
| ODA_SELECT
| ODA_FOCUS
;
574 CONV_RECT16TO32( &lpitem
->rect
, &dis
.rcItem
);
575 SendMessage32A( hwnd
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
579 if (menuBar
&& (lpitem
->item_flags
& MF_SEPARATOR
)) return;
582 /* Draw the background */
584 if (lpitem
->item_flags
& MF_HILITE
)
585 FillRect16( hdc
, &rect
, sysColorObjects
.hbrushHighlight
);
586 else FillRect16( hdc
, &rect
, sysColorObjects
.hbrushMenu
);
587 SetBkMode32( hdc
, TRANSPARENT
);
589 /* Draw the separator bar (if any) */
591 if (!menuBar
&& (lpitem
->item_flags
& MF_MENUBARBREAK
))
593 SelectObject32( hdc
, sysColorObjects
.hpenWindowFrame
);
594 MoveTo( hdc
, rect
.left
, 0 );
595 LineTo32( hdc
, rect
.left
, height
);
597 if (lpitem
->item_flags
& MF_SEPARATOR
)
599 SelectObject32( hdc
, sysColorObjects
.hpenWindowFrame
);
600 MoveTo( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
601 LineTo32( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
607 if (lpitem
->item_flags
& MF_HILITE
)
609 if (lpitem
->item_flags
& MF_GRAYED
)
610 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
612 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
613 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
617 if (lpitem
->item_flags
& MF_GRAYED
)
618 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
620 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
621 SetBkColor( hdc
, GetSysColor( COLOR_MENU
) );
626 /* Draw the check mark */
628 if (lpitem
->item_flags
& MF_CHECKED
)
630 GRAPH_DrawBitmap(hdc
, lpitem
->hCheckBit
? lpitem
->hCheckBit
:
631 hStdCheck
, rect
.left
,
632 (rect
.top
+rect
.bottom
-check_bitmap_height
) / 2,
633 0, 0, check_bitmap_width
, check_bitmap_height
);
635 else if (lpitem
->hUnCheckBit
!= 0) /* Not checked */
637 GRAPH_DrawBitmap(hdc
, lpitem
->hUnCheckBit
, rect
.left
,
638 (rect
.top
+rect
.bottom
-check_bitmap_height
) / 2,
639 0, 0, check_bitmap_width
, check_bitmap_height
);
642 /* Draw the popup-menu arrow */
644 if (lpitem
->item_flags
& MF_POPUP
)
646 GRAPH_DrawBitmap( hdc
, hStdMnArrow
,
647 rect
.right
-arrow_bitmap_width
-1,
648 (rect
.top
+rect
.bottom
-arrow_bitmap_height
) / 2,
649 0, 0, arrow_bitmap_width
, arrow_bitmap_height
);
652 rect
.left
+= check_bitmap_width
;
653 rect
.right
-= arrow_bitmap_width
;
656 /* Draw the item text or bitmap */
658 if (lpitem
->item_flags
& MF_BITMAP
)
660 GRAPH_DrawBitmap( hdc
, (HBITMAP16
)(UINT32
)lpitem
->text
,
661 rect
.left
, rect
.top
, 0, 0,
662 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
);
665 /* No bitmap - process text if present */
666 else if (IS_STRING_ITEM(lpitem
->item_flags
))
672 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
673 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
674 i
= strlen( lpitem
->text
);
678 for (i
= 0; lpitem
->text
[i
]; i
++)
679 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
683 DrawText16( hdc
, lpitem
->text
, i
, &rect
,
684 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
686 if (lpitem
->text
[i
]) /* There's a tab or flush-right char */
688 if (lpitem
->text
[i
] == '\t')
690 rect
.left
= lpitem
->xTab
;
691 DrawText16( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
,
692 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
694 else DrawText16( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
,
695 DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
);
701 /***********************************************************************
704 * Paint a popup menu.
706 static void MENU_DrawPopupMenu( HWND hwnd
, HDC32 hdc
, HMENU16 hmenu
)
713 GetClientRect16( hwnd
, &rect
);
714 FillRect16( hdc
, &rect
, sysColorObjects
.hbrushMenu
);
715 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
716 if (!menu
|| !menu
->nItems
) return;
717 for (i
= menu
->nItems
, item
= menu
->items
; i
> 0; i
--, item
++)
718 MENU_DrawMenuItem( hwnd
, hdc
, item
, menu
->Height
, FALSE
);
722 /***********************************************************************
725 * Paint a menu bar. Returns the height of the menu bar.
727 UINT
MENU_DrawMenuBar( HDC32 hDC
, LPRECT16 lprect
, HWND hwnd
,
732 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
734 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( (HMENU16
)wndPtr
->wIDmenu
);
735 if (lppop
== NULL
|| lprect
== NULL
) return SYSMETRICS_CYMENU
;
736 dprintf_menu(stddeb
,"MENU_DrawMenuBar(%04x, %p, %p); !\n",
738 if (lppop
->Height
== 0) MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
739 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
740 if (suppress_draw
) return lppop
->Height
;
742 FillRect16(hDC
, lprect
, sysColorObjects
.hbrushMenu
);
743 SelectObject32( hDC
, sysColorObjects
.hpenWindowFrame
);
744 MoveTo( hDC
, lprect
->left
, lprect
->bottom
);
745 LineTo32( hDC
, lprect
->right
, lprect
->bottom
);
747 if (lppop
->nItems
== 0) return SYSMETRICS_CYMENU
;
748 for (i
= 0; i
< lppop
->nItems
; i
++)
750 MENU_DrawMenuItem( hwnd
, hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
);
752 return lppop
->Height
;
756 /***********************************************************************
759 BOOL32
MENU_SwitchTPWndTo( HTASK16 hTask
)
761 /* This is supposed to be called when popup is hidden.
762 * AppExit() calls with hTask == 0, so we get the next to current.
767 if( !pTopPWnd
) return 0;
771 task
= (TDB
*)GlobalLock16( (hTask
= GetCurrentTask()) );
772 if( task
&& task
->hQueue
== pTopPWnd
->hmemTaskQ
)
773 hTask
= TASK_GetNextTask(hTask
);
777 task
= (TDB
*)GlobalLock16(hTask
);
778 if( !task
) return 0;
780 /* if this task got as far as menu tracking it must have a queue */
782 pTopPWnd
->hInstance
= task
->hInstance
;
783 pTopPWnd
->hmemTaskQ
= task
->hQueue
;
787 /***********************************************************************
790 * Display a popup menu.
792 static BOOL
MENU_ShowPopup(HWND hwndOwner
, HMENU16 hmenu
, UINT id
, int x
, int y
,
793 int xanchor
, int yanchor
)
800 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
801 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
803 menu
->items
[menu
->FocusedItem
].item_flags
&= ~(MF_HILITE
|MF_MOUSESELECT
);
804 menu
->FocusedItem
= NO_SELECTED_ITEM
;
806 SendMessage16( hwndOwner
, WM_INITMENUPOPUP
, (WPARAM16
)hmenu
,
807 MAKELONG( id
, (menu
->wFlags
& MF_SYSMENU
) ? 1 : 0 ));
808 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
810 /* adjust popup menu pos so that it fits within the desktop */
812 width
= menu
->Width
+ 2*SYSMETRICS_CXBORDER
;
813 height
= menu
->Height
+ 2*SYSMETRICS_CYBORDER
;
815 if( x
+ width
> SYSMETRICS_CXSCREEN
)
818 x
-= width
- xanchor
;
819 if( x
+ width
> SYSMETRICS_CXSCREEN
)
820 x
= SYSMETRICS_CXSCREEN
- width
;
825 if( y
+ height
> SYSMETRICS_CYSCREEN
)
828 y
-= height
+ yanchor
;
829 if( y
+ height
> SYSMETRICS_CYSCREEN
)
830 y
= SYSMETRICS_CYSCREEN
- height
;
835 wndPtr
= WIN_FindWndPtr( hwndOwner
);
836 if (!wndPtr
) return FALSE
;
840 pTopPWnd
= WIN_FindWndPtr(CreateWindow16( POPUPMENU_CLASS_ATOM
, NULL
,
841 WS_POPUP
| WS_BORDER
, x
, y
,
843 hwndOwner
, 0, wndPtr
->hInstance
,
844 (LPVOID
)(HMENU32
)hmenu
));
845 if (!pTopPWnd
) return FALSE
;
851 /* create new window for the submenu */
852 HWND hWnd
= CreateWindow16( POPUPMENU_CLASS_ATOM
, NULL
,
853 WS_POPUP
| WS_BORDER
, x
, y
,
855 menu
->hWnd
, 0, wndPtr
->hInstance
,
856 (LPVOID
)(HMENU32
)hmenu
);
857 if( !hWnd
) return FALSE
;
864 MENU_SwitchTPWndTo(GetCurrentTask());
865 SendMessage16( pTopPWnd
->hwndSelf
, WM_USER
, (WPARAM16
)hmenu
, 0L);
867 menu
->hWnd
= pTopPWnd
->hwndSelf
;
872 wndPtr
= WIN_FindWndPtr( menu
->hWnd
);
874 SetWindowPos(menu
->hWnd
, 0, x
, y
, width
, height
,
875 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_NOREDRAW
);
876 /* Display the window */
878 SetWindowPos( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
879 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
880 UpdateWindow( menu
->hWnd
);
885 /***********************************************************************
888 static void MENU_SelectItem( HWND hwndOwner
, HMENU16 hmenu
, UINT wIndex
,
889 BOOL sendMenuSelect
)
894 lppop
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
895 if (!lppop
->nItems
) return;
896 if ((wIndex
!= NO_SELECTED_ITEM
) &&
897 (wIndex
!= SYSMENU_SELECTED
) &&
898 (lppop
->items
[wIndex
].item_flags
& MF_SEPARATOR
))
899 wIndex
= NO_SELECTED_ITEM
;
900 if (lppop
->FocusedItem
== wIndex
) return;
901 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC32( lppop
->hWnd
);
902 else hdc
= GetDCEx32( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
904 /* Clear previous highlighted item */
905 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
907 if (lppop
->FocusedItem
== SYSMENU_SELECTED
)
908 NC_DrawSysButton( lppop
->hWnd
, hdc
, FALSE
);
911 lppop
->items
[lppop
->FocusedItem
].item_flags
&=~(MF_HILITE
|MF_MOUSESELECT
);
912 MENU_DrawMenuItem(lppop
->hWnd
,hdc
,&lppop
->items
[lppop
->FocusedItem
],
913 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
) );
917 /* Highlight new item (if any) */
918 lppop
->FocusedItem
= wIndex
;
919 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
921 if (lppop
->FocusedItem
== SYSMENU_SELECTED
)
923 NC_DrawSysButton( lppop
->hWnd
, hdc
, TRUE
);
925 SendMessage16( hwndOwner
, WM_MENUSELECT
,
926 WIN_FindWndPtr(lppop
->hWnd
)->hSysMenu
,
927 MAKELONG(lppop
->wFlags
| MF_MOUSESELECT
, hmenu
));
931 lppop
->items
[lppop
->FocusedItem
].item_flags
|= MF_HILITE
;
932 MENU_DrawMenuItem( lppop
->hWnd
, hdc
, &lppop
->items
[lppop
->FocusedItem
],
933 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
) );
935 SendMessage16( hwndOwner
, WM_MENUSELECT
,
936 lppop
->items
[lppop
->FocusedItem
].item_id
,
937 MAKELONG( lppop
->items
[lppop
->FocusedItem
].item_flags
| MF_MOUSESELECT
, hmenu
));
940 else if (sendMenuSelect
)
941 SendMessage16( hwndOwner
, WM_MENUSELECT
, hmenu
,
942 MAKELONG( lppop
->wFlags
| MF_MOUSESELECT
, hmenu
) );
944 ReleaseDC32( lppop
->hWnd
, hdc
);
948 /***********************************************************************
952 static void MENU_SelectItemRel( HWND hwndOwner
, HMENU16 hmenu
, int offset
)
957 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
958 if (!menu
->items
) return;
959 if ((menu
->FocusedItem
!= NO_SELECTED_ITEM
) &&
960 (menu
->FocusedItem
!= SYSMENU_SELECTED
))
962 for (i
= menu
->FocusedItem
+ offset
; i
>= 0 && i
< menu
->nItems
965 if (!(menu
->items
[i
].item_flags
& MF_SEPARATOR
))
967 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
972 if (MENU_HasSysMenu( menu
))
974 MENU_SelectItem( hwndOwner
, hmenu
, SYSMENU_SELECTED
, TRUE
);
979 if( offset
> 0 ) { i
= 0; min
= -1; }
980 else i
= menu
->nItems
- 1;
982 for ( ; i
> min
&& i
< menu
->nItems
; i
+= offset
)
984 if (!(menu
->items
[i
].item_flags
& MF_SEPARATOR
))
986 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
990 if (MENU_HasSysMenu( menu
))
991 MENU_SelectItem( hwndOwner
, hmenu
, SYSMENU_SELECTED
, TRUE
);
995 /**********************************************************************
998 * Set an item flags, id and text ptr.
1000 static BOOL
MENU_SetItemData( MENUITEM
*item
, UINT flags
, UINT id
, LPCSTR str
)
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
) || (flags
& MF_OWNERDRAW
))
1025 item
->text
= (LPSTR
)str
;
1026 else item
->text
= NULL
;
1028 item
->item_flags
= flags
& ~(MF_HILITE
| MF_MOUSESELECT
);
1030 SetRectEmpty16( &item
->rect
);
1031 if (prevText
) HeapFree( SystemHeap
, 0, prevText
);
1036 /**********************************************************************
1039 * Insert a new item into a menu.
1041 static MENUITEM
*MENU_InsertItem( HMENU16 hMenu
, UINT pos
, UINT 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
== (UINT
)-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
, HMENU16 hMenu
, BOOL 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 HMENU16 hSubMenu
= CreatePopupMenu();
1130 if (!hSubMenu
) return NULL
;
1131 if (!(res
= MENU_ParseResource( res
, hSubMenu
, unicode
)))
1133 if (!unicode
) AppendMenu32A( hMenu
, flags
, (UINT
)hSubMenu
, str
);
1134 else AppendMenu32W( hMenu
, flags
, (UINT
)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 HMENU16
MENU_GetSubPopup( HMENU16 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 (HMENU16
)item
->item_id
;
1169 /***********************************************************************
1170 * MENU_HideSubPopups
1172 * Hide the sub-popup menus of this menu.
1174 static void MENU_HideSubPopups( HWND hwndOwner
, HMENU16 hmenu
,
1175 BOOL 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
= (HMENU16
)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 ShowWindow( submenu
->hWnd
, SW_HIDE
);
1205 DestroyWindow( 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 HMENU16
MENU_ShowSubPopup( HWND hwndOwner
, HMENU16 hmenu
,
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
);
1234 if (selectFirst
) MENU_SelectItemRel( hwndOwner
, wndPtr
->hSysMenu
, ITEM_NEXT
);
1235 return wndPtr
->hSysMenu
;
1237 item
= &menu
->items
[menu
->FocusedItem
];
1238 if (!(item
->item_flags
& MF_POPUP
) ||
1239 (item
->item_flags
& (MF_GRAYED
| MF_DISABLED
))) return hmenu
;
1240 item
->item_flags
|= MF_MOUSESELECT
;
1241 if (menu
->wFlags
& MF_POPUP
)
1243 MENU_ShowPopup( hwndOwner
, (HMENU16
)item
->item_id
, menu
->FocusedItem
,
1244 wndPtr
->rectWindow
.left
+ item
->rect
.right
-arrow_bitmap_width
,
1245 wndPtr
->rectWindow
.top
+ item
->rect
.top
,
1246 item
->rect
.left
- item
->rect
.right
+ 2*arrow_bitmap_width
,
1247 item
->rect
.top
- item
->rect
.bottom
);
1251 MENU_ShowPopup( hwndOwner
, (HMENU16
)item
->item_id
, menu
->FocusedItem
,
1252 wndPtr
->rectWindow
.left
+ item
->rect
.left
,
1253 wndPtr
->rectWindow
.top
+ item
->rect
.bottom
,
1254 item
->rect
.right
- item
->rect
.left
, item
->rect
.bottom
- item
->rect
.top
);
1256 if (selectFirst
) MENU_SelectItemRel( hwndOwner
, (HMENU16
)item
->item_id
, ITEM_NEXT
);
1257 return (HMENU16
)item
->item_id
;
1261 /***********************************************************************
1262 * MENU_FindMenuByCoords
1264 * Find the menu containing a given point (in screen coords).
1266 static HMENU16
MENU_FindMenuByCoords( HMENU16 hmenu
, POINT16 pt
)
1271 if (!(hwnd
= WindowFromPoint16( pt
))) return 0;
1274 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1275 if (menu
->hWnd
== hwnd
)
1277 if (!(menu
->wFlags
& MF_POPUP
))
1279 /* Make sure it's in the menu bar (or in system menu) */
1280 WND
*wndPtr
= WIN_FindWndPtr( menu
->hWnd
);
1281 if ((pt
.x
< wndPtr
->rectClient
.left
) ||
1282 (pt
.x
>= wndPtr
->rectClient
.right
) ||
1283 (pt
.y
>= wndPtr
->rectClient
.top
)) return 0;
1284 if (pt
.y
< wndPtr
->rectClient
.top
- menu
->Height
)
1286 if (!MENU_IsInSysMenu( menu
, pt
)) return 0;
1288 /* else it's in the menu bar */
1292 hmenu
= MENU_GetSubPopup( hmenu
);
1298 /***********************************************************************
1299 * MENU_ExecFocusedItem
1301 * Execute a menu item (for instance when user pressed Enter).
1302 * Return TRUE if we can go on with menu tracking.
1304 static BOOL
MENU_ExecFocusedItem( HWND hwndOwner
, HMENU16 hmenu
,
1305 HMENU16
*hmenuCurrent
)
1308 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1309 if (!menu
|| !menu
->nItems
|| (menu
->FocusedItem
== NO_SELECTED_ITEM
) ||
1310 (menu
->FocusedItem
== SYSMENU_SELECTED
)) return TRUE
;
1311 item
= &menu
->items
[menu
->FocusedItem
];
1312 if (!(item
->item_flags
& MF_POPUP
))
1314 if (!(item
->item_flags
& (MF_GRAYED
| MF_DISABLED
)))
1316 PostMessage( hwndOwner
, (menu
->wFlags
& MF_SYSMENU
) ?
1317 WM_SYSCOMMAND
: WM_COMMAND
, item
->item_id
, 0 );
1324 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, TRUE
);
1330 /***********************************************************************
1333 * Handle a button-down event in a menu. Point is in screen coords.
1334 * hmenuCurrent is the top-most visible popup.
1335 * Return TRUE if we can go on with menu tracking.
1337 static BOOL
MENU_ButtonDown( HWND hwndOwner
, HMENU16 hmenu
,
1338 HMENU16
*hmenuCurrent
, POINT16 pt
)
1344 if (!hmenu
) return FALSE
; /* Outside all menus */
1345 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1346 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1347 if (!item
) /* Maybe in system menu */
1349 if (!MENU_IsInSysMenu( menu
, pt
)) return FALSE
;
1350 id
= SYSMENU_SELECTED
;
1353 if (menu
->FocusedItem
== id
)
1355 if (id
== SYSMENU_SELECTED
) return FALSE
;
1356 if (item
->item_flags
& MF_POPUP
)
1358 if (item
->item_flags
& MF_MOUSESELECT
)
1360 if (menu
->wFlags
& MF_POPUP
)
1362 MENU_HideSubPopups( hwndOwner
, hmenu
, TRUE
);
1363 *hmenuCurrent
= hmenu
;
1367 else *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1372 MENU_HideSubPopups( hwndOwner
, hmenu
, FALSE
);
1373 MENU_SelectItem( hwndOwner
, hmenu
, id
, TRUE
);
1374 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1380 /***********************************************************************
1383 * Handle a button-up event in a menu. Point is in screen coords.
1384 * hmenuCurrent is the top-most visible popup.
1385 * Return TRUE if we can go on with menu tracking.
1387 static BOOL
MENU_ButtonUp( HWND hwndOwner
, HMENU16 hmenu
,
1388 HMENU16
*hmenuCurrent
, POINT16 pt
)
1392 HMENU16 hsubmenu
= 0;
1395 if (!hmenu
) return FALSE
; /* Outside all menus */
1396 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1397 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1398 if (!item
) /* Maybe in system menu */
1400 if (!MENU_IsInSysMenu( menu
, pt
)) return FALSE
;
1401 id
= SYSMENU_SELECTED
;
1402 hsubmenu
= WIN_FindWndPtr(menu
->hWnd
)->hSysMenu
;
1405 if (menu
->FocusedItem
!= id
) return FALSE
;
1407 if (id
!= SYSMENU_SELECTED
)
1409 if (!(item
->item_flags
& MF_POPUP
))
1411 return MENU_ExecFocusedItem( hwndOwner
, hmenu
, hmenuCurrent
);
1413 hsubmenu
= (HMENU16
)item
->item_id
;
1415 /* Select first item of sub-popup */
1416 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, FALSE
);
1417 MENU_SelectItemRel( hwndOwner
, hsubmenu
, ITEM_NEXT
);
1422 /***********************************************************************
1425 * Handle a motion event in a menu. Point is in screen coords.
1426 * hmenuCurrent is the top-most visible popup.
1427 * Return TRUE if we can go on with menu tracking.
1429 static BOOL
MENU_MouseMove( HWND hwndOwner
, HMENU16 hmenu
,
1430 HMENU16
*hmenuCurrent
, POINT16 pt
)
1433 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1434 UINT id
= NO_SELECTED_ITEM
;
1438 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1439 if (!item
) /* Maybe in system menu */
1441 if (!MENU_IsInSysMenu( menu
, pt
))
1442 id
= NO_SELECTED_ITEM
; /* Outside all items */
1443 else id
= SYSMENU_SELECTED
;
1446 if (id
== NO_SELECTED_ITEM
)
1448 MENU_SelectItem( hwndOwner
, *hmenuCurrent
, NO_SELECTED_ITEM
, TRUE
);
1450 else if (menu
->FocusedItem
!= id
)
1452 MENU_HideSubPopups( hwndOwner
, hmenu
, FALSE
);
1453 MENU_SelectItem( hwndOwner
, hmenu
, id
, TRUE
);
1454 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1459 /***********************************************************************
1462 static LRESULT
MENU_DoNextMenu( HWND
* hwndOwner
, HMENU16
* hmenu
,
1463 HMENU16
*hmenuCurrent
, UINT vk
)
1465 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( *hmenu
);
1468 if( (vk
== VK_LEFT
&& !menu
->FocusedItem
)
1469 || (vk
== VK_RIGHT
&& menu
->FocusedItem
== menu
->nItems
- 1)
1470 || menu
->FocusedItem
== SYSMENU_SELECTED
1471 || ((menu
->wFlags
& (MF_POPUP
| MF_SYSMENU
)) == (MF_POPUP
| MF_SYSMENU
)) )
1473 LRESULT l
= SendMessage16( *hwndOwner
, WM_NEXTMENU
, (WPARAM16
)vk
,
1474 (LPARAM
)((menu
->FocusedItem
== SYSMENU_SELECTED
)
1475 ? GetSystemMenu( *hwndOwner
, 0)
1478 if( l
== 0 || !IsMenu(LOWORD(l
)) || !IsWindow(HIWORD(l
)) ) return 0;
1480 /* shutdown current menu -
1481 * all these checks for system popup window are needed
1482 * only because Wine system menu tracking is unsuitable
1483 * for a lot of things (esp. when we do not have wIDmenu to fall back on).
1486 MENU_SelectItem( *hwndOwner
, *hmenu
, NO_SELECTED_ITEM
, FALSE
);
1488 if( (menu
->wFlags
& (MF_POPUP
| MF_SYSMENU
)) == (MF_POPUP
| MF_SYSMENU
) )
1490 ShowWindow( menu
->hWnd
, SW_HIDE
);
1493 if( !IsIconic( *hwndOwner
) )
1495 HDC32 hdc
= GetDCEx32( *hwndOwner
, 0, DCX_CACHE
| DCX_WINDOW
);
1496 NC_DrawSysButton( *hwndOwner
, hdc
, FALSE
);
1497 ReleaseDC32( *hwndOwner
, hdc
);
1502 *hwndOwner
= HIWORD(l
);
1504 SetCapture32( *hwndOwner
);
1506 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( *hmenu
);
1508 /* init next menu */
1510 if( (menu
->wFlags
& (MF_POPUP
| MF_SYSMENU
)) == (MF_POPUP
| MF_SYSMENU
) )
1513 WND
* wndPtr
= WIN_FindWndPtr( *hwndOwner
);
1515 /* stupid kludge, see above */
1517 if( wndPtr
->wIDmenu
&& !(wndPtr
->dwStyle
& WS_CHILD
) )
1518 { *hmenu
= wndPtr
->wIDmenu
; id
= SYSMENU_SELECTED
; }
1521 if( NC_GetSysPopupPos( wndPtr
, &rect
) )
1522 MENU_ShowPopup( *hwndOwner
, *hmenu
, 0, rect
.left
, rect
.bottom
,
1523 SYSMETRICS_CXSIZE
, SYSMETRICS_CYSIZE
);
1525 if( !IsIconic( *hwndOwner
) )
1527 HDC32 hdc
= GetDCEx32( *hwndOwner
, 0, DCX_CACHE
| DCX_WINDOW
);
1528 NC_DrawSysButton( *hwndOwner
, hdc
, TRUE
);
1529 ReleaseDC32( *hwndOwner
, hdc
);
1534 MENU_SelectItem( *hwndOwner
, *hmenu
, id
, TRUE
);
1540 /***********************************************************************
1543 * Handle a VK_LEFT key event in a menu.
1544 * hmenuCurrent is the top-most visible popup.
1546 static void MENU_KeyLeft( HWND
* hwndOwner
, HMENU16
* hmenu
,
1547 HMENU16
*hmenuCurrent
)
1550 HMENU16 hmenutmp
, hmenuprev
;
1552 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( *hmenu
);
1553 hmenuprev
= hmenutmp
= *hmenu
;
1554 while (hmenutmp
!= *hmenuCurrent
)
1556 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
1557 if (hmenutmp
!= *hmenuCurrent
) hmenuprev
= hmenutmp
;
1559 MENU_HideSubPopups( *hwndOwner
, hmenuprev
, TRUE
);
1562 if ( (hmenuprev
== *hmenu
) &&
1563 ((menu
->wFlags
& MF_SYSMENU
) || !(menu
->wFlags
& MF_POPUP
)) )
1565 /* send WM_NEXTMENU */
1567 if( !MENU_DoNextMenu( hwndOwner
, hmenu
, hmenuCurrent
, VK_LEFT
) )
1568 MENU_SelectItemRel( *hwndOwner
, *hmenu
, ITEM_PREV
);
1569 else *hmenuCurrent
= *hmenu
;
1571 if (*hmenuCurrent
!= hmenutmp
)
1573 /* A sublevel menu was displayed -> display the next one */
1574 *hmenuCurrent
= MENU_ShowSubPopup( *hwndOwner
, *hmenu
, TRUE
);
1577 else *hmenuCurrent
= hmenuprev
;
1581 /***********************************************************************
1584 * Handle a VK_RIGHT key event in a menu.
1585 * hmenuCurrent is the top-most visible popup.
1587 static void MENU_KeyRight( HWND
* hwndOwner
, HMENU16
* hmenu
,
1588 HMENU16
*hmenuCurrent
)
1593 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( *hmenu
);
1595 if ((menu
->wFlags
& MF_POPUP
) || (*hmenuCurrent
!= *hmenu
))
1597 /* If already displaying a popup, try to display sub-popup */
1598 hmenutmp
= MENU_ShowSubPopup( *hwndOwner
, *hmenuCurrent
, TRUE
);
1599 if (hmenutmp
!= *hmenuCurrent
) /* Sub-popup displayed */
1601 *hmenuCurrent
= hmenutmp
;
1606 /* If menu-bar tracking, go to next item */
1608 if (!(menu
->wFlags
& MF_POPUP
) || (menu
->wFlags
& MF_SYSMENU
))
1610 MENU_HideSubPopups( *hwndOwner
, *hmenu
, FALSE
);
1613 /* Send WM_NEXTMENU */
1615 if( !MENU_DoNextMenu( hwndOwner
, hmenu
, hmenuCurrent
, VK_RIGHT
) )
1616 MENU_SelectItemRel( *hwndOwner
, *hmenu
, ITEM_NEXT
);
1617 else *hmenuCurrent
= *hmenu
;
1619 if (*hmenuCurrent
!= hmenutmp
)
1621 /* A sublevel menu was displayed -> display the next one */
1622 *hmenuCurrent
= MENU_ShowSubPopup( *hwndOwner
, *hmenu
, TRUE
);
1625 else if (*hmenuCurrent
!= *hmenu
) /* Hide last level popup */
1628 hmenuprev
= hmenutmp
= *hmenu
;
1629 while (hmenutmp
!= *hmenuCurrent
)
1631 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
1632 if (hmenutmp
!= *hmenuCurrent
) hmenuprev
= hmenutmp
;
1634 MENU_HideSubPopups( *hwndOwner
, hmenuprev
, TRUE
);
1635 *hmenuCurrent
= hmenuprev
;
1640 /***********************************************************************
1643 * Menu tracking code.
1644 * If 'x' and 'y' are not 0, we simulate a button-down event at (x,y)
1645 * before beginning tracking. This is to help menu-bar tracking.
1647 static BOOL
MENU_TrackMenu( HMENU16 hmenu
, UINT wFlags
, int x
, int y
,
1648 HWND hwnd
, const RECT16
*lprect
)
1652 HMENU16 hmenuCurrent
= hmenu
;
1653 BOOL fClosed
= FALSE
, fRemove
;
1656 fEndMenuCalled
= FALSE
;
1657 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
1660 POINT16 pt
= { x
, y
};
1661 MENU_ButtonDown( hwnd
, hmenu
, &hmenuCurrent
, pt
);
1663 SetCapture32( hwnd
);
1666 if (!MSG_InternalGetMessage( &msg
, 0, hwnd
, MSGF_MENU
, 0, TRUE
))
1669 TranslateMessage( &msg
);
1672 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
1674 /* Find the sub-popup for this mouse event (if any) */
1675 HMENU16 hsubmenu
= MENU_FindMenuByCoords( hmenu
, msg
.pt
);
1679 case WM_RBUTTONDOWN
:
1680 case WM_NCRBUTTONDOWN
:
1681 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
1683 case WM_LBUTTONDOWN
:
1684 case WM_NCLBUTTONDOWN
:
1685 fClosed
= !MENU_ButtonDown( hwnd
, hsubmenu
,
1686 &hmenuCurrent
, msg
.pt
);
1690 case WM_NCRBUTTONUP
:
1691 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
1694 case WM_NCLBUTTONUP
:
1695 /* If outside all menus but inside lprect, ignore it */
1696 if (!hsubmenu
&& lprect
&& PtInRect16(lprect
, msg
.pt
)) break;
1697 fClosed
= !MENU_ButtonUp( hwnd
, hsubmenu
,
1698 &hmenuCurrent
, msg
.pt
);
1699 fRemove
= TRUE
; /* Remove event even if outside menu */
1703 case WM_NCMOUSEMOVE
:
1704 if ((msg
.wParam
& MK_LBUTTON
) ||
1705 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
.wParam
& MK_RBUTTON
)))
1707 fClosed
= !MENU_MouseMove( hwnd
, hsubmenu
,
1708 &hmenuCurrent
, msg
.pt
);
1713 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
1715 fRemove
= TRUE
; /* Keyboard messages are always removed */
1723 MENU_SelectItem( hwnd
, hmenuCurrent
, NO_SELECTED_ITEM
, FALSE
);
1727 MENU_SelectItemRel( hwnd
, hmenuCurrent
,
1728 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
1731 case VK_DOWN
: /* If on menu bar, pull-down the menu */
1733 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1734 if (!(menu
->wFlags
& MF_POPUP
) && (hmenuCurrent
== hmenu
))
1735 hmenuCurrent
= MENU_ShowSubPopup( hwnd
, hmenu
, TRUE
);
1737 MENU_SelectItemRel( hwnd
, hmenuCurrent
, ITEM_NEXT
);
1741 MENU_KeyLeft( &hwnd
, &hmenu
, &hmenuCurrent
);
1745 MENU_KeyRight( &hwnd
, &hmenu
, &hmenuCurrent
);
1750 fClosed
= !MENU_ExecFocusedItem( hwnd
, hmenuCurrent
,
1761 break; /* WM_KEYDOWN */
1771 break; /* WM_SYSKEYDOWN */
1775 /* Hack to avoid control chars. */
1776 /* We will find a better way real soon... */
1777 if ((msg
.wParam
<= 32) || (msg
.wParam
>= 127)) break;
1778 pos
= MENU_FindItemByKey( hwnd
, hmenuCurrent
, msg
.wParam
);
1779 if (pos
== (UINT
)-2) fClosed
= TRUE
;
1780 else if (pos
== (UINT
)-1) MessageBeep(0);
1783 MENU_SelectItem( hwnd
, hmenuCurrent
, pos
, TRUE
);
1784 fClosed
= !MENU_ExecFocusedItem( hwnd
, hmenuCurrent
,
1789 break; /* WM_CHAR */
1790 } /* switch(msg.message) */
1794 DispatchMessage( &msg
);
1796 if (fEndMenuCalled
) fClosed
= TRUE
;
1797 if (!fClosed
) fRemove
= TRUE
;
1799 if (fRemove
) /* Remove the message from the queue */
1800 PeekMessage16( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
1804 MENU_HideSubPopups( hwnd
, hmenu
, FALSE
);
1805 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1806 if (menu
&& menu
->wFlags
& MF_POPUP
)
1808 ShowWindow( menu
->hWnd
, SW_HIDE
);
1811 MENU_SelectItem( hwnd
, hmenu
, NO_SELECTED_ITEM
, FALSE
);
1812 SendMessage16( hwnd
, WM_MENUSELECT
, 0, MAKELONG( 0xffff, 0 ) );
1813 fEndMenuCalled
= FALSE
;
1818 /***********************************************************************
1819 * MENU_TrackMouseMenuBar
1821 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
1823 void MENU_TrackMouseMenuBar( HWND hwnd
, POINT16 pt
)
1825 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1827 SendMessage16( hwnd
, WM_ENTERMENULOOP
, 0, 0 );
1828 SendMessage16( hwnd
, WM_INITMENU
, wndPtr
->wIDmenu
, 0 );
1829 MENU_TrackMenu( (HMENU16
)wndPtr
->wIDmenu
, TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
1830 pt
.x
, pt
.y
, hwnd
, NULL
);
1831 SendMessage16( hwnd
, WM_EXITMENULOOP
, 0, 0 );
1836 /***********************************************************************
1837 * MENU_TrackKbdMenuBar
1839 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
1841 void MENU_TrackKbdMenuBar( WND
* wndPtr
, UINT wParam
, INT vkey
)
1843 UINT uItem
= NO_SELECTED_ITEM
;
1846 /* find window that has a menu
1849 if( !(wndPtr
->dwStyle
& WS_CHILD
) )
1851 wndPtr
= WIN_FindWndPtr( GetActiveWindow() );
1852 if( !wndPtr
) return;
1855 while( wndPtr
->dwStyle
& WS_CHILD
&&
1856 !(wndPtr
->dwStyle
& WS_SYSMENU
) )
1857 if( !(wndPtr
= wndPtr
->parent
) ) return;
1859 if( wndPtr
->dwStyle
& WS_CHILD
|| !wndPtr
->wIDmenu
)
1860 if( !(wndPtr
->dwStyle
& WS_SYSMENU
) )
1863 hTrackMenu
= ( IsMenu( wndPtr
->wIDmenu
) )? wndPtr
->wIDmenu
:
1867 SendMessage16( wndPtr
->hwndSelf
, WM_ENTERMENULOOP
, 0, 0 );
1868 SendMessage16( wndPtr
->hwndSelf
, WM_INITMENU
, wndPtr
->wIDmenu
, 0 );
1870 /* find suitable menu entry
1873 if( vkey
== VK_SPACE
)
1874 uItem
= SYSMENU_SELECTED
;
1877 uItem
= MENU_FindItemByKey( wndPtr
->hwndSelf
, wndPtr
->wIDmenu
, vkey
);
1878 if( uItem
>= 0xFFFE )
1880 if( uItem
== 0xFFFF )
1882 SendMessage16( wndPtr
->hwndSelf
, WM_EXITMENULOOP
, 0, 0 );
1888 MENU_SelectItem( wndPtr
->hwndSelf
, hTrackMenu
, uItem
, TRUE
);
1889 if( uItem
== NO_SELECTED_ITEM
)
1890 MENU_SelectItemRel( wndPtr
->hwndSelf
, hTrackMenu
, ITEM_NEXT
);
1892 PostMessage( wndPtr
->hwndSelf
, WM_KEYDOWN
, VK_DOWN
, 0L );
1894 MENU_TrackMenu( hTrackMenu
, TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
1895 0, 0, wndPtr
->hwndSelf
, NULL
);
1897 SendMessage16( wndPtr
->hwndSelf
, WM_EXITMENULOOP
, 0, 0 );
1902 /**********************************************************************
1903 * TrackPopupMenu16 (USER.416)
1905 BOOL16
TrackPopupMenu16( HMENU16 hMenu
, UINT16 wFlags
, INT16 x
, INT16 y
,
1906 INT16 nReserved
, HWND16 hWnd
, const RECT16
*lpRect
)
1911 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
, 0, 0 ))
1912 ret
= MENU_TrackMenu( hMenu
, wFlags
, 0, 0, hWnd
, lpRect
);
1918 /**********************************************************************
1919 * TrackPopupMenu32 (USER32.548)
1921 BOOL32
TrackPopupMenu32( HMENU32 hMenu
, UINT32 wFlags
, INT32 x
, INT32 y
,
1922 INT32 nReserved
, HWND32 hWnd
, const RECT32
*lpRect
)
1926 CONV_RECT32TO16( lpRect
, &r
);
1927 return TrackPopupMenu16(hMenu
,wFlags
,x
,y
,nReserved
,hWnd
,lpRect
?&r
:NULL
);
1931 /***********************************************************************
1934 LRESULT
PopupMenuWndProc(HWND hwnd
,UINT message
,WPARAM16 wParam
,LPARAM lParam
)
1940 CREATESTRUCT16
*cs
= (CREATESTRUCT16
*)PTR_SEG_TO_LIN(lParam
);
1941 SetWindowLong32A( hwnd
, 0, (LONG
)cs
->lpCreateParams
);
1945 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1946 return MA_NOACTIVATE
;
1951 BeginPaint16( hwnd
, &ps
);
1952 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
1953 (HMENU16
)GetWindowLong32A( hwnd
, 0 ) );
1954 EndPaint16( hwnd
, &ps
);
1959 /* zero out global pointer in case system popup
1960 * was destroyed by AppExit
1963 if( hwnd
== pTopPWnd
->hwndSelf
)
1964 { pTopPWnd
= NULL
; uSubPWndLevel
= 0; }
1970 if (wParam
) SetWindowLong32A( hwnd
, 0, (HMENU16
)wParam
);
1973 return DefWindowProc16(hwnd
, message
, wParam
, lParam
);
1979 /***********************************************************************
1980 * MENU_GetMenuBarHeight
1982 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
1984 UINT
MENU_GetMenuBarHeight( HWND hwnd
, UINT menubarWidth
, int orgX
, int orgY
)
1991 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
1992 if (!(lppop
= (LPPOPUPMENU
)USER_HEAP_LIN_ADDR((HMENU16
)wndPtr
->wIDmenu
)))
1994 hdc
= GetDCEx32( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1995 SetRect16(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+SYSMETRICS_CYMENU
);
1996 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
1997 ReleaseDC32( hwnd
, hdc
);
1998 return lppop
->Height
;
2002 /*******************************************************************
2003 * ChangeMenu16 (USER.153)
2005 BOOL16
ChangeMenu16( HMENU16 hMenu
, UINT16 pos
, SEGPTR data
,
2006 UINT16 id
, UINT16 flags
)
2008 dprintf_menu( stddeb
,"ChangeMenu16: menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
2009 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2010 if (flags
& MF_APPEND
) return AppendMenu16( hMenu
, flags
& ~MF_APPEND
,
2012 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
2013 /* for MF_DELETE. We should check the parameters for all others */
2014 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
2015 if (flags
& MF_DELETE
) return DeleteMenu( hMenu
, pos
, flags
& ~MF_DELETE
);
2016 if (flags
& MF_CHANGE
) return ModifyMenu16( hMenu
, pos
, flags
& ~MF_CHANGE
,
2018 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
2019 flags
& MF_BYPOSITION
? pos
: id
,
2020 flags
& ~MF_REMOVE
);
2021 /* Default: MF_INSERT */
2022 return InsertMenu16( hMenu
, pos
, flags
, id
, data
);
2026 /*******************************************************************
2027 * ChangeMenu32A (USER32.22)
2029 BOOL32
ChangeMenu32A( HMENU32 hMenu
, UINT32 pos
, LPCSTR data
,
2030 UINT32 id
, UINT32 flags
)
2032 dprintf_menu( stddeb
,"ChangeMenu32A: menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2033 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2034 if (flags
& MF_APPEND
) return AppendMenu32A( hMenu
, flags
& ~MF_APPEND
,
2036 if (flags
& MF_DELETE
) return DeleteMenu( hMenu
, pos
, flags
& ~MF_DELETE
);
2037 if (flags
& MF_CHANGE
) return ModifyMenu32A(hMenu
, pos
, flags
& ~MF_CHANGE
,
2039 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
2040 flags
& MF_BYPOSITION
? pos
: id
,
2041 flags
& ~MF_REMOVE
);
2042 /* Default: MF_INSERT */
2043 return InsertMenu32A( hMenu
, pos
, flags
, id
, data
);
2047 /*******************************************************************
2048 * ChangeMenu32W (USER32.23)
2050 BOOL32
ChangeMenu32W( HMENU32 hMenu
, UINT32 pos
, LPCWSTR data
,
2051 UINT32 id
, UINT32 flags
)
2053 dprintf_menu( stddeb
,"ChangeMenu32W: menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2054 hMenu
, pos
, (DWORD
)data
, id
, flags
);
2055 if (flags
& MF_APPEND
) return AppendMenu32W( hMenu
, flags
& ~MF_APPEND
,
2057 if (flags
& MF_DELETE
) return DeleteMenu( hMenu
, pos
, flags
& ~MF_DELETE
);
2058 if (flags
& MF_CHANGE
) return ModifyMenu32W(hMenu
, pos
, flags
& ~MF_CHANGE
,
2060 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
2061 flags
& MF_BYPOSITION
? pos
: id
,
2062 flags
& ~MF_REMOVE
);
2063 /* Default: MF_INSERT */
2064 return InsertMenu32W( hMenu
, pos
, flags
, id
, data
);
2068 /*******************************************************************
2069 * CheckMenuItem (USER.154)
2071 INT
CheckMenuItem( HMENU16 hMenu
, UINT id
, UINT flags
)
2076 dprintf_menu( stddeb
,"CheckMenuItem: %04x %04x %04x\n", hMenu
, id
, flags
);
2077 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
2078 ret
= item
->item_flags
& MF_CHECKED
;
2079 if (flags
& MF_CHECKED
) item
->item_flags
|= MF_CHECKED
;
2080 else item
->item_flags
&= ~MF_CHECKED
;
2085 /**********************************************************************
2086 * EnableMenuItem [USER.155]
2088 BOOL
EnableMenuItem(HMENU16 hMenu
, UINT wItemID
, UINT wFlags
)
2091 dprintf_menu(stddeb
,"EnableMenuItem (%04x, %04X, %04X) !\n",
2092 hMenu
, wItemID
, wFlags
);
2093 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return FALSE
;
2095 /* We can't have MF_GRAYED and MF_DISABLED together */
2096 if (wFlags
& MF_GRAYED
)
2098 item
->item_flags
= (item
->item_flags
& ~MF_DISABLED
) | MF_GRAYED
;
2100 else if (wFlags
& MF_DISABLED
)
2102 item
->item_flags
= (item
->item_flags
& ~MF_GRAYED
) | MF_DISABLED
;
2104 else /* MF_ENABLED */
2106 item
->item_flags
&= ~(MF_GRAYED
| MF_DISABLED
);
2112 /*******************************************************************
2113 * GetMenuString (USER.161)
2115 int GetMenuString( HMENU16 hMenu
, UINT wItemID
,
2116 LPSTR str
, short nMaxSiz
, UINT wFlags
)
2120 dprintf_menu( stddeb
, "GetMenuString: menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
2121 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
2122 if (!str
|| !nMaxSiz
) return 0;
2124 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
2125 if (!IS_STRING_ITEM(item
->item_flags
)) return 0;
2126 lstrcpyn32A( str
, item
->text
, nMaxSiz
);
2127 dprintf_menu( stddeb
, "GetMenuString: returning '%s'\n", str
);
2132 /**********************************************************************
2133 * HiliteMenuItem [USER.162]
2135 BOOL
HiliteMenuItem(HWND hWnd
, HMENU16 hMenu
, UINT wItemID
, UINT wHilite
)
2138 dprintf_menu(stddeb
,"HiliteMenuItem(%04x, %04x, %04x, %04x);\n",
2139 hWnd
, hMenu
, wItemID
, wHilite
);
2140 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
2141 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
2142 if (menu
->FocusedItem
== wItemID
) return TRUE
;
2143 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
2144 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
);
2149 /**********************************************************************
2150 * GetMenuState [USER.250]
2152 UINT
GetMenuState(HMENU16 hMenu
, UINT wItemID
, UINT wFlags
)
2155 dprintf_menu(stddeb
,"GetMenuState(%04x, %04x, %04x);\n",
2156 hMenu
, wItemID
, wFlags
);
2157 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
2158 if (item
->item_flags
& MF_POPUP
)
2160 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( (HMENU16
)item
->item_id
);
2161 if (!menu
) return -1;
2162 else return (menu
->nItems
<< 8) | (menu
->wFlags
& 0xff);
2164 else return item
->item_flags
;
2168 /**********************************************************************
2169 * GetMenuItemCount [USER.263]
2171 INT
GetMenuItemCount(HMENU16 hMenu
)
2174 dprintf_menu(stddeb
,"GetMenuItemCount(%04x);\n", hMenu
);
2175 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2176 if (menu
== NULL
|| menu
->wMagic
!= MENU_MAGIC
) return (UINT
)-1;
2177 dprintf_menu(stddeb
,"GetMenuItemCount(%04x) return %d \n",
2178 hMenu
, menu
->nItems
);
2179 return menu
->nItems
;
2183 /**********************************************************************
2184 * GetMenuItemID [USER.264]
2186 UINT
GetMenuItemID(HMENU16 hMenu
, int nPos
)
2190 dprintf_menu(stddeb
,"GetMenuItemID(%04x, %d);\n", hMenu
, nPos
);
2191 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
2192 if ((nPos
< 0) || (nPos
>= menu
->nItems
)) return -1;
2193 if (menu
->items
[nPos
].item_flags
& MF_POPUP
) return -1;
2194 return menu
->items
[nPos
].item_id
;
2198 /*******************************************************************
2199 * InsertMenu16 (USER.410)
2201 BOOL16
InsertMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
2202 UINT16 id
, SEGPTR data
)
2204 if (IS_STRING_ITEM(flags
) && data
)
2205 return InsertMenu32A( hMenu
, (INT32
)(INT16
)pos
, flags
, id
,
2206 (LPSTR
)PTR_SEG_TO_LIN(data
) );
2207 return InsertMenu32A( hMenu
, (INT32
)(INT16
)pos
, flags
, id
, (LPSTR
)data
);
2211 /*******************************************************************
2212 * InsertMenu32A (USER32.321)
2214 BOOL32
InsertMenu32A( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2215 UINT32 id
, LPCSTR str
)
2219 if (IS_STRING_ITEM(flags
) && str
)
2220 dprintf_menu( stddeb
, "InsertMenu: %04x %d %04x %04x '%s'\n",
2221 hMenu
, pos
, flags
, id
, str
);
2222 else dprintf_menu( stddeb
, "InsertMenu: %04x %d %04x %04x %08lx\n",
2223 hMenu
, pos
, flags
, id
, (DWORD
)str
);
2225 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
2227 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
2229 RemoveMenu( hMenu
, pos
, flags
);
2233 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
2234 ((POPUPMENU
*)USER_HEAP_LIN_ADDR((HMENU16
)id
))->wFlags
|= MF_POPUP
;
2236 item
->hCheckBit
= hStdCheck
;
2237 item
->hUnCheckBit
= 0;
2242 /*******************************************************************
2243 * InsertMenu32W (USER32.324)
2245 BOOL32
InsertMenu32W( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2246 UINT32 id
, LPCWSTR str
)
2250 if (IS_STRING_ITEM(flags
) && str
)
2252 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
2253 ret
= InsertMenu32A( hMenu
, pos
, flags
, id
, newstr
);
2254 HeapFree( GetProcessHeap(), 0, newstr
);
2257 else return InsertMenu32A( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
2261 /*******************************************************************
2262 * AppendMenu16 (USER.411)
2264 BOOL16
AppendMenu16( HMENU16 hMenu
, UINT16 flags
, UINT16 id
, SEGPTR data
)
2266 return InsertMenu16( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
2270 /*******************************************************************
2271 * AppendMenu32A (USER32.4)
2273 BOOL32
AppendMenu32A( HMENU32 hMenu
, UINT32 flags
, UINT32 id
, LPCSTR data
)
2275 return InsertMenu32A( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
2279 /*******************************************************************
2280 * AppendMenu32W (USER32.5)
2282 BOOL32
AppendMenu32W( HMENU32 hMenu
, UINT32 flags
, UINT32 id
, LPCWSTR data
)
2284 return InsertMenu32W( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
2288 /**********************************************************************
2289 * RemoveMenu [USER.412]
2291 BOOL
RemoveMenu(HMENU16 hMenu
, UINT nPos
, UINT wFlags
)
2296 dprintf_menu(stddeb
,"RemoveMenu (%04x, %04x, %04x)\n",hMenu
, nPos
, wFlags
);
2297 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
2298 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
2302 if (IS_STRING_ITEM(item
->item_flags
) && item
->text
)
2303 HeapFree( SystemHeap
, 0, item
->text
);
2304 if (--menu
->nItems
== 0)
2306 HeapFree( SystemHeap
, 0, menu
->items
);
2311 while(nPos
< menu
->nItems
)
2317 menu
->items
= HeapReAlloc( SystemHeap
, 0, menu
->items
,
2318 menu
->nItems
* sizeof(MENUITEM
) );
2324 /**********************************************************************
2325 * DeleteMenu [USER.413]
2327 BOOL
DeleteMenu(HMENU16 hMenu
, UINT nPos
, UINT wFlags
)
2329 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
2330 if (!item
) return FALSE
;
2331 if (item
->item_flags
& MF_POPUP
) DestroyMenu( (HMENU16
)item
->item_id
);
2332 /* nPos is now the position of the item */
2333 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
2338 /*******************************************************************
2339 * ModifyMenu16 (USER.414)
2341 BOOL16
ModifyMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
2342 UINT16 id
, SEGPTR data
)
2344 if (IS_STRING_ITEM(flags
))
2345 return ModifyMenu32A( hMenu
, (INT32
)(INT16
)pos
, flags
, id
,
2346 (LPSTR
)PTR_SEG_TO_LIN(data
) );
2347 return ModifyMenu32A( hMenu
, (INT32
)(INT16
)pos
, flags
, id
, (LPSTR
)data
);
2351 /*******************************************************************
2352 * ModifyMenu32A (USER32.396)
2354 BOOL32
ModifyMenu32A( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2355 UINT32 id
, LPCSTR str
)
2358 HMENU16 hMenu16
= hMenu
;
2361 if (IS_STRING_ITEM(flags
))
2363 dprintf_menu( stddeb
, "ModifyMenu: %04x %d %04x %04x '%s'\n",
2364 hMenu
, pos
, flags
, id
, str
? str
: "#NULL#" );
2365 if (!str
) return FALSE
;
2369 dprintf_menu( stddeb
, "ModifyMenu: %04x %d %04x %04x %08lx\n",
2370 hMenu
, pos
, flags
, id
, (DWORD
)str
);
2373 if (!(item
= MENU_FindItem( &hMenu16
, &pos16
, flags
))) return FALSE
;
2374 return MENU_SetItemData( item
, flags
, id
, str
);
2378 /*******************************************************************
2379 * ModifyMenu32W (USER32.397)
2381 BOOL32
ModifyMenu32W( HMENU32 hMenu
, UINT32 pos
, UINT32 flags
,
2382 UINT32 id
, LPCWSTR str
)
2386 if (IS_STRING_ITEM(flags
) && str
)
2388 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
2389 ret
= ModifyMenu32A( hMenu
, pos
, flags
, id
, newstr
);
2390 HeapFree( GetProcessHeap(), 0, newstr
);
2393 else return ModifyMenu32A( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
2397 /**********************************************************************
2398 * CreatePopupMenu [USER.415]
2400 HMENU16
CreatePopupMenu()
2405 if (!(hmenu
= CreateMenu())) return 0;
2406 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
2407 menu
->wFlags
|= MF_POPUP
;
2412 /**********************************************************************
2413 * GetMenuCheckMarkDimensions [USER.417]
2415 DWORD
GetMenuCheckMarkDimensions()
2417 return MAKELONG( check_bitmap_width
, check_bitmap_height
);
2421 /**********************************************************************
2422 * SetMenuItemBitmaps [USER.418]
2424 BOOL
SetMenuItemBitmaps(HMENU16 hMenu
, UINT nPos
, UINT wFlags
,
2425 HBITMAP16 hNewUnCheck
, HBITMAP16 hNewCheck
)
2428 dprintf_menu(stddeb
,"SetMenuItemBitmaps(%04x, %04x, %04x, %04x, %04x)\n",
2429 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
2430 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
2432 if (!hNewCheck
&& !hNewUnCheck
)
2434 /* If both are NULL, restore default bitmaps */
2435 item
->hCheckBit
= hStdCheck
;
2436 item
->hUnCheckBit
= 0;
2437 item
->item_flags
&= ~MF_USECHECKBITMAPS
;
2439 else /* Install new bitmaps */
2441 item
->hCheckBit
= hNewCheck
;
2442 item
->hUnCheckBit
= hNewUnCheck
;
2443 item
->item_flags
|= MF_USECHECKBITMAPS
;
2449 /**********************************************************************
2450 * CreateMenu [USER.151]
2452 HMENU16
CreateMenu()
2456 dprintf_menu(stddeb
,"CreateMenu !\n");
2457 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) )))
2459 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2461 menu
->wMagic
= MENU_MAGIC
;
2468 menu
->FocusedItem
= NO_SELECTED_ITEM
;
2469 dprintf_menu(stddeb
,"CreateMenu // return %04x\n", hMenu
);
2474 /**********************************************************************
2475 * DestroyMenu [USER.152]
2477 BOOL
DestroyMenu(HMENU16 hMenu
)
2480 dprintf_menu(stddeb
,"DestroyMenu (%04x) !\n", hMenu
);
2482 if (hMenu
== 0) return FALSE
;
2483 /* Silently ignore attempts to destroy default system menu */
2484 if (hMenu
== MENU_DefSysMenu
) return TRUE
;
2485 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2486 if (!lppop
|| (lppop
->wMagic
!= MENU_MAGIC
)) return FALSE
;
2487 lppop
->wMagic
= 0; /* Mark it as destroyed */
2488 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
&& (!pTopPWnd
|| (lppop
->hWnd
!= pTopPWnd
->hwndSelf
)))
2489 DestroyWindow( lppop
->hWnd
);
2494 MENUITEM
*item
= lppop
->items
;
2495 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
2497 if (item
->item_flags
& MF_POPUP
)
2498 DestroyMenu( (HMENU16
)item
->item_id
);
2499 if (IS_STRING_ITEM(item
->item_flags
) && item
->text
)
2500 HeapFree( SystemHeap
, 0, item
->text
);
2502 HeapFree( SystemHeap
, 0, lppop
->items
);
2504 USER_HEAP_FREE( hMenu
);
2505 dprintf_menu(stddeb
,"DestroyMenu (%04x) // End !\n", hMenu
);
2509 /**********************************************************************
2510 * GetSystemMenu [USER.156]
2512 HMENU16
GetSystemMenu(HWND hWnd
, BOOL bRevert
)
2514 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
2515 if (!wndPtr
) return 0;
2517 if (!wndPtr
->hSysMenu
|| (wndPtr
->hSysMenu
== MENU_DefSysMenu
))
2519 wndPtr
->hSysMenu
= MENU_CopySysMenu();
2520 return wndPtr
->hSysMenu
;
2522 if (!bRevert
) return wndPtr
->hSysMenu
;
2523 if (wndPtr
->hSysMenu
) DestroyMenu(wndPtr
->hSysMenu
);
2524 wndPtr
->hSysMenu
= MENU_CopySysMenu();
2525 return wndPtr
->hSysMenu
;
2529 /*******************************************************************
2530 * SetSystemMenu (USER.280)
2532 BOOL
SetSystemMenu( HWND hwnd
, HMENU16 hMenu
)
2536 if (!(wndPtr
= WIN_FindWndPtr(hwnd
))) return FALSE
;
2537 if (wndPtr
->hSysMenu
&& (wndPtr
->hSysMenu
!= MENU_DefSysMenu
))
2538 DestroyMenu( wndPtr
->hSysMenu
);
2539 wndPtr
->hSysMenu
= hMenu
;
2544 /**********************************************************************
2545 * GetMenu [USER.157]
2547 HMENU16
GetMenu(HWND hWnd
)
2549 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
2550 if (wndPtr
== NULL
) return 0;
2551 return (HMENU16
)wndPtr
->wIDmenu
;
2555 /**********************************************************************
2556 * SetMenu [USER.158]
2558 BOOL
SetMenu(HWND hWnd
, HMENU16 hMenu
)
2561 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
2562 if (wndPtr
== NULL
) {
2563 fprintf(stderr
,"SetMenu(%04x, %04x) // Bad window handle !\n",
2567 dprintf_menu(stddeb
,"SetMenu(%04x, %04x);\n", hWnd
, hMenu
);
2568 if (GetCapture32() == hWnd
) ReleaseCapture();
2569 wndPtr
->wIDmenu
= (UINT
)hMenu
;
2572 lpmenu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2573 if (lpmenu
== NULL
) {
2574 fprintf(stderr
,"SetMenu(%04x, %04x) // Bad menu handle !\n",
2578 lpmenu
->hWnd
= hWnd
;
2579 lpmenu
->wFlags
&= ~MF_POPUP
; /* Can't be a popup */
2580 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
2582 if (IsWindowVisible(hWnd
))
2583 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
2584 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
2590 /**********************************************************************
2591 * GetSubMenu [USER.159]
2593 HMENU16
GetSubMenu(HMENU16 hMenu
, short nPos
)
2597 dprintf_menu(stddeb
,"GetSubMenu (%04x, %04X) !\n", hMenu
, nPos
);
2598 if (!(lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return 0;
2599 if ((UINT
)nPos
>= lppop
->nItems
) return 0;
2600 if (!(lppop
->items
[nPos
].item_flags
& MF_POPUP
)) return 0;
2601 return (HMENU16
)lppop
->items
[nPos
].item_id
;
2605 /**********************************************************************
2606 * DrawMenuBar [USER.160]
2608 void DrawMenuBar(HWND hWnd
)
2612 dprintf_menu(stddeb
,"DrawMenuBar (%04x)\n", hWnd
);
2613 wndPtr
= WIN_FindWndPtr(hWnd
);
2614 if (wndPtr
!= NULL
&& (wndPtr
->dwStyle
& WS_CHILD
) == 0 &&
2615 wndPtr
->wIDmenu
!= 0) {
2616 dprintf_menu(stddeb
,"DrawMenuBar wIDmenu=%04X \n",
2618 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR((HMENU16
)wndPtr
->wIDmenu
);
2619 if (lppop
== NULL
) return;
2621 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
2622 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
2623 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
2628 /***********************************************************************
2629 * EndMenu (USER.187)
2633 /* FIXME: this won't work when we have multiple tasks... */
2634 fEndMenuCalled
= TRUE
;
2638 /***********************************************************************
2639 * LookupMenuHandle (USER.217)
2641 HMENU16
LookupMenuHandle( HMENU16 hmenu
, INT id
)
2643 if (!MENU_FindItem( &hmenu
, &id
, MF_BYCOMMAND
)) return 0;
2648 /**********************************************************************
2649 * LoadMenu (USER.150)
2651 HMENU16
LoadMenu16( HINSTANCE16 instance
, SEGPTR name
)
2659 char *str
= (char *)PTR_SEG_TO_LIN( name
);
2660 dprintf_menu( stddeb
, "LoadMenu(%04x,'%s')\n", instance
, str
);
2661 if (str
[0] == '#') name
= (SEGPTR
)atoi( str
+ 1 );
2664 dprintf_resource(stddeb
,"LoadMenu(%04x,%04x)\n",instance
,LOWORD(name
));
2666 if (!name
) return 0;
2668 /* check for Win32 module */
2669 instance
= GetExePtr( instance
);
2670 if (MODULE_GetPtr(instance
)->flags
& NE_FFLAGS_WIN32
)
2671 return LoadMenu32A(instance
,PTR_SEG_TO_LIN(name
));
2673 if (!(hRsrc
= FindResource16( instance
, name
, RT_MENU
))) return 0;
2674 if (!(handle
= LoadResource16( instance
, hRsrc
))) return 0;
2675 hMenu
= LoadMenuIndirect16(LockResource16(handle
));
2676 FreeResource16( handle
);
2681 /*****************************************************************
2682 * LoadMenu32A (USER32.370)
2684 HMENU32
LoadMenu32A( HINSTANCE32 instance
, LPCSTR name
)
2686 HRSRC32 hrsrc
= FindResource32A( instance
, name
, (LPSTR
)RT_MENU
);
2687 if (!hrsrc
) return 0;
2688 return LoadMenuIndirect32A( (LPCVOID
)LoadResource32( instance
, hrsrc
));
2692 /*****************************************************************
2693 * LoadMenu32W (USER32.372)
2695 HMENU32
LoadMenu32W( HINSTANCE32 instance
, LPCWSTR name
)
2697 HRSRC32 hrsrc
= FindResource32W( instance
, name
, (LPWSTR
)RT_MENU
);
2698 if (!hrsrc
) return 0;
2699 return LoadMenuIndirect32W( (LPCVOID
)LoadResource32( instance
, hrsrc
));
2703 /**********************************************************************
2704 * LoadMenuIndirect16 (USER.220)
2706 HMENU16
LoadMenuIndirect16( LPCVOID
template )
2709 WORD version
, offset
;
2710 LPCSTR p
= (LPCSTR
)template;
2712 dprintf_menu(stddeb
,"LoadMenuIndirect32A: %p\n", template );
2713 version
= GET_WORD(p
);
2717 fprintf( stderr
, "LoadMenuIndirect16: version must be 0 for Win16\n" );
2720 offset
= GET_WORD(p
);
2721 p
+= sizeof(WORD
) + offset
;
2722 if (!(hMenu
= CreateMenu())) return 0;
2723 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
2725 DestroyMenu( hMenu
);
2732 /**********************************************************************
2733 * LoadMenuIndirect32A (USER32.370)
2735 HMENU32
LoadMenuIndirect32A( LPCVOID
template )
2738 WORD version
, offset
;
2739 LPCSTR p
= (LPCSTR
)template;
2741 dprintf_menu(stddeb
,"LoadMenuIndirect32A: %p\n", template );
2742 version
= GET_WORD(p
);
2746 fprintf( stderr
, "LoadMenuIndirect32A: version %d not supported.\n",
2750 offset
= GET_WORD(p
);
2751 p
+= sizeof(WORD
) + offset
;
2752 if (!(hMenu
= CreateMenu())) return 0;
2753 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
2755 DestroyMenu( hMenu
);
2762 /**********************************************************************
2763 * LoadMenuIndirect32W (USER32.371)
2765 HMENU32
LoadMenuIndirect32W( LPCVOID
template )
2767 /* FIXME: is there anything different between A and W? */
2768 return LoadMenuIndirect32A( template );
2772 /**********************************************************************
2775 BOOL
IsMenu( HMENU16 hmenu
)
2778 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
2779 return (menu
->wMagic
== MENU_MAGIC
);