4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
9 * Note: the style MF_MOUSESELECT is used to mark popup items that
10 * have been selected, i.e. their popup menu is currently displayed.
11 * This is probably not the meaning this style has in MS-Windows.
20 #include "sysmetrics.h"
27 /* #define DEBUG_MENU */
28 /* #define DEBUG_MENUCALC */
29 /* #define DEBUG_MENUSHORTCUT */
33 /* Dimension of the menu bitmaps */
34 static WORD check_bitmap_width
= 0, check_bitmap_height
= 0;
35 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
37 /* Flag set by EndMenu() to force an exit from menu tracking */
38 static BOOL fEndMenuCalled
= FALSE
;
40 /* Space between 2 menu bar items */
41 #define MENU_BAR_ITEMS_SPACE 16
43 /* Minimum width of a tab character */
44 #define MENU_TAB_SPACE 8
46 /* Height of a separator item */
47 #define SEPARATOR_HEIGHT 5
49 /* Values for menu->FocusedItem */
50 /* (other values give the position of the focused item) */
51 #define NO_SELECTED_ITEM 0xffff
52 #define SYSMENU_SELECTED 0xfffe /* Only valid on menu-bars */
54 #define IS_STRING_ITEM(flags) (!((flags) & (MF_BITMAP | MF_OWNERDRAW | \
55 MF_MENUBARBREAK | MF_MENUBREAK | MF_SEPARATOR)))
58 extern void NC_DrawSysButton(HWND hwnd
, HDC hdc
, BOOL down
); /* nonclient.c */
60 static HBITMAP hStdCheck
= 0;
61 static HBITMAP hStdMnArrow
= 0;
64 WORD
* ParseMenuResource(WORD
*first_item
, int level
, HMENU hMenu
);
67 /***********************************************************************
70 * Menus initialisation.
78 if (!(hStdCheck
= LoadBitmap( 0, MAKEINTRESOURCE(OBM_CHECK
) )))
80 GetObject( hStdCheck
, sizeof(BITMAP
), (LPSTR
)&bm
);
81 check_bitmap_width
= bm
.bmWidth
;
82 check_bitmap_height
= bm
.bmHeight
;
83 if (!(hStdMnArrow
= LoadBitmap( 0, MAKEINTRESOURCE(OBM_MNARROW
) )))
85 GetObject( hStdMnArrow
, sizeof(BITMAP
), (LPSTR
)&bm
);
86 arrow_bitmap_width
= bm
.bmWidth
;
87 arrow_bitmap_height
= bm
.bmHeight
;
93 /***********************************************************************
96 * Check whether the window owning the menu bar has a system menu.
98 static BOOL
MENU_HasSysMenu( POPUPMENU
*menu
)
102 if (menu
->wFlags
& MF_POPUP
) return FALSE
;
103 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return FALSE
;
104 return (wndPtr
->dwStyle
& WS_SYSMENU
) != 0;
108 /***********************************************************************
111 * Check whether the point (in screen coords) is in the system menu
112 * of the window owning the given menu.
114 static BOOL
MENU_IsInSysMenu( POPUPMENU
*menu
, POINT pt
)
118 if (menu
->wFlags
& MF_POPUP
) return FALSE
;
119 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return FALSE
;
120 if (!(wndPtr
->dwStyle
& WS_SYSMENU
)) return FALSE
;
121 if ((pt
.x
< wndPtr
->rectClient
.left
) ||
122 (pt
.x
>= wndPtr
->rectClient
.left
+SYSMETRICS_CXSIZE
+SYSMETRICS_CXBORDER
))
124 if ((pt
.y
>= wndPtr
->rectClient
.top
- menu
->Height
) ||
125 (pt
.y
< wndPtr
->rectClient
.top
- menu
->Height
-
126 SYSMETRICS_CYSIZE
- SYSMETRICS_CYBORDER
)) return FALSE
;
131 /***********************************************************************
134 * Find a menu item. Return a pointer on the item, and modifies *hmenu
135 * in case the item was in a sub-menu.
137 static MENUITEM
*MENU_FindItem( HMENU
*hmenu
, WORD
*nPos
, WORD wFlags
)
143 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(*hmenu
))) return NULL
;
144 item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
145 if (wFlags
& MF_BYPOSITION
)
147 if (*nPos
>= menu
->nItems
) return NULL
;
152 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
154 if (item
->item_id
== *nPos
)
159 else if (item
->item_flags
& MF_POPUP
)
161 HMENU hsubmenu
= (HMENU
)item
->item_id
;
162 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
175 /***********************************************************************
176 * MENU_FindItemByCoords
178 * Find the item at the specified coordinates (screen coords).
180 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
, int x
, int y
, WORD
*pos
)
186 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return NULL
;
187 x
-= wndPtr
->rectWindow
.left
;
188 y
-= wndPtr
->rectWindow
.top
;
189 item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
190 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
192 if ((x
>= item
->rect
.left
) && (x
< item
->rect
.right
) &&
193 (y
>= item
->rect
.top
) && (y
< item
->rect
.bottom
))
203 /***********************************************************************
206 * Find the menu item selected by a key press.
207 * Return item id, -1 if none, -2 if we should close the menu.
209 static WORD
MENU_FindItemByKey( HWND hwndOwner
, HMENU hmenu
, WORD key
)
216 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
217 lpitem
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
219 for (i
= 0; i
< menu
->nItems
; i
++, lpitem
++)
221 if (IS_STRING_ITEM(lpitem
->item_flags
))
223 char *p
= strchr( lpitem
->item_text
, '&' );
224 if (p
&& (p
[1] != '&') && (toupper(p
[1]) == key
)) return i
;
227 menuchar
= SendMessage( hwndOwner
, WM_MENUCHAR
, key
,
228 MAKELONG( menu
->wFlags
, hmenu
) );
229 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
230 if (HIWORD(menuchar
) == 1) return -2;
235 /***********************************************************************
238 * Calculate the size of the menu item and store it in lpitem->rect.
240 static void MENU_CalcItemSize( HDC hdc
, LPMENUITEM lpitem
, HWND hwndOwner
,
241 int orgX
, int orgY
, BOOL menuBar
)
246 SetRect( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
248 if (lpitem
->item_flags
& MF_OWNERDRAW
) {
249 static HANDLE mistrh
= 0;
250 static SEGPTR mistrsegp
= 0;
251 static LPMEASUREITEMSTRUCT mistruct
=NULL
;
252 if (mistruct
== NULL
) {
253 mistrh
= GlobalAlloc(0,sizeof(MEASUREITEMSTRUCT
));
254 mistrsegp
= WIN16_GlobalLock(mistrh
);
255 mistruct
= PTR_SEG_TO_LIN(mistrsegp
);
257 mistruct
->CtlType
= ODT_MENU
;
258 mistruct
->itemID
= lpitem
->item_id
;
259 mistruct
->itemData
= (long int)lpitem
->item_text
;
260 mistruct
->itemHeight
= 16;
261 mistruct
->itemWidth
= 30;
262 SendMessage(hwndOwner
,WM_MEASUREITEM
,0,mistrsegp
);
263 lpitem
->rect
.bottom
+= mistruct
->itemHeight
;
264 lpitem
->rect
.right
+= mistruct
->itemWidth
;
265 dprintf_menu(stddeb
,"DrawMenuItem: MeasureItem %04x %d:%d!\n",
266 lpitem
->item_id
,mistruct
->itemWidth
, mistruct
->itemHeight
);
270 if (lpitem
->item_flags
& MF_SEPARATOR
)
272 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
278 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
279 if (lpitem
->item_flags
& MF_POPUP
)
280 lpitem
->rect
.right
+= arrow_bitmap_width
;
283 if (lpitem
->item_flags
& MF_BITMAP
)
286 GetObject( (HBITMAP
)lpitem
->hText
, sizeof(BITMAP
), (LPSTR
)&bm
);
287 lpitem
->rect
.right
+= bm
.bmWidth
;
288 lpitem
->rect
.bottom
+= bm
.bmHeight
;
292 /* If we get here, then it is a text item */
294 dwSize
= (lpitem
->item_text
== NULL
) ? 0 : GetTextExtent( hdc
, lpitem
->item_text
, strlen(lpitem
->item_text
));
295 lpitem
->rect
.right
+= LOWORD(dwSize
);
296 lpitem
->rect
.bottom
+= max( HIWORD(dwSize
), SYSMETRICS_CYMENU
);
298 if (menuBar
) lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
299 else if ((p
= strchr( lpitem
->item_text
, '\t' )) != NULL
)
301 /* Item contains a tab (only meaningful in popup menus) */
302 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+
303 LOWORD( GetTextExtent( hdc
, lpitem
->item_text
,
304 (int)(p
- lpitem
->item_text
) ));
305 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
309 if (strchr( lpitem
->item_text
, '\b' ))
310 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
311 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
312 - arrow_bitmap_width
;
317 /***********************************************************************
318 * MENU_PopupMenuCalcSize
320 * Calculate the size of a popup menu.
322 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND hwndOwner
)
324 LPMENUITEM items
, lpitem
;
327 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
329 lppop
->Width
= lppop
->Height
= 0;
330 if (lppop
->nItems
== 0) return;
331 items
= (MENUITEM
*)USER_HEAP_LIN_ADDR( lppop
->hItems
);
334 while (start
< lppop
->nItems
)
336 lpitem
= &items
[start
];
339 maxTab
= maxTabWidth
= 0;
341 /* Parse items until column break or end of menu */
342 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
345 (lpitem
->item_flags
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
346 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
347 if (lpitem
->item_flags
& MF_MENUBARBREAK
) orgX
++;
348 maxX
= max( maxX
, lpitem
->rect
.right
);
349 orgY
= lpitem
->rect
.bottom
;
352 maxTab
= max( maxTab
, lpitem
->xTab
);
353 maxTabWidth
= max(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
357 /* Finish the column (set all items to the largest width found) */
358 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
359 for (lpitem
= &items
[start
]; start
< i
; start
++, lpitem
++)
361 lpitem
->rect
.right
= maxX
;
362 if (lpitem
->xTab
) lpitem
->xTab
= maxTab
;
364 lppop
->Height
= max( lppop
->Height
, orgY
);
372 /***********************************************************************
373 * MENU_MenuBarCalcSize
375 * Calculate the size of the menu bar.
377 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
, LPPOPUPMENU lppop
,
380 LPMENUITEM lpitem
, items
;
381 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
383 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
384 if (lppop
->nItems
== 0) return;
385 dprintf_menucalc(stddeb
,"MenuBarCalcSize left=%d top=%d right=%d bottom=%d !\n",
386 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
387 items
= (MENUITEM
*)USER_HEAP_LIN_ADDR( lppop
->hItems
);
388 lppop
->Width
= lprect
->right
- lprect
->left
;
393 while (start
< lppop
->nItems
)
395 lpitem
= &items
[start
];
399 /* Parse items until line break or end of menu */
400 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
402 if ((helpPos
== -1) && (lpitem
->item_flags
& MF_HELP
)) helpPos
= i
;
404 (lpitem
->item_flags
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
405 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
406 if (lpitem
->rect
.right
> lprect
->right
)
408 if (i
!= start
) break;
409 else lpitem
->rect
.right
= lprect
->right
;
411 maxY
= max( maxY
, lpitem
->rect
.bottom
);
412 orgX
= lpitem
->rect
.right
;
415 /* Finish the line (set all items to the largest height found) */
416 while (start
< i
) items
[start
++].rect
.bottom
= maxY
;
419 lprect
->bottom
= maxY
;
420 lppop
->Height
= lprect
->bottom
- lprect
->top
;
422 /* Flush right all items between the MF_HELP and the last item */
423 /* (if several lines, only move the last line) */
426 lpitem
= &items
[lppop
->nItems
-1];
427 orgY
= lpitem
->rect
.top
;
428 orgX
= lprect
->right
;
429 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--)
431 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
432 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
433 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
434 lpitem
->rect
.right
= orgX
;
435 orgX
= lpitem
->rect
.left
;
441 /***********************************************************************
444 * Draw a single menu item.
446 static void MENU_DrawMenuItem( HWND hwnd
, HDC hdc
, LPMENUITEM lpitem
,
447 WORD height
, BOOL menuBar
)
451 if (lpitem
->item_flags
& MF_OWNERDRAW
) {
452 static HANDLE distrh
= 0;
453 static SEGPTR distrsegp
= 0;
454 static LPDRAWITEMSTRUCT distruct
=NULL
;
455 if (distruct
== NULL
) {
456 distrh
= GlobalAlloc(0,sizeof(DRAWITEMSTRUCT
));
457 distrsegp
= WIN16_GlobalLock(distrh
);
458 distruct
= PTR_SEG_TO_LIN(distrsegp
);
460 dprintf_menu(stddeb
,"DrawMenuItem: Ownerdraw!\n");
461 distruct
->CtlType
= ODT_MENU
;
462 distruct
->itemID
= lpitem
->item_id
;
463 distruct
->itemData
= (long int)lpitem
->item_text
;
464 distruct
->itemState
= 0;
465 if (lpitem
->item_flags
& MF_CHECKED
) distruct
->itemState
|= ODS_CHECKED
;
466 if (lpitem
->item_flags
& MF_GRAYED
) distruct
->itemState
|= ODS_GRAYED
;
467 if (lpitem
->item_flags
& MF_HILITE
) distruct
->itemState
|= ODS_SELECTED
;
468 distruct
->itemAction
= ODA_DRAWENTIRE
| ODA_SELECT
| ODA_FOCUS
;
469 distruct
->hwndItem
= hwnd
;
471 distruct
->rcItem
= lpitem
->rect
;
472 SendMessage(hwnd
,WM_DRAWITEM
,0,distrsegp
);
475 if (menuBar
&& (lpitem
->item_flags
& MF_SEPARATOR
)) return;
478 /* Draw the background */
480 if (lpitem
->item_flags
& MF_HILITE
)
481 FillRect( hdc
, &rect
, sysColorObjects
.hbrushHighlight
);
482 else FillRect( hdc
, &rect
, sysColorObjects
.hbrushMenu
);
483 SetBkMode( hdc
, TRANSPARENT
);
485 /* Draw the separator bar (if any) */
487 if (!menuBar
&& (lpitem
->item_flags
& MF_MENUBARBREAK
))
489 SelectObject( hdc
, sysColorObjects
.hpenWindowFrame
);
490 MoveTo( hdc
, rect
.left
, 0 );
491 LineTo( hdc
, rect
.left
, height
);
493 if (lpitem
->item_flags
& MF_SEPARATOR
)
495 SelectObject( hdc
, sysColorObjects
.hpenWindowFrame
);
496 MoveTo( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
497 LineTo( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
503 if (lpitem
->item_flags
& MF_HILITE
)
505 if (lpitem
->item_flags
& MF_GRAYED
)
506 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
508 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
509 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
513 if (lpitem
->item_flags
& MF_GRAYED
)
514 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
516 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
517 SetBkColor( hdc
, GetSysColor( COLOR_MENU
) );
522 /* Draw the check mark */
524 if (lpitem
->item_flags
& MF_CHECKED
)
526 GRAPH_DrawBitmap(hdc
, lpitem
->hCheckBit
? lpitem
->hCheckBit
:
527 hStdCheck
, rect
.left
,
528 (rect
.top
+rect
.bottom
-check_bitmap_height
) / 2,
529 0, 0, check_bitmap_width
, check_bitmap_height
);
531 else if (lpitem
->hUnCheckBit
!= 0) /* Not checked */
533 GRAPH_DrawBitmap(hdc
, lpitem
->hUnCheckBit
, rect
.left
,
534 (rect
.top
+rect
.bottom
-check_bitmap_height
) / 2,
535 0, 0, check_bitmap_width
, check_bitmap_height
);
538 /* Draw the popup-menu arrow */
540 if (lpitem
->item_flags
& MF_POPUP
)
542 GRAPH_DrawBitmap( hdc
, hStdMnArrow
,
543 rect
.right
-arrow_bitmap_width
-1,
544 (rect
.top
+rect
.bottom
-arrow_bitmap_height
) / 2,
545 0, 0, arrow_bitmap_width
, arrow_bitmap_height
);
548 rect
.left
+= check_bitmap_width
;
549 rect
.right
-= arrow_bitmap_width
;
552 /* Draw the item text or bitmap */
554 if (lpitem
->item_flags
& MF_BITMAP
)
556 GRAPH_DrawBitmap( hdc
, (HBITMAP
)lpitem
->hText
, rect
.left
, rect
.top
,
557 0, 0, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
);
560 /* No bitmap - process text if present */
561 else if ((lpitem
->item_text
) != ((char *) NULL
))
567 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
568 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
569 i
= strlen( lpitem
->item_text
);
573 for (i
= 0; lpitem
->item_text
[i
]; i
++)
574 if ((lpitem
->item_text
[i
] == '\t') ||
575 (lpitem
->item_text
[i
] == '\b')) break;
578 DrawText( hdc
, lpitem
->item_text
, i
, &rect
,
579 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
581 if (lpitem
->item_text
[i
]) /* There's a tab or flush-right char */
583 if (lpitem
->item_text
[i
] == '\t')
585 rect
.left
= lpitem
->xTab
;
586 DrawText( hdc
, lpitem
->item_text
+ i
+ 1, -1, &rect
,
587 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
589 else DrawText( hdc
, lpitem
->item_text
+ i
+ 1, -1, &rect
,
590 DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
);
596 /***********************************************************************
599 * Paint a popup menu.
601 static void MENU_DrawPopupMenu( HWND hwnd
, HDC hdc
, HMENU hmenu
)
608 GetClientRect( hwnd
, &rect
);
609 FillRect( hdc
, &rect
, sysColorObjects
.hbrushMenu
);
610 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
611 if (!menu
|| !menu
->nItems
) return;
612 item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
613 for (i
= menu
->nItems
; i
> 0; i
--, item
++)
614 MENU_DrawMenuItem( hwnd
, hdc
, item
, menu
->Height
, FALSE
);
618 /***********************************************************************
621 * Paint a menu bar. Returns the height of the menu bar.
623 WORD
MENU_DrawMenuBar(HDC hDC
, LPRECT lprect
, HWND hwnd
, BOOL suppress_draw
)
628 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
630 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( wndPtr
->wIDmenu
);
631 if (lppop
== NULL
|| lprect
== NULL
) return SYSMETRICS_CYMENU
;
632 dprintf_menu(stddeb
,"MENU_DrawMenuBar(%04X, %p, %p); !\n",
634 if (lppop
->Height
== 0) MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
635 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
636 if (suppress_draw
) return lppop
->Height
;
638 FillRect(hDC
, lprect
, sysColorObjects
.hbrushMenu
);
639 SelectObject( hDC
, sysColorObjects
.hpenWindowFrame
);
640 MoveTo( hDC
, lprect
->left
, lprect
->bottom
);
641 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
643 if (lppop
->nItems
== 0) return SYSMETRICS_CYMENU
;
644 lpitem
= (MENUITEM
*) USER_HEAP_LIN_ADDR( lppop
->hItems
);
645 for (i
= 0; i
< lppop
->nItems
; i
++, lpitem
++)
647 MENU_DrawMenuItem( hwnd
, hDC
, lpitem
, lppop
->Height
, TRUE
);
649 return lppop
->Height
;
653 /***********************************************************************
656 * Display a popup menu.
658 static BOOL
MENU_ShowPopup(HWND hwndOwner
, HMENU hmenu
, WORD id
, int x
, int y
)
662 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
663 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
665 MENUITEM
*item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
666 item
[menu
->FocusedItem
].item_flags
&= ~(MF_HILITE
| MF_MOUSESELECT
);
667 menu
->FocusedItem
= NO_SELECTED_ITEM
;
669 SendMessage( hwndOwner
, WM_INITMENUPOPUP
, hmenu
,
670 MAKELONG( id
, (menu
->wFlags
& MF_SYSMENU
) ? 1 : 0 ));
671 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
674 WND
*wndPtr
= WIN_FindWndPtr( hwndOwner
);
675 if (!wndPtr
) return FALSE
;
676 menu
->hWnd
= CreateWindow( POPUPMENU_CLASS_NAME
, "",
677 WS_POPUP
| WS_BORDER
, x
, y
,
678 menu
->Width
+ 2*SYSMETRICS_CXBORDER
,
679 menu
->Height
+ 2*SYSMETRICS_CYBORDER
,
680 0, 0, wndPtr
->hInstance
, (SEGPTR
)hmenu
);
681 if (!menu
->hWnd
) return FALSE
;
683 else SetWindowPos( menu
->hWnd
, 0, x
, y
,
684 menu
->Width
+ 2*SYSMETRICS_CXBORDER
,
685 menu
->Height
+ 2*SYSMETRICS_CYBORDER
,
686 SWP_NOACTIVATE
| SWP_NOZORDER
);
688 /* Display the window */
690 SetWindowPos( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
691 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
692 UpdateWindow( menu
->hWnd
);
697 /***********************************************************************
700 static void MENU_SelectItem( HMENU hmenu
, WORD wIndex
)
706 lppop
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
707 if (!lppop
->nItems
) return;
708 items
= (MENUITEM
*) USER_HEAP_LIN_ADDR( lppop
->hItems
);
709 if ((wIndex
!= NO_SELECTED_ITEM
) &&
710 (wIndex
!= SYSMENU_SELECTED
) &&
711 (items
[wIndex
].item_flags
& MF_SEPARATOR
))
712 wIndex
= NO_SELECTED_ITEM
;
713 if (lppop
->FocusedItem
== wIndex
) return;
714 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC( lppop
->hWnd
);
715 else hdc
= GetDCEx( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
717 /* Clear previous highlighted item */
718 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
720 if (lppop
->FocusedItem
== SYSMENU_SELECTED
)
721 NC_DrawSysButton( lppop
->hWnd
, hdc
, FALSE
);
724 items
[lppop
->FocusedItem
].item_flags
&=~(MF_HILITE
|MF_MOUSESELECT
);
725 MENU_DrawMenuItem( lppop
->hWnd
, hdc
, &items
[lppop
->FocusedItem
], lppop
->Height
,
726 !(lppop
->wFlags
& MF_POPUP
) );
730 /* Highlight new item (if any) */
731 lppop
->FocusedItem
= wIndex
;
732 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
734 if (lppop
->FocusedItem
== SYSMENU_SELECTED
)
735 NC_DrawSysButton( lppop
->hWnd
, hdc
, TRUE
);
738 items
[lppop
->FocusedItem
].item_flags
|= MF_HILITE
;
739 MENU_DrawMenuItem( lppop
->hWnd
, hdc
, &items
[lppop
->FocusedItem
], lppop
->Height
,
740 !(lppop
->wFlags
& MF_POPUP
) );
741 dprintf_menu(stddeb
,"Sending WM_MENUSELECT %04x %04x\n", items
[lppop
->FocusedItem
].item_id
,items
[lppop
->FocusedItem
].item_flags
);
742 SendMessage(lppop
->hWnd
, WM_MENUSELECT
, items
[lppop
->FocusedItem
].item_id
,
743 MAKELONG( items
[lppop
->FocusedItem
].item_flags
| MF_MOUSESELECT
, hmenu
));
746 ReleaseDC( lppop
->hWnd
, hdc
);
750 /***********************************************************************
751 * MENU_SelectNextItem
753 static void MENU_SelectNextItem( HMENU hmenu
)
759 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
760 if (!menu
->nItems
) return;
761 items
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
762 if ((menu
->FocusedItem
!= NO_SELECTED_ITEM
) &&
763 (menu
->FocusedItem
!= SYSMENU_SELECTED
))
765 for (i
= menu
->FocusedItem
+1; i
< menu
->nItems
; i
++)
767 if (!(items
[i
].item_flags
& MF_SEPARATOR
))
769 MENU_SelectItem( hmenu
, i
);
773 if (MENU_HasSysMenu( menu
))
775 MENU_SelectItem( hmenu
, SYSMENU_SELECTED
);
779 for (i
= 0; i
< menu
->nItems
; i
++)
781 if (!(items
[i
].item_flags
& MF_SEPARATOR
))
783 MENU_SelectItem( hmenu
, i
);
787 if (MENU_HasSysMenu( menu
)) MENU_SelectItem( hmenu
, SYSMENU_SELECTED
);
791 /***********************************************************************
792 * MENU_SelectPrevItem
794 static void MENU_SelectPrevItem( HMENU hmenu
)
800 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
801 if (!menu
->nItems
) return;
802 items
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
803 if ((menu
->FocusedItem
!= NO_SELECTED_ITEM
) &&
804 (menu
->FocusedItem
!= SYSMENU_SELECTED
))
806 for (i
= menu
->FocusedItem
- 1; i
>= 0; i
--)
808 if (!(items
[i
].item_flags
& MF_SEPARATOR
))
810 MENU_SelectItem( hmenu
, i
);
814 if (MENU_HasSysMenu( menu
))
816 MENU_SelectItem( hmenu
, SYSMENU_SELECTED
);
820 for (i
= menu
->nItems
- 1; i
> 0; i
--)
822 if (!(items
[i
].item_flags
& MF_SEPARATOR
))
824 MENU_SelectItem( hmenu
, i
);
828 if (MENU_HasSysMenu( menu
)) MENU_SelectItem( hmenu
, SYSMENU_SELECTED
);
832 /***********************************************************************
835 * Return the handle of the selected sub-popup menu (if any).
837 static HMENU
MENU_GetSubPopup( HMENU hmenu
)
842 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
843 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return 0;
844 else if (menu
->FocusedItem
== SYSMENU_SELECTED
)
845 return GetSystemMenu( menu
->hWnd
, FALSE
);
847 item
= ((MENUITEM
*)USER_HEAP_LIN_ADDR(menu
->hItems
)) + menu
->FocusedItem
;
848 if (!(item
->item_flags
& MF_POPUP
) || !(item
->item_flags
& MF_MOUSESELECT
))
850 return item
->item_id
;
854 /***********************************************************************
857 * Hide the sub-popup menus of this menu.
859 static void MENU_HideSubPopups( HMENU hmenu
)
862 POPUPMENU
*menu
, *submenu
;
865 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return;
866 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return;
867 if (menu
->FocusedItem
== SYSMENU_SELECTED
)
869 hsubmenu
= GetSystemMenu( menu
->hWnd
, FALSE
);
873 item
= ((MENUITEM
*)USER_HEAP_LIN_ADDR(menu
->hItems
)) + menu
->FocusedItem
;
874 if (!(item
->item_flags
& MF_POPUP
) ||
875 !(item
->item_flags
& MF_MOUSESELECT
)) return;
876 item
->item_flags
&= ~MF_MOUSESELECT
;
877 hsubmenu
= item
->item_id
;
879 submenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hsubmenu
);
880 MENU_HideSubPopups( hsubmenu
);
881 if (submenu
->hWnd
) ShowWindow( submenu
->hWnd
, SW_HIDE
);
882 MENU_SelectItem( hsubmenu
, NO_SELECTED_ITEM
);
886 /***********************************************************************
889 * Display the sub-menu of the selected item of this menu.
890 * Return the handle of the submenu, or hmenu if no submenu to display.
892 static HMENU
MENU_ShowSubPopup( HWND hwndOwner
, HMENU hmenu
, BOOL selectFirst
)
898 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return hmenu
;
899 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return hmenu
;
900 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return hmenu
;
901 if (menu
->FocusedItem
== SYSMENU_SELECTED
)
903 MENU_ShowPopup(hwndOwner
, wndPtr
->hSysMenu
, 0, wndPtr
->rectClient
.left
,
904 wndPtr
->rectClient
.top
- menu
->Height
- 2*SYSMETRICS_CYBORDER
);
905 if (selectFirst
) MENU_SelectNextItem( wndPtr
->hSysMenu
);
906 return wndPtr
->hSysMenu
;
908 item
= ((MENUITEM
*)USER_HEAP_LIN_ADDR(menu
->hItems
)) + menu
->FocusedItem
;
909 if (!(item
->item_flags
& MF_POPUP
) ||
910 (item
->item_flags
& (MF_GRAYED
| MF_DISABLED
))) return hmenu
;
911 item
->item_flags
|= MF_MOUSESELECT
;
912 if (menu
->wFlags
& MF_POPUP
)
914 MENU_ShowPopup( hwndOwner
, (HMENU
)item
->item_id
, menu
->FocusedItem
,
915 wndPtr
->rectWindow
.left
+ item
->rect
.right
-arrow_bitmap_width
,
916 wndPtr
->rectWindow
.top
+ item
->rect
.top
);
920 MENU_ShowPopup( hwndOwner
, (HMENU
)item
->item_id
, menu
->FocusedItem
,
921 wndPtr
->rectWindow
.left
+ item
->rect
.left
,
922 wndPtr
->rectWindow
.top
+ item
->rect
.bottom
);
924 if (selectFirst
) MENU_SelectNextItem( (HMENU
)item
->item_id
);
925 return (HMENU
)item
->item_id
;
929 /***********************************************************************
930 * MENU_FindMenuByCoords
932 * Find the menu containing a given point (in screen coords).
934 static HMENU
MENU_FindMenuByCoords( HMENU hmenu
, POINT pt
)
939 if (!(hwnd
= WindowFromPoint( pt
))) return 0;
942 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
943 if (menu
->hWnd
== hwnd
)
945 if (!(menu
->wFlags
& MF_POPUP
))
947 /* Make sure it's in the menu bar (or in system menu) */
948 WND
*wndPtr
= WIN_FindWndPtr( menu
->hWnd
);
949 if ((pt
.x
< wndPtr
->rectClient
.left
) ||
950 (pt
.x
>= wndPtr
->rectClient
.right
) ||
951 (pt
.y
>= wndPtr
->rectClient
.top
)) return 0;
952 if (pt
.y
< wndPtr
->rectClient
.top
- menu
->Height
)
954 if (!MENU_IsInSysMenu( menu
, pt
)) return 0;
956 /* else it's in the menu bar */
960 hmenu
= MENU_GetSubPopup( hmenu
);
966 /***********************************************************************
967 * MENU_ExecFocusedItem
969 * Execute a menu item (for instance when user pressed Enter).
970 * Return TRUE if we can go on with menu tracking.
972 static BOOL
MENU_ExecFocusedItem( HWND hwndOwner
, HMENU hmenu
,
973 HMENU
*hmenuCurrent
)
976 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
977 if (!menu
|| !menu
->nItems
|| (menu
->FocusedItem
== NO_SELECTED_ITEM
) ||
978 (menu
->FocusedItem
== SYSMENU_SELECTED
)) return TRUE
;
979 item
= ((MENUITEM
*)USER_HEAP_LIN_ADDR(menu
->hItems
)) + menu
->FocusedItem
;
980 if (!(item
->item_flags
& MF_POPUP
))
982 if (!(item
->item_flags
& (MF_GRAYED
| MF_DISABLED
)))
984 PostMessage( hwndOwner
, (menu
->wFlags
& MF_SYSMENU
) ?
985 WM_SYSCOMMAND
: WM_COMMAND
, item
->item_id
, 0 );
992 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, TRUE
);
998 /***********************************************************************
1001 * Handle a button-down event in a menu. Point is in screen coords.
1002 * hmenuCurrent is the top-most visible popup.
1003 * Return TRUE if we can go on with menu tracking.
1005 static BOOL
MENU_ButtonDown( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
,
1012 if (!hmenu
) return FALSE
; /* Outside all menus */
1013 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1014 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1015 if (!item
) /* Maybe in system menu */
1017 if (!MENU_IsInSysMenu( menu
, pt
)) return FALSE
;
1018 id
= SYSMENU_SELECTED
;
1021 if (menu
->FocusedItem
== id
)
1023 if (id
== SYSMENU_SELECTED
) return FALSE
;
1024 if (item
->item_flags
& MF_POPUP
)
1026 if (item
->item_flags
& MF_MOUSESELECT
)
1028 if (menu
->wFlags
& MF_POPUP
)
1030 MENU_HideSubPopups( hmenu
);
1031 *hmenuCurrent
= hmenu
;
1035 else *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1040 MENU_HideSubPopups( hmenu
);
1041 MENU_SelectItem( hmenu
, id
);
1042 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1048 /***********************************************************************
1051 * Handle a button-up event in a menu. Point is in screen coords.
1052 * hmenuCurrent is the top-most visible popup.
1053 * Return TRUE if we can go on with menu tracking.
1055 static BOOL
MENU_ButtonUp( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
,
1063 if (!hmenu
) return FALSE
; /* Outside all menus */
1064 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1065 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1066 if (!item
) /* Maybe in system menu */
1068 if (!MENU_IsInSysMenu( menu
, pt
)) return FALSE
;
1069 id
= SYSMENU_SELECTED
;
1070 hsubmenu
= GetSystemMenu( menu
->hWnd
, FALSE
);
1073 if (menu
->FocusedItem
!= id
) return FALSE
;
1075 if (id
!= SYSMENU_SELECTED
)
1077 if (!(item
->item_flags
& MF_POPUP
))
1079 return MENU_ExecFocusedItem( hwndOwner
, hmenu
, hmenuCurrent
);
1081 hsubmenu
= item
->item_id
;
1083 /* Select first item of sub-popup */
1084 MENU_SelectItem( hsubmenu
, NO_SELECTED_ITEM
);
1085 MENU_SelectNextItem( hsubmenu
);
1090 /***********************************************************************
1093 * Handle a motion event in a menu. Point is in screen coords.
1094 * hmenuCurrent is the top-most visible popup.
1095 * Return TRUE if we can go on with menu tracking.
1097 static BOOL
MENU_MouseMove( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
,
1101 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1102 WORD id
= NO_SELECTED_ITEM
;
1106 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1107 if (!item
) /* Maybe in system menu */
1109 if (!MENU_IsInSysMenu( menu
, pt
))
1110 id
= NO_SELECTED_ITEM
; /* Outside all items */
1111 else id
= SYSMENU_SELECTED
;
1114 if (id
== NO_SELECTED_ITEM
)
1116 MENU_SelectItem( *hmenuCurrent
, NO_SELECTED_ITEM
);
1118 else if (menu
->FocusedItem
!= id
)
1120 MENU_HideSubPopups( hmenu
);
1121 MENU_SelectItem( hmenu
, id
);
1122 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1128 /***********************************************************************
1131 * Handle a VK_LEFT key event in a menu.
1132 * hmenuCurrent is the top-most visible popup.
1134 static void MENU_KeyLeft( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
)
1137 HMENU hmenutmp
, hmenuprev
;
1139 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1140 hmenuprev
= hmenutmp
= hmenu
;
1141 while (hmenutmp
!= *hmenuCurrent
)
1143 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
1144 if (hmenutmp
!= *hmenuCurrent
) hmenuprev
= hmenutmp
;
1146 MENU_HideSubPopups( hmenuprev
);
1148 if ((hmenuprev
== hmenu
) && !(menu
->wFlags
& MF_POPUP
))
1150 /* Select previous item on the menu bar */
1151 MENU_SelectPrevItem( hmenu
);
1152 if (*hmenuCurrent
!= hmenu
)
1154 /* A popup menu was displayed -> display the next one */
1155 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, TRUE
);
1158 else *hmenuCurrent
= hmenuprev
;
1162 /***********************************************************************
1165 * Handle a VK_RIGHT key event in a menu.
1166 * hmenuCurrent is the top-most visible popup.
1168 static void MENU_KeyRight( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
)
1173 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1175 if ((menu
->wFlags
& MF_POPUP
) || (*hmenuCurrent
!= hmenu
))
1177 /* If already displaying a popup, try to display sub-popup */
1178 hmenutmp
= MENU_ShowSubPopup( hwndOwner
, *hmenuCurrent
, TRUE
);
1179 if (hmenutmp
!= *hmenuCurrent
) /* Sub-popup displayed */
1181 *hmenuCurrent
= hmenutmp
;
1186 /* If on menu-bar, go to next item */
1187 if (!(menu
->wFlags
& MF_POPUP
))
1189 MENU_HideSubPopups( hmenu
);
1190 MENU_SelectNextItem( hmenu
);
1191 if (*hmenuCurrent
!= hmenu
)
1193 /* A popup menu was displayed -> display the next one */
1194 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, TRUE
);
1197 else if (*hmenuCurrent
!= hmenu
) /* Hide last level popup */
1200 hmenuprev
= hmenutmp
= hmenu
;
1201 while (hmenutmp
!= *hmenuCurrent
)
1203 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
1204 if (hmenutmp
!= *hmenuCurrent
) hmenuprev
= hmenutmp
;
1206 MENU_HideSubPopups( hmenuprev
);
1207 *hmenuCurrent
= hmenuprev
;
1212 /***********************************************************************
1215 * Menu tracking code.
1216 * If 'x' and 'y' are not 0, we simulate a button-down event at (x,y)
1217 * before beginning tracking. This is to help menu-bar tracking.
1219 static BOOL
MENU_TrackMenu( HMENU hmenu
, WORD wFlags
, int x
, int y
,
1220 HWND hwnd
, LPRECT lprect
)
1225 HMENU hmenuCurrent
= hmenu
;
1226 BOOL fClosed
= FALSE
, fRemove
;
1229 fEndMenuCalled
= FALSE
;
1230 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
1233 POINT pt
= { x
, y
};
1234 MENU_ButtonDown( hwnd
, hmenu
, &hmenuCurrent
, pt
);
1237 hMsg
= USER_HEAP_ALLOC( sizeof(MSG
) );
1238 msg
= (MSG
*)USER_HEAP_LIN_ADDR( hMsg
);
1241 if (!MSG_InternalGetMessage( USER_HEAP_SEG_ADDR(hMsg
), 0,
1242 hwnd
, MSGF_MENU
, 0, TRUE
))
1246 if ((msg
->message
>= WM_MOUSEFIRST
) && (msg
->message
<= WM_MOUSELAST
))
1248 /* Find the sub-popup for this mouse event (if any) */
1249 HMENU hsubmenu
= MENU_FindMenuByCoords( hmenu
, msg
->pt
);
1251 switch(msg
->message
)
1253 case WM_RBUTTONDOWN
:
1254 case WM_NCRBUTTONDOWN
:
1255 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
1257 case WM_LBUTTONDOWN
:
1258 case WM_NCLBUTTONDOWN
:
1259 fClosed
= !MENU_ButtonDown( hwnd
, hsubmenu
,
1260 &hmenuCurrent
, msg
->pt
);
1264 case WM_NCRBUTTONUP
:
1265 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
1268 case WM_NCLBUTTONUP
:
1269 /* If outside all menus but inside lprect, ignore it */
1270 if (!hsubmenu
&& lprect
&& PtInRect( lprect
, msg
->pt
)) break;
1271 fClosed
= !MENU_ButtonUp( hwnd
, hsubmenu
,
1272 &hmenuCurrent
, msg
->pt
);
1273 fRemove
= TRUE
; /* Remove event even if outside menu */
1277 case WM_NCMOUSEMOVE
:
1278 if ((msg
->wParam
& MK_LBUTTON
) ||
1279 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
->wParam
& MK_RBUTTON
)))
1281 fClosed
= !MENU_MouseMove( hwnd
, hsubmenu
,
1282 &hmenuCurrent
, msg
->pt
);
1287 else if ((msg
->message
>= WM_KEYFIRST
) && (msg
->message
<= WM_KEYLAST
))
1289 fRemove
= TRUE
; /* Keyboard messages are always removed */
1290 switch(msg
->message
)
1296 MENU_SelectItem( hmenuCurrent
, NO_SELECTED_ITEM
);
1297 MENU_SelectNextItem( hmenuCurrent
);
1301 MENU_SelectItem( hmenuCurrent
, NO_SELECTED_ITEM
);
1302 MENU_SelectPrevItem( hmenuCurrent
);
1306 MENU_SelectPrevItem( hmenuCurrent
);
1310 /* If on menu bar, pull-down the menu */
1311 if (!(menu
->wFlags
& MF_POPUP
) && (hmenuCurrent
== hmenu
))
1312 hmenuCurrent
= MENU_ShowSubPopup( hwnd
, hmenu
, TRUE
);
1314 MENU_SelectNextItem( hmenuCurrent
);
1318 MENU_KeyLeft( hwnd
, hmenu
, &hmenuCurrent
);
1322 MENU_KeyRight( hwnd
, hmenu
, &hmenuCurrent
);
1327 fClosed
= !MENU_ExecFocusedItem( hwnd
, hmenuCurrent
,
1338 break; /* WM_KEYDOWN */
1348 break; /* WM_SYSKEYDOWN */
1352 /* Hack to avoid control chars. */
1353 /* We will find a better way real soon... */
1354 if ((msg
->wParam
<= 32) || (msg
->wParam
>= 127)) break;
1355 pos
= MENU_FindItemByKey( hwnd
, hmenuCurrent
, msg
->wParam
);
1356 if (pos
== (WORD
)-2) fClosed
= TRUE
;
1357 else if (pos
== (WORD
)-1) MessageBeep(0);
1360 MENU_SelectItem( hmenuCurrent
, pos
);
1361 fClosed
= !MENU_ExecFocusedItem( hwnd
, hmenuCurrent
,
1366 break; /* WM_CHAR */
1367 } /* switch(msg->message) */
1371 DispatchMessage( msg
);
1373 if (fEndMenuCalled
) fClosed
= TRUE
;
1374 if (!fClosed
) fRemove
= TRUE
;
1376 if (fRemove
) /* Remove the message from the queue */
1377 PeekMessage( msg
, 0, msg
->message
, msg
->message
, PM_REMOVE
);
1379 USER_HEAP_FREE( hMsg
);
1381 MENU_HideSubPopups( hmenu
);
1382 if (menu
->wFlags
& MF_POPUP
) ShowWindow( menu
->hWnd
, SW_HIDE
);
1383 MENU_SelectItem( hmenu
, NO_SELECTED_ITEM
);
1384 fEndMenuCalled
= FALSE
;
1389 /***********************************************************************
1390 * MENU_TrackMouseMenuBar
1392 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
1394 void MENU_TrackMouseMenuBar( HWND hwnd
, POINT pt
)
1396 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1397 SendMessage( hwnd
, WM_ENTERMENULOOP
, 0, 0 );
1398 MENU_TrackMenu( (HMENU
)wndPtr
->wIDmenu
, TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
1399 pt
.x
, pt
.y
, hwnd
, NULL
);
1400 SendMessage( hwnd
, WM_EXITMENULOOP
, 0, 0 );
1404 /***********************************************************************
1405 * MENU_TrackKbdMenuBar
1407 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
1409 void MENU_TrackKbdMenuBar( HWND hwnd
, WORD wParam
)
1411 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1412 if (!wndPtr
->wIDmenu
) return;
1413 SendMessage( hwnd
, WM_ENTERMENULOOP
, 0, 0 );
1414 /* Select first selectable item */
1415 MENU_SelectItem( wndPtr
->wIDmenu
, NO_SELECTED_ITEM
);
1416 MENU_SelectNextItem( (HMENU
)wndPtr
->wIDmenu
);
1417 MENU_TrackMenu( (HMENU
)wndPtr
->wIDmenu
, TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
1419 SendMessage( hwnd
, WM_EXITMENULOOP
, 0, 0 );
1423 /**********************************************************************
1424 * TrackPopupMenu [USER.416]
1426 BOOL
TrackPopupMenu( HMENU hMenu
, WORD wFlags
, short x
, short y
,
1427 short nReserved
, HWND hWnd
, LPRECT lpRect
)
1429 if (!MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
)) return FALSE
;
1430 return MENU_TrackMenu( hMenu
, wFlags
, 0, 0, hWnd
, lpRect
);
1434 /***********************************************************************
1437 LONG
PopupMenuWndProc( HWND hwnd
, WORD message
, WORD wParam
, LONG lParam
)
1443 CREATESTRUCT
*createStruct
= (CREATESTRUCT
*)PTR_SEG_TO_LIN(lParam
);
1444 HMENU hmenu
= (HMENU
) ((int)createStruct
->lpCreateParams
& 0xffff);
1445 SetWindowWord( hwnd
, 0, hmenu
);
1449 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1450 return MA_NOACTIVATE
;
1455 BeginPaint( hwnd
, &ps
);
1456 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
1457 (HMENU
)GetWindowWord( hwnd
, 0 ) );
1458 EndPaint( hwnd
, &ps
);
1463 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
1469 /***********************************************************************
1470 * MENU_GetMenuBarHeight
1472 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
1474 WORD
MENU_GetMenuBarHeight( HWND hwnd
, WORD menubarWidth
, int orgX
, int orgY
)
1481 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
1482 if (!(lppop
= (LPPOPUPMENU
)USER_HEAP_LIN_ADDR(wndPtr
->wIDmenu
))) return 0;
1483 hdc
= GetDC( hwnd
);
1484 SetRect( &rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+SYSMETRICS_CYMENU
);
1485 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
1486 ReleaseDC( hwnd
, hdc
);
1487 return lppop
->Height
;
1491 /**********************************************************************
1492 * ChangeMenu [USER.153]
1494 BOOL
ChangeMenu(HMENU hMenu
, WORD nPos
, LPSTR lpNewItem
,
1495 WORD wItemID
, WORD wFlags
)
1497 dprintf_menu(stddeb
,"ChangeMenu(%04X, %X, '%s', %X, %X)\n",
1498 hMenu
, nPos
, lpNewItem
, wItemID
, wFlags
);
1499 if (wFlags
& MF_APPEND
) {
1500 return AppendMenu(hMenu
, wFlags
& ~MF_APPEND
, wItemID
, lpNewItem
);
1502 if (wFlags
& MF_DELETE
) {
1503 return DeleteMenu(hMenu
, wFlags
& MF_BYPOSITION
? nPos
: wItemID
,
1504 wFlags
& ~MF_DELETE
);
1506 if (wFlags
& MF_CHANGE
) {
1507 return ModifyMenu(hMenu
, nPos
, wFlags
& ~MF_CHANGE
, wItemID
, lpNewItem
);
1509 if (wFlags
& MF_REMOVE
) {
1510 return RemoveMenu(hMenu
, wFlags
& MF_BYPOSITION
? nPos
: wItemID
,
1511 wFlags
& ~MF_REMOVE
);
1513 /* Default: MF_INSERT */
1514 return InsertMenu(hMenu
, nPos
, wFlags
, wItemID
, lpNewItem
);
1518 /**********************************************************************
1519 * CheckMenuItem [USER.154]
1521 BOOL
CheckMenuItem(HMENU hMenu
, WORD wItemID
, WORD wFlags
)
1524 dprintf_menu(stddeb
,"CheckMenuItem (%04X, %04X, %04X) !\n",
1525 hMenu
, wItemID
, wFlags
);
1526 if (!(lpitem
= MENU_FindItem(&hMenu
, &wItemID
, wFlags
))) return FALSE
;
1527 if (wFlags
& MF_CHECKED
) lpitem
->item_flags
|= MF_CHECKED
;
1528 else lpitem
->item_flags
&= ~MF_CHECKED
;
1533 /**********************************************************************
1534 * EnableMenuItem [USER.155]
1536 BOOL
EnableMenuItem(HMENU hMenu
, WORD wItemID
, WORD wFlags
)
1539 dprintf_menu(stddeb
,"EnableMenuItem (%04X, %04X, %04X) !\n",
1540 hMenu
, wItemID
, wFlags
);
1541 if (!(lpitem
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return FALSE
;
1543 /* We can't have MF_GRAYED and MF_DISABLED together */
1544 if (wFlags
& MF_GRAYED
)
1546 lpitem
->item_flags
= (lpitem
->item_flags
& ~MF_DISABLED
) | MF_GRAYED
;
1548 else if (wFlags
& MF_DISABLED
)
1550 lpitem
->item_flags
= (lpitem
->item_flags
& ~MF_GRAYED
) | MF_DISABLED
;
1552 else /* MF_ENABLED */
1554 lpitem
->item_flags
&= ~(MF_GRAYED
| MF_DISABLED
);
1560 /**********************************************************************
1561 * GetMenuString [USER.161]
1563 int GetMenuString(HMENU hMenu
, WORD wItemID
,
1564 LPSTR str
, short nMaxSiz
, WORD wFlags
)
1568 dprintf_menu(stddeb
,"GetMenuString(%04X, %04X, %p, %d, %04X);\n",
1569 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
1570 if (str
== NULL
) return FALSE
;
1571 lpitem
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
);
1572 if (lpitem
!= NULL
) {
1573 if (lpitem
->item_text
!= NULL
) {
1574 maxsiz
= min(nMaxSiz
- 1, strlen(lpitem
->item_text
));
1575 strncpy(str
, lpitem
->item_text
, maxsiz
+ 1);
1579 dprintf_menu(stddeb
,"GetMenuString // Found !\n");
1586 /**********************************************************************
1587 * HiliteMenuItem [USER.162]
1589 BOOL
HiliteMenuItem(HWND hWnd
, HMENU hMenu
, WORD wItemID
, WORD wHilite
)
1593 dprintf_menu(stddeb
,"HiliteMenuItem(%04X, %04X, %04X, %04X);\n",
1594 hWnd
, hMenu
, wItemID
, wHilite
);
1595 if (!(lpitem
= MENU_FindItem( &hMenu
, &wItemID
, wHilite
))) return FALSE
;
1596 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
1597 if (menu
->FocusedItem
== wItemID
) return TRUE
;
1598 MENU_HideSubPopups( hMenu
);
1599 MENU_SelectItem( hMenu
, wItemID
);
1604 /**********************************************************************
1605 * GetMenuState [USER.250]
1607 WORD
GetMenuState(HMENU hMenu
, WORD wItemID
, WORD wFlags
)
1610 dprintf_menu(stddeb
,"GetMenuState(%04X, %04X, %04X);\n",
1611 hMenu
, wItemID
, wFlags
);
1612 if (!(lpitem
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
1613 if (lpitem
->item_flags
& MF_POPUP
)
1615 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( lpitem
->item_id
);
1616 if (!menu
) return -1;
1617 else return (menu
->nItems
<< 8) | (menu
->wFlags
& 0xff);
1619 else return lpitem
->item_flags
;
1623 /**********************************************************************
1624 * GetMenuItemCount [USER.263]
1626 WORD
GetMenuItemCount(HMENU hMenu
)
1629 dprintf_menu(stddeb
,"GetMenuItemCount(%04X);\n", hMenu
);
1630 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
1631 if (menu
== NULL
) return (WORD
)-1;
1632 dprintf_menu(stddeb
,"GetMenuItemCount(%04X) return %d \n",
1633 hMenu
, menu
->nItems
);
1634 return menu
->nItems
;
1638 /**********************************************************************
1639 * GetMenuItemID [USER.264]
1641 WORD
GetMenuItemID(HMENU hMenu
, int nPos
)
1646 dprintf_menu(stddeb
,"GetMenuItemID(%04X, %d);\n", hMenu
, nPos
);
1647 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
1648 if ((nPos
< 0) || (nPos
>= menu
->nItems
)) return -1;
1649 item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
1650 if (item
[nPos
].item_flags
& MF_POPUP
) return -1;
1651 return item
[nPos
].item_id
;
1655 /**********************************************************************
1656 * InsertMenu [USER.410]
1658 BOOL
InsertMenu(HMENU hMenu
, WORD nPos
, WORD wFlags
, WORD wItemID
, LPSTR lpNewItem
)
1661 MENUITEM
*lpitem
, *newItems
;
1664 if (IS_STRING_ITEM(wFlags
))
1666 dprintf_menu(stddeb
,"InsertMenu (%04X, %04X, %04X, %04X, '%s') !\n",
1667 hMenu
, nPos
, wFlags
, wItemID
, lpNewItem
);
1670 dprintf_menu(stddeb
,"InsertMenu (%04X, %04X, %04X, %04X, %p) !\n",
1671 hMenu
, nPos
, wFlags
, wItemID
, lpNewItem
);
1673 /* Find where to insert new item */
1675 if ((wFlags
& MF_BYPOSITION
) &&
1676 ((nPos
== (WORD
)-1) || (nPos
== GetMenuItemCount(hMenu
))))
1678 /* Special case: append to menu
1679 Some programs specify the menu length to do that */
1680 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
)))
1682 dprintf_menu(stddeb
,"InsertMenu: %04X not a menu handle\n", hMenu
);
1685 nPos
= menu
->nItems
;
1689 if (!MENU_FindItem( &hMenu
, &nPos
, wFlags
))
1691 dprintf_menu(stddeb
,"InsertMenu: Item %X not found\n", nPos
);
1694 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
)))
1696 dprintf_menu(stddeb
,"InsertMenu: %04X not a menu handle\n", hMenu
);
1701 /* Create new items array */
1703 hNewItems
= USER_HEAP_ALLOC( sizeof(MENUITEM
) * (menu
->nItems
+1) );
1706 dprintf_menu(stddeb
,"InsertMenu: allocation failed\n");
1709 newItems
= (MENUITEM
*) USER_HEAP_LIN_ADDR( hNewItems
);
1710 if (menu
->nItems
> 0)
1712 /* Copy the old array into the new */
1713 MENUITEM
*oldItems
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
1714 if (nPos
> 0) memcpy( newItems
, oldItems
, nPos
* sizeof(MENUITEM
) );
1715 if (nPos
< menu
->nItems
) memcpy( &newItems
[nPos
+1], &oldItems
[nPos
],
1716 (menu
->nItems
-nPos
)*sizeof(MENUITEM
) );
1718 USER_HEAP_FREE( menu
->hItems
);
1720 menu
->hItems
= hNewItems
;
1723 /* Store the new item data */
1725 lpitem
= &newItems
[nPos
];
1726 lpitem
->item_flags
= wFlags
& ~(MF_HILITE
| MF_MOUSESELECT
);
1727 lpitem
->item_id
= wItemID
;
1729 if (IS_STRING_ITEM(wFlags
))
1731 /* Item beginning with a backspace is a help item */
1732 if (lpNewItem
[0] == '\b')
1734 lpitem
->item_flags
|= MF_HELP
;
1737 lpitem
->hText
= USER_HEAP_ALLOC( strlen(lpNewItem
)+1 );
1738 lpitem
->item_text
= (char *)USER_HEAP_LIN_ADDR( lpitem
->hText
);
1739 strcpy( lpitem
->item_text
, lpNewItem
);
1741 else if (wFlags
& MF_BITMAP
) lpitem
->hText
= LOWORD((DWORD
)lpNewItem
);
1742 else lpitem
->item_text
= lpNewItem
;
1744 if (wFlags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
1745 ((POPUPMENU
*)USER_HEAP_LIN_ADDR(wItemID
))->wFlags
|= MF_POPUP
;
1747 SetRectEmpty( &lpitem
->rect
);
1748 lpitem
->hCheckBit
= hStdCheck
;
1749 lpitem
->hUnCheckBit
= 0;
1754 /**********************************************************************
1755 * AppendMenu [USER.411]
1757 BOOL
AppendMenu(HMENU hMenu
, WORD wFlags
, WORD wItemID
, LPSTR lpNewItem
)
1759 return InsertMenu( hMenu
, -1, wFlags
| MF_BYPOSITION
, wItemID
, lpNewItem
);
1763 /**********************************************************************
1764 * RemoveMenu [USER.412]
1766 BOOL
RemoveMenu(HMENU hMenu
, WORD nPos
, WORD wFlags
)
1770 dprintf_menu(stddeb
,"RemoveMenu (%04X, %04X, %04X) !\n",
1771 hMenu
, nPos
, wFlags
);
1772 if (!(lpitem
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
1773 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
1777 if (IS_STRING_ITEM(lpitem
->item_flags
)) USER_HEAP_FREE( lpitem
->hText
);
1778 if (--menu
->nItems
== 0)
1780 USER_HEAP_FREE( menu
->hItems
);
1785 while(nPos
< menu
->nItems
)
1787 *lpitem
= *(lpitem
+1);
1791 menu
->hItems
= USER_HEAP_REALLOC( menu
->hItems
,
1792 menu
->nItems
* sizeof(MENUITEM
) );
1798 /**********************************************************************
1799 * DeleteMenu [USER.413]
1801 BOOL
DeleteMenu(HMENU hMenu
, WORD nPos
, WORD wFlags
)
1803 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
1804 if (!item
) return FALSE
;
1805 if (item
->item_flags
& MF_POPUP
) DestroyMenu( item
->item_id
);
1806 /* nPos is now the position of the item */
1807 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
1812 /**********************************************************************
1813 * ModifyMenu [USER.414]
1815 BOOL
ModifyMenu(HMENU hMenu
, WORD nPos
, WORD wFlags
, WORD wItemID
, LPSTR lpNewItem
)
1818 if (IS_STRING_ITEM(wFlags
))
1819 dprintf_menu(stddeb
,"ModifyMenu (%04X, %04X, %04X, %04X, '%s') !\n",
1820 hMenu
, nPos
, wFlags
, wItemID
, lpNewItem
);
1822 dprintf_menu(stddeb
,"ModifyMenu (%04X, %04X, %04X, %04X, %p) !\n",
1823 hMenu
, nPos
, wFlags
, wItemID
, lpNewItem
);
1824 if (!(lpitem
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
1826 if (IS_STRING_ITEM(lpitem
->item_flags
)) USER_HEAP_FREE( lpitem
->hText
);
1827 lpitem
->item_flags
= wFlags
& ~(MF_HILITE
| MF_MOUSESELECT
);
1828 lpitem
->item_id
= wItemID
;
1830 if (IS_STRING_ITEM(wFlags
))
1832 lpitem
->hText
= USER_HEAP_ALLOC( strlen(lpNewItem
)+1 );
1833 lpitem
->item_text
= (char *)USER_HEAP_LIN_ADDR( lpitem
->hText
);
1834 strcpy( lpitem
->item_text
, lpNewItem
);
1836 else if (wFlags
& MF_BITMAP
) lpitem
->hText
= LOWORD((DWORD
)lpNewItem
);
1837 else lpitem
->item_text
= lpNewItem
;
1838 SetRectEmpty( &lpitem
->rect
);
1843 /**********************************************************************
1844 * CreatePopupMenu [USER.415]
1846 HMENU
CreatePopupMenu()
1851 if (!(hmenu
= CreateMenu())) return 0;
1852 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1853 menu
->wFlags
|= MF_POPUP
;
1858 /**********************************************************************
1859 * GetMenuCheckMarkDimensions [USER.417]
1861 DWORD
GetMenuCheckMarkDimensions()
1863 return MAKELONG( check_bitmap_width
, check_bitmap_height
);
1867 /**********************************************************************
1868 * SetMenuItemBitmaps [USER.418]
1870 BOOL
SetMenuItemBitmaps(HMENU hMenu
, WORD nPos
, WORD wFlags
,
1871 HBITMAP hNewCheck
, HBITMAP hNewUnCheck
)
1874 dprintf_menu(stddeb
,"SetMenuItemBitmaps (%04X, %04X, %04X, %04X, %08X) !\n",
1875 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
1876 if (!(lpitem
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
1878 if (!hNewCheck
&& !hNewUnCheck
)
1880 /* If both are NULL, restore default bitmaps */
1881 lpitem
->hCheckBit
= hStdCheck
;
1882 lpitem
->hUnCheckBit
= 0;
1883 lpitem
->item_flags
&= ~MF_USECHECKBITMAPS
;
1885 else /* Install new bitmaps */
1887 lpitem
->hCheckBit
= hNewCheck
;
1888 lpitem
->hUnCheckBit
= hNewUnCheck
;
1889 lpitem
->item_flags
|= MF_USECHECKBITMAPS
;
1895 /**********************************************************************
1896 * CreateMenu [USER.151]
1902 dprintf_menu(stddeb
,"CreateMenu !\n");
1903 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) )))
1905 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
1908 menu
->wMagic
= MENU_MAGIC
;
1915 menu
->FocusedItem
= NO_SELECTED_ITEM
;
1916 dprintf_menu(stddeb
,"CreateMenu // return %04X\n", hMenu
);
1921 /**********************************************************************
1922 * DestroyMenu [USER.152]
1924 BOOL
DestroyMenu(HMENU hMenu
)
1927 dprintf_menu(stddeb
,"DestroyMenu (%04X) !\n", hMenu
);
1928 if (hMenu
== 0) return FALSE
;
1929 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
1930 if (lppop
== NULL
) return FALSE
;
1931 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
)
1932 DestroyWindow( lppop
->hWnd
);
1937 MENUITEM
*item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( lppop
->hItems
);
1938 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
1940 if (item
->item_flags
& MF_POPUP
)
1941 DestroyMenu( item
->item_id
);
1943 USER_HEAP_FREE( lppop
->hItems
);
1945 USER_HEAP_FREE( hMenu
);
1946 dprintf_menu(stddeb
,"DestroyMenu (%04X) // End !\n", hMenu
);
1950 /**********************************************************************
1951 * GetSystemMenu [USER.156]
1953 HMENU
GetSystemMenu(HWND hWnd
, BOOL bRevert
)
1956 wndPtr
= WIN_FindWndPtr(hWnd
);
1958 return wndPtr
->hSysMenu
;
1961 DestroyMenu(wndPtr
->hSysMenu
);
1962 wndPtr
->hSysMenu
= CopySysMenu();
1964 return wndPtr
->hSysMenu
;
1967 /**********************************************************************
1968 * SetSystemMenu [USER.280]
1970 BOOL
SetSystemMenu(HWND hWnd
, HMENU newHmenu
)
1974 if ((wndPtr
= WIN_FindWndPtr(hWnd
)) != NULL
) wndPtr
->hSysMenu
= newHmenu
;
1979 /**********************************************************************
1980 * GetMenu [USER.157]
1982 HMENU
GetMenu(HWND hWnd
)
1984 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
1985 if (wndPtr
== NULL
) return 0;
1986 return wndPtr
->wIDmenu
;
1990 /**********************************************************************
1991 * SetMenu [USER.158]
1993 BOOL
SetMenu(HWND hWnd
, HMENU hMenu
)
1996 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
1997 if (wndPtr
== NULL
) {
1998 fprintf(stderr
,"SetMenu(%04X, %04X) // Bad window handle !\n",
2002 dprintf_menu(stddeb
,"SetMenu(%04X, %04X);\n", hWnd
, hMenu
);
2003 if (GetCapture() == hWnd
) ReleaseCapture();
2004 wndPtr
->wIDmenu
= hMenu
;
2007 lpmenu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2008 if (lpmenu
== NULL
) {
2009 fprintf(stderr
,"SetMenu(%04X, %04X) // Bad menu handle !\n",
2013 lpmenu
->hWnd
= hWnd
;
2014 lpmenu
->wFlags
&= ~MF_POPUP
; /* Can't be a popup */
2015 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
2017 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
2018 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
2024 /**********************************************************************
2025 * GetSubMenu [USER.159]
2027 HMENU
GetSubMenu(HMENU hMenu
, short nPos
)
2031 dprintf_menu(stddeb
,"GetSubMenu (%04X, %04X) !\n", hMenu
, nPos
);
2032 if (!(lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return 0;
2033 if ((WORD
)nPos
>= lppop
->nItems
) return 0;
2034 lpitem
= (MENUITEM
*) USER_HEAP_LIN_ADDR( lppop
->hItems
);
2035 if (!(lpitem
[nPos
].item_flags
& MF_POPUP
)) return 0;
2036 return lpitem
[nPos
].item_id
;
2040 /**********************************************************************
2041 * DrawMenuBar [USER.160]
2043 void DrawMenuBar(HWND hWnd
)
2047 dprintf_menu(stddeb
,"DrawMenuBar (%04X)\n", hWnd
);
2048 wndPtr
= WIN_FindWndPtr(hWnd
);
2049 if (wndPtr
!= NULL
&& (wndPtr
->dwStyle
& WS_CHILD
) == 0 &&
2050 wndPtr
->wIDmenu
!= 0) {
2051 dprintf_menu(stddeb
,"DrawMenuBar wIDmenu=%04X \n",
2053 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(wndPtr
->wIDmenu
);
2054 if (lppop
== NULL
) return;
2056 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
2057 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
2058 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
2063 /***********************************************************************
2064 * EndMenu (USER.187)
2068 /* Note: this won't work when we have multiple tasks... */
2069 fEndMenuCalled
= TRUE
;
2073 /***********************************************************************
2074 * LookupMenuHandle (USER.217)
2076 HMENU
LookupMenuHandle( HMENU hmenu
, INT id
)
2078 if (!MENU_FindItem( &hmenu
, &id
, MF_BYCOMMAND
)) return 0;
2083 /**********************************************************************
2084 * LoadMenu (USER.150)
2086 HMENU
LoadMenu( HINSTANCE instance
, SEGPTR name
)
2094 char *str
= (char *)PTR_SEG_TO_LIN( name
);
2095 dprintf_menu( stddeb
, "LoadMenu(%04x,'%s')\n", instance
, str
);
2096 if (str
[0] == '#') name
= (SEGPTR
)atoi( str
+ 1 );
2099 dprintf_resource(stddeb
,"LoadMenu(%04x,%04x)\n",instance
,LOWORD(name
));
2101 if (!name
) return 0;
2103 if (!(hRsrc
= FindResource( instance
, name
, RT_MENU
))) return 0;
2104 if (!(handle
= LoadResource( instance
, hRsrc
))) return 0;
2105 hMenu
= LoadMenuIndirect( LockResource(handle
) );
2106 FreeResource( handle
);
2111 /**********************************************************************
2112 * LoadMenuIndirect [USER.220]
2114 HMENU
LoadMenuIndirect(LPSTR menu_template
)
2117 MENU_HEADER
*menu_desc
;
2118 dprintf_menu(stddeb
,"LoadMenuIndirect: menu_template '%p'\n",
2120 hMenu
= CreateMenu();
2121 menu_desc
= (MENU_HEADER
*)menu_template
;
2122 ParseMenuResource((WORD
*)(menu_desc
+ 1), 0, hMenu
);
2127 /**********************************************************************
2128 * CopySysMenu (Internal)
2134 extern unsigned char sysres_MENU_SYSMENU
[];
2136 hMenu
=LoadMenuIndirect(sysres_MENU_SYSMENU
);
2138 dprintf_menu(stddeb
,"No SYSMENU\n");
2141 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
2142 menu
->wFlags
|= MF_SYSMENU
|MF_POPUP
;
2143 dprintf_menu(stddeb
,"CopySysMenu hMenu=%04X !\n", hMenu
);
2148 /**********************************************************************
2149 * ParseMenuResource (from Resource or Template)
2151 WORD
* ParseMenuResource(WORD
*first_item
, int level
, HMENU hMenu
)
2159 next_item
= first_item
;
2164 if (*item
& MF_POPUP
) {
2165 MENU_POPUPITEM
*popup_item
= (MENU_POPUPITEM
*) item
;
2166 next_item
= (WORD
*) (popup_item
->item_text
+
2167 strlen(popup_item
->item_text
) + 1);
2168 hSubMenu
= CreatePopupMenu();
2169 next_item
= ParseMenuResource(next_item
, level
, hSubMenu
);
2170 AppendMenu(hMenu
, popup_item
->item_flags
,
2171 hSubMenu
, popup_item
->item_text
);
2174 MENUITEMTEMPLATE
*normal_item
= (MENUITEMTEMPLATE
*) item
;
2175 next_item
= (WORD
*) (normal_item
->item_text
+
2176 strlen(normal_item
->item_text
) + 1);
2177 if (strlen(normal_item
->item_text
) == 0 && normal_item
->item_id
== 0)
2178 normal_item
->item_flags
|= MF_SEPARATOR
;
2179 AppendMenu(hMenu
, normal_item
->item_flags
,
2180 normal_item
->item_id
, normal_item
->item_text
);
2183 while (!(*item
& MF_END
));
2188 /**********************************************************************
2191 BOOL
IsMenu( HMENU hmenu
)
2194 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
2195 return (menu
->wMagic
== MENU_MAGIC
);