Release 961222
[wine/multimedia.git] / controls / menu.c
blob8e8583da4284f70df6e24ecb78beff814af09368
1 /*
2 * Menu functions
4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
6 */
8 /*
9 * Note: the style MF_MOUSESELECT is used to mark popup items that
10 * have been selected, i.e. their popup menu is currently displayed.
11 * This is probably not the meaning this style has in MS-Windows.
14 #include <ctype.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include "windows.h"
19 #include "syscolor.h"
20 #include "sysmetrics.h"
21 #include "task.h"
22 #include "win.h"
23 #include "heap.h"
24 #include "menu.h"
25 #include "module.h"
26 #include "neexe.h"
27 #include "user.h"
28 #include "message.h"
29 #include "graphics.h"
30 #include "resource.h"
31 #include "stddebug.h"
32 #include "debug.h"
34 /* Menu item structure */
35 typedef struct
37 WORD item_flags; /* Item flags */
38 UINT item_id; /* Item or popup id */
39 RECT16 rect; /* Item area (relative to menu window) */
40 WORD xTab; /* X position of text after Tab */
41 HBITMAP16 hCheckBit; /* Bitmap for checked item */
42 HBITMAP16 hUnCheckBit; /* Bitmap for unchecked item */
43 LPSTR text; /* Item text or bitmap handle */
44 } MENUITEM;
46 /* Popup menu structure */
47 typedef struct
49 WORD wFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */
50 WORD wMagic; /* Magic number */
51 HQUEUE16 hTaskQ; /* Task queue for this menu */
52 WORD Width; /* Width of the whole menu */
53 WORD Height; /* Height of the whole menu */
54 WORD nItems; /* Number of items in the menu */
55 HWND hWnd; /* Window containing the menu */
56 MENUITEM *items; /* Array of menu items */
57 UINT FocusedItem; /* Currently focused item */
58 } POPUPMENU, *LPPOPUPMENU;
60 #define MENU_MAGIC 0x554d /* 'MU' */
62 #define ITEM_PREV -1
63 #define ITEM_NEXT 1
65 /* Dimension of the menu bitmaps */
66 static WORD check_bitmap_width = 0, check_bitmap_height = 0;
67 static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
69 /* Flag set by EndMenu() to force an exit from menu tracking */
70 static BOOL fEndMenuCalled = FALSE;
72 /* Space between 2 menu bar items */
73 #define MENU_BAR_ITEMS_SPACE 16
75 /* Minimum width of a tab character */
76 #define MENU_TAB_SPACE 8
78 /* Height of a separator item */
79 #define SEPARATOR_HEIGHT 5
81 /* Values for menu->FocusedItem */
82 /* (other values give the position of the focused item) */
83 #define NO_SELECTED_ITEM 0xffff
84 #define SYSMENU_SELECTED 0xfffe /* Only valid on menu-bars */
86 #define IS_STRING_ITEM(flags) \
87 (!((flags) & (MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)))
89 extern void NC_DrawSysButton(HWND hwnd, HDC32 hdc, BOOL down); /*nonclient.c*/
90 extern BOOL NC_GetSysPopupPos(WND* wndPtr, RECT16* rect);
91 extern HTASK16 TASK_GetNextTask(HTASK16);
93 static HBITMAP16 hStdCheck = 0;
94 static HBITMAP16 hStdMnArrow = 0;
95 static HMENU16 MENU_DefSysMenu = 0; /* Default system menu */
98 /* we _can_ use global popup window because there's no way 2 menues can
99 * be tracked at the same time.
102 static WND* pTopPWnd = 0;
103 static UINT uSubPWndLevel = 0;
106 /**********************************************************************
107 * MENU_CopySysMenu
109 * Load a copy of the system menu.
111 static HMENU16 MENU_CopySysMenu(void)
113 HMENU16 hMenu;
114 HGLOBAL16 handle;
115 POPUPMENU *menu;
117 if (!(handle = SYSRES_LoadResource( SYSRES_MENU_SYSMENU ))) return 0;
118 hMenu = LoadMenuIndirect16( GlobalLock16( handle ) );
119 SYSRES_FreeResource( handle );
120 if (!hMenu)
122 dprintf_menu(stddeb,"No SYSMENU\n");
123 return 0;
125 menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hMenu);
126 menu->wFlags |= MF_SYSMENU | MF_POPUP;
127 dprintf_menu(stddeb,"CopySysMenu hMenu=%04x !\n", hMenu);
128 return hMenu;
132 /***********************************************************************
133 * MENU_Init
135 * Menus initialisation.
137 BOOL MENU_Init()
139 BITMAP16 bm;
141 /* Load bitmaps */
143 if (!(hStdCheck = LoadBitmap16( 0, MAKEINTRESOURCE(OBM_CHECK) )))
144 return FALSE;
145 GetObject16( hStdCheck, sizeof(bm), &bm );
146 check_bitmap_width = bm.bmWidth;
147 check_bitmap_height = bm.bmHeight;
148 if (!(hStdMnArrow = LoadBitmap16( 0, MAKEINTRESOURCE(OBM_MNARROW) )))
149 return FALSE;
150 GetObject16( hStdMnArrow, sizeof(bm), &bm );
151 arrow_bitmap_width = bm.bmWidth;
152 arrow_bitmap_height = bm.bmHeight;
154 if (!(MENU_DefSysMenu = MENU_CopySysMenu()))
156 fprintf( stderr, "Unable to create default system menu\n" );
157 return FALSE;
159 return TRUE;
163 /***********************************************************************
164 * MENU_GetDefSysMenu
166 * Return the default system menu.
168 HMENU16 MENU_GetDefSysMenu(void)
170 return MENU_DefSysMenu;
174 /***********************************************************************
175 * MENU_HasSysMenu
177 * Check whether the window owning the menu bar has a system menu.
179 static BOOL MENU_HasSysMenu( POPUPMENU *menu )
181 WND *wndPtr;
183 if (menu->wFlags & MF_POPUP) return FALSE;
184 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return FALSE;
185 return (wndPtr->dwStyle & WS_SYSMENU) != 0;
189 /***********************************************************************
190 * MENU_IsInSysMenu
192 * Check whether the point (in screen coords) is in the system menu
193 * of the window owning the given menu.
195 static BOOL MENU_IsInSysMenu( POPUPMENU *menu, POINT16 pt )
197 WND *wndPtr;
199 if (menu->wFlags & MF_POPUP) return FALSE;
200 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return FALSE;
201 if (!(wndPtr->dwStyle & WS_SYSMENU)) return FALSE;
202 if ((pt.x < wndPtr->rectClient.left) ||
203 (pt.x >= wndPtr->rectClient.left+SYSMETRICS_CXSIZE+SYSMETRICS_CXBORDER))
204 return FALSE;
205 if ((pt.y >= wndPtr->rectClient.top - menu->Height) ||
206 (pt.y < wndPtr->rectClient.top - menu->Height -
207 SYSMETRICS_CYSIZE - SYSMETRICS_CYBORDER)) return FALSE;
208 return TRUE;
212 /***********************************************************************
213 * MENU_InitSysMenuPopup
215 * Grey the appropriate items in System menu.
217 void MENU_InitSysMenuPopup(HMENU16 hmenu, DWORD style, DWORD clsStyle)
219 BOOL gray;
221 gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
222 EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
223 gray = ((style & WS_MAXIMIZE) != 0);
224 EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
225 gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
226 EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
227 gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
228 EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
229 gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
230 EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
231 gray = (clsStyle & CS_NOCLOSE) != 0;
232 EnableMenuItem( hmenu, SC_CLOSE, (gray ? MF_GRAYED : MF_ENABLED) );
236 /***********************************************************************
237 * MENU_FindItem
239 * Find a menu item. Return a pointer on the item, and modifies *hmenu
240 * in case the item was in a sub-menu.
242 static MENUITEM *MENU_FindItem( HMENU16 *hmenu, UINT *nPos, UINT wFlags )
244 POPUPMENU *menu;
245 int i;
247 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(*hmenu))) return NULL;
248 if (wFlags & MF_BYPOSITION)
250 if (*nPos >= menu->nItems) return NULL;
251 return &menu->items[*nPos];
253 else
255 MENUITEM *item = menu->items;
256 for (i = 0; i < menu->nItems; i++, item++)
258 if (item->item_id == *nPos)
260 *nPos = i;
261 return item;
263 else if (item->item_flags & MF_POPUP)
265 HMENU16 hsubmenu = (HMENU16)item->item_id;
266 MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
267 if (subitem)
269 *hmenu = hsubmenu;
270 return subitem;
275 return NULL;
279 /***********************************************************************
280 * MENU_FindItemByCoords
282 * Find the item at the specified coordinates (screen coords).
284 static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu, int x, int y, UINT *pos )
286 MENUITEM *item;
287 WND *wndPtr;
288 int i;
290 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return NULL;
291 x -= wndPtr->rectWindow.left;
292 y -= wndPtr->rectWindow.top;
293 item = menu->items;
294 for (i = 0; i < menu->nItems; i++, item++)
296 if ((x >= item->rect.left) && (x < item->rect.right) &&
297 (y >= item->rect.top) && (y < item->rect.bottom))
299 if (pos) *pos = i;
300 return item;
303 return NULL;
307 /***********************************************************************
308 * MENU_FindItemByKey
310 * Find the menu item selected by a key press.
311 * Return item id, -1 if none, -2 if we should close the menu.
313 static UINT MENU_FindItemByKey( HWND hwndOwner, HMENU16 hmenu, UINT key )
315 POPUPMENU *menu;
316 MENUITEM *item;
317 int i;
318 LONG menuchar;
320 if (!IsMenu( hmenu )) hmenu = WIN_FindWndPtr(hwndOwner)->hSysMenu;
321 if (!hmenu) return -1;
323 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
324 item = menu->items;
325 key = toupper(key);
326 for (i = 0; i < menu->nItems; i++, item++)
328 if (IS_STRING_ITEM(item->item_flags))
330 char *p = strchr( item->text, '&' );
331 if (p && (p[1] != '&') && (toupper(p[1]) == key)) return i;
334 menuchar = SendMessage32A( hwndOwner, WM_MENUCHAR,
335 MAKEWPARAM( key, menu->wFlags ), hmenu );
336 if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
337 if (HIWORD(menuchar) == 1) return -2;
338 return -1;
342 /***********************************************************************
343 * MENU_CalcItemSize
345 * Calculate the size of the menu item and store it in lpitem->rect.
347 static void MENU_CalcItemSize( HDC32 hdc, MENUITEM *lpitem, HWND hwndOwner,
348 int orgX, int orgY, BOOL menuBar )
350 DWORD dwSize;
351 char *p;
353 SetRect16( &lpitem->rect, orgX, orgY, orgX, orgY );
355 if (lpitem->item_flags & MF_OWNERDRAW)
357 MEASUREITEMSTRUCT16 *mis;
358 if (!(mis = SEGPTR_NEW(MEASUREITEMSTRUCT16))) return;
359 mis->CtlType = ODT_MENU;
360 mis->itemID = lpitem->item_id;
361 mis->itemData = (DWORD)lpitem->text;
362 mis->itemHeight = 16;
363 mis->itemWidth = 30;
364 SendMessage16( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)SEGPTR_GET(mis) );
365 lpitem->rect.bottom += mis->itemHeight;
366 lpitem->rect.right += mis->itemWidth;
367 dprintf_menu( stddeb, "DrawMenuItem: MeasureItem %04x %dx%d!\n",
368 lpitem->item_id, mis->itemWidth, mis->itemHeight );
369 SEGPTR_FREE(mis);
370 return;
373 if (lpitem->item_flags & MF_SEPARATOR)
375 lpitem->rect.bottom += SEPARATOR_HEIGHT;
376 return;
379 if (!menuBar)
381 lpitem->rect.right += 2 * check_bitmap_width;
382 if (lpitem->item_flags & MF_POPUP)
383 lpitem->rect.right += arrow_bitmap_width;
386 if (lpitem->item_flags & MF_BITMAP)
388 BITMAP16 bm;
389 if (GetObject16( (HBITMAP16)(UINT32)lpitem->text, sizeof(bm), &bm ))
391 lpitem->rect.right += bm.bmWidth;
392 lpitem->rect.bottom += bm.bmHeight;
394 return;
397 /* If we get here, then it must be a text item */
399 if (IS_STRING_ITEM( lpitem->item_flags ))
401 dwSize = GetTextExtent( hdc, lpitem->text, strlen(lpitem->text) );
402 lpitem->rect.right += LOWORD(dwSize);
403 lpitem->rect.bottom += MAX( HIWORD(dwSize), SYSMETRICS_CYMENU );
404 lpitem->xTab = 0;
406 if (menuBar) lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
407 else if ((p = strchr( lpitem->text, '\t' )) != NULL)
409 /* Item contains a tab (only meaningful in popup menus) */
410 lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE +
411 LOWORD( GetTextExtent( hdc, lpitem->text,
412 (int)(p - lpitem->text) ));
413 lpitem->rect.right += MENU_TAB_SPACE;
415 else
417 if (strchr( lpitem->text, '\b' ))
418 lpitem->rect.right += MENU_TAB_SPACE;
419 lpitem->xTab = lpitem->rect.right - check_bitmap_width
420 - arrow_bitmap_width;
426 /***********************************************************************
427 * MENU_PopupMenuCalcSize
429 * Calculate the size of a popup menu.
431 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
433 MENUITEM *lpitem;
434 HDC32 hdc;
435 int start, i;
436 int orgX, orgY, maxX, maxTab, maxTabWidth;
438 lppop->Width = lppop->Height = 0;
439 if (lppop->nItems == 0) return;
440 hdc = GetDC32( 0 );
441 maxX = start = 0;
442 while (start < lppop->nItems)
444 lpitem = &lppop->items[start];
445 orgX = maxX;
446 orgY = 0;
447 maxTab = maxTabWidth = 0;
449 /* Parse items until column break or end of menu */
450 for (i = start; i < lppop->nItems; i++, lpitem++)
452 if ((i != start) &&
453 (lpitem->item_flags & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
454 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
455 if (lpitem->item_flags & MF_MENUBARBREAK) orgX++;
456 maxX = MAX( maxX, lpitem->rect.right );
457 orgY = lpitem->rect.bottom;
458 if (IS_STRING_ITEM(lpitem->item_flags) && lpitem->xTab)
460 maxTab = MAX( maxTab, lpitem->xTab );
461 maxTabWidth = MAX(maxTabWidth,lpitem->rect.right-lpitem->xTab);
465 /* Finish the column (set all items to the largest width found) */
466 maxX = MAX( maxX, maxTab + maxTabWidth );
467 for (lpitem = &lppop->items[start]; start < i; start++, lpitem++)
469 lpitem->rect.right = maxX;
470 if (IS_STRING_ITEM(lpitem->item_flags) && lpitem->xTab)
471 lpitem->xTab = maxTab;
473 lppop->Height = MAX( lppop->Height, orgY );
476 lppop->Width = maxX;
477 ReleaseDC32( 0, hdc );
481 /***********************************************************************
482 * MENU_MenuBarCalcSize
484 * Calculate the size of the menu bar.
486 static void MENU_MenuBarCalcSize( HDC32 hdc, LPRECT16 lprect,
487 LPPOPUPMENU lppop, HWND hwndOwner )
489 MENUITEM *lpitem;
490 int start, i, orgX, orgY, maxY, helpPos;
492 if ((lprect == NULL) || (lppop == NULL)) return;
493 if (lppop->nItems == 0) return;
494 dprintf_menu(stddeb,"MENU_MenuBarCalcSize left=%d top=%d right=%d bottom=%d\n",
495 lprect->left, lprect->top, lprect->right, lprect->bottom);
496 lppop->Width = lprect->right - lprect->left;
497 lppop->Height = 0;
498 maxY = lprect->top;
499 start = 0;
500 helpPos = -1;
501 while (start < lppop->nItems)
503 lpitem = &lppop->items[start];
504 orgX = lprect->left;
505 orgY = maxY;
507 /* Parse items until line break or end of menu */
508 for (i = start; i < lppop->nItems; i++, lpitem++)
510 if ((helpPos == -1) && (lpitem->item_flags & MF_HELP)) helpPos = i;
511 if ((i != start) &&
512 (lpitem->item_flags & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
513 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE );
514 if (lpitem->rect.right > lprect->right)
516 if (i != start) break;
517 else lpitem->rect.right = lprect->right;
519 maxY = MAX( maxY, lpitem->rect.bottom );
520 orgX = lpitem->rect.right;
523 /* Finish the line (set all items to the largest height found) */
524 while (start < i) lppop->items[start++].rect.bottom = maxY;
527 lprect->bottom = maxY;
528 lppop->Height = lprect->bottom - lprect->top;
530 /* Flush right all items between the MF_HELP and the last item */
531 /* (if several lines, only move the last line) */
532 if (helpPos != -1)
534 lpitem = &lppop->items[lppop->nItems-1];
535 orgY = lpitem->rect.top;
536 orgX = lprect->right;
537 for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--)
539 if (lpitem->rect.top != orgY) break; /* Other line */
540 if (lpitem->rect.right >= orgX) break; /* Too far right already */
541 lpitem->rect.left += orgX - lpitem->rect.right;
542 lpitem->rect.right = orgX;
543 orgX = lpitem->rect.left;
549 /***********************************************************************
550 * MENU_DrawMenuItem
552 * Draw a single menu item.
554 static void MENU_DrawMenuItem( HWND hwnd, HDC32 hdc, MENUITEM *lpitem,
555 UINT height, BOOL menuBar )
557 RECT16 rect;
559 if (lpitem->item_flags & MF_OWNERDRAW)
561 DRAWITEMSTRUCT32 dis;
563 dprintf_menu( stddeb, "DrawMenuItem: Ownerdraw!\n" );
564 dis.CtlType = ODT_MENU;
565 dis.itemID = lpitem->item_id;
566 dis.itemData = (DWORD)lpitem->text;
567 dis.itemState = 0;
568 if (lpitem->item_flags & MF_CHECKED) dis.itemState |= ODS_CHECKED;
569 if (lpitem->item_flags & MF_GRAYED) dis.itemState |= ODS_GRAYED;
570 if (lpitem->item_flags & MF_HILITE) dis.itemState |= ODS_SELECTED;
571 dis.itemAction = ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS;
572 dis.hwndItem = hwnd;
573 dis.hDC = hdc;
574 CONV_RECT16TO32( &lpitem->rect, &dis.rcItem );
575 SendMessage32A( hwnd, WM_DRAWITEM, 0, (LPARAM)&dis );
576 return;
579 if (menuBar && (lpitem->item_flags & MF_SEPARATOR)) return;
580 rect = lpitem->rect;
582 /* Draw the background */
584 if (lpitem->item_flags & MF_HILITE)
585 FillRect16( hdc, &rect, sysColorObjects.hbrushHighlight );
586 else FillRect16( hdc, &rect, sysColorObjects.hbrushMenu );
587 SetBkMode32( hdc, TRANSPARENT );
589 /* Draw the separator bar (if any) */
591 if (!menuBar && (lpitem->item_flags & MF_MENUBARBREAK))
593 SelectObject32( hdc, sysColorObjects.hpenWindowFrame );
594 MoveTo( hdc, rect.left, 0 );
595 LineTo32( hdc, rect.left, height );
597 if (lpitem->item_flags & MF_SEPARATOR)
599 SelectObject32( hdc, sysColorObjects.hpenWindowFrame );
600 MoveTo( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2 );
601 LineTo32( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 );
602 return;
605 /* Setup colors */
607 if (lpitem->item_flags & MF_HILITE)
609 if (lpitem->item_flags & MF_GRAYED)
610 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
611 else
612 SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
613 SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
615 else
617 if (lpitem->item_flags & MF_GRAYED)
618 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
619 else
620 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
621 SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
624 if (!menuBar)
626 /* Draw the check mark */
628 if (lpitem->item_flags & MF_CHECKED)
630 GRAPH_DrawBitmap(hdc, lpitem->hCheckBit ? lpitem->hCheckBit :
631 hStdCheck, rect.left,
632 (rect.top+rect.bottom-check_bitmap_height) / 2,
633 0, 0, check_bitmap_width, check_bitmap_height );
635 else if (lpitem->hUnCheckBit != 0) /* Not checked */
637 GRAPH_DrawBitmap(hdc, lpitem->hUnCheckBit, rect.left,
638 (rect.top+rect.bottom-check_bitmap_height) / 2,
639 0, 0, check_bitmap_width, check_bitmap_height );
642 /* Draw the popup-menu arrow */
644 if (lpitem->item_flags & MF_POPUP)
646 GRAPH_DrawBitmap( hdc, hStdMnArrow,
647 rect.right-arrow_bitmap_width-1,
648 (rect.top+rect.bottom-arrow_bitmap_height) / 2,
649 0, 0, arrow_bitmap_width, arrow_bitmap_height );
652 rect.left += check_bitmap_width;
653 rect.right -= arrow_bitmap_width;
656 /* Draw the item text or bitmap */
658 if (lpitem->item_flags & MF_BITMAP)
660 GRAPH_DrawBitmap( hdc, (HBITMAP16)(UINT32)lpitem->text,
661 rect.left, rect.top, 0, 0,
662 rect.right-rect.left, rect.bottom-rect.top );
663 return;
665 /* No bitmap - process text if present */
666 else if (IS_STRING_ITEM(lpitem->item_flags))
668 register int i;
670 if (menuBar)
672 rect.left += MENU_BAR_ITEMS_SPACE / 2;
673 rect.right -= MENU_BAR_ITEMS_SPACE / 2;
674 i = strlen( lpitem->text );
676 else
678 for (i = 0; lpitem->text[i]; i++)
679 if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
680 break;
683 DrawText16( hdc, lpitem->text, i, &rect,
684 DT_LEFT | DT_VCENTER | DT_SINGLELINE );
686 if (lpitem->text[i]) /* There's a tab or flush-right char */
688 if (lpitem->text[i] == '\t')
690 rect.left = lpitem->xTab;
691 DrawText16( hdc, lpitem->text + i + 1, -1, &rect,
692 DT_LEFT | DT_VCENTER | DT_SINGLELINE );
694 else DrawText16( hdc, lpitem->text + i + 1, -1, &rect,
695 DT_RIGHT | DT_VCENTER | DT_SINGLELINE );
701 /***********************************************************************
702 * MENU_DrawPopupMenu
704 * Paint a popup menu.
706 static void MENU_DrawPopupMenu( HWND hwnd, HDC32 hdc, HMENU16 hmenu )
708 POPUPMENU *menu;
709 MENUITEM *item;
710 RECT16 rect;
711 int i;
713 GetClientRect16( hwnd, &rect );
714 FillRect16( hdc, &rect, sysColorObjects.hbrushMenu );
715 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
716 if (!menu || !menu->nItems) return;
717 for (i = menu->nItems, item = menu->items; i > 0; i--, item++)
718 MENU_DrawMenuItem( hwnd, hdc, item, menu->Height, FALSE );
722 /***********************************************************************
723 * MENU_DrawMenuBar
725 * Paint a menu bar. Returns the height of the menu bar.
727 UINT MENU_DrawMenuBar( HDC32 hDC, LPRECT16 lprect, HWND hwnd,
728 BOOL suppress_draw)
730 LPPOPUPMENU lppop;
731 int i;
732 WND *wndPtr = WIN_FindWndPtr( hwnd );
734 lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR( (HMENU16)wndPtr->wIDmenu );
735 if (lppop == NULL || lprect == NULL) return SYSMETRICS_CYMENU;
736 dprintf_menu(stddeb,"MENU_DrawMenuBar(%04x, %p, %p); !\n",
737 hDC, lprect, lppop);
738 if (lppop->Height == 0) MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
739 lprect->bottom = lprect->top + lppop->Height;
740 if (suppress_draw) return lppop->Height;
742 FillRect16(hDC, lprect, sysColorObjects.hbrushMenu );
743 SelectObject32( hDC, sysColorObjects.hpenWindowFrame );
744 MoveTo( hDC, lprect->left, lprect->bottom );
745 LineTo32( hDC, lprect->right, lprect->bottom );
747 if (lppop->nItems == 0) return SYSMETRICS_CYMENU;
748 for (i = 0; i < lppop->nItems; i++)
750 MENU_DrawMenuItem( hwnd, hDC, &lppop->items[i], lppop->Height, TRUE );
752 return lppop->Height;
756 /***********************************************************************
757 * MENU_SwitchTPWndTo
759 BOOL32 MENU_SwitchTPWndTo( HTASK16 hTask )
761 /* This is supposed to be called when popup is hidden.
762 * AppExit() calls with hTask == 0, so we get the next to current.
765 TDB* task;
767 if( !pTopPWnd ) return 0;
769 if( !hTask )
771 task = (TDB*)GlobalLock16( (hTask = GetCurrentTask()) );
772 if( task && task->hQueue == pTopPWnd->hmemTaskQ )
773 hTask = TASK_GetNextTask(hTask);
774 else return 0;
777 task = (TDB*)GlobalLock16(hTask);
778 if( !task ) return 0;
780 /* if this task got as far as menu tracking it must have a queue */
782 pTopPWnd->hInstance = task->hInstance;
783 pTopPWnd->hmemTaskQ = task->hQueue;
784 return 1;
787 /***********************************************************************
788 * MENU_ShowPopup
790 * Display a popup menu.
792 static BOOL MENU_ShowPopup(HWND hwndOwner, HMENU16 hmenu, UINT id, int x, int y,
793 int xanchor, int yanchor)
795 POPUPMENU *menu;
796 WND *wndPtr = NULL;
797 BOOL skip_init = 0;
798 UINT width, height;
800 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
801 if (menu->FocusedItem != NO_SELECTED_ITEM)
803 menu->items[menu->FocusedItem].item_flags &= ~(MF_HILITE|MF_MOUSESELECT);
804 menu->FocusedItem = NO_SELECTED_ITEM;
806 SendMessage16( hwndOwner, WM_INITMENUPOPUP, (WPARAM16)hmenu,
807 MAKELONG( id, (menu->wFlags & MF_SYSMENU) ? 1 : 0 ));
808 MENU_PopupMenuCalcSize( menu, hwndOwner );
810 /* adjust popup menu pos so that it fits within the desktop */
812 width = menu->Width + 2*SYSMETRICS_CXBORDER;
813 height = menu->Height + 2*SYSMETRICS_CYBORDER;
815 if( x + width > SYSMETRICS_CXSCREEN )
817 if( xanchor )
818 x -= width - xanchor;
819 if( x + width > SYSMETRICS_CXSCREEN)
820 x = SYSMETRICS_CXSCREEN - width;
822 if( x < 0 )
823 x = 0;
825 if( y + height > SYSMETRICS_CYSCREEN )
827 if( yanchor )
828 y -= height + yanchor;
829 if( y + height > SYSMETRICS_CYSCREEN )
830 y = SYSMETRICS_CYSCREEN - height;
832 if( y < 0 )
833 y = 0;
835 wndPtr = WIN_FindWndPtr( hwndOwner );
836 if (!wndPtr) return FALSE;
838 if (!pTopPWnd)
840 pTopPWnd = WIN_FindWndPtr(CreateWindow16( POPUPMENU_CLASS_ATOM, NULL,
841 WS_POPUP | WS_BORDER, x, y,
842 width, height,
843 hwndOwner, 0, wndPtr->hInstance,
844 (LPVOID)(HMENU32)hmenu ));
845 if (!pTopPWnd) return FALSE;
846 skip_init = TRUE;
849 if( uSubPWndLevel )
851 /* create new window for the submenu */
852 HWND hWnd = CreateWindow16( POPUPMENU_CLASS_ATOM, NULL,
853 WS_POPUP | WS_BORDER, x, y,
854 width, height,
855 menu->hWnd, 0, wndPtr->hInstance,
856 (LPVOID)(HMENU32)hmenu );
857 if( !hWnd ) return FALSE;
858 menu->hWnd = hWnd;
860 else
862 if( !skip_init )
864 MENU_SwitchTPWndTo(GetCurrentTask());
865 SendMessage16( pTopPWnd->hwndSelf, WM_USER, (WPARAM16)hmenu, 0L);
867 menu->hWnd = pTopPWnd->hwndSelf;
870 uSubPWndLevel++;
872 wndPtr = WIN_FindWndPtr( menu->hWnd );
874 SetWindowPos(menu->hWnd, 0, x, y, width, height,
875 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW);
876 /* Display the window */
878 SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
879 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
880 UpdateWindow( menu->hWnd );
881 return TRUE;
885 /***********************************************************************
886 * MENU_SelectItem
888 static void MENU_SelectItem( HWND hwndOwner, HMENU16 hmenu, UINT wIndex,
889 BOOL sendMenuSelect )
891 LPPOPUPMENU lppop;
892 HDC32 hdc;
894 lppop = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
895 if (!lppop->nItems) return;
896 if ((wIndex != NO_SELECTED_ITEM) &&
897 (wIndex != SYSMENU_SELECTED) &&
898 (lppop->items[wIndex].item_flags & MF_SEPARATOR))
899 wIndex = NO_SELECTED_ITEM;
900 if (lppop->FocusedItem == wIndex) return;
901 if (lppop->wFlags & MF_POPUP) hdc = GetDC32( lppop->hWnd );
902 else hdc = GetDCEx32( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
904 /* Clear previous highlighted item */
905 if (lppop->FocusedItem != NO_SELECTED_ITEM)
907 if (lppop->FocusedItem == SYSMENU_SELECTED)
908 NC_DrawSysButton( lppop->hWnd, hdc, FALSE );
909 else
911 lppop->items[lppop->FocusedItem].item_flags &=~(MF_HILITE|MF_MOUSESELECT);
912 MENU_DrawMenuItem(lppop->hWnd,hdc,&lppop->items[lppop->FocusedItem],
913 lppop->Height, !(lppop->wFlags & MF_POPUP) );
917 /* Highlight new item (if any) */
918 lppop->FocusedItem = wIndex;
919 if (lppop->FocusedItem != NO_SELECTED_ITEM)
921 if (lppop->FocusedItem == SYSMENU_SELECTED)
923 NC_DrawSysButton( lppop->hWnd, hdc, TRUE );
924 if (sendMenuSelect)
925 SendMessage16( hwndOwner, WM_MENUSELECT,
926 WIN_FindWndPtr(lppop->hWnd)->hSysMenu,
927 MAKELONG(lppop->wFlags | MF_MOUSESELECT, hmenu));
929 else
931 lppop->items[lppop->FocusedItem].item_flags |= MF_HILITE;
932 MENU_DrawMenuItem( lppop->hWnd, hdc, &lppop->items[lppop->FocusedItem],
933 lppop->Height, !(lppop->wFlags & MF_POPUP) );
934 if (sendMenuSelect)
935 SendMessage16( hwndOwner, WM_MENUSELECT,
936 lppop->items[lppop->FocusedItem].item_id,
937 MAKELONG( lppop->items[lppop->FocusedItem].item_flags | MF_MOUSESELECT, hmenu));
940 else if (sendMenuSelect)
941 SendMessage16( hwndOwner, WM_MENUSELECT, hmenu,
942 MAKELONG( lppop->wFlags | MF_MOUSESELECT, hmenu ) );
944 ReleaseDC32( lppop->hWnd, hdc );
948 /***********************************************************************
949 * MENU_SelectItemRel
952 static void MENU_SelectItemRel( HWND hwndOwner, HMENU16 hmenu, int offset )
954 int i, min = 0;
955 POPUPMENU *menu;
957 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
958 if (!menu->items) return;
959 if ((menu->FocusedItem != NO_SELECTED_ITEM) &&
960 (menu->FocusedItem != SYSMENU_SELECTED))
962 for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems
963 ; i += offset)
965 if (!(menu->items[i].item_flags & MF_SEPARATOR))
967 MENU_SelectItem( hwndOwner, hmenu, i, TRUE );
968 return;
972 if (MENU_HasSysMenu( menu ))
974 MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED, TRUE );
975 return;
979 if( offset > 0 ) { i = 0; min = -1; }
980 else i = menu->nItems - 1;
982 for ( ; i > min && i < menu->nItems ; i += offset)
984 if (!(menu->items[i].item_flags & MF_SEPARATOR))
986 MENU_SelectItem( hwndOwner, hmenu, i, TRUE );
987 return;
990 if (MENU_HasSysMenu( menu ))
991 MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED, TRUE );
995 /**********************************************************************
996 * MENU_SetItemData
998 * Set an item flags, id and text ptr.
1000 static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT id, LPCSTR str )
1002 LPSTR prevText = IS_STRING_ITEM(item->item_flags) ? item->text : NULL;
1004 if (IS_STRING_ITEM(flags))
1006 if (!str)
1008 flags |= MF_SEPARATOR;
1009 item->text = NULL;
1011 else
1013 LPSTR text;
1014 /* Item beginning with a backspace is a help item */
1015 if (*str == '\b')
1017 flags |= MF_HELP;
1018 str++;
1020 if (!(text = HEAP_strdupA( SystemHeap, 0, str ))) return FALSE;
1021 item->text = text;
1024 else if ((flags & MF_BITMAP) || (flags & MF_OWNERDRAW))
1025 item->text = (LPSTR)str;
1026 else item->text = NULL;
1028 item->item_flags = flags & ~(MF_HILITE | MF_MOUSESELECT);
1029 item->item_id = id;
1030 SetRectEmpty16( &item->rect );
1031 if (prevText) HeapFree( SystemHeap, 0, prevText );
1032 return TRUE;
1036 /**********************************************************************
1037 * MENU_InsertItem
1039 * Insert a new item into a menu.
1041 static MENUITEM *MENU_InsertItem( HMENU16 hMenu, UINT pos, UINT flags )
1043 MENUITEM *newItems;
1044 POPUPMENU *menu;
1046 if (!(menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu)))
1048 dprintf_menu( stddeb, "MENU_InsertItem: %04x not a menu handle\n",
1049 hMenu );
1050 return NULL;
1053 /* Find where to insert new item */
1055 if ((flags & MF_BYPOSITION) &&
1056 ((pos == (UINT)-1) || (pos == menu->nItems)))
1058 /* Special case: append to menu */
1059 /* Some programs specify the menu length to do that */
1060 pos = menu->nItems;
1062 else
1064 if (!MENU_FindItem( &hMenu, &pos, flags ))
1066 dprintf_menu( stddeb, "MENU_InsertItem: item %x not found\n",
1067 pos );
1068 return NULL;
1070 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu)))
1072 dprintf_menu(stddeb,"MENU_InsertItem: %04x not a menu handle\n",
1073 hMenu);
1074 return NULL;
1078 /* Create new items array */
1080 newItems = HeapAlloc( SystemHeap, 0, sizeof(MENUITEM) * (menu->nItems+1) );
1081 if (!newItems)
1083 dprintf_menu( stddeb, "MENU_InsertItem: allocation failed\n" );
1084 return NULL;
1086 if (menu->nItems > 0)
1088 /* Copy the old array into the new */
1089 if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
1090 if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
1091 (menu->nItems-pos)*sizeof(MENUITEM) );
1092 HeapFree( SystemHeap, 0, menu->items );
1094 menu->items = newItems;
1095 menu->nItems++;
1096 memset( &newItems[pos], 0, sizeof(*newItems) );
1097 return &newItems[pos];
1101 /**********************************************************************
1102 * MENU_ParseResource
1104 * Parse a standard menu resource and add items to the menu.
1105 * Return a pointer to the end of the resource.
1107 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU16 hMenu, BOOL unicode )
1109 WORD flags, id = 0;
1110 LPCSTR str;
1114 flags = GET_WORD(res);
1115 res += sizeof(WORD);
1116 if (!(flags & MF_POPUP))
1118 id = GET_WORD(res);
1119 res += sizeof(WORD);
1121 if (!IS_STRING_ITEM(flags))
1122 fprintf( stderr, "MENU_ParseResource: not a string item %04x\n",
1123 flags );
1124 str = res;
1125 if (!unicode) res += strlen(str) + 1;
1126 else res += (lstrlen32W((LPCWSTR)str) + 1) * sizeof(WCHAR);
1127 if (flags & MF_POPUP)
1129 HMENU16 hSubMenu = CreatePopupMenu();
1130 if (!hSubMenu) return NULL;
1131 if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
1132 return NULL;
1133 if (!unicode) AppendMenu32A( hMenu, flags, (UINT)hSubMenu, str );
1134 else AppendMenu32W( hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str );
1136 else /* Not a popup */
1138 if (!unicode) AppendMenu32A( hMenu, flags, id, *str ? str : NULL );
1139 else AppendMenu32W( hMenu, flags, id,
1140 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
1142 } while (!(flags & MF_END));
1143 return res;
1147 /***********************************************************************
1148 * MENU_GetSubPopup
1150 * Return the handle of the selected sub-popup menu (if any).
1152 static HMENU16 MENU_GetSubPopup( HMENU16 hmenu )
1154 POPUPMENU *menu;
1155 MENUITEM *item;
1157 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1158 if (menu->FocusedItem == NO_SELECTED_ITEM) return 0;
1159 else if (menu->FocusedItem == SYSMENU_SELECTED)
1160 return WIN_FindWndPtr(menu->hWnd)->hSysMenu;
1162 item = &menu->items[menu->FocusedItem];
1163 if (!(item->item_flags & MF_POPUP) || !(item->item_flags & MF_MOUSESELECT))
1164 return 0;
1165 return (HMENU16)item->item_id;
1169 /***********************************************************************
1170 * MENU_HideSubPopups
1172 * Hide the sub-popup menus of this menu.
1174 static void MENU_HideSubPopups( HWND hwndOwner, HMENU16 hmenu,
1175 BOOL sendMenuSelect )
1177 MENUITEM *item;
1178 POPUPMENU *menu, *submenu;
1179 HMENU16 hsubmenu;
1181 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return;
1182 if (menu->FocusedItem == NO_SELECTED_ITEM) return;
1183 if (menu->FocusedItem == SYSMENU_SELECTED)
1185 hsubmenu = WIN_FindWndPtr(menu->hWnd)->hSysMenu;
1187 else
1189 item = &menu->items[menu->FocusedItem];
1190 if (!(item->item_flags & MF_POPUP) ||
1191 !(item->item_flags & MF_MOUSESELECT)) return;
1192 item->item_flags &= ~MF_MOUSESELECT;
1193 hsubmenu = (HMENU16)item->item_id;
1195 submenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hsubmenu );
1196 MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
1197 MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect );
1198 if (submenu->hWnd == pTopPWnd->hwndSelf )
1200 ShowWindow( submenu->hWnd, SW_HIDE );
1201 uSubPWndLevel = 0;
1203 else
1205 DestroyWindow( submenu->hWnd );
1206 submenu->hWnd = 0;
1211 /***********************************************************************
1212 * MENU_ShowSubPopup
1214 * Display the sub-menu of the selected item of this menu.
1215 * Return the handle of the submenu, or hmenu if no submenu to display.
1217 static HMENU16 MENU_ShowSubPopup( HWND hwndOwner, HMENU16 hmenu,
1218 BOOL selectFirst )
1220 POPUPMENU *menu;
1221 MENUITEM *item;
1222 WND *wndPtr;
1224 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return hmenu;
1225 if (!(wndPtr = WIN_FindWndPtr( menu->hWnd ))) return hmenu;
1226 if (menu->FocusedItem == NO_SELECTED_ITEM) return hmenu;
1227 if (menu->FocusedItem == SYSMENU_SELECTED)
1229 MENU_InitSysMenuPopup(wndPtr->hSysMenu, wndPtr->dwStyle,
1230 wndPtr->class->style);
1231 MENU_ShowPopup(hwndOwner, wndPtr->hSysMenu, 0, wndPtr->rectClient.left,
1232 wndPtr->rectClient.top - menu->Height - 2*SYSMETRICS_CYBORDER,
1233 SYSMETRICS_CXSIZE, SYSMETRICS_CYSIZE );
1234 if (selectFirst) MENU_SelectItemRel( hwndOwner, wndPtr->hSysMenu, ITEM_NEXT );
1235 return wndPtr->hSysMenu;
1237 item = &menu->items[menu->FocusedItem];
1238 if (!(item->item_flags & MF_POPUP) ||
1239 (item->item_flags & (MF_GRAYED | MF_DISABLED))) return hmenu;
1240 item->item_flags |= MF_MOUSESELECT;
1241 if (menu->wFlags & MF_POPUP)
1243 MENU_ShowPopup( hwndOwner, (HMENU16)item->item_id, menu->FocusedItem,
1244 wndPtr->rectWindow.left + item->rect.right-arrow_bitmap_width,
1245 wndPtr->rectWindow.top + item->rect.top,
1246 item->rect.left - item->rect.right + 2*arrow_bitmap_width,
1247 item->rect.top - item->rect.bottom );
1249 else
1251 MENU_ShowPopup( hwndOwner, (HMENU16)item->item_id, menu->FocusedItem,
1252 wndPtr->rectWindow.left + item->rect.left,
1253 wndPtr->rectWindow.top + item->rect.bottom,
1254 item->rect.right - item->rect.left, item->rect.bottom - item->rect.top );
1256 if (selectFirst) MENU_SelectItemRel( hwndOwner, (HMENU16)item->item_id, ITEM_NEXT );
1257 return (HMENU16)item->item_id;
1261 /***********************************************************************
1262 * MENU_FindMenuByCoords
1264 * Find the menu containing a given point (in screen coords).
1266 static HMENU16 MENU_FindMenuByCoords( HMENU16 hmenu, POINT16 pt )
1268 POPUPMENU *menu;
1269 HWND hwnd;
1271 if (!(hwnd = WindowFromPoint16( pt ))) return 0;
1272 while (hmenu)
1274 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1275 if (menu->hWnd == hwnd)
1277 if (!(menu->wFlags & MF_POPUP))
1279 /* Make sure it's in the menu bar (or in system menu) */
1280 WND *wndPtr = WIN_FindWndPtr( menu->hWnd );
1281 if ((pt.x < wndPtr->rectClient.left) ||
1282 (pt.x >= wndPtr->rectClient.right) ||
1283 (pt.y >= wndPtr->rectClient.top)) return 0;
1284 if (pt.y < wndPtr->rectClient.top - menu->Height)
1286 if (!MENU_IsInSysMenu( menu, pt )) return 0;
1288 /* else it's in the menu bar */
1290 return hmenu;
1292 hmenu = MENU_GetSubPopup( hmenu );
1294 return 0;
1298 /***********************************************************************
1299 * MENU_ExecFocusedItem
1301 * Execute a menu item (for instance when user pressed Enter).
1302 * Return TRUE if we can go on with menu tracking.
1304 static BOOL MENU_ExecFocusedItem( HWND hwndOwner, HMENU16 hmenu,
1305 HMENU16 *hmenuCurrent )
1307 MENUITEM *item;
1308 POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1309 if (!menu || !menu->nItems || (menu->FocusedItem == NO_SELECTED_ITEM) ||
1310 (menu->FocusedItem == SYSMENU_SELECTED)) return TRUE;
1311 item = &menu->items[menu->FocusedItem];
1312 if (!(item->item_flags & MF_POPUP))
1314 if (!(item->item_flags & (MF_GRAYED | MF_DISABLED)))
1316 PostMessage( hwndOwner, (menu->wFlags & MF_SYSMENU) ?
1317 WM_SYSCOMMAND : WM_COMMAND, item->item_id, 0 );
1318 return FALSE;
1320 else return TRUE;
1322 else
1324 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, TRUE );
1325 return TRUE;
1330 /***********************************************************************
1331 * MENU_ButtonDown
1333 * Handle a button-down event in a menu. Point is in screen coords.
1334 * hmenuCurrent is the top-most visible popup.
1335 * Return TRUE if we can go on with menu tracking.
1337 static BOOL MENU_ButtonDown( HWND hwndOwner, HMENU16 hmenu,
1338 HMENU16 *hmenuCurrent, POINT16 pt )
1340 POPUPMENU *menu;
1341 MENUITEM *item;
1342 UINT id;
1344 if (!hmenu) return FALSE; /* Outside all menus */
1345 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1346 item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
1347 if (!item) /* Maybe in system menu */
1349 if (!MENU_IsInSysMenu( menu, pt )) return FALSE;
1350 id = SYSMENU_SELECTED;
1353 if (menu->FocusedItem == id)
1355 if (id == SYSMENU_SELECTED) return FALSE;
1356 if (item->item_flags & MF_POPUP)
1358 if (item->item_flags & MF_MOUSESELECT)
1360 if (menu->wFlags & MF_POPUP)
1362 MENU_HideSubPopups( hwndOwner, hmenu, TRUE );
1363 *hmenuCurrent = hmenu;
1365 else return FALSE;
1367 else *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
1370 else
1372 MENU_HideSubPopups( hwndOwner, hmenu, FALSE );
1373 MENU_SelectItem( hwndOwner, hmenu, id, TRUE );
1374 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
1376 return TRUE;
1380 /***********************************************************************
1381 * MENU_ButtonUp
1383 * Handle a button-up event in a menu. Point is in screen coords.
1384 * hmenuCurrent is the top-most visible popup.
1385 * Return TRUE if we can go on with menu tracking.
1387 static BOOL MENU_ButtonUp( HWND hwndOwner, HMENU16 hmenu,
1388 HMENU16 *hmenuCurrent, POINT16 pt )
1390 POPUPMENU *menu;
1391 MENUITEM *item;
1392 HMENU16 hsubmenu = 0;
1393 UINT id;
1395 if (!hmenu) return FALSE; /* Outside all menus */
1396 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1397 item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
1398 if (!item) /* Maybe in system menu */
1400 if (!MENU_IsInSysMenu( menu, pt )) return FALSE;
1401 id = SYSMENU_SELECTED;
1402 hsubmenu = WIN_FindWndPtr(menu->hWnd)->hSysMenu;
1405 if (menu->FocusedItem != id) return FALSE;
1407 if (id != SYSMENU_SELECTED)
1409 if (!(item->item_flags & MF_POPUP))
1411 return MENU_ExecFocusedItem( hwndOwner, hmenu, hmenuCurrent );
1413 hsubmenu = (HMENU16)item->item_id;
1415 /* Select first item of sub-popup */
1416 MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, FALSE );
1417 MENU_SelectItemRel( hwndOwner, hsubmenu, ITEM_NEXT );
1418 return TRUE;
1422 /***********************************************************************
1423 * MENU_MouseMove
1425 * Handle a motion event in a menu. Point is in screen coords.
1426 * hmenuCurrent is the top-most visible popup.
1427 * Return TRUE if we can go on with menu tracking.
1429 static BOOL MENU_MouseMove( HWND hwndOwner, HMENU16 hmenu,
1430 HMENU16 *hmenuCurrent, POINT16 pt )
1432 MENUITEM *item;
1433 POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1434 UINT id = NO_SELECTED_ITEM;
1436 if (hmenu)
1438 item = MENU_FindItemByCoords( menu, pt.x, pt.y, &id );
1439 if (!item) /* Maybe in system menu */
1441 if (!MENU_IsInSysMenu( menu, pt ))
1442 id = NO_SELECTED_ITEM; /* Outside all items */
1443 else id = SYSMENU_SELECTED;
1446 if (id == NO_SELECTED_ITEM)
1448 MENU_SelectItem( hwndOwner, *hmenuCurrent, NO_SELECTED_ITEM, TRUE );
1450 else if (menu->FocusedItem != id)
1452 MENU_HideSubPopups( hwndOwner, hmenu, FALSE );
1453 MENU_SelectItem( hwndOwner, hmenu, id, TRUE );
1454 *hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
1456 return TRUE;
1459 /***********************************************************************
1460 * MENU_DoNextMenu
1462 static LRESULT MENU_DoNextMenu( HWND* hwndOwner, HMENU16* hmenu,
1463 HMENU16 *hmenuCurrent, UINT vk)
1465 POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( *hmenu );
1466 UINT id = 0;
1468 if( (vk == VK_LEFT && !menu->FocusedItem)
1469 || (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1)
1470 || menu->FocusedItem == SYSMENU_SELECTED
1471 || ((menu->wFlags & (MF_POPUP | MF_SYSMENU)) == (MF_POPUP | MF_SYSMENU)) )
1473 LRESULT l = SendMessage16( *hwndOwner, WM_NEXTMENU, (WPARAM16)vk,
1474 (LPARAM)((menu->FocusedItem == SYSMENU_SELECTED)
1475 ? GetSystemMenu( *hwndOwner, 0)
1476 : *hmenu));
1478 if( l == 0 || !IsMenu(LOWORD(l)) || !IsWindow(HIWORD(l)) ) return 0;
1480 /* shutdown current menu -
1481 * all these checks for system popup window are needed
1482 * only because Wine system menu tracking is unsuitable
1483 * for a lot of things (esp. when we do not have wIDmenu to fall back on).
1486 MENU_SelectItem( *hwndOwner, *hmenu, NO_SELECTED_ITEM, FALSE );
1488 if( (menu->wFlags & (MF_POPUP | MF_SYSMENU)) == (MF_POPUP | MF_SYSMENU) )
1490 ShowWindow( menu->hWnd, SW_HIDE );
1491 uSubPWndLevel = 0;
1493 if( !IsIconic( *hwndOwner ) )
1495 HDC32 hdc = GetDCEx32( *hwndOwner, 0, DCX_CACHE | DCX_WINDOW);
1496 NC_DrawSysButton( *hwndOwner, hdc, FALSE );
1497 ReleaseDC32( *hwndOwner, hdc );
1501 ReleaseCapture();
1502 *hwndOwner = HIWORD(l);
1503 *hmenu = LOWORD(l);
1504 SetCapture32( *hwndOwner );
1506 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( *hmenu );
1508 /* init next menu */
1510 if( (menu->wFlags & (MF_POPUP | MF_SYSMENU)) == (MF_POPUP | MF_SYSMENU) )
1512 RECT16 rect;
1513 WND* wndPtr = WIN_FindWndPtr( *hwndOwner );
1515 /* stupid kludge, see above */
1517 if( wndPtr->wIDmenu && !(wndPtr->dwStyle & WS_CHILD) )
1518 { *hmenu = wndPtr->wIDmenu; id = SYSMENU_SELECTED; }
1519 else
1521 if( NC_GetSysPopupPos( wndPtr, &rect ) )
1522 MENU_ShowPopup( *hwndOwner, *hmenu, 0, rect.left, rect.bottom,
1523 SYSMETRICS_CXSIZE, SYSMETRICS_CYSIZE );
1525 if( !IsIconic( *hwndOwner ) )
1527 HDC32 hdc = GetDCEx32( *hwndOwner, 0, DCX_CACHE | DCX_WINDOW);
1528 NC_DrawSysButton( *hwndOwner, hdc, TRUE );
1529 ReleaseDC32( *hwndOwner, hdc );
1534 MENU_SelectItem( *hwndOwner, *hmenu, id, TRUE );
1535 return l;
1537 return 0;
1540 /***********************************************************************
1541 * MENU_KeyLeft
1543 * Handle a VK_LEFT key event in a menu.
1544 * hmenuCurrent is the top-most visible popup.
1546 static void MENU_KeyLeft( HWND* hwndOwner, HMENU16* hmenu,
1547 HMENU16 *hmenuCurrent )
1549 POPUPMENU *menu;
1550 HMENU16 hmenutmp, hmenuprev;
1552 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( *hmenu );
1553 hmenuprev = hmenutmp = *hmenu;
1554 while (hmenutmp != *hmenuCurrent)
1556 hmenutmp = MENU_GetSubPopup( hmenuprev );
1557 if (hmenutmp != *hmenuCurrent) hmenuprev = hmenutmp;
1559 MENU_HideSubPopups( *hwndOwner, hmenuprev, TRUE );
1560 hmenutmp = *hmenu;
1562 if ( (hmenuprev == *hmenu) &&
1563 ((menu->wFlags & MF_SYSMENU) || !(menu->wFlags & MF_POPUP)) )
1565 /* send WM_NEXTMENU */
1567 if( !MENU_DoNextMenu( hwndOwner, hmenu, hmenuCurrent, VK_LEFT) )
1568 MENU_SelectItemRel( *hwndOwner, *hmenu, ITEM_PREV );
1569 else *hmenuCurrent = *hmenu;
1571 if (*hmenuCurrent != hmenutmp)
1573 /* A sublevel menu was displayed -> display the next one */
1574 *hmenuCurrent = MENU_ShowSubPopup( *hwndOwner, *hmenu, TRUE );
1577 else *hmenuCurrent = hmenuprev;
1581 /***********************************************************************
1582 * MENU_KeyRight
1584 * Handle a VK_RIGHT key event in a menu.
1585 * hmenuCurrent is the top-most visible popup.
1587 static void MENU_KeyRight( HWND* hwndOwner, HMENU16* hmenu,
1588 HMENU16 *hmenuCurrent )
1590 POPUPMENU *menu;
1591 HMENU16 hmenutmp;
1593 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( *hmenu );
1595 if ((menu->wFlags & MF_POPUP) || (*hmenuCurrent != *hmenu))
1597 /* If already displaying a popup, try to display sub-popup */
1598 hmenutmp = MENU_ShowSubPopup( *hwndOwner, *hmenuCurrent, TRUE );
1599 if (hmenutmp != *hmenuCurrent) /* Sub-popup displayed */
1601 *hmenuCurrent = hmenutmp;
1602 return;
1606 /* If menu-bar tracking, go to next item */
1608 if (!(menu->wFlags & MF_POPUP) || (menu->wFlags & MF_SYSMENU))
1610 MENU_HideSubPopups( *hwndOwner, *hmenu, FALSE );
1611 hmenutmp = *hmenu;
1613 /* Send WM_NEXTMENU */
1615 if( !MENU_DoNextMenu( hwndOwner, hmenu, hmenuCurrent, VK_RIGHT) )
1616 MENU_SelectItemRel( *hwndOwner, *hmenu, ITEM_NEXT );
1617 else *hmenuCurrent = *hmenu;
1619 if (*hmenuCurrent != hmenutmp)
1621 /* A sublevel menu was displayed -> display the next one */
1622 *hmenuCurrent = MENU_ShowSubPopup( *hwndOwner, *hmenu, TRUE );
1625 else if (*hmenuCurrent != *hmenu) /* Hide last level popup */
1627 HMENU16 hmenuprev;
1628 hmenuprev = hmenutmp = *hmenu;
1629 while (hmenutmp != *hmenuCurrent)
1631 hmenutmp = MENU_GetSubPopup( hmenuprev );
1632 if (hmenutmp != *hmenuCurrent) hmenuprev = hmenutmp;
1634 MENU_HideSubPopups( *hwndOwner, hmenuprev, TRUE );
1635 *hmenuCurrent = hmenuprev;
1640 /***********************************************************************
1641 * MENU_TrackMenu
1643 * Menu tracking code.
1644 * If 'x' and 'y' are not 0, we simulate a button-down event at (x,y)
1645 * before beginning tracking. This is to help menu-bar tracking.
1647 static BOOL MENU_TrackMenu( HMENU16 hmenu, UINT wFlags, int x, int y,
1648 HWND hwnd, const RECT16 *lprect )
1650 MSG16 msg;
1651 POPUPMENU *menu;
1652 HMENU16 hmenuCurrent = hmenu;
1653 BOOL fClosed = FALSE, fRemove;
1654 UINT pos;
1656 fEndMenuCalled = FALSE;
1657 if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
1658 if (x && y)
1660 POINT16 pt = { x, y };
1661 MENU_ButtonDown( hwnd, hmenu, &hmenuCurrent, pt );
1663 SetCapture32( hwnd );
1664 while (!fClosed)
1666 if (!MSG_InternalGetMessage( &msg, 0, hwnd, MSGF_MENU, 0, TRUE ))
1667 break;
1669 TranslateMessage( &msg );
1671 fRemove = FALSE;
1672 if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
1674 /* Find the sub-popup for this mouse event (if any) */
1675 HMENU16 hsubmenu = MENU_FindMenuByCoords( hmenu, msg.pt );
1677 switch(msg.message)
1679 case WM_RBUTTONDOWN:
1680 case WM_NCRBUTTONDOWN:
1681 if (!(wFlags & TPM_RIGHTBUTTON)) break;
1682 /* fall through */
1683 case WM_LBUTTONDOWN:
1684 case WM_NCLBUTTONDOWN:
1685 fClosed = !MENU_ButtonDown( hwnd, hsubmenu,
1686 &hmenuCurrent, msg.pt );
1687 break;
1689 case WM_RBUTTONUP:
1690 case WM_NCRBUTTONUP:
1691 if (!(wFlags & TPM_RIGHTBUTTON)) break;
1692 /* fall through */
1693 case WM_LBUTTONUP:
1694 case WM_NCLBUTTONUP:
1695 /* If outside all menus but inside lprect, ignore it */
1696 if (!hsubmenu && lprect && PtInRect16(lprect, msg.pt)) break;
1697 fClosed = !MENU_ButtonUp( hwnd, hsubmenu,
1698 &hmenuCurrent, msg.pt );
1699 fRemove = TRUE; /* Remove event even if outside menu */
1700 break;
1702 case WM_MOUSEMOVE:
1703 case WM_NCMOUSEMOVE:
1704 if ((msg.wParam & MK_LBUTTON) ||
1705 ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON)))
1707 fClosed = !MENU_MouseMove( hwnd, hsubmenu,
1708 &hmenuCurrent, msg.pt );
1710 break;
1713 else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
1715 fRemove = TRUE; /* Keyboard messages are always removed */
1716 switch(msg.message)
1718 case WM_KEYDOWN:
1719 switch(msg.wParam)
1721 case VK_HOME:
1722 case VK_END:
1723 MENU_SelectItem( hwnd, hmenuCurrent, NO_SELECTED_ITEM, FALSE );
1725 /* fall through */
1726 case VK_UP:
1727 MENU_SelectItemRel( hwnd, hmenuCurrent,
1728 (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
1729 break;
1731 case VK_DOWN: /* If on menu bar, pull-down the menu */
1733 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1734 if (!(menu->wFlags & MF_POPUP) && (hmenuCurrent == hmenu))
1735 hmenuCurrent = MENU_ShowSubPopup( hwnd, hmenu, TRUE );
1736 else
1737 MENU_SelectItemRel( hwnd, hmenuCurrent, ITEM_NEXT );
1738 break;
1740 case VK_LEFT:
1741 MENU_KeyLeft( &hwnd, &hmenu, &hmenuCurrent );
1742 break;
1744 case VK_RIGHT:
1745 MENU_KeyRight( &hwnd, &hmenu, &hmenuCurrent );
1746 break;
1748 case VK_SPACE:
1749 case VK_RETURN:
1750 fClosed = !MENU_ExecFocusedItem( hwnd, hmenuCurrent,
1751 &hmenuCurrent );
1752 break;
1754 case VK_ESCAPE:
1755 fClosed = TRUE;
1756 break;
1758 default:
1759 break;
1761 break; /* WM_KEYDOWN */
1763 case WM_SYSKEYDOWN:
1764 switch(msg.wParam)
1766 case VK_MENU:
1767 fClosed = TRUE;
1768 break;
1771 break; /* WM_SYSKEYDOWN */
1773 case WM_CHAR:
1775 /* Hack to avoid control chars. */
1776 /* We will find a better way real soon... */
1777 if ((msg.wParam <= 32) || (msg.wParam >= 127)) break;
1778 pos = MENU_FindItemByKey( hwnd, hmenuCurrent, msg.wParam );
1779 if (pos == (UINT)-2) fClosed = TRUE;
1780 else if (pos == (UINT)-1) MessageBeep(0);
1781 else
1783 MENU_SelectItem( hwnd, hmenuCurrent, pos, TRUE );
1784 fClosed = !MENU_ExecFocusedItem( hwnd, hmenuCurrent,
1785 &hmenuCurrent );
1789 break; /* WM_CHAR */
1790 } /* switch(msg.message) */
1792 else
1794 DispatchMessage( &msg );
1796 if (fEndMenuCalled) fClosed = TRUE;
1797 if (!fClosed) fRemove = TRUE;
1799 if (fRemove) /* Remove the message from the queue */
1800 PeekMessage16( &msg, 0, msg.message, msg.message, PM_REMOVE );
1803 ReleaseCapture();
1804 MENU_HideSubPopups( hwnd, hmenu, FALSE );
1805 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
1806 if (menu && menu->wFlags & MF_POPUP)
1808 ShowWindow( menu->hWnd, SW_HIDE );
1809 uSubPWndLevel = 0;
1811 MENU_SelectItem( hwnd, hmenu, NO_SELECTED_ITEM, FALSE );
1812 SendMessage16( hwnd, WM_MENUSELECT, 0, MAKELONG( 0xffff, 0 ) );
1813 fEndMenuCalled = FALSE;
1814 return TRUE;
1818 /***********************************************************************
1819 * MENU_TrackMouseMenuBar
1821 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
1823 void MENU_TrackMouseMenuBar( HWND hwnd, POINT16 pt )
1825 WND *wndPtr = WIN_FindWndPtr( hwnd );
1826 HideCaret(0);
1827 SendMessage16( hwnd, WM_ENTERMENULOOP, 0, 0 );
1828 SendMessage16( hwnd, WM_INITMENU, wndPtr->wIDmenu, 0 );
1829 MENU_TrackMenu( (HMENU16)wndPtr->wIDmenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
1830 pt.x, pt.y, hwnd, NULL );
1831 SendMessage16( hwnd, WM_EXITMENULOOP, 0, 0 );
1832 ShowCaret(0);
1836 /***********************************************************************
1837 * MENU_TrackKbdMenuBar
1839 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
1841 void MENU_TrackKbdMenuBar( WND* wndPtr, UINT wParam, INT vkey)
1843 UINT uItem = NO_SELECTED_ITEM;
1844 HMENU16 hTrackMenu;
1846 /* find window that has a menu
1849 if( !(wndPtr->dwStyle & WS_CHILD) )
1851 wndPtr = WIN_FindWndPtr( GetActiveWindow() );
1852 if( !wndPtr ) return;
1854 else
1855 while( wndPtr->dwStyle & WS_CHILD &&
1856 !(wndPtr->dwStyle & WS_SYSMENU) )
1857 if( !(wndPtr = wndPtr->parent) ) return;
1859 if( wndPtr->dwStyle & WS_CHILD || !wndPtr->wIDmenu )
1860 if( !(wndPtr->dwStyle & WS_SYSMENU) )
1861 return;
1863 hTrackMenu = ( IsMenu( wndPtr->wIDmenu ) )? wndPtr->wIDmenu:
1864 wndPtr->hSysMenu;
1866 HideCaret(0);
1867 SendMessage16( wndPtr->hwndSelf, WM_ENTERMENULOOP, 0, 0 );
1868 SendMessage16( wndPtr->hwndSelf, WM_INITMENU, wndPtr->wIDmenu, 0 );
1870 /* find suitable menu entry
1873 if( vkey == VK_SPACE )
1874 uItem = SYSMENU_SELECTED;
1875 else if( vkey )
1877 uItem = MENU_FindItemByKey( wndPtr->hwndSelf, wndPtr->wIDmenu, vkey );
1878 if( uItem >= 0xFFFE )
1880 if( uItem == 0xFFFF )
1881 MessageBeep(0);
1882 SendMessage16( wndPtr->hwndSelf, WM_EXITMENULOOP, 0, 0 );
1883 ShowCaret(0);
1884 return;
1888 MENU_SelectItem( wndPtr->hwndSelf, hTrackMenu, uItem, TRUE );
1889 if( uItem == NO_SELECTED_ITEM )
1890 MENU_SelectItemRel( wndPtr->hwndSelf, hTrackMenu, ITEM_NEXT );
1891 else
1892 PostMessage( wndPtr->hwndSelf, WM_KEYDOWN, VK_DOWN, 0L );
1894 MENU_TrackMenu( hTrackMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
1895 0, 0, wndPtr->hwndSelf, NULL );
1897 SendMessage16( wndPtr->hwndSelf, WM_EXITMENULOOP, 0, 0 );
1898 ShowCaret(0);
1902 /**********************************************************************
1903 * TrackPopupMenu16 (USER.416)
1905 BOOL16 TrackPopupMenu16( HMENU16 hMenu, UINT16 wFlags, INT16 x, INT16 y,
1906 INT16 nReserved, HWND16 hWnd, const RECT16 *lpRect )
1908 BOOL ret = FALSE;
1910 HideCaret(0);
1911 if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
1912 ret = MENU_TrackMenu( hMenu, wFlags, 0, 0, hWnd, lpRect );
1913 ShowCaret(0);
1914 return ret;
1918 /**********************************************************************
1919 * TrackPopupMenu32 (USER32.548)
1921 BOOL32 TrackPopupMenu32( HMENU32 hMenu, UINT32 wFlags, INT32 x, INT32 y,
1922 INT32 nReserved, HWND32 hWnd, const RECT32 *lpRect )
1924 RECT16 r;
1925 if (lpRect)
1926 CONV_RECT32TO16( lpRect, &r );
1927 return TrackPopupMenu16(hMenu,wFlags,x,y,nReserved,hWnd,lpRect?&r:NULL);
1931 /***********************************************************************
1932 * PopupMenuWndProc
1934 LRESULT PopupMenuWndProc(HWND hwnd,UINT message,WPARAM16 wParam,LPARAM lParam)
1936 switch(message)
1938 case WM_CREATE:
1940 CREATESTRUCT16 *cs = (CREATESTRUCT16*)PTR_SEG_TO_LIN(lParam);
1941 SetWindowLong32A( hwnd, 0, (LONG)cs->lpCreateParams );
1942 return 0;
1945 case WM_MOUSEACTIVATE: /* We don't want to be activated */
1946 return MA_NOACTIVATE;
1948 case WM_PAINT:
1950 PAINTSTRUCT16 ps;
1951 BeginPaint16( hwnd, &ps );
1952 MENU_DrawPopupMenu( hwnd, ps.hdc,
1953 (HMENU16)GetWindowLong32A( hwnd, 0 ) );
1954 EndPaint16( hwnd, &ps );
1955 return 0;
1958 case WM_DESTROY:
1959 /* zero out global pointer in case system popup
1960 * was destroyed by AppExit
1963 if( hwnd == pTopPWnd->hwndSelf )
1964 { pTopPWnd = NULL; uSubPWndLevel = 0; }
1965 else
1966 uSubPWndLevel--;
1967 break;
1969 case WM_USER:
1970 if (wParam) SetWindowLong32A( hwnd, 0, (HMENU16)wParam );
1971 break;
1972 default:
1973 return DefWindowProc16(hwnd, message, wParam, lParam);
1975 return 0;
1979 /***********************************************************************
1980 * MENU_GetMenuBarHeight
1982 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
1984 UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth, int orgX, int orgY )
1986 HDC32 hdc;
1987 RECT16 rectBar;
1988 WND *wndPtr;
1989 LPPOPUPMENU lppop;
1991 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
1992 if (!(lppop = (LPPOPUPMENU)USER_HEAP_LIN_ADDR((HMENU16)wndPtr->wIDmenu)))
1993 return 0;
1994 hdc = GetDCEx32( hwnd, 0, DCX_CACHE | DCX_WINDOW );
1995 SetRect16(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+SYSMETRICS_CYMENU);
1996 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
1997 ReleaseDC32( hwnd, hdc );
1998 return lppop->Height;
2002 /*******************************************************************
2003 * ChangeMenu16 (USER.153)
2005 BOOL16 ChangeMenu16( HMENU16 hMenu, UINT16 pos, SEGPTR data,
2006 UINT16 id, UINT16 flags )
2008 dprintf_menu( stddeb,"ChangeMenu16: menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
2009 hMenu, pos, (DWORD)data, id, flags );
2010 if (flags & MF_APPEND) return AppendMenu16( hMenu, flags & ~MF_APPEND,
2011 id, data );
2012 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
2013 /* for MF_DELETE. We should check the parameters for all others */
2014 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
2015 if (flags & MF_DELETE) return DeleteMenu( hMenu, pos, flags & ~MF_DELETE );
2016 if (flags & MF_CHANGE) return ModifyMenu16( hMenu, pos, flags & ~MF_CHANGE,
2017 id, data );
2018 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
2019 flags & MF_BYPOSITION ? pos : id,
2020 flags & ~MF_REMOVE );
2021 /* Default: MF_INSERT */
2022 return InsertMenu16( hMenu, pos, flags, id, data );
2026 /*******************************************************************
2027 * ChangeMenu32A (USER32.22)
2029 BOOL32 ChangeMenu32A( HMENU32 hMenu, UINT32 pos, LPCSTR data,
2030 UINT32 id, UINT32 flags )
2032 dprintf_menu( stddeb,"ChangeMenu32A: menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2033 hMenu, pos, (DWORD)data, id, flags );
2034 if (flags & MF_APPEND) return AppendMenu32A( hMenu, flags & ~MF_APPEND,
2035 id, data );
2036 if (flags & MF_DELETE) return DeleteMenu( hMenu, pos, flags & ~MF_DELETE );
2037 if (flags & MF_CHANGE) return ModifyMenu32A(hMenu, pos, flags & ~MF_CHANGE,
2038 id, data );
2039 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
2040 flags & MF_BYPOSITION ? pos : id,
2041 flags & ~MF_REMOVE );
2042 /* Default: MF_INSERT */
2043 return InsertMenu32A( hMenu, pos, flags, id, data );
2047 /*******************************************************************
2048 * ChangeMenu32W (USER32.23)
2050 BOOL32 ChangeMenu32W( HMENU32 hMenu, UINT32 pos, LPCWSTR data,
2051 UINT32 id, UINT32 flags )
2053 dprintf_menu( stddeb,"ChangeMenu32W: menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
2054 hMenu, pos, (DWORD)data, id, flags );
2055 if (flags & MF_APPEND) return AppendMenu32W( hMenu, flags & ~MF_APPEND,
2056 id, data );
2057 if (flags & MF_DELETE) return DeleteMenu( hMenu, pos, flags & ~MF_DELETE );
2058 if (flags & MF_CHANGE) return ModifyMenu32W(hMenu, pos, flags & ~MF_CHANGE,
2059 id, data );
2060 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
2061 flags & MF_BYPOSITION ? pos : id,
2062 flags & ~MF_REMOVE );
2063 /* Default: MF_INSERT */
2064 return InsertMenu32W( hMenu, pos, flags, id, data );
2068 /*******************************************************************
2069 * CheckMenuItem (USER.154)
2071 INT CheckMenuItem( HMENU16 hMenu, UINT id, UINT flags )
2073 MENUITEM *item;
2074 INT ret;
2076 dprintf_menu( stddeb,"CheckMenuItem: %04x %04x %04x\n", hMenu, id, flags );
2077 if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
2078 ret = item->item_flags & MF_CHECKED;
2079 if (flags & MF_CHECKED) item->item_flags |= MF_CHECKED;
2080 else item->item_flags &= ~MF_CHECKED;
2081 return ret;
2085 /**********************************************************************
2086 * EnableMenuItem [USER.155]
2088 BOOL EnableMenuItem(HMENU16 hMenu, UINT wItemID, UINT wFlags)
2090 MENUITEM *item;
2091 dprintf_menu(stddeb,"EnableMenuItem (%04x, %04X, %04X) !\n",
2092 hMenu, wItemID, wFlags);
2093 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return FALSE;
2095 /* We can't have MF_GRAYED and MF_DISABLED together */
2096 if (wFlags & MF_GRAYED)
2098 item->item_flags = (item->item_flags & ~MF_DISABLED) | MF_GRAYED;
2100 else if (wFlags & MF_DISABLED)
2102 item->item_flags = (item->item_flags & ~MF_GRAYED) | MF_DISABLED;
2104 else /* MF_ENABLED */
2106 item->item_flags &= ~(MF_GRAYED | MF_DISABLED);
2108 return TRUE;
2112 /*******************************************************************
2113 * GetMenuString (USER.161)
2115 int GetMenuString( HMENU16 hMenu, UINT wItemID,
2116 LPSTR str, short nMaxSiz, UINT wFlags )
2118 MENUITEM *item;
2120 dprintf_menu( stddeb, "GetMenuString: menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
2121 hMenu, wItemID, str, nMaxSiz, wFlags );
2122 if (!str || !nMaxSiz) return 0;
2123 str[0] = '\0';
2124 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
2125 if (!IS_STRING_ITEM(item->item_flags)) return 0;
2126 lstrcpyn32A( str, item->text, nMaxSiz );
2127 dprintf_menu( stddeb, "GetMenuString: returning '%s'\n", str );
2128 return strlen(str);
2132 /**********************************************************************
2133 * HiliteMenuItem [USER.162]
2135 BOOL HiliteMenuItem(HWND hWnd, HMENU16 hMenu, UINT wItemID, UINT wHilite)
2137 LPPOPUPMENU menu;
2138 dprintf_menu(stddeb,"HiliteMenuItem(%04x, %04x, %04x, %04x);\n",
2139 hWnd, hMenu, wItemID, wHilite);
2140 if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
2141 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
2142 if (menu->FocusedItem == wItemID) return TRUE;
2143 MENU_HideSubPopups( hWnd, hMenu, FALSE );
2144 MENU_SelectItem( hWnd, hMenu, wItemID, TRUE );
2145 return TRUE;
2149 /**********************************************************************
2150 * GetMenuState [USER.250]
2152 UINT GetMenuState(HMENU16 hMenu, UINT wItemID, UINT wFlags)
2154 MENUITEM *item;
2155 dprintf_menu(stddeb,"GetMenuState(%04x, %04x, %04x);\n",
2156 hMenu, wItemID, wFlags);
2157 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
2158 if (item->item_flags & MF_POPUP)
2160 POPUPMENU *menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( (HMENU16)item->item_id );
2161 if (!menu) return -1;
2162 else return (menu->nItems << 8) | (menu->wFlags & 0xff);
2164 else return item->item_flags;
2168 /**********************************************************************
2169 * GetMenuItemCount [USER.263]
2171 INT GetMenuItemCount(HMENU16 hMenu)
2173 LPPOPUPMENU menu;
2174 dprintf_menu(stddeb,"GetMenuItemCount(%04x);\n", hMenu);
2175 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
2176 if (menu == NULL || menu->wMagic != MENU_MAGIC) return (UINT)-1;
2177 dprintf_menu(stddeb,"GetMenuItemCount(%04x) return %d \n",
2178 hMenu, menu->nItems);
2179 return menu->nItems;
2183 /**********************************************************************
2184 * GetMenuItemID [USER.264]
2186 UINT GetMenuItemID(HMENU16 hMenu, int nPos)
2188 LPPOPUPMENU menu;
2190 dprintf_menu(stddeb,"GetMenuItemID(%04x, %d);\n", hMenu, nPos);
2191 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return -1;
2192 if ((nPos < 0) || (nPos >= menu->nItems)) return -1;
2193 if (menu->items[nPos].item_flags & MF_POPUP) return -1;
2194 return menu->items[nPos].item_id;
2198 /*******************************************************************
2199 * InsertMenu16 (USER.410)
2201 BOOL16 InsertMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
2202 UINT16 id, SEGPTR data )
2204 if (IS_STRING_ITEM(flags) && data)
2205 return InsertMenu32A( hMenu, (INT32)(INT16)pos, flags, id,
2206 (LPSTR)PTR_SEG_TO_LIN(data) );
2207 return InsertMenu32A( hMenu, (INT32)(INT16)pos, flags, id, (LPSTR)data );
2211 /*******************************************************************
2212 * InsertMenu32A (USER32.321)
2214 BOOL32 InsertMenu32A( HMENU32 hMenu, UINT32 pos, UINT32 flags,
2215 UINT32 id, LPCSTR str )
2217 MENUITEM *item;
2219 if (IS_STRING_ITEM(flags) && str)
2220 dprintf_menu( stddeb, "InsertMenu: %04x %d %04x %04x '%s'\n",
2221 hMenu, pos, flags, id, str );
2222 else dprintf_menu( stddeb, "InsertMenu: %04x %d %04x %04x %08lx\n",
2223 hMenu, pos, flags, id, (DWORD)str );
2225 if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
2227 if (!(MENU_SetItemData( item, flags, id, str )))
2229 RemoveMenu( hMenu, pos, flags );
2230 return FALSE;
2233 if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
2234 ((POPUPMENU *)USER_HEAP_LIN_ADDR((HMENU16)id))->wFlags |= MF_POPUP;
2236 item->hCheckBit = hStdCheck;
2237 item->hUnCheckBit = 0;
2238 return TRUE;
2242 /*******************************************************************
2243 * InsertMenu32W (USER32.324)
2245 BOOL32 InsertMenu32W( HMENU32 hMenu, UINT32 pos, UINT32 flags,
2246 UINT32 id, LPCWSTR str )
2248 BOOL32 ret;
2250 if (IS_STRING_ITEM(flags) && str)
2252 LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
2253 ret = InsertMenu32A( hMenu, pos, flags, id, newstr );
2254 HeapFree( GetProcessHeap(), 0, newstr );
2255 return ret;
2257 else return InsertMenu32A( hMenu, pos, flags, id, (LPCSTR)str );
2261 /*******************************************************************
2262 * AppendMenu16 (USER.411)
2264 BOOL16 AppendMenu16( HMENU16 hMenu, UINT16 flags, UINT16 id, SEGPTR data )
2266 return InsertMenu16( hMenu, -1, flags | MF_BYPOSITION, id, data );
2270 /*******************************************************************
2271 * AppendMenu32A (USER32.4)
2273 BOOL32 AppendMenu32A( HMENU32 hMenu, UINT32 flags, UINT32 id, LPCSTR data )
2275 return InsertMenu32A( hMenu, -1, flags | MF_BYPOSITION, id, data );
2279 /*******************************************************************
2280 * AppendMenu32W (USER32.5)
2282 BOOL32 AppendMenu32W( HMENU32 hMenu, UINT32 flags, UINT32 id, LPCWSTR data )
2284 return InsertMenu32W( hMenu, -1, flags | MF_BYPOSITION, id, data );
2288 /**********************************************************************
2289 * RemoveMenu [USER.412]
2291 BOOL RemoveMenu(HMENU16 hMenu, UINT nPos, UINT wFlags)
2293 LPPOPUPMENU menu;
2294 MENUITEM *item;
2296 dprintf_menu(stddeb,"RemoveMenu (%04x, %04x, %04x)\n",hMenu, nPos, wFlags);
2297 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
2298 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
2300 /* Remove item */
2302 if (IS_STRING_ITEM(item->item_flags) && item->text)
2303 HeapFree( SystemHeap, 0, item->text );
2304 if (--menu->nItems == 0)
2306 HeapFree( SystemHeap, 0, menu->items );
2307 menu->items = NULL;
2309 else
2311 while(nPos < menu->nItems)
2313 *item = *(item+1);
2314 item++;
2315 nPos++;
2317 menu->items = HeapReAlloc( SystemHeap, 0, menu->items,
2318 menu->nItems * sizeof(MENUITEM) );
2320 return TRUE;
2324 /**********************************************************************
2325 * DeleteMenu [USER.413]
2327 BOOL DeleteMenu(HMENU16 hMenu, UINT nPos, UINT wFlags)
2329 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
2330 if (!item) return FALSE;
2331 if (item->item_flags & MF_POPUP) DestroyMenu( (HMENU16)item->item_id );
2332 /* nPos is now the position of the item */
2333 RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
2334 return TRUE;
2338 /*******************************************************************
2339 * ModifyMenu16 (USER.414)
2341 BOOL16 ModifyMenu16( HMENU16 hMenu, UINT16 pos, UINT16 flags,
2342 UINT16 id, SEGPTR data )
2344 if (IS_STRING_ITEM(flags))
2345 return ModifyMenu32A( hMenu, (INT32)(INT16)pos, flags, id,
2346 (LPSTR)PTR_SEG_TO_LIN(data) );
2347 return ModifyMenu32A( hMenu, (INT32)(INT16)pos, flags, id, (LPSTR)data );
2351 /*******************************************************************
2352 * ModifyMenu32A (USER32.396)
2354 BOOL32 ModifyMenu32A( HMENU32 hMenu, UINT32 pos, UINT32 flags,
2355 UINT32 id, LPCSTR str )
2357 MENUITEM *item;
2358 HMENU16 hMenu16 = hMenu;
2359 UINT16 pos16 = pos;
2361 if (IS_STRING_ITEM(flags))
2363 dprintf_menu( stddeb, "ModifyMenu: %04x %d %04x %04x '%s'\n",
2364 hMenu, pos, flags, id, str ? str : "#NULL#" );
2365 if (!str) return FALSE;
2367 else
2369 dprintf_menu( stddeb, "ModifyMenu: %04x %d %04x %04x %08lx\n",
2370 hMenu, pos, flags, id, (DWORD)str );
2373 if (!(item = MENU_FindItem( &hMenu16, &pos16, flags ))) return FALSE;
2374 return MENU_SetItemData( item, flags, id, str );
2378 /*******************************************************************
2379 * ModifyMenu32W (USER32.397)
2381 BOOL32 ModifyMenu32W( HMENU32 hMenu, UINT32 pos, UINT32 flags,
2382 UINT32 id, LPCWSTR str )
2384 BOOL32 ret;
2386 if (IS_STRING_ITEM(flags) && str)
2388 LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
2389 ret = ModifyMenu32A( hMenu, pos, flags, id, newstr );
2390 HeapFree( GetProcessHeap(), 0, newstr );
2391 return ret;
2393 else return ModifyMenu32A( hMenu, pos, flags, id, (LPCSTR)str );
2397 /**********************************************************************
2398 * CreatePopupMenu [USER.415]
2400 HMENU16 CreatePopupMenu()
2402 HMENU16 hmenu;
2403 POPUPMENU *menu;
2405 if (!(hmenu = CreateMenu())) return 0;
2406 menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu );
2407 menu->wFlags |= MF_POPUP;
2408 return hmenu;
2412 /**********************************************************************
2413 * GetMenuCheckMarkDimensions [USER.417]
2415 DWORD GetMenuCheckMarkDimensions()
2417 return MAKELONG( check_bitmap_width, check_bitmap_height );
2421 /**********************************************************************
2422 * SetMenuItemBitmaps [USER.418]
2424 BOOL SetMenuItemBitmaps(HMENU16 hMenu, UINT nPos, UINT wFlags,
2425 HBITMAP16 hNewUnCheck, HBITMAP16 hNewCheck)
2427 MENUITEM *item;
2428 dprintf_menu(stddeb,"SetMenuItemBitmaps(%04x, %04x, %04x, %04x, %04x)\n",
2429 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
2430 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
2432 if (!hNewCheck && !hNewUnCheck)
2434 /* If both are NULL, restore default bitmaps */
2435 item->hCheckBit = hStdCheck;
2436 item->hUnCheckBit = 0;
2437 item->item_flags &= ~MF_USECHECKBITMAPS;
2439 else /* Install new bitmaps */
2441 item->hCheckBit = hNewCheck;
2442 item->hUnCheckBit = hNewUnCheck;
2443 item->item_flags |= MF_USECHECKBITMAPS;
2445 return TRUE;
2449 /**********************************************************************
2450 * CreateMenu [USER.151]
2452 HMENU16 CreateMenu()
2454 HMENU16 hMenu;
2455 LPPOPUPMENU menu;
2456 dprintf_menu(stddeb,"CreateMenu !\n");
2457 if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) )))
2458 return 0;
2459 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
2460 menu->wFlags = 0;
2461 menu->wMagic = MENU_MAGIC;
2462 menu->hTaskQ = 0;
2463 menu->Width = 0;
2464 menu->Height = 0;
2465 menu->nItems = 0;
2466 menu->hWnd = 0;
2467 menu->items = NULL;
2468 menu->FocusedItem = NO_SELECTED_ITEM;
2469 dprintf_menu(stddeb,"CreateMenu // return %04x\n", hMenu);
2470 return hMenu;
2474 /**********************************************************************
2475 * DestroyMenu [USER.152]
2477 BOOL DestroyMenu(HMENU16 hMenu)
2479 LPPOPUPMENU lppop;
2480 dprintf_menu(stddeb,"DestroyMenu (%04x) !\n", hMenu);
2482 if (hMenu == 0) return FALSE;
2483 /* Silently ignore attempts to destroy default system menu */
2484 if (hMenu == MENU_DefSysMenu) return TRUE;
2485 lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
2486 if (!lppop || (lppop->wMagic != MENU_MAGIC)) return FALSE;
2487 lppop->wMagic = 0; /* Mark it as destroyed */
2488 if ((lppop->wFlags & MF_POPUP) && lppop->hWnd && (!pTopPWnd || (lppop->hWnd != pTopPWnd->hwndSelf)))
2489 DestroyWindow( lppop->hWnd );
2491 if (lppop->items)
2493 int i;
2494 MENUITEM *item = lppop->items;
2495 for (i = lppop->nItems; i > 0; i--, item++)
2497 if (item->item_flags & MF_POPUP)
2498 DestroyMenu( (HMENU16)item->item_id );
2499 if (IS_STRING_ITEM(item->item_flags) && item->text)
2500 HeapFree( SystemHeap, 0, item->text );
2502 HeapFree( SystemHeap, 0, lppop->items );
2504 USER_HEAP_FREE( hMenu );
2505 dprintf_menu(stddeb,"DestroyMenu (%04x) // End !\n", hMenu);
2506 return TRUE;
2509 /**********************************************************************
2510 * GetSystemMenu [USER.156]
2512 HMENU16 GetSystemMenu(HWND hWnd, BOOL bRevert)
2514 WND *wndPtr = WIN_FindWndPtr( hWnd );
2515 if (!wndPtr) return 0;
2517 if (!wndPtr->hSysMenu || (wndPtr->hSysMenu == MENU_DefSysMenu))
2519 wndPtr->hSysMenu = MENU_CopySysMenu();
2520 return wndPtr->hSysMenu;
2522 if (!bRevert) return wndPtr->hSysMenu;
2523 if (wndPtr->hSysMenu) DestroyMenu(wndPtr->hSysMenu);
2524 wndPtr->hSysMenu = MENU_CopySysMenu();
2525 return wndPtr->hSysMenu;
2529 /*******************************************************************
2530 * SetSystemMenu (USER.280)
2532 BOOL SetSystemMenu( HWND hwnd, HMENU16 hMenu )
2534 WND *wndPtr;
2536 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
2537 if (wndPtr->hSysMenu && (wndPtr->hSysMenu != MENU_DefSysMenu))
2538 DestroyMenu( wndPtr->hSysMenu );
2539 wndPtr->hSysMenu = hMenu;
2540 return TRUE;
2544 /**********************************************************************
2545 * GetMenu [USER.157]
2547 HMENU16 GetMenu(HWND hWnd)
2549 WND * wndPtr = WIN_FindWndPtr(hWnd);
2550 if (wndPtr == NULL) return 0;
2551 return (HMENU16)wndPtr->wIDmenu;
2555 /**********************************************************************
2556 * SetMenu [USER.158]
2558 BOOL SetMenu(HWND hWnd, HMENU16 hMenu)
2560 LPPOPUPMENU lpmenu;
2561 WND * wndPtr = WIN_FindWndPtr(hWnd);
2562 if (wndPtr == NULL) {
2563 fprintf(stderr,"SetMenu(%04x, %04x) // Bad window handle !\n",
2564 hWnd, hMenu);
2565 return FALSE;
2567 dprintf_menu(stddeb,"SetMenu(%04x, %04x);\n", hWnd, hMenu);
2568 if (GetCapture32() == hWnd) ReleaseCapture();
2569 wndPtr->wIDmenu = (UINT)hMenu;
2570 if (hMenu != 0)
2572 lpmenu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
2573 if (lpmenu == NULL) {
2574 fprintf(stderr,"SetMenu(%04x, %04x) // Bad menu handle !\n",
2575 hWnd, hMenu);
2576 return FALSE;
2578 lpmenu->hWnd = hWnd;
2579 lpmenu->wFlags &= ~MF_POPUP; /* Can't be a popup */
2580 lpmenu->Height = 0; /* Make sure we recalculate the size */
2582 if (IsWindowVisible(hWnd))
2583 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
2584 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
2585 return TRUE;
2590 /**********************************************************************
2591 * GetSubMenu [USER.159]
2593 HMENU16 GetSubMenu(HMENU16 hMenu, short nPos)
2595 LPPOPUPMENU lppop;
2597 dprintf_menu(stddeb,"GetSubMenu (%04x, %04X) !\n", hMenu, nPos);
2598 if (!(lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return 0;
2599 if ((UINT)nPos >= lppop->nItems) return 0;
2600 if (!(lppop->items[nPos].item_flags & MF_POPUP)) return 0;
2601 return (HMENU16)lppop->items[nPos].item_id;
2605 /**********************************************************************
2606 * DrawMenuBar [USER.160]
2608 void DrawMenuBar(HWND hWnd)
2610 WND *wndPtr;
2611 LPPOPUPMENU lppop;
2612 dprintf_menu(stddeb,"DrawMenuBar (%04x)\n", hWnd);
2613 wndPtr = WIN_FindWndPtr(hWnd);
2614 if (wndPtr != NULL && (wndPtr->dwStyle & WS_CHILD) == 0 &&
2615 wndPtr->wIDmenu != 0) {
2616 dprintf_menu(stddeb,"DrawMenuBar wIDmenu=%04X \n",
2617 wndPtr->wIDmenu);
2618 lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR((HMENU16)wndPtr->wIDmenu);
2619 if (lppop == NULL) return;
2621 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
2622 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
2623 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
2628 /***********************************************************************
2629 * EndMenu (USER.187)
2631 void EndMenu(void)
2633 /* FIXME: this won't work when we have multiple tasks... */
2634 fEndMenuCalled = TRUE;
2638 /***********************************************************************
2639 * LookupMenuHandle (USER.217)
2641 HMENU16 LookupMenuHandle( HMENU16 hmenu, INT id )
2643 if (!MENU_FindItem( &hmenu, &id, MF_BYCOMMAND )) return 0;
2644 else return hmenu;
2648 /**********************************************************************
2649 * LoadMenu (USER.150)
2651 HMENU16 LoadMenu16( HINSTANCE16 instance, SEGPTR name )
2653 HRSRC16 hRsrc;
2654 HGLOBAL16 handle;
2655 HMENU16 hMenu;
2657 if (HIWORD(name))
2659 char *str = (char *)PTR_SEG_TO_LIN( name );
2660 dprintf_menu( stddeb, "LoadMenu(%04x,'%s')\n", instance, str );
2661 if (str[0] == '#') name = (SEGPTR)atoi( str + 1 );
2663 else
2664 dprintf_resource(stddeb,"LoadMenu(%04x,%04x)\n",instance,LOWORD(name));
2666 if (!name) return 0;
2668 /* check for Win32 module */
2669 instance = GetExePtr( instance );
2670 if (MODULE_GetPtr(instance)->flags & NE_FFLAGS_WIN32)
2671 return LoadMenu32A(instance,PTR_SEG_TO_LIN(name));
2673 if (!(hRsrc = FindResource16( instance, name, RT_MENU ))) return 0;
2674 if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
2675 hMenu = LoadMenuIndirect16(LockResource16(handle));
2676 FreeResource16( handle );
2677 return hMenu;
2681 /*****************************************************************
2682 * LoadMenu32A (USER32.370)
2684 HMENU32 LoadMenu32A( HINSTANCE32 instance, LPCSTR name )
2686 HRSRC32 hrsrc = FindResource32A( instance, name, (LPSTR)RT_MENU );
2687 if (!hrsrc) return 0;
2688 return LoadMenuIndirect32A( (LPCVOID)LoadResource32( instance, hrsrc ));
2692 /*****************************************************************
2693 * LoadMenu32W (USER32.372)
2695 HMENU32 LoadMenu32W( HINSTANCE32 instance, LPCWSTR name )
2697 HRSRC32 hrsrc = FindResource32W( instance, name, (LPWSTR)RT_MENU );
2698 if (!hrsrc) return 0;
2699 return LoadMenuIndirect32W( (LPCVOID)LoadResource32( instance, hrsrc ));
2703 /**********************************************************************
2704 * LoadMenuIndirect16 (USER.220)
2706 HMENU16 LoadMenuIndirect16( LPCVOID template )
2708 HMENU16 hMenu;
2709 WORD version, offset;
2710 LPCSTR p = (LPCSTR)template;
2712 dprintf_menu(stddeb,"LoadMenuIndirect32A: %p\n", template );
2713 version = GET_WORD(p);
2714 p += sizeof(WORD);
2715 if (version)
2717 fprintf( stderr, "LoadMenuIndirect16: version must be 0 for Win16\n" );
2718 return 0;
2720 offset = GET_WORD(p);
2721 p += sizeof(WORD) + offset;
2722 if (!(hMenu = CreateMenu())) return 0;
2723 if (!MENU_ParseResource( p, hMenu, FALSE ))
2725 DestroyMenu( hMenu );
2726 return 0;
2728 return hMenu;
2732 /**********************************************************************
2733 * LoadMenuIndirect32A (USER32.370)
2735 HMENU32 LoadMenuIndirect32A( LPCVOID template )
2737 HMENU16 hMenu;
2738 WORD version, offset;
2739 LPCSTR p = (LPCSTR)template;
2741 dprintf_menu(stddeb,"LoadMenuIndirect32A: %p\n", template );
2742 version = GET_WORD(p);
2743 p += sizeof(WORD);
2744 if (version)
2746 fprintf( stderr, "LoadMenuIndirect32A: version %d not supported.\n",
2747 version );
2748 return 0;
2750 offset = GET_WORD(p);
2751 p += sizeof(WORD) + offset;
2752 if (!(hMenu = CreateMenu())) return 0;
2753 if (!MENU_ParseResource( p, hMenu, TRUE ))
2755 DestroyMenu( hMenu );
2756 return 0;
2758 return hMenu;
2762 /**********************************************************************
2763 * LoadMenuIndirect32W (USER32.371)
2765 HMENU32 LoadMenuIndirect32W( LPCVOID template )
2767 /* FIXME: is there anything different between A and W? */
2768 return LoadMenuIndirect32A( template );
2772 /**********************************************************************
2773 * IsMenu (USER.358)
2775 BOOL IsMenu( HMENU16 hmenu )
2777 LPPOPUPMENU menu;
2778 if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
2779 return (menu->wMagic == MENU_MAGIC);