Release 941017
[wine/gsoc-2012-control.git] / controls / menu.c
blob8290ddaba2a145ad71391280ebc7d0a800c83d80
1 /*
2 * Menus functions
3 */
4 static char RCSId[] = "$Id$";
5 static char Copyright[] = "Copyright Martin Ayotte, 1993";
6 static char Copyright2[] = "Copyright Alexandre Julliard, 1994";
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.
15 #include <ctype.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include "windows.h"
20 #include "syscolor.h"
21 #include "sysmetrics.h"
22 #include "prototypes.h"
23 #include "menu.h"
24 #include "user.h"
25 #include "win.h"
26 #include "message.h"
27 #include "debug.h"
29 /* #define DEBUG_MENU /* */
30 /* #undef DEBUG_MENU /* */
31 /* #define DEBUG_MENUCALC /* */
32 /* #undef DEBUG_MENUCALC /* */
33 /* #define DEBUG_MENUSHORTCUT /* */
34 /* #undef DEBUG_MENUSHORTCUT /* */
36 /* Dimension of the menu bitmaps */
37 static WORD check_bitmap_width = 0, check_bitmap_height = 0;
38 static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
40 /* Flag set by EndMenu() to force an exit from menu tracking */
41 static BOOL fEndMenuCalled = FALSE;
43 /* Space between 2 menu bar items */
44 #define MENU_BAR_ITEMS_SPACE 16
46 /* Minimum width of a tab character */
47 #define MENU_TAB_SPACE 8
49 /* Height of a separator item */
50 #define SEPARATOR_HEIGHT 5
52 /* Values for menu->FocusedItem */
53 /* (other values give the position of the focused item) */
54 #define NO_SELECTED_ITEM 0xffff
55 #define SYSMENU_SELECTED 0xfffe /* Only valid on menu-bars */
57 #define IS_STRING_ITEM(flags) (!((flags) & (MF_BITMAP | MF_OWNERDRAW | \
58 MF_MENUBARBREAK | MF_MENUBREAK | MF_SEPARATOR)))
61 extern void NC_DrawSysButton(HWND hwnd, HDC hdc, BOOL down); /* nonclient.c */
62 extern void CURSOR_SetWinCursor( HWND hwnd, HCURSOR hcursor ); /* cursor.c */
63 extern BOOL GRAPH_DrawBitmap( HDC hdc, HBITMAP hbitmap, int xdest, int ydest,
64 int xsrc, int ysrc, int width, int height,
65 int rop ); /* graphics.c */
67 extern HINSTANCE hSysRes;
69 static HMENU hSysMenu = 0;
70 static HBITMAP hStdCheck = 0;
71 static HBITMAP hStdMnArrow = 0;
73 HMENU CopySysMenu();
74 WORD * ParseMenuResource(WORD *first_item, int level, HMENU hMenu);
77 /***********************************************************************
78 * MENU_Init
80 * Menus initialisation.
82 BOOL MENU_Init()
84 BITMAP bm;
86 /* Load bitmaps */
88 if (!(hStdCheck = LoadBitmap( 0, MAKEINTRESOURCE(OBM_CHECK) )))
89 return FALSE;
90 GetObject( hStdCheck, sizeof(BITMAP), (LPSTR)&bm );
91 check_bitmap_width = bm.bmWidth;
92 check_bitmap_height = bm.bmHeight;
93 if (!(hStdMnArrow = LoadBitmap( 0, MAKEINTRESOURCE(OBM_MNARROW) )))
94 return FALSE;
95 GetObject( hStdMnArrow, sizeof(BITMAP), (LPSTR)&bm );
96 arrow_bitmap_width = bm.bmWidth;
97 arrow_bitmap_height = bm.bmHeight;
99 /* Load system menu */
101 if (!(hSysMenu = LoadMenu( hSysRes, "SYSMENU" )))
103 fprintf(stderr,"SysMenu not found in system resources !\n");
104 return FALSE;
107 return TRUE;
111 /***********************************************************************
112 * MENU_HasSysMenu
114 * Check whether the window owning the menu bar has a system menu.
116 static BOOL MENU_HasSysMenu( POPUPMENU *menu )
118 WND *wndPtr;
120 if (menu->wFlags & MF_POPUP) return FALSE;
121 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return FALSE;
122 return (wndPtr->dwStyle & WS_SYSMENU) != 0;
126 /***********************************************************************
127 * MENU_IsInSysMenu
129 * Check whether the point (in screen coords) is in the system menu
130 * of the window owning the given menu.
132 static BOOL MENU_IsInSysMenu( POPUPMENU *menu, POINT pt )
134 WND *wndPtr;
136 if (menu->wFlags & MF_POPUP) return FALSE;
137 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return FALSE;
138 if (!(wndPtr->dwStyle & WS_SYSMENU)) return FALSE;
139 if ((pt.x < wndPtr->rectClient.left) ||
140 (pt.x >= wndPtr->rectClient.left+SYSMETRICS_CXSIZE+SYSMETRICS_CXBORDER))
141 return FALSE;
142 if ((pt.y >= wndPtr->rectClient.top - menu->Height) ||
143 (pt.y < wndPtr->rectClient.top - menu->Height -
144 SYSMETRICS_CYSIZE - SYSMETRICS_CYBORDER)) return FALSE;
145 return TRUE;
149 /***********************************************************************
150 * MENU_FindItem
152 * Find a menu item. Return a pointer on the item, and modifies *hmenu
153 * in case the item was in a sub-menu.
155 static MENUITEM *MENU_FindItem( HMENU *hmenu, WORD *nPos, WORD wFlags )
157 POPUPMENU *menu;
158 MENUITEM *item;
159 int i;
161 if (!(menu = (POPUPMENU *) USER_HEAP_ADDR(*hmenu))) return NULL;
162 item = (MENUITEM *) USER_HEAP_ADDR( menu->hItems );
163 if (wFlags & MF_BYPOSITION)
165 if (*nPos >= menu->nItems) return NULL;
166 return &item[*nPos];
168 else
170 for (i = 0; i < menu->nItems; i++, item++)
172 if (item->item_id == *nPos)
174 *nPos = i;
175 return item;
177 else if (item->item_flags & MF_POPUP)
179 HMENU hsubmenu = (HMENU)item->item_id;
180 MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
181 if (subitem)
183 *hmenu = hsubmenu;
184 return subitem;
189 return NULL;
193 /***********************************************************************
194 * MENU_FindItemByCoords
196 * Find the item at the specified coordinates (screen coords).
198 static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu, int x, int y, WORD *pos )
200 MENUITEM *item;
201 WND *wndPtr;
202 int i;
204 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return NULL;
205 x -= wndPtr->rectWindow.left;
206 y -= wndPtr->rectWindow.top;
207 item = (MENUITEM *) USER_HEAP_ADDR( menu->hItems );
208 for (i = 0; i < menu->nItems; i++, item++)
210 if ((x >= item->rect.left) && (x < item->rect.right) &&
211 (y >= item->rect.top) && (y < item->rect.bottom))
213 if (pos) *pos = i;
214 return item;
217 return NULL;
221 /***********************************************************************
222 * MENU_FindItemByKey
224 * Find the menu item selected by a key press.
225 * Return item id, -1 if none, -2 if we should close the menu.
227 static WORD MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu, WORD key )
229 POPUPMENU *menu;
230 LPMENUITEM lpitem;
231 int i;
232 LONG menuchar;
234 menu = (POPUPMENU *) USER_HEAP_ADDR( hmenu );
235 lpitem = (MENUITEM *) USER_HEAP_ADDR( menu->hItems );
236 key = toupper(key);
237 for (i = 0; i < menu->nItems; i++, lpitem++)
239 if (IS_STRING_ITEM(lpitem->item_flags))
241 char *p = strchr( lpitem->item_text, '&' );
242 if (p && (p[1] != '&') && (toupper(p[1]) == key)) return i;
245 menuchar = SendMessage( hwndOwner, WM_MENUCHAR, key,
246 MAKELONG( menu->wFlags, hmenu ) );
247 if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
248 if (HIWORD(menuchar) == 1) return -2;
249 return -1;
253 /***********************************************************************
254 * MENU_CalcItemSize
256 * Calculate the size of the menu item and store it in lpitem->rect.
258 static void MENU_CalcItemSize( HDC hdc, LPMENUITEM lpitem, HWND hwndOwner,
259 int orgX, int orgY, BOOL menuBar )
261 DWORD dwSize;
262 char *p;
264 SetRect( &lpitem->rect, orgX, orgY, orgX, orgY );
265 lpitem->xTab = 0;
267 if (lpitem->item_flags & MF_SEPARATOR)
269 lpitem->rect.bottom += SEPARATOR_HEIGHT;
270 return;
273 if (!menuBar)
275 lpitem->rect.right += 2 * check_bitmap_width;
276 if (lpitem->item_flags & MF_POPUP)
277 lpitem->rect.right += arrow_bitmap_width;
280 if (lpitem->item_flags & MF_BITMAP)
282 BITMAP bm;
283 GetObject( (HBITMAP)lpitem->hText, sizeof(BITMAP), (LPSTR)&bm );
284 lpitem->rect.right += bm.bmWidth;
285 lpitem->rect.bottom += bm.bmHeight;
286 return;
289 /* If we get here, then it is a text item */
291 dwSize = GetTextExtent( hdc, lpitem->item_text, strlen(lpitem->item_text));
292 lpitem->rect.right += LOWORD(dwSize);
293 lpitem->rect.bottom += max( HIWORD(dwSize), SYSMETRICS_CYMENU );
295 if (menuBar) lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
296 else if ((p = strchr( lpitem->item_text, '\t' )) != NULL)
298 /* Item contains a tab (only meaningful in popup menus) */
299 lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE +
300 LOWORD( GetTextExtent( hdc, lpitem->item_text,
301 (int)(p - lpitem->item_text) ));
302 lpitem->rect.right += MENU_TAB_SPACE;
304 else
306 if (strchr( lpitem->item_text, '\b' ))
307 lpitem->rect.right += MENU_TAB_SPACE;
308 lpitem->xTab = lpitem->rect.right - check_bitmap_width
309 - arrow_bitmap_width;
314 /***********************************************************************
315 * MENU_PopupMenuCalcSize
317 * Calculate the size of a popup menu.
319 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
321 LPMENUITEM items, lpitem;
322 HDC hdc;
323 int start, i;
324 int orgX, orgY, maxX, maxTab, maxTabWidth;
326 lppop->Width = lppop->Height = 0;
327 if (lppop->nItems == 0) return;
328 items = (MENUITEM *)USER_HEAP_ADDR( lppop->hItems );
329 hdc = GetDC( 0 );
330 maxX = start = 0;
331 while (start < lppop->nItems)
333 lpitem = &items[start];
334 orgX = maxX;
335 orgY = 0;
336 maxTab = maxTabWidth = 0;
338 /* Parse items until column break or end of menu */
339 for (i = start; i < lppop->nItems; i++, lpitem++)
341 if ((i != start) &&
342 (lpitem->item_flags & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
343 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
344 maxX = max( maxX, lpitem->rect.right );
345 orgY = lpitem->rect.bottom;
346 if (lpitem->xTab)
348 maxTab = max( maxTab, lpitem->xTab );
349 maxTabWidth = max(maxTabWidth,lpitem->rect.right-lpitem->xTab);
353 /* Finish the column (set all items to the largest width found) */
354 maxX = max( maxX, maxTab + maxTabWidth );
355 for (lpitem = &items[start]; start < i; start++, lpitem++)
357 lpitem->rect.right = maxX;
358 if (lpitem->xTab) lpitem->xTab = maxTab;
360 lppop->Height = max( lppop->Height, orgY );
363 lppop->Width = maxX;
364 ReleaseDC( 0, hdc );
368 /***********************************************************************
369 * MENU_MenuBarCalcSize
371 * Calculate the size of the menu bar.
373 static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect, LPPOPUPMENU lppop,
374 HWND hwndOwner )
376 LPMENUITEM lpitem, items;
377 int start, i, orgX, orgY, maxY, helpPos;
379 if ((lprect == NULL) || (lppop == NULL)) return;
380 if (lppop->nItems == 0) return;
381 dprintf_menucalc(stddeb,"MenuBarCalcSize left=%d top=%d right=%d bottom=%d !\n",
382 lprect->left, lprect->top, lprect->right, lprect->bottom);
383 items = (MENUITEM *)USER_HEAP_ADDR( lppop->hItems );
384 lppop->Width = lprect->right - lprect->left;
385 lppop->Height = 0;
386 maxY = lprect->top;
387 start = 0;
388 helpPos = -1;
389 while (start < lppop->nItems)
391 lpitem = &items[start];
392 orgX = lprect->left;
393 orgY = maxY;
395 /* Parse items until line break or end of menu */
396 for (i = start; i < lppop->nItems; i++, lpitem++)
398 if ((helpPos == -1) && (lpitem->item_flags & MF_HELP)) helpPos = i;
399 if ((i != start) &&
400 (lpitem->item_flags & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
401 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE );
402 if (lpitem->rect.right > lprect->right)
404 if (i != start) break;
405 else lpitem->rect.right = lprect->right;
407 maxY = max( maxY, lpitem->rect.bottom );
408 orgX = lpitem->rect.right;
411 /* Finish the line (set all items to the largest height found) */
412 while (start < i) items[start++].rect.bottom = maxY;
415 lprect->bottom = maxY;
416 lppop->Height = lprect->bottom - lprect->top;
418 /* Flush right all items between the MF_HELP and the last item */
419 /* (if several lines, only move the last line) */
420 if (helpPos != -1)
422 lpitem = &items[lppop->nItems-1];
423 orgY = lpitem->rect.top;
424 orgX = lprect->right;
425 for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--)
427 if (lpitem->rect.top != orgY) break; /* Other line */
428 if (lpitem->rect.right >= orgX) break; /* Too far right already */
429 lpitem->rect.left += orgX - lpitem->rect.right;
430 lpitem->rect.right = orgX;
431 orgX = lpitem->rect.left;
437 /***********************************************************************
438 * MENU_DrawMenuItem
440 * Draw a single menu item.
442 static void MENU_DrawMenuItem( HDC hdc, LPMENUITEM lpitem,
443 WORD height, BOOL menuBar )
445 RECT rect;
447 if (menuBar && (lpitem->item_flags & MF_SEPARATOR)) return;
448 rect = lpitem->rect;
450 /* Draw the background */
452 if (lpitem->item_flags & MF_HILITE)
453 FillRect( hdc, &rect, sysColorObjects.hbrushHighlight );
454 else FillRect( hdc, &rect, sysColorObjects.hbrushMenu );
455 SetBkMode( hdc, TRANSPARENT );
457 /* Draw the separator bar (if any) */
459 if (!menuBar && (lpitem->item_flags & MF_MENUBARBREAK))
461 SelectObject( hdc, sysColorObjects.hpenWindowFrame );
462 MoveTo( hdc, rect.left, 0 );
463 LineTo( hdc, rect.left, height );
465 if (lpitem->item_flags & MF_SEPARATOR)
467 SelectObject( hdc, sysColorObjects.hpenWindowFrame );
468 MoveTo( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2 );
469 LineTo( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 );
470 return;
473 /* Setup colors */
475 if (lpitem->item_flags & MF_HILITE)
477 if (lpitem->item_flags & MF_GRAYED)
478 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
479 else
480 SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
481 SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
483 else
485 if (lpitem->item_flags & MF_GRAYED)
486 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
487 else
488 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
489 SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
492 if (!menuBar)
494 /* Draw the check mark */
496 if (lpitem->item_flags & MF_CHECKED)
498 GRAPH_DrawBitmap(hdc, lpitem->hCheckBit ? lpitem->hCheckBit :
499 hStdCheck, rect.left,
500 (rect.top+rect.bottom-check_bitmap_height) / 2,
501 0, 0, check_bitmap_width, check_bitmap_height,
502 SRCCOPY);
504 else if (lpitem->hUnCheckBit != 0) /* Not checked */
506 GRAPH_DrawBitmap(hdc, lpitem->hUnCheckBit, rect.left,
507 (rect.top+rect.bottom-check_bitmap_height) / 2,
508 0, 0, check_bitmap_width, check_bitmap_height,
509 SRCCOPY);
512 /* Draw the popup-menu arrow */
514 if (lpitem->item_flags & MF_POPUP)
516 GRAPH_DrawBitmap( hdc, hStdMnArrow,
517 rect.right-arrow_bitmap_width-1,
518 (rect.top+rect.bottom-arrow_bitmap_height) / 2,
519 0, 0, arrow_bitmap_width, arrow_bitmap_height,
520 SRCCOPY );
523 rect.left += check_bitmap_width;
524 rect.right -= arrow_bitmap_width;
527 /* Draw the item text or bitmap */
529 if (lpitem->item_flags & MF_BITMAP)
531 GRAPH_DrawBitmap( hdc, (HBITMAP)lpitem->hText, rect.left, rect.top,
532 0, 0, rect.right-rect.left, rect.bottom-rect.top,
533 SRCCOPY );
534 return;
536 /* No bitmap - process text if present */
537 else if ((lpitem->item_text) != ((char *) NULL))
539 register int i;
541 if (menuBar)
543 rect.left += MENU_BAR_ITEMS_SPACE / 2;
544 rect.right -= MENU_BAR_ITEMS_SPACE / 2;
545 i = strlen( lpitem->item_text );
547 else
549 for (i = 0; lpitem->item_text[i]; i++)
550 if ((lpitem->item_text[i] == '\t') ||
551 (lpitem->item_text[i] == '\b')) break;
554 DrawText( hdc, lpitem->item_text, i, &rect,
555 DT_LEFT | DT_VCENTER | DT_SINGLELINE );
557 if (lpitem->item_text[i]) /* There's a tab or flush-right char */
559 if (lpitem->item_text[i] == '\t')
561 rect.left = lpitem->xTab;
562 DrawText( hdc, lpitem->item_text + i + 1, -1, &rect,
563 DT_LEFT | DT_VCENTER | DT_SINGLELINE );
565 else DrawText( hdc, lpitem->item_text + i + 1, -1, &rect,
566 DT_RIGHT | DT_VCENTER | DT_SINGLELINE );
572 /***********************************************************************
573 * MENU_DrawPopupMenu
575 * Paint a popup menu.
577 static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
579 POPUPMENU *menu;
580 MENUITEM *item;
581 RECT rect;
582 int i;
584 GetClientRect( hwnd, &rect );
585 FillRect( hdc, &rect, sysColorObjects.hbrushMenu );
586 menu = (POPUPMENU *) USER_HEAP_ADDR( hmenu );
587 if (!menu || !menu->nItems) return;
588 item = (MENUITEM *) USER_HEAP_ADDR( menu->hItems );
589 for (i = menu->nItems; i > 0; i--, item++)
590 MENU_DrawMenuItem( hdc, item, menu->Height, FALSE );
594 /***********************************************************************
595 * MENU_DrawMenuBar
597 * Paint a menu bar. Returns the height of the menu bar.
599 WORD MENU_DrawMenuBar(HDC hDC, LPRECT lprect, HWND hwnd, BOOL suppress_draw)
601 LPPOPUPMENU lppop;
602 LPMENUITEM lpitem;
603 int i;
604 WND *wndPtr = WIN_FindWndPtr( hwnd );
606 lppop = (LPPOPUPMENU) USER_HEAP_ADDR( wndPtr->wIDmenu );
607 if (lppop == NULL || lprect == NULL) return SYSMETRICS_CYMENU;
608 dprintf_menu(stddeb,"MENU_DrawMenuBar(%04X, %08X, %08X); !\n",
609 hDC, lprect, lppop);
610 if (lppop->Height == 0) MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
611 lprect->bottom = lprect->top + lppop->Height;
612 if (suppress_draw) return lppop->Height;
614 FillRect(hDC, lprect, sysColorObjects.hbrushMenu );
615 SelectObject( hDC, sysColorObjects.hpenWindowFrame );
616 MoveTo( hDC, lprect->left, lprect->bottom );
617 LineTo( hDC, lprect->right, lprect->bottom );
619 if (lppop->nItems == 0) return SYSMETRICS_CYMENU;
620 lpitem = (MENUITEM *) USER_HEAP_ADDR( lppop->hItems );
621 for (i = 0; i < lppop->nItems; i++, lpitem++)
623 MENU_DrawMenuItem( hDC, lpitem, lppop->Height, TRUE );
625 return lppop->Height;
629 /***********************************************************************
630 * MENU_ShowPopup
632 * Display a popup menu.
634 static BOOL MENU_ShowPopup(HWND hwndOwner, HMENU hmenu, WORD id, int x, int y)
636 POPUPMENU *menu;
638 if (!(menu = (POPUPMENU *) USER_HEAP_ADDR( hmenu ))) return FALSE;
639 if (menu->FocusedItem != NO_SELECTED_ITEM)
641 MENUITEM *item = (MENUITEM *) USER_HEAP_ADDR( menu->hItems );
642 item[menu->FocusedItem].item_flags &= ~(MF_HILITE | MF_MOUSESELECT);
643 menu->FocusedItem = NO_SELECTED_ITEM;
645 SendMessage( hwndOwner, WM_INITMENUPOPUP, hmenu,
646 MAKELONG( id, (menu->wFlags & MF_POPUP) ? 1 : 0 ));
647 MENU_PopupMenuCalcSize( menu, hwndOwner );
648 if (!menu->hWnd)
650 WND *wndPtr = WIN_FindWndPtr( hwndOwner );
651 if (!wndPtr) return FALSE;
652 menu->hWnd = CreateWindow( POPUPMENU_CLASS_NAME, "",
653 WS_POPUP | WS_BORDER, x, y,
654 menu->Width + 2*SYSMETRICS_CXBORDER,
655 menu->Height + 2*SYSMETRICS_CYBORDER,
656 0, 0, wndPtr->hInstance,
657 (LPSTR)(DWORD)hmenu );
658 if (!menu->hWnd) return FALSE;
660 else SetWindowPos( menu->hWnd, 0, x, y,
661 menu->Width + 2*SYSMETRICS_CXBORDER,
662 menu->Height + 2*SYSMETRICS_CYBORDER,
663 SWP_NOACTIVATE | SWP_NOZORDER );
665 /* Display the window */
667 SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
668 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
669 UpdateWindow( menu->hWnd );
670 return TRUE;
674 /***********************************************************************
675 * MENU_SelectItem
677 static void MENU_SelectItem( HMENU hmenu, WORD wIndex )
679 MENUITEM *items;
680 LPPOPUPMENU lppop;
681 HDC hdc;
683 lppop = (POPUPMENU *) USER_HEAP_ADDR( hmenu );
684 if (!lppop->nItems) return;
685 items = (MENUITEM *) USER_HEAP_ADDR( lppop->hItems );
686 if ((wIndex != NO_SELECTED_ITEM) &&
687 (wIndex != SYSMENU_SELECTED) &&
688 (items[wIndex].item_flags & MF_SEPARATOR))
689 wIndex = NO_SELECTED_ITEM;
690 if (lppop->FocusedItem == wIndex) return;
691 if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
692 else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
694 /* Clear previous highlighted item */
695 if (lppop->FocusedItem != NO_SELECTED_ITEM)
697 if (lppop->FocusedItem == SYSMENU_SELECTED)
698 NC_DrawSysButton( lppop->hWnd, hdc, FALSE );
699 else
701 items[lppop->FocusedItem].item_flags &=~(MF_HILITE|MF_MOUSESELECT);
702 MENU_DrawMenuItem( hdc, &items[lppop->FocusedItem], lppop->Height,
703 !(lppop->wFlags & MF_POPUP) );
707 /* Highlight new item (if any) */
708 lppop->FocusedItem = wIndex;
709 if (lppop->FocusedItem != NO_SELECTED_ITEM)
711 if (lppop->FocusedItem == SYSMENU_SELECTED)
712 NC_DrawSysButton( lppop->hWnd, hdc, TRUE );
713 else
715 items[lppop->FocusedItem].item_flags |= MF_HILITE;
716 MENU_DrawMenuItem( hdc, &items[lppop->FocusedItem], lppop->Height,
717 !(lppop->wFlags & MF_POPUP) );
718 SendMessage(lppop->hWnd, WM_MENUSELECT,
719 items[lppop->FocusedItem].item_id,
720 MAKELONG( hmenu, items[lppop->FocusedItem].item_flags));
723 ReleaseDC( lppop->hWnd, hdc );
727 /***********************************************************************
728 * MENU_SelectNextItem
730 static void MENU_SelectNextItem( HMENU hmenu )
732 int i;
733 MENUITEM *items;
734 POPUPMENU *menu;
736 menu = (POPUPMENU *) USER_HEAP_ADDR( hmenu );
737 if (!menu->nItems) return;
738 items = (MENUITEM *) USER_HEAP_ADDR( menu->hItems );
739 if ((menu->FocusedItem != NO_SELECTED_ITEM) &&
740 (menu->FocusedItem != SYSMENU_SELECTED))
742 for (i = menu->FocusedItem+1; i < menu->nItems; i++)
744 if (!(items[i].item_flags & MF_SEPARATOR))
746 MENU_SelectItem( hmenu, i );
747 return;
750 if (MENU_HasSysMenu( menu ))
752 MENU_SelectItem( hmenu, SYSMENU_SELECTED );
753 return;
756 for (i = 0; i < menu->nItems; i++)
758 if (!(items[i].item_flags & MF_SEPARATOR))
760 MENU_SelectItem( hmenu, i );
761 return;
764 if (MENU_HasSysMenu( menu )) MENU_SelectItem( hmenu, SYSMENU_SELECTED );
768 /***********************************************************************
769 * MENU_SelectPrevItem
771 static void MENU_SelectPrevItem( HMENU hmenu )
773 int i;
774 MENUITEM *items;
775 POPUPMENU *menu;
777 menu = (POPUPMENU *) USER_HEAP_ADDR( hmenu );
778 if (!menu->nItems) return;
779 items = (MENUITEM *) USER_HEAP_ADDR( menu->hItems );
780 if ((menu->FocusedItem != NO_SELECTED_ITEM) &&
781 (menu->FocusedItem != SYSMENU_SELECTED))
783 for (i = menu->FocusedItem - 1; i >= 0; i--)
785 if (!(items[i].item_flags & MF_SEPARATOR))
787 MENU_SelectItem( hmenu, i );
788 return;
791 if (MENU_HasSysMenu( menu ))
793 MENU_SelectItem( hmenu, SYSMENU_SELECTED );
794 return;
797 for (i = menu->nItems - 1; i > 0; i--)
799 if (!(items[i].item_flags & MF_SEPARATOR))
801 MENU_SelectItem( hmenu, i );
802 return;
805 if (MENU_HasSysMenu( menu )) MENU_SelectItem( hmenu, SYSMENU_SELECTED );
809 /***********************************************************************
810 * MENU_GetSubPopup
812 * Return the handle of the selected sub-popup menu (if any).
814 static HMENU MENU_GetSubPopup( HMENU hmenu )
816 POPUPMENU *menu;
817 MENUITEM *item;
819 menu = (POPUPMENU *) USER_HEAP_ADDR( hmenu );
820 if (menu->FocusedItem == NO_SELECTED_ITEM) return 0;
821 else if (menu->FocusedItem == SYSMENU_SELECTED)
822 return GetSystemMenu( menu->hWnd, FALSE );
824 item = ((MENUITEM *)USER_HEAP_ADDR( menu->hItems )) + menu->FocusedItem;
825 if (!(item->item_flags & MF_POPUP) || !(item->item_flags & MF_MOUSESELECT))
826 return 0;
827 return item->item_id;
831 /***********************************************************************
832 * MENU_HideSubPopups
834 * Hide the sub-popup menus of this menu.
836 static void MENU_HideSubPopups( HMENU hmenu )
838 MENUITEM *item;
839 POPUPMENU *menu, *submenu;
840 HMENU hsubmenu;
842 if (!(menu = (POPUPMENU *) USER_HEAP_ADDR( hmenu ))) return;
843 if (menu->FocusedItem == NO_SELECTED_ITEM) return;
844 if (menu->FocusedItem == SYSMENU_SELECTED)
846 hsubmenu = GetSystemMenu( menu->hWnd, FALSE );
848 else
850 item = ((MENUITEM *)USER_HEAP_ADDR(menu->hItems)) + menu->FocusedItem;
851 if (!(item->item_flags & MF_POPUP) ||
852 !(item->item_flags & MF_MOUSESELECT)) return;
853 item->item_flags &= ~MF_MOUSESELECT;
854 hsubmenu = item->item_id;
856 submenu = (POPUPMENU *) USER_HEAP_ADDR( hsubmenu );
857 MENU_HideSubPopups( hsubmenu );
858 if (submenu->hWnd) ShowWindow( submenu->hWnd, SW_HIDE );
859 MENU_SelectItem( hsubmenu, NO_SELECTED_ITEM );
863 /***********************************************************************
864 * MENU_ShowSubPopup
866 * Display the sub-menu of the selected item of this menu.
867 * Return the handle of the submenu, or hmenu if no submenu to display.
869 static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu, BOOL selectFirst )
871 POPUPMENU *menu;
872 MENUITEM *item;
873 WND *wndPtr;
875 if (!(menu = (POPUPMENU *) USER_HEAP_ADDR( hmenu ))) return hmenu;
876 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return hmenu;
877 if (menu->FocusedItem == NO_SELECTED_ITEM) return hmenu;
878 if (menu->FocusedItem == SYSMENU_SELECTED)
880 MENU_ShowPopup(hwndOwner, wndPtr->hSysMenu, 0, wndPtr->rectClient.left,
881 wndPtr->rectClient.top - menu->Height - 2*SYSMETRICS_CYBORDER);
882 if (selectFirst) MENU_SelectNextItem( wndPtr->hSysMenu );
883 return wndPtr->hSysMenu;
885 item = ((MENUITEM *)USER_HEAP_ADDR( menu->hItems )) + menu->FocusedItem;
886 if (!(item->item_flags & MF_POPUP) ||
887 (item->item_flags & (MF_GRAYED | MF_DISABLED))) return hmenu;
888 item->item_flags |= MF_MOUSESELECT;
889 if (menu->wFlags & MF_POPUP)
891 MENU_ShowPopup( hwndOwner, (HMENU)item->item_id, menu->FocusedItem,
892 wndPtr->rectWindow.left + item->rect.right-arrow_bitmap_width,
893 wndPtr->rectWindow.top + item->rect.top );
895 else
897 MENU_ShowPopup( hwndOwner, (HMENU)item->item_id, menu->FocusedItem,
898 wndPtr->rectWindow.left + item->rect.left,
899 wndPtr->rectWindow.top + item->rect.bottom );
901 if (selectFirst) MENU_SelectNextItem( (HMENU)item->item_id );
902 return (HMENU)item->item_id;
906 /***********************************************************************
907 * MENU_FindMenuByCoords
909 * Find the menu containing a given point (in screen coords).
911 static HMENU MENU_FindMenuByCoords( HMENU hmenu, POINT pt )
913 POPUPMENU *menu;
914 HWND hwnd;
916 if (!(hwnd = WindowFromPoint( pt ))) return 0;
917 while (hmenu)
919 menu = (POPUPMENU *) USER_HEAP_ADDR( hmenu );
920 if (menu->hWnd == hwnd)
922 if (!(menu->wFlags & MF_POPUP))
924 /* Make sure it's in the menu bar (or in system menu) */
925 WND *wndPtr = WIN_FindWndPtr( menu->hWnd );
926 if ((pt.x < wndPtr->rectClient.left) ||
927 (pt.x >= wndPtr->rectClient.right) ||
928 (pt.y >= wndPtr->rectClient.top)) return 0;
929 if (pt.y < wndPtr->rectClient.top - menu->Height)
931 if (!MENU_IsInSysMenu( menu, pt )) return 0;
933 /* else it's in the menu bar */
935 return hmenu;
937 hmenu = MENU_GetSubPopup( hmenu );
939 return 0;
943 /***********************************************************************
944 * MENU_ExecFocusedItem
946 * Execute a menu item (for instance when user pressed Enter).
947 * Return TRUE if we can go on with menu tracking.
949 static BOOL MENU_ExecFocusedItem( HWND hwndOwner, HMENU hmenu,
950 HMENU *hmenuCurrent )
952 MENUITEM *item;
953 POPUPMENU *menu = (POPUPMENU *) USER_HEAP_ADDR( hmenu );
954 if (!menu || !menu->nItems || (menu->FocusedItem == NO_SELECTED_ITEM) ||
955 (menu->FocusedItem == SYSMENU_SELECTED)) return TRUE;
956 item = ((MENUITEM *)USER_HEAP_ADDR( menu->hItems )) + menu->FocusedItem;
957 if (!(item->item_flags & MF_POPUP))
959 if (!(item->item_flags & (MF_GRAYED | MF_DISABLED)))
961 PostMessage( hwndOwner, (menu->wFlags & MF_SYSMENU) ?
962 WM_SYSCOMMAND : WM_COMMAND, item->item_id, 0 );
963 return FALSE;
965 else return TRUE;
967 else
969 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, TRUE );
970 return TRUE;
975 /***********************************************************************
976 * MENU_ButtonDown
978 * Handle a button-down event in a menu. Point is in screen coords.
979 * hmenuCurrent is the top-most visible popup.
980 * Return TRUE if we can go on with menu tracking.
982 static BOOL MENU_ButtonDown( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent,
983 POINT pt )
985 POPUPMENU *menu;
986 MENUITEM *item;
987 WORD id;
989 if (!hmenu) return FALSE; /* Outside all menus */
990 menu = (POPUPMENU *) USER_HEAP_ADDR( hmenu );
991 item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
992 if (!item) /* Maybe in system menu */
994 if (!MENU_IsInSysMenu( menu, pt )) return FALSE;
995 id = SYSMENU_SELECTED;
998 if (menu->FocusedItem == id)
1000 if (id == SYSMENU_SELECTED) return FALSE;
1001 if (item->item_flags & MF_POPUP)
1003 if (item->item_flags & MF_MOUSESELECT)
1005 if (menu->wFlags & MF_POPUP)
1007 MENU_HideSubPopups( hmenu );
1008 *hmenuCurrent = hmenu;
1010 else return FALSE;
1012 else *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
1015 else
1017 MENU_HideSubPopups( hmenu );
1018 MENU_SelectItem( hmenu, id );
1019 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
1021 return TRUE;
1025 /***********************************************************************
1026 * MENU_ButtonUp
1028 * Handle a button-up event in a menu. Point is in screen coords.
1029 * hmenuCurrent is the top-most visible popup.
1030 * Return TRUE if we can go on with menu tracking.
1032 static BOOL MENU_ButtonUp( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent,
1033 POINT pt )
1035 POPUPMENU *menu;
1036 MENUITEM *item;
1037 HMENU hsubmenu;
1038 WORD id;
1040 if (!hmenu) return FALSE; /* Outside all menus */
1041 menu = (POPUPMENU *) USER_HEAP_ADDR( hmenu );
1042 item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
1043 if (!item) /* Maybe in system menu */
1045 if (!MENU_IsInSysMenu( menu, pt )) return FALSE;
1046 id = SYSMENU_SELECTED;
1047 hsubmenu = GetSystemMenu( menu->hWnd, FALSE );
1050 if (menu->FocusedItem != id) return FALSE;
1052 if (id != SYSMENU_SELECTED)
1054 if (!(item->item_flags & MF_POPUP))
1056 return MENU_ExecFocusedItem( hwndOwner, hmenu, hmenuCurrent );
1058 hsubmenu = item->item_id;
1060 /* Select first item of sub-popup */
1061 MENU_SelectItem( hsubmenu, NO_SELECTED_ITEM );
1062 MENU_SelectNextItem( hsubmenu );
1063 return TRUE;
1067 /***********************************************************************
1068 * MENU_MouseMove
1070 * Handle a motion event in a menu. Point is in screen coords.
1071 * hmenuCurrent is the top-most visible popup.
1072 * Return TRUE if we can go on with menu tracking.
1074 static BOOL MENU_MouseMove( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent,
1075 POINT pt )
1077 POPUPMENU *menu;
1078 MENUITEM *item;
1079 WORD id = NO_SELECTED_ITEM;
1081 if (hmenu)
1083 menu = (POPUPMENU *) USER_HEAP_ADDR( hmenu );
1084 item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
1085 if (!item) /* Maybe in system menu */
1087 if (!MENU_IsInSysMenu( menu, pt ))
1088 id = NO_SELECTED_ITEM; /* Outside all items */
1089 else id = SYSMENU_SELECTED;
1092 if (id == NO_SELECTED_ITEM)
1094 MENU_SelectItem( *hmenuCurrent, NO_SELECTED_ITEM );
1096 else if (menu->FocusedItem != id)
1098 MENU_HideSubPopups( hmenu );
1099 MENU_SelectItem( hmenu, id );
1100 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
1102 return TRUE;
1106 /***********************************************************************
1107 * MENU_KeyLeft
1109 * Handle a VK_LEFT key event in a menu.
1110 * hmenuCurrent is the top-most visible popup.
1112 static void MENU_KeyLeft( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent )
1114 POPUPMENU *menu;
1115 HMENU hmenutmp, hmenuprev;
1117 menu = (POPUPMENU *) USER_HEAP_ADDR( hmenu );
1118 hmenuprev = hmenutmp = hmenu;
1119 while (hmenutmp != *hmenuCurrent)
1121 hmenutmp = MENU_GetSubPopup( hmenuprev );
1122 if (hmenutmp != *hmenuCurrent) hmenuprev = hmenutmp;
1124 MENU_HideSubPopups( hmenuprev );
1126 if ((hmenuprev == hmenu) && !(menu->wFlags & MF_POPUP))
1128 /* Select previous item on the menu bar */
1129 MENU_SelectPrevItem( hmenu );
1130 if (*hmenuCurrent != hmenu)
1132 /* A popup menu was displayed -> display the next one */
1133 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, TRUE );
1136 else *hmenuCurrent = hmenuprev;
1140 /***********************************************************************
1141 * MENU_KeyRight
1143 * Handle a VK_RIGHT key event in a menu.
1144 * hmenuCurrent is the top-most visible popup.
1146 static void MENU_KeyRight( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent )
1148 POPUPMENU *menu;
1149 HMENU hmenutmp;
1151 menu = (POPUPMENU *) USER_HEAP_ADDR( hmenu );
1153 if ((menu->wFlags & MF_POPUP) || (*hmenuCurrent != hmenu))
1155 /* If already displaying a popup, try to display sub-popup */
1156 hmenutmp = MENU_ShowSubPopup( hwndOwner, *hmenuCurrent, TRUE );
1157 if (hmenutmp != *hmenuCurrent) /* Sub-popup displayed */
1159 *hmenuCurrent = hmenutmp;
1160 return;
1164 /* If on menu-bar, go to next item */
1165 if (!(menu->wFlags & MF_POPUP))
1167 MENU_HideSubPopups( hmenu );
1168 MENU_SelectNextItem( hmenu );
1169 if (*hmenuCurrent != hmenu)
1171 /* A popup menu was displayed -> display the next one */
1172 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, TRUE );
1175 else if (*hmenuCurrent != hmenu) /* Hide last level popup */
1177 HMENU hmenuprev;
1178 hmenuprev = hmenutmp = hmenu;
1179 while (hmenutmp != *hmenuCurrent)
1181 hmenutmp = MENU_GetSubPopup( hmenuprev );
1182 if (hmenutmp != *hmenuCurrent) hmenuprev = hmenutmp;
1184 MENU_HideSubPopups( hmenuprev );
1185 *hmenuCurrent = hmenuprev;
1190 /***********************************************************************
1191 * MENU_TrackMenu
1193 * Menu tracking code.
1194 * If 'x' and 'y' are not 0, we simulate a button-down event at (x,y)
1195 * before beginning tracking. This is to help menu-bar tracking.
1197 static BOOL MENU_TrackMenu( HMENU hmenu, WORD wFlags, int x, int y,
1198 HWND hwnd, LPRECT lprect )
1200 MSG msg;
1201 POPUPMENU *menu;
1202 HMENU hmenuCurrent = hmenu;
1203 BOOL fClosed = FALSE;
1204 WORD pos;
1206 fEndMenuCalled = FALSE;
1207 if (!(menu = (POPUPMENU *) USER_HEAP_ADDR( hmenu ))) return FALSE;
1208 if (x && y)
1210 POINT pt = { x, y };
1211 MENU_ButtonDown( hwnd, hmenu, &hmenuCurrent, pt );
1213 SetCapture( hwnd );
1215 while (!fClosed)
1217 if (!MSG_InternalGetMessage( &msg, 0, hwnd, MSGF_MENU, 0, TRUE ))
1218 break;
1220 if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
1222 /* Find the sub-popup for this mouse event (if any) */
1223 HMENU hsubmenu = MENU_FindMenuByCoords( hmenu, msg.pt );
1225 switch(msg.message)
1227 case WM_RBUTTONDOWN:
1228 case WM_NCRBUTTONDOWN:
1229 if (!(wFlags & TPM_RIGHTBUTTON)) break;
1230 /* fall through */
1231 case WM_LBUTTONDOWN:
1232 case WM_NCLBUTTONDOWN:
1233 fClosed = !MENU_ButtonDown( hwnd, hsubmenu,
1234 &hmenuCurrent, msg.pt );
1235 break;
1237 case WM_RBUTTONUP:
1238 case WM_NCRBUTTONUP:
1239 if (!(wFlags & TPM_RIGHTBUTTON)) break;
1240 /* fall through */
1241 case WM_LBUTTONUP:
1242 case WM_NCLBUTTONUP:
1243 /* If outside all menus but inside lprect, ignore it */
1244 if (!hsubmenu && lprect && PtInRect( lprect, msg.pt )) break;
1245 fClosed = !MENU_ButtonUp( hwnd, hsubmenu,
1246 &hmenuCurrent, msg.pt );
1247 break;
1249 case WM_MOUSEMOVE:
1250 case WM_NCMOUSEMOVE:
1251 if ((msg.wParam & MK_LBUTTON) ||
1252 ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON)))
1254 fClosed = !MENU_MouseMove( hwnd, hsubmenu,
1255 &hmenuCurrent, msg.pt );
1257 break;
1260 else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
1262 switch(msg.message)
1264 case WM_KEYDOWN:
1265 switch(msg.wParam)
1267 case VK_HOME:
1268 MENU_SelectItem( hmenuCurrent, NO_SELECTED_ITEM );
1269 MENU_SelectNextItem( hmenuCurrent );
1270 break;
1272 case VK_END:
1273 MENU_SelectItem( hmenuCurrent, NO_SELECTED_ITEM );
1274 MENU_SelectPrevItem( hmenuCurrent );
1275 break;
1277 case VK_UP:
1278 MENU_SelectPrevItem( hmenuCurrent );
1279 break;
1281 case VK_DOWN:
1282 /* If on menu bar, pull-down the menu */
1283 if (!(menu->wFlags & MF_POPUP) && (hmenuCurrent == hmenu))
1284 hmenuCurrent = MENU_ShowSubPopup( hwnd, hmenu, TRUE );
1285 else
1286 MENU_SelectNextItem( hmenuCurrent );
1287 break;
1289 case VK_LEFT:
1290 MENU_KeyLeft( hwnd, hmenu, &hmenuCurrent );
1291 break;
1293 case VK_RIGHT:
1294 MENU_KeyRight( hwnd, hmenu, &hmenuCurrent );
1295 break;
1297 case VK_SPACE:
1298 case VK_RETURN:
1299 fClosed = !MENU_ExecFocusedItem( hwnd, hmenuCurrent,
1300 &hmenuCurrent );
1301 break;
1303 case VK_ESCAPE:
1304 fClosed = TRUE;
1305 break;
1307 default:
1308 break;
1310 break; /* WM_KEYDOWN */
1312 case WM_SYSKEYDOWN:
1313 switch(msg.wParam)
1315 case VK_MENU:
1316 fClosed = TRUE;
1317 break;
1320 break; /* WM_SYSKEYDOWN */
1322 case WM_CHAR:
1324 /* Hack to avoid control chars. */
1325 /* We will find a better way real soon... */
1326 if ((msg.wParam <= 32) || (msg.wParam >= 127)) break;
1327 pos = MENU_FindItemByKey( hwnd, hmenuCurrent, msg.wParam );
1328 if (pos == (WORD)-2) fClosed = TRUE;
1329 else if (pos == (WORD)-1) MessageBeep(0);
1330 else
1332 MENU_SelectItem( hmenuCurrent, pos );
1333 fClosed = !MENU_ExecFocusedItem( hwnd, hmenuCurrent,
1334 &hmenuCurrent );
1338 break; /* WM_CHAR */
1339 } /* switch(msg.message) */
1341 else
1343 DispatchMessage( &msg );
1345 if (fEndMenuCalled) fClosed = TRUE;
1347 if (!fClosed) /* Remove the message from the queue */
1348 PeekMessage( &msg, 0, 0, 0, PM_REMOVE );
1350 ReleaseCapture();
1351 MENU_HideSubPopups( hmenu );
1352 if (menu->wFlags & MF_POPUP) ShowWindow( menu->hWnd, SW_HIDE );
1353 MENU_SelectItem( hmenu, NO_SELECTED_ITEM );
1354 fEndMenuCalled = FALSE;
1355 return TRUE;
1359 /***********************************************************************
1360 * MENU_TrackMouseMenuBar
1362 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
1364 void MENU_TrackMouseMenuBar( HWND hwnd, POINT pt )
1366 WND *wndPtr = WIN_FindWndPtr( hwnd );
1367 SendMessage( hwnd, WM_ENTERMENULOOP, 0, 0 );
1368 MENU_TrackMenu( (HMENU)wndPtr->wIDmenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
1369 pt.x, pt.y, hwnd, NULL );
1370 SendMessage( hwnd, WM_EXITMENULOOP, 0, 0 );
1374 /***********************************************************************
1375 * MENU_TrackKbdMenuBar
1377 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
1379 void MENU_TrackKbdMenuBar( HWND hwnd, WORD wParam )
1381 WND *wndPtr = WIN_FindWndPtr( hwnd );
1382 SendMessage( hwnd, WM_ENTERMENULOOP, 0, 0 );
1383 /* Select first selectable item */
1384 MENU_SelectItem( wndPtr->wIDmenu, NO_SELECTED_ITEM );
1385 MENU_SelectNextItem( (HMENU)wndPtr->wIDmenu );
1386 MENU_TrackMenu( (HMENU)wndPtr->wIDmenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
1387 0, 0, hwnd, NULL );
1388 SendMessage( hwnd, WM_EXITMENULOOP, 0, 0 );
1392 /**********************************************************************
1393 * TrackPopupMenu [USER.416]
1395 BOOL TrackPopupMenu( HMENU hMenu, WORD wFlags, short x, short y,
1396 short nReserved, HWND hWnd, LPRECT lpRect )
1398 if (!MENU_ShowPopup( hWnd, hMenu, 0, x, y )) return FALSE;
1399 return MENU_TrackMenu( hMenu, wFlags, 0, 0, hWnd, lpRect );
1403 /***********************************************************************
1404 * PopupMenuWndProc
1406 LONG PopupMenuWndProc( HWND hwnd, WORD message, WORD wParam, LONG lParam )
1408 switch(message)
1410 case WM_CREATE:
1412 CREATESTRUCT *createStruct = (CREATESTRUCT *)lParam;
1413 HMENU hmenu = (HMENU) ((int)createStruct->lpCreateParams & 0xffff);
1414 SetWindowWord( hwnd, 0, hmenu );
1415 return 0;
1418 case WM_MOUSEACTIVATE: /* We don't want to be activated */
1419 return MA_NOACTIVATE;
1421 case WM_PAINT:
1423 PAINTSTRUCT ps;
1424 BeginPaint( hwnd, &ps );
1425 MENU_DrawPopupMenu( hwnd, ps.hdc,
1426 (HMENU)GetWindowWord( hwnd, 0 ) );
1427 EndPaint( hwnd, &ps );
1428 return 0;
1431 default:
1432 return DefWindowProc(hwnd, message, wParam, lParam);
1434 return 0;
1438 /***********************************************************************
1439 * MENU_GetMenuBarHeight
1441 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
1443 WORD MENU_GetMenuBarHeight( HWND hwnd, WORD menubarWidth, int orgX, int orgY )
1445 HDC hdc;
1446 RECT rectBar;
1447 WND *wndPtr;
1448 LPPOPUPMENU lppop;
1450 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
1451 if (!(lppop = (LPPOPUPMENU)USER_HEAP_ADDR( wndPtr->wIDmenu ))) return 0;
1452 hdc = GetDC( hwnd );
1453 SetRect( &rectBar, orgX, orgY, orgX+menubarWidth, orgY+SYSMETRICS_CYMENU );
1454 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
1455 ReleaseDC( hwnd, hdc );
1456 return lppop->Height;
1460 /**********************************************************************
1461 * ChangeMenu [USER.153]
1463 BOOL ChangeMenu(HMENU hMenu, WORD nPos, LPSTR lpNewItem,
1464 WORD wItemID, WORD wFlags)
1466 if (wFlags & MF_APPEND)
1467 return AppendMenu(hMenu, wFlags, wItemID, lpNewItem);
1468 if (wFlags & MF_DELETE)
1469 return DeleteMenu(hMenu, wItemID, wFlags);
1470 if (wFlags & MF_INSERT)
1471 return InsertMenu(hMenu, nPos, wFlags, wItemID, lpNewItem);
1472 if (wFlags & MF_CHANGE)
1473 return ModifyMenu(hMenu, nPos, wFlags, wItemID, lpNewItem);
1474 if (wFlags & MF_REMOVE)
1475 return RemoveMenu(hMenu, wItemID, wFlags);
1476 return FALSE;
1480 /**********************************************************************
1481 * CheckMenuItem [USER.154]
1483 BOOL CheckMenuItem(HMENU hMenu, WORD wItemID, WORD wFlags)
1485 LPMENUITEM lpitem;
1486 dprintf_menu(stddeb,"CheckMenuItem (%04X, %04X, %04X) !\n",
1487 hMenu, wItemID, wFlags);
1488 if (!(lpitem = MENU_FindItem(&hMenu, &wItemID, wFlags))) return FALSE;
1489 if (wFlags & MF_CHECKED) lpitem->item_flags |= MF_CHECKED;
1490 else lpitem->item_flags &= ~MF_CHECKED;
1491 return TRUE;
1495 /**********************************************************************
1496 * EnableMenuItem [USER.155]
1498 BOOL EnableMenuItem(HMENU hMenu, WORD wItemID, WORD wFlags)
1500 LPMENUITEM lpitem;
1501 dprintf_menu(stddeb,"EnableMenuItem (%04X, %04X, %04X) !\n",
1502 hMenu, wItemID, wFlags);
1503 if (!(lpitem = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return FALSE;
1505 /* We can't have MF_GRAYED and MF_DISABLED together */
1506 if (wFlags & MF_GRAYED)
1508 lpitem->item_flags = (lpitem->item_flags & ~MF_DISABLED) | MF_GRAYED;
1510 else if (wFlags & MF_DISABLED)
1512 lpitem->item_flags = (lpitem->item_flags & ~MF_GRAYED) | MF_DISABLED;
1514 else /* MF_ENABLED */
1516 lpitem->item_flags &= ~(MF_GRAYED | MF_DISABLED);
1518 return TRUE;
1522 /**********************************************************************
1523 * GetMenuString [USER.161]
1525 int GetMenuString(HMENU hMenu, WORD wItemID,
1526 LPSTR str, short nMaxSiz, WORD wFlags)
1528 LPMENUITEM lpitem;
1529 int maxsiz;
1530 dprintf_menu(stddeb,"GetMenuString(%04X, %04X, %08X, %d, %04X);\n",
1531 hMenu, wItemID, str, nMaxSiz, wFlags);
1532 if (str == NULL) return FALSE;
1533 lpitem = MENU_FindItem( &hMenu, &wItemID, wFlags );
1534 if (lpitem != NULL) {
1535 if (lpitem->item_text != NULL) {
1536 maxsiz = min(nMaxSiz - 1, strlen(lpitem->item_text));
1537 strncpy(str, lpitem->item_text, maxsiz + 1);
1539 else
1540 maxsiz = 0;
1541 dprintf_menu(stddeb,"GetMenuString // Found !\n");
1542 return maxsiz;
1544 return 0;
1548 /**********************************************************************
1549 * HiliteMenuItem [USER.162]
1551 BOOL HiliteMenuItem(HWND hWnd, HMENU hMenu, WORD wItemID, WORD wHilite)
1553 LPPOPUPMENU menu;
1554 LPMENUITEM lpitem;
1555 dprintf_menu(stddeb,"HiliteMenuItem(%04X, %04X, %04X, %04X);\n",
1556 hWnd, hMenu, wItemID, wHilite);
1557 if (!(lpitem = MENU_FindItem( &hMenu, &wItemID, wHilite ))) return FALSE;
1558 if (!(menu = (LPPOPUPMENU) USER_HEAP_ADDR(hMenu))) return FALSE;
1559 if (menu->FocusedItem == wItemID) return TRUE;
1560 MENU_HideSubPopups( hMenu );
1561 MENU_SelectItem( hMenu, wItemID );
1562 return TRUE;
1566 /**********************************************************************
1567 * GetMenuState [USER.250]
1569 WORD GetMenuState(HMENU hMenu, WORD wItemID, WORD wFlags)
1571 LPMENUITEM lpitem;
1572 dprintf_menu(stddeb,"GetMenuState(%04X, %04X, %04X);\n",
1573 hMenu, wItemID, wFlags);
1574 if (!(lpitem = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
1575 if (lpitem->item_flags & MF_POPUP)
1577 POPUPMENU *menu = (POPUPMENU *) USER_HEAP_ADDR( lpitem->item_id );
1578 if (!menu) return -1;
1579 else return (menu->nItems << 8) | (menu->wFlags & 0xff);
1581 else return lpitem->item_flags;
1585 /**********************************************************************
1586 * GetMenuItemCount [USER.263]
1588 WORD GetMenuItemCount(HMENU hMenu)
1590 LPPOPUPMENU menu;
1591 dprintf_menu(stddeb,"GetMenuItemCount(%04X);\n", hMenu);
1592 menu = (LPPOPUPMENU) USER_HEAP_ADDR(hMenu);
1593 if (menu == NULL) return (WORD)-1;
1594 dprintf_menu(stddeb,"GetMenuItemCount(%04X) return %d \n",
1595 hMenu, menu->nItems);
1596 return menu->nItems;
1600 /**********************************************************************
1601 * GetMenuItemID [USER.264]
1603 WORD GetMenuItemID(HMENU hMenu, int nPos)
1605 LPPOPUPMENU menu;
1606 MENUITEM *item;
1608 dprintf_menu(stddeb,"GetMenuItemID(%04X, %d);\n", hMenu, nPos);
1609 if (!(menu = (LPPOPUPMENU) USER_HEAP_ADDR(hMenu))) return -1;
1610 if ((nPos < 0) || (nPos >= menu->nItems)) return -1;
1611 item = (MENUITEM *) USER_HEAP_ADDR( menu->hItems );
1612 if (item[nPos].item_flags & MF_POPUP) return -1;
1613 return item[nPos].item_id;
1617 /**********************************************************************
1618 * InsertMenu [USER.410]
1620 BOOL InsertMenu(HMENU hMenu, WORD nPos, WORD wFlags, WORD wItemID, LPSTR lpNewItem)
1622 HANDLE hNewItems;
1623 MENUITEM *lpitem, *newItems;
1624 LPPOPUPMENU menu;
1626 if (IS_STRING_ITEM(wFlags))
1627 dprintf_menu(stddeb,"InsertMenu (%04X, %04X, %04X, '%s') !\n",
1628 hMenu, wFlags, wItemID, lpNewItem);
1629 else
1630 dprintf_menu(stddeb,"InsertMenu (%04X, %04X, %04X, %04X, %08X) !\n",
1631 hMenu, nPos, wFlags, wItemID, lpNewItem);
1633 /* Find where to insert new item */
1635 if ((wFlags & MF_BYPOSITION) && (nPos == (WORD)-1))
1637 /* Special case: append to menu */
1638 if (!(menu = (LPPOPUPMENU) USER_HEAP_ADDR(hMenu))) return FALSE;
1639 nPos = menu->nItems;
1641 else
1643 if (!MENU_FindItem( &hMenu, &nPos, wFlags )) return FALSE;
1644 if (!(menu = (LPPOPUPMENU) USER_HEAP_ADDR(hMenu))) return FALSE;
1647 /* Create new items array */
1649 hNewItems = USER_HEAP_ALLOC( GMEM_MOVEABLE,
1650 sizeof(MENUITEM) * (menu->nItems+1) );
1651 if (!hNewItems) return FALSE;
1652 newItems = (MENUITEM *) USER_HEAP_ADDR( hNewItems );
1653 if (menu->nItems > 0)
1655 /* Copy the old array into the new */
1656 MENUITEM *oldItems = (MENUITEM *) USER_HEAP_ADDR( menu->hItems );
1657 if (nPos > 0) memcpy( newItems, oldItems, nPos * sizeof(MENUITEM) );
1658 if (nPos < menu->nItems) memcpy( &newItems[nPos+1], &oldItems[nPos],
1659 (menu->nItems-nPos)*sizeof(MENUITEM) );
1661 USER_HEAP_FREE( menu->hItems );
1663 menu->hItems = hNewItems;
1664 menu->nItems++;
1666 /* Store the new item data */
1668 lpitem = &newItems[nPos];
1669 lpitem->item_flags = wFlags & ~(MF_HILITE | MF_MOUSESELECT);
1670 lpitem->item_id = wItemID;
1672 if (IS_STRING_ITEM(wFlags))
1674 /* Item beginning with a backspace is a help item */
1675 if (lpNewItem[0] == '\b')
1677 lpitem->item_flags |= MF_HELP;
1678 lpNewItem++;
1680 lpitem->hText = USER_HEAP_ALLOC( GMEM_MOVEABLE, strlen(lpNewItem)+1 );
1681 lpitem->item_text = (char *)USER_HEAP_ADDR( lpitem->hText );
1682 strcpy( lpitem->item_text, lpNewItem );
1684 else if (wFlags & MF_BITMAP) lpitem->hText = LOWORD((DWORD)lpNewItem);
1685 else lpitem->item_text = lpNewItem;
1687 if (wFlags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
1688 ((POPUPMENU *)USER_HEAP_ADDR(wItemID))->wFlags |= MF_POPUP;
1690 SetRectEmpty( &lpitem->rect );
1691 lpitem->hCheckBit = hStdCheck;
1692 lpitem->hUnCheckBit = 0;
1693 return TRUE;
1697 /**********************************************************************
1698 * AppendMenu [USER.411]
1700 BOOL AppendMenu(HMENU hMenu, WORD wFlags, WORD wItemID, LPSTR lpNewItem)
1702 return InsertMenu( hMenu, -1, wFlags | MF_BYPOSITION, wItemID, lpNewItem );
1706 /**********************************************************************
1707 * RemoveMenu [USER.412]
1709 BOOL RemoveMenu(HMENU hMenu, WORD nPos, WORD wFlags)
1711 LPPOPUPMENU menu;
1712 LPMENUITEM lpitem;
1713 dprintf_menu(stddeb,"RemoveMenu (%04X, %04X, %04X) !\n",
1714 hMenu, nPos, wFlags);
1715 if (!(lpitem = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
1716 if (!(menu = (LPPOPUPMENU) USER_HEAP_ADDR(hMenu))) return FALSE;
1718 /* Remove item */
1720 if (IS_STRING_ITEM(lpitem->item_flags)) USER_HEAP_FREE( lpitem->hText );
1721 if (--menu->nItems == 0)
1723 USER_HEAP_FREE( menu->hItems );
1724 menu->hItems = 0;
1726 else
1728 while(nPos < menu->nItems)
1730 *lpitem = *(lpitem+1);
1731 lpitem++;
1732 nPos++;
1734 menu->hItems = USER_HEAP_REALLOC( menu->hItems,
1735 menu->nItems * sizeof(MENUITEM),
1736 GMEM_MOVEABLE );
1738 return TRUE;
1742 /**********************************************************************
1743 * DeleteMenu [USER.413]
1745 BOOL DeleteMenu(HMENU hMenu, WORD nPos, WORD wFlags)
1747 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
1748 if (!item) return FALSE;
1749 if (item->item_flags & MF_POPUP) DestroyMenu( item->item_id );
1750 /* nPos is now the position of the item */
1751 RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
1752 return TRUE;
1756 /**********************************************************************
1757 * ModifyMenu [USER.414]
1759 BOOL ModifyMenu(HMENU hMenu, WORD nPos, WORD wFlags, WORD wItemID, LPSTR lpNewItem)
1761 LPMENUITEM lpitem;
1762 if (IS_STRING_ITEM(wFlags))
1763 dprintf_menu(stddeb,"ModifyMenu (%04X, %04X, %04X, %04X, '%s') !\n",
1764 hMenu, nPos, wFlags, wItemID, lpNewItem);
1765 else
1766 dprintf_menu(stddeb,"ModifyMenu (%04X, %04X, %04X, %04X, %08X) !\n",
1767 hMenu, nPos, wFlags, wItemID, lpNewItem);
1768 if (!(lpitem = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
1770 if (IS_STRING_ITEM(lpitem->item_flags)) USER_HEAP_FREE( lpitem->hText );
1771 lpitem->item_flags = wFlags & ~(MF_HILITE | MF_MOUSESELECT);
1772 lpitem->item_id = wItemID;
1774 if (IS_STRING_ITEM(wFlags))
1776 lpitem->hText = USER_HEAP_ALLOC( GMEM_MOVEABLE, strlen(lpNewItem)+1 );
1777 lpitem->item_text = (char *)USER_HEAP_ADDR( lpitem->hText );
1778 strcpy( lpitem->item_text, lpNewItem );
1780 else if (wFlags & MF_BITMAP) lpitem->hText = LOWORD((DWORD)lpNewItem);
1781 else lpitem->item_text = lpNewItem;
1782 SetRectEmpty( &lpitem->rect );
1783 return TRUE;
1787 /**********************************************************************
1788 * CreatePopupMenu [USER.415]
1790 HMENU CreatePopupMenu()
1792 HMENU hmenu;
1793 POPUPMENU *menu;
1795 if (!(hmenu = CreateMenu())) return 0;
1796 menu = (POPUPMENU *) USER_HEAP_ADDR( hmenu );
1797 menu->wFlags |= MF_POPUP;
1798 return hmenu;
1802 /**********************************************************************
1803 * GetMenuCheckMarkDimensions [USER.417]
1805 DWORD GetMenuCheckMarkDimensions()
1807 return MAKELONG( check_bitmap_width, check_bitmap_height );
1811 /**********************************************************************
1812 * SetMenuItemBitmaps [USER.418]
1814 BOOL SetMenuItemBitmaps(HMENU hMenu, WORD nPos, WORD wFlags,
1815 HBITMAP hNewCheck, HBITMAP hNewUnCheck)
1817 LPMENUITEM lpitem;
1818 dprintf_menu(stddeb,"SetMenuItemBitmaps (%04X, %04X, %04X, %04X, %08X) !\n",
1819 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
1820 if (!(lpitem = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
1822 if (!hNewCheck && !hNewUnCheck)
1824 /* If both are NULL, restore default bitmaps */
1825 lpitem->hCheckBit = hStdCheck;
1826 lpitem->hUnCheckBit = 0;
1827 lpitem->item_flags &= ~MF_USECHECKBITMAPS;
1829 else /* Install new bitmaps */
1831 lpitem->hCheckBit = hNewCheck;
1832 lpitem->hUnCheckBit = hNewUnCheck;
1833 lpitem->item_flags |= MF_USECHECKBITMAPS;
1835 return TRUE;
1839 /**********************************************************************
1840 * CreateMenu [USER.151]
1842 HMENU CreateMenu()
1844 HMENU hMenu;
1845 LPPOPUPMENU menu;
1846 dprintf_menu(stddeb,"CreateMenu !\n");
1847 if (!(hMenu = USER_HEAP_ALLOC( GMEM_MOVEABLE, sizeof(POPUPMENU) )))
1848 return 0;
1849 menu = (LPPOPUPMENU) USER_HEAP_ADDR(hMenu);
1850 menu->hNext = 0;
1851 menu->wFlags = 0;
1852 menu->wMagic = MENU_MAGIC;
1853 menu->hTaskQ = 0;
1854 menu->Width = 0;
1855 menu->Height = 0;
1856 menu->nItems = 0;
1857 menu->hWnd = 0;
1858 menu->hItems = 0;
1859 menu->FocusedItem = NO_SELECTED_ITEM;
1860 dprintf_menu(stddeb,"CreateMenu // return %04X\n", hMenu);
1861 return hMenu;
1865 /**********************************************************************
1866 * DestroyMenu [USER.152]
1868 BOOL DestroyMenu(HMENU hMenu)
1870 LPPOPUPMENU lppop;
1871 dprintf_menu(stddeb,"DestroyMenu (%04X) !\n", hMenu);
1872 if (hMenu == 0) return FALSE;
1873 lppop = (LPPOPUPMENU) USER_HEAP_ADDR(hMenu);
1874 if (lppop == NULL) return FALSE;
1875 if (lppop->hWnd) DestroyWindow (lppop->hWnd);
1877 if (lppop->hItems)
1879 int i;
1880 MENUITEM *item = (MENUITEM *) USER_HEAP_ADDR( lppop->hItems );
1881 for (i = lppop->nItems; i > 0; i--, item++)
1883 if (item->item_flags & MF_POPUP)
1884 DestroyMenu( item->item_id );
1886 USER_HEAP_FREE( lppop->hItems );
1888 USER_HEAP_FREE( hMenu );
1889 dprintf_menu(stddeb,"DestroyMenu (%04X) // End !\n", hMenu);
1890 return TRUE;
1893 /**********************************************************************
1894 * GetSystemMenu [USER.156]
1896 HMENU GetSystemMenu(HWND hWnd, BOOL bRevert)
1898 WND *wndPtr;
1899 wndPtr = WIN_FindWndPtr(hWnd);
1900 if (!bRevert) {
1901 return wndPtr->hSysMenu;
1903 else {
1904 DestroyMenu(wndPtr->hSysMenu);
1905 wndPtr->hSysMenu = CopySysMenu();
1907 return wndPtr->hSysMenu;
1910 /**********************************************************************
1911 * SetSystemMenu [USER.280]
1913 BOOL SetSystemMenu(HWND hWnd, HMENU newHmenu)
1915 WND *wndPtr;
1917 if ((wndPtr = WIN_FindWndPtr(hWnd)) != NULL)
1918 wndPtr->hSysMenu = newHmenu;
1922 /**********************************************************************
1923 * GetMenu [USER.157]
1925 HMENU GetMenu(HWND hWnd)
1927 WND * wndPtr = WIN_FindWndPtr(hWnd);
1928 if (wndPtr == NULL) return 0;
1929 return wndPtr->wIDmenu;
1933 /**********************************************************************
1934 * SetMenu [USER.158]
1936 BOOL SetMenu(HWND hWnd, HMENU hMenu)
1938 LPPOPUPMENU lpmenu;
1939 WND * wndPtr = WIN_FindWndPtr(hWnd);
1940 if (wndPtr == NULL) {
1941 fprintf(stderr,"SetMenu(%04X, %04X) // Bad window handle !\n",
1942 hWnd, hMenu);
1943 return FALSE;
1945 dprintf_menu(stddeb,"SetMenu(%04X, %04X);\n", hWnd, hMenu);
1946 if (GetCapture() == hWnd) ReleaseCapture();
1947 wndPtr->wIDmenu = hMenu;
1948 if (hMenu != 0)
1950 lpmenu = (LPPOPUPMENU) USER_HEAP_ADDR(hMenu);
1951 if (lpmenu == NULL) {
1952 fprintf(stderr,"SetMenu(%04X, %04X) // Bad menu handle !\n",
1953 hWnd, hMenu);
1954 return FALSE;
1956 lpmenu->hWnd = hWnd;
1957 lpmenu->wFlags &= ~MF_POPUP; /* Can't be a popup */
1958 lpmenu->Height = 0; /* Make sure we recalculate the size */
1960 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
1961 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
1962 return TRUE;
1967 /**********************************************************************
1968 * GetSubMenu [USER.159]
1970 HMENU GetSubMenu(HMENU hMenu, short nPos)
1972 LPPOPUPMENU lppop;
1973 LPMENUITEM lpitem;
1974 dprintf_menu(stddeb,"GetSubMenu (%04X, %04X) !\n", hMenu, nPos);
1975 if (!(lppop = (LPPOPUPMENU) USER_HEAP_ADDR(hMenu))) return 0;
1976 if ((WORD)nPos >= lppop->nItems) return 0;
1977 lpitem = (MENUITEM *) USER_HEAP_ADDR( lppop->hItems );
1978 if (!(lpitem[nPos].item_flags & MF_POPUP)) return 0;
1979 return lpitem[nPos].item_id;
1983 /**********************************************************************
1984 * DrawMenuBar [USER.160]
1986 void DrawMenuBar(HWND hWnd)
1988 WND *wndPtr;
1989 LPPOPUPMENU lppop;
1990 dprintf_menu(stddeb,"DrawMenuBar (%04X)\n", hWnd);
1991 wndPtr = WIN_FindWndPtr(hWnd);
1992 if (wndPtr != NULL && (wndPtr->dwStyle & WS_CHILD) == 0 &&
1993 wndPtr->wIDmenu != 0) {
1994 dprintf_menu(stddeb,"DrawMenuBar wIDmenu=%04X \n",
1995 wndPtr->wIDmenu);
1996 lppop = (LPPOPUPMENU) USER_HEAP_ADDR(wndPtr->wIDmenu);
1997 if (lppop == NULL) return;
1999 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
2000 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
2001 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
2006 /***********************************************************************
2007 * EndMenu (USER.187)
2009 void EndMenu(void)
2011 /* Note: this won't work when we have multiple tasks... */
2012 fEndMenuCalled = TRUE;
2016 /***********************************************************************
2017 * LookupMenuHandle (USER.217)
2019 HMENU LookupMenuHandle( HMENU hmenu, INT id )
2021 if (!MENU_FindItem( &hmenu, &id, MF_BYCOMMAND )) return 0;
2022 else return hmenu;
2026 /**********************************************************************
2027 * LoadMenuIndirect [USER.220]
2029 HMENU LoadMenuIndirect(LPSTR menu_template)
2031 HMENU hMenu;
2032 MENU_HEADER *menu_desc;
2033 dprintf_menu(stddeb,"LoadMenuIndirect: menu_template '%08X'\n",
2034 menu_template);
2035 hMenu = CreateMenu();
2036 menu_desc = (MENU_HEADER *)menu_template;
2037 ParseMenuResource((WORD *)(menu_desc + 1), 0, hMenu);
2038 return hMenu;
2042 /**********************************************************************
2043 * CopySysMenu (Internal)
2045 HMENU CopySysMenu()
2047 HMENU hMenu;
2048 LPPOPUPMENU sysmenu, menu;
2049 MENUITEM *item;
2050 int i;
2052 sysmenu = (LPPOPUPMENU) USER_HEAP_ADDR(hSysMenu);
2053 if (!(hMenu = CreatePopupMenu())) return 0;
2054 menu = (POPUPMENU *) USER_HEAP_ADDR( hMenu );
2055 menu->wFlags |= MF_SYSMENU;
2056 item = (MENUITEM *) USER_HEAP_ADDR( sysmenu->hItems );
2057 for (i = 0; i < sysmenu->nItems; i++, item++)
2059 AppendMenu( hMenu, item->item_flags, item->item_id, item->item_text );
2062 dprintf_menu(stddeb,"CopySysMenu hMenu=%04X !\n", hMenu);
2063 return hMenu;
2067 /**********************************************************************
2068 * ParseMenuResource (from Resource or Template)
2070 WORD * ParseMenuResource(WORD *first_item, int level, HMENU hMenu)
2072 WORD *item;
2073 WORD *next_item;
2074 HMENU hSubMenu;
2075 int i;
2077 level++;
2078 next_item = first_item;
2079 i = 0;
2080 do {
2081 i++;
2082 item = next_item;
2083 if (*item & MF_POPUP) {
2084 MENU_POPUPITEM *popup_item = (MENU_POPUPITEM *) item;
2085 next_item = (WORD *) (popup_item->item_text +
2086 strlen(popup_item->item_text) + 1);
2087 hSubMenu = CreatePopupMenu();
2088 next_item = ParseMenuResource(next_item, level, hSubMenu);
2089 AppendMenu(hMenu, popup_item->item_flags,
2090 hSubMenu, popup_item->item_text);
2092 else {
2093 MENUITEMTEMPLATE *normal_item = (MENUITEMTEMPLATE *) item;
2094 next_item = (WORD *) (normal_item->item_text +
2095 strlen(normal_item->item_text) + 1);
2096 if (strlen(normal_item->item_text) == 0 && normal_item->item_id == 0)
2097 normal_item->item_flags |= MF_SEPARATOR;
2098 AppendMenu(hMenu, normal_item->item_flags,
2099 normal_item->item_id, normal_item->item_text);
2102 while (!(*item & MF_END));
2103 return next_item;
2107 /**********************************************************************
2108 * IsMenu (USER.358)
2110 BOOL IsMenu( HMENU hmenu )
2112 LPPOPUPMENU menu;
2113 if (!(menu = (LPPOPUPMENU) USER_HEAP_ADDR( hmenu ))) return FALSE;
2114 return (menu->wMagic == MENU_MAGIC);