4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
9 * Note: the style MF_MOUSESELECT is used to mark popup items that
10 * have been selected, i.e. their popup menu is currently displayed.
11 * This is probably not the meaning this style has in MS-Windows.
20 #include "sysmetrics.h"
30 #include "stackframe.h"
34 /* Dimension of the menu bitmaps */
35 static WORD check_bitmap_width = 0, check_bitmap_height = 0;
36 static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
38 /* Flag set by EndMenu() to force an exit from menu tracking */
39 static BOOL fEndMenuCalled = FALSE;
41 /* Space between 2 menu bar items */
42 #define MENU_BAR_ITEMS_SPACE 16
44 /* Minimum width of a tab character */
45 #define MENU_TAB_SPACE 8
47 /* Height of a separator item */
48 #define SEPARATOR_HEIGHT 5
50 /* Values for menu->FocusedItem */
51 /* (other values give the position of the focused item) */
52 #define NO_SELECTED_ITEM 0xffff
53 #define SYSMENU_SELECTED 0xfffe /* Only valid on menu-bars */
55 #define IS_STRING_ITEM(flags) (!((flags) & (MF_BITMAP | MF_OWNERDRAW | \
56 MF_MENUBARBREAK | MF_MENUBREAK | MF_SEPARATOR)))
58 #define SET_OWNERDRAW_DATA(item,data) \
59 ((item)->hText = LOWORD((DWORD)(data)), (item)->xTab = HIWORD((DWORD)(data)))
61 #define GET_OWNERDRAW_DATA(item) \
62 ((DWORD)MAKELONG( (WORD)(item)->hText, (item)->xTab ))
64 extern void NC_DrawSysButton(HWND hwnd, HDC hdc, BOOL down); /* nonclient.c */
65 static HMENU MENU_CopySysMenu(void);
67 static HBITMAP hStdCheck = 0;
68 static HBITMAP hStdMnArrow = 0;
69 static HMENU MENU_DefSysMenu = 0; /* Default system menu */
72 /* we _can_ use global popup window because there's no way 2 menues can
73 * be tracked at the same time.
76 static WND* pTopPWnd = 0;
77 static UINT uSubPWndLevel = 0;
79 /***********************************************************************
82 * Menus initialisation.
90 if (!(hStdCheck = LoadBitmap( 0, MAKEINTRESOURCE(OBM_CHECK) )))
92 GetObject( hStdCheck, sizeof(BITMAP), (LPSTR)&bm );
93 check_bitmap_width = bm.bmWidth;
94 check_bitmap_height = bm.bmHeight;
95 if (!(hStdMnArrow = LoadBitmap( 0, MAKEINTRESOURCE(OBM_MNARROW) )))
97 GetObject( hStdMnArrow, sizeof(BITMAP), (LPSTR)&bm );
98 arrow_bitmap_width = bm.bmWidth;
99 arrow_bitmap_height = bm.bmHeight;
101 if (!(MENU_DefSysMenu = MENU_CopySysMenu()))
103 fprintf( stderr, "Unable to create default system menu\n" );
110 /***********************************************************************
113 * Return the default system menu.
115 HMENU MENU_GetDefSysMenu(void)
117 return MENU_DefSysMenu;
121 /***********************************************************************
124 * Check whether the window owning the menu bar has a system menu.
126 static BOOL MENU_HasSysMenu( POPUPMENU *menu )
130 if (menu->wFlags & MF_POPUP) return FALSE;
131 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return FALSE;
132 return (wndPtr->dwStyle & WS_SYSMENU) != 0;
136 /**********************************************************************
139 static HMENU MENU_CopySysMenu(void)
145 if (!(handle = SYSRES_LoadResource( SYSRES_MENU_SYSMENU ))) return 0;
146 hMenu = LoadMenuIndirect( WIN16_GlobalLock16( handle ) );
147 SYSRES_FreeResource( handle );
150 dprintf_menu(stddeb,"No SYSMENU\n");
153 menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hMenu);
154 menu->wFlags |= MF_SYSMENU | MF_POPUP;
155 dprintf_menu(stddeb,"CopySysMenu hMenu=%04x !\n", hMenu);
160 /***********************************************************************
163 * Check whether the point (in screen coords) is in the system menu
164 * of the window owning the given menu.
166 static BOOL MENU_IsInSysMenu( POPUPMENU *menu, POINT pt )
170 if (menu->wFlags & MF_POPUP) return FALSE;
171 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return FALSE;
172 if (!(wndPtr->dwStyle & WS_SYSMENU)) return FALSE;
173 if ((pt.x < wndPtr->rectClient.left) ||
174 (pt.x >= wndPtr->rectClient.left+SYSMETRICS_CXSIZE+SYSMETRICS_CXBORDER))
176 if ((pt.y >= wndPtr->rectClient.top - menu->Height) ||
177 (pt.y < wndPtr->rectClient.top - menu->Height -
178 SYSMETRICS_CYSIZE - SYSMETRICS_CYBORDER)) return FALSE;
183 /***********************************************************************
186 * Find a menu item. Return a pointer on the item, and modifies *hmenu
187 * in case the item was in a sub-menu.
189 static MENUITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
195 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(*hmenu))) return NULL;
196 item = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
197 if (wFlags & MF_BYPOSITION)
199 if (*nPos >= menu->nItems) return NULL;
204 for (i = 0; i < menu->nItems; i++, item++)
206 if (item->item_id == *nPos)
211 else if (item->item_flags & MF_POPUP)
213 HMENU hsubmenu = (HMENU)item->item_id;
214 MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
227 /***********************************************************************
228 * MENU_FindItemByCoords
230 * Find the item at the specified coordinates (screen coords).
232 static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu, int x, int y, UINT *pos )
238 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return NULL;
239 x -= wndPtr->rectWindow.left;
240 y -= wndPtr->rectWindow.top;
241 item = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
242 for (i = 0; i < menu->nItems; i++, item++)
244 if ((x >= item->rect.left) && (x < item->rect.right) &&
245 (y >= item->rect.top) && (y < item->rect.bottom))
255 /***********************************************************************
258 * Find the menu item selected by a key press.
259 * Return item id, -1 if none, -2 if we should close the menu.
261 static UINT MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu, UINT key )
268 if (!IsMenu( hmenu )) hmenu = WIN_FindWndPtr(hwndOwner)->hSysMenu;
269 if (!hmenu) return -1;
271 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
272 lpitem = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
274 for (i = 0; i < menu->nItems; i++, lpitem++)
276 if (IS_STRING_ITEM(lpitem->item_flags))
278 char *p = strchr( (char *)USER_HEAP_LIN_ADDR(lpitem->hText), '&' );
279 if (p && (p[1] != '&') && (toupper(p[1]) == key)) return i;
283 menuchar = SendMessage( hwndOwner, WM_MENUCHAR,
284 MAKEWPARAM(key,menu->wFlags), hmenu );
286 menuchar = SendMessage( hwndOwner, WM_MENUCHAR, key,
287 MAKELONG( menu->wFlags, hmenu ) );
289 if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
290 if (HIWORD(menuchar) == 1) return -2;
295 /***********************************************************************
298 * Calculate the size of the menu item and store it in lpitem->rect.
300 static void MENU_CalcItemSize( HDC hdc, LPMENUITEM lpitem, HWND hwndOwner,
301 int orgX, int orgY, BOOL menuBar )
306 SetRect( &lpitem->rect, orgX, orgY, orgX, orgY );
308 if (lpitem->item_flags & MF_OWNERDRAW)
310 MEASUREITEMSTRUCT mis;
311 mis.CtlType = ODT_MENU;
312 mis.itemID = lpitem->item_id;
313 mis.itemData = GET_OWNERDRAW_DATA(lpitem);
316 SendMessage( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)MAKE_SEGPTR(&mis) );
317 lpitem->rect.bottom += mis.itemHeight;
318 lpitem->rect.right += mis.itemWidth;
319 dprintf_menu( stddeb, "DrawMenuItem: MeasureItem %04x %dx%d!\n",
320 lpitem->item_id, mis.itemWidth, mis.itemHeight );
324 if (lpitem->item_flags & MF_SEPARATOR)
326 lpitem->rect.bottom += SEPARATOR_HEIGHT;
332 lpitem->rect.right += 2 * check_bitmap_width;
333 if (lpitem->item_flags & MF_POPUP)
334 lpitem->rect.right += arrow_bitmap_width;
337 if (lpitem->item_flags & MF_BITMAP)
340 if (GetObject( (HBITMAP)lpitem->hText, sizeof(BITMAP), (LPSTR)&bm ))
342 lpitem->rect.right += bm.bmWidth;
343 lpitem->rect.bottom += bm.bmHeight;
348 /* If we get here, then it must be a text item */
350 if (IS_STRING_ITEM( lpitem->item_flags ))
352 const char *text = (const char *)USER_HEAP_LIN_ADDR( lpitem->hText );
353 dwSize = GetTextExtent( hdc, text, strlen(text) );
354 lpitem->rect.right += LOWORD(dwSize);
355 lpitem->rect.bottom += MAX( HIWORD(dwSize), SYSMETRICS_CYMENU );
358 if (menuBar) lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
359 else if ((p = strchr( text, '\t' )) != NULL)
361 /* Item contains a tab (only meaningful in popup menus) */
362 lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE +
363 LOWORD( GetTextExtent( hdc, text, (int)(p - text) ));
364 lpitem->rect.right += MENU_TAB_SPACE;
368 if (strchr( text, '\b' )) lpitem->rect.right += MENU_TAB_SPACE;
369 lpitem->xTab = lpitem->rect.right - check_bitmap_width
370 - arrow_bitmap_width;
376 /***********************************************************************
377 * MENU_PopupMenuCalcSize
379 * Calculate the size of a popup menu.
381 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
383 LPMENUITEM items, lpitem;
386 int orgX, orgY, maxX, maxTab, maxTabWidth;
388 lppop->Width = lppop->Height = 0;
389 if (lppop->nItems == 0) return;
390 items = (MENUITEM *)USER_HEAP_LIN_ADDR( lppop->hItems );
393 while (start < lppop->nItems)
395 lpitem = &items[start];
398 maxTab = maxTabWidth = 0;
400 /* Parse items until column break or end of menu */
401 for (i = start; i < lppop->nItems; i++, lpitem++)
404 (lpitem->item_flags & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
405 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
406 if (lpitem->item_flags & MF_MENUBARBREAK) orgX++;
407 maxX = MAX( maxX, lpitem->rect.right );
408 orgY = lpitem->rect.bottom;
409 if (IS_STRING_ITEM(lpitem->item_flags) && lpitem->xTab)
411 maxTab = MAX( maxTab, lpitem->xTab );
412 maxTabWidth = MAX(maxTabWidth,lpitem->rect.right-lpitem->xTab);
416 /* Finish the column (set all items to the largest width found) */
417 maxX = MAX( maxX, maxTab + maxTabWidth );
418 for (lpitem = &items[start]; start < i; start++, lpitem++)
420 lpitem->rect.right = maxX;
421 if (IS_STRING_ITEM(lpitem->item_flags) && lpitem->xTab)
422 lpitem->xTab = maxTab;
424 lppop->Height = MAX( lppop->Height, orgY );
432 /***********************************************************************
433 * MENU_MenuBarCalcSize
435 * Calculate the size of the menu bar.
437 static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect, LPPOPUPMENU lppop,
440 LPMENUITEM lpitem, items;
441 int start, i, orgX, orgY, maxY, helpPos;
443 if ((lprect == NULL) || (lppop == NULL)) return;
444 if (lppop->nItems == 0) return;
445 dprintf_menu(stddeb,"MENU_MenuBarCalcSize left=%d top=%d right=%d bottom=%d\n",
446 lprect->left, lprect->top, lprect->right, lprect->bottom);
447 items = (MENUITEM *)USER_HEAP_LIN_ADDR( lppop->hItems );
448 lppop->Width = lprect->right - lprect->left;
453 while (start < lppop->nItems)
455 lpitem = &items[start];
459 /* Parse items until line break or end of menu */
460 for (i = start; i < lppop->nItems; i++, lpitem++)
462 if ((helpPos == -1) && (lpitem->item_flags & MF_HELP)) helpPos = i;
464 (lpitem->item_flags & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
465 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE );
466 if (lpitem->rect.right > lprect->right)
468 if (i != start) break;
469 else lpitem->rect.right = lprect->right;
471 maxY = MAX( maxY, lpitem->rect.bottom );
472 orgX = lpitem->rect.right;
475 /* Finish the line (set all items to the largest height found) */
476 while (start < i) items[start++].rect.bottom = maxY;
479 lprect->bottom = maxY;
480 lppop->Height = lprect->bottom - lprect->top;
482 /* Flush right all items between the MF_HELP and the last item */
483 /* (if several lines, only move the last line) */
486 lpitem = &items[lppop->nItems-1];
487 orgY = lpitem->rect.top;
488 orgX = lprect->right;
489 for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--)
491 if (lpitem->rect.top != orgY) break; /* Other line */
492 if (lpitem->rect.right >= orgX) break; /* Too far right already */
493 lpitem->rect.left += orgX - lpitem->rect.right;
494 lpitem->rect.right = orgX;
495 orgX = lpitem->rect.left;
501 /***********************************************************************
504 * Draw a single menu item.
506 static void MENU_DrawMenuItem( HWND hwnd, HDC hdc, LPMENUITEM lpitem,
507 UINT height, BOOL menuBar )
511 if (lpitem->item_flags & MF_OWNERDRAW)
515 dprintf_menu( stddeb, "DrawMenuItem: Ownerdraw!\n" );
516 dis.CtlType = ODT_MENU;
517 dis.itemID = lpitem->item_id;
518 dis.itemData = GET_OWNERDRAW_DATA(lpitem);
520 if (lpitem->item_flags & MF_CHECKED) dis.itemState |= ODS_CHECKED;
521 if (lpitem->item_flags & MF_GRAYED) dis.itemState |= ODS_GRAYED;
522 if (lpitem->item_flags & MF_HILITE) dis.itemState |= ODS_SELECTED;
523 dis.itemAction = ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS;
526 dis.rcItem = lpitem->rect;
527 SendMessage( hwnd, WM_DRAWITEM, 0, (LPARAM)MAKE_SEGPTR(&dis) );
531 if (menuBar && (lpitem->item_flags & MF_SEPARATOR)) return;
534 /* Draw the background */
536 if (lpitem->item_flags & MF_HILITE)
537 FillRect( hdc, &rect, sysColorObjects.hbrushHighlight );
538 else FillRect( hdc, &rect, sysColorObjects.hbrushMenu );
539 SetBkMode( hdc, TRANSPARENT );
541 /* Draw the separator bar (if any) */
543 if (!menuBar && (lpitem->item_flags & MF_MENUBARBREAK))
545 SelectObject( hdc, sysColorObjects.hpenWindowFrame );
546 MoveTo( hdc, rect.left, 0 );
547 LineTo( hdc, rect.left, height );
549 if (lpitem->item_flags & MF_SEPARATOR)
551 SelectObject( hdc, sysColorObjects.hpenWindowFrame );
552 MoveTo( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2 );
553 LineTo( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 );
559 if (lpitem->item_flags & MF_HILITE)
561 if (lpitem->item_flags & MF_GRAYED)
562 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
564 SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
565 SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
569 if (lpitem->item_flags & MF_GRAYED)
570 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
572 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
573 SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
578 /* Draw the check mark */
580 if (lpitem->item_flags & MF_CHECKED)
582 GRAPH_DrawBitmap(hdc, lpitem->hCheckBit ? lpitem->hCheckBit :
583 hStdCheck, rect.left,
584 (rect.top+rect.bottom-check_bitmap_height) / 2,
585 0, 0, check_bitmap_width, check_bitmap_height );
587 else if (lpitem->hUnCheckBit != 0) /* Not checked */
589 GRAPH_DrawBitmap(hdc, lpitem->hUnCheckBit, rect.left,
590 (rect.top+rect.bottom-check_bitmap_height) / 2,
591 0, 0, check_bitmap_width, check_bitmap_height );
594 /* Draw the popup-menu arrow */
596 if (lpitem->item_flags & MF_POPUP)
598 GRAPH_DrawBitmap( hdc, hStdMnArrow,
599 rect.right-arrow_bitmap_width-1,
600 (rect.top+rect.bottom-arrow_bitmap_height) / 2,
601 0, 0, arrow_bitmap_width, arrow_bitmap_height );
604 rect.left += check_bitmap_width;
605 rect.right -= arrow_bitmap_width;
608 /* Draw the item text or bitmap */
610 if (lpitem->item_flags & MF_BITMAP)
612 GRAPH_DrawBitmap( hdc, (HBITMAP)lpitem->hText, rect.left, rect.top,
613 0, 0, rect.right-rect.left, rect.bottom-rect.top );
616 /* No bitmap - process text if present */
617 else if (IS_STRING_ITEM(lpitem->item_flags))
620 const char *text = (const char *)USER_HEAP_LIN_ADDR( lpitem->hText );
624 rect.left += MENU_BAR_ITEMS_SPACE / 2;
625 rect.right -= MENU_BAR_ITEMS_SPACE / 2;
630 for (i = 0; text[i]; i++)
631 if ((text[i] == '\t') || (text[i] == '\b')) break;
634 DrawText( hdc, text, i, &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE );
636 if (text[i]) /* There's a tab or flush-right char */
640 rect.left = lpitem->xTab;
641 DrawText( hdc, text + i + 1, -1, &rect,
642 DT_LEFT | DT_VCENTER | DT_SINGLELINE );
644 else DrawText( hdc, text + i + 1, -1, &rect,
645 DT_RIGHT | DT_VCENTER | DT_SINGLELINE );
651 /***********************************************************************
654 * Paint a popup menu.
656 static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
663 GetClientRect( hwnd, &rect );
664 FillRect( hdc, &rect, sysColorObjects.hbrushMenu );
665 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
666 if (!menu || !menu->nItems) return;
667 item = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
668 for (i = menu->nItems; i > 0; i--, item++)
669 MENU_DrawMenuItem( hwnd, hdc, item, menu->Height, FALSE );
673 /***********************************************************************
676 * Paint a menu bar. Returns the height of the menu bar.
678 UINT MENU_DrawMenuBar(HDC hDC, LPRECT lprect, HWND hwnd, BOOL suppress_draw)
683 WND *wndPtr = WIN_FindWndPtr( hwnd );
685 lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR( (HMENU)wndPtr->wIDmenu );
686 if (lppop == NULL || lprect == NULL) return SYSMETRICS_CYMENU;
687 dprintf_menu(stddeb,"MENU_DrawMenuBar(%04x, %p, %p); !\n",
689 if (lppop->Height == 0) MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
690 lprect->bottom = lprect->top + lppop->Height;
691 if (suppress_draw) return lppop->Height;
693 FillRect(hDC, lprect, sysColorObjects.hbrushMenu );
694 SelectObject( hDC, sysColorObjects.hpenWindowFrame );
695 MoveTo( hDC, lprect->left, lprect->bottom );
696 LineTo( hDC, lprect->right, lprect->bottom );
698 if (lppop->nItems == 0) return SYSMETRICS_CYMENU;
699 lpitem = (MENUITEM *) USER_HEAP_LIN_ADDR( lppop->hItems );
700 for (i = 0; i < lppop->nItems; i++, lpitem++)
702 MENU_DrawMenuItem( hwnd, hDC, lpitem, lppop->Height, TRUE );
704 return lppop->Height;
707 /***********************************************************************
710 BOOL MENU_SwitchTPWndTo( HTASK hTask)
712 /* This is supposed to be called when popup is hidden */
714 TDB* task = (TDB*)GlobalLock16(hTask);
716 if( !task ) return 0;
718 /* if this task got as far as menu tracking it must have a queue */
720 pTopPWnd->hInstance = task->hInstance;
721 pTopPWnd->hmemTaskQ = task->hQueue;
725 /***********************************************************************
728 * Display a popup menu.
730 static BOOL MENU_ShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, int x, int y)
736 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
737 if (menu->FocusedItem != NO_SELECTED_ITEM)
739 MENUITEM *item = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
740 item[menu->FocusedItem].item_flags &= ~(MF_HILITE | MF_MOUSESELECT);
741 menu->FocusedItem = NO_SELECTED_ITEM;
743 SendMessage( hwndOwner, WM_INITMENUPOPUP, (WPARAM)hmenu,
744 MAKELONG( id, (menu->wFlags & MF_SYSMENU) ? 1 : 0 ));
745 MENU_PopupMenuCalcSize( menu, hwndOwner );
747 wndPtr = WIN_FindWndPtr( hwndOwner );
748 if (!wndPtr) return FALSE;
752 pTopPWnd = WIN_FindWndPtr(CreateWindow16( POPUPMENU_CLASS_ATOM, (SEGPTR)0,
753 WS_POPUP | WS_BORDER, x, y,
754 menu->Width + 2*SYSMETRICS_CXBORDER,
755 menu->Height + 2*SYSMETRICS_CYBORDER,
756 0, 0, wndPtr->hInstance, (SEGPTR)hmenu ));
757 if (!pTopPWnd) return FALSE;
763 /* create new window for the submenu */
764 HWND hWnd = CreateWindow16( POPUPMENU_CLASS_ATOM, (SEGPTR)0,
765 WS_POPUP | WS_BORDER, x, y,
766 menu->Width + 2*SYSMETRICS_CXBORDER,
767 menu->Height + 2*SYSMETRICS_CYBORDER,
768 menu->hWnd, 0, wndPtr->hInstance, (SEGPTR)hmenu );
769 if( !hWnd ) return FALSE;
776 MENU_SwitchTPWndTo(GetCurrentTask());
777 SendMessage( pTopPWnd->hwndSelf, WM_USER, (WPARAM)hmenu, 0L);
779 menu->hWnd = pTopPWnd->hwndSelf;
784 SetWindowPos(menu->hWnd, 0, x, y, menu->Width + 2*SYSMETRICS_CXBORDER,
785 menu->Height + 2*SYSMETRICS_CYBORDER,
786 SWP_NOACTIVATE | SWP_NOZORDER );
788 /* Display the window */
790 SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
791 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
792 UpdateWindow( menu->hWnd );
797 /***********************************************************************
800 static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex )
806 lppop = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
807 if (!lppop->nItems) return;
808 items = (MENUITEM *) USER_HEAP_LIN_ADDR( lppop->hItems );
809 if ((wIndex != NO_SELECTED_ITEM) &&
810 (wIndex != SYSMENU_SELECTED) &&
811 (items[wIndex].item_flags & MF_SEPARATOR))
812 wIndex = NO_SELECTED_ITEM;
813 if (lppop->FocusedItem == wIndex) return;
814 if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
815 else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
817 /* Clear previous highlighted item */
818 if (lppop->FocusedItem != NO_SELECTED_ITEM)
820 if (lppop->FocusedItem == SYSMENU_SELECTED)
821 NC_DrawSysButton( lppop->hWnd, hdc, FALSE );
824 items[lppop->FocusedItem].item_flags &=~(MF_HILITE|MF_MOUSESELECT);
825 MENU_DrawMenuItem( lppop->hWnd, hdc, &items[lppop->FocusedItem], lppop->Height,
826 !(lppop->wFlags & MF_POPUP) );
830 /* Highlight new item (if any) */
831 lppop->FocusedItem = wIndex;
832 if (lppop->FocusedItem != NO_SELECTED_ITEM)
834 if (lppop->FocusedItem == SYSMENU_SELECTED)
836 NC_DrawSysButton( lppop->hWnd, hdc, TRUE );
839 SendMessage( hwndOwner, WM_MENUSELECT,
840 MAKEWPARAM( WIN_FindWndPtr(lppop->hWnd)->hSysMenu,
841 lppop->wFlags | MF_MOUSESELECT ),
844 SendMessage( hwndOwner, WM_MENUSELECT,
845 WIN_FindWndPtr(lppop->hWnd)->hSysMenu,
846 MAKELONG( lppop->wFlags | MF_MOUSESELECT, hmenu ) );
851 items[lppop->FocusedItem].item_flags |= MF_HILITE;
852 MENU_DrawMenuItem( lppop->hWnd, hdc, &items[lppop->FocusedItem], lppop->Height,
853 !(lppop->wFlags & MF_POPUP) );
855 SendMessage( hwndOwner, WM_MENUSELECT,
856 MAKEWPARAM( items[lppop->FocusedItem].item_id,
857 items[lppop->FocusedItem].item_flags |
861 SendMessage( hwndOwner, WM_MENUSELECT,
862 items[lppop->FocusedItem].item_id,
863 MAKELONG( items[lppop->FocusedItem].item_flags | MF_MOUSESELECT, hmenu));
869 else SendMessage( hwndOwner, WM_MENUSELECT,
870 MAKEWPARAM( (DWORD)hmenu, lppop->wFlags | MF_MOUSESELECT),
873 else SendMessage( hwndOwner, WM_MENUSELECT, hmenu,
874 MAKELONG( lppop->wFlags | MF_MOUSESELECT, hmenu ) );
877 ReleaseDC( lppop->hWnd, hdc );
881 /***********************************************************************
882 * MENU_SelectNextItem
884 static void MENU_SelectNextItem( HWND hwndOwner, HMENU hmenu )
890 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
891 if (!menu->nItems) return;
892 items = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
893 if ((menu->FocusedItem != NO_SELECTED_ITEM) &&
894 (menu->FocusedItem != SYSMENU_SELECTED))
896 for (i = menu->FocusedItem+1; i < menu->nItems; i++)
898 if (!(items[i].item_flags & MF_SEPARATOR))
900 MENU_SelectItem( hwndOwner, hmenu, i );
904 if (MENU_HasSysMenu( menu ))
906 MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED );
910 for (i = 0; i < menu->nItems; i++)
912 if (!(items[i].item_flags & MF_SEPARATOR))
914 MENU_SelectItem( hwndOwner, hmenu, i );
918 if (MENU_HasSysMenu( menu ))
919 MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED );
923 /***********************************************************************
924 * MENU_SelectPrevItem
926 static void MENU_SelectPrevItem( HWND hwndOwner, HMENU hmenu )
932 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
933 if (!menu->nItems) return;
934 items = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
935 if ((menu->FocusedItem != NO_SELECTED_ITEM) &&
936 (menu->FocusedItem != SYSMENU_SELECTED))
938 for (i = menu->FocusedItem - 1; i >= 0; i--)
940 if (!(items[i].item_flags & MF_SEPARATOR))
942 MENU_SelectItem( hwndOwner, hmenu, i );
946 if (MENU_HasSysMenu( menu ))
948 MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED );
952 for (i = menu->nItems - 1; i > 0; i--)
954 if (!(items[i].item_flags & MF_SEPARATOR))
956 MENU_SelectItem( hwndOwner, hmenu, i );
960 if (MENU_HasSysMenu( menu ))
961 MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED );
965 /**********************************************************************
968 * Set an item flags, id and text ptr.
970 static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT id, SEGPTR data)
972 HANDLE hPrevText = IS_STRING_ITEM(item->item_flags) ? item->hText : 0;
974 if (IS_STRING_ITEM(flags))
978 flags |= MF_SEPARATOR;
983 char *str = (char *)PTR_SEG_TO_LIN(data);
986 /* Item beginning with a backspace is a help item */
992 if (!(hText = USER_HEAP_ALLOC( strlen(str)+1 ))) return FALSE;
994 strcpy( (char *)USER_HEAP_LIN_ADDR( hText ), str );
997 else if (flags & MF_BITMAP) item->hText = (HANDLE)data;
998 else if (flags & MF_OWNERDRAW) SET_OWNERDRAW_DATA( item, data );
999 else item->hText = 0;
1001 item->item_flags = flags & ~(MF_HILITE | MF_MOUSESELECT);
1003 SetRectEmpty( &item->rect );
1004 if (hPrevText) USER_HEAP_FREE( hPrevText );
1009 /**********************************************************************
1012 * Insert a new item into a menu.
1014 static MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
1020 if (!(menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu)))
1022 dprintf_menu( stddeb, "MENU_InsertItem: %04x not a menu handle\n",
1027 /* Find where to insert new item */
1029 if ((flags & MF_BYPOSITION) &&
1030 ((pos == (UINT)-1) || (pos == menu->nItems)))
1032 /* Special case: append to menu */
1033 /* Some programs specify the menu length to do that */
1038 if (!MENU_FindItem( &hMenu, &pos, flags ))
1040 dprintf_menu( stddeb, "MENU_InsertItem: item %x not found\n",
1044 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu)))
1046 dprintf_menu(stddeb,"MENU_InsertItem: %04x not a menu handle\n",
1052 /* Create new items array */
1054 hNewItems = USER_HEAP_ALLOC( sizeof(MENUITEM) * (menu->nItems+1) );
1057 dprintf_menu( stddeb, "MENU_InsertMenu: allocation failed\n" );
1060 newItems = (MENUITEM *) USER_HEAP_LIN_ADDR( hNewItems );
1061 if (menu->nItems > 0)
1063 /* Copy the old array into the new */
1064 MENUITEM *oldItems = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
1065 if (pos > 0) memcpy( newItems, oldItems, pos * sizeof(MENUITEM) );
1066 if (pos < menu->nItems) memcpy( &newItems[pos+1], &oldItems[pos],
1067 (menu->nItems-pos)*sizeof(MENUITEM) );
1069 USER_HEAP_FREE( menu->hItems );
1071 menu->hItems = hNewItems;
1073 memset( &newItems[pos], 0, sizeof(*newItems) );
1074 return &newItems[pos];
1078 /**********************************************************************
1079 * MENU_ParseResource
1081 * Parse a menu resource and add items to the menu.
1082 * Return a pointer to the end of the resource.
1084 static SEGPTR MENU_ParseResource( SEGPTR res, HMENU hMenu )
1091 flags = GET_WORD( PTR_SEG_TO_LIN( res ) );
1092 res += sizeof(WORD);
1093 if (!(flags & MF_POPUP))
1095 id = GET_WORD( PTR_SEG_TO_LIN( res ) );
1096 res += sizeof(WORD);
1099 res += strlen( (char *)PTR_SEG_TO_LIN(data) ) + 1;
1100 if (!IS_STRING_ITEM(flags))
1101 fprintf( stderr, "MENU_ParseResource: not a string item %04x\n",
1103 if (flags & MF_POPUP)
1105 HMENU hSubMenu = CreatePopupMenu();
1106 if (!hSubMenu) return (SEGPTR)0;
1107 if (!(res = MENU_ParseResource( res, hSubMenu ))) return (SEGPTR)0;
1108 AppendMenu( hMenu, flags, (UINT)hSubMenu, data );
1112 if (!*(char *)PTR_SEG_TO_LIN(data)) data = 0;
1113 AppendMenu( hMenu, flags, id, data );
1115 } while (!(flags & MF_END));
1120 /***********************************************************************
1123 * Return the handle of the selected sub-popup menu (if any).
1125 static HMENU MENU_GetSubPopup( HMENU hmenu )
1130 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1131 if (menu->FocusedItem == NO_SELECTED_ITEM) return 0;
1132 else if (menu->FocusedItem == SYSMENU_SELECTED)
1133 return WIN_FindWndPtr(menu->hWnd)->hSysMenu;
1135 item = ((MENUITEM *)USER_HEAP_LIN_ADDR(menu->hItems)) + menu->FocusedItem;
1136 if (!(item->item_flags & MF_POPUP) || !(item->item_flags & MF_MOUSESELECT))
1138 return (HMENU)item->item_id;
1142 /***********************************************************************
1143 * MENU_HideSubPopups
1145 * Hide the sub-popup menus of this menu.
1147 static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu )
1150 POPUPMENU *menu, *submenu;
1153 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return;
1154 if (menu->FocusedItem == NO_SELECTED_ITEM) return;
1155 if (menu->FocusedItem == SYSMENU_SELECTED)
1157 hsubmenu = WIN_FindWndPtr(menu->hWnd)->hSysMenu;
1161 item = ((MENUITEM *)USER_HEAP_LIN_ADDR(menu->hItems)) + menu->FocusedItem;
1162 if (!(item->item_flags & MF_POPUP) ||
1163 !(item->item_flags & MF_MOUSESELECT)) return;
1164 item->item_flags &= ~MF_MOUSESELECT;
1165 hsubmenu = (HMENU)item->item_id;
1167 submenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hsubmenu );
1168 MENU_HideSubPopups( hwndOwner, hsubmenu );
1169 if (submenu->hWnd == pTopPWnd->hwndSelf )
1171 ShowWindow( submenu->hWnd, SW_HIDE );
1176 DestroyWindow( submenu->hWnd );
1179 MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM );
1183 /***********************************************************************
1186 * Display the sub-menu of the selected item of this menu.
1187 * Return the handle of the submenu, or hmenu if no submenu to display.
1189 static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu, BOOL selectFirst )
1195 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return hmenu;
1196 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return hmenu;
1197 if (menu->FocusedItem == NO_SELECTED_ITEM) return hmenu;
1198 if (menu->FocusedItem == SYSMENU_SELECTED)
1200 MENU_ShowPopup(hwndOwner, wndPtr->hSysMenu, 0, wndPtr->rectClient.left,
1201 wndPtr->rectClient.top - menu->Height - 2*SYSMETRICS_CYBORDER);
1202 if (selectFirst) MENU_SelectNextItem( hwndOwner, wndPtr->hSysMenu );
1203 return wndPtr->hSysMenu;
1205 item = ((MENUITEM *)USER_HEAP_LIN_ADDR(menu->hItems)) + menu->FocusedItem;
1206 if (!(item->item_flags & MF_POPUP) ||
1207 (item->item_flags & (MF_GRAYED | MF_DISABLED))) return hmenu;
1208 item->item_flags |= MF_MOUSESELECT;
1209 if (menu->wFlags & MF_POPUP)
1211 MENU_ShowPopup( hwndOwner, (HMENU)item->item_id, menu->FocusedItem,
1212 wndPtr->rectWindow.left + item->rect.right-arrow_bitmap_width,
1213 wndPtr->rectWindow.top + item->rect.top );
1217 MENU_ShowPopup( hwndOwner, (HMENU)item->item_id, menu->FocusedItem,
1218 wndPtr->rectWindow.left + item->rect.left,
1219 wndPtr->rectWindow.top + item->rect.bottom );
1221 if (selectFirst) MENU_SelectNextItem( hwndOwner, (HMENU)item->item_id );
1222 return (HMENU)item->item_id;
1226 /***********************************************************************
1227 * MENU_FindMenuByCoords
1229 * Find the menu containing a given point (in screen coords).
1231 static HMENU MENU_FindMenuByCoords( HMENU hmenu, POINT pt )
1236 if (!(hwnd = WindowFromPoint( pt ))) return 0;
1239 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1240 if (menu->hWnd == hwnd)
1242 if (!(menu->wFlags & MF_POPUP))
1244 /* Make sure it's in the menu bar (or in system menu) */
1245 WND *wndPtr = WIN_FindWndPtr( menu->hWnd );
1246 if ((pt.x < wndPtr->rectClient.left) ||
1247 (pt.x >= wndPtr->rectClient.right) ||
1248 (pt.y >= wndPtr->rectClient.top)) return 0;
1249 if (pt.y < wndPtr->rectClient.top - menu->Height)
1251 if (!MENU_IsInSysMenu( menu, pt )) return 0;
1253 /* else it's in the menu bar */
1257 hmenu = MENU_GetSubPopup( hmenu );
1263 /***********************************************************************
1264 * MENU_ExecFocusedItem
1266 * Execute a menu item (for instance when user pressed Enter).
1267 * Return TRUE if we can go on with menu tracking.
1269 static BOOL MENU_ExecFocusedItem( HWND hwndOwner, HMENU hmenu,
1270 HMENU *hmenuCurrent )
1273 POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1274 if (!menu || !menu->nItems || (menu->FocusedItem == NO_SELECTED_ITEM) ||
1275 (menu->FocusedItem == SYSMENU_SELECTED)) return TRUE;
1276 item = ((MENUITEM *)USER_HEAP_LIN_ADDR(menu->hItems)) + menu->FocusedItem;
1277 if (!(item->item_flags & MF_POPUP))
1279 if (!(item->item_flags & (MF_GRAYED | MF_DISABLED)))
1281 PostMessage( hwndOwner, (menu->wFlags & MF_SYSMENU) ?
1282 WM_SYSCOMMAND : WM_COMMAND, item->item_id, 0 );
1289 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, TRUE );
1295 /***********************************************************************
1298 * Handle a button-down event in a menu. Point is in screen coords.
1299 * hmenuCurrent is the top-most visible popup.
1300 * Return TRUE if we can go on with menu tracking.
1302 static BOOL MENU_ButtonDown( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent,
1309 if (!hmenu) return FALSE; /* Outside all menus */
1310 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1311 item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
1312 if (!item) /* Maybe in system menu */
1314 if (!MENU_IsInSysMenu( menu, pt )) return FALSE;
1315 id = SYSMENU_SELECTED;
1318 if (menu->FocusedItem == id)
1320 if (id == SYSMENU_SELECTED) return FALSE;
1321 if (item->item_flags & MF_POPUP)
1323 if (item->item_flags & MF_MOUSESELECT)
1325 if (menu->wFlags & MF_POPUP)
1327 MENU_HideSubPopups( hwndOwner, hmenu );
1328 *hmenuCurrent = hmenu;
1332 else *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
1337 MENU_HideSubPopups( hwndOwner, hmenu );
1338 MENU_SelectItem( hwndOwner, hmenu, id );
1339 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
1345 /***********************************************************************
1348 * Handle a button-up event in a menu. Point is in screen coords.
1349 * hmenuCurrent is the top-most visible popup.
1350 * Return TRUE if we can go on with menu tracking.
1352 static BOOL MENU_ButtonUp( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent,
1360 if (!hmenu) return FALSE; /* Outside all menus */
1361 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1362 item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
1363 if (!item) /* Maybe in system menu */
1365 if (!MENU_IsInSysMenu( menu, pt )) return FALSE;
1366 id = SYSMENU_SELECTED;
1367 hsubmenu = WIN_FindWndPtr(menu->hWnd)->hSysMenu;
1370 if (menu->FocusedItem != id) return FALSE;
1372 if (id != SYSMENU_SELECTED)
1374 if (!(item->item_flags & MF_POPUP))
1376 return MENU_ExecFocusedItem( hwndOwner, hmenu, hmenuCurrent );
1378 hsubmenu = (HMENU)item->item_id;
1380 /* Select first item of sub-popup */
1381 MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM );
1382 MENU_SelectNextItem( hwndOwner, hsubmenu );
1387 /***********************************************************************
1390 * Handle a motion event in a menu. Point is in screen coords.
1391 * hmenuCurrent is the top-most visible popup.
1392 * Return TRUE if we can go on with menu tracking.
1394 static BOOL MENU_MouseMove( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent,
1398 POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1399 UINT id = NO_SELECTED_ITEM;
1403 item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
1404 if (!item) /* Maybe in system menu */
1406 if (!MENU_IsInSysMenu( menu, pt ))
1407 id = NO_SELECTED_ITEM; /* Outside all items */
1408 else id = SYSMENU_SELECTED;
1411 if (id == NO_SELECTED_ITEM)
1413 MENU_SelectItem( hwndOwner, *hmenuCurrent, NO_SELECTED_ITEM );
1415 else if (menu->FocusedItem != id)
1417 MENU_HideSubPopups( hwndOwner, hmenu );
1418 MENU_SelectItem( hwndOwner, hmenu, id );
1419 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
1425 /***********************************************************************
1428 * Handle a VK_LEFT key event in a menu.
1429 * hmenuCurrent is the top-most visible popup.
1431 static void MENU_KeyLeft( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent )
1434 HMENU hmenutmp, hmenuprev;
1436 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1437 hmenuprev = hmenutmp = hmenu;
1438 while (hmenutmp != *hmenuCurrent)
1440 hmenutmp = MENU_GetSubPopup( hmenuprev );
1441 if (hmenutmp != *hmenuCurrent) hmenuprev = hmenutmp;
1443 MENU_HideSubPopups( hwndOwner, hmenuprev );
1445 if ((hmenuprev == hmenu) && !(menu->wFlags & MF_POPUP))
1447 /* Select previous item on the menu bar */
1448 MENU_SelectPrevItem( hwndOwner, hmenu );
1449 if (*hmenuCurrent != hmenu)
1451 /* A popup menu was displayed -> display the next one */
1452 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, TRUE );
1455 else *hmenuCurrent = hmenuprev;
1459 /***********************************************************************
1462 * Handle a VK_RIGHT key event in a menu.
1463 * hmenuCurrent is the top-most visible popup.
1465 static void MENU_KeyRight( HWND hwndOwner, HMENU hmenu, HMENU *hmenuCurrent )
1470 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1472 if ((menu->wFlags & MF_POPUP) || (*hmenuCurrent != hmenu))
1474 /* If already displaying a popup, try to display sub-popup */
1475 hmenutmp = MENU_ShowSubPopup( hwndOwner, *hmenuCurrent, TRUE );
1476 if (hmenutmp != *hmenuCurrent) /* Sub-popup displayed */
1478 *hmenuCurrent = hmenutmp;
1483 /* If on menu-bar, go to next item */
1484 if (!(menu->wFlags & MF_POPUP))
1486 MENU_HideSubPopups( hwndOwner, hmenu );
1487 MENU_SelectNextItem( hwndOwner, hmenu );
1488 if (*hmenuCurrent != hmenu)
1490 /* A popup menu was displayed -> display the next one */
1491 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, TRUE );
1494 else if (*hmenuCurrent != hmenu) /* Hide last level popup */
1497 hmenuprev = hmenutmp = hmenu;
1498 while (hmenutmp != *hmenuCurrent)
1500 hmenutmp = MENU_GetSubPopup( hmenuprev );
1501 if (hmenutmp != *hmenuCurrent) hmenuprev = hmenutmp;
1503 MENU_HideSubPopups( hwndOwner, hmenuprev );
1504 *hmenuCurrent = hmenuprev;
1509 /***********************************************************************
1512 * Menu tracking code.
1513 * If 'x' and 'y' are not 0, we simulate a button-down event at (x,y)
1514 * before beginning tracking. This is to help menu-bar tracking.
1516 static BOOL MENU_TrackMenu( HMENU hmenu, UINT wFlags, int x, int y,
1517 HWND hwnd, LPRECT lprect )
1522 HMENU hmenuCurrent = hmenu;
1523 BOOL fClosed = FALSE, fRemove;
1526 fEndMenuCalled = FALSE;
1527 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
1530 POINT pt = { x, y };
1531 MENU_ButtonDown( hwnd, hmenu, &hmenuCurrent, pt );
1534 hMsg = USER_HEAP_ALLOC( sizeof(MSG) );
1535 msg = (MSG *)USER_HEAP_LIN_ADDR( hMsg );
1538 if (!MSG_InternalGetMessage( (SEGPTR)USER_HEAP_SEG_ADDR(hMsg), 0,
1539 hwnd, MSGF_MENU, 0, TRUE ))
1543 if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
1545 /* Find the sub-popup for this mouse event (if any) */
1546 HMENU hsubmenu = MENU_FindMenuByCoords( hmenu, msg->pt );
1548 switch(msg->message)
1550 case WM_RBUTTONDOWN:
1551 case WM_NCRBUTTONDOWN:
1552 if (!(wFlags & TPM_RIGHTBUTTON)) break;
1554 case WM_LBUTTONDOWN:
1555 case WM_NCLBUTTONDOWN:
1556 fClosed = !MENU_ButtonDown( hwnd, hsubmenu,
1557 &hmenuCurrent, msg->pt );
1561 case WM_NCRBUTTONUP:
1562 if (!(wFlags & TPM_RIGHTBUTTON)) break;
1565 case WM_NCLBUTTONUP:
1566 /* If outside all menus but inside lprect, ignore it */
1567 if (!hsubmenu && lprect && PtInRect( lprect, msg->pt )) break;
1568 fClosed = !MENU_ButtonUp( hwnd, hsubmenu,
1569 &hmenuCurrent, msg->pt );
1570 fRemove = TRUE; /* Remove event even if outside menu */
1574 case WM_NCMOUSEMOVE:
1575 if ((msg->wParam & MK_LBUTTON) ||
1576 ((wFlags & TPM_RIGHTBUTTON) && (msg->wParam & MK_RBUTTON)))
1578 fClosed = !MENU_MouseMove( hwnd, hsubmenu,
1579 &hmenuCurrent, msg->pt );
1584 else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
1586 fRemove = TRUE; /* Keyboard messages are always removed */
1587 switch(msg->message)
1593 MENU_SelectItem( hwnd, hmenuCurrent, NO_SELECTED_ITEM );
1594 MENU_SelectNextItem( hwnd, hmenuCurrent );
1598 MENU_SelectItem( hwnd, hmenuCurrent, NO_SELECTED_ITEM );
1599 MENU_SelectPrevItem( hwnd, hmenuCurrent );
1603 MENU_SelectPrevItem( hwnd, hmenuCurrent );
1607 /* If on menu bar, pull-down the menu */
1608 if (!(menu->wFlags & MF_POPUP) && (hmenuCurrent == hmenu))
1609 hmenuCurrent = MENU_ShowSubPopup( hwnd, hmenu, TRUE );
1611 MENU_SelectNextItem( hwnd, hmenuCurrent );
1615 MENU_KeyLeft( hwnd, hmenu, &hmenuCurrent );
1619 MENU_KeyRight( hwnd, hmenu, &hmenuCurrent );
1624 fClosed = !MENU_ExecFocusedItem( hwnd, hmenuCurrent,
1635 break; /* WM_KEYDOWN */
1645 break; /* WM_SYSKEYDOWN */
1649 /* Hack to avoid control chars. */
1650 /* We will find a better way real soon... */
1651 if ((msg->wParam <= 32) || (msg->wParam >= 127)) break;
1652 pos = MENU_FindItemByKey( hwnd, hmenuCurrent, msg->wParam );
1653 if (pos == (UINT)-2) fClosed = TRUE;
1654 else if (pos == (UINT)-1) MessageBeep(0);
1657 MENU_SelectItem( hwnd, hmenuCurrent, pos );
1658 fClosed = !MENU_ExecFocusedItem( hwnd, hmenuCurrent,
1663 break; /* WM_CHAR */
1664 } /* switch(msg->message) */
1668 DispatchMessage( msg );
1670 if (fEndMenuCalled) fClosed = TRUE;
1671 if (!fClosed) fRemove = TRUE;
1673 if (fRemove) /* Remove the message from the queue */
1674 PeekMessage( msg, 0, msg->message, msg->message, PM_REMOVE );
1676 USER_HEAP_FREE( hMsg );
1678 MENU_HideSubPopups( hwnd, hmenu );
1679 if (menu->wFlags & MF_POPUP)
1681 ShowWindow( menu->hWnd, SW_HIDE );
1684 MENU_SelectItem( hwnd, hmenu, NO_SELECTED_ITEM );
1685 SendMessage( hwnd, WM_MENUSELECT, 0, MAKELONG( 0xffff, 0 ) );
1686 fEndMenuCalled = FALSE;
1691 /***********************************************************************
1692 * MENU_TrackMouseMenuBar
1694 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
1696 void MENU_TrackMouseMenuBar( HWND hwnd, POINT pt )
1698 WND *wndPtr = WIN_FindWndPtr( hwnd );
1700 SendMessage( hwnd, WM_ENTERMENULOOP, 0, 0 );
1701 SendMessage( hwnd, WM_INITMENU, wndPtr->wIDmenu, 0 );
1702 MENU_TrackMenu( (HMENU)wndPtr->wIDmenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
1703 pt.x, pt.y, hwnd, NULL );
1704 SendMessage( hwnd, WM_EXITMENULOOP, 0, 0 );
1709 /***********************************************************************
1710 * MENU_TrackKbdMenuBar
1712 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
1714 void MENU_TrackKbdMenuBar( WND* wndPtr, UINT wParam, INT vkey)
1716 UINT uItem = NO_SELECTED_ITEM;
1719 /* find window that has a menu
1722 if( !(wndPtr->dwStyle & WS_CHILD) )
1724 wndPtr = WIN_FindWndPtr( GetActiveWindow() );
1725 if( !wndPtr ) return;
1728 while( wndPtr->dwStyle & WS_CHILD &&
1729 !(wndPtr->dwStyle & WS_SYSMENU) )
1730 if( !(wndPtr = wndPtr->parent) ) return;
1732 if( wndPtr->dwStyle & WS_CHILD || !wndPtr->wIDmenu )
1733 if( !(wndPtr->dwStyle & WS_SYSMENU) )
1736 hTrackMenu = ( IsMenu( wndPtr->wIDmenu ) )? wndPtr->wIDmenu:
1740 SendMessage( wndPtr->hwndSelf, WM_ENTERMENULOOP, 0, 0 );
1741 SendMessage( wndPtr->hwndSelf, WM_INITMENU, wndPtr->wIDmenu, 0 );
1743 /* find suitable menu entry
1746 if( vkey == VK_SPACE )
1747 uItem = SYSMENU_SELECTED;
1750 uItem = MENU_FindItemByKey( wndPtr->hwndSelf, wndPtr->wIDmenu, vkey );
1751 if( uItem >= 0xFFFE )
1753 if( uItem == 0xFFFF )
1755 SendMessage( wndPtr->hwndSelf, WM_EXITMENULOOP, 0, 0 );
1761 MENU_SelectItem( wndPtr->hwndSelf, hTrackMenu, uItem );
1762 if( uItem == NO_SELECTED_ITEM )
1763 MENU_SelectNextItem( wndPtr->hwndSelf, hTrackMenu );
1765 PostMessage( wndPtr->hwndSelf, WM_KEYDOWN, VK_DOWN, 0L );
1767 MENU_TrackMenu( hTrackMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
1768 0, 0, wndPtr->hwndSelf, NULL );
1770 SendMessage( wndPtr->hwndSelf, WM_EXITMENULOOP, 0, 0 );
1775 /**********************************************************************
1776 * TrackPopupMenu (USER.416)
1778 BOOL TrackPopupMenu( HMENU hMenu, UINT wFlags, short x, short y,
1779 short nReserved, HWND hWnd, LPRECT lpRect )
1783 if (!MENU_ShowPopup( hWnd, hMenu, 0, x, y ))
1786 ret = MENU_TrackMenu( hMenu, wFlags, 0, 0, hWnd, lpRect );
1792 /***********************************************************************
1795 LRESULT PopupMenuWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
1801 CREATESTRUCT *createStruct = (CREATESTRUCT*)PTR_SEG_TO_LIN(lParam);
1803 HMENU hmenu = (HMENU) (createStruct->lpCreateParams);
1804 SetWindowLong( hwnd, 0, hmenu );
1806 HMENU hmenu = (HMENU) ((int)createStruct->lpCreateParams & 0xffff);
1807 SetWindowWord( hwnd, 0, hmenu );
1812 case WM_MOUSEACTIVATE: /* We don't want to be activated */
1813 return MA_NOACTIVATE;
1818 BeginPaint( hwnd, &ps );
1819 MENU_DrawPopupMenu( hwnd, ps.hdc,
1821 (HMENU)GetWindowLong( hwnd, 0 )
1823 (HMENU)GetWindowWord( hwnd, 0 )
1826 EndPaint( hwnd, &ps );
1831 /* zero out global pointer in case system popup
1832 * was destroyed by AppExit
1835 if( hwnd == pTopPWnd->hwndSelf )
1844 SetWindowLong( hwnd, 0, (HMENU)wParam );
1846 SetWindowWord( hwnd, 0, (HMENU)wParam );
1850 return DefWindowProc(hwnd, message, wParam, lParam);
1856 /***********************************************************************
1857 * MENU_GetMenuBarHeight
1859 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
1861 UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth, int orgX, int orgY )
1868 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
1869 if (!(lppop = (LPPOPUPMENU)USER_HEAP_LIN_ADDR((HMENU)wndPtr->wIDmenu)))
1871 hdc = GetDC( hwnd );
1872 SetRect( &rectBar, orgX, orgY, orgX+menubarWidth, orgY+SYSMETRICS_CYMENU );
1873 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
1874 ReleaseDC( hwnd, hdc );
1875 return lppop->Height;
1879 /*******************************************************************
1880 * ChangeMenu (USER.153)
1882 BOOL ChangeMenu( HMENU hMenu, UINT pos, SEGPTR data, UINT id, UINT flags )
1884 dprintf_menu( stddeb,"ChangeMenu: menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
1885 hMenu, pos, (DWORD)data, id, flags );
1886 if (flags & MF_APPEND)
1888 return AppendMenu( hMenu, flags & ~MF_APPEND, id, data );
1890 if (flags & MF_DELETE)
1892 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
1893 /* for MF_DELETE. We should check the parameters for all others */
1894 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
1895 return DeleteMenu( hMenu, pos, flags & ~MF_DELETE );
1897 if (flags & MF_CHANGE)
1899 return ModifyMenu( hMenu, pos, flags & ~MF_CHANGE, id, data );
1901 if (flags & MF_REMOVE)
1903 return RemoveMenu( hMenu, flags & MF_BYPOSITION ? pos : id,
1904 flags & ~MF_REMOVE );
1906 /* Default: MF_INSERT */
1907 return InsertMenu( hMenu, pos, flags, id, data );
1911 /*******************************************************************
1912 * CheckMenuItem (USER.154)
1914 INT CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
1919 dprintf_menu( stddeb,"CheckMenuItem: %04x %04x %04x\n", hMenu, id, flags );
1920 if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
1921 ret = item->item_flags & MF_CHECKED;
1922 if (flags & MF_CHECKED) item->item_flags |= MF_CHECKED;
1923 else item->item_flags &= ~MF_CHECKED;
1928 /**********************************************************************
1929 * EnableMenuItem [USER.155]
1931 BOOL EnableMenuItem(HMENU hMenu, UINT wItemID, UINT wFlags)
1934 dprintf_menu(stddeb,"EnableMenuItem (%04x, %04X, %04X) !\n",
1935 hMenu, wItemID, wFlags);
1936 if (!(lpitem = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return FALSE;
1938 /* We can't have MF_GRAYED and MF_DISABLED together */
1939 if (wFlags & MF_GRAYED)
1941 lpitem->item_flags = (lpitem->item_flags & ~MF_DISABLED) | MF_GRAYED;
1943 else if (wFlags & MF_DISABLED)
1945 lpitem->item_flags = (lpitem->item_flags & ~MF_GRAYED) | MF_DISABLED;
1947 else /* MF_ENABLED */
1949 lpitem->item_flags &= ~(MF_GRAYED | MF_DISABLED);
1955 /*******************************************************************
1956 * GetMenuString (USER.161)
1958 int GetMenuString( HMENU hMenu, UINT wItemID,
1959 LPSTR str, short nMaxSiz, UINT wFlags )
1963 dprintf_menu( stddeb, "GetMenuString: menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
1964 hMenu, wItemID, str, nMaxSiz, wFlags );
1965 if (!str || !nMaxSiz) return 0;
1967 if (!(lpitem = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
1968 if (!IS_STRING_ITEM(lpitem->item_flags)) return 0;
1969 lstrcpyn( str, (char *)USER_HEAP_LIN_ADDR(lpitem->hText), nMaxSiz );
1970 dprintf_menu( stddeb, "GetMenuString: returning '%s'\n", str );
1975 /**********************************************************************
1976 * HiliteMenuItem [USER.162]
1978 BOOL HiliteMenuItem(HWND hWnd, HMENU hMenu, UINT wItemID, UINT wHilite)
1982 dprintf_menu(stddeb,"HiliteMenuItem(%04x, %04x, %04x, %04x);\n",
1983 hWnd, hMenu, wItemID, wHilite);
1984 if (!(lpitem = MENU_FindItem( &hMenu, &wItemID, wHilite ))) return FALSE;
1985 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
1986 if (menu->FocusedItem == wItemID) return TRUE;
1987 MENU_HideSubPopups( hWnd, hMenu );
1988 MENU_SelectItem( hWnd, hMenu, wItemID );
1993 /**********************************************************************
1994 * GetMenuState [USER.250]
1996 UINT GetMenuState(HMENU hMenu, UINT wItemID, UINT wFlags)
1999 dprintf_menu(stddeb,"GetMenuState(%04x, %04x, %04x);\n",
2000 hMenu, wItemID, wFlags);
2001 if (!(lpitem = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
2002 if (lpitem->item_flags & MF_POPUP)
2004 POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( (HMENU)lpitem->item_id );
2005 if (!menu) return -1;
2006 else return (menu->nItems << 8) | (menu->wFlags & 0xff);
2008 else return lpitem->item_flags;
2012 /**********************************************************************
2013 * GetMenuItemCount [USER.263]
2015 INT GetMenuItemCount(HMENU hMenu)
2018 dprintf_menu(stddeb,"GetMenuItemCount(%04x);\n", hMenu);
2019 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
2020 if (menu == NULL) return (UINT)-1;
2021 dprintf_menu(stddeb,"GetMenuItemCount(%04x) return %d \n",
2022 hMenu, menu->nItems);
2023 return menu->nItems;
2027 /**********************************************************************
2028 * GetMenuItemID [USER.264]
2030 UINT GetMenuItemID(HMENU hMenu, int nPos)
2035 dprintf_menu(stddeb,"GetMenuItemID(%04x, %d);\n", hMenu, nPos);
2036 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return -1;
2037 if ((nPos < 0) || (nPos >= menu->nItems)) return -1;
2038 item = (MENUITEM *) USER_HEAP_LIN_ADDR( menu->hItems );
2039 if (item[nPos].item_flags & MF_POPUP) return -1;
2040 return item[nPos].item_id;
2044 /*******************************************************************
2045 * InsertMenu (USER.410)
2047 BOOL InsertMenu( HMENU hMenu, UINT pos, UINT flags, UINT id, SEGPTR data )
2051 if (IS_STRING_ITEM(flags) && data)
2052 dprintf_menu( stddeb, "InsertMenu: %04x %d %04x %04x '%s'\n",
2053 hMenu, pos, flags, id, (char *)PTR_SEG_TO_LIN(data) );
2054 else dprintf_menu( stddeb, "InsertMenu: %04x %d %04x %04x %08lx\n",
2055 hMenu, pos, flags, id, (DWORD)data );
2057 if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
2059 if (!(MENU_SetItemData( item, flags, id, data )))
2061 RemoveMenu( hMenu, pos, flags );
2065 if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
2066 ((POPUPMENU *)USER_HEAP_LIN_ADDR((HMENU)id))->wFlags |= MF_POPUP;
2068 item->hCheckBit = hStdCheck;
2069 item->hUnCheckBit = 0;
2074 /*******************************************************************
2075 * AppendMenu (USER.411)
2077 BOOL AppendMenu( HMENU hMenu, UINT flags, UINT id, SEGPTR data )
2079 return InsertMenu( hMenu, -1, flags | MF_BYPOSITION, id, data );
2083 /**********************************************************************
2084 * RemoveMenu [USER.412]
2086 BOOL RemoveMenu(HMENU hMenu, UINT nPos, UINT wFlags)
2090 dprintf_menu(stddeb,"RemoveMenu (%04x, %04x, %04x) !\n",
2091 hMenu, nPos, wFlags);
2092 if (!(lpitem = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
2093 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
2097 if (IS_STRING_ITEM(lpitem->item_flags) && lpitem->hText)
2098 USER_HEAP_FREE(lpitem->hText);
2099 if (--menu->nItems == 0)
2101 USER_HEAP_FREE( menu->hItems );
2106 while(nPos < menu->nItems)
2108 *lpitem = *(lpitem+1);
2112 menu->hItems = USER_HEAP_REALLOC( menu->hItems,
2113 menu->nItems * sizeof(MENUITEM) );
2119 /**********************************************************************
2120 * DeleteMenu [USER.413]
2122 BOOL DeleteMenu(HMENU hMenu, UINT nPos, UINT wFlags)
2124 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
2125 if (!item) return FALSE;
2126 if (item->item_flags & MF_POPUP) DestroyMenu( (HMENU)item->item_id );
2127 /* nPos is now the position of the item */
2128 RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
2133 /*******************************************************************
2134 * ModifyMenu (USER.414)
2136 BOOL ModifyMenu( HMENU hMenu, UINT pos, UINT flags, UINT id, SEGPTR data )
2140 if (IS_STRING_ITEM(flags))
2142 dprintf_menu( stddeb, "ModifyMenu: %04x %d %04x %04x '%s'\n",
2143 hMenu, pos, flags, id,
2144 data ? (char *)PTR_SEG_TO_LIN(data) : "#NULL#");
2145 if (!data) return FALSE;
2148 dprintf_menu( stddeb, "ModifyMenu: %04x %d %04x %04x %08lx\n",
2149 hMenu, pos, flags, id, (DWORD)data );
2150 if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
2152 return MENU_SetItemData( item, flags, id, data );
2156 /**********************************************************************
2157 * CreatePopupMenu [USER.415]
2159 HMENU CreatePopupMenu()
2164 if (!(hmenu = CreateMenu())) return 0;
2165 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
2166 menu->wFlags |= MF_POPUP;
2171 /**********************************************************************
2172 * GetMenuCheckMarkDimensions [USER.417]
2174 DWORD GetMenuCheckMarkDimensions()
2176 return MAKELONG( check_bitmap_width, check_bitmap_height );
2180 /**********************************************************************
2181 * SetMenuItemBitmaps [USER.418]
2183 BOOL SetMenuItemBitmaps(HMENU hMenu, UINT nPos, UINT wFlags,
2184 HBITMAP hNewUnCheck, HBITMAP hNewCheck)
2187 dprintf_menu(stddeb,"SetMenuItemBitmaps(%04x, %04x, %04x, %04x, %04x)\n",
2188 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
2189 if (!(lpitem = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
2191 if (!hNewCheck && !hNewUnCheck)
2193 /* If both are NULL, restore default bitmaps */
2194 lpitem->hCheckBit = hStdCheck;
2195 lpitem->hUnCheckBit = 0;
2196 lpitem->item_flags &= ~MF_USECHECKBITMAPS;
2198 else /* Install new bitmaps */
2200 lpitem->hCheckBit = hNewCheck;
2201 lpitem->hUnCheckBit = hNewUnCheck;
2202 lpitem->item_flags |= MF_USECHECKBITMAPS;
2208 /**********************************************************************
2209 * CreateMenu [USER.151]
2215 dprintf_menu(stddeb,"CreateMenu !\n");
2216 if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) )))
2218 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
2221 menu->wMagic = MENU_MAGIC;
2228 menu->FocusedItem = NO_SELECTED_ITEM;
2229 dprintf_menu(stddeb,"CreateMenu // return %04x\n", hMenu);
2234 /**********************************************************************
2235 * DestroyMenu [USER.152]
2237 BOOL DestroyMenu(HMENU hMenu)
2240 dprintf_menu(stddeb,"DestroyMenu (%04x) !\n", hMenu);
2242 if (hMenu == 0) return FALSE;
2243 /* Silently ignore attempts to destroy default system menu */
2244 if (hMenu == MENU_DefSysMenu) return TRUE;
2245 lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
2246 if (!lppop || (lppop->wMagic != MENU_MAGIC)) return FALSE;
2247 lppop->wMagic = 0; /* Mark it as destroyed */
2248 if ((lppop->wFlags & MF_POPUP) && lppop->hWnd && lppop->hWnd != pTopPWnd->hwndSelf )
2249 DestroyWindow( lppop->hWnd );
2254 MENUITEM *item = (MENUITEM *) USER_HEAP_LIN_ADDR( lppop->hItems );
2255 for (i = lppop->nItems; i > 0; i--, item++)
2257 if (item->item_flags & MF_POPUP)
2258 DestroyMenu( (HMENU)item->item_id );
2259 if (IS_STRING_ITEM(item->item_flags) && item->hText)
2260 USER_HEAP_FREE(item->hText);
2262 USER_HEAP_FREE( lppop->hItems );
2264 USER_HEAP_FREE( hMenu );
2265 dprintf_menu(stddeb,"DestroyMenu (%04x) // End !\n", hMenu);
2269 /**********************************************************************
2270 * GetSystemMenu [USER.156]
2272 HMENU GetSystemMenu(HWND hWnd, BOOL bRevert)
2274 WND *wndPtr = WIN_FindWndPtr( hWnd );
2275 if (!wndPtr) return 0;
2277 if (!wndPtr->hSysMenu || (wndPtr->hSysMenu == MENU_DefSysMenu))
2279 wndPtr->hSysMenu = MENU_CopySysMenu();
2280 return wndPtr->hSysMenu;
2282 if (!bRevert) return wndPtr->hSysMenu;
2283 if (wndPtr->hSysMenu) DestroyMenu(wndPtr->hSysMenu);
2284 wndPtr->hSysMenu = MENU_CopySysMenu();
2285 return wndPtr->hSysMenu;
2289 /*******************************************************************
2290 * SetSystemMenu (USER.280)
2292 BOOL SetSystemMenu( HWND hwnd, HMENU hMenu )
2296 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
2297 if (wndPtr->hSysMenu && (wndPtr->hSysMenu != MENU_DefSysMenu))
2298 DestroyMenu( wndPtr->hSysMenu );
2299 wndPtr->hSysMenu = hMenu;
2304 /**********************************************************************
2305 * GetMenu [USER.157]
2307 HMENU GetMenu(HWND hWnd)
2309 WND * wndPtr = WIN_FindWndPtr(hWnd);
2310 if (wndPtr == NULL) return 0;
2311 return (HMENU)wndPtr->wIDmenu;
2315 /**********************************************************************
2316 * SetMenu [USER.158]
2318 BOOL SetMenu(HWND hWnd, HMENU hMenu)
2321 WND * wndPtr = WIN_FindWndPtr(hWnd);
2322 if (wndPtr == NULL) {
2323 fprintf(stderr,"SetMenu(%04x, %04x) // Bad window handle !\n",
2327 dprintf_menu(stddeb,"SetMenu(%04x, %04x);\n", hWnd, hMenu);
2328 if (GetCapture() == hWnd) ReleaseCapture();
2329 wndPtr->wIDmenu = (UINT)hMenu;
2332 lpmenu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
2333 if (lpmenu == NULL) {
2334 fprintf(stderr,"SetMenu(%04x, %04x) // Bad menu handle !\n",
2338 lpmenu->hWnd = hWnd;
2339 lpmenu->wFlags &= ~MF_POPUP; /* Can't be a popup */
2340 lpmenu->Height = 0; /* Make sure we recalculate the size */
2342 if (IsWindowVisible(hWnd))
2343 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
2344 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
2350 /**********************************************************************
2351 * GetSubMenu [USER.159]
2353 HMENU GetSubMenu(HMENU hMenu, short nPos)
2357 dprintf_menu(stddeb,"GetSubMenu (%04x, %04X) !\n", hMenu, nPos);
2358 if (!(lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return 0;
2359 if ((UINT)nPos >= lppop->nItems) return 0;
2360 lpitem = (MENUITEM *) USER_HEAP_LIN_ADDR( lppop->hItems );
2361 if (!(lpitem[nPos].item_flags & MF_POPUP)) return 0;
2362 return (HMENU)lpitem[nPos].item_id;
2366 /**********************************************************************
2367 * DrawMenuBar [USER.160]
2369 void DrawMenuBar(HWND hWnd)
2373 dprintf_menu(stddeb,"DrawMenuBar (%04x)\n", hWnd);
2374 wndPtr = WIN_FindWndPtr(hWnd);
2375 if (wndPtr != NULL && (wndPtr->dwStyle & WS_CHILD) == 0 &&
2376 wndPtr->wIDmenu != 0) {
2377 dprintf_menu(stddeb,"DrawMenuBar wIDmenu=%04X \n",
2379 lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR((HMENU)wndPtr->wIDmenu);
2380 if (lppop == NULL) return;
2382 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
2383 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
2384 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
2389 /***********************************************************************
2390 * EndMenu (USER.187)
2394 /* FIXME: this won't work when we have multiple tasks... */
2395 fEndMenuCalled = TRUE;
2399 /***********************************************************************
2400 * LookupMenuHandle (USER.217)
2402 HMENU LookupMenuHandle( HMENU hmenu, INT id )
2404 if (!MENU_FindItem( &hmenu, &id, MF_BYCOMMAND )) return 0;
2409 /**********************************************************************
2410 * LoadMenu (USER.150)
2412 HMENU LoadMenu( HINSTANCE instance, SEGPTR name )
2420 char *str = (char *)PTR_SEG_TO_LIN( name );
2421 dprintf_menu( stddeb, "LoadMenu(%04x,'%s')\n", instance, str );
2422 if (str[0] == '#') name = (SEGPTR)atoi( str + 1 );
2425 dprintf_resource(stddeb,"LoadMenu(%04x,%04x)\n",instance,LOWORD(name));
2427 if (!name) return 0;
2429 /* check for Win32 module */
2430 instance = GetExePtr( instance );
2431 if (MODULE_GetPtr(instance)->flags & NE_FFLAGS_WIN32)
2432 return WIN32_LoadMenuA(instance,PTR_SEG_TO_LIN(name));
2434 if (!(hRsrc = FindResource( instance, name, RT_MENU ))) return 0;
2435 if (!(handle = LoadResource( instance, hRsrc ))) return 0;
2436 hMenu = LoadMenuIndirect( WIN16_LockResource(handle) );
2437 FreeResource( handle );
2442 /**********************************************************************
2443 * LoadMenuIndirect (USER.220)
2445 HMENU LoadMenuIndirect( SEGPTR template )
2449 dprintf_menu(stddeb,"LoadMenuIndirect: %08lx\n", (DWORD)template );
2450 if (!(hMenu = CreateMenu())) return (HMENU)0;
2451 template += sizeof(MENU_HEADER);
2452 if (!MENU_ParseResource( template, hMenu ))
2454 DestroyMenu( hMenu );
2461 /**********************************************************************
2464 BOOL IsMenu( HMENU hmenu )
2467 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
2468 return (menu->wMagic == MENU_MAGIC);