Release 950319
[wine/multimedia.git] / controls / menu.c
blobac118e902e1254c4eee6f80b49f627f113e555ef
1 /*
2 * Menu functions
4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
6 */
8 /*
9 * Note: the style MF_MOUSESELECT is used to mark popup items that
10 * have been selected, i.e. their popup menu is currently displayed.
11 * This is probably not the meaning this style has in MS-Windows.
14 #include <ctype.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include "windows.h"
19 #include "syscolor.h"
20 #include "sysmetrics.h"
21 #include "menu.h"
22 #include "user.h"
23 #include "win.h"
24 #include "library.h"
25 #include "message.h"
26 #include "graphics.h"
27 #include "stddebug.h"
28 /* #define DEBUG_MENU */
29 /* #define DEBUG_MENUCALC */
30 /* #define DEBUG_MENUSHORTCUT */
31 #include "debug.h"
34 /* Dimension of the menu bitmaps */
35 static WORD check_bitmap_width = 0, check_bitmap_height = 0;
36 static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
38 /* Flag set by EndMenu() to force an exit from menu tracking */
39 static BOOL fEndMenuCalled = FALSE;
41 /* Space between 2 menu bar items */
42 #define MENU_BAR_ITEMS_SPACE 16
44 /* Minimum width of a tab character */
45 #define MENU_TAB_SPACE 8
47 /* Height of a separator item */
48 #define SEPARATOR_HEIGHT 5
50 /* Values for menu->FocusedItem */
51 /* (other values give the position of the focused item) */
52 #define NO_SELECTED_ITEM 0xffff
53 #define SYSMENU_SELECTED 0xfffe /* Only valid on menu-bars */
55 #define IS_STRING_ITEM(flags) (!((flags) & (MF_BITMAP | MF_OWNERDRAW | \
56 MF_MENUBARBREAK | MF_MENUBREAK | MF_SEPARATOR)))
59 extern void NC_DrawSysButton(HWND hwnd, HDC hdc, BOOL down); /* nonclient.c */
61 static HBITMAP hStdCheck = 0;
62 static HBITMAP hStdMnArrow = 0;
64 HMENU CopySysMenu();
65 WORD * ParseMenuResource(WORD *first_item, int level, HMENU hMenu);
68 /***********************************************************************
69 * MENU_Init
71 * Menus initialisation.
73 BOOL MENU_Init()
75 BITMAP bm;
77 /* Load bitmaps */
79 if (!(hStdCheck = LoadBitmap( 0, MAKEINTRESOURCE(OBM_CHECK) )))
80 return FALSE;
81 GetObject( hStdCheck, sizeof(BITMAP), (LPSTR)&bm );
82 check_bitmap_width = bm.bmWidth;
83 check_bitmap_height = bm.bmHeight;
84 if (!(hStdMnArrow = LoadBitmap( 0, MAKEINTRESOURCE(OBM_MNARROW) )))
85 return FALSE;
86 GetObject( hStdMnArrow, sizeof(BITMAP), (LPSTR)&bm );
87 arrow_bitmap_width = bm.bmWidth;
88 arrow_bitmap_height = bm.bmHeight;
90 return TRUE;
94 /***********************************************************************
95 * MENU_HasSysMenu
97 * Check whether the window owning the menu bar has a system menu.
99 static BOOL MENU_HasSysMenu( POPUPMENU *menu )
101 WND *wndPtr;
103 if (menu->wFlags & MF_POPUP) return FALSE;
104 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return FALSE;
105 return (wndPtr->dwStyle & WS_SYSMENU) != 0;
109 /***********************************************************************
110 * MENU_IsInSysMenu
112 * Check whether the point (in screen coords) is in the system menu
113 * of the window owning the given menu.
115 static BOOL MENU_IsInSysMenu( POPUPMENU *menu, POINT pt )
117 WND *wndPtr;
119 if (menu->wFlags & MF_POPUP) return FALSE;
120 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return FALSE;
121 if (!(wndPtr->dwStyle & WS_SYSMENU)) return FALSE;
122 if ((pt.x < wndPtr->rectClient.left) ||
123 (pt.x >= wndPtr->rectClient.left+SYSMETRICS_CXSIZE+SYSMETRICS_CXBORDER))
124 return FALSE;
125 if ((pt.y >= wndPtr->rectClient.top - menu->Height) ||
126 (pt.y < wndPtr->rectClient.top - menu->Height -
127 SYSMETRICS_CYSIZE - SYSMETRICS_CYBORDER)) return FALSE;
128 return TRUE;
132 /***********************************************************************
133 * MENU_FindItem
135 * Find a menu item. Return a pointer on the item, and modifies *hmenu
136 * in case the item was in a sub-menu.
138 static MENUITEM *MENU_FindItem( HMENU *hmenu, WORD *nPos, WORD wFlags )
140 POPUPMENU *menu;
141 MENUITEM *item;
142 int i;
144 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(*hmenu))) return NULL;
145 item = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
146 if (wFlags & MF_BYPOSITION)
148 if (*nPos >= menu->nItems) return NULL;
149 return &item[*nPos];
151 else
153 for (i = 0; i < menu->nItems; i++, item++)
155 if (item->item_id == *nPos)
157 *nPos = i;
158 return item;
160 else if (item->item_flags & MF_POPUP)
162 HMENU hsubmenu = (HMENU)item->item_id;
163 MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
164 if (subitem)
166 *hmenu = hsubmenu;
167 return subitem;
172 return NULL;
176 /***********************************************************************
177 * MENU_FindItemByCoords
179 * Find the item at the specified coordinates (screen coords).
181 static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu, int x, int y, WORD *pos )
183 MENUITEM *item;
184 WND *wndPtr;
185 int i;
187 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return NULL;
188 x -= wndPtr->rectWindow.left;
189 y -= wndPtr->rectWindow.top;
190 item = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
191 for (i = 0; i < menu->nItems; i++, item++)
193 if ((x >= item->rect.left) && (x < item->rect.right) &&
194 (y >= item->rect.top) && (y < item->rect.bottom))
196 if (pos) *pos = i;
197 return item;
200 return NULL;
204 /***********************************************************************
205 * MENU_FindItemByKey
207 * Find the menu item selected by a key press.
208 * Return item id, -1 if none, -2 if we should close the menu.
210 static WORD MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu, WORD key )
212 POPUPMENU *menu;
213 LPMENUITEM lpitem;
214 int i;
215 LONG menuchar;
217 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
218 lpitem = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
219 key = toupper(key);
220 for (i = 0; i < menu->nItems; i++, lpitem++)
222 if (IS_STRING_ITEM(lpitem->item_flags))
224 char *p = strchr( lpitem->item_text, '&' );
225 if (p && (p[1] != '&') && (toupper(p[1]) == key)) return i;
228 menuchar = SendMessage( hwndOwner, WM_MENUCHAR, key,
229 MAKELONG( menu->wFlags, hmenu ) );
230 if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
231 if (HIWORD(menuchar) == 1) return -2;
232 return -1;
236 /***********************************************************************
237 * MENU_CalcItemSize
239 * Calculate the size of the menu item and store it in lpitem->rect.
241 static void MENU_CalcItemSize( HDC hdc, LPMENUITEM lpitem, HWND hwndOwner,
242 int orgX, int orgY, BOOL menuBar )
244 DWORD dwSize;
245 char *p;
247 SetRect( &lpitem->rect, orgX, orgY, orgX, orgY );
248 lpitem->xTab = 0;
250 if (lpitem->item_flags & MF_SEPARATOR)
252 lpitem->rect.bottom += SEPARATOR_HEIGHT;
253 return;
256 if (!menuBar)
258 lpitem->rect.right += 2 * check_bitmap_width;
259 if (lpitem->item_flags & MF_POPUP)
260 lpitem->rect.right += arrow_bitmap_width;
263 if (lpitem->item_flags & MF_BITMAP)
265 BITMAP bm;
266 GetObject( (HBITMAP)lpitem->hText, sizeof(BITMAP), (LPSTR)&bm );
267 lpitem->rect.right += bm.bmWidth;
268 lpitem->rect.bottom += bm.bmHeight;
269 return;
272 /* If we get here, then it is a text item */
274 dwSize = (lpitem->item_text == NULL) ? 0 : GetTextExtent( hdc, lpitem->item_text, strlen(lpitem->item_text));
275 lpitem->rect.right += LOWORD(dwSize);
276 lpitem->rect.bottom += max( HIWORD(dwSize), SYSMETRICS_CYMENU );
278 if (menuBar) lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
279 else if ((p = strchr( lpitem->item_text, '\t' )) != NULL)
281 /* Item contains a tab (only meaningful in popup menus) */
282 lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE +
283 LOWORD( GetTextExtent( hdc, lpitem->item_text,
284 (int)(p - lpitem->item_text) ));
285 lpitem->rect.right += MENU_TAB_SPACE;
287 else
289 if (strchr( lpitem->item_text, '\b' ))
290 lpitem->rect.right += MENU_TAB_SPACE;
291 lpitem->xTab = lpitem->rect.right - check_bitmap_width
292 - arrow_bitmap_width;
297 /***********************************************************************
298 * MENU_PopupMenuCalcSize
300 * Calculate the size of a popup menu.
302 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
304 LPMENUITEM items, lpitem;
305 HDC hdc;
306 int start, i;
307 int orgX, orgY, maxX, maxTab, maxTabWidth;
309 lppop->Width = lppop->Height = 0;
310 if (lppop->nItems == 0) return;
311 items = (MENUITEM *)USER_HEAP_LIN_ADDR( lppop->hItems );
312 hdc = GetDC( 0 );
313 maxX = start = 0;
314 while (start < lppop->nItems)
316 lpitem = &items[start];
317 orgX = maxX;
318 orgY = 0;
319 maxTab = maxTabWidth = 0;
321 /* Parse items until column break or end of menu */
322 for (i = start; i < lppop->nItems; i++, lpitem++)
324 if ((i != start) &&
325 (lpitem->item_flags & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
326 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
327 maxX = max( maxX, lpitem->rect.right );
328 orgY = lpitem->rect.bottom;
329 if (lpitem->xTab)
331 maxTab = max( maxTab, lpitem->xTab );
332 maxTabWidth = max(maxTabWidth,lpitem->rect.right-lpitem->xTab);
336 /* Finish the column (set all items to the largest width found) */
337 maxX = max( maxX, maxTab + maxTabWidth );
338 for (lpitem = &items[start]; start < i; start++, lpitem++)
340 lpitem->rect.right = maxX;
341 if (lpitem->xTab) lpitem->xTab = maxTab;
343 lppop->Height = max( lppop->Height, orgY );
346 lppop->Width = maxX;
347 ReleaseDC( 0, hdc );
351 /***********************************************************************
352 * MENU_MenuBarCalcSize
354 * Calculate the size of the menu bar.
356 static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect, LPPOPUPMENU lppop,
357 HWND hwndOwner )
359 LPMENUITEM lpitem, items;
360 int start, i, orgX, orgY, maxY, helpPos;
362 if ((lprect == NULL) || (lppop == NULL)) return;
363 if (lppop->nItems == 0) return;
364 dprintf_menucalc(stddeb,"MenuBarCalcSize left=%d top=%d right=%d bottom=%d !\n",
365 lprect->left, lprect->top, lprect->right, lprect->bottom);
366 items = (MENUITEM *)USER_HEAP_LIN_ADDR( lppop->hItems );
367 lppop->Width = lprect->right - lprect->left;
368 lppop->Height = 0;
369 maxY = lprect->top;
370 start = 0;
371 helpPos = -1;
372 while (start < lppop->nItems)
374 lpitem = &items[start];
375 orgX = lprect->left;
376 orgY = maxY;
378 /* Parse items until line break or end of menu */
379 for (i = start; i < lppop->nItems; i++, lpitem++)
381 if ((helpPos == -1) && (lpitem->item_flags & MF_HELP)) helpPos = i;
382 if ((i != start) &&
383 (lpitem->item_flags & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
384 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE );
385 if (lpitem->rect.right > lprect->right)
387 if (i != start) break;
388 else lpitem->rect.right = lprect->right;
390 maxY = max( maxY, lpitem->rect.bottom );
391 orgX = lpitem->rect.right;
394 /* Finish the line (set all items to the largest height found) */
395 while (start < i) items[start++].rect.bottom = maxY;
398 lprect->bottom = maxY;
399 lppop->Height = lprect->bottom - lprect->top;
401 /* Flush right all items between the MF_HELP and the last item */
402 /* (if several lines, only move the last line) */
403 if (helpPos != -1)
405 lpitem = &items[lppop->nItems-1];
406 orgY = lpitem->rect.top;
407 orgX = lprect->right;
408 for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--)
410 if (lpitem->rect.top != orgY) break; /* Other line */
411 if (lpitem->rect.right >= orgX) break; /* Too far right already */
412 lpitem->rect.left += orgX - lpitem->rect.right;
413 lpitem->rect.right = orgX;
414 orgX = lpitem->rect.left;
420 /***********************************************************************
421 * MENU_DrawMenuItem
423 * Draw a single menu item.
425 static void MENU_DrawMenuItem( HDC hdc, LPMENUITEM lpitem,
426 WORD height, BOOL menuBar )
428 RECT rect;
430 if (menuBar && (lpitem->item_flags & MF_SEPARATOR)) return;
431 rect = lpitem->rect;
433 /* Draw the background */
435 if (lpitem->item_flags & MF_HILITE)
436 FillRect( hdc, &rect, sysColorObjects.hbrushHighlight );
437 else FillRect( hdc, &rect, sysColorObjects.hbrushMenu );
438 SetBkMode( hdc, TRANSPARENT );
440 /* Draw the separator bar (if any) */
442 if (!menuBar && (lpitem->item_flags & MF_MENUBARBREAK))
444 SelectObject( hdc, sysColorObjects.hpenWindowFrame );
445 MoveTo( hdc, rect.left, 0 );
446 LineTo( hdc, rect.left, height );
448 if (lpitem->item_flags & MF_SEPARATOR)
450 SelectObject( hdc, sysColorObjects.hpenWindowFrame );
451 MoveTo( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2 );
452 LineTo( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 );
453 return;
456 /* Setup colors */
458 if (lpitem->item_flags & MF_HILITE)
460 if (lpitem->item_flags & MF_GRAYED)
461 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
462 else
463 SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
464 SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
466 else
468 if (lpitem->item_flags & MF_GRAYED)
469 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
470 else
471 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
472 SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
475 if (!menuBar)
477 /* Draw the check mark */
479 if (lpitem->item_flags & MF_CHECKED)
481 GRAPH_DrawBitmap(hdc, lpitem->hCheckBit ? lpitem->hCheckBit :
482 hStdCheck, rect.left,
483 (rect.top+rect.bottom-check_bitmap_height) / 2,
484 0, 0, check_bitmap_width, check_bitmap_height );
486 else if (lpitem->hUnCheckBit != 0) /* Not checked */
488 GRAPH_DrawBitmap(hdc, lpitem->hUnCheckBit, rect.left,
489 (rect.top+rect.bottom-check_bitmap_height) / 2,
490 0, 0, check_bitmap_width, check_bitmap_height );
493 /* Draw the popup-menu arrow */
495 if (lpitem->item_flags & MF_POPUP)
497 GRAPH_DrawBitmap( hdc, hStdMnArrow,
498 rect.right-arrow_bitmap_width-1,
499 (rect.top+rect.bottom-arrow_bitmap_height) / 2,
500 0, 0, arrow_bitmap_width, arrow_bitmap_height );
503 rect.left += check_bitmap_width;
504 rect.right -= arrow_bitmap_width;
507 /* Draw the item text or bitmap */
509 if (lpitem->item_flags & MF_BITMAP)
511 GRAPH_DrawBitmap( hdc, (HBITMAP)lpitem->hText, rect.left, rect.top,
512 0, 0, rect.right-rect.left, rect.bottom-rect.top );
513 return;
515 /* No bitmap - process text if present */
516 else if ((lpitem->item_text) != ((char *) NULL))
518 register int i;
520 if (menuBar)
522 rect.left += MENU_BAR_ITEMS_SPACE / 2;
523 rect.right -= MENU_BAR_ITEMS_SPACE / 2;
524 i = strlen( lpitem->item_text );
526 else
528 for (i = 0; lpitem->item_text[i]; i++)
529 if ((lpitem->item_text[i] == '\t') ||
530 (lpitem->item_text[i] == '\b')) break;
533 DrawText( hdc, lpitem->item_text, i, &rect,
534 DT_LEFT | DT_VCENTER | DT_SINGLELINE );
536 if (lpitem->item_text[i]) /* There's a tab or flush-right char */
538 if (lpitem->item_text[i] == '\t')
540 rect.left = lpitem->xTab;
541 DrawText( hdc, lpitem->item_text + i + 1, -1, &rect,
542 DT_LEFT | DT_VCENTER | DT_SINGLELINE );
544 else DrawText( hdc, lpitem->item_text + i + 1, -1, &rect,
545 DT_RIGHT | DT_VCENTER | DT_SINGLELINE );
551 /***********************************************************************
552 * MENU_DrawPopupMenu
554 * Paint a popup menu.
556 static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
558 POPUPMENU *menu;
559 MENUITEM *item;
560 RECT rect;
561 int i;
563 GetClientRect( hwnd, &rect );
564 FillRect( hdc, &rect, sysColorObjects.hbrushMenu );
565 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
566 if (!menu || !menu->nItems) return;
567 item = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
568 for (i = menu->nItems; i > 0; i--, item++)
569 MENU_DrawMenuItem( hdc, item, menu->Height, FALSE );
573 /***********************************************************************
574 * MENU_DrawMenuBar
576 * Paint a menu bar. Returns the height of the menu bar.
578 WORD MENU_DrawMenuBar(HDC hDC, LPRECT lprect, HWND hwnd, BOOL suppress_draw)
580 LPPOPUPMENU lppop;
581 LPMENUITEM lpitem;
582 int i;
583 WND *wndPtr = WIN_FindWndPtr( hwnd );
585 lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR( wndPtr->wIDmenu );
586 if (lppop == NULL || lprect == NULL) return SYSMETRICS_CYMENU;
587 dprintf_menu(stddeb,"MENU_DrawMenuBar(%04X, %p, %p); !\n",
588 hDC, lprect, lppop);
589 if (lppop->Height == 0) MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
590 lprect->bottom = lprect->top + lppop->Height;
591 if (suppress_draw) return lppop->Height;
593 FillRect(hDC, lprect, sysColorObjects.hbrushMenu );
594 SelectObject( hDC, sysColorObjects.hpenWindowFrame );
595 MoveTo( hDC, lprect->left, lprect->bottom );
596 LineTo( hDC, lprect->right, lprect->bottom );
598 if (lppop->nItems == 0) return SYSMETRICS_CYMENU;
599 lpitem = (MENUITEM *) USER_HEAP_LIN_ADDR( lppop->hItems );
600 for (i = 0; i < lppop->nItems; i++, lpitem++)
602 MENU_DrawMenuItem( hDC, lpitem, lppop->Height, TRUE );
604 return lppop->Height;
608 /***********************************************************************
609 * MENU_ShowPopup
611 * Display a popup menu.
613 static BOOL MENU_ShowPopup(HWND hwndOwner, HMENU hmenu, WORD id, int x, int y)
615 POPUPMENU *menu;
617 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
618 if (menu->FocusedItem != NO_SELECTED_ITEM)
620 MENUITEM *item = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
621 item[menu->FocusedItem].item_flags &= ~(MF_HILITE | MF_MOUSESELECT);
622 menu->FocusedItem = NO_SELECTED_ITEM;
624 SendMessage( hwndOwner, WM_INITMENUPOPUP, hmenu,
625 MAKELONG( id, (menu->wFlags & MF_POPUP) ? 1 : 0 ));
626 MENU_PopupMenuCalcSize( menu, hwndOwner );
627 if (!menu->hWnd)
629 WND *wndPtr = WIN_FindWndPtr( hwndOwner );
630 if (!wndPtr) return FALSE;
631 menu->hWnd = CreateWindow( POPUPMENU_CLASS_NAME, "",
632 WS_POPUP | WS_BORDER, x, y,
633 menu->Width + 2*SYSMETRICS_CXBORDER,
634 menu->Height + 2*SYSMETRICS_CYBORDER,
635 0, 0, wndPtr->hInstance, (SEGPTR)hmenu );
636 if (!menu->hWnd) return FALSE;
638 else SetWindowPos( menu->hWnd, 0, x, y,
639 menu->Width + 2*SYSMETRICS_CXBORDER,
640 menu->Height + 2*SYSMETRICS_CYBORDER,
641 SWP_NOACTIVATE | SWP_NOZORDER );
643 /* Display the window */
645 SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
646 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
647 UpdateWindow( menu->hWnd );
648 return TRUE;
652 /***********************************************************************
653 * MENU_SelectItem
655 static void MENU_SelectItem( HMENU hmenu, WORD wIndex )
657 MENUITEM *items;
658 LPPOPUPMENU lppop;
659 HDC hdc;
661 lppop = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
662 if (!lppop->nItems) return;
663 items = (MENUITEM *) USER_HEAP_LIN_ADDR( lppop->hItems );
664 if ((wIndex != NO_SELECTED_ITEM) &&
665 (wIndex != SYSMENU_SELECTED) &&
666 (items[wIndex].item_flags & MF_SEPARATOR))
667 wIndex = NO_SELECTED_ITEM;
668 if (lppop->FocusedItem == wIndex) return;
669 if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
670 else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
672 /* Clear previous highlighted item */
673 if (lppop->FocusedItem != NO_SELECTED_ITEM)
675 if (lppop->FocusedItem == SYSMENU_SELECTED)
676 NC_DrawSysButton( lppop->hWnd, hdc, FALSE );
677 else
679 items[lppop->FocusedItem].item_flags &=~(MF_HILITE|MF_MOUSESELECT);
680 MENU_DrawMenuItem( hdc, &items[lppop->FocusedItem], lppop->Height,
681 !(lppop->wFlags & MF_POPUP) );
685 /* Highlight new item (if any) */
686 lppop->FocusedItem = wIndex;
687 if (lppop->FocusedItem != NO_SELECTED_ITEM)
689 if (lppop->FocusedItem == SYSMENU_SELECTED)
690 NC_DrawSysButton( lppop->hWnd, hdc, TRUE );
691 else
693 items[lppop->FocusedItem].item_flags |= MF_HILITE;
694 MENU_DrawMenuItem( hdc, &items[lppop->FocusedItem], lppop->Height,
695 !(lppop->wFlags & MF_POPUP) );
696 SendMessage(lppop->hWnd, WM_MENUSELECT,
697 items[lppop->FocusedItem].item_id,
698 MAKELONG( hmenu, items[lppop->FocusedItem].item_flags));
701 ReleaseDC( lppop->hWnd, hdc );
705 /***********************************************************************
706 * MENU_SelectNextItem
708 static void MENU_SelectNextItem( HMENU hmenu )
710 int i;
711 MENUITEM *items;
712 POPUPMENU *menu;
714 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
715 if (!menu->nItems) return;
716 items = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
717 if ((menu->FocusedItem != NO_SELECTED_ITEM) &&
718 (menu->FocusedItem != SYSMENU_SELECTED))
720 for (i = menu->FocusedItem+1; i < menu->nItems; i++)
722 if (!(items[i].item_flags & MF_SEPARATOR))
724 MENU_SelectItem( hmenu, i );
725 return;
728 if (MENU_HasSysMenu( menu ))
730 MENU_SelectItem( hmenu, SYSMENU_SELECTED );
731 return;
734 for (i = 0; i < menu->nItems; i++)
736 if (!(items[i].item_flags & MF_SEPARATOR))
738 MENU_SelectItem( hmenu, i );
739 return;
742 if (MENU_HasSysMenu( menu )) MENU_SelectItem( hmenu, SYSMENU_SELECTED );
746 /***********************************************************************
747 * MENU_SelectPrevItem
749 static void MENU_SelectPrevItem( HMENU hmenu )
751 int i;
752 MENUITEM *items;
753 POPUPMENU *menu;
755 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
756 if (!menu->nItems) return;
757 items = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
758 if ((menu->FocusedItem != NO_SELECTED_ITEM) &&
759 (menu->FocusedItem != SYSMENU_SELECTED))
761 for (i = menu->FocusedItem - 1; i >= 0; i--)
763 if (!(items[i].item_flags & MF_SEPARATOR))
765 MENU_SelectItem( hmenu, i );
766 return;
769 if (MENU_HasSysMenu( menu ))
771 MENU_SelectItem( hmenu, SYSMENU_SELECTED );
772 return;
775 for (i = menu->nItems - 1; i > 0; i--)
777 if (!(items[i].item_flags & MF_SEPARATOR))
779 MENU_SelectItem( hmenu, i );
780 return;
783 if (MENU_HasSysMenu( menu )) MENU_SelectItem( hmenu, SYSMENU_SELECTED );
787 /***********************************************************************
788 * MENU_GetSubPopup
790 * Return the handle of the selected sub-popup menu (if any).
792 static HMENU MENU_GetSubPopup( HMENU hmenu )
794 POPUPMENU *menu;
795 MENUITEM *item;
797 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
798 if (menu->FocusedItem == NO_SELECTED_ITEM) return 0;
799 else if (menu->FocusedItem == SYSMENU_SELECTED)
800 return GetSystemMenu( menu->hWnd, FALSE );
802 item = ((MENUITEM *)USER_HEAP_LIN_ADDR(menu->hItems)) + menu->FocusedItem;
803 if (!(item->item_flags & MF_POPUP) || !(item->item_flags & MF_MOUSESELECT))
804 return 0;
805 return item->item_id;
809 /***********************************************************************
810 * MENU_HideSubPopups
812 * Hide the sub-popup menus of this menu.
814 static void MENU_HideSubPopups( HMENU hmenu )
816 MENUITEM *item;
817 POPUPMENU *menu, *submenu;
818 HMENU hsubmenu;
820 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return;
821 if (menu->FocusedItem == NO_SELECTED_ITEM) return;
822 if (menu->FocusedItem == SYSMENU_SELECTED)
824 hsubmenu = GetSystemMenu( menu->hWnd, FALSE );
826 else
828 item = ((MENUITEM *)USER_HEAP_LIN_ADDR(menu->hItems)) + menu->FocusedItem;
829 if (!(item->item_flags & MF_POPUP) ||
830 !(item->item_flags & MF_MOUSESELECT)) return;
831 item->item_flags &= ~MF_MOUSESELECT;
832 hsubmenu = item->item_id;
834 submenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hsubmenu );
835 MENU_HideSubPopups( hsubmenu );
836 if (submenu->hWnd) ShowWindow( submenu->hWnd, SW_HIDE );
837 MENU_SelectItem( hsubmenu, NO_SELECTED_ITEM );
841 /***********************************************************************
842 * MENU_ShowSubPopup
844 * Display the sub-menu of the selected item of this menu.
845 * Return the handle of the submenu, or hmenu if no submenu to display.
847 static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu, BOOL selectFirst )
849 POPUPMENU *menu;
850 MENUITEM *item;
851 WND *wndPtr;
853 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return hmenu;
854 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return hmenu;
855 if (menu->FocusedItem == NO_SELECTED_ITEM) return hmenu;
856 if (menu->FocusedItem == SYSMENU_SELECTED)
858 MENU_ShowPopup(hwndOwner, wndPtr->hSysMenu, 0, wndPtr->rectClient.left,
859 wndPtr->rectClient.top - menu->Height - 2*SYSMETRICS_CYBORDER);
860 if (selectFirst) MENU_SelectNextItem( wndPtr->hSysMenu );
861 return wndPtr->hSysMenu;
863 item = ((MENUITEM *)USER_HEAP_LIN_ADDR(menu->hItems)) + menu->FocusedItem;
864 if (!(item->item_flags & MF_POPUP) ||
865 (item->item_flags & (MF_GRAYED | MF_DISABLED))) return hmenu;
866 item->item_flags |= MF_MOUSESELECT;
867 if (menu->wFlags & MF_POPUP)
869 MENU_ShowPopup( hwndOwner, (HMENU)item->item_id, menu->FocusedItem,
870 wndPtr->rectWindow.left + item->rect.right-arrow_bitmap_width,
871 wndPtr->rectWindow.top + item->rect.top );
873 else
875 MENU_ShowPopup( hwndOwner, (HMENU)item->item_id, menu->FocusedItem,
876 wndPtr->rectWindow.left + item->rect.left,
877 wndPtr->rectWindow.top + item->rect.bottom );
879 if (selectFirst) MENU_SelectNextItem( (HMENU)item->item_id );
880 return (HMENU)item->item_id;
884 /***********************************************************************
885 * MENU_FindMenuByCoords
887 * Find the menu containing a given point (in screen coords).
889 static HMENU MENU_FindMenuByCoords( HMENU hmenu, POINT pt )
891 POPUPMENU *menu;
892 HWND hwnd;
894 if (!(hwnd = WindowFromPoint( pt ))) return 0;
895 while (hmenu)
897 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
898 if (menu->hWnd == hwnd)
900 if (!(menu->wFlags & MF_POPUP))
902 /* Make sure it's in the menu bar (or in system menu) */
903 WND *wndPtr = WIN_FindWndPtr( menu->hWnd );
904 if ((pt.x < wndPtr->rectClient.left) ||
905 (pt.x >= wndPtr->rectClient.right) ||
906 (pt.y >= wndPtr->rectClient.top)) return 0;
907 if (pt.y < wndPtr->rectClient.top - menu->Height)
909 if (!MENU_IsInSysMenu( menu, pt )) return 0;
911 /* else it's in the menu bar */
913 return hmenu;
915 hmenu = MENU_GetSubPopup( hmenu );
917 return 0;
921 /***********************************************************************
922 * MENU_ExecFocusedItem
924 * Execute a menu item (for instance when user pressed Enter).
925 * Return TRUE if we can go on with menu tracking.
927 static BOOL MENU_ExecFocusedItem( HWND hwndOwner, HMENU hmenu,
928 HMENU *hmenuCurrent )
930 MENUITEM *item;
931 POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
932 if (!menu || !menu->nItems || (menu->FocusedItem == NO_SELECTED_ITEM) ||
933 (menu->FocusedItem == SYSMENU_SELECTED)) return TRUE;
934 item = ((MENUITEM *)USER_HEAP_LIN_ADDR(menu->hItems)) + menu->FocusedItem;
935 if (!(item->item_flags & MF_POPUP))
937 if (!(item->item_flags & (MF_GRAYED | MF_DISABLED)))
939 PostMessage( hwndOwner, (menu->wFlags & MF_SYSMENU) ?
940 WM_SYSCOMMAND : WM_COMMAND, item->item_id, 0 );
941 return FALSE;
943 else return TRUE;
945 else
947 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, TRUE );
948 return TRUE;
953 /***********************************************************************
954 * MENU_ButtonDown
956 * Handle a button-down event in a menu. Point is in screen coords.
957 * hmenuCurrent is the top-most visible popup.
958 * Return TRUE if we can go on with menu tracking.
960 static BOOL MENU_ButtonDown( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent,
961 POINT pt )
963 POPUPMENU *menu;
964 MENUITEM *item;
965 WORD id;
967 if (!hmenu) return FALSE; /* Outside all menus */
968 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
969 item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
970 if (!item) /* Maybe in system menu */
972 if (!MENU_IsInSysMenu( menu, pt )) return FALSE;
973 id = SYSMENU_SELECTED;
976 if (menu->FocusedItem == id)
978 if (id == SYSMENU_SELECTED) return FALSE;
979 if (item->item_flags & MF_POPUP)
981 if (item->item_flags & MF_MOUSESELECT)
983 if (menu->wFlags & MF_POPUP)
985 MENU_HideSubPopups( hmenu );
986 *hmenuCurrent = hmenu;
988 else return FALSE;
990 else *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
993 else
995 MENU_HideSubPopups( hmenu );
996 MENU_SelectItem( hmenu, id );
997 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
999 return TRUE;
1003 /***********************************************************************
1004 * MENU_ButtonUp
1006 * Handle a button-up event in a menu. Point is in screen coords.
1007 * hmenuCurrent is the top-most visible popup.
1008 * Return TRUE if we can go on with menu tracking.
1010 static BOOL MENU_ButtonUp( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent,
1011 POINT pt )
1013 POPUPMENU *menu;
1014 MENUITEM *item;
1015 HMENU hsubmenu = 0;
1016 WORD id;
1018 if (!hmenu) return FALSE; /* Outside all menus */
1019 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1020 item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
1021 if (!item) /* Maybe in system menu */
1023 if (!MENU_IsInSysMenu( menu, pt )) return FALSE;
1024 id = SYSMENU_SELECTED;
1025 hsubmenu = GetSystemMenu( menu->hWnd, FALSE );
1028 if (menu->FocusedItem != id) return FALSE;
1030 if (id != SYSMENU_SELECTED)
1032 if (!(item->item_flags & MF_POPUP))
1034 return MENU_ExecFocusedItem( hwndOwner, hmenu, hmenuCurrent );
1036 hsubmenu = item->item_id;
1038 /* Select first item of sub-popup */
1039 MENU_SelectItem( hsubmenu, NO_SELECTED_ITEM );
1040 MENU_SelectNextItem( hsubmenu );
1041 return TRUE;
1045 /***********************************************************************
1046 * MENU_MouseMove
1048 * Handle a motion event in a menu. Point is in screen coords.
1049 * hmenuCurrent is the top-most visible popup.
1050 * Return TRUE if we can go on with menu tracking.
1052 static BOOL MENU_MouseMove( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent,
1053 POINT pt )
1055 MENUITEM *item;
1056 POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1057 WORD id = NO_SELECTED_ITEM;
1059 if (hmenu)
1061 item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
1062 if (!item) /* Maybe in system menu */
1064 if (!MENU_IsInSysMenu( menu, pt ))
1065 id = NO_SELECTED_ITEM; /* Outside all items */
1066 else id = SYSMENU_SELECTED;
1069 if (id == NO_SELECTED_ITEM)
1071 MENU_SelectItem( *hmenuCurrent, NO_SELECTED_ITEM );
1073 else if (menu->FocusedItem != id)
1075 MENU_HideSubPopups( hmenu );
1076 MENU_SelectItem( hmenu, id );
1077 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
1079 return TRUE;
1083 /***********************************************************************
1084 * MENU_KeyLeft
1086 * Handle a VK_LEFT key event in a menu.
1087 * hmenuCurrent is the top-most visible popup.
1089 static void MENU_KeyLeft( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent )
1091 POPUPMENU *menu;
1092 HMENU hmenutmp, hmenuprev;
1094 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1095 hmenuprev = hmenutmp = hmenu;
1096 while (hmenutmp != *hmenuCurrent)
1098 hmenutmp = MENU_GetSubPopup( hmenuprev );
1099 if (hmenutmp != *hmenuCurrent) hmenuprev = hmenutmp;
1101 MENU_HideSubPopups( hmenuprev );
1103 if ((hmenuprev == hmenu) && !(menu->wFlags & MF_POPUP))
1105 /* Select previous item on the menu bar */
1106 MENU_SelectPrevItem( hmenu );
1107 if (*hmenuCurrent != hmenu)
1109 /* A popup menu was displayed -> display the next one */
1110 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, TRUE );
1113 else *hmenuCurrent = hmenuprev;
1117 /***********************************************************************
1118 * MENU_KeyRight
1120 * Handle a VK_RIGHT key event in a menu.
1121 * hmenuCurrent is the top-most visible popup.
1123 static void MENU_KeyRight( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent )
1125 POPUPMENU *menu;
1126 HMENU hmenutmp;
1128 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1130 if ((menu->wFlags & MF_POPUP) || (*hmenuCurrent != hmenu))
1132 /* If already displaying a popup, try to display sub-popup */
1133 hmenutmp = MENU_ShowSubPopup( hwndOwner, *hmenuCurrent, TRUE );
1134 if (hmenutmp != *hmenuCurrent) /* Sub-popup displayed */
1136 *hmenuCurrent = hmenutmp;
1137 return;
1141 /* If on menu-bar, go to next item */
1142 if (!(menu->wFlags & MF_POPUP))
1144 MENU_HideSubPopups( hmenu );
1145 MENU_SelectNextItem( hmenu );
1146 if (*hmenuCurrent != hmenu)
1148 /* A popup menu was displayed -> display the next one */
1149 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, TRUE );
1152 else if (*hmenuCurrent != hmenu) /* Hide last level popup */
1154 HMENU hmenuprev;
1155 hmenuprev = hmenutmp = hmenu;
1156 while (hmenutmp != *hmenuCurrent)
1158 hmenutmp = MENU_GetSubPopup( hmenuprev );
1159 if (hmenutmp != *hmenuCurrent) hmenuprev = hmenutmp;
1161 MENU_HideSubPopups( hmenuprev );
1162 *hmenuCurrent = hmenuprev;
1167 /***********************************************************************
1168 * MENU_TrackMenu
1170 * Menu tracking code.
1171 * If 'x' and 'y' are not 0, we simulate a button-down event at (x,y)
1172 * before beginning tracking. This is to help menu-bar tracking.
1174 static BOOL MENU_TrackMenu( HMENU hmenu, WORD wFlags, int x, int y,
1175 HWND hwnd, LPRECT lprect )
1177 MSG *msg;
1178 HLOCAL hMsg;
1179 POPUPMENU *menu;
1180 HMENU hmenuCurrent = hmenu;
1181 BOOL fClosed = FALSE, fRemove;
1182 WORD pos;
1184 fEndMenuCalled = FALSE;
1185 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
1186 if (x && y)
1188 POINT pt = { x, y };
1189 MENU_ButtonDown( hwnd, hmenu, &hmenuCurrent, pt );
1191 SetCapture( hwnd );
1192 hMsg = USER_HEAP_ALLOC( sizeof(MSG) );
1193 msg = (MSG *)USER_HEAP_LIN_ADDR( hMsg );
1194 while (!fClosed)
1196 if (!MSG_InternalGetMessage( USER_HEAP_SEG_ADDR(hMsg), 0,
1197 hwnd, MSGF_MENU, 0, TRUE ))
1198 break;
1200 fRemove = FALSE;
1201 if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
1203 /* Find the sub-popup for this mouse event (if any) */
1204 HMENU hsubmenu = MENU_FindMenuByCoords( hmenu, msg->pt );
1206 switch(msg->message)
1208 case WM_RBUTTONDOWN:
1209 case WM_NCRBUTTONDOWN:
1210 if (!(wFlags & TPM_RIGHTBUTTON)) break;
1211 /* fall through */
1212 case WM_LBUTTONDOWN:
1213 case WM_NCLBUTTONDOWN:
1214 fClosed = !MENU_ButtonDown( hwnd, hsubmenu,
1215 &hmenuCurrent, msg->pt );
1216 break;
1218 case WM_RBUTTONUP:
1219 case WM_NCRBUTTONUP:
1220 if (!(wFlags & TPM_RIGHTBUTTON)) break;
1221 /* fall through */
1222 case WM_LBUTTONUP:
1223 case WM_NCLBUTTONUP:
1224 /* If outside all menus but inside lprect, ignore it */
1225 if (!hsubmenu && lprect && PtInRect( lprect, msg->pt )) break;
1226 fClosed = !MENU_ButtonUp( hwnd, hsubmenu,
1227 &hmenuCurrent, msg->pt );
1228 fRemove = TRUE; /* Remove event even if outside menu */
1229 break;
1231 case WM_MOUSEMOVE:
1232 case WM_NCMOUSEMOVE:
1233 if ((msg->wParam & MK_LBUTTON) ||
1234 ((wFlags & TPM_RIGHTBUTTON) && (msg->wParam & MK_RBUTTON)))
1236 fClosed = !MENU_MouseMove( hwnd, hsubmenu,
1237 &hmenuCurrent, msg->pt );
1239 break;
1242 else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
1244 fRemove = TRUE; /* Keyboard messages are always removed */
1245 switch(msg->message)
1247 case WM_KEYDOWN:
1248 switch(msg->wParam)
1250 case VK_HOME:
1251 MENU_SelectItem( hmenuCurrent, NO_SELECTED_ITEM );
1252 MENU_SelectNextItem( hmenuCurrent );
1253 break;
1255 case VK_END:
1256 MENU_SelectItem( hmenuCurrent, NO_SELECTED_ITEM );
1257 MENU_SelectPrevItem( hmenuCurrent );
1258 break;
1260 case VK_UP:
1261 MENU_SelectPrevItem( hmenuCurrent );
1262 break;
1264 case VK_DOWN:
1265 /* If on menu bar, pull-down the menu */
1266 if (!(menu->wFlags & MF_POPUP) && (hmenuCurrent == hmenu))
1267 hmenuCurrent = MENU_ShowSubPopup( hwnd, hmenu, TRUE );
1268 else
1269 MENU_SelectNextItem( hmenuCurrent );
1270 break;
1272 case VK_LEFT:
1273 MENU_KeyLeft( hwnd, hmenu, &hmenuCurrent );
1274 break;
1276 case VK_RIGHT:
1277 MENU_KeyRight( hwnd, hmenu, &hmenuCurrent );
1278 break;
1280 case VK_SPACE:
1281 case VK_RETURN:
1282 fClosed = !MENU_ExecFocusedItem( hwnd, hmenuCurrent,
1283 &hmenuCurrent );
1284 break;
1286 case VK_ESCAPE:
1287 fClosed = TRUE;
1288 break;
1290 default:
1291 break;
1293 break; /* WM_KEYDOWN */
1295 case WM_SYSKEYDOWN:
1296 switch(msg->wParam)
1298 case VK_MENU:
1299 fClosed = TRUE;
1300 break;
1303 break; /* WM_SYSKEYDOWN */
1305 case WM_CHAR:
1307 /* Hack to avoid control chars. */
1308 /* We will find a better way real soon... */
1309 if ((msg->wParam <= 32) || (msg->wParam >= 127)) break;
1310 pos = MENU_FindItemByKey( hwnd, hmenuCurrent, msg->wParam );
1311 if (pos == (WORD)-2) fClosed = TRUE;
1312 else if (pos == (WORD)-1) MessageBeep(0);
1313 else
1315 MENU_SelectItem( hmenuCurrent, pos );
1316 fClosed = !MENU_ExecFocusedItem( hwnd, hmenuCurrent,
1317 &hmenuCurrent );
1321 break; /* WM_CHAR */
1322 } /* switch(msg->message) */
1324 else
1326 DispatchMessage( msg );
1328 if (fEndMenuCalled) fClosed = TRUE;
1329 if (!fClosed) fRemove = TRUE;
1331 if (fRemove) /* Remove the message from the queue */
1332 PeekMessage( msg, 0, msg->message, msg->message, PM_REMOVE );
1334 USER_HEAP_FREE( hMsg );
1335 ReleaseCapture();
1336 MENU_HideSubPopups( hmenu );
1337 if (menu->wFlags & MF_POPUP) ShowWindow( menu->hWnd, SW_HIDE );
1338 MENU_SelectItem( hmenu, NO_SELECTED_ITEM );
1339 fEndMenuCalled = FALSE;
1340 return TRUE;
1344 /***********************************************************************
1345 * MENU_TrackMouseMenuBar
1347 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
1349 void MENU_TrackMouseMenuBar( HWND hwnd, POINT pt )
1351 WND *wndPtr = WIN_FindWndPtr( hwnd );
1352 SendMessage( hwnd, WM_ENTERMENULOOP, 0, 0 );
1353 MENU_TrackMenu( (HMENU)wndPtr->wIDmenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
1354 pt.x, pt.y, hwnd, NULL );
1355 SendMessage( hwnd, WM_EXITMENULOOP, 0, 0 );
1359 /***********************************************************************
1360 * MENU_TrackKbdMenuBar
1362 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
1364 void MENU_TrackKbdMenuBar( HWND hwnd, WORD wParam )
1366 WND *wndPtr = WIN_FindWndPtr( hwnd );
1367 if (!wndPtr->wIDmenu) return;
1368 SendMessage( hwnd, WM_ENTERMENULOOP, 0, 0 );
1369 /* Select first selectable item */
1370 MENU_SelectItem( wndPtr->wIDmenu, NO_SELECTED_ITEM );
1371 MENU_SelectNextItem( (HMENU)wndPtr->wIDmenu );
1372 MENU_TrackMenu( (HMENU)wndPtr->wIDmenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
1373 0, 0, hwnd, NULL );
1374 SendMessage( hwnd, WM_EXITMENULOOP, 0, 0 );
1378 /**********************************************************************
1379 * TrackPopupMenu [USER.416]
1381 BOOL TrackPopupMenu( HMENU hMenu, WORD wFlags, short x, short y,
1382 short nReserved, HWND hWnd, LPRECT lpRect )
1384 if (!MENU_ShowPopup( hWnd, hMenu, 0, x, y )) return FALSE;
1385 return MENU_TrackMenu( hMenu, wFlags, 0, 0, hWnd, lpRect );
1389 /***********************************************************************
1390 * PopupMenuWndProc
1392 LONG PopupMenuWndProc( HWND hwnd, WORD message, WORD wParam, LONG lParam )
1394 switch(message)
1396 case WM_CREATE:
1398 CREATESTRUCT *createStruct = (CREATESTRUCT*)PTR_SEG_TO_LIN(lParam);
1399 HMENU hmenu = (HMENU) ((int)createStruct->lpCreateParams & 0xffff);
1400 SetWindowWord( hwnd, 0, hmenu );
1401 return 0;
1404 case WM_MOUSEACTIVATE: /* We don't want to be activated */
1405 return MA_NOACTIVATE;
1407 case WM_PAINT:
1409 PAINTSTRUCT ps;
1410 BeginPaint( hwnd, &ps );
1411 MENU_DrawPopupMenu( hwnd, ps.hdc,
1412 (HMENU)GetWindowWord( hwnd, 0 ) );
1413 EndPaint( hwnd, &ps );
1414 return 0;
1417 default:
1418 return DefWindowProc(hwnd, message, wParam, lParam);
1420 return 0;
1424 /***********************************************************************
1425 * MENU_GetMenuBarHeight
1427 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
1429 WORD MENU_GetMenuBarHeight( HWND hwnd, WORD menubarWidth, int orgX, int orgY )
1431 HDC hdc;
1432 RECT rectBar;
1433 WND *wndPtr;
1434 LPPOPUPMENU lppop;
1436 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
1437 if (!(lppop = (LPPOPUPMENU)USER_HEAP_LIN_ADDR(wndPtr->wIDmenu))) return 0;
1438 hdc = GetDC( hwnd );
1439 SetRect( &rectBar, orgX, orgY, orgX+menubarWidth, orgY+SYSMETRICS_CYMENU );
1440 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
1441 ReleaseDC( hwnd, hdc );
1442 return lppop->Height;
1446 /**********************************************************************
1447 * ChangeMenu [USER.153]
1449 BOOL ChangeMenu(HMENU hMenu, WORD nPos, LPSTR lpNewItem,
1450 WORD wItemID, WORD wFlags)
1452 dprintf_menu(stddeb,"ChangeMenu(%04X, %X, '%s', %X, %X)\n",
1453 hMenu, nPos, lpNewItem, wItemID, wFlags);
1454 if (wFlags & MF_APPEND)
1455 return AppendMenu(hMenu, wFlags, wItemID, lpNewItem);
1456 if (wFlags & MF_DELETE)
1457 return DeleteMenu(hMenu, wItemID, wFlags);
1458 if (wFlags & MF_CHANGE)
1459 return ModifyMenu(hMenu, nPos, wFlags, wItemID, lpNewItem);
1460 if (wFlags & MF_REMOVE)
1461 return RemoveMenu(hMenu, wItemID, wFlags);
1462 /* Default: MF_INSERT */
1463 return InsertMenu(hMenu, nPos, wFlags, wItemID, lpNewItem);
1467 /**********************************************************************
1468 * CheckMenuItem [USER.154]
1470 BOOL CheckMenuItem(HMENU hMenu, WORD wItemID, WORD wFlags)
1472 LPMENUITEM lpitem;
1473 dprintf_menu(stddeb,"CheckMenuItem (%04X, %04X, %04X) !\n",
1474 hMenu, wItemID, wFlags);
1475 if (!(lpitem = MENU_FindItem(&hMenu, &wItemID, wFlags))) return FALSE;
1476 if (wFlags & MF_CHECKED) lpitem->item_flags |= MF_CHECKED;
1477 else lpitem->item_flags &= ~MF_CHECKED;
1478 return TRUE;
1482 /**********************************************************************
1483 * EnableMenuItem [USER.155]
1485 BOOL EnableMenuItem(HMENU hMenu, WORD wItemID, WORD wFlags)
1487 LPMENUITEM lpitem;
1488 dprintf_menu(stddeb,"EnableMenuItem (%04X, %04X, %04X) !\n",
1489 hMenu, wItemID, wFlags);
1490 if (!(lpitem = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return FALSE;
1492 /* We can't have MF_GRAYED and MF_DISABLED together */
1493 if (wFlags & MF_GRAYED)
1495 lpitem->item_flags = (lpitem->item_flags & ~MF_DISABLED) | MF_GRAYED;
1497 else if (wFlags & MF_DISABLED)
1499 lpitem->item_flags = (lpitem->item_flags & ~MF_GRAYED) | MF_DISABLED;
1501 else /* MF_ENABLED */
1503 lpitem->item_flags &= ~(MF_GRAYED | MF_DISABLED);
1505 return TRUE;
1509 /**********************************************************************
1510 * GetMenuString [USER.161]
1512 int GetMenuString(HMENU hMenu, WORD wItemID,
1513 LPSTR str, short nMaxSiz, WORD wFlags)
1515 LPMENUITEM lpitem;
1516 int maxsiz;
1517 dprintf_menu(stddeb,"GetMenuString(%04X, %04X, %p, %d, %04X);\n",
1518 hMenu, wItemID, str, nMaxSiz, wFlags);
1519 if (str == NULL) return FALSE;
1520 lpitem = MENU_FindItem( &hMenu, &wItemID, wFlags );
1521 if (lpitem != NULL) {
1522 if (lpitem->item_text != NULL) {
1523 maxsiz = min(nMaxSiz - 1, strlen(lpitem->item_text));
1524 strncpy(str, lpitem->item_text, maxsiz + 1);
1526 else
1527 maxsiz = 0;
1528 dprintf_menu(stddeb,"GetMenuString // Found !\n");
1529 return maxsiz;
1531 return 0;
1535 /**********************************************************************
1536 * HiliteMenuItem [USER.162]
1538 BOOL HiliteMenuItem(HWND hWnd, HMENU hMenu, WORD wItemID, WORD wHilite)
1540 LPPOPUPMENU menu;
1541 LPMENUITEM lpitem;
1542 dprintf_menu(stddeb,"HiliteMenuItem(%04X, %04X, %04X, %04X);\n",
1543 hWnd, hMenu, wItemID, wHilite);
1544 if (!(lpitem = MENU_FindItem( &hMenu, &wItemID, wHilite ))) return FALSE;
1545 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
1546 if (menu->FocusedItem == wItemID) return TRUE;
1547 MENU_HideSubPopups( hMenu );
1548 MENU_SelectItem( hMenu, wItemID );
1549 return TRUE;
1553 /**********************************************************************
1554 * GetMenuState [USER.250]
1556 WORD GetMenuState(HMENU hMenu, WORD wItemID, WORD wFlags)
1558 LPMENUITEM lpitem;
1559 dprintf_menu(stddeb,"GetMenuState(%04X, %04X, %04X);\n",
1560 hMenu, wItemID, wFlags);
1561 if (!(lpitem = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
1562 if (lpitem->item_flags & MF_POPUP)
1564 POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( lpitem->item_id );
1565 if (!menu) return -1;
1566 else return (menu->nItems << 8) | (menu->wFlags & 0xff);
1568 else return lpitem->item_flags;
1572 /**********************************************************************
1573 * GetMenuItemCount [USER.263]
1575 WORD GetMenuItemCount(HMENU hMenu)
1577 LPPOPUPMENU menu;
1578 dprintf_menu(stddeb,"GetMenuItemCount(%04X);\n", hMenu);
1579 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
1580 if (menu == NULL) return (WORD)-1;
1581 dprintf_menu(stddeb,"GetMenuItemCount(%04X) return %d \n",
1582 hMenu, menu->nItems);
1583 return menu->nItems;
1587 /**********************************************************************
1588 * GetMenuItemID [USER.264]
1590 WORD GetMenuItemID(HMENU hMenu, int nPos)
1592 LPPOPUPMENU menu;
1593 MENUITEM *item;
1595 dprintf_menu(stddeb,"GetMenuItemID(%04X, %d);\n", hMenu, nPos);
1596 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return -1;
1597 if ((nPos < 0) || (nPos >= menu->nItems)) return -1;
1598 item = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
1599 if (item[nPos].item_flags & MF_POPUP) return -1;
1600 return item[nPos].item_id;
1604 /**********************************************************************
1605 * InsertMenu [USER.410]
1607 BOOL InsertMenu(HMENU hMenu, WORD nPos, WORD wFlags, WORD wItemID, LPSTR lpNewItem)
1609 HANDLE hNewItems;
1610 MENUITEM *lpitem, *newItems;
1611 LPPOPUPMENU menu;
1613 if (IS_STRING_ITEM(wFlags))
1615 dprintf_menu(stddeb,"InsertMenu (%04X, %04X, %04X, %04X, '%s') !\n",
1616 hMenu, nPos, wFlags, wItemID, lpNewItem);
1618 else
1619 dprintf_menu(stddeb,"InsertMenu (%04X, %04X, %04X, %04X, %p) !\n",
1620 hMenu, nPos, wFlags, wItemID, lpNewItem);
1622 /* Find where to insert new item */
1624 if ((wFlags & MF_BYPOSITION) &&
1625 ((nPos == (WORD)-1) || (nPos == GetMenuItemCount(hMenu))))
1627 /* Special case: append to menu
1628 Some programs specify the menu length to do that */
1629 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu)))
1631 dprintf_menu(stddeb,"InsertMenu: %04X not a menu handle\n", hMenu);
1632 return FALSE;
1634 nPos = menu->nItems;
1636 else
1638 if (!MENU_FindItem( &hMenu, &nPos, wFlags ))
1640 dprintf_menu(stddeb,"InsertMenu: Item %X not found\n", nPos);
1641 return FALSE;
1643 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu)))
1645 dprintf_menu(stddeb,"InsertMenu: %04X not a menu handle\n", hMenu);
1646 return FALSE;
1650 /* Create new items array */
1652 hNewItems = USER_HEAP_ALLOC( sizeof(MENUITEM) * (menu->nItems+1) );
1653 if (!hNewItems)
1655 dprintf_menu(stddeb,"InsertMenu: allocation failed\n");
1656 return FALSE;
1658 newItems = (MENUITEM *) USER_HEAP_LIN_ADDR( hNewItems );
1659 if (menu->nItems > 0)
1661 /* Copy the old array into the new */
1662 MENUITEM *oldItems = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
1663 if (nPos > 0) memcpy( newItems, oldItems, nPos * sizeof(MENUITEM) );
1664 if (nPos < menu->nItems) memcpy( &newItems[nPos+1], &oldItems[nPos],
1665 (menu->nItems-nPos)*sizeof(MENUITEM) );
1667 USER_HEAP_FREE( menu->hItems );
1669 menu->hItems = hNewItems;
1670 menu->nItems++;
1672 /* Store the new item data */
1674 lpitem = &newItems[nPos];
1675 lpitem->item_flags = wFlags & ~(MF_HILITE | MF_MOUSESELECT);
1676 lpitem->item_id = wItemID;
1678 if (IS_STRING_ITEM(wFlags))
1680 /* Item beginning with a backspace is a help item */
1681 if (lpNewItem[0] == '\b')
1683 lpitem->item_flags |= MF_HELP;
1684 lpNewItem++;
1686 lpitem->hText = USER_HEAP_ALLOC( strlen(lpNewItem)+1 );
1687 lpitem->item_text = (char *)USER_HEAP_LIN_ADDR( lpitem->hText );
1688 strcpy( lpitem->item_text, lpNewItem );
1690 else if (wFlags & MF_BITMAP) lpitem->hText = LOWORD((DWORD)lpNewItem);
1691 else lpitem->item_text = lpNewItem;
1693 if (wFlags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
1694 ((POPUPMENU *)USER_HEAP_LIN_ADDR(wItemID))->wFlags |= MF_POPUP;
1696 SetRectEmpty( &lpitem->rect );
1697 lpitem->hCheckBit = hStdCheck;
1698 lpitem->hUnCheckBit = 0;
1699 return TRUE;
1703 /**********************************************************************
1704 * AppendMenu [USER.411]
1706 BOOL AppendMenu(HMENU hMenu, WORD wFlags, WORD wItemID, LPSTR lpNewItem)
1708 return InsertMenu( hMenu, -1, wFlags | MF_BYPOSITION, wItemID, lpNewItem );
1712 /**********************************************************************
1713 * RemoveMenu [USER.412]
1715 BOOL RemoveMenu(HMENU hMenu, WORD nPos, WORD wFlags)
1717 LPPOPUPMENU menu;
1718 LPMENUITEM lpitem;
1719 dprintf_menu(stddeb,"RemoveMenu (%04X, %04X, %04X) !\n",
1720 hMenu, nPos, wFlags);
1721 if (!(lpitem = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
1722 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
1724 /* Remove item */
1726 if (IS_STRING_ITEM(lpitem->item_flags)) USER_HEAP_FREE( lpitem->hText );
1727 if (--menu->nItems == 0)
1729 USER_HEAP_FREE( menu->hItems );
1730 menu->hItems = 0;
1732 else
1734 while(nPos < menu->nItems)
1736 *lpitem = *(lpitem+1);
1737 lpitem++;
1738 nPos++;
1740 menu->hItems = USER_HEAP_REALLOC( menu->hItems,
1741 menu->nItems * sizeof(MENUITEM) );
1743 return TRUE;
1747 /**********************************************************************
1748 * DeleteMenu [USER.413]
1750 BOOL DeleteMenu(HMENU hMenu, WORD nPos, WORD wFlags)
1752 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
1753 if (!item) return FALSE;
1754 if (item->item_flags & MF_POPUP) DestroyMenu( item->item_id );
1755 /* nPos is now the position of the item */
1756 RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
1757 return TRUE;
1761 /**********************************************************************
1762 * ModifyMenu [USER.414]
1764 BOOL ModifyMenu(HMENU hMenu, WORD nPos, WORD wFlags, WORD wItemID, LPSTR lpNewItem)
1766 LPMENUITEM lpitem;
1767 if (IS_STRING_ITEM(wFlags))
1768 dprintf_menu(stddeb,"ModifyMenu (%04X, %04X, %04X, %04X, '%s') !\n",
1769 hMenu, nPos, wFlags, wItemID, lpNewItem);
1770 else
1771 dprintf_menu(stddeb,"ModifyMenu (%04X, %04X, %04X, %04X, %p) !\n",
1772 hMenu, nPos, wFlags, wItemID, lpNewItem);
1773 if (!(lpitem = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
1775 if (IS_STRING_ITEM(lpitem->item_flags)) USER_HEAP_FREE( lpitem->hText );
1776 lpitem->item_flags = wFlags & ~(MF_HILITE | MF_MOUSESELECT);
1777 lpitem->item_id = wItemID;
1779 if (IS_STRING_ITEM(wFlags))
1781 lpitem->hText = USER_HEAP_ALLOC( strlen(lpNewItem)+1 );
1782 lpitem->item_text = (char *)USER_HEAP_LIN_ADDR( lpitem->hText );
1783 strcpy( lpitem->item_text, lpNewItem );
1785 else if (wFlags & MF_BITMAP) lpitem->hText = LOWORD((DWORD)lpNewItem);
1786 else lpitem->item_text = lpNewItem;
1787 SetRectEmpty( &lpitem->rect );
1788 return TRUE;
1792 /**********************************************************************
1793 * CreatePopupMenu [USER.415]
1795 HMENU CreatePopupMenu()
1797 HMENU hmenu;
1798 POPUPMENU *menu;
1800 if (!(hmenu = CreateMenu())) return 0;
1801 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1802 menu->wFlags |= MF_POPUP;
1803 return hmenu;
1807 /**********************************************************************
1808 * GetMenuCheckMarkDimensions [USER.417]
1810 DWORD GetMenuCheckMarkDimensions()
1812 return MAKELONG( check_bitmap_width, check_bitmap_height );
1816 /**********************************************************************
1817 * SetMenuItemBitmaps [USER.418]
1819 BOOL SetMenuItemBitmaps(HMENU hMenu, WORD nPos, WORD wFlags,
1820 HBITMAP hNewCheck, HBITMAP hNewUnCheck)
1822 LPMENUITEM lpitem;
1823 dprintf_menu(stddeb,"SetMenuItemBitmaps (%04X, %04X, %04X, %04X, %08X) !\n",
1824 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
1825 if (!(lpitem = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
1827 if (!hNewCheck && !hNewUnCheck)
1829 /* If both are NULL, restore default bitmaps */
1830 lpitem->hCheckBit = hStdCheck;
1831 lpitem->hUnCheckBit = 0;
1832 lpitem->item_flags &= ~MF_USECHECKBITMAPS;
1834 else /* Install new bitmaps */
1836 lpitem->hCheckBit = hNewCheck;
1837 lpitem->hUnCheckBit = hNewUnCheck;
1838 lpitem->item_flags |= MF_USECHECKBITMAPS;
1840 return TRUE;
1844 /**********************************************************************
1845 * CreateMenu [USER.151]
1847 HMENU CreateMenu()
1849 HMENU hMenu;
1850 LPPOPUPMENU menu;
1851 dprintf_menu(stddeb,"CreateMenu !\n");
1852 if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) )))
1853 return 0;
1854 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
1855 menu->hNext = 0;
1856 menu->wFlags = 0;
1857 menu->wMagic = MENU_MAGIC;
1858 menu->hTaskQ = 0;
1859 menu->Width = 0;
1860 menu->Height = 0;
1861 menu->nItems = 0;
1862 menu->hWnd = 0;
1863 menu->hItems = 0;
1864 menu->FocusedItem = NO_SELECTED_ITEM;
1865 dprintf_menu(stddeb,"CreateMenu // return %04X\n", hMenu);
1866 return hMenu;
1870 /**********************************************************************
1871 * DestroyMenu [USER.152]
1873 BOOL DestroyMenu(HMENU hMenu)
1875 LPPOPUPMENU lppop;
1876 dprintf_menu(stddeb,"DestroyMenu (%04X) !\n", hMenu);
1877 if (hMenu == 0) return FALSE;
1878 lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
1879 if (lppop == NULL) return FALSE;
1880 if ((lppop->wFlags & MF_POPUP) && lppop->hWnd)
1881 DestroyWindow( lppop->hWnd );
1883 if (lppop->hItems)
1885 int i;
1886 MENUITEM *item = (MENUITEM *) USER_HEAP_LIN_ADDR( lppop->hItems );
1887 for (i = lppop->nItems; i > 0; i--, item++)
1889 if (item->item_flags & MF_POPUP)
1890 DestroyMenu( item->item_id );
1892 USER_HEAP_FREE( lppop->hItems );
1894 USER_HEAP_FREE( hMenu );
1895 dprintf_menu(stddeb,"DestroyMenu (%04X) // End !\n", hMenu);
1896 return TRUE;
1899 /**********************************************************************
1900 * GetSystemMenu [USER.156]
1902 HMENU GetSystemMenu(HWND hWnd, BOOL bRevert)
1904 WND *wndPtr;
1905 wndPtr = WIN_FindWndPtr(hWnd);
1906 if (!bRevert) {
1907 return wndPtr->hSysMenu;
1909 else {
1910 DestroyMenu(wndPtr->hSysMenu);
1911 wndPtr->hSysMenu = CopySysMenu();
1913 return wndPtr->hSysMenu;
1916 /**********************************************************************
1917 * SetSystemMenu [USER.280]
1919 BOOL SetSystemMenu(HWND hWnd, HMENU newHmenu)
1921 WND *wndPtr;
1923 if ((wndPtr = WIN_FindWndPtr(hWnd)) != NULL) wndPtr->hSysMenu = newHmenu;
1924 return TRUE;
1928 /**********************************************************************
1929 * GetMenu [USER.157]
1931 HMENU GetMenu(HWND hWnd)
1933 WND * wndPtr = WIN_FindWndPtr(hWnd);
1934 if (wndPtr == NULL) return 0;
1935 return wndPtr->wIDmenu;
1939 /**********************************************************************
1940 * SetMenu [USER.158]
1942 BOOL SetMenu(HWND hWnd, HMENU hMenu)
1944 LPPOPUPMENU lpmenu;
1945 WND * wndPtr = WIN_FindWndPtr(hWnd);
1946 if (wndPtr == NULL) {
1947 fprintf(stderr,"SetMenu(%04X, %04X) // Bad window handle !\n",
1948 hWnd, hMenu);
1949 return FALSE;
1951 dprintf_menu(stddeb,"SetMenu(%04X, %04X);\n", hWnd, hMenu);
1952 if (GetCapture() == hWnd) ReleaseCapture();
1953 wndPtr->wIDmenu = hMenu;
1954 if (hMenu != 0)
1956 lpmenu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
1957 if (lpmenu == NULL) {
1958 fprintf(stderr,"SetMenu(%04X, %04X) // Bad menu handle !\n",
1959 hWnd, hMenu);
1960 return FALSE;
1962 lpmenu->hWnd = hWnd;
1963 lpmenu->wFlags &= ~MF_POPUP; /* Can't be a popup */
1964 lpmenu->Height = 0; /* Make sure we recalculate the size */
1966 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
1967 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
1968 return TRUE;
1973 /**********************************************************************
1974 * GetSubMenu [USER.159]
1976 HMENU GetSubMenu(HMENU hMenu, short nPos)
1978 LPPOPUPMENU lppop;
1979 LPMENUITEM lpitem;
1980 dprintf_menu(stddeb,"GetSubMenu (%04X, %04X) !\n", hMenu, nPos);
1981 if (!(lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return 0;
1982 if ((WORD)nPos >= lppop->nItems) return 0;
1983 lpitem = (MENUITEM *) USER_HEAP_LIN_ADDR( lppop->hItems );
1984 if (!(lpitem[nPos].item_flags & MF_POPUP)) return 0;
1985 return lpitem[nPos].item_id;
1989 /**********************************************************************
1990 * DrawMenuBar [USER.160]
1992 void DrawMenuBar(HWND hWnd)
1994 WND *wndPtr;
1995 LPPOPUPMENU lppop;
1996 dprintf_menu(stddeb,"DrawMenuBar (%04X)\n", hWnd);
1997 wndPtr = WIN_FindWndPtr(hWnd);
1998 if (wndPtr != NULL && (wndPtr->dwStyle & WS_CHILD) == 0 &&
1999 wndPtr->wIDmenu != 0) {
2000 dprintf_menu(stddeb,"DrawMenuBar wIDmenu=%04X \n",
2001 wndPtr->wIDmenu);
2002 lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(wndPtr->wIDmenu);
2003 if (lppop == NULL) return;
2005 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
2006 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
2007 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
2012 /***********************************************************************
2013 * EndMenu (USER.187)
2015 void EndMenu(void)
2017 /* Note: this won't work when we have multiple tasks... */
2018 fEndMenuCalled = TRUE;
2022 /***********************************************************************
2023 * LookupMenuHandle (USER.217)
2025 HMENU LookupMenuHandle( HMENU hmenu, INT id )
2027 if (!MENU_FindItem( &hmenu, &id, MF_BYCOMMAND )) return 0;
2028 else return hmenu;
2032 /**********************************************************************
2033 * LoadMenuIndirect [USER.220]
2035 HMENU LoadMenuIndirect(LPSTR menu_template)
2037 HMENU hMenu;
2038 MENU_HEADER *menu_desc;
2039 dprintf_menu(stddeb,"LoadMenuIndirect: menu_template '%p'\n",
2040 menu_template);
2041 hMenu = CreateMenu();
2042 menu_desc = (MENU_HEADER *)menu_template;
2043 ParseMenuResource((WORD *)(menu_desc + 1), 0, hMenu);
2044 return hMenu;
2048 /**********************************************************************
2049 * CopySysMenu (Internal)
2051 HMENU CopySysMenu()
2053 HMENU hMenu;
2054 LPPOPUPMENU menu;
2055 extern unsigned char sysres_MENU_SYSMENU[];
2057 hMenu=LoadMenuIndirect(sysres_MENU_SYSMENU);
2058 if(!hMenu){
2059 dprintf_menu(stddeb,"No SYSMENU\n");
2060 return 0;
2062 menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hMenu);
2063 menu->wFlags |= MF_SYSMENU|MF_POPUP;
2064 dprintf_menu(stddeb,"CopySysMenu hMenu=%04X !\n", hMenu);
2065 return hMenu;
2069 /**********************************************************************
2070 * ParseMenuResource (from Resource or Template)
2072 WORD * ParseMenuResource(WORD *first_item, int level, HMENU hMenu)
2074 WORD *item;
2075 WORD *next_item;
2076 HMENU hSubMenu;
2077 int i;
2079 level++;
2080 next_item = first_item;
2081 i = 0;
2082 do {
2083 i++;
2084 item = next_item;
2085 if (*item & MF_POPUP) {
2086 MENU_POPUPITEM *popup_item = (MENU_POPUPITEM *) item;
2087 next_item = (WORD *) (popup_item->item_text +
2088 strlen(popup_item->item_text) + 1);
2089 hSubMenu = CreatePopupMenu();
2090 next_item = ParseMenuResource(next_item, level, hSubMenu);
2091 AppendMenu(hMenu, popup_item->item_flags,
2092 hSubMenu, popup_item->item_text);
2094 else {
2095 MENUITEMTEMPLATE *normal_item = (MENUITEMTEMPLATE *) item;
2096 next_item = (WORD *) (normal_item->item_text +
2097 strlen(normal_item->item_text) + 1);
2098 if (strlen(normal_item->item_text) == 0 && normal_item->item_id == 0)
2099 normal_item->item_flags |= MF_SEPARATOR;
2100 AppendMenu(hMenu, normal_item->item_flags,
2101 normal_item->item_id, normal_item->item_text);
2104 while (!(*item & MF_END));
2105 return next_item;
2109 /**********************************************************************
2110 * IsMenu (USER.358)
2112 BOOL IsMenu( HMENU hmenu )
2114 LPPOPUPMENU menu;
2115 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
2116 return (menu->wMagic == MENU_MAGIC);