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