Release 970112
[wine.git] / controls / menu.c
blob197262f78dc0372d24600ff13ed917c2189e2375
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 #define NO_TRANSITION_TYPES /* This file is Win32-clean */
15 #include <ctype.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include "windows.h"
20 #include "syscolor.h"
21 #include "sysmetrics.h"
22 #include "task.h"
23 #include "win.h"
24 #include "heap.h"
25 #include "menu.h"
26 #include "module.h"
27 #include "neexe.h"
28 #include "nonclient.h"
29 #include "user.h"
30 #include "message.h"
31 #include "graphics.h"
32 #include "resource.h"
33 #include "stddebug.h"
34 #include "debug.h"
36 /* Menu item structure */
37 typedef struct
39 UINT32 item_flags; /* Item flags */
40 UINT32 item_id; /* Item or popup id */
41 RECT32 rect; /* Item area (relative to menu window) */
42 UINT32 xTab; /* X position of text after Tab */
43 HBITMAP32 hCheckBit; /* Bitmap for checked item */
44 HBITMAP32 hUnCheckBit; /* Bitmap for unchecked item */
45 LPSTR text; /* Item text or bitmap handle */
46 } MENUITEM;
48 /* Popup menu structure */
49 typedef struct
51 WORD wFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */
52 WORD wMagic; /* Magic number */
53 HQUEUE16 hTaskQ; /* Task queue for this menu */
54 WORD Width; /* Width of the whole menu */
55 WORD Height; /* Height of the whole menu */
56 WORD nItems; /* Number of items in the menu */
57 HWND32 hWnd; /* Window containing the menu */
58 MENUITEM *items; /* Array of menu items */
59 UINT32 FocusedItem; /* Currently focused item */
60 } POPUPMENU, *LPPOPUPMENU;
62 #define MENU_MAGIC 0x554d /* 'MU' */
64 #define ITEM_PREV -1
65 #define ITEM_NEXT 1
67 /* Dimension of the menu bitmaps */
68 static WORD check_bitmap_width = 0, check_bitmap_height = 0;
69 static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
71 /* Flag set by EndMenu() to force an exit from menu tracking */
72 static BOOL32 fEndMenuCalled = FALSE;
74 /* Space between 2 menu bar items */
75 #define MENU_BAR_ITEMS_SPACE 16
77 /* Minimum width of a tab character */
78 #define MENU_TAB_SPACE 8
80 /* Height of a separator item */
81 #define SEPARATOR_HEIGHT 5
83 /* Values for menu->FocusedItem */
84 /* (other values give the position of the focused item) */
85 #define NO_SELECTED_ITEM 0xffff
86 #define SYSMENU_SELECTED 0xfffe /* Only valid on menu-bars */
88 #define IS_STRING_ITEM(flags) \
89 (!((flags) & (MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)))
91 static HBITMAP32 hStdCheck = 0;
92 static HBITMAP32 hStdMnArrow = 0;
93 static HMENU32 MENU_DefSysMenu = 0; /* Default system menu */
96 /* we _can_ use global popup window because there's no way 2 menues can
97 * be tracked at the same time.
98 */
100 static WND* pTopPWnd = 0;
101 static UINT32 uSubPWndLevel = 0;
104 /**********************************************************************
105 * MENU_CopySysMenu
107 * Load a copy of the system menu.
109 static HMENU32 MENU_CopySysMenu(void)
111 HMENU32 hMenu;
112 POPUPMENU *menu;
114 if (!(hMenu = LoadMenuIndirect32A( SYSRES_GetResPtr(SYSRES_MENU_SYSMENU))))
116 dprintf_menu(stddeb,"No SYSMENU\n");
117 return 0;
119 menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hMenu);
120 menu->wFlags |= MF_SYSMENU | MF_POPUP;
121 dprintf_menu(stddeb,"CopySysMenu hMenu=%04x !\n", hMenu);
122 return hMenu;
126 /***********************************************************************
127 * MENU_Init
129 * Menus initialisation.
131 BOOL32 MENU_Init()
133 BITMAP32 bm;
135 /* Load bitmaps */
137 if (!(hStdCheck = LoadBitmap32A( 0, (LPSTR)MAKEINTRESOURCE(OBM_CHECK) )))
138 return FALSE;
139 GetObject32A( hStdCheck, sizeof(bm), &bm );
140 check_bitmap_width = bm.bmWidth;
141 check_bitmap_height = bm.bmHeight;
142 if (!(hStdMnArrow = LoadBitmap32A(0,(LPSTR)MAKEINTRESOURCE(OBM_MNARROW))))
143 return FALSE;
144 GetObject32A( hStdMnArrow, sizeof(bm), &bm );
145 arrow_bitmap_width = bm.bmWidth;
146 arrow_bitmap_height = bm.bmHeight;
148 if (!(MENU_DefSysMenu = MENU_CopySysMenu()))
150 fprintf( stderr, "Unable to create default system menu\n" );
151 return FALSE;
153 return TRUE;
157 /***********************************************************************
158 * MENU_GetDefSysMenu
160 * Return the default system menu.
162 HMENU32 MENU_GetDefSysMenu(void)
164 return MENU_DefSysMenu;
168 /***********************************************************************
169 * MENU_HasSysMenu
171 * Check whether the window owning the menu bar has a system menu.
173 static BOOL32 MENU_HasSysMenu( POPUPMENU *menu )
175 WND *wndPtr;
177 if (menu->wFlags & MF_POPUP) return FALSE;
178 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return FALSE;
179 return (wndPtr->dwStyle & WS_SYSMENU) != 0;
183 /***********************************************************************
184 * MENU_IsInSysMenu
186 * Check whether the point (in screen coords) is in the system menu
187 * of the window owning the given menu.
189 static BOOL32 MENU_IsInSysMenu( POPUPMENU *menu, POINT32 pt )
191 WND *wndPtr;
193 if (menu->wFlags & MF_POPUP) return FALSE;
194 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return FALSE;
195 if (!(wndPtr->dwStyle & WS_SYSMENU)) return FALSE;
196 if ((pt.x < wndPtr->rectClient.left) ||
197 (pt.x >= wndPtr->rectClient.left+SYSMETRICS_CXSIZE+SYSMETRICS_CXBORDER))
198 return FALSE;
199 if ((pt.y >= wndPtr->rectClient.top - menu->Height) ||
200 (pt.y < wndPtr->rectClient.top - menu->Height -
201 SYSMETRICS_CYSIZE - SYSMETRICS_CYBORDER)) return FALSE;
202 return TRUE;
206 /***********************************************************************
207 * MENU_InitSysMenuPopup
209 * Grey the appropriate items in System menu.
211 void MENU_InitSysMenuPopup( HMENU32 hmenu, DWORD style, DWORD clsStyle )
213 BOOL32 gray;
215 gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
216 EnableMenuItem32( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
217 gray = ((style & WS_MAXIMIZE) != 0);
218 EnableMenuItem32( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
219 gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
220 EnableMenuItem32( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
221 gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
222 EnableMenuItem32( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
223 gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
224 EnableMenuItem32( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
225 gray = (clsStyle & CS_NOCLOSE) != 0;
226 EnableMenuItem32( hmenu, SC_CLOSE, (gray ? MF_GRAYED : MF_ENABLED) );
230 /***********************************************************************
231 * MENU_FindItem
233 * Find a menu item. Return a pointer on the item, and modifies *hmenu
234 * in case the item was in a sub-menu.
236 static MENUITEM *MENU_FindItem( HMENU32 *hmenu, UINT32 *nPos, UINT32 wFlags )
238 POPUPMENU *menu;
239 UINT32 i;
241 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(*hmenu))) return NULL;
242 if (wFlags & MF_BYPOSITION)
244 if (*nPos >= menu->nItems) return NULL;
245 return &menu->items[*nPos];
247 else
249 MENUITEM *item = menu->items;
250 for (i = 0; i < menu->nItems; i++, item++)
252 if (item->item_id == *nPos)
254 *nPos = i;
255 return item;
257 else if (item->item_flags & MF_POPUP)
259 HMENU32 hsubmenu = (HMENU32)item->item_id;
260 MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
261 if (subitem)
263 *hmenu = hsubmenu;
264 return subitem;
269 return NULL;
273 /***********************************************************************
274 * MENU_FindItemByCoords
276 * Find the item at the specified coordinates (screen coords).
278 static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu, INT32 x, INT32 y,
279 UINT32 *pos )
281 MENUITEM *item;
282 WND *wndPtr;
283 UINT32 i;
285 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return NULL;
286 x -= wndPtr->rectWindow.left;
287 y -= wndPtr->rectWindow.top;
288 item = menu->items;
289 for (i = 0; i < menu->nItems; i++, item++)
291 if ((x >= item->rect.left) && (x < item->rect.right) &&
292 (y >= item->rect.top) && (y < item->rect.bottom))
294 if (pos) *pos = i;
295 return item;
298 return NULL;
302 /***********************************************************************
303 * MENU_FindItemByKey
305 * Find the menu item selected by a key press.
306 * Return item id, -1 if none, -2 if we should close the menu.
308 static UINT32 MENU_FindItemByKey( HWND32 hwndOwner, HMENU32 hmenu, UINT32 key )
310 POPUPMENU *menu;
311 MENUITEM *item;
312 UINT32 i;
313 LONG menuchar;
315 if (!IsMenu32( hmenu )) hmenu = WIN_FindWndPtr(hwndOwner)->hSysMenu;
316 if (!hmenu) return -1;
318 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
319 item = menu->items;
320 key = toupper(key);
321 for (i = 0; i < menu->nItems; i++, item++)
323 if (IS_STRING_ITEM(item->item_flags))
325 char *p = strchr( item->text, '&' );
326 if (p && (p[1] != '&') && (toupper(p[1]) == key)) return i;
329 menuchar = SendMessage32A( hwndOwner, WM_MENUCHAR,
330 MAKEWPARAM( key, menu->wFlags ), hmenu );
331 if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
332 if (HIWORD(menuchar) == 1) return -2;
333 return -1;
337 /***********************************************************************
338 * MENU_CalcItemSize
340 * Calculate the size of the menu item and store it in lpitem->rect.
342 static void MENU_CalcItemSize( HDC32 hdc, MENUITEM *lpitem, HWND32 hwndOwner,
343 INT32 orgX, INT32 orgY, BOOL32 menuBar )
345 DWORD dwSize;
346 char *p;
348 SetRect32( &lpitem->rect, orgX, orgY, orgX, orgY );
350 if (lpitem->item_flags & MF_OWNERDRAW)
352 MEASUREITEMSTRUCT32 mis;
353 mis.CtlType = ODT_MENU;
354 mis.itemID = lpitem->item_id;
355 mis.itemData = (DWORD)lpitem->text;
356 mis.itemHeight = 16;
357 mis.itemWidth = 30;
358 SendMessage32A( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
359 lpitem->rect.bottom += mis.itemHeight;
360 lpitem->rect.right += mis.itemWidth;
361 dprintf_menu( stddeb, "DrawMenuItem: MeasureItem %04x %dx%d!\n",
362 lpitem->item_id, mis.itemWidth, mis.itemHeight );
363 return;
366 if (lpitem->item_flags & MF_SEPARATOR)
368 lpitem->rect.bottom += SEPARATOR_HEIGHT;
369 return;
372 if (!menuBar)
374 lpitem->rect.right += 2 * check_bitmap_width;
375 if (lpitem->item_flags & MF_POPUP)
376 lpitem->rect.right += arrow_bitmap_width;
379 if (lpitem->item_flags & MF_BITMAP)
381 BITMAP32 bm;
382 if (GetObject32A( (HBITMAP32)lpitem->text, sizeof(bm), &bm ))
384 lpitem->rect.right += bm.bmWidth;
385 lpitem->rect.bottom += bm.bmHeight;
387 return;
390 /* If we get here, then it must be a text item */
392 if (IS_STRING_ITEM( lpitem->item_flags ))
394 dwSize = GetTextExtent( hdc, lpitem->text, strlen(lpitem->text) );
395 lpitem->rect.right += LOWORD(dwSize);
396 lpitem->rect.bottom += MAX( HIWORD(dwSize), SYSMETRICS_CYMENU );
397 lpitem->xTab = 0;
399 if (menuBar) lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
400 else if ((p = strchr( lpitem->text, '\t' )) != NULL)
402 /* Item contains a tab (only meaningful in popup menus) */
403 lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE +
404 LOWORD( GetTextExtent( hdc, lpitem->text,
405 (int)(p - lpitem->text) ));
406 lpitem->rect.right += MENU_TAB_SPACE;
408 else
410 if (strchr( lpitem->text, '\b' ))
411 lpitem->rect.right += MENU_TAB_SPACE;
412 lpitem->xTab = lpitem->rect.right - check_bitmap_width
413 - arrow_bitmap_width;
419 /***********************************************************************
420 * MENU_PopupMenuCalcSize
422 * Calculate the size of a popup menu.
424 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND32 hwndOwner )
426 MENUITEM *lpitem;
427 HDC32 hdc;
428 int start, i;
429 int orgX, orgY, maxX, maxTab, maxTabWidth;
431 lppop->Width = lppop->Height = 0;
432 if (lppop->nItems == 0) return;
433 hdc = GetDC32( 0 );
434 maxX = start = 0;
435 while (start < lppop->nItems)
437 lpitem = &lppop->items[start];
438 orgX = maxX;
439 orgY = 0;
440 maxTab = maxTabWidth = 0;
442 /* Parse items until column break or end of menu */
443 for (i = start; i < lppop->nItems; i++, lpitem++)
445 if ((i != start) &&
446 (lpitem->item_flags & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
447 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
448 if (lpitem->item_flags & MF_MENUBARBREAK) orgX++;
449 maxX = MAX( maxX, lpitem->rect.right );
450 orgY = lpitem->rect.bottom;
451 if (IS_STRING_ITEM(lpitem->item_flags) && lpitem->xTab)
453 maxTab = MAX( maxTab, lpitem->xTab );
454 maxTabWidth = MAX(maxTabWidth,lpitem->rect.right-lpitem->xTab);
458 /* Finish the column (set all items to the largest width found) */
459 maxX = MAX( maxX, maxTab + maxTabWidth );
460 for (lpitem = &lppop->items[start]; start < i; start++, lpitem++)
462 lpitem->rect.right = maxX;
463 if (IS_STRING_ITEM(lpitem->item_flags) && lpitem->xTab)
464 lpitem->xTab = maxTab;
466 lppop->Height = MAX( lppop->Height, orgY );
469 lppop->Width = maxX;
470 ReleaseDC32( 0, hdc );
474 /***********************************************************************
475 * MENU_MenuBarCalcSize
477 * Calculate the size of the menu bar.
479 static void MENU_MenuBarCalcSize( HDC32 hdc, LPRECT32 lprect,
480 LPPOPUPMENU lppop, HWND32 hwndOwner )
482 MENUITEM *lpitem;
483 int start, i, orgX, orgY, maxY, helpPos;
485 if ((lprect == NULL) || (lppop == NULL)) return;
486 if (lppop->nItems == 0) return;
487 dprintf_menu(stddeb,"MENU_MenuBarCalcSize left=%d top=%d right=%d bottom=%d\n",
488 lprect->left, lprect->top, lprect->right, lprect->bottom);
489 lppop->Width = lprect->right - lprect->left;
490 lppop->Height = 0;
491 maxY = lprect->top;
492 start = 0;
493 helpPos = -1;
494 while (start < lppop->nItems)
496 lpitem = &lppop->items[start];
497 orgX = lprect->left;
498 orgY = maxY;
500 /* Parse items until line break or end of menu */
501 for (i = start; i < lppop->nItems; i++, lpitem++)
503 if ((helpPos == -1) && (lpitem->item_flags & MF_HELP)) helpPos = i;
504 if ((i != start) &&
505 (lpitem->item_flags & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
506 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE );
507 if (lpitem->rect.right > lprect->right)
509 if (i != start) break;
510 else lpitem->rect.right = lprect->right;
512 maxY = MAX( maxY, lpitem->rect.bottom );
513 orgX = lpitem->rect.right;
516 /* Finish the line (set all items to the largest height found) */
517 while (start < i) lppop->items[start++].rect.bottom = maxY;
520 lprect->bottom = maxY;
521 lppop->Height = lprect->bottom - lprect->top;
523 /* Flush right all items between the MF_HELP and the last item */
524 /* (if several lines, only move the last line) */
525 if (helpPos != -1)
527 lpitem = &lppop->items[lppop->nItems-1];
528 orgY = lpitem->rect.top;
529 orgX = lprect->right;
530 for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--)
532 if (lpitem->rect.top != orgY) break; /* Other line */
533 if (lpitem->rect.right >= orgX) break; /* Too far right already */
534 lpitem->rect.left += orgX - lpitem->rect.right;
535 lpitem->rect.right = orgX;
536 orgX = lpitem->rect.left;
542 /***********************************************************************
543 * MENU_DrawMenuItem
545 * Draw a single menu item.
547 static void MENU_DrawMenuItem( HWND32 hwnd, HDC32 hdc, MENUITEM *lpitem,
548 UINT32 height, BOOL32 menuBar )
550 RECT32 rect;
552 if (lpitem->item_flags & MF_OWNERDRAW)
554 DRAWITEMSTRUCT32 dis;
556 dprintf_menu( stddeb, "DrawMenuItem: Ownerdraw!\n" );
557 dis.CtlType = ODT_MENU;
558 dis.itemID = lpitem->item_id;
559 dis.itemData = (DWORD)lpitem->text;
560 dis.itemState = 0;
561 if (lpitem->item_flags & MF_CHECKED) dis.itemState |= ODS_CHECKED;
562 if (lpitem->item_flags & MF_GRAYED) dis.itemState |= ODS_GRAYED;
563 if (lpitem->item_flags & MF_HILITE) dis.itemState |= ODS_SELECTED;
564 dis.itemAction = ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS;
565 dis.hwndItem = hwnd;
566 dis.hDC = hdc;
567 dis.rcItem = lpitem->rect;
568 SendMessage32A( hwnd, WM_DRAWITEM, 0, (LPARAM)&dis );
569 return;
572 if (menuBar && (lpitem->item_flags & MF_SEPARATOR)) return;
573 rect = lpitem->rect;
575 /* Draw the background */
577 if (lpitem->item_flags & MF_HILITE)
578 FillRect32( hdc, &rect, sysColorObjects.hbrushHighlight );
579 else FillRect32( hdc, &rect, sysColorObjects.hbrushMenu );
580 SetBkMode32( hdc, TRANSPARENT );
582 /* Draw the separator bar (if any) */
584 if (!menuBar && (lpitem->item_flags & MF_MENUBARBREAK))
586 SelectObject32( hdc, sysColorObjects.hpenWindowFrame );
587 MoveTo( hdc, rect.left, 0 );
588 LineTo32( hdc, rect.left, height );
590 if (lpitem->item_flags & MF_SEPARATOR)
592 SelectObject32( hdc, sysColorObjects.hpenWindowFrame );
593 MoveTo( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2 );
594 LineTo32( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 );
595 return;
598 /* Setup colors */
600 if (lpitem->item_flags & MF_HILITE)
602 if (lpitem->item_flags & MF_GRAYED)
603 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
604 else
605 SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
606 SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
608 else
610 if (lpitem->item_flags & MF_GRAYED)
611 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
612 else
613 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
614 SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
617 if (!menuBar)
619 /* Draw the check mark */
621 if (lpitem->item_flags & MF_CHECKED)
623 GRAPH_DrawBitmap(hdc, lpitem->hCheckBit ? lpitem->hCheckBit :
624 hStdCheck, rect.left,
625 (rect.top+rect.bottom-check_bitmap_height) / 2,
626 0, 0, check_bitmap_width, check_bitmap_height );
628 else if (lpitem->hUnCheckBit != 0) /* Not checked */
630 GRAPH_DrawBitmap(hdc, lpitem->hUnCheckBit, rect.left,
631 (rect.top+rect.bottom-check_bitmap_height) / 2,
632 0, 0, check_bitmap_width, check_bitmap_height );
635 /* Draw the popup-menu arrow */
637 if (lpitem->item_flags & MF_POPUP)
639 GRAPH_DrawBitmap( hdc, hStdMnArrow,
640 rect.right-arrow_bitmap_width-1,
641 (rect.top+rect.bottom-arrow_bitmap_height) / 2,
642 0, 0, arrow_bitmap_width, arrow_bitmap_height );
645 rect.left += check_bitmap_width;
646 rect.right -= arrow_bitmap_width;
649 /* Draw the item text or bitmap */
651 if (lpitem->item_flags & MF_BITMAP)
653 GRAPH_DrawBitmap( hdc, (HBITMAP16)(UINT32)lpitem->text,
654 rect.left, rect.top, 0, 0,
655 rect.right-rect.left, rect.bottom-rect.top );
656 return;
658 /* No bitmap - process text if present */
659 else if (IS_STRING_ITEM(lpitem->item_flags))
661 register int i;
663 if (menuBar)
665 rect.left += MENU_BAR_ITEMS_SPACE / 2;
666 rect.right -= MENU_BAR_ITEMS_SPACE / 2;
667 i = strlen( lpitem->text );
669 else
671 for (i = 0; lpitem->text[i]; i++)
672 if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
673 break;
676 DrawText32A( hdc, lpitem->text, i, &rect,
677 DT_LEFT | DT_VCENTER | DT_SINGLELINE );
679 if (lpitem->text[i]) /* There's a tab or flush-right char */
681 if (lpitem->text[i] == '\t')
683 rect.left = lpitem->xTab;
684 DrawText32A( hdc, lpitem->text + i + 1, -1, &rect,
685 DT_LEFT | DT_VCENTER | DT_SINGLELINE );
687 else DrawText32A( hdc, lpitem->text + i + 1, -1, &rect,
688 DT_RIGHT | DT_VCENTER | DT_SINGLELINE );
694 /***********************************************************************
695 * MENU_DrawPopupMenu
697 * Paint a popup menu.
699 static void MENU_DrawPopupMenu( HWND32 hwnd, HDC32 hdc, HMENU32 hmenu )
701 POPUPMENU *menu;
702 MENUITEM *item;
703 RECT32 rect;
704 UINT32 i;
706 GetClientRect32( hwnd, &rect );
707 FillRect32( hdc, &rect, sysColorObjects.hbrushMenu );
708 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
709 if (!menu || !menu->nItems) return;
710 for (i = menu->nItems, item = menu->items; i > 0; i--, item++)
711 MENU_DrawMenuItem( hwnd, hdc, item, menu->Height, FALSE );
715 /***********************************************************************
716 * MENU_DrawMenuBar
718 * Paint a menu bar. Returns the height of the menu bar.
720 UINT32 MENU_DrawMenuBar( HDC32 hDC, LPRECT32 lprect, HWND32 hwnd,
721 BOOL32 suppress_draw)
723 LPPOPUPMENU lppop;
724 UINT32 i;
725 WND *wndPtr = WIN_FindWndPtr( hwnd );
727 lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR( (HMENU16)wndPtr->wIDmenu );
728 if (lppop == NULL || lprect == NULL) return SYSMETRICS_CYMENU;
729 dprintf_menu(stddeb,"MENU_DrawMenuBar(%04x, %p, %p); !\n",
730 hDC, lprect, lppop);
731 if (lppop->Height == 0) MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
732 lprect->bottom = lprect->top + lppop->Height;
733 if (suppress_draw) return lppop->Height;
735 FillRect32(hDC, lprect, sysColorObjects.hbrushMenu );
736 SelectObject32( hDC, sysColorObjects.hpenWindowFrame );
737 MoveTo( hDC, lprect->left, lprect->bottom );
738 LineTo32( hDC, lprect->right, lprect->bottom );
740 if (lppop->nItems == 0) return SYSMETRICS_CYMENU;
741 for (i = 0; i < lppop->nItems; i++)
743 MENU_DrawMenuItem( hwnd, hDC, &lppop->items[i], lppop->Height, TRUE );
745 return lppop->Height;
749 /***********************************************************************
750 * MENU_SwitchTPWndTo
752 BOOL32 MENU_SwitchTPWndTo( HTASK16 hTask )
754 /* This is supposed to be called when popup is hidden.
755 * AppExit() calls with hTask == 0, so we get the next to current.
758 TDB* task;
760 if( !pTopPWnd ) return 0;
762 if( !hTask )
764 task = (TDB*)GlobalLock16( (hTask = GetCurrentTask()) );
765 if( task && task->hQueue == pTopPWnd->hmemTaskQ )
766 hTask = TASK_GetNextTask(hTask);
767 else return 0;
770 task = (TDB*)GlobalLock16(hTask);
771 if( !task ) return 0;
773 /* if this task got as far as menu tracking it must have a queue */
775 pTopPWnd->hInstance = task->hInstance;
776 pTopPWnd->hmemTaskQ = task->hQueue;
777 return 1;
780 /***********************************************************************
781 * MENU_ShowPopup
783 * Display a popup menu.
785 static BOOL32 MENU_ShowPopup( HWND32 hwndOwner, HMENU32 hmenu, UINT32 id,
786 INT32 x, INT32 y, INT32 xanchor, INT32 yanchor )
788 POPUPMENU *menu;
789 WND *wndPtr = NULL;
790 BOOL32 skip_init = 0;
791 UINT32 width, height;
793 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
794 if (menu->FocusedItem != NO_SELECTED_ITEM)
796 menu->items[menu->FocusedItem].item_flags &= ~(MF_HILITE|MF_MOUSESELECT);
797 menu->FocusedItem = NO_SELECTED_ITEM;
799 SendMessage16( hwndOwner, WM_INITMENUPOPUP, (WPARAM16)hmenu,
800 MAKELONG( id, (menu->wFlags & MF_SYSMENU) ? 1 : 0 ));
801 MENU_PopupMenuCalcSize( menu, hwndOwner );
803 /* adjust popup menu pos so that it fits within the desktop */
805 width = menu->Width + 2*SYSMETRICS_CXBORDER;
806 height = menu->Height + 2*SYSMETRICS_CYBORDER;
808 if( x + width > SYSMETRICS_CXSCREEN )
810 if( xanchor )
811 x -= width - xanchor;
812 if( x + width > SYSMETRICS_CXSCREEN)
813 x = SYSMETRICS_CXSCREEN - width;
815 if( x < 0 )
816 x = 0;
818 if( y + height > SYSMETRICS_CYSCREEN )
820 if( yanchor )
821 y -= height + yanchor;
822 if( y + height > SYSMETRICS_CYSCREEN )
823 y = SYSMETRICS_CYSCREEN - height;
825 if( y < 0 )
826 y = 0;
828 wndPtr = WIN_FindWndPtr( hwndOwner );
829 if (!wndPtr) return FALSE;
831 if (!pTopPWnd)
833 pTopPWnd = WIN_FindWndPtr(CreateWindow32A( POPUPMENU_CLASS_ATOM, NULL,
834 WS_POPUP | WS_BORDER, x, y,
835 width, height,
836 hwndOwner, 0, wndPtr->hInstance,
837 (LPVOID)hmenu ));
838 if (!pTopPWnd) return FALSE;
839 skip_init = TRUE;
842 if( uSubPWndLevel )
844 /* create new window for the submenu */
845 HWND32 hWnd = CreateWindow32A( POPUPMENU_CLASS_ATOM, NULL,
846 WS_POPUP | WS_BORDER, x, y,
847 width, height,
848 menu->hWnd, 0, wndPtr->hInstance,
849 (LPVOID)hmenu );
850 if( !hWnd ) return FALSE;
851 menu->hWnd = hWnd;
853 else
855 if( !skip_init )
857 MENU_SwitchTPWndTo(GetCurrentTask());
858 SendMessage16( pTopPWnd->hwndSelf, WM_USER, (WPARAM16)hmenu, 0L);
860 menu->hWnd = pTopPWnd->hwndSelf;
863 uSubPWndLevel++;
865 wndPtr = WIN_FindWndPtr( menu->hWnd );
867 SetWindowPos(menu->hWnd, 0, x, y, width, height,
868 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW);
869 /* Display the window */
871 SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
872 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
873 UpdateWindow( menu->hWnd );
874 return TRUE;
878 /***********************************************************************
879 * MENU_SelectItem
881 static void MENU_SelectItem( HWND32 hwndOwner, HMENU32 hmenu, UINT32 wIndex,
882 BOOL32 sendMenuSelect )
884 LPPOPUPMENU lppop;
885 HDC32 hdc;
887 lppop = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
888 if (!lppop->nItems) return;
889 if ((wIndex != NO_SELECTED_ITEM) &&
890 (wIndex != SYSMENU_SELECTED) &&
891 (lppop->items[wIndex].item_flags & MF_SEPARATOR))
892 wIndex = NO_SELECTED_ITEM;
893 if (lppop->FocusedItem == wIndex) return;
894 if (lppop->wFlags & MF_POPUP) hdc = GetDC32( lppop->hWnd );
895 else hdc = GetDCEx32( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
897 /* Clear previous highlighted item */
898 if (lppop->FocusedItem != NO_SELECTED_ITEM)
900 if (lppop->FocusedItem == SYSMENU_SELECTED)
901 NC_DrawSysButton( lppop->hWnd, hdc, FALSE );
902 else
904 lppop->items[lppop->FocusedItem].item_flags &=~(MF_HILITE|MF_MOUSESELECT);
905 MENU_DrawMenuItem(lppop->hWnd,hdc,&lppop->items[lppop->FocusedItem],
906 lppop->Height, !(lppop->wFlags & MF_POPUP) );
910 /* Highlight new item (if any) */
911 lppop->FocusedItem = wIndex;
912 if (lppop->FocusedItem != NO_SELECTED_ITEM)
914 if (lppop->FocusedItem == SYSMENU_SELECTED)
916 NC_DrawSysButton( lppop->hWnd, hdc, TRUE );
917 if (sendMenuSelect)
918 SendMessage16( hwndOwner, WM_MENUSELECT,
919 WIN_FindWndPtr(lppop->hWnd)->hSysMenu,
920 MAKELONG(lppop->wFlags | MF_MOUSESELECT, hmenu));
922 else
924 lppop->items[lppop->FocusedItem].item_flags |= MF_HILITE;
925 MENU_DrawMenuItem( lppop->hWnd, hdc, &lppop->items[lppop->FocusedItem],
926 lppop->Height, !(lppop->wFlags & MF_POPUP) );
927 if (sendMenuSelect)
928 SendMessage16( hwndOwner, WM_MENUSELECT,
929 lppop->items[lppop->FocusedItem].item_id,
930 MAKELONG( lppop->items[lppop->FocusedItem].item_flags | MF_MOUSESELECT, hmenu));
933 else if (sendMenuSelect)
934 SendMessage16( hwndOwner, WM_MENUSELECT, hmenu,
935 MAKELONG( lppop->wFlags | MF_MOUSESELECT, hmenu ) );
937 ReleaseDC32( lppop->hWnd, hdc );
941 /***********************************************************************
942 * MENU_SelectItemRel
945 static void MENU_SelectItemRel( HWND32 hwndOwner, HMENU32 hmenu, INT32 offset )
947 INT32 i, min = 0;
948 POPUPMENU *menu;
950 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
951 if (!menu->items) return;
952 if ((menu->FocusedItem != NO_SELECTED_ITEM) &&
953 (menu->FocusedItem != SYSMENU_SELECTED))
955 for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems
956 ; i += offset)
958 if (!(menu->items[i].item_flags & MF_SEPARATOR))
960 MENU_SelectItem( hwndOwner, hmenu, i, TRUE );
961 return;
965 if (MENU_HasSysMenu( menu ))
967 MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED, TRUE );
968 return;
972 if( offset > 0 ) { i = 0; min = -1; }
973 else i = menu->nItems - 1;
975 for ( ; i > min && i < menu->nItems ; i += offset)
977 if (!(menu->items[i].item_flags & MF_SEPARATOR))
979 MENU_SelectItem( hwndOwner, hmenu, i, TRUE );
980 return;
983 if (MENU_HasSysMenu( menu ))
984 MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED, TRUE );
988 /**********************************************************************
989 * MENU_SetItemData
991 * Set an item flags, id and text ptr.
993 static BOOL32 MENU_SetItemData( MENUITEM *item, UINT32 flags, UINT32 id,
994 LPCSTR str )
996 LPSTR prevText = IS_STRING_ITEM(item->item_flags) ? item->text : NULL;
998 if (IS_STRING_ITEM(flags))
1000 if (!str)
1002 flags |= MF_SEPARATOR;
1003 item->text = NULL;
1005 else
1007 LPSTR text;
1008 /* Item beginning with a backspace is a help item */
1009 if (*str == '\b')
1011 flags |= MF_HELP;
1012 str++;
1014 if (!(text = HEAP_strdupA( SystemHeap, 0, str ))) return FALSE;
1015 item->text = text;
1018 else if ((flags & MF_BITMAP) || (flags & MF_OWNERDRAW))
1019 item->text = (LPSTR)str;
1020 else item->text = NULL;
1022 item->item_flags = flags & ~(MF_HILITE | MF_MOUSESELECT);
1023 item->item_id = id;
1024 SetRectEmpty32( &item->rect );
1025 if (prevText) HeapFree( SystemHeap, 0, prevText );
1026 return TRUE;
1030 /**********************************************************************
1031 * MENU_InsertItem
1033 * Insert a new item into a menu.
1035 static MENUITEM *MENU_InsertItem( HMENU32 hMenu, UINT32 pos, UINT32 flags )
1037 MENUITEM *newItems;
1038 POPUPMENU *menu;
1040 if (!(menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu)))
1042 dprintf_menu( stddeb, "MENU_InsertItem: %04x not a menu handle\n",
1043 hMenu );
1044 return NULL;
1047 /* Find where to insert new item */
1049 if ((flags & MF_BYPOSITION) &&
1050 ((pos == (UINT32)-1) || (pos == menu->nItems)))
1052 /* Special case: append to menu */
1053 /* Some programs specify the menu length to do that */
1054 pos = menu->nItems;
1056 else
1058 if (!MENU_FindItem( &hMenu, &pos, flags ))
1060 dprintf_menu( stddeb, "MENU_InsertItem: item %x not found\n",
1061 pos );
1062 return NULL;
1064 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu)))
1066 dprintf_menu(stddeb,"MENU_InsertItem: %04x not a menu handle\n",
1067 hMenu);
1068 return NULL;
1072 /* Create new items array */
1074 newItems = HeapAlloc( SystemHeap, 0, sizeof(MENUITEM) * (menu->nItems+1) );
1075 if (!newItems)
1077 dprintf_menu( stddeb, "MENU_InsertItem: allocation failed\n" );
1078 return NULL;
1080 if (menu->nItems > 0)
1082 /* Copy the old array into the new */
1083 if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
1084 if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
1085 (menu->nItems-pos)*sizeof(MENUITEM) );
1086 HeapFree( SystemHeap, 0, menu->items );
1088 menu->items = newItems;
1089 menu->nItems++;
1090 memset( &newItems[pos], 0, sizeof(*newItems) );
1091 return &newItems[pos];
1095 /**********************************************************************
1096 * MENU_ParseResource
1098 * Parse a standard menu resource and add items to the menu.
1099 * Return a pointer to the end of the resource.
1101 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU32 hMenu, BOOL32 unicode )
1103 WORD flags, id = 0;
1104 LPCSTR str;
1108 flags = GET_WORD(res);
1109 res += sizeof(WORD);
1110 if (!(flags & MF_POPUP))
1112 id = GET_WORD(res);
1113 res += sizeof(WORD);
1115 if (!IS_STRING_ITEM(flags))
1116 fprintf( stderr, "MENU_ParseResource: not a string item %04x\n",
1117 flags );
1118 str = res;
1119 if (!unicode) res += strlen(str) + 1;
1120 else res += (lstrlen32W((LPCWSTR)str) + 1) * sizeof(WCHAR);
1121 if (flags & MF_POPUP)
1123 HMENU32 hSubMenu = CreatePopupMenu32();
1124 if (!hSubMenu) return NULL;
1125 if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
1126 return NULL;
1127 if (!unicode) AppendMenu32A( hMenu, flags, (UINT32)hSubMenu, str );
1128 else AppendMenu32W( hMenu, flags, (UINT32)hSubMenu, (LPCWSTR)str );
1130 else /* Not a popup */
1132 if (!unicode) AppendMenu32A( hMenu, flags, id, *str ? str : NULL );
1133 else AppendMenu32W( hMenu, flags, id,
1134 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
1136 } while (!(flags & MF_END));
1137 return res;
1141 /***********************************************************************
1142 * MENU_GetSubPopup
1144 * Return the handle of the selected sub-popup menu (if any).
1146 static HMENU32 MENU_GetSubPopup( HMENU32 hmenu )
1148 POPUPMENU *menu;
1149 MENUITEM *item;
1151 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1152 if (menu->FocusedItem == NO_SELECTED_ITEM) return 0;
1153 else if (menu->FocusedItem == SYSMENU_SELECTED)
1154 return WIN_FindWndPtr(menu->hWnd)->hSysMenu;
1156 item = &menu->items[menu->FocusedItem];
1157 if (!(item->item_flags & MF_POPUP) || !(item->item_flags & MF_MOUSESELECT))
1158 return 0;
1159 return (HMENU32)item->item_id;
1163 /***********************************************************************
1164 * MENU_HideSubPopups
1166 * Hide the sub-popup menus of this menu.
1168 static void MENU_HideSubPopups( HWND32 hwndOwner, HMENU32 hmenu,
1169 BOOL32 sendMenuSelect )
1171 MENUITEM *item;
1172 POPUPMENU *menu, *submenu;
1173 HMENU32 hsubmenu;
1175 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return;
1176 if (menu->FocusedItem == NO_SELECTED_ITEM) return;
1177 if (menu->FocusedItem == SYSMENU_SELECTED)
1179 hsubmenu = WIN_FindWndPtr(menu->hWnd)->hSysMenu;
1181 else
1183 item = &menu->items[menu->FocusedItem];
1184 if (!(item->item_flags & MF_POPUP) ||
1185 !(item->item_flags & MF_MOUSESELECT)) return;
1186 item->item_flags &= ~MF_MOUSESELECT;
1187 hsubmenu = (HMENU32)item->item_id;
1189 submenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hsubmenu );
1190 MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
1191 MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect );
1192 if (submenu->hWnd == pTopPWnd->hwndSelf )
1194 ShowWindow( submenu->hWnd, SW_HIDE );
1195 uSubPWndLevel = 0;
1197 else
1199 DestroyWindow( submenu->hWnd );
1200 submenu->hWnd = 0;
1205 /***********************************************************************
1206 * MENU_ShowSubPopup
1208 * Display the sub-menu of the selected item of this menu.
1209 * Return the handle of the submenu, or hmenu if no submenu to display.
1211 static HMENU32 MENU_ShowSubPopup( HWND32 hwndOwner, HMENU32 hmenu,
1212 BOOL32 selectFirst )
1214 POPUPMENU *menu;
1215 MENUITEM *item;
1216 WND *wndPtr;
1218 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return hmenu;
1219 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return hmenu;
1220 if (menu->FocusedItem == NO_SELECTED_ITEM) return hmenu;
1221 if (menu->FocusedItem == SYSMENU_SELECTED)
1223 MENU_InitSysMenuPopup(wndPtr->hSysMenu, wndPtr->dwStyle,
1224 wndPtr->class->style);
1225 MENU_ShowPopup(hwndOwner, wndPtr->hSysMenu, 0, wndPtr->rectClient.left,
1226 wndPtr->rectClient.top - menu->Height - 2*SYSMETRICS_CYBORDER,
1227 SYSMETRICS_CXSIZE, SYSMETRICS_CYSIZE );
1228 if (selectFirst)
1229 MENU_SelectItemRel( hwndOwner, wndPtr->hSysMenu, ITEM_NEXT );
1230 return wndPtr->hSysMenu;
1232 item = &menu->items[menu->FocusedItem];
1233 if (!(item->item_flags & MF_POPUP) ||
1234 (item->item_flags & (MF_GRAYED | MF_DISABLED))) return hmenu;
1235 item->item_flags |= MF_MOUSESELECT;
1236 if (menu->wFlags & MF_POPUP)
1238 MENU_ShowPopup( hwndOwner, (HMENU16)item->item_id, menu->FocusedItem,
1239 wndPtr->rectWindow.left + item->rect.right-arrow_bitmap_width,
1240 wndPtr->rectWindow.top + item->rect.top,
1241 item->rect.left - item->rect.right + 2*arrow_bitmap_width,
1242 item->rect.top - item->rect.bottom );
1244 else
1246 MENU_ShowPopup( hwndOwner, (HMENU16)item->item_id, menu->FocusedItem,
1247 wndPtr->rectWindow.left + item->rect.left,
1248 wndPtr->rectWindow.top + item->rect.bottom,
1249 item->rect.right - item->rect.left,
1250 item->rect.bottom - item->rect.top );
1252 if (selectFirst)
1253 MENU_SelectItemRel( hwndOwner, (HMENU32)item->item_id, ITEM_NEXT );
1254 return (HMENU32)item->item_id;
1258 /***********************************************************************
1259 * MENU_FindMenuByCoords
1261 * Find the menu containing a given point (in screen coords).
1263 static HMENU32 MENU_FindMenuByCoords( HMENU32 hmenu, POINT32 pt )
1265 POPUPMENU *menu;
1266 HWND32 hwnd;
1268 if (!(hwnd = WindowFromPoint32( pt ))) return 0;
1269 while (hmenu)
1271 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1272 if (menu->hWnd == hwnd)
1274 if (!(menu->wFlags & MF_POPUP))
1276 /* Make sure it's in the menu bar (or in system menu) */
1277 WND *wndPtr = WIN_FindWndPtr( menu->hWnd );
1278 if ((pt.x < wndPtr->rectClient.left) ||
1279 (pt.x >= wndPtr->rectClient.right) ||
1280 (pt.y >= wndPtr->rectClient.top)) return 0;
1281 if (pt.y < wndPtr->rectClient.top - menu->Height)
1283 if (!MENU_IsInSysMenu( menu, pt )) return 0;
1285 /* else it's in the menu bar */
1287 return hmenu;
1289 hmenu = MENU_GetSubPopup( hmenu );
1291 return 0;
1295 /***********************************************************************
1296 * MENU_ExecFocusedItem
1298 * Execute a menu item (for instance when user pressed Enter).
1299 * Return TRUE if we can go on with menu tracking.
1301 static BOOL32 MENU_ExecFocusedItem( HWND32 hwndOwner, HMENU32 hmenu,
1302 HMENU32 *hmenuCurrent )
1304 MENUITEM *item;
1305 POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1306 if (!menu || !menu->nItems || (menu->FocusedItem == NO_SELECTED_ITEM) ||
1307 (menu->FocusedItem == SYSMENU_SELECTED)) return TRUE;
1308 item = &menu->items[menu->FocusedItem];
1309 if (!(item->item_flags & MF_POPUP))
1311 if (!(item->item_flags & (MF_GRAYED | MF_DISABLED)))
1313 PostMessage( hwndOwner, (menu->wFlags & MF_SYSMENU) ?
1314 WM_SYSCOMMAND : WM_COMMAND, item->item_id, 0 );
1315 return FALSE;
1317 else return TRUE;
1319 else
1321 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, TRUE );
1322 return TRUE;
1327 /***********************************************************************
1328 * MENU_ButtonDown
1330 * Handle a button-down event in a menu. Point is in screen coords.
1331 * hmenuCurrent is the top-most visible popup.
1332 * Return TRUE if we can go on with menu tracking.
1334 static BOOL32 MENU_ButtonDown( HWND32 hwndOwner, HMENU32 hmenu,
1335 HMENU32 *hmenuCurrent, POINT32 pt )
1337 POPUPMENU *menu;
1338 MENUITEM *item;
1339 UINT32 id;
1341 if (!hmenu) return FALSE; /* Outside all menus */
1342 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1343 item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
1344 if (!item) /* Maybe in system menu */
1346 if (!MENU_IsInSysMenu( menu, pt )) return FALSE;
1347 id = SYSMENU_SELECTED;
1350 if (menu->FocusedItem == id)
1352 if (id == SYSMENU_SELECTED) return FALSE;
1353 if (item->item_flags & MF_POPUP)
1355 if (item->item_flags & MF_MOUSESELECT)
1357 if (menu->wFlags & MF_POPUP)
1359 MENU_HideSubPopups( hwndOwner, hmenu, TRUE );
1360 *hmenuCurrent = hmenu;
1362 else return FALSE;
1364 else *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
1367 else
1369 MENU_HideSubPopups( hwndOwner, hmenu, FALSE );
1370 MENU_SelectItem( hwndOwner, hmenu, id, TRUE );
1371 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
1373 return TRUE;
1377 /***********************************************************************
1378 * MENU_ButtonUp
1380 * Handle a button-up event in a menu. Point is in screen coords.
1381 * hmenuCurrent is the top-most visible popup.
1382 * Return TRUE if we can go on with menu tracking.
1384 static BOOL32 MENU_ButtonUp( HWND32 hwndOwner, HMENU32 hmenu,
1385 HMENU32 *hmenuCurrent, POINT32 pt )
1387 POPUPMENU *menu;
1388 MENUITEM *item;
1389 HMENU32 hsubmenu = 0;
1390 UINT32 id;
1392 if (!hmenu) return FALSE; /* Outside all menus */
1393 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1394 item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
1395 if (!item) /* Maybe in system menu */
1397 if (!MENU_IsInSysMenu( menu, pt )) return FALSE;
1398 id = SYSMENU_SELECTED;
1399 hsubmenu = WIN_FindWndPtr(menu->hWnd)->hSysMenu;
1402 if (menu->FocusedItem != id) return FALSE;
1404 if (id != SYSMENU_SELECTED)
1406 if (!(item->item_flags & MF_POPUP))
1408 return MENU_ExecFocusedItem( hwndOwner, hmenu, hmenuCurrent );
1410 hsubmenu = (HMENU32)item->item_id;
1412 /* Select first item of sub-popup */
1413 MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, FALSE );
1414 MENU_SelectItemRel( hwndOwner, hsubmenu, ITEM_NEXT );
1415 return TRUE;
1419 /***********************************************************************
1420 * MENU_MouseMove
1422 * Handle a motion event in a menu. Point is in screen coords.
1423 * hmenuCurrent is the top-most visible popup.
1424 * Return TRUE if we can go on with menu tracking.
1426 static BOOL32 MENU_MouseMove( HWND32 hwndOwner, HMENU32 hmenu,
1427 HMENU32 *hmenuCurrent, POINT32 pt )
1429 MENUITEM *item;
1430 POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1431 UINT32 id = NO_SELECTED_ITEM;
1433 if (hmenu)
1435 item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
1436 if (!item) /* Maybe in system menu */
1438 if (!MENU_IsInSysMenu( menu, pt ))
1439 id = NO_SELECTED_ITEM; /* Outside all items */
1440 else id = SYSMENU_SELECTED;
1443 if (id == NO_SELECTED_ITEM)
1445 MENU_SelectItem( hwndOwner, *hmenuCurrent, NO_SELECTED_ITEM, TRUE );
1447 else if (menu->FocusedItem != id)
1449 MENU_HideSubPopups( hwndOwner, hmenu, FALSE );
1450 MENU_SelectItem( hwndOwner, hmenu, id, TRUE );
1451 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
1453 return TRUE;
1457 /***********************************************************************
1458 * MENU_DoNextMenu
1460 static LRESULT MENU_DoNextMenu( HWND32* hwndOwner, HMENU32* hmenu,
1461 HMENU32 *hmenuCurrent, UINT32 vk )
1463 POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( *hmenu );
1464 UINT32 id = 0;
1466 if( (vk == VK_LEFT && !menu->FocusedItem)
1467 || (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1)
1468 || menu->FocusedItem == SYSMENU_SELECTED
1469 || ((menu->wFlags & (MF_POPUP | MF_SYSMENU)) == (MF_POPUP | MF_SYSMENU)))
1471 LRESULT l = SendMessage16( *hwndOwner, WM_NEXTMENU, (WPARAM16)vk,
1472 (LPARAM)((menu->FocusedItem == SYSMENU_SELECTED)
1473 ? GetSystemMenu32( *hwndOwner, 0)
1474 : *hmenu));
1476 if( l == 0 || !IsMenu32(LOWORD(l)) || !IsWindow(HIWORD(l)) ) return 0;
1478 /* shutdown current menu -
1479 * all these checks for system popup window are needed
1480 * only because Wine system menu tracking is unsuitable
1481 * for a lot of things (esp. when we do not have wIDmenu to fall back on).
1484 MENU_SelectItem( *hwndOwner, *hmenu, NO_SELECTED_ITEM, FALSE );
1486 if( (menu->wFlags & (MF_POPUP | MF_SYSMENU)) == (MF_POPUP | MF_SYSMENU) )
1488 ShowWindow( menu->hWnd, SW_HIDE );
1489 uSubPWndLevel = 0;
1491 if( !IsIconic( *hwndOwner ) )
1493 HDC32 hdc = GetDCEx32( *hwndOwner, 0, DCX_CACHE | DCX_WINDOW);
1494 NC_DrawSysButton( *hwndOwner, hdc, FALSE );
1495 ReleaseDC32( *hwndOwner, hdc );
1499 ReleaseCapture();
1500 *hwndOwner = HIWORD(l);
1501 *hmenu = LOWORD(l);
1502 SetCapture32( *hwndOwner );
1504 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( *hmenu );
1506 /* init next menu */
1508 if( (menu->wFlags & (MF_POPUP | MF_SYSMENU)) == (MF_POPUP | MF_SYSMENU) )
1510 RECT32 rect;
1511 WND* wndPtr = WIN_FindWndPtr( *hwndOwner );
1513 /* stupid kludge, see above */
1515 if( wndPtr->wIDmenu && !(wndPtr->dwStyle & WS_CHILD) )
1517 *hmenu = wndPtr->wIDmenu;
1518 id = SYSMENU_SELECTED;
1520 else
1522 if( NC_GetSysPopupPos( wndPtr, &rect ) )
1523 MENU_ShowPopup( *hwndOwner, *hmenu, 0, rect.left, rect.bottom,
1524 SYSMETRICS_CXSIZE, SYSMETRICS_CYSIZE );
1526 if( !IsIconic( *hwndOwner ) )
1528 HDC32 hdc = GetDCEx32( *hwndOwner, 0, DCX_CACHE | DCX_WINDOW);
1529 NC_DrawSysButton( *hwndOwner, hdc, TRUE );
1530 ReleaseDC32( *hwndOwner, hdc );
1535 MENU_SelectItem( *hwndOwner, *hmenu, id, TRUE );
1536 return l;
1538 return 0;
1541 /***********************************************************************
1542 * MENU_KeyLeft
1544 * Handle a VK_LEFT key event in a menu.
1545 * hmenuCurrent is the top-most visible popup.
1547 static void MENU_KeyLeft( HWND32* hwndOwner, HMENU32* hmenu,
1548 HMENU32 *hmenuCurrent )
1550 POPUPMENU *menu;
1551 HMENU32 hmenutmp, hmenuprev;
1553 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( *hmenu );
1554 hmenuprev = hmenutmp = *hmenu;
1555 while (hmenutmp != *hmenuCurrent)
1557 hmenutmp = MENU_GetSubPopup( hmenuprev );
1558 if (hmenutmp != *hmenuCurrent) hmenuprev = hmenutmp;
1560 MENU_HideSubPopups( *hwndOwner, hmenuprev, TRUE );
1561 hmenutmp = *hmenu;
1563 if ( (hmenuprev == *hmenu) &&
1564 ((menu->wFlags & MF_SYSMENU) || !(menu->wFlags & MF_POPUP)) )
1566 /* send WM_NEXTMENU */
1568 if( !MENU_DoNextMenu( hwndOwner, hmenu, hmenuCurrent, VK_LEFT) )
1569 MENU_SelectItemRel( *hwndOwner, *hmenu, ITEM_PREV );
1570 else *hmenuCurrent = *hmenu;
1572 if (*hmenuCurrent != hmenutmp)
1574 /* A sublevel menu was displayed -> display the next one */
1575 *hmenuCurrent = MENU_ShowSubPopup( *hwndOwner, *hmenu, TRUE );
1578 else *hmenuCurrent = hmenuprev;
1582 /***********************************************************************
1583 * MENU_KeyRight
1585 * Handle a VK_RIGHT key event in a menu.
1586 * hmenuCurrent is the top-most visible popup.
1588 static void MENU_KeyRight( HWND32* hwndOwner, HMENU32* hmenu,
1589 HMENU32 *hmenuCurrent )
1591 POPUPMENU *menu;
1592 HMENU32 hmenutmp;
1594 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( *hmenu );
1596 if ((menu->wFlags & MF_POPUP) || (*hmenuCurrent != *hmenu))
1598 /* If already displaying a popup, try to display sub-popup */
1599 hmenutmp = MENU_ShowSubPopup( *hwndOwner, *hmenuCurrent, TRUE );
1600 if (hmenutmp != *hmenuCurrent) /* Sub-popup displayed */
1602 *hmenuCurrent = hmenutmp;
1603 return;
1607 /* If menu-bar tracking, go to next item */
1609 if (!(menu->wFlags & MF_POPUP) || (menu->wFlags & MF_SYSMENU))
1611 MENU_HideSubPopups( *hwndOwner, *hmenu, FALSE );
1612 hmenutmp = *hmenu;
1614 /* Send WM_NEXTMENU */
1616 if( !MENU_DoNextMenu( hwndOwner, hmenu, hmenuCurrent, VK_RIGHT) )
1617 MENU_SelectItemRel( *hwndOwner, *hmenu, ITEM_NEXT );
1618 else *hmenuCurrent = *hmenu;
1620 if (*hmenuCurrent != hmenutmp)
1622 /* A sublevel menu was displayed -> display the next one */
1623 *hmenuCurrent = MENU_ShowSubPopup( *hwndOwner, *hmenu, TRUE );
1626 else if (*hmenuCurrent != *hmenu) /* Hide last level popup */
1628 HMENU16 hmenuprev;
1629 hmenuprev = hmenutmp = *hmenu;
1630 while (hmenutmp != *hmenuCurrent)
1632 hmenutmp = MENU_GetSubPopup( hmenuprev );
1633 if (hmenutmp != *hmenuCurrent) hmenuprev = hmenutmp;
1635 MENU_HideSubPopups( *hwndOwner, hmenuprev, TRUE );
1636 *hmenuCurrent = hmenuprev;
1641 /***********************************************************************
1642 * MENU_TrackMenu
1644 * Menu tracking code.
1645 * If 'x' and 'y' are not 0, we simulate a button-down event at (x,y)
1646 * before beginning tracking. This is to help menu-bar tracking.
1648 static BOOL32 MENU_TrackMenu( HMENU32 hmenu, UINT32 wFlags, INT32 x, INT32 y,
1649 HWND32 hwnd, const RECT32 *lprect )
1651 MSG16 msg;
1652 POPUPMENU *menu;
1653 HMENU32 hmenuCurrent = hmenu;
1654 BOOL32 fClosed = FALSE, fRemove;
1655 UINT32 pos;
1656 POINT32 pt;
1658 fEndMenuCalled = FALSE;
1659 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
1660 if (x && y)
1662 pt.x = x;
1663 pt.y = y;
1664 MENU_ButtonDown( hwnd, hmenu, &hmenuCurrent, pt );
1667 EVENT_Capture( hwnd, HTMENU );
1669 while (!fClosed)
1671 /* we have to keep the message in the queue until it's
1672 * clear that menu loop is not over yet.
1675 if (!MSG_InternalGetMessage( &msg, 0, hwnd, MSGF_MENU,
1676 PM_NOREMOVE, TRUE ))
1677 break;
1679 TranslateMessage( &msg );
1680 CONV_POINT16TO32( &msg.pt, &pt );
1682 fRemove = FALSE;
1683 if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
1685 /* Find the sub-popup for this mouse event (if any) */
1687 HMENU32 hsubmenu = MENU_FindMenuByCoords( hmenu, pt );
1689 switch(msg.message)
1691 /* no WM_NC... messages in captured state */
1693 case WM_RBUTTONDBLCLK:
1694 case WM_RBUTTONDOWN:
1695 if (!(wFlags & TPM_RIGHTBUTTON)) break;
1696 /* fall through */
1698 case WM_LBUTTONDBLCLK:
1699 case WM_LBUTTONDOWN:
1700 fClosed = !MENU_ButtonDown( hwnd, hsubmenu,
1701 &hmenuCurrent, pt );
1702 break;
1704 case WM_RBUTTONUP:
1705 if (!(wFlags & TPM_RIGHTBUTTON)) break;
1706 /* fall through */
1708 case WM_LBUTTONUP:
1709 /* If outside all menus but inside lprect, ignore it */
1710 if (!hsubmenu && lprect && PtInRect32(lprect, pt)) break;
1711 fClosed = !MENU_ButtonUp( hwnd, hsubmenu,
1712 &hmenuCurrent, pt );
1713 fRemove = TRUE; /* Remove event even if outside menu */
1714 break;
1716 case WM_MOUSEMOVE:
1717 if ((msg.wParam & MK_LBUTTON) ||
1718 ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON)))
1720 fClosed = !MENU_MouseMove( hwnd, hsubmenu,
1721 &hmenuCurrent, pt );
1723 break;
1726 else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
1728 fRemove = TRUE; /* Keyboard messages are always removed */
1729 switch(msg.message)
1731 case WM_KEYDOWN:
1732 switch(msg.wParam)
1734 case VK_HOME:
1735 case VK_END:
1736 MENU_SelectItem( hwnd, hmenuCurrent, NO_SELECTED_ITEM, FALSE );
1738 /* fall through */
1739 case VK_UP:
1740 MENU_SelectItemRel( hwnd, hmenuCurrent,
1741 (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
1742 break;
1744 case VK_DOWN: /* If on menu bar, pull-down the menu */
1746 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1747 if (!(menu->wFlags & MF_POPUP) && (hmenuCurrent == hmenu))
1748 hmenuCurrent = MENU_ShowSubPopup( hwnd, hmenu, TRUE );
1749 else
1750 MENU_SelectItemRel( hwnd, hmenuCurrent, ITEM_NEXT );
1751 break;
1753 case VK_LEFT:
1754 MENU_KeyLeft( &hwnd, &hmenu, &hmenuCurrent );
1755 break;
1757 case VK_RIGHT:
1758 MENU_KeyRight( &hwnd, &hmenu, &hmenuCurrent );
1759 break;
1761 case VK_SPACE:
1762 case VK_RETURN:
1763 fClosed = !MENU_ExecFocusedItem( hwnd, hmenuCurrent,
1764 &hmenuCurrent );
1765 break;
1767 case VK_ESCAPE:
1768 fClosed = TRUE;
1769 break;
1771 default:
1772 break;
1774 break; /* WM_KEYDOWN */
1776 case WM_SYSKEYDOWN:
1777 switch(msg.wParam)
1779 case VK_MENU:
1780 fClosed = TRUE;
1781 break;
1784 break; /* WM_SYSKEYDOWN */
1786 case WM_CHAR:
1788 /* Hack to avoid control chars. */
1789 /* We will find a better way real soon... */
1790 if ((msg.wParam <= 32) || (msg.wParam >= 127)) break;
1791 pos = MENU_FindItemByKey( hwnd, hmenuCurrent, msg.wParam );
1792 if (pos == (UINT32)-2) fClosed = TRUE;
1793 else if (pos == (UINT32)-1) MessageBeep(0);
1794 else
1796 MENU_SelectItem( hwnd, hmenuCurrent, pos, TRUE );
1797 fClosed = !MENU_ExecFocusedItem( hwnd, hmenuCurrent,
1798 &hmenuCurrent );
1802 break; /* WM_CHAR */
1803 } /* switch(msg.message) */
1805 else
1807 DispatchMessage( &msg );
1809 if (fEndMenuCalled) fClosed = TRUE;
1810 if (!fClosed) fRemove = TRUE;
1812 if (fRemove) /* Remove the message from the queue */
1813 PeekMessage16( &msg, 0, msg.message, msg.message, PM_REMOVE );
1816 ReleaseCapture();
1817 MENU_HideSubPopups( hwnd, hmenu, FALSE );
1818 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1819 if (menu && menu->wFlags & MF_POPUP)
1821 ShowWindow( menu->hWnd, SW_HIDE );
1822 uSubPWndLevel = 0;
1824 MENU_SelectItem( hwnd, hmenu, NO_SELECTED_ITEM, FALSE );
1825 SendMessage16( hwnd, WM_MENUSELECT, 0, MAKELONG( 0xffff, 0 ) );
1826 fEndMenuCalled = FALSE;
1827 return TRUE;
1830 /***********************************************************************
1831 * MENU_TrackSysPopup
1833 static void MENU_TrackSysPopup( WND* pWnd )
1835 RECT32 rect;
1836 HMENU32 hMenu = pWnd->hSysMenu;
1837 HDC32 hDC = 0;
1839 /* track the system menu like a normal popup menu */
1841 if(IsMenu32(hMenu))
1843 HWND32 hWnd = pWnd->hwndSelf;
1844 if (!(pWnd->dwStyle & WS_MINIMIZE))
1846 hDC = GetWindowDC32( hWnd );
1847 NC_DrawSysButton( hWnd, hDC, TRUE );
1849 NC_GetSysPopupPos( pWnd, &rect );
1850 MENU_InitSysMenuPopup( hMenu, pWnd->dwStyle,
1851 pWnd->class->style);
1852 TrackPopupMenu32( hMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
1853 rect.left, rect.bottom, 0, hWnd, &rect );
1854 if (!(pWnd->dwStyle & WS_MINIMIZE))
1856 NC_DrawSysButton( hWnd, hDC, FALSE );
1857 ReleaseDC32( hWnd, hDC );
1862 /***********************************************************************
1863 * MENU_TrackMouseMenuBar
1865 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
1867 void MENU_TrackMouseMenuBar( WND* wndPtr, INT32 ht, POINT32 pt )
1869 BOOL32 bTrackSys = ((ht == HTSYSMENU && !wndPtr->wIDmenu) ||
1870 (wndPtr->dwStyle & (WS_MINIMIZE | WS_CHILD)));
1871 HWND32 hWnd = wndPtr->hwndSelf;
1872 HMENU32 hMenu = (bTrackSys) ? wndPtr->hSysMenu : wndPtr->wIDmenu;
1874 if (IsMenu32(hMenu))
1876 HideCaret(0);
1877 SendMessage16( hWnd, WM_ENTERMENULOOP, 0, 0 );
1878 SendMessage16( hWnd, WM_INITMENU, hMenu, 0 );
1879 if( bTrackSys )
1880 MENU_TrackSysPopup( wndPtr );
1881 else
1882 MENU_TrackMenu( hMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
1883 pt.x, pt.y, hWnd, NULL );
1884 SendMessage16( hWnd, WM_EXITMENULOOP, 0, 0 );
1885 ShowCaret(0);
1890 /***********************************************************************
1891 * MENU_TrackKbdMenuBar
1893 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
1895 void MENU_TrackKbdMenuBar( WND* wndPtr, UINT32 wParam, INT32 vkey)
1897 INT32 htMenu;
1898 UINT32 uItem = NO_SELECTED_ITEM;
1899 HMENU32 hTrackMenu;
1901 /* find window that has a menu */
1903 while( wndPtr->dwStyle & WS_CHILD && !(wndPtr->dwStyle & WS_SYSMENU) )
1904 if( !(wndPtr = wndPtr->parent) ) return;
1906 if( !wndPtr->wIDmenu && !(wndPtr->dwStyle & WS_SYSMENU) ) return;
1908 htMenu = ((wndPtr->dwStyle & (WS_CHILD | WS_MINIMIZE)) ||
1909 !wndPtr->wIDmenu) ? HTSYSMENU : HTMENU;
1910 hTrackMenu = ( htMenu == HTSYSMENU ) ? wndPtr->hSysMenu : wndPtr->wIDmenu;
1912 if (IsMenu32( hTrackMenu ))
1914 HideCaret(0);
1915 SendMessage16( wndPtr->hwndSelf, WM_ENTERMENULOOP, 0, 0 );
1916 SendMessage16( wndPtr->hwndSelf, WM_INITMENU, hTrackMenu, 0 );
1918 /* find suitable menu entry */
1920 if( vkey == VK_SPACE )
1921 uItem = SYSMENU_SELECTED;
1922 else if( vkey )
1924 uItem = ( htMenu == HTSYSMENU )
1925 ? 0xFFFE /* only VK_SPACE in this case */
1926 : MENU_FindItemByKey( wndPtr->hwndSelf, wndPtr->wIDmenu, vkey );
1927 if( uItem >= 0xFFFE )
1929 if( uItem == 0xFFFF ) MessageBeep(0);
1930 htMenu = 0;
1934 switch( htMenu )
1936 case HTMENU:
1937 MENU_SelectItem( wndPtr->hwndSelf, hTrackMenu, uItem, TRUE );
1938 if( uItem == NO_SELECTED_ITEM )
1939 MENU_SelectItemRel( wndPtr->hwndSelf, hTrackMenu, ITEM_NEXT );
1940 else
1941 PostMessage( wndPtr->hwndSelf, WM_KEYDOWN, VK_DOWN, 0L );
1943 MENU_TrackMenu( hTrackMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
1944 0, 0, wndPtr->hwndSelf, NULL );
1945 break;
1947 case HTSYSMENU:
1948 MENU_TrackSysPopup( wndPtr );
1950 default:
1953 SendMessage16( wndPtr->hwndSelf, WM_EXITMENULOOP, 0, 0 );
1954 ShowCaret(0);
1959 /**********************************************************************
1960 * TrackPopupMenu16 (USER.416)
1962 BOOL16 TrackPopupMenu16( HMENU16 hMenu, UINT16 wFlags, INT16 x, INT16 y,
1963 INT16 nReserved, HWND16 hWnd, const RECT16 *lpRect )
1965 RECT32 r;
1966 if (lpRect)
1967 CONV_RECT16TO32( lpRect, &r );
1968 return TrackPopupMenu32( hMenu, wFlags, x, y, nReserved, hWnd,
1969 lpRect ? &r : NULL );
1973 /**********************************************************************
1974 * TrackPopupMenu32 (USER32.548)
1976 BOOL32 TrackPopupMenu32( HMENU32 hMenu, UINT32 wFlags, INT32 x, INT32 y,
1977 INT32 nReserved, HWND32 hWnd, const RECT32 *lpRect )
1979 BOOL32 ret = FALSE;
1981 HideCaret(0);
1982 if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
1983 ret = MENU_TrackMenu( hMenu, wFlags, 0, 0, hWnd, lpRect );
1984 ShowCaret(0);
1985 return ret;
1988 /**********************************************************************
1989 * TrackPopupMenuEx (USER32.549)
1991 BOOL32 TrackPopupMenuEx( HMENU32 hMenu, UINT32 wFlags, INT32 x, INT32 y,
1992 HWND32 hWnd, LPTPMPARAMS lpTpm )
1994 fprintf( stderr, "TrackPopupMenuEx: not fully implemented\n" );
1995 return TrackPopupMenu32( hMenu, wFlags, x, y, 0, hWnd,
1996 lpTpm ? &lpTpm->rcExclude : NULL );
1999 /***********************************************************************
2000 * PopupMenuWndProc
2002 LRESULT PopupMenuWndProc( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
2003 LPARAM lParam )
2005 switch(message)
2007 case WM_CREATE:
2009 CREATESTRUCT32A *cs = (CREATESTRUCT32A*)lParam;
2010 SetWindowLong32A( hwnd, 0, (LONG)cs->lpCreateParams );
2011 return 0;
2014 case WM_MOUSEACTIVATE: /* We don't want to be activated */
2015 return MA_NOACTIVATE;
2017 case WM_PAINT:
2019 PAINTSTRUCT32 ps;
2020 BeginPaint32( hwnd, &ps );
2021 MENU_DrawPopupMenu( hwnd, ps.hdc,
2022 (HMENU32)GetWindowLong32A( hwnd, 0 ) );
2023 EndPaint32( hwnd, &ps );
2024 return 0;
2027 case WM_DESTROY:
2028 /* zero out global pointer in case system popup
2029 * was destroyed by AppExit
2032 if( hwnd == pTopPWnd->hwndSelf )
2033 { pTopPWnd = NULL; uSubPWndLevel = 0; }
2034 else
2035 uSubPWndLevel--;
2036 break;
2038 case WM_USER:
2039 if (wParam) SetWindowLong32A( hwnd, 0, (HMENU16)wParam );
2040 break;
2041 default:
2042 return DefWindowProc32A( hwnd, message, wParam, lParam );
2044 return 0;
2048 /***********************************************************************
2049 * MENU_GetMenuBarHeight
2051 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
2053 UINT32 MENU_GetMenuBarHeight( HWND32 hwnd, UINT32 menubarWidth,
2054 INT32 orgX, INT32 orgY )
2056 HDC32 hdc;
2057 RECT32 rectBar;
2058 WND *wndPtr;
2059 LPPOPUPMENU lppop;
2061 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
2062 if (!(lppop = (LPPOPUPMENU)USER_HEAP_LIN_ADDR((HMENU16)wndPtr->wIDmenu)))
2063 return 0;
2064 hdc = GetDCEx32( hwnd, 0, DCX_CACHE | DCX_WINDOW );
2065 SetRect32(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+SYSMETRICS_CYMENU);
2066 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
2067 ReleaseDC32( hwnd, hdc );
2068 return lppop->Height;
2072 /*******************************************************************
2073 * ChangeMenu16 (USER.153)
2075 BOOL16 ChangeMenu16( HMENU16 hMenu, UINT16 pos, SEGPTR data,
2076 UINT16 id, UINT16 flags )
2078 dprintf_menu( stddeb,"ChangeMenu16: menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
2079 hMenu, pos, (DWORD)data, id, flags );
2080 if (flags & MF_APPEND) return AppendMenu16( hMenu, flags & ~MF_APPEND,
2081 id, data );
2082 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
2083 /* for MF_DELETE. We should check the parameters for all others */
2084 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
2085 if (flags & MF_DELETE) return DeleteMenu16(hMenu, pos, flags & ~MF_DELETE);
2086 if (flags & MF_CHANGE) return ModifyMenu16(hMenu, pos, flags & ~MF_CHANGE,
2087 id, data );
2088 if (flags & MF_REMOVE) return RemoveMenu16(hMenu,
2089 flags & MF_BYPOSITION ? pos : id,
2090 flags & ~MF_REMOVE );
2091 /* Default: MF_INSERT */
2092 return InsertMenu16( hMenu, pos, flags, id, data );
2096 /*******************************************************************
2097 * ChangeMenu32A (USER32.22)
2099 BOOL32 ChangeMenu32A( HMENU32 hMenu, UINT32 pos, LPCSTR data,
2100 UINT32 id, UINT32 flags )
2102 dprintf_menu( stddeb,"ChangeMenu32A: menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2103 hMenu, pos, (DWORD)data, id, flags );
2104 if (flags & MF_APPEND) return AppendMenu32A( hMenu, flags & ~MF_APPEND,
2105 id, data );
2106 if (flags & MF_DELETE) return DeleteMenu32(hMenu, pos, flags & ~MF_DELETE);
2107 if (flags & MF_CHANGE) return ModifyMenu32A(hMenu, pos, flags & ~MF_CHANGE,
2108 id, data );
2109 if (flags & MF_REMOVE) return RemoveMenu32( hMenu,
2110 flags & MF_BYPOSITION ? pos : id,
2111 flags & ~MF_REMOVE );
2112 /* Default: MF_INSERT */
2113 return InsertMenu32A( hMenu, pos, flags, id, data );
2117 /*******************************************************************
2118 * ChangeMenu32W (USER32.23)
2120 BOOL32 ChangeMenu32W( HMENU32 hMenu, UINT32 pos, LPCWSTR data,
2121 UINT32 id, UINT32 flags )
2123 dprintf_menu( stddeb,"ChangeMenu32W: menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2124 hMenu, pos, (DWORD)data, id, flags );
2125 if (flags & MF_APPEND) return AppendMenu32W( hMenu, flags & ~MF_APPEND,
2126 id, data );
2127 if (flags & MF_DELETE) return DeleteMenu32(hMenu, pos, flags & ~MF_DELETE);
2128 if (flags & MF_CHANGE) return ModifyMenu32W(hMenu, pos, flags & ~MF_CHANGE,
2129 id, data );
2130 if (flags & MF_REMOVE) return RemoveMenu32( hMenu,
2131 flags & MF_BYPOSITION ? pos : id,
2132 flags & ~MF_REMOVE );
2133 /* Default: MF_INSERT */
2134 return InsertMenu32W( hMenu, pos, flags, id, data );
2138 /*******************************************************************
2139 * CheckMenuItem16 (USER.154)
2141 BOOL16 CheckMenuItem16( HMENU16 hMenu, UINT16 id, UINT16 flags )
2143 return (BOOL16)CheckMenuItem32( hMenu, id, flags );
2147 /*******************************************************************
2148 * CheckMenuItem32 (USER32.45)
2150 DWORD CheckMenuItem32( HMENU32 hMenu, UINT32 id, UINT32 flags )
2152 MENUITEM *item;
2153 DWORD ret;
2155 dprintf_menu( stddeb,"CheckMenuItem: %04x %04x %04x\n", hMenu, id, flags );
2156 if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
2157 ret = item->item_flags & MF_CHECKED;
2158 if (flags & MF_CHECKED) item->item_flags |= MF_CHECKED;
2159 else item->item_flags &= ~MF_CHECKED;
2160 return ret;
2164 /**********************************************************************
2165 * EnableMenuItem16 (USER.155)
2167 BOOL16 EnableMenuItem16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
2169 return EnableMenuItem32( hMenu, wItemID, wFlags );
2173 /**********************************************************************
2174 * EnableMenuItem32 (USER32.169)
2176 BOOL32 EnableMenuItem32( HMENU32 hMenu, UINT32 wItemID, UINT32 wFlags )
2178 MENUITEM *item;
2179 dprintf_menu(stddeb,"EnableMenuItem (%04x, %04X, %04X) !\n",
2180 hMenu, wItemID, wFlags);
2181 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return FALSE;
2183 /* We can't have MF_GRAYED and MF_DISABLED together */
2184 if (wFlags & MF_GRAYED)
2186 item->item_flags = (item->item_flags & ~MF_DISABLED) | MF_GRAYED;
2188 else if (wFlags & MF_DISABLED)
2190 item->item_flags = (item->item_flags & ~MF_GRAYED) | MF_DISABLED;
2192 else /* MF_ENABLED */
2194 item->item_flags &= ~(MF_GRAYED | MF_DISABLED);
2196 return TRUE;
2200 /*******************************************************************
2201 * GetMenuString16 (USER.161)
2203 INT16 GetMenuString16( HMENU16 hMenu, UINT16 wItemID,
2204 LPSTR str, INT16 nMaxSiz, UINT16 wFlags )
2206 return GetMenuString32A( hMenu, wItemID, str, nMaxSiz, wFlags );
2210 /*******************************************************************
2211 * GetMenuString32A (USER32.267)
2213 INT32 GetMenuString32A( HMENU32 hMenu, UINT32 wItemID,
2214 LPSTR str, INT32 nMaxSiz, UINT32 wFlags )
2216 MENUITEM *item;
2218 dprintf_menu( stddeb, "GetMenuString32A: menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
2219 hMenu, wItemID, str, nMaxSiz, wFlags );
2220 if (!str || !nMaxSiz) return 0;
2221 str[0] = '\0';
2222 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
2223 if (!IS_STRING_ITEM(item->item_flags)) return 0;
2224 lstrcpyn32A( str, item->text, nMaxSiz );
2225 dprintf_menu( stddeb, "GetMenuString32A: returning '%s'\n", str );
2226 return strlen(str);
2230 /*******************************************************************
2231 * GetMenuString32W (USER32.268)
2233 INT32 GetMenuString32W( HMENU32 hMenu, UINT32 wItemID,
2234 LPWSTR str, INT32 nMaxSiz, UINT32 wFlags )
2236 MENUITEM *item;
2238 dprintf_menu( stddeb, "GetMenuString32W: menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
2239 hMenu, wItemID, str, nMaxSiz, wFlags );
2240 if (!str || !nMaxSiz) return 0;
2241 str[0] = '\0';
2242 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
2243 if (!IS_STRING_ITEM(item->item_flags)) return 0;
2244 lstrcpynAtoW( str, item->text, nMaxSiz );
2245 return lstrlen32W(str);
2249 /**********************************************************************
2250 * HiliteMenuItem16 (USER.162)
2252 BOOL16 HiliteMenuItem16( HWND16 hWnd, HMENU16 hMenu, UINT16 wItemID,
2253 UINT16 wHilite )
2255 return HiliteMenuItem32( hWnd, hMenu, wItemID, wHilite );
2259 /**********************************************************************
2260 * HiliteMenuItem32 (USER32.317)
2262 BOOL32 HiliteMenuItem32( HWND32 hWnd, HMENU32 hMenu, UINT32 wItemID,
2263 UINT32 wHilite )
2265 LPPOPUPMENU menu;
2266 dprintf_menu(stddeb,"HiliteMenuItem(%04x, %04x, %04x, %04x);\n",
2267 hWnd, hMenu, wItemID, wHilite);
2268 if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
2269 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
2270 if (menu->FocusedItem == wItemID) return TRUE;
2271 MENU_HideSubPopups( hWnd, hMenu, FALSE );
2272 MENU_SelectItem( hWnd, hMenu, wItemID, TRUE );
2273 return TRUE;
2277 /**********************************************************************
2278 * GetMenuState16 (USER.250)
2280 UINT16 GetMenuState16( HMENU16 hMenu, UINT16 wItemID, UINT16 wFlags )
2282 return GetMenuState32( hMenu, wItemID, wFlags );
2286 /**********************************************************************
2287 * GetMenuState32 (USER32.266)
2289 UINT32 GetMenuState32( HMENU32 hMenu, UINT32 wItemID, UINT32 wFlags )
2291 MENUITEM *item;
2292 dprintf_menu(stddeb,"GetMenuState(%04x, %04x, %04x);\n",
2293 hMenu, wItemID, wFlags);
2294 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
2295 if (item->item_flags & MF_POPUP)
2297 POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( (HMENU16)item->item_id );
2298 if (!menu) return -1;
2299 else return (menu->nItems << 8) | (menu->wFlags & 0xff);
2301 else return item->item_flags;
2305 /**********************************************************************
2306 * GetMenuItemCount16 (USER.263)
2308 INT16 GetMenuItemCount16( HMENU16 hMenu )
2310 LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
2311 if (!menu || (menu->wMagic != MENU_MAGIC)) return -1;
2312 dprintf_menu( stddeb,"GetMenuItemCount16(%04x) returning %d\n",
2313 hMenu, menu->nItems );
2314 return menu->nItems;
2318 /**********************************************************************
2319 * GetMenuItemCount32 (USER32.261)
2321 INT32 GetMenuItemCount32( HMENU32 hMenu )
2323 LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
2324 if (!menu || (menu->wMagic != MENU_MAGIC)) return -1;
2325 dprintf_menu( stddeb,"GetMenuItemCount32(%04x) returning %d\n",
2326 hMenu, menu->nItems );
2327 return menu->nItems;
2331 /**********************************************************************
2332 * GetMenuItemID16 (USER.264)
2334 UINT16 GetMenuItemID16( HMENU16 hMenu, INT16 nPos )
2336 LPPOPUPMENU menu;
2338 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return -1;
2339 if ((nPos < 0) || (nPos >= menu->nItems)) return -1;
2340 if (menu->items[nPos].item_flags & MF_POPUP) return -1;
2341 return menu->items[nPos].item_id;
2345 /**********************************************************************
2346 * GetMenuItemID32 (USER32.262)
2348 UINT32 GetMenuItemID32( HMENU32 hMenu, INT32 nPos )
2350 LPPOPUPMENU menu;
2352 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return -1;
2353 if ((nPos < 0) || (nPos >= menu->nItems)) return -1;
2354 if (menu->items[nPos].item_flags & MF_POPUP) return -1;
2355 return menu->items[nPos].item_id;
2359 /*******************************************************************
2360 * InsertMenu16 (USER.410)
2362 BOOL16 InsertMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
2363 UINT16 id, SEGPTR data )
2365 UINT32 pos32 = (UINT32)pos;
2366 if ((pos == (UINT16)-1) && (flags & MF_BYPOSITION)) pos32 = (UINT32)-1;
2367 if (IS_STRING_ITEM(flags) && data)
2368 return InsertMenu32A( hMenu, pos32, flags, id,
2369 (LPSTR)PTR_SEG_TO_LIN(data) );
2370 return InsertMenu32A( hMenu, pos32, flags, id, (LPSTR)data );
2374 /*******************************************************************
2375 * InsertMenu32A (USER32.321)
2377 BOOL32 InsertMenu32A( HMENU32 hMenu, UINT32 pos, UINT32 flags,
2378 UINT32 id, LPCSTR str )
2380 MENUITEM *item;
2382 if (IS_STRING_ITEM(flags) && str)
2383 dprintf_menu( stddeb, "InsertMenu: %04x %d %04x %04x '%s'\n",
2384 hMenu, pos, flags, id, str );
2385 else dprintf_menu( stddeb, "InsertMenu: %04x %d %04x %04x %08lx\n",
2386 hMenu, pos, flags, id, (DWORD)str );
2388 if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
2390 if (!(MENU_SetItemData( item, flags, id, str )))
2392 RemoveMenu32( hMenu, pos, flags );
2393 return FALSE;
2396 if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
2397 ((POPUPMENU *)USER_HEAP_LIN_ADDR((HMENU16)id))->wFlags |= MF_POPUP;
2399 item->hCheckBit = hStdCheck;
2400 item->hUnCheckBit = 0;
2401 return TRUE;
2405 /*******************************************************************
2406 * InsertMenu32W (USER32.324)
2408 BOOL32 InsertMenu32W( HMENU32 hMenu, UINT32 pos, UINT32 flags,
2409 UINT32 id, LPCWSTR str )
2411 BOOL32 ret;
2413 if (IS_STRING_ITEM(flags) && str)
2415 LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
2416 ret = InsertMenu32A( hMenu, pos, flags, id, newstr );
2417 HeapFree( GetProcessHeap(), 0, newstr );
2418 return ret;
2420 else return InsertMenu32A( hMenu, pos, flags, id, (LPCSTR)str );
2424 /*******************************************************************
2425 * AppendMenu16 (USER.411)
2427 BOOL16 AppendMenu16( HMENU16 hMenu, UINT16 flags, UINT16 id, SEGPTR data )
2429 return InsertMenu16( hMenu, -1, flags | MF_BYPOSITION, id, data );
2433 /*******************************************************************
2434 * AppendMenu32A (USER32.4)
2436 BOOL32 AppendMenu32A( HMENU32 hMenu, UINT32 flags, UINT32 id, LPCSTR data )
2438 return InsertMenu32A( hMenu, -1, flags | MF_BYPOSITION, id, data );
2442 /*******************************************************************
2443 * AppendMenu32W (USER32.5)
2445 BOOL32 AppendMenu32W( HMENU32 hMenu, UINT32 flags, UINT32 id, LPCWSTR data )
2447 return InsertMenu32W( hMenu, -1, flags | MF_BYPOSITION, id, data );
2451 /**********************************************************************
2452 * RemoveMenu16 (USER.412)
2454 BOOL16 RemoveMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
2456 return RemoveMenu32( hMenu, nPos, wFlags );
2460 /**********************************************************************
2461 * RemoveMenu32 (USER32.440)
2463 BOOL32 RemoveMenu32( HMENU32 hMenu, UINT32 nPos, UINT32 wFlags )
2465 LPPOPUPMENU menu;
2466 MENUITEM *item;
2468 dprintf_menu(stddeb,"RemoveMenu (%04x, %04x, %04x)\n",hMenu, nPos, wFlags);
2469 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
2470 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
2472 /* Remove item */
2474 if (IS_STRING_ITEM(item->item_flags) && item->text)
2475 HeapFree( SystemHeap, 0, item->text );
2476 if (--menu->nItems == 0)
2478 HeapFree( SystemHeap, 0, menu->items );
2479 menu->items = NULL;
2481 else
2483 while(nPos < menu->nItems)
2485 *item = *(item+1);
2486 item++;
2487 nPos++;
2489 menu->items = HeapReAlloc( SystemHeap, 0, menu->items,
2490 menu->nItems * sizeof(MENUITEM) );
2492 return TRUE;
2496 /**********************************************************************
2497 * DeleteMenu16 (USER.413)
2499 BOOL16 DeleteMenu16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags )
2501 return DeleteMenu32( hMenu, nPos, wFlags );
2505 /**********************************************************************
2506 * DeleteMenu32 (USER32.128)
2508 BOOL32 DeleteMenu32( HMENU32 hMenu, UINT32 nPos, UINT32 wFlags )
2510 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
2511 if (!item) return FALSE;
2512 if (item->item_flags & MF_POPUP) DestroyMenu32( (HMENU32)item->item_id );
2513 /* nPos is now the position of the item */
2514 RemoveMenu32( hMenu, nPos, wFlags | MF_BYPOSITION );
2515 return TRUE;
2519 /*******************************************************************
2520 * ModifyMenu16 (USER.414)
2522 BOOL16 ModifyMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
2523 UINT16 id, SEGPTR data )
2525 if (IS_STRING_ITEM(flags))
2526 return ModifyMenu32A( hMenu, pos, flags, id,
2527 (LPSTR)PTR_SEG_TO_LIN(data) );
2528 return ModifyMenu32A( hMenu, pos, flags, id, (LPSTR)data );
2532 /*******************************************************************
2533 * ModifyMenu32A (USER32.396)
2535 BOOL32 ModifyMenu32A( HMENU32 hMenu, UINT32 pos, UINT32 flags,
2536 UINT32 id, LPCSTR str )
2538 MENUITEM *item;
2540 if (IS_STRING_ITEM(flags))
2542 dprintf_menu( stddeb, "ModifyMenu: %04x %d %04x %04x '%s'\n",
2543 hMenu, pos, flags, id, str ? str : "#NULL#" );
2544 if (!str) return FALSE;
2546 else
2548 dprintf_menu( stddeb, "ModifyMenu: %04x %d %04x %04x %08lx\n",
2549 hMenu, pos, flags, id, (DWORD)str );
2552 if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
2553 return MENU_SetItemData( item, flags, id, str );
2557 /*******************************************************************
2558 * ModifyMenu32W (USER32.397)
2560 BOOL32 ModifyMenu32W( HMENU32 hMenu, UINT32 pos, UINT32 flags,
2561 UINT32 id, LPCWSTR str )
2563 BOOL32 ret;
2565 if (IS_STRING_ITEM(flags) && str)
2567 LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
2568 ret = ModifyMenu32A( hMenu, pos, flags, id, newstr );
2569 HeapFree( GetProcessHeap(), 0, newstr );
2570 return ret;
2572 else return ModifyMenu32A( hMenu, pos, flags, id, (LPCSTR)str );
2576 /**********************************************************************
2577 * CreatePopupMenu16 (USER.415)
2579 HMENU16 CreatePopupMenu16(void)
2581 return CreatePopupMenu32();
2585 /**********************************************************************
2586 * CreatePopupMenu32 (USER32.81)
2588 HMENU32 CreatePopupMenu32(void)
2590 HMENU32 hmenu;
2591 POPUPMENU *menu;
2593 if (!(hmenu = CreateMenu32())) return 0;
2594 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
2595 menu->wFlags |= MF_POPUP;
2596 return hmenu;
2600 /**********************************************************************
2601 * GetMenuCheckMarkDimensions (USER.417) (USER32.257)
2603 DWORD GetMenuCheckMarkDimensions(void)
2605 return MAKELONG( check_bitmap_width, check_bitmap_height );
2609 /**********************************************************************
2610 * SetMenuItemBitmaps16 (USER.418)
2612 BOOL16 SetMenuItemBitmaps16( HMENU16 hMenu, UINT16 nPos, UINT16 wFlags,
2613 HBITMAP16 hNewUnCheck, HBITMAP16 hNewCheck )
2615 return SetMenuItemBitmaps32( hMenu, nPos, wFlags, hNewUnCheck, hNewCheck );
2619 /**********************************************************************
2620 * SetMenuItemBitmaps32 (USER32.489)
2622 BOOL32 SetMenuItemBitmaps32( HMENU32 hMenu, UINT32 nPos, UINT32 wFlags,
2623 HBITMAP32 hNewUnCheck, HBITMAP32 hNewCheck )
2625 MENUITEM *item;
2626 dprintf_menu(stddeb,"SetMenuItemBitmaps(%04x, %04x, %04x, %04x, %04x)\n",
2627 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
2628 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
2630 if (!hNewCheck && !hNewUnCheck)
2632 /* If both are NULL, restore default bitmaps */
2633 item->hCheckBit = hStdCheck;
2634 item->hUnCheckBit = 0;
2635 item->item_flags &= ~MF_USECHECKBITMAPS;
2637 else /* Install new bitmaps */
2639 item->hCheckBit = hNewCheck;
2640 item->hUnCheckBit = hNewUnCheck;
2641 item->item_flags |= MF_USECHECKBITMAPS;
2643 return TRUE;
2647 /**********************************************************************
2648 * CreateMenu16 (USER.151)
2650 HMENU16 CreateMenu16(void)
2652 return CreateMenu32();
2656 /**********************************************************************
2657 * CreateMenu32 (USER32.80)
2659 HMENU32 CreateMenu32(void)
2661 HMENU32 hMenu;
2662 LPPOPUPMENU menu;
2663 if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
2664 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
2665 menu->wFlags = 0;
2666 menu->wMagic = MENU_MAGIC;
2667 menu->hTaskQ = 0;
2668 menu->Width = 0;
2669 menu->Height = 0;
2670 menu->nItems = 0;
2671 menu->hWnd = 0;
2672 menu->items = NULL;
2673 menu->FocusedItem = NO_SELECTED_ITEM;
2674 dprintf_menu( stddeb, "CreateMenu: return %04x\n", hMenu );
2675 return hMenu;
2679 /**********************************************************************
2680 * DestroyMenu16 (USER.152)
2682 BOOL16 DestroyMenu16( HMENU16 hMenu )
2684 return DestroyMenu32( hMenu );
2688 /**********************************************************************
2689 * DestroyMenu32 (USER32.133)
2691 BOOL32 DestroyMenu32( HMENU32 hMenu )
2693 LPPOPUPMENU lppop;
2694 dprintf_menu(stddeb,"DestroyMenu(%04x)\n", hMenu);
2696 if (hMenu == 0) return FALSE;
2697 /* Silently ignore attempts to destroy default system menu */
2698 if (hMenu == MENU_DefSysMenu) return TRUE;
2699 lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
2700 if (!lppop || (lppop->wMagic != MENU_MAGIC)) return FALSE;
2701 lppop->wMagic = 0; /* Mark it as destroyed */
2702 if ((lppop->wFlags & MF_POPUP) &&
2703 lppop->hWnd &&
2704 (!pTopPWnd || (lppop->hWnd != pTopPWnd->hwndSelf)))
2705 DestroyWindow( lppop->hWnd );
2707 if (lppop->items)
2709 int i;
2710 MENUITEM *item = lppop->items;
2711 for (i = lppop->nItems; i > 0; i--, item++)
2713 if (item->item_flags & MF_POPUP)
2714 DestroyMenu32( (HMENU32)item->item_id );
2715 if (IS_STRING_ITEM(item->item_flags) && item->text)
2716 HeapFree( SystemHeap, 0, item->text );
2718 HeapFree( SystemHeap, 0, lppop->items );
2720 USER_HEAP_FREE( hMenu );
2721 return TRUE;
2725 /**********************************************************************
2726 * GetSystemMenu16 (USER.156)
2728 HMENU16 GetSystemMenu16( HWND16 hWnd, BOOL16 bRevert )
2730 return GetSystemMenu32( hWnd, bRevert );
2734 /**********************************************************************
2735 * GetSystemMenu32 (USER32.290)
2737 HMENU32 GetSystemMenu32( HWND32 hWnd, BOOL32 bRevert )
2739 WND *wndPtr = WIN_FindWndPtr( hWnd );
2740 if (!wndPtr) return 0;
2742 if (!wndPtr->hSysMenu || (wndPtr->hSysMenu == MENU_DefSysMenu))
2744 wndPtr->hSysMenu = MENU_CopySysMenu();
2745 return wndPtr->hSysMenu;
2747 if (!bRevert) return wndPtr->hSysMenu;
2748 if (wndPtr->hSysMenu) DestroyMenu32(wndPtr->hSysMenu);
2749 wndPtr->hSysMenu = MENU_CopySysMenu();
2750 return wndPtr->hSysMenu;
2754 /*******************************************************************
2755 * SetSystemMenu16 (USER.280)
2757 BOOL16 SetSystemMenu16( HWND16 hwnd, HMENU16 hMenu )
2759 return SetSystemMenu32( hwnd, hMenu );
2763 /*******************************************************************
2764 * SetSystemMenu32 (USER32.507)
2766 BOOL32 SetSystemMenu32( HWND32 hwnd, HMENU32 hMenu )
2768 WND *wndPtr;
2770 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
2771 if (wndPtr->hSysMenu && (wndPtr->hSysMenu != MENU_DefSysMenu))
2772 DestroyMenu32( wndPtr->hSysMenu );
2773 wndPtr->hSysMenu = hMenu;
2774 return TRUE;
2778 /**********************************************************************
2779 * GetMenu16 (USER.157)
2781 HMENU16 GetMenu16( HWND16 hWnd )
2783 WND * wndPtr = WIN_FindWndPtr(hWnd);
2784 if (wndPtr) return (HMENU16)wndPtr->wIDmenu;
2785 return 0;
2789 /**********************************************************************
2790 * GetMenu32 (USER32.256)
2792 HMENU32 GetMenu32( HWND32 hWnd )
2794 WND * wndPtr = WIN_FindWndPtr(hWnd);
2795 if (wndPtr) return (HMENU32)wndPtr->wIDmenu;
2796 return 0;
2800 /**********************************************************************
2801 * SetMenu16 (USER.158)
2803 BOOL16 SetMenu16( HWND16 hWnd, HMENU16 hMenu )
2805 return SetMenu32( hWnd, hMenu );
2809 /**********************************************************************
2810 * SetMenu32 (USER32.486)
2812 BOOL32 SetMenu32( HWND32 hWnd, HMENU32 hMenu )
2814 LPPOPUPMENU lpmenu;
2815 WND * wndPtr = WIN_FindWndPtr(hWnd);
2816 if (!wndPtr) return FALSE;
2817 dprintf_menu(stddeb,"SetMenu(%04x, %04x);\n", hWnd, hMenu);
2818 if (GetCapture32() == hWnd) ReleaseCapture();
2819 wndPtr->wIDmenu = (UINT32)hMenu;
2820 if (hMenu != 0)
2822 if (!(lpmenu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
2823 lpmenu->hWnd = hWnd;
2824 lpmenu->wFlags &= ~MF_POPUP; /* Can't be a popup */
2825 lpmenu->Height = 0; /* Make sure we recalculate the size */
2827 if (IsWindowVisible(hWnd))
2828 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
2829 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
2830 return TRUE;
2835 /**********************************************************************
2836 * GetSubMenu16 (USER.159)
2838 HMENU16 GetSubMenu16( HMENU16 hMenu, INT16 nPos )
2840 return GetSubMenu32( hMenu, nPos );
2844 /**********************************************************************
2845 * GetSubMenu32 (USER32.287)
2847 HMENU32 GetSubMenu32( HMENU32 hMenu, INT32 nPos )
2849 LPPOPUPMENU lppop;
2851 if (!(lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return 0;
2852 if ((UINT32)nPos >= lppop->nItems) return 0;
2853 if (!(lppop->items[nPos].item_flags & MF_POPUP)) return 0;
2854 return (HMENU32)lppop->items[nPos].item_id;
2858 /**********************************************************************
2859 * DrawMenuBar16 (USER.160)
2861 void DrawMenuBar16( HWND16 hWnd )
2863 DrawMenuBar32( hWnd );
2867 /**********************************************************************
2868 * DrawMenuBar32 (USER32.160)
2870 BOOL32 DrawMenuBar32( HWND32 hWnd )
2872 LPPOPUPMENU lppop;
2873 WND *wndPtr = WIN_FindWndPtr(hWnd);
2874 if (wndPtr && !(wndPtr->dwStyle & WS_CHILD) && wndPtr->wIDmenu)
2876 lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR((HMENU16)wndPtr->wIDmenu);
2877 if (lppop == NULL) return FALSE;
2879 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
2880 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
2881 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
2882 return TRUE;
2884 return FALSE;
2888 /***********************************************************************
2889 * EndMenu (USER.187) (USER32.174)
2891 void EndMenu(void)
2893 /* FIXME: this won't work when we have multiple tasks... */
2894 fEndMenuCalled = TRUE;
2898 /***********************************************************************
2899 * LookupMenuHandle (USER.217)
2901 HMENU16 LookupMenuHandle( HMENU16 hmenu, INT16 id )
2903 HMENU32 hmenu32 = hmenu;
2904 INT32 id32 = id;
2905 if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
2906 else return hmenu32;
2910 /**********************************************************************
2911 * LoadMenu16 (USER.150)
2913 HMENU16 LoadMenu16( HINSTANCE16 instance, SEGPTR name )
2915 HRSRC16 hRsrc;
2916 HGLOBAL16 handle;
2917 HMENU16 hMenu;
2919 if (HIWORD(name))
2921 char *str = (char *)PTR_SEG_TO_LIN( name );
2922 dprintf_menu( stddeb, "LoadMenu(%04x,'%s')\n", instance, str );
2923 if (str[0] == '#') name = (SEGPTR)atoi( str + 1 );
2925 else
2926 dprintf_resource(stddeb,"LoadMenu(%04x,%04x)\n",instance,LOWORD(name));
2928 if (!name) return 0;
2930 /* check for Win32 module */
2931 instance = GetExePtr( instance );
2932 if (MODULE_GetPtr(instance)->flags & NE_FFLAGS_WIN32)
2933 return LoadMenu32A(instance,PTR_SEG_TO_LIN(name));
2935 if (!(hRsrc = FindResource16( instance, name, RT_MENU ))) return 0;
2936 if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
2937 hMenu = LoadMenuIndirect16(LockResource16(handle));
2938 FreeResource16( handle );
2939 return hMenu;
2943 /*****************************************************************
2944 * LoadMenu32A (USER32.370)
2946 HMENU32 LoadMenu32A( HINSTANCE32 instance, LPCSTR name )
2948 HRSRC32 hrsrc = FindResource32A( instance, name, (LPSTR)RT_MENU );
2949 if (!hrsrc) return 0;
2950 return LoadMenuIndirect32A( (LPCVOID)LoadResource32( instance, hrsrc ));
2954 /*****************************************************************
2955 * LoadMenu32W (USER32.372)
2957 HMENU32 LoadMenu32W( HINSTANCE32 instance, LPCWSTR name )
2959 HRSRC32 hrsrc = FindResource32W( instance, name, (LPWSTR)RT_MENU );
2960 if (!hrsrc) return 0;
2961 return LoadMenuIndirect32W( (LPCVOID)LoadResource32( instance, hrsrc ));
2965 /**********************************************************************
2966 * LoadMenuIndirect16 (USER.220)
2968 HMENU16 LoadMenuIndirect16( LPCVOID template )
2970 HMENU16 hMenu;
2971 WORD version, offset;
2972 LPCSTR p = (LPCSTR)template;
2974 dprintf_menu(stddeb,"LoadMenuIndirect16: %p\n", template );
2975 version = GET_WORD(p);
2976 p += sizeof(WORD);
2977 if (version)
2979 fprintf( stderr, "LoadMenuIndirect16: version must be 0 for Win16\n" );
2980 return 0;
2982 offset = GET_WORD(p);
2983 p += sizeof(WORD) + offset;
2984 if (!(hMenu = CreateMenu32())) return 0;
2985 if (!MENU_ParseResource( p, hMenu, FALSE ))
2987 DestroyMenu32( hMenu );
2988 return 0;
2990 return hMenu;
2994 /**********************************************************************
2995 * LoadMenuIndirect32A (USER32.370)
2997 HMENU32 LoadMenuIndirect32A( LPCVOID template )
2999 HMENU16 hMenu;
3000 WORD version, offset;
3001 LPCSTR p = (LPCSTR)template;
3003 dprintf_menu(stddeb,"LoadMenuIndirect16: %p\n", template );
3004 version = GET_WORD(p);
3005 p += sizeof(WORD);
3006 if (version)
3008 fprintf( stderr, "LoadMenuIndirect32A: version %d not supported.\n",
3009 version );
3010 return 0;
3012 offset = GET_WORD(p);
3013 p += sizeof(WORD) + offset;
3014 if (!(hMenu = CreateMenu32())) return 0;
3015 if (!MENU_ParseResource( p, hMenu, TRUE ))
3017 DestroyMenu32( hMenu );
3018 return 0;
3020 return hMenu;
3024 /**********************************************************************
3025 * LoadMenuIndirect32W (USER32.371)
3027 HMENU32 LoadMenuIndirect32W( LPCVOID template )
3029 /* FIXME: is there anything different between A and W? */
3030 return LoadMenuIndirect32A( template );
3034 /**********************************************************************
3035 * IsMenu16 (USER.358)
3037 BOOL16 IsMenu16( HMENU16 hmenu )
3039 LPPOPUPMENU menu;
3040 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
3041 return (menu->wMagic == MENU_MAGIC);
3045 /**********************************************************************
3046 * IsMenu32 (USER32.345)
3048 BOOL32 IsMenu32( HMENU32 hmenu )
3050 LPPOPUPMENU menu;
3051 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
3052 return (menu->wMagic == MENU_MAGIC);