4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
6 * Copyright 1997 Morten Welinder
10 * Note: the style MF_MOUSESELECT is used to mark popup items that
11 * have been selected, i.e. their popup menu is currently displayed.
12 * This is probably not the meaning this style has in MS-Windows.
21 #include "wine/winbase16.h"
22 #include "wine/winuser16.h"
23 #include "sysmetrics.h"
27 #include "nonclient.h"
36 /* internal popup menu window messages */
38 #define MM_SETMENUHANDLE (WM_USER + 0)
39 #define MM_GETMENUHANDLE (WM_USER + 1)
41 /* Menu item structure */
43 /* ----------- MENUITEMINFO Stuff ----------- */
44 UINT fType
; /* Item type. */
45 UINT fState
; /* Item state. */
46 UINT wID
; /* Item id. */
47 HMENU hSubMenu
; /* Pop-up menu. */
48 HBITMAP hCheckBit
; /* Bitmap when checked. */
49 HBITMAP hUnCheckBit
; /* Bitmap when unchecked. */
50 LPSTR text
; /* Item text or bitmap handle. */
51 DWORD dwItemData
; /* Application defined. */
52 DWORD dwTypeData
; /* depends on fMask */
53 HBITMAP hbmpItem
; /* bitmap in win98 style menus */
54 /* ----------- Wine stuff ----------- */
55 RECT rect
; /* Item area (relative to menu window) */
56 UINT xTab
; /* X position of text after Tab */
59 /* Popup menu structure */
61 WORD wFlags
; /* Menu flags (MF_POPUP, MF_SYSMENU) */
62 WORD wMagic
; /* Magic number */
63 HQUEUE16 hTaskQ
; /* Task queue for this menu */
64 WORD Width
; /* Width of the whole menu */
65 WORD Height
; /* Height of the whole menu */
66 WORD nItems
; /* Number of items in the menu */
67 HWND hWnd
; /* Window containing the menu */
68 MENUITEM
*items
; /* Array of menu items */
69 UINT FocusedItem
; /* Currently focused item */
70 WORD defitem
; /* default item position. Unused (except for set/get)*/
71 HWND hwndOwner
; /* window receiving the messages for ownerdraw */
72 /* ------------ MENUINFO members ------ */
73 DWORD dwStyle
; /* Extended mennu style */
74 UINT cyMax
; /* max hight of the whole menu, 0 is screen hight */
75 HBRUSH hbrBack
; /* brush for menu background */
76 DWORD dwContextHelpID
;
77 DWORD dwMenuData
; /* application defined value */
78 } POPUPMENU
, *LPPOPUPMENU
;
80 /* internal flags for menu tracking */
82 #define TF_ENDMENU 0x0001
83 #define TF_SUSPENDPOPUP 0x0002
84 #define TF_SKIPREMOVE 0x0004
89 HMENU hCurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
90 HMENU hTopMenu
; /* initial menu */
91 HWND hOwnerWnd
; /* where notifications are sent */
95 #define MENU_MAGIC 0x554d /* 'MU' */
96 #define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
101 /* Internal MENU_TrackMenu() flags */
102 #define TPM_INTERNAL 0xF0000000
103 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
104 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
105 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
107 /* popup menu shade thickness */
108 #define POPUP_XSHADE 4
109 #define POPUP_YSHADE 4
111 /* Space between 2 menu bar items */
112 #define MENU_BAR_ITEMS_SPACE 12
114 /* Minimum width of a tab character */
115 #define MENU_TAB_SPACE 8
117 /* Height of a separator item */
118 #define SEPARATOR_HEIGHT 5
120 /* (other menu->FocusedItem values give the position of the focused item) */
121 #define NO_SELECTED_ITEM 0xffff
123 #define MENU_ITEM_TYPE(flags) \
124 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
126 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
127 #define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
129 #define IS_SYSTEM_MENU(menu) \
130 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
132 #define IS_SYSTEM_POPUP(menu) \
133 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
135 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
136 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
137 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
138 MF_POPUP | MF_SYSMENU | MF_HELP)
139 #define STATE_MASK (~TYPE_MASK)
141 /* Dimension of the menu bitmaps */
142 static WORD check_bitmap_width
= 0, check_bitmap_height
= 0;
143 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
145 static HBITMAP hStdRadioCheck
= 0;
146 static HBITMAP hStdCheck
= 0;
147 static HBITMAP hStdMnArrow
= 0;
149 // Minimze/restore/close buttons to be inserted in menubar
150 static HBITMAP hBmpMinimize
= 0;
151 static HBITMAP hBmpMinimizeD
= 0;
152 static HBITMAP hBmpMaximize
= 0;
153 static HBITMAP hBmpMaximizeD
= 0;
154 static HBITMAP hBmpClose
= 0;
155 static HBITMAP hBmpCloseD
= 0;
158 static HBRUSH hShadeBrush
= 0;
159 static HFONT hMenuFont
= 0;
161 static HMENU MENU_DefSysPopup
= 0; /* Default system menu popup */
163 /* Use global popup window because there's no way 2 menus can
164 * be tracked at the same time. */
166 static WND
* pTopPopupWnd
= 0;
167 static UINT uSubPWndLevel
= 0;
169 /* Flag set by EndMenu() to force an exit from menu tracking */
170 static BOOL fEndMenu
= FALSE
;
173 /***********************************************************************
174 * debug_print_menuitem
176 * Print a menuitem in readable form.
179 #define debug_print_menuitem(pre, mp, post) \
180 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
182 #define MENUOUT(text) \
183 dsprintf(menu, "%s%s", (count++ ? "," : ""), (text))
185 #define MENUFLAG(bit,text) \
187 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
190 static void do_debug_print_menuitem(const char *prefix
, MENUITEM
* mp
,
193 dbg_decl_str(menu
, 256);
196 UINT flags
= mp
->fType
;
197 int typ
= MENU_ITEM_TYPE(flags
);
198 dsprintf(menu
, "{ ID=0x%x", mp
->wID
);
199 if (flags
& MF_POPUP
)
200 dsprintf(menu
, ", Sub=0x%x", mp
->hSubMenu
);
203 dsprintf(menu
, ", Typ=");
204 if (typ
== MFT_STRING
)
206 else if (typ
== MFT_SEPARATOR
)
208 else if (typ
== MFT_OWNERDRAW
)
210 else if (typ
== MFT_BITMAP
)
216 MENUFLAG(MF_POPUP
, "pop");
217 MENUFLAG(MFT_MENUBARBREAK
, "barbrk");
218 MENUFLAG(MFT_MENUBREAK
, "brk");
219 MENUFLAG(MFT_RADIOCHECK
, "radio");
220 MENUFLAG(MFT_RIGHTORDER
, "rorder");
221 MENUFLAG(MF_SYSMENU
, "sys");
222 MENUFLAG(MFT_RIGHTJUSTIFY
, "right");
225 dsprintf(menu
, "+0x%x", flags
);
230 dsprintf(menu
, ", State=");
231 MENUFLAG(MFS_GRAYED
, "grey");
232 MENUFLAG(MFS_DISABLED
, "dis");
233 MENUFLAG(MFS_CHECKED
, "check");
234 MENUFLAG(MFS_HILITE
, "hi");
235 MENUFLAG(MF_USECHECKBITMAPS
, "usebit");
236 MENUFLAG(MF_MOUSESELECT
, "mouse");
238 dsprintf(menu
, "+0x%x", flags
);
241 dsprintf(menu
, ", Chk=0x%x", mp
->hCheckBit
);
243 dsprintf(menu
, ", Unc=0x%x", mp
->hUnCheckBit
);
245 if (typ
== MFT_STRING
) {
247 dsprintf(menu
, ", Text=\"%s\"", mp
->text
);
249 dsprintf(menu
, ", Text=Null");
250 } else if (mp
->text
== NULL
)
253 dsprintf(menu
, ", Text=%p", mp
->text
);
255 dsprintf(menu
, ", ItemData=0x%08lx", mp
->dwItemData
);
256 dsprintf(menu
, " }");
258 dsprintf(menu
, "NULL");
261 TRACE(menu
, "%s %s %s\n", prefix
, dbg_str(menu
), postfix
);
267 /***********************************************************************
270 * Return the default system menu.
272 static HMENU
MENU_CopySysPopup(void)
274 HMENU hMenu
= LoadMenuIndirectA(SYSRES_GetResPtr(SYSRES_MENU_SYSMENU
));
277 POPUPMENU
* menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
278 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
282 ERR(menu
, "Unable to load default system menu\n" );
285 TRACE(menu
, "returning %x.\n", hMenu
);
290 /***********************************************************************
291 * MENU_GetTopPopupWnd()
293 * Return the locked pointer pTopPopupWnd.
295 WND
*MENU_GetTopPopupWnd()
297 return WIN_LockWndPtr(pTopPopupWnd
);
299 /***********************************************************************
300 * MENU_ReleaseTopPopupWnd()
302 * Realease the locked pointer pTopPopupWnd.
304 void MENU_ReleaseTopPopupWnd()
306 WIN_ReleaseWndPtr(pTopPopupWnd
);
308 /***********************************************************************
309 * MENU_DestroyTopPopupWnd()
311 * Destroy the locked pointer pTopPopupWnd.
313 void MENU_DestroyTopPopupWnd()
315 WND
*tmpWnd
= pTopPopupWnd
;
317 WIN_ReleaseWndPtr(tmpWnd
);
322 /**********************************************************************
325 * Create a copy of the system menu. System menu in Windows is
326 * a special menu-bar with the single entry - system menu popup.
327 * This popup is presented to the outside world as a "system menu".
328 * However, the real system menu handle is sometimes seen in the
329 * WM_MENUSELECT paramemters (and Word 6 likes it this way).
331 HMENU
MENU_GetSysMenu( HWND hWnd
, HMENU hPopupMenu
)
335 if ((hMenu
= CreateMenu()))
337 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
338 menu
->wFlags
= MF_SYSMENU
;
341 if (hPopupMenu
== (HMENU
)(-1))
342 hPopupMenu
= MENU_CopySysPopup();
343 else if( !hPopupMenu
) hPopupMenu
= MENU_DefSysPopup
;
347 InsertMenuA( hMenu
, -1, MF_SYSMENU
| MF_POPUP
| MF_BYPOSITION
, hPopupMenu
, NULL
);
349 menu
->items
[0].fType
= MF_SYSMENU
| MF_POPUP
;
350 menu
->items
[0].fState
= 0;
351 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hPopupMenu
);
352 menu
->wFlags
|= MF_SYSMENU
;
354 TRACE(menu
,"GetSysMenu hMenu=%04x (%04x)\n", hMenu
, hPopupMenu
);
357 DestroyMenu( hMenu
);
359 ERR(menu
, "failed to load system menu!\n");
364 /***********************************************************************
367 * Menus initialisation.
372 NONCLIENTMETRICSA ncm
;
374 static unsigned char shade_bits
[16] = { 0x55, 0, 0xAA, 0,
379 /* Load menu bitmaps */
380 hStdCheck
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CHECK
));
381 hStdRadioCheck
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_RADIOCHECK
));
382 hStdMnArrow
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW
));
383 /* Load system buttons bitmaps */
384 hBmpMinimize
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCE
));
385 hBmpMinimizeD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCED
));
386 hBmpMaximize
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORE
));
387 hBmpMaximizeD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORED
));
388 hBmpClose
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSE
));
389 hBmpCloseD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSED
));
394 GetObjectA( hStdCheck
, sizeof(bm
), &bm
);
395 check_bitmap_width
= bm
.bmWidth
;
396 check_bitmap_height
= bm
.bmHeight
;
400 /* Assume that radio checks have the same size as regular check. */
407 GetObjectA( hStdMnArrow
, sizeof(bm
), &bm
);
408 arrow_bitmap_width
= bm
.bmWidth
;
409 arrow_bitmap_height
= bm
.bmHeight
;
413 if (! (hBitmap
= CreateBitmap( 8, 8, 1, 1, shade_bits
)))
416 if(!(hShadeBrush
= CreatePatternBrush( hBitmap
)))
419 DeleteObject( hBitmap
);
420 if (!(MENU_DefSysPopup
= MENU_CopySysPopup()))
423 ncm
.cbSize
= sizeof (NONCLIENTMETRICSA
);
424 if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS
, sizeof(NONCLIENTMETRICSA
), &ncm
, 0)))
427 if (!(hMenuFont
= CreateFontIndirectA( &ncm
.lfMenuFont
)))
433 /***********************************************************************
434 * MENU_InitSysMenuPopup
436 * Grey the appropriate items in System menu.
438 static void MENU_InitSysMenuPopup( HMENU hmenu
, DWORD style
, DWORD clsStyle
)
442 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
443 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
444 gray
= ((style
& WS_MAXIMIZE
) != 0);
445 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
446 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
447 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
448 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
449 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
450 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
451 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
452 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
453 EnableMenuItem( hmenu
, SC_CLOSE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
457 /******************************************************************************
459 * UINT32 MENU_GetStartOfNextColumn(
462 *****************************************************************************/
464 static UINT
MENU_GetStartOfNextColumn(
467 POPUPMENU
*menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
468 UINT i
= menu
->FocusedItem
+ 1;
471 return NO_SELECTED_ITEM
;
473 if( i
== NO_SELECTED_ITEM
)
476 for( ; i
< menu
->nItems
; ++i
) {
477 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
481 return NO_SELECTED_ITEM
;
485 /******************************************************************************
487 * UINT32 MENU_GetStartOfPrevColumn(
490 *****************************************************************************/
492 static UINT
MENU_GetStartOfPrevColumn(
495 POPUPMENU
const *menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
499 return NO_SELECTED_ITEM
;
501 if( menu
->FocusedItem
== 0 || menu
->FocusedItem
== NO_SELECTED_ITEM
)
502 return NO_SELECTED_ITEM
;
504 /* Find the start of the column */
506 for(i
= menu
->FocusedItem
; i
!= 0 &&
507 !(menu
->items
[i
].fType
& MF_MENUBARBREAK
);
511 return NO_SELECTED_ITEM
;
513 for(--i
; i
!= 0; --i
) {
514 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
518 TRACE(menu
, "ret %d.\n", i
);
525 /***********************************************************************
528 * Find a menu item. Return a pointer on the item, and modifies *hmenu
529 * in case the item was in a sub-menu.
531 static MENUITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
536 if (((*hmenu
)==0xffff) || (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(*hmenu
)))) return NULL
;
537 if (wFlags
& MF_BYPOSITION
)
539 if (*nPos
>= menu
->nItems
) return NULL
;
540 return &menu
->items
[*nPos
];
544 MENUITEM
*item
= menu
->items
;
545 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
547 if (item
->wID
== *nPos
)
552 else if (item
->fType
& MF_POPUP
)
554 HMENU hsubmenu
= item
->hSubMenu
;
555 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
567 /***********************************************************************
570 static void MENU_FreeItemData( MENUITEM
* item
)
573 if (IS_STRING_ITEM(item
->fType
) && item
->text
)
574 HeapFree( SystemHeap
, 0, item
->text
);
577 /***********************************************************************
578 * MENU_FindItemByCoords
580 * Find the item at the specified coordinates (screen coords). Does
581 * not work for child windows and therefore should not be called for
582 * an arbitrary system menu.
584 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
,
585 POINT pt
, UINT
*pos
)
591 if (!GetWindowRect(menu
->hWnd
,&wrect
)) return NULL
;
592 pt
.x
-= wrect
.left
;pt
.y
-= wrect
.top
;
594 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
596 if ((pt
.x
>= item
->rect
.left
) && (pt
.x
< item
->rect
.right
) &&
597 (pt
.y
>= item
->rect
.top
) && (pt
.y
< item
->rect
.bottom
))
607 /***********************************************************************
610 * Find the menu item selected by a key press.
611 * Return item id, -1 if none, -2 if we should close the menu.
613 static UINT
MENU_FindItemByKey( HWND hwndOwner
, HMENU hmenu
,
614 UINT key
, BOOL forceMenuChar
)
616 TRACE(menu
,"\tlooking for '%c' in [%04x]\n", (char)key
, (UINT16
)hmenu
);
618 if (!IsMenu( hmenu
))
620 WND
* w
= WIN_FindWndPtr(hwndOwner
);
621 hmenu
= GetSubMenu(w
->hSysMenu
, 0);
622 WIN_ReleaseWndPtr(w
);
627 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
628 MENUITEM
*item
= menu
->items
;
636 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
638 if (item
->text
&& (IS_STRING_ITEM(item
->fType
)))
640 char *p
= item
->text
- 2;
643 p
= strchr (p
+ 2, '&');
645 while (p
!= NULL
&& p
[1] == '&');
646 if (p
&& (toupper(p
[1]) == key
)) return i
;
650 menuchar
= SendMessageA( hwndOwner
, WM_MENUCHAR
,
651 MAKEWPARAM( key
, menu
->wFlags
), hmenu
);
652 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
653 if (HIWORD(menuchar
) == 1) return (UINT
)(-2);
657 /***********************************************************************
660 * Load the bitmap associated with the magic menu item and its style
663 static HBITMAP
MENU_LoadMagicItem(UINT id
, BOOL hilite
, DWORD dwItemData
)
665 // Magic menu item id's section
666 // These magic id's are used by windows to insert "standard" mdi
667 // buttons (minimize,restore,close) on menu. Under windows,
668 // these magic id's make sure the right things appear when those
669 // bitmap buttons are pressed/selected/released.
672 { case HBMMENU_SYSTEM
:
673 return (dwItemData
) ?
674 (HBITMAP
)dwItemData
:
675 (hilite
? hBmpMinimizeD
: hBmpMinimize
);
676 case HBMMENU_MBAR_RESTORE
:
677 return (hilite
? hBmpMaximizeD
: hBmpMaximize
);
678 case HBMMENU_MBAR_MINIMIZE
:
679 return (hilite
? hBmpMinimizeD
: hBmpMinimize
);
680 case HBMMENU_MBAR_CLOSE
:
681 return (hilite
? hBmpCloseD
: hBmpClose
);
682 case HBMMENU_CALLBACK
:
683 case HBMMENU_MBAR_CLOSE_D
:
684 case HBMMENU_MBAR_MINIMIZE_D
:
685 case HBMMENU_POPUP_CLOSE
:
686 case HBMMENU_POPUP_RESTORE
:
687 case HBMMENU_POPUP_MAXIMIZE
:
688 case HBMMENU_POPUP_MINIMIZE
:
690 FIXME(menu
,"Magic 0x%08x not implemented\n", id
);
696 /***********************************************************************
699 * Calculate the size of the menu item and store it in lpitem->rect.
701 static void MENU_CalcItemSize( HDC hdc
, MENUITEM
*lpitem
, HWND hwndOwner
,
702 INT orgX
, INT orgY
, BOOL menuBar
)
706 TRACE(menu
, "dc=0x%04x owner=0x%04x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
707 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem
,
708 (menuBar
? " (MenuBar)" : ""));
710 SetRect( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
712 if (lpitem
->fType
& MF_OWNERDRAW
)
714 MEASUREITEMSTRUCT mis
;
715 mis
.CtlType
= ODT_MENU
;
717 mis
.itemID
= lpitem
->wID
;
718 mis
.itemData
= (DWORD
)lpitem
->dwItemData
;
721 SendMessageA( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
722 lpitem
->rect
.bottom
+= mis
.itemHeight
;
723 lpitem
->rect
.right
+= mis
.itemWidth
;
724 TRACE(menu
, "id=%04x size=%dx%d\n",
725 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
729 if (lpitem
->fType
& MF_SEPARATOR
)
731 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
737 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
738 if (lpitem
->fType
& MF_POPUP
)
739 lpitem
->rect
.right
+= arrow_bitmap_width
;
742 if (IS_BITMAP_ITEM(lpitem
->fType
))
747 // Check if there is a magic menu item associated with this item
748 if((LOWORD((int)lpitem
->text
))<12)
750 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
, (lpitem
->fType
& MF_HILITE
),
754 resBmp
= (HBITMAP
)lpitem
->text
;
756 if (GetObjectA(resBmp
, sizeof(bm
), &bm
))
758 lpitem
->rect
.right
+= bm
.bmWidth
;
759 lpitem
->rect
.bottom
+= bm
.bmHeight
;
765 /* If we get here, then it must be a text item */
766 if (IS_STRING_ITEM( lpitem
->fType
))
769 GetTextExtentPoint32A(hdc
, lpitem
->text
, strlen(lpitem
->text
), &size
);
771 lpitem
->rect
.right
+= size
.cx
;
772 if (TWEAK_WineLook
== WIN31_LOOK
)
773 lpitem
->rect
.bottom
+= MAX( size
.cy
, SYSMETRICS_CYMENU
);
775 lpitem
->rect
.bottom
+= MAX (size
.cy
, sysMetrics
[SM_CYMENU
]- 1);
780 lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
782 else if ((p
= strchr( lpitem
->text
, '\t' )) != NULL
)
784 /* Item contains a tab (only meaningful in popup menus) */
785 GetTextExtentPoint32A(hdc
, lpitem
->text
, (int)(p
- lpitem
->text
) , &size
);
786 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+ size
.cx
;
787 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
791 if (strchr( lpitem
->text
, '\b' ))
792 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
793 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
794 - arrow_bitmap_width
;
797 TRACE(menu
,"(%d,%d)-(%d,%d)\n", lpitem
->rect
.left
, lpitem
->rect
.top
, lpitem
->rect
.right
, lpitem
->rect
.bottom
);
801 /***********************************************************************
802 * MENU_PopupMenuCalcSize
804 * Calculate the size of a popup menu.
806 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND hwndOwner
)
811 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
813 lppop
->Width
= lppop
->Height
= 0;
814 if (lppop
->nItems
== 0) return;
817 SelectObject( hdc
, hMenuFont
);
820 maxX
= SYSMETRICS_CXBORDER
;
821 while (start
< lppop
->nItems
)
823 lpitem
= &lppop
->items
[start
];
825 orgY
= SYSMETRICS_CYBORDER
;
827 maxTab
= maxTabWidth
= 0;
829 /* Parse items until column break or end of menu */
830 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
833 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
835 if (TWEAK_WineLook
> WIN31_LOOK
)
838 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
840 if (lpitem
->fType
& MF_MENUBARBREAK
) orgX
++;
841 maxX
= MAX( maxX
, lpitem
->rect
.right
);
842 orgY
= lpitem
->rect
.bottom
;
843 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
845 maxTab
= MAX( maxTab
, lpitem
->xTab
);
846 maxTabWidth
= MAX(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
850 /* Finish the column (set all items to the largest width found) */
851 maxX
= MAX( maxX
, maxTab
+ maxTabWidth
);
852 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
854 lpitem
->rect
.right
= maxX
;
855 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
856 lpitem
->xTab
= maxTab
;
858 lppop
->Height
= MAX( lppop
->Height
, orgY
);
861 if(TWEAK_WineLook
> WIN31_LOOK
)
869 /***********************************************************************
870 * MENU_MenuBarCalcSize
872 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
873 * height is off by 1 pixel which causes lengthy window relocations when
874 * active document window is maximized/restored.
876 * Calculate the size of the menu bar.
878 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
,
879 LPPOPUPMENU lppop
, HWND hwndOwner
)
882 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
884 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
885 if (lppop
->nItems
== 0) return;
886 TRACE(menu
,"left=%d top=%d right=%d bottom=%d\n",
887 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
888 lppop
->Width
= lprect
->right
- lprect
->left
;
893 while (start
< lppop
->nItems
)
895 lpitem
= &lppop
->items
[start
];
899 /* Parse items until line break or end of menu */
900 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
902 if ((helpPos
== -1) && (lpitem
->fType
& MF_HELP
)) helpPos
= i
;
904 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
906 TRACE(menu
, "calling MENU_CalcItemSize org=(%d, %d)\n",
908 debug_print_menuitem (" item: ", lpitem
, "");
909 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
911 if (lpitem
->rect
.right
> lprect
->right
)
913 if (i
!= start
) break;
914 else lpitem
->rect
.right
= lprect
->right
;
916 maxY
= MAX( maxY
, lpitem
->rect
.bottom
);
917 orgX
= lpitem
->rect
.right
;
920 /* Finish the line (set all items to the largest height found) */
921 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
924 lprect
->bottom
= maxY
;
925 lppop
->Height
= lprect
->bottom
- lprect
->top
;
927 /* Flush right all items between the MF_HELP and the last item */
928 /* (if several lines, only move the last line) */
931 lpitem
= &lppop
->items
[lppop
->nItems
-1];
932 orgY
= lpitem
->rect
.top
;
933 orgX
= lprect
->right
;
934 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--)
936 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
937 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
938 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
939 lpitem
->rect
.right
= orgX
;
940 orgX
= lpitem
->rect
.left
;
945 /***********************************************************************
948 * Draw a single menu item.
950 static void MENU_DrawMenuItem( HWND hwnd
, HMENU hmenu
, HWND hwndOwner
, HDC hdc
, MENUITEM
*lpitem
,
951 UINT height
, BOOL menuBar
, UINT odaction
)
955 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem
, "");
957 if (lpitem
->fType
& MF_SYSMENU
)
959 if( !IsIconic(hwnd
) ) {
960 if (TWEAK_WineLook
> WIN31_LOOK
)
961 NC_DrawSysButton95( hwnd
, hdc
,
963 (MF_HILITE
| MF_MOUSESELECT
) );
965 NC_DrawSysButton( hwnd
, hdc
,
967 (MF_HILITE
| MF_MOUSESELECT
) );
973 if (lpitem
->fType
& MF_OWNERDRAW
)
977 dis
.CtlType
= ODT_MENU
;
979 dis
.itemID
= lpitem
->wID
;
980 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
982 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
983 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
;
984 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
985 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
986 dis
.hwndItem
= hmenu
;
988 dis
.rcItem
= lpitem
->rect
;
989 TRACE(menu
, "Ownerdraw: owner=%04x itemID=%d, itemState=%d, itemAction=%d, "
990 "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n", hwndOwner
,
991 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
992 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
994 SendMessageA( hwndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
998 TRACE(menu
, "rect={%d,%d,%d,%d}\n", lpitem
->rect
.left
, lpitem
->rect
.top
,
999 lpitem
->rect
.right
,lpitem
->rect
.bottom
);
1001 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1003 rect
= lpitem
->rect
;
1005 if ((lpitem
->fState
& MF_HILITE
) && !(IS_BITMAP_ITEM(lpitem
->fType
)))
1006 if ((menuBar
) && (TWEAK_WineLook
==WIN98_LOOK
))
1007 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1009 FillRect( hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
) );
1011 FillRect( hdc
, &rect
, GetSysColorBrush(COLOR_MENU
) );
1013 SetBkMode( hdc
, TRANSPARENT
);
1015 /* vertical separator */
1016 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1018 if (TWEAK_WineLook
> WIN31_LOOK
)
1022 rc
.bottom
= height
- 3;
1023 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1027 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1028 MoveTo16( hdc
, rect
.left
, 0 );
1029 LineTo( hdc
, rect
.left
, height
);
1033 /* horizontal separator */
1034 if (lpitem
->fType
& MF_SEPARATOR
)
1036 if (TWEAK_WineLook
> WIN31_LOOK
)
1041 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1042 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1046 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1047 MoveTo16( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
1048 LineTo( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
1055 if ((lpitem
->fState
& MF_HILITE
) && !(IS_BITMAP_ITEM(lpitem
->fType
)) )
1057 if (lpitem
->fState
& MF_GRAYED
)
1058 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1060 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
1061 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
1065 if (lpitem
->fState
& MF_GRAYED
)
1066 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1068 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1069 SetBkColor( hdc
, GetSysColor( COLOR_MENU
) );
1072 /* helper lines for debugging */
1073 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1074 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1075 MoveTo16( hdc, rect.left, (rect.top + rect.bottom)/2 );
1076 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1081 INT y
= rect
.top
+ rect
.bottom
;
1083 /* Draw the check mark
1086 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1089 if (lpitem
->fState
& MF_CHECKED
)
1091 HBITMAP bm
= lpitem
->hCheckBit
? lpitem
->hCheckBit
:
1092 ((lpitem
->fType
& MFT_RADIOCHECK
) ? hStdRadioCheck
: hStdCheck
);
1093 HDC hdcMem
= CreateCompatibleDC( hdc
);
1095 SelectObject( hdcMem
, bm
);
1096 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1097 check_bitmap_width
, check_bitmap_height
,
1098 hdcMem
, 0, 0, SRCCOPY
);
1101 else if (lpitem
->hUnCheckBit
)
1103 HDC hdcMem
= CreateCompatibleDC( hdc
);
1105 SelectObject( hdcMem
, lpitem
->hUnCheckBit
);
1106 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1107 check_bitmap_width
, check_bitmap_height
,
1108 hdcMem
, 0, 0, SRCCOPY
);
1112 /* Draw the popup-menu arrow */
1113 if (lpitem
->fType
& MF_POPUP
)
1115 HDC hdcMem
= CreateCompatibleDC( hdc
);
1117 SelectObject( hdcMem
, hStdMnArrow
);
1118 BitBlt( hdc
, rect
.right
- arrow_bitmap_width
- 1,
1119 (y
- arrow_bitmap_height
) / 2,
1120 arrow_bitmap_width
, arrow_bitmap_height
,
1121 hdcMem
, 0, 0, SRCCOPY
);
1125 rect
.left
+= check_bitmap_width
;
1126 rect
.right
-= arrow_bitmap_width
;
1129 /* Draw the item text or bitmap */
1130 if (IS_BITMAP_ITEM(lpitem
->fType
))
1135 HDC hdcMem
= CreateCompatibleDC( hdc
);
1137 // Check if there is a magic menu item associated with this item
1138 // and load the appropriate bitmap
1139 if((LOWORD((int)lpitem
->text
)) < 12)
1141 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
, (lpitem
->fState
& MF_HILITE
),
1142 lpitem
->dwItemData
);
1145 resBmp
= (HBITMAP
)lpitem
->text
;
1150 GetObjectA( resBmp
, sizeof(bm
), &bm
);
1152 SelectObject(hdcMem
,resBmp
);
1154 /* handle fontsize > bitmap_height */
1155 top
= ((rect
.bottom
-rect
.top
)>bm
.bmHeight
) ?
1156 rect
.top
+(rect
.bottom
-rect
.top
-bm
.bmHeight
)/2 : rect
.top
;
1158 BitBlt( hdc
, rect
.left
, top
, rect
.right
- rect
.left
,
1159 rect
.bottom
- rect
.top
, hdcMem
, 0, 0, SRCCOPY
);
1166 /* No bitmap - process text if present */
1167 else if (IS_STRING_ITEM(lpitem
->fType
))
1170 UINT uFormat
= (menuBar
) ?
1171 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
1172 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1176 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1177 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1178 i
= strlen( lpitem
->text
);
1182 for (i
= 0; lpitem
->text
[i
]; i
++)
1183 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
1187 if((TWEAK_WineLook
== WIN31_LOOK
) || !(lpitem
->fState
& MF_GRAYED
))
1189 DrawTextA( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1192 { if (!(lpitem
->fState
& MF_HILITE
))
1198 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1199 DrawTextA( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1205 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1206 DrawTextA( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1209 if (lpitem
->text
[i
]) /* There's a tab or flush-right char */
1211 if (lpitem
->text
[i
] == '\t')
1213 rect
.left
= lpitem
->xTab
;
1214 DrawTextA( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1216 else DrawTextA( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1222 /***********************************************************************
1223 * MENU_DrawPopupMenu
1225 * Paint a popup menu.
1227 static void MENU_DrawPopupMenu( HWND hwnd
, HDC hdc
, HMENU hmenu
)
1229 HBRUSH hPrevBrush
= 0;
1232 TRACE(menu
,"wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd
, hdc
, hmenu
);
1234 GetClientRect( hwnd
, &rect
);
1236 if(TWEAK_WineLook
== WIN31_LOOK
)
1238 rect
.bottom
-= POPUP_YSHADE
* SYSMETRICS_CYBORDER
;
1239 rect
.right
-= POPUP_XSHADE
* SYSMETRICS_CXBORDER
;
1242 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1243 && (SelectObject( hdc
, hMenuFont
)))
1247 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1249 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1255 /* draw 3-d shade */
1256 if(TWEAK_WineLook
== WIN31_LOOK
) {
1257 SelectObject( hdc
, hShadeBrush
);
1258 SetBkMode( hdc
, TRANSPARENT
);
1259 ropPrev
= SetROP2( hdc
, R2_MASKPEN
);
1261 i
= rect
.right
; /* why SetBrushOrg() doesn't? */
1262 PatBlt( hdc
, i
& 0xfffffffe,
1263 rect
.top
+ POPUP_YSHADE
*SYSMETRICS_CYBORDER
,
1264 i
%2 + POPUP_XSHADE
*SYSMETRICS_CXBORDER
,
1265 rect
.bottom
- rect
.top
, 0x00a000c9 );
1267 PatBlt( hdc
, rect
.left
+ POPUP_XSHADE
*SYSMETRICS_CXBORDER
,
1268 i
& 0xfffffffe,rect
.right
- rect
.left
,
1269 i
%2 + POPUP_YSHADE
*SYSMETRICS_CYBORDER
, 0x00a000c9 );
1270 SelectObject( hdc
, hPrevPen
);
1271 SelectObject( hdc
, hPrevBrush
);
1272 SetROP2( hdc
, ropPrev
);
1275 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1277 /* draw menu items */
1279 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1280 if (menu
&& menu
->nItems
)
1285 for (u
= menu
->nItems
, item
= menu
->items
; u
> 0; u
--, item
++)
1286 MENU_DrawMenuItem( hwnd
, hmenu
, menu
->hwndOwner
, hdc
, item
,
1287 menu
->Height
, FALSE
, ODA_DRAWENTIRE
);
1292 SelectObject( hdc
, hPrevBrush
);
1297 /***********************************************************************
1300 * Paint a menu bar. Returns the height of the menu bar.
1301 * called from [windows/nonclient.c]
1303 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1310 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1312 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( (HMENU
)wndPtr
->wIDmenu
);
1313 if (lppop
== NULL
|| lprect
== NULL
)
1315 retvalue
= SYSMETRICS_CYMENU
;
1319 TRACE(menu
,"(%04x, %p, %p)\n", hDC
, lprect
, lppop
);
1321 hfontOld
= SelectObject( hDC
, hMenuFont
);
1323 if (lppop
->Height
== 0)
1324 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
1326 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
1330 retvalue
= lppop
->Height
;
1334 FillRect(hDC
, lprect
, GetSysColorBrush(COLOR_MENU
) );
1336 if (TWEAK_WineLook
== WIN31_LOOK
)
1338 SelectObject( hDC
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1339 MoveTo16( hDC
, lprect
->left
, lprect
->bottom
);
1340 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1344 SelectObject( hDC
, GetSysColorPen(COLOR_3DFACE
));
1345 MoveTo16( hDC
, lprect
->left
, lprect
->bottom
);
1346 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1349 if (lppop
->nItems
== 0)
1351 retvalue
= SYSMETRICS_CYMENU
;
1355 for (i
= 0; i
< lppop
->nItems
; i
++)
1357 MENU_DrawMenuItem( hwnd
, (HMENU
)wndPtr
->wIDmenu
, GetWindow(hwnd
,GW_OWNER
),
1358 hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
, ODA_DRAWENTIRE
);
1360 retvalue
= lppop
->Height
;
1364 SelectObject (hDC
, hfontOld
);
1366 WIN_ReleaseWndPtr(wndPtr
);
1370 /***********************************************************************
1371 * MENU_PatchResidentPopup
1373 BOOL
MENU_PatchResidentPopup( HQUEUE16 checkQueue
, WND
* checkWnd
)
1375 WND
*pTPWnd
= MENU_GetTopPopupWnd();
1381 TRACE(menu
,"patching resident popup: %04x %04x [%04x %04x]\n",
1382 checkQueue
, checkWnd
? checkWnd
->hwndSelf
: 0, pTPWnd
->hmemTaskQ
,
1383 pTPWnd
->owner
? pTPWnd
->owner
->hwndSelf
: 0);
1385 switch( checkQueue
)
1387 case 0: /* checkWnd is the new popup owner */
1390 pTPWnd
->owner
= checkWnd
;
1391 if( pTPWnd
->hmemTaskQ
!= checkWnd
->hmemTaskQ
)
1392 hTask
= QUEUE_GetQueueTask( checkWnd
->hmemTaskQ
);
1396 case 0xFFFF: /* checkWnd is destroyed */
1397 if( pTPWnd
->owner
== checkWnd
)
1398 pTPWnd
->owner
= NULL
;
1399 MENU_ReleaseTopPopupWnd();
1402 default: /* checkQueue is exiting */
1403 if( pTPWnd
->hmemTaskQ
== checkQueue
)
1405 hTask
= QUEUE_GetQueueTask( pTPWnd
->hmemTaskQ
);
1406 hTask
= TASK_GetNextTask( hTask
);
1413 TDB
* task
= (TDB
*)GlobalLock16( hTask
);
1416 pTPWnd
->hInstance
= task
->hInstance
;
1417 pTPWnd
->hmemTaskQ
= task
->hQueue
;
1418 MENU_ReleaseTopPopupWnd();
1421 else WARN(menu
,"failed to patch resident popup.\n");
1424 MENU_ReleaseTopPopupWnd();
1428 /***********************************************************************
1431 * Display a popup menu.
1433 static BOOL
MENU_ShowPopup( HWND hwndOwner
, HMENU hmenu
, UINT id
,
1434 INT x
, INT y
, INT xanchor
, INT yanchor
)
1437 WND
*wndOwner
= NULL
;
1439 TRACE(menu
,"owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1440 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1442 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
1443 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1445 menu
->items
[menu
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1446 menu
->FocusedItem
= NO_SELECTED_ITEM
;
1449 /* store the owner for DrawItem*/
1450 menu
->hwndOwner
= hwndOwner
;
1452 if( (wndOwner
= WIN_FindWndPtr( hwndOwner
)) )
1456 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
1458 /* adjust popup menu pos so that it fits within the desktop */
1460 width
= menu
->Width
+ SYSMETRICS_CXBORDER
;
1461 height
= menu
->Height
+ SYSMETRICS_CYBORDER
;
1463 if( x
+ width
> SYSMETRICS_CXSCREEN
)
1466 x
-= width
- xanchor
;
1467 if( x
+ width
> SYSMETRICS_CXSCREEN
)
1468 x
= SYSMETRICS_CXSCREEN
- width
;
1472 if( y
+ height
> SYSMETRICS_CYSCREEN
)
1475 y
-= height
+ yanchor
;
1476 if( y
+ height
> SYSMETRICS_CYSCREEN
)
1477 y
= SYSMETRICS_CYSCREEN
- height
;
1481 if( TWEAK_WineLook
== WIN31_LOOK
)
1483 width
+= POPUP_XSHADE
* SYSMETRICS_CXBORDER
; /* add space for shading */
1484 height
+= POPUP_YSHADE
* SYSMETRICS_CYBORDER
;
1487 /* NOTE: In Windows, top menu popup is not owned. */
1488 if (!pTopPopupWnd
) /* create top level popup menu window */
1490 assert( uSubPWndLevel
== 0 );
1492 pTopPopupWnd
= WIN_FindWndPtr(CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1493 WS_POPUP
, x
, y
, width
, height
,
1494 hwndOwner
, 0, wndOwner
->hInstance
,
1498 WIN_ReleaseWndPtr(wndOwner
);
1501 menu
->hWnd
= pTopPopupWnd
->hwndSelf
;
1502 MENU_ReleaseTopPopupWnd();
1507 /* create a new window for the submenu */
1509 menu
->hWnd
= CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1510 WS_POPUP
, x
, y
, width
, height
,
1511 hwndOwner
, 0, wndOwner
->hInstance
,
1515 WIN_ReleaseWndPtr(wndOwner
);
1519 else /* top level popup menu window already exists */
1521 WND
*pTPWnd
= MENU_GetTopPopupWnd();
1522 menu
->hWnd
= pTPWnd
->hwndSelf
;
1524 MENU_PatchResidentPopup( 0, wndOwner
);
1525 SendMessageA( pTPWnd
->hwndSelf
, MM_SETMENUHANDLE
, (WPARAM16
)hmenu
, 0L);
1527 /* adjust its size */
1529 SetWindowPos( menu
->hWnd
, 0, x
, y
, width
, height
,
1530 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_NOREDRAW
);
1531 MENU_ReleaseTopPopupWnd();
1534 uSubPWndLevel
++; /* menu level counter */
1536 /* Display the window */
1538 SetWindowPos( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
1539 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1540 UpdateWindow( menu
->hWnd
);
1541 WIN_ReleaseWndPtr(wndOwner
);
1548 /***********************************************************************
1551 static void MENU_SelectItem( HWND hwndOwner
, HMENU hmenu
, UINT wIndex
,
1552 BOOL sendMenuSelect
)
1557 TRACE(menu
, "owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1559 lppop
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1560 if (!lppop
->nItems
) return;
1562 if ((wIndex
!= NO_SELECTED_ITEM
) &&
1563 (lppop
->items
[wIndex
].fType
& MF_SEPARATOR
))
1564 wIndex
= NO_SELECTED_ITEM
;
1566 if (lppop
->FocusedItem
== wIndex
) return;
1567 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC( lppop
->hWnd
);
1568 else hdc
= GetDCEx( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1570 SelectObject( hdc
, hMenuFont
);
1572 /* Clear previous highlighted item */
1573 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1575 lppop
->items
[lppop
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1576 MENU_DrawMenuItem(lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,&lppop
->items
[lppop
->FocusedItem
],
1577 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
),
1581 /* Highlight new item (if any) */
1582 lppop
->FocusedItem
= wIndex
;
1583 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1585 lppop
->items
[lppop
->FocusedItem
].fState
|= MF_HILITE
;
1586 MENU_DrawMenuItem( lppop
->hWnd
, hmenu
, hwndOwner
, hdc
, &lppop
->items
[lppop
->FocusedItem
],
1587 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
),
1591 MENUITEM
*ip
= &lppop
->items
[lppop
->FocusedItem
];
1592 SendMessageA( hwndOwner
, WM_MENUSELECT
,
1593 MAKELONG(ip
->wID
,ip
->fType
| (ip
->fState
| MF_MOUSESELECT
)), hmenu
);
1596 else if (sendMenuSelect
) {
1597 SendMessageA( hwndOwner
, WM_MENUSELECT
,
1598 MAKELONG( hmenu
, lppop
->wFlags
| MF_MOUSESELECT
), hmenu
);
1600 ReleaseDC( lppop
->hWnd
, hdc
);
1604 /***********************************************************************
1605 * MENU_MoveSelection
1607 * Moves currently selected item according to the offset parameter.
1608 * If there is no selection then it should select the last item if
1609 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1611 static void MENU_MoveSelection( HWND hwndOwner
, HMENU hmenu
, INT offset
)
1616 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1617 if (!menu
->items
) return;
1619 if ( menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1621 if( menu
->nItems
== 1 ) return; else
1622 for (i
= menu
->FocusedItem
+ offset
; i
>= 0 && i
< menu
->nItems
1624 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1626 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
1631 for ( i
= (offset
> 0) ? 0 : menu
->nItems
- 1;
1632 i
>= 0 && i
< menu
->nItems
; i
+= offset
)
1633 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1635 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
);
1641 /**********************************************************************
1644 * Set an item flags, id and text ptr. Called by InsertMenu() and
1647 static BOOL
MENU_SetItemData( MENUITEM
*item
, UINT flags
, UINT id
,
1650 LPSTR prevText
= IS_STRING_ITEM(item
->fType
) ? item
->text
: NULL
;
1652 debug_print_menuitem("MENU_SetItemData from: ", item
, "");
1654 if (IS_STRING_ITEM(flags
))
1658 flags
|= MF_SEPARATOR
;
1664 /* Item beginning with a backspace is a help item */
1670 if (!(text
= HEAP_strdupA( SystemHeap
, 0, str
))) return FALSE
;
1674 else if (IS_BITMAP_ITEM(flags
))
1675 item
->text
= (LPSTR
)(HBITMAP
)LOWORD(str
);
1676 else item
->text
= NULL
;
1678 if (flags
& MF_OWNERDRAW
)
1679 item
->dwItemData
= (DWORD
)str
;
1681 item
->dwItemData
= 0;
1683 if ((item
->fType
& MF_POPUP
) && (flags
& MF_POPUP
) && (item
->hSubMenu
!= id
) )
1684 DestroyMenu( item
->hSubMenu
); /* ModifyMenu() spec */
1686 if (flags
& MF_POPUP
)
1688 POPUPMENU
*menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR((UINT16
)id
);
1689 if (IS_A_MENU(menu
)) menu
->wFlags
|= MF_POPUP
;
1701 if (flags
& MF_POPUP
)
1702 item
->hSubMenu
= id
;
1704 if ((item
->fType
& MF_POPUP
) && !(flags
& MF_POPUP
) )
1705 flags
|= MF_POPUP
; /* keep popup */
1707 item
->fType
= flags
& TYPE_MASK
;
1708 item
->fState
= (flags
& STATE_MASK
) &
1709 ~(MF_HILITE
| MF_MOUSESELECT
| MF_BYPOSITION
);
1712 /* Don't call SetRectEmpty here! */
1715 if (prevText
) HeapFree( SystemHeap
, 0, prevText
);
1717 debug_print_menuitem("MENU_SetItemData to : ", item
, "");
1722 /**********************************************************************
1725 * Insert a new item into a menu.
1727 static MENUITEM
*MENU_InsertItem( HMENU hMenu
, UINT pos
, UINT flags
)
1732 if (!(menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
)))
1734 WARN(menu
, "%04x not a menu handle\n",
1739 /* Find where to insert new item */
1741 if ((flags
& MF_BYPOSITION
) &&
1742 ((pos
== (UINT
)-1) || (pos
== menu
->nItems
)))
1744 /* Special case: append to menu */
1745 /* Some programs specify the menu length to do that */
1750 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
1752 WARN(menu
, "item %x not found\n",
1756 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
)))
1758 WARN(menu
,"%04x not a menu handle\n",
1764 /* Create new items array */
1766 newItems
= HeapAlloc( SystemHeap
, 0, sizeof(MENUITEM
) * (menu
->nItems
+1) );
1769 WARN(menu
, "allocation failed\n" );
1772 if (menu
->nItems
> 0)
1774 /* Copy the old array into the new */
1775 if (pos
> 0) memcpy( newItems
, menu
->items
, pos
* sizeof(MENUITEM
) );
1776 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &menu
->items
[pos
],
1777 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
1778 HeapFree( SystemHeap
, 0, menu
->items
);
1780 menu
->items
= newItems
;
1782 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
1783 return &newItems
[pos
];
1787 /**********************************************************************
1788 * MENU_ParseResource
1790 * Parse a standard menu resource and add items to the menu.
1791 * Return a pointer to the end of the resource.
1793 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1800 flags
= GET_WORD(res
);
1801 res
+= sizeof(WORD
);
1802 if (!(flags
& MF_POPUP
))
1805 res
+= sizeof(WORD
);
1807 if (!IS_STRING_ITEM(flags
))
1808 ERR(menu
, "not a string item %04x\n", flags
);
1810 if (!unicode
) res
+= strlen(str
) + 1;
1811 else res
+= (lstrlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1812 if (flags
& MF_POPUP
)
1814 HMENU hSubMenu
= CreatePopupMenu();
1815 if (!hSubMenu
) return NULL
;
1816 if (!(res
= MENU_ParseResource( res
, hSubMenu
, unicode
)))
1818 if (!unicode
) AppendMenuA( hMenu
, flags
, (UINT
)hSubMenu
, str
);
1819 else AppendMenuW( hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1821 else /* Not a popup */
1823 if (!unicode
) AppendMenuA( hMenu
, flags
, id
, *str
? str
: NULL
);
1824 else AppendMenuW( hMenu
, flags
, id
,
1825 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1827 } while (!(flags
& MF_END
));
1832 /**********************************************************************
1833 * MENUEX_ParseResource
1835 * Parse an extended menu resource and add items to the menu.
1836 * Return a pointer to the end of the resource.
1838 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
1844 mii
.cbSize
= sizeof(mii
);
1845 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
1846 mii
.fType
= GET_DWORD(res
);
1847 res
+= sizeof(DWORD
);
1848 mii
.fState
= GET_DWORD(res
);
1849 res
+= sizeof(DWORD
);
1850 mii
.wID
= GET_DWORD(res
);
1851 res
+= sizeof(DWORD
);
1852 resinfo
= GET_WORD(res
); /* FIXME: for 16-bit apps this is a byte. */
1853 res
+= sizeof(WORD
);
1854 /* Align the text on a word boundary. */
1855 res
+= (~((int)res
- 1)) & 1;
1856 mii
.dwTypeData
= (LPWSTR
) res
;
1857 res
+= (1 + lstrlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
1858 /* Align the following fields on a dword boundary. */
1859 res
+= (~((int)res
- 1)) & 3;
1861 /* FIXME: This is inefficient and cannot be optimised away by gcc. */
1863 LPSTR newstr
= HEAP_strdupWtoA(GetProcessHeap(),
1865 TRACE(menu
, "Menu item: [%08x,%08x,%04x,%04x,%s]\n",
1866 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, newstr
);
1867 HeapFree( GetProcessHeap(), 0, newstr
);
1870 if (resinfo
& 1) { /* Pop-up? */
1871 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
1872 res
+= sizeof(DWORD
);
1873 mii
.hSubMenu
= CreatePopupMenu();
1876 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
1877 DestroyMenu(mii
.hSubMenu
);
1880 mii
.fMask
|= MIIM_SUBMENU
;
1881 mii
.fType
|= MF_POPUP
;
1883 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
1884 } while (!(resinfo
& MF_END
));
1889 /***********************************************************************
1892 * Return the handle of the selected sub-popup menu (if any).
1894 static HMENU
MENU_GetSubPopup( HMENU hmenu
)
1899 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1901 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return 0;
1903 item
= &menu
->items
[menu
->FocusedItem
];
1904 if ((item
->fType
& MF_POPUP
) && (item
->fState
& MF_MOUSESELECT
))
1905 return item
->hSubMenu
;
1910 /***********************************************************************
1911 * MENU_HideSubPopups
1913 * Hide the sub-popup menus of this menu.
1915 static void MENU_HideSubPopups( HWND hwndOwner
, HMENU hmenu
,
1916 BOOL sendMenuSelect
)
1918 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);;
1920 if (menu
&& uSubPWndLevel
)
1926 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1928 item
= &menu
->items
[menu
->FocusedItem
];
1929 if (!(item
->fType
& MF_POPUP
) ||
1930 !(item
->fState
& MF_MOUSESELECT
)) return;
1931 item
->fState
&= ~MF_MOUSESELECT
;
1932 hsubmenu
= item
->hSubMenu
;
1935 submenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hsubmenu
);
1936 MENU_HideSubPopups( hwndOwner
, hsubmenu
, FALSE
);
1937 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, sendMenuSelect
);
1939 if (submenu
->hWnd
== MENU_GetTopPopupWnd()->hwndSelf
)
1941 ShowWindow( submenu
->hWnd
, SW_HIDE
);
1946 DestroyWindow( submenu
->hWnd
);
1949 MENU_ReleaseTopPopupWnd();
1954 /***********************************************************************
1957 * Display the sub-menu of the selected item of this menu.
1958 * Return the handle of the submenu, or hmenu if no submenu to display.
1960 static HMENU
MENU_ShowSubPopup( HWND hwndOwner
, HMENU hmenu
,
1969 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return hmenu
;
1971 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
)) ||
1972 (menu
->FocusedItem
== NO_SELECTED_ITEM
))
1974 WIN_ReleaseWndPtr(wndPtr
);
1978 item
= &menu
->items
[menu
->FocusedItem
];
1979 if (!(item
->fType
& MF_POPUP
) ||
1980 (item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
1982 WIN_ReleaseWndPtr(wndPtr
);
1986 /* message must be send before using item,
1987 because nearly everything may by changed by the application ! */
1989 SendMessageA( hwndOwner
, WM_INITMENUPOPUP
, item
->hSubMenu
,
1990 MAKELONG( menu
->FocusedItem
, IS_SYSTEM_MENU(menu
) ));
1992 item
= &menu
->items
[menu
->FocusedItem
];
1995 /* correct item if modified as a reaction to WM_INITMENUPOPUP-message */
1996 if (!(item
->fState
& MF_HILITE
))
1998 if (menu
->wFlags
& MF_POPUP
) hdc
= GetDC( menu
->hWnd
);
1999 else hdc
= GetDCEx( menu
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2001 SelectObject( hdc
, hMenuFont
);
2003 item
->fState
|= MF_HILITE
;
2004 MENU_DrawMenuItem( menu
->hWnd
, hmenu
, hwndOwner
, hdc
, item
, menu
->Height
, !(menu
->wFlags
& MF_POPUP
), ODA_DRAWENTIRE
);
2005 ReleaseDC( menu
->hWnd
, hdc
);
2007 if (!item
->rect
.top
&& !item
->rect
.left
&& !item
->rect
.bottom
&& !item
->rect
.right
)
2010 item
->fState
|= MF_MOUSESELECT
;
2012 if (IS_SYSTEM_MENU(menu
))
2014 MENU_InitSysMenuPopup(item
->hSubMenu
, wndPtr
->dwStyle
, wndPtr
->class->style
);
2016 NC_GetSysPopupPos( wndPtr
, &rect
);
2017 rect
.top
= rect
.bottom
;
2018 rect
.right
= SYSMETRICS_CXSIZE
;
2019 rect
.bottom
= SYSMETRICS_CYSIZE
;
2023 if (menu
->wFlags
& MF_POPUP
)
2025 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.right
-arrow_bitmap_width
;
2026 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.top
;
2027 rect
.right
= item
->rect
.left
- item
->rect
.right
+ 2*arrow_bitmap_width
;
2028 rect
.bottom
= item
->rect
.top
- item
->rect
.bottom
;
2032 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.left
;
2033 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.bottom
;
2034 rect
.right
= item
->rect
.right
- item
->rect
.left
;
2035 rect
.bottom
= item
->rect
.bottom
- item
->rect
.top
;
2039 MENU_ShowPopup( hwndOwner
, item
->hSubMenu
, menu
->FocusedItem
,
2040 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2042 MENU_MoveSelection( hwndOwner
, item
->hSubMenu
, ITEM_NEXT
);
2043 WIN_ReleaseWndPtr(wndPtr
);
2044 return item
->hSubMenu
;
2047 /***********************************************************************
2050 * Walks menu chain trying to find a menu pt maps to.
2052 static HMENU
MENU_PtMenu( HMENU hMenu
, POINT16 pt
)
2054 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hMenu
);
2055 register UINT ht
= menu
->FocusedItem
;
2057 /* try subpopup first (if any) */
2058 ht
= (ht
!= NO_SELECTED_ITEM
&&
2059 (menu
->items
[ht
].fType
& MF_POPUP
) &&
2060 (menu
->items
[ht
].fState
& MF_MOUSESELECT
))
2061 ? (UINT
) MENU_PtMenu(menu
->items
[ht
].hSubMenu
, pt
) : 0;
2063 if( !ht
) /* check the current window (avoiding WM_HITTEST) */
2065 ht
= (UINT
)NC_HandleNCHitTest( menu
->hWnd
, pt
);
2066 if( menu
->wFlags
& MF_POPUP
)
2067 ht
= (ht
!= (UINT
)HTNOWHERE
&&
2068 ht
!= (UINT
)HTERROR
) ? (UINT
)hMenu
: 0;
2071 WND
* wndPtr
= WIN_FindWndPtr(menu
->hWnd
);
2073 ht
= ( ht
== HTSYSMENU
) ? (UINT
)(wndPtr
->hSysMenu
)
2074 : ( ht
== HTMENU
) ? (UINT
)(wndPtr
->wIDmenu
) : 0;
2075 WIN_ReleaseWndPtr(wndPtr
);
2080 /***********************************************************************
2081 * MENU_ExecFocusedItem
2083 * Execute a menu item (for instance when user pressed Enter).
2084 * Return the wID of the executed item. Otherwise, zero indicating
2085 * that no menu item wase executed;
2087 static INT
MENU_ExecFocusedItem( MTRACKER
* pmt
, HMENU hMenu
)
2090 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hMenu
);
2091 if (!menu
|| !menu
->nItems
||
2092 (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return 0;
2094 item
= &menu
->items
[menu
->FocusedItem
];
2096 TRACE(menu
, "%08x %08x %08x\n",
2097 hMenu
, item
->wID
, item
->hSubMenu
);
2099 if (!(item
->fType
& MF_POPUP
))
2101 if (!(item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
2103 if( menu
->wFlags
& MF_SYSMENU
)
2105 PostMessageA( pmt
->hOwnerWnd
, WM_SYSCOMMAND
, item
->wID
,
2106 MAKELPARAM((INT16
)pmt
->pt
.x
, (INT16
)pmt
->pt
.y
) );
2110 PostMessageA( pmt
->hOwnerWnd
, WM_COMMAND
, item
->wID
, 0 );
2118 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hMenu
, TRUE
);
2123 /***********************************************************************
2124 * MENU_SwitchTracking
2126 * Helper function for menu navigation routines.
2128 static void MENU_SwitchTracking( MTRACKER
* pmt
, HMENU hPtMenu
, UINT id
)
2130 POPUPMENU
*ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
2131 POPUPMENU
*topmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( pmt
->hTopMenu
);
2133 if( pmt
->hTopMenu
!= hPtMenu
&&
2134 !((ptmenu
->wFlags
| topmenu
->wFlags
) & MF_POPUP
) )
2136 /* both are top level menus (system and menu-bar) */
2138 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2139 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
);
2140 pmt
->hTopMenu
= hPtMenu
;
2142 else MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
2143 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, id
, TRUE
);
2147 /***********************************************************************
2150 * Return TRUE if we can go on with menu tracking.
2152 static BOOL
MENU_ButtonDown( MTRACKER
* pmt
, HMENU hPtMenu
)
2157 POPUPMENU
*ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
2160 if( IS_SYSTEM_MENU(ptmenu
) )
2161 item
= ptmenu
->items
;
2163 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2167 if( ptmenu
->FocusedItem
== id
)
2169 /* nothing to do with already selected non-popup */
2170 if( !(item
->fType
& MF_POPUP
) ) return TRUE
;
2172 if( item
->fState
& MF_MOUSESELECT
)
2174 if( ptmenu
->wFlags
& MF_POPUP
)
2176 /* hide selected subpopup */
2178 MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, TRUE
);
2179 pmt
->hCurrentMenu
= hPtMenu
;
2182 return FALSE
; /* shouldn't get here */
2185 else MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2187 /* try to display a subpopup */
2189 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
2192 else WARN(menu
, "\tunable to find clicked item!\n");
2197 /***********************************************************************
2200 * Return the the value of MENU_ExecFocusedItem if
2201 * the selected item was not a popup
2202 * 1 if the item was a popup
2204 * A zero return value indicates that we can't go on with menu tracking.
2206 static INT
MENU_ButtonUp( MTRACKER
* pmt
, HMENU hPtMenu
)
2211 POPUPMENU
*ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
2214 if( IS_SYSTEM_MENU(ptmenu
) )
2215 item
= ptmenu
->items
;
2217 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2219 if( item
&& (ptmenu
->FocusedItem
== id
))
2221 if( !(item
->fType
& MF_POPUP
) )
2222 return MENU_ExecFocusedItem( pmt
, hPtMenu
);
2223 hPtMenu
= item
->hSubMenu
;
2224 if( hPtMenu
== pmt
->hCurrentMenu
)
2226 /* Select first item of sub-popup */
2228 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, NO_SELECTED_ITEM
, FALSE
);
2229 MENU_MoveSelection( pmt
->hOwnerWnd
, hPtMenu
, ITEM_NEXT
);
2238 /***********************************************************************
2241 * Return TRUE if we can go on with menu tracking.
2243 static BOOL
MENU_MouseMove( MTRACKER
* pmt
, HMENU hPtMenu
)
2245 UINT id
= NO_SELECTED_ITEM
;
2246 POPUPMENU
*ptmenu
= NULL
;
2250 ptmenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hPtMenu
);
2251 if( IS_SYSTEM_MENU(ptmenu
) )
2254 MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2257 if( id
== NO_SELECTED_ITEM
)
2259 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2260 NO_SELECTED_ITEM
, TRUE
);
2262 else if( ptmenu
->FocusedItem
!= id
)
2264 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2265 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
2271 /***********************************************************************
2274 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2276 static LRESULT
MENU_DoNextMenu( MTRACKER
* pmt
, UINT vk
)
2278 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( pmt
->hTopMenu
);
2280 if( (vk
== VK_LEFT
&& menu
->FocusedItem
== 0 ) ||
2281 (vk
== VK_RIGHT
&& menu
->FocusedItem
== menu
->nItems
- 1))
2287 LRESULT l
= SendMessageA( pmt
->hOwnerWnd
, WM_NEXTMENU
, vk
,
2288 (IS_SYSTEM_MENU(menu
)) ? GetSubMenu16(pmt
->hTopMenu
,0) : pmt
->hTopMenu
);
2290 TRACE(menu
,"%04x [%04x] -> %04x [%04x]\n",
2291 (UINT16
)pmt
->hCurrentMenu
, (UINT16
)pmt
->hOwnerWnd
, LOWORD(l
), HIWORD(l
) );
2295 wndPtr
= WIN_FindWndPtr(pmt
->hOwnerWnd
);
2297 hNewWnd
= pmt
->hOwnerWnd
;
2298 if( IS_SYSTEM_MENU(menu
) )
2300 /* switch to the menu bar */
2302 if( wndPtr
->dwStyle
& WS_CHILD
|| !wndPtr
->wIDmenu
)
2304 WIN_ReleaseWndPtr(wndPtr
);
2308 hNewMenu
= wndPtr
->wIDmenu
;
2311 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hNewMenu
);
2312 id
= menu
->nItems
- 1;
2315 else if( wndPtr
->dwStyle
& WS_SYSMENU
)
2317 /* switch to the system menu */
2318 hNewMenu
= wndPtr
->hSysMenu
;
2322 WIN_ReleaseWndPtr(wndPtr
);
2325 WIN_ReleaseWndPtr(wndPtr
);
2327 else /* application returned a new menu to switch to */
2329 hNewMenu
= LOWORD(l
); hNewWnd
= HIWORD(l
);
2331 if( IsMenu(hNewMenu
) && IsWindow(hNewWnd
) )
2333 wndPtr
= WIN_FindWndPtr(hNewWnd
);
2335 if( wndPtr
->dwStyle
& WS_SYSMENU
&&
2336 GetSubMenu16(wndPtr
->hSysMenu
, 0) == hNewMenu
)
2338 /* get the real system menu */
2339 hNewMenu
= wndPtr
->hSysMenu
;
2341 else if( wndPtr
->dwStyle
& WS_CHILD
|| wndPtr
->wIDmenu
!= hNewMenu
)
2343 /* FIXME: Not sure what to do here, perhaps,
2344 * try to track hNewMenu as a popup? */
2346 TRACE(menu
," -- got confused.\n");
2347 WIN_ReleaseWndPtr(wndPtr
);
2350 WIN_ReleaseWndPtr(wndPtr
);
2355 if( hNewMenu
!= pmt
->hTopMenu
)
2357 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
);
2358 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2359 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2362 if( hNewWnd
!= pmt
->hOwnerWnd
)
2365 pmt
->hOwnerWnd
= hNewWnd
;
2366 EVENT_Capture( pmt
->hOwnerWnd
, HTMENU
);
2369 pmt
->hTopMenu
= pmt
->hCurrentMenu
= hNewMenu
; /* all subpopups are hidden */
2370 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, id
, TRUE
);
2377 /***********************************************************************
2380 * The idea is not to show the popup if the next input message is
2381 * going to hide it anyway.
2383 static BOOL
MENU_SuspendPopup( MTRACKER
* pmt
, UINT16 uMsg
)
2387 msg
.hwnd
= pmt
->hOwnerWnd
;
2389 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2390 pmt
->trackFlags
|= TF_SKIPREMOVE
;
2395 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2396 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
2398 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2399 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2400 if( msg
.message
== WM_KEYDOWN
&&
2401 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
2403 pmt
->trackFlags
|= TF_SUSPENDPOPUP
;
2410 /* failures go through this */
2411 pmt
->trackFlags
&= ~TF_SUSPENDPOPUP
;
2415 /***********************************************************************
2418 * Handle a VK_LEFT key event in a menu.
2420 static void MENU_KeyLeft( MTRACKER
* pmt
)
2423 HMENU hmenutmp
, hmenuprev
;
2426 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
2427 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenutmp
);
2429 /* Try to move 1 column left (if possible) */
2430 if( (prevcol
= MENU_GetStartOfPrevColumn( pmt
->hCurrentMenu
)) !=
2431 NO_SELECTED_ITEM
) {
2433 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2438 /* close topmost popup */
2439 while (hmenutmp
!= pmt
->hCurrentMenu
)
2441 hmenuprev
= hmenutmp
;
2442 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
2445 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
);
2446 pmt
->hCurrentMenu
= hmenuprev
;
2448 if ( (hmenuprev
== pmt
->hTopMenu
) && !(menu
->wFlags
& MF_POPUP
) )
2450 /* move menu bar selection if no more popups are left */
2452 if( !MENU_DoNextMenu( pmt
, VK_LEFT
) )
2453 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_PREV
);
2455 if ( hmenuprev
!= hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2457 /* A sublevel menu was displayed - display the next one
2458 * unless there is another displacement coming up */
2460 if( !MENU_SuspendPopup( pmt
, WM_KEYDOWN
) )
2461 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
,
2462 pmt
->hTopMenu
, TRUE
);
2468 /***********************************************************************
2471 * Handle a VK_RIGHT key event in a menu.
2473 static void MENU_KeyRight( MTRACKER
* pmt
)
2476 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( pmt
->hTopMenu
);
2479 TRACE(menu
, "MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2481 ((POPUPMENU
*)USER_HEAP_LIN_ADDR(pmt
->hCurrentMenu
))->
2483 pmt
->hTopMenu
, menu
->items
[0].text
);
2485 if ( (menu
->wFlags
& MF_POPUP
) || (pmt
->hCurrentMenu
!= pmt
->hTopMenu
))
2487 /* If already displaying a popup, try to display sub-popup */
2489 hmenutmp
= pmt
->hCurrentMenu
;
2490 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hmenutmp
, TRUE
);
2492 /* if subpopup was displayed then we are done */
2493 if (hmenutmp
!= pmt
->hCurrentMenu
) return;
2496 /* Check to see if there's another column */
2497 if( (nextcol
= MENU_GetStartOfNextColumn( pmt
->hCurrentMenu
)) !=
2498 NO_SELECTED_ITEM
) {
2499 TRACE(menu
, "Going to %d.\n", nextcol
);
2500 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2505 if (!(menu
->wFlags
& MF_POPUP
)) /* menu bar tracking */
2507 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2509 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2510 hmenutmp
= pmt
->hCurrentMenu
= pmt
->hTopMenu
;
2511 } else hmenutmp
= 0;
2513 /* try to move to the next item */
2514 if( !MENU_DoNextMenu( pmt
, VK_RIGHT
) )
2515 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_NEXT
);
2517 if( hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2518 if( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
2519 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
,
2520 pmt
->hTopMenu
, TRUE
);
2524 /***********************************************************************
2527 * Menu tracking code.
2529 static INT
MENU_TrackMenu( HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
2530 HWND hwnd
, const RECT
*lprect
)
2535 INT executedMenuId
= 0;
2536 MTRACKER mt
= { 0, hmenu
, hmenu
, hwnd
, {x
, y
} }; /* control struct */
2538 TRACE(menu
,"hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2539 hmenu
, wFlags
, x
, y
, hwnd
, lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
2542 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
2544 if (wFlags
& TPM_BUTTONDOWN
) MENU_ButtonDown( &mt
, hmenu
);
2546 EVENT_Capture( mt
.hOwnerWnd
, HTMENU
);
2550 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( mt
.hCurrentMenu
);
2551 msg
.hwnd
= (wFlags
& TPM_ENTERIDLEEX
&& menu
->wFlags
& MF_POPUP
) ? menu
->hWnd
: 0;
2553 /* we have to keep the message in the queue until it's
2554 * clear that menu loop is not over yet. */
2556 if (!MSG_InternalGetMessage( &msg
, msg
.hwnd
, mt
.hOwnerWnd
,
2557 MSGF_MENU
, PM_NOREMOVE
, TRUE
)) break;
2559 TranslateMessage( &msg
);
2563 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
2565 /* Find a menu for this mouse event */
2567 CONV_POINT32TO16( &msg
.pt
, &pt16
);
2568 hmenu
= MENU_PtMenu( mt
.hTopMenu
, pt16
);
2572 /* no WM_NC... messages in captured state */
2574 case WM_RBUTTONDBLCLK
:
2575 case WM_RBUTTONDOWN
:
2576 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2578 case WM_LBUTTONDBLCLK
:
2579 case WM_LBUTTONDOWN
:
2580 fEndMenu
|= !MENU_ButtonDown( &mt
, hmenu
);
2584 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2587 /* Check if a menu was selected by the mouse */
2590 executedMenuId
= MENU_ButtonUp( &mt
, hmenu
);
2592 /* the executedMenuId higher than one means that it contains
2593 the id of the selected item so we have to put the fEndMenu to TRUE.
2594 Otherwise, it contains a continue
2595 flag returned by MENU_ButtonUp indicating if we can continue with
2596 menu tracking or not*/
2597 fEndMenu
= ((executedMenuId
> 1) ? TRUE
: FALSE
);
2600 /* No menu was selected by the mouse */
2601 /* if the function was called by TrackPopupMenu, continue
2602 with the menu tracking. If not, stop it */
2604 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
2609 /* In win95 winelook, the selected menu item must be changed every time the
2610 mouse moves. In Win31 winelook, the mouse button has to be held down */
2612 if ( (TWEAK_WineLook
> WIN31_LOOK
) ||
2613 ( (msg
.wParam
& MK_LBUTTON
) ||
2614 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
.wParam
& MK_RBUTTON
))) )
2616 fEndMenu
|= !MENU_MouseMove( &mt
, hmenu
);
2618 } /* switch(msg.message) - mouse */
2620 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
2622 fRemove
= TRUE
; /* Keyboard messages are always removed */
2630 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2631 NO_SELECTED_ITEM
, FALSE
);
2634 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2635 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
2638 case VK_DOWN
: /* If on menu bar, pull-down the menu */
2640 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( mt
.hCurrentMenu
);
2641 if (!(menu
->wFlags
& MF_POPUP
))
2642 mt
.hCurrentMenu
= MENU_ShowSubPopup( mt
.hOwnerWnd
, mt
.hTopMenu
, TRUE
);
2643 else /* otherwise try to move selection */
2644 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
, ITEM_NEXT
);
2648 MENU_KeyLeft( &mt
);
2652 MENU_KeyRight( &mt
);
2662 break; /* WM_KEYDOWN */
2672 break; /* WM_SYSKEYDOWN */
2678 if (msg
.wParam
== '\r' || msg
.wParam
== ' ')
2680 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
);
2681 fEndMenu
= ((executedMenuId
!= 0) ? TRUE
:FALSE
);
2686 /* Hack to avoid control chars. */
2687 /* We will find a better way real soon... */
2688 if ((msg
.wParam
<= 32) || (msg
.wParam
>= 127)) break;
2690 pos
= MENU_FindItemByKey( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2691 LOWORD(msg
.wParam
), FALSE
);
2692 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
2693 else if (pos
== (UINT
)-1) MessageBeep(0);
2696 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
, pos
, TRUE
);
2697 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
);
2698 fEndMenu
= ((executedMenuId
!= 0) ? TRUE
:FALSE
);
2702 } /* switch(msg.message) - kbd */
2706 DispatchMessageA( &msg
);
2709 if (!fEndMenu
) fRemove
= TRUE
;
2711 /* finally remove message from the queue */
2713 if (fRemove
&& !(mt
.trackFlags
& TF_SKIPREMOVE
) )
2714 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2715 else mt
.trackFlags
&= ~TF_SKIPREMOVE
;
2719 if( IsWindow( mt
.hOwnerWnd
) )
2721 MENU_HideSubPopups( mt
.hOwnerWnd
, mt
.hTopMenu
, FALSE
);
2723 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( mt
.hTopMenu
);
2724 if (menu
&& menu
->wFlags
& MF_POPUP
)
2726 ShowWindow( menu
->hWnd
, SW_HIDE
);
2729 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hTopMenu
, NO_SELECTED_ITEM
, FALSE
);
2730 SendMessageA( mt
.hOwnerWnd
, WM_MENUSELECT
, MAKELONG(0,0), 0xffff );
2733 /* returning the id of the selected menu.
2734 The return value is only used by TrackPopupMenu */
2735 return executedMenuId
;
2738 /***********************************************************************
2741 static BOOL
MENU_InitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
)
2744 TRACE(menu
, "hwnd=0x%04x hmenu=0x%04x\n", hWnd
, hMenu
);
2747 SendMessageA( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
2748 SendMessageA( hWnd
, WM_SETCURSOR
, hWnd
, HTCAPTION
);
2749 SendMessageA( hWnd
, WM_INITMENU
, hMenu
, 0 );
2752 /***********************************************************************
2755 static BOOL
MENU_ExitTracking(HWND hWnd
)
2757 TRACE(menu
, "hwnd=0x%04x\n", hWnd
);
2759 SendMessageA( hWnd
, WM_EXITMENULOOP
, 0, 0 );
2764 /***********************************************************************
2765 * MENU_TrackMouseMenuBar
2767 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2769 void MENU_TrackMouseMenuBar( WND
* wndPtr
, INT ht
, POINT pt
)
2771 HWND hWnd
= wndPtr
->hwndSelf
;
2772 HMENU hMenu
= (ht
== HTSYSMENU
) ? wndPtr
->hSysMenu
: wndPtr
->wIDmenu
;
2774 TRACE(menu
,"pwnd=%p ht=0x%04x (%ld,%ld)\n", wndPtr
, ht
, pt
.x
, pt
.y
);
2778 MENU_InitTracking( hWnd
, hMenu
, FALSE
);
2779 MENU_TrackMenu( hMenu
, TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
|
2780 TPM_LEFTALIGN
| TPM_LEFTBUTTON
, pt
.x
, pt
.y
, hWnd
, NULL
);
2781 MENU_ExitTracking(hWnd
);
2786 /***********************************************************************
2787 * MENU_TrackKbdMenuBar
2789 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
2791 void MENU_TrackKbdMenuBar( WND
* wndPtr
, UINT wParam
, INT vkey
)
2793 UINT uItem
= NO_SELECTED_ITEM
;
2796 /* find window that has a menu */
2798 while( wndPtr
->dwStyle
& WS_CHILD
&& !(wndPtr
->dwStyle
& WS_SYSMENU
) )
2799 if( !(wndPtr
= wndPtr
->parent
) ) return;
2801 /* check if we have to track a system menu */
2803 if( (wndPtr
->dwStyle
& (WS_CHILD
| WS_MINIMIZE
)) ||
2804 !wndPtr
->wIDmenu
|| vkey
== VK_SPACE
)
2806 if( !(wndPtr
->dwStyle
& WS_SYSMENU
) ) return;
2807 hTrackMenu
= wndPtr
->hSysMenu
;
2809 wParam
|= HTSYSMENU
; /* prevent item lookup */
2812 hTrackMenu
= wndPtr
->wIDmenu
;
2814 if (IsMenu( hTrackMenu
))
2816 MENU_InitTracking( wndPtr
->hwndSelf
, hTrackMenu
, FALSE
);
2818 if( vkey
&& vkey
!= VK_SPACE
)
2820 uItem
= MENU_FindItemByKey( wndPtr
->hwndSelf
, hTrackMenu
,
2821 vkey
, (wParam
& HTSYSMENU
) );
2822 if( uItem
>= (UINT
)(-2) )
2824 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
2831 MENU_SelectItem( wndPtr
->hwndSelf
, hTrackMenu
, uItem
, TRUE
);
2833 if( uItem
== NO_SELECTED_ITEM
)
2834 MENU_MoveSelection( wndPtr
->hwndSelf
, hTrackMenu
, ITEM_NEXT
);
2836 PostMessageA( wndPtr
->hwndSelf
, WM_KEYDOWN
, VK_DOWN
, 0L );
2838 MENU_TrackMenu( hTrackMenu
, TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
2839 0, 0, wndPtr
->hwndSelf
, NULL
);
2842 MENU_ExitTracking (wndPtr
->hwndSelf
);
2847 /**********************************************************************
2848 * TrackPopupMenu16 (USER.416)
2850 BOOL16 WINAPI
TrackPopupMenu16( HMENU16 hMenu
, UINT16 wFlags
, INT16 x
, INT16 y
,
2851 INT16 nReserved
, HWND16 hWnd
, const RECT16
*lpRect
)
2855 CONV_RECT16TO32( lpRect
, &r
);
2856 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, nReserved
, hWnd
,
2857 lpRect
? &r
: NULL
);
2861 /**********************************************************************
2862 * TrackPopupMenu (USER32.549)
2864 BOOL WINAPI
TrackPopupMenu( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
2865 INT nReserved
, HWND hWnd
, const RECT
*lpRect
)
2869 MENU_InitTracking(hWnd
, hMenu
, TRUE
);
2870 SendMessageA( hWnd
, WM_INITMENUPOPUP
, hMenu
, 0);
2871 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
, 0, 0 ))
2872 ret
= MENU_TrackMenu( hMenu
, wFlags
| TPM_POPUPMENU
, 0, 0, hWnd
, lpRect
);
2873 MENU_ExitTracking(hWnd
);
2877 /**********************************************************************
2878 * TrackPopupMenuEx (USER32.550)
2880 BOOL WINAPI
TrackPopupMenuEx( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
2881 HWND hWnd
, LPTPMPARAMS lpTpm
)
2883 FIXME(menu
, "not fully implemented\n" );
2884 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, 0, hWnd
,
2885 lpTpm
? &lpTpm
->rcExclude
: NULL
);
2888 /***********************************************************************
2891 * NOTE: Windows has totally different (and undocumented) popup wndproc.
2893 LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
,
2896 WND
* wndPtr
= WIN_FindWndPtr(hwnd
);
2899 TRACE(menu
,"hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
2900 hwnd
, message
, wParam
, lParam
);
2906 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*)lParam
;
2907 SetWindowLongA( hwnd
, 0, (LONG
)cs
->lpCreateParams
);
2912 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2913 retvalue
= MA_NOACTIVATE
;
2919 BeginPaint( hwnd
, &ps
);
2920 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
2921 (HMENU
)GetWindowLongA( hwnd
, 0 ) );
2922 EndPaint( hwnd
, &ps
);
2932 /* zero out global pointer in case resident popup window
2933 * was somehow destroyed. */
2935 if(MENU_GetTopPopupWnd() )
2937 if( hwnd
== pTopPopupWnd
->hwndSelf
)
2939 ERR(menu
, "resident popup destroyed!\n");
2941 MENU_DestroyTopPopupWnd();
2946 MENU_ReleaseTopPopupWnd();
2954 if( !(*(HMENU
*)wndPtr
->wExtra
) )
2955 ERR(menu
,"no menu to display\n");
2958 *(HMENU
*)wndPtr
->wExtra
= 0;
2961 case MM_SETMENUHANDLE
:
2963 *(HMENU
*)wndPtr
->wExtra
= (HMENU
)wParam
;
2966 case MM_GETMENUHANDLE
:
2968 retvalue
= *(HMENU
*)wndPtr
->wExtra
;
2972 retvalue
= DefWindowProcA( hwnd
, message
, wParam
, lParam
);
2977 WIN_ReleaseWndPtr(wndPtr
);
2982 /***********************************************************************
2983 * MENU_GetMenuBarHeight
2985 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
2987 UINT
MENU_GetMenuBarHeight( HWND hwnd
, UINT menubarWidth
,
2988 INT orgX
, INT orgY
)
2996 TRACE(menu
, "HWND 0x%x, width %d, at (%d, %d).\n",
2997 hwnd
, menubarWidth
, orgX
, orgY
);
2999 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
3002 if (!(lppop
= (LPPOPUPMENU
)USER_HEAP_LIN_ADDR((HMENU16
)wndPtr
->wIDmenu
)))
3004 WIN_ReleaseWndPtr(wndPtr
);
3008 hdc
= GetDCEx( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3009 SelectObject( hdc
, hMenuFont
);
3010 SetRect(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+SYSMETRICS_CYMENU
);
3011 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
3012 ReleaseDC( hwnd
, hdc
);
3013 retvalue
= lppop
->Height
;
3014 WIN_ReleaseWndPtr(wndPtr
);
3019 /*******************************************************************
3020 * ChangeMenu16 (USER.153)
3022 BOOL16 WINAPI
ChangeMenu16( HMENU16 hMenu
, UINT16 pos
, SEGPTR data
,
3023 UINT16 id
, UINT16 flags
)
3025 TRACE(menu
,"menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
3026 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3027 if (flags
& MF_APPEND
) return AppendMenu16( hMenu
, flags
& ~MF_APPEND
,
3030 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
3031 /* for MF_DELETE. We should check the parameters for all others */
3032 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
3034 if (flags
& MF_DELETE
) return DeleteMenu16(hMenu
, pos
, flags
& ~MF_DELETE
);
3035 if (flags
& MF_CHANGE
) return ModifyMenu16(hMenu
, pos
, flags
& ~MF_CHANGE
,
3037 if (flags
& MF_REMOVE
) return RemoveMenu16(hMenu
,
3038 flags
& MF_BYPOSITION
? pos
: id
,
3039 flags
& ~MF_REMOVE
);
3040 /* Default: MF_INSERT */
3041 return InsertMenu16( hMenu
, pos
, flags
, id
, data
);
3045 /*******************************************************************
3046 * ChangeMenu32A (USER32.23)
3048 BOOL WINAPI
ChangeMenuA( HMENU hMenu
, UINT pos
, LPCSTR data
,
3049 UINT id
, UINT flags
)
3051 TRACE(menu
,"menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3052 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3053 if (flags
& MF_APPEND
) return AppendMenuA( hMenu
, flags
& ~MF_APPEND
,
3055 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3056 if (flags
& MF_CHANGE
) return ModifyMenuA(hMenu
, pos
, flags
& ~MF_CHANGE
,
3058 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3059 flags
& MF_BYPOSITION
? pos
: id
,
3060 flags
& ~MF_REMOVE
);
3061 /* Default: MF_INSERT */
3062 return InsertMenuA( hMenu
, pos
, flags
, id
, data
);
3066 /*******************************************************************
3067 * ChangeMenu32W (USER32.24)
3069 BOOL WINAPI
ChangeMenuW( HMENU hMenu
, UINT pos
, LPCWSTR data
,
3070 UINT id
, UINT flags
)
3072 TRACE(menu
,"menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3073 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3074 if (flags
& MF_APPEND
) return AppendMenuW( hMenu
, flags
& ~MF_APPEND
,
3076 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3077 if (flags
& MF_CHANGE
) return ModifyMenuW(hMenu
, pos
, flags
& ~MF_CHANGE
,
3079 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3080 flags
& MF_BYPOSITION
? pos
: id
,
3081 flags
& ~MF_REMOVE
);
3082 /* Default: MF_INSERT */
3083 return InsertMenuW( hMenu
, pos
, flags
, id
, data
);
3087 /*******************************************************************
3088 * CheckMenuItem16 (USER.154)
3090 BOOL16 WINAPI
CheckMenuItem16( HMENU16 hMenu
, UINT16 id
, UINT16 flags
)
3092 return (BOOL16
)CheckMenuItem( hMenu
, id
, flags
);
3096 /*******************************************************************
3097 * CheckMenuItem (USER32.46)
3099 DWORD WINAPI
CheckMenuItem( HMENU hMenu
, UINT id
, UINT flags
)
3104 TRACE(menu
,"menu=%04x id=%04x flags=%04x\n", hMenu
, id
, flags
);
3105 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
3106 ret
= item
->fState
& MF_CHECKED
;
3107 if (flags
& MF_CHECKED
) item
->fState
|= MF_CHECKED
;
3108 else item
->fState
&= ~MF_CHECKED
;
3113 /**********************************************************************
3114 * EnableMenuItem16 (USER.155)
3116 UINT16 WINAPI
EnableMenuItem16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3118 return EnableMenuItem( hMenu
, wItemID
, wFlags
);
3122 /**********************************************************************
3123 * EnableMenuItem32 (USER32.170)
3125 UINT WINAPI
EnableMenuItem( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3130 TRACE(menu
,"(%04x, %04X, %04X) !\n",
3131 hMenu
, wItemID
, wFlags
);
3133 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
)))
3136 oldflags
= item
->fState
& (MF_GRAYED
| MF_DISABLED
);
3137 item
->fState
^= (oldflags
^ wFlags
) & (MF_GRAYED
| MF_DISABLED
);
3142 /*******************************************************************
3143 * GetMenuString16 (USER.161)
3145 INT16 WINAPI
GetMenuString16( HMENU16 hMenu
, UINT16 wItemID
,
3146 LPSTR str
, INT16 nMaxSiz
, UINT16 wFlags
)
3148 return GetMenuStringA( hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3152 /*******************************************************************
3153 * GetMenuString32A (USER32.268)
3155 INT WINAPI
GetMenuStringA( HMENU hMenu
, UINT wItemID
,
3156 LPSTR str
, INT nMaxSiz
, UINT wFlags
)
3160 TRACE(menu
, "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3161 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3162 if (!str
|| !nMaxSiz
) return 0;
3164 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3165 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3166 lstrcpynA( str
, item
->text
, nMaxSiz
);
3167 TRACE(menu
, "returning '%s'\n", str
);
3172 /*******************************************************************
3173 * GetMenuString32W (USER32.269)
3175 INT WINAPI
GetMenuStringW( HMENU hMenu
, UINT wItemID
,
3176 LPWSTR str
, INT nMaxSiz
, UINT wFlags
)
3180 TRACE(menu
, "menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3181 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3182 if (!str
|| !nMaxSiz
) return 0;
3184 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3185 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3186 lstrcpynAtoW( str
, item
->text
, nMaxSiz
);
3187 return lstrlenW(str
);
3191 /**********************************************************************
3192 * HiliteMenuItem16 (USER.162)
3194 BOOL16 WINAPI
HiliteMenuItem16( HWND16 hWnd
, HMENU16 hMenu
, UINT16 wItemID
,
3197 return HiliteMenuItem( hWnd
, hMenu
, wItemID
, wHilite
);
3201 /**********************************************************************
3202 * HiliteMenuItem32 (USER32.318)
3204 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
3208 TRACE(menu
,"(%04x, %04x, %04x, %04x);\n",
3209 hWnd
, hMenu
, wItemID
, wHilite
);
3210 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
3211 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
3212 if (menu
->FocusedItem
== wItemID
) return TRUE
;
3213 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
3214 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
);
3219 /**********************************************************************
3220 * GetMenuState16 (USER.250)
3222 UINT16 WINAPI
GetMenuState16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3224 return GetMenuState( hMenu
, wItemID
, wFlags
);
3228 /**********************************************************************
3229 * GetMenuState (USER32.267)
3231 UINT WINAPI
GetMenuState( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3234 TRACE(menu
,"(menu=%04x, id=%04x, flags=%04x);\n",
3235 hMenu
, wItemID
, wFlags
);
3236 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
3237 debug_print_menuitem (" item: ", item
, "");
3238 if (item
->fType
& MF_POPUP
)
3240 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( item
->hSubMenu
);
3241 if (!menu
) return -1;
3242 else return (menu
->nItems
<< 8) | ((item
->fState
|item
->fType
) & 0xff);
3246 /* We used to (from way back then) mask the result to 0xff. */
3247 /* I don't know why and it seems wrong as the documented */
3248 /* return flag MF_SEPARATOR is outside that mask. */
3249 return (item
->fType
| item
->fState
);
3254 /**********************************************************************
3255 * GetMenuItemCount16 (USER.263)
3257 INT16 WINAPI
GetMenuItemCount16( HMENU16 hMenu
)
3259 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3260 if (!IS_A_MENU(menu
)) return -1;
3261 TRACE(menu
,"(%04x) returning %d\n",
3262 hMenu
, menu
->nItems
);
3263 return menu
->nItems
;
3267 /**********************************************************************
3268 * GetMenuItemCount32 (USER32.262)
3270 INT WINAPI
GetMenuItemCount( HMENU hMenu
)
3272 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3273 if (!IS_A_MENU(menu
)) return -1;
3274 TRACE(menu
,"(%04x) returning %d\n",
3275 hMenu
, menu
->nItems
);
3276 return menu
->nItems
;
3280 /**********************************************************************
3281 * GetMenuItemID16 (USER.264)
3283 UINT16 WINAPI
GetMenuItemID16( HMENU16 hMenu
, INT16 nPos
)
3287 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
3288 if ((nPos
< 0) || ((UINT16
) nPos
>= menu
->nItems
)) return -1;
3289 if (menu
->items
[nPos
].fType
& MF_POPUP
) return -1;
3290 return menu
->items
[nPos
].wID
;
3294 /**********************************************************************
3295 * GetMenuItemID32 (USER32.263)
3297 UINT WINAPI
GetMenuItemID( HMENU hMenu
, INT nPos
)
3301 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
3302 if ((nPos
< 0) || (nPos
>= menu
->nItems
)) return -1;
3303 if (menu
->items
[nPos
].fType
& MF_POPUP
) return -1;
3304 return menu
->items
[nPos
].wID
;
3308 /*******************************************************************
3309 * InsertMenu16 (USER.410)
3311 BOOL16 WINAPI
InsertMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3312 UINT16 id
, SEGPTR data
)
3314 UINT pos32
= (UINT
)pos
;
3315 if ((pos
== (UINT16
)-1) && (flags
& MF_BYPOSITION
)) pos32
= (UINT
)-1;
3316 if (IS_STRING_ITEM(flags
) && data
)
3317 return InsertMenuA( hMenu
, pos32
, flags
, id
,
3318 (LPSTR
)PTR_SEG_TO_LIN(data
) );
3319 return InsertMenuA( hMenu
, pos32
, flags
, id
, (LPSTR
)data
);
3323 /*******************************************************************
3324 * InsertMenu32A (USER32.322)
3326 BOOL WINAPI
InsertMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3327 UINT id
, LPCSTR str
)
3331 if (IS_STRING_ITEM(flags
) && str
)
3332 TRACE(menu
, "hMenu %04x, pos %d, flags %08x, "
3333 "id %04x, str '%s'\n",
3334 hMenu
, pos
, flags
, id
, str
);
3335 else TRACE(menu
, "hMenu %04x, pos %d, flags %08x, "
3336 "id %04x, str %08lx (not a string)\n",
3337 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3339 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
3341 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
3343 RemoveMenu( hMenu
, pos
, flags
);
3347 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
3348 ((POPUPMENU
*)USER_HEAP_LIN_ADDR((HMENU16
)id
))->wFlags
|= MF_POPUP
;
3350 item
->hCheckBit
= item
->hUnCheckBit
= 0;
3355 /*******************************************************************
3356 * InsertMenu32W (USER32.325)
3358 BOOL WINAPI
InsertMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3359 UINT id
, LPCWSTR str
)
3363 if (IS_STRING_ITEM(flags
) && str
)
3365 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
3366 ret
= InsertMenuA( hMenu
, pos
, flags
, id
, newstr
);
3367 HeapFree( GetProcessHeap(), 0, newstr
);
3370 else return InsertMenuA( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
3374 /*******************************************************************
3375 * AppendMenu16 (USER.411)
3377 BOOL16 WINAPI
AppendMenu16(HMENU16 hMenu
, UINT16 flags
, UINT16 id
, SEGPTR data
)
3379 return InsertMenu16( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3383 /*******************************************************************
3384 * AppendMenu32A (USER32.5)
3386 BOOL WINAPI
AppendMenuA( HMENU hMenu
, UINT flags
,
3387 UINT id
, LPCSTR data
)
3389 return InsertMenuA( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3393 /*******************************************************************
3394 * AppendMenu32W (USER32.6)
3396 BOOL WINAPI
AppendMenuW( HMENU hMenu
, UINT flags
,
3397 UINT id
, LPCWSTR data
)
3399 return InsertMenuW( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3403 /**********************************************************************
3404 * RemoveMenu16 (USER.412)
3406 BOOL16 WINAPI
RemoveMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3408 return RemoveMenu( hMenu
, nPos
, wFlags
);
3412 /**********************************************************************
3413 * RemoveMenu (USER32.441)
3415 BOOL WINAPI
RemoveMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3420 TRACE(menu
,"(menu=%04x pos=%04x flags=%04x)\n",hMenu
, nPos
, wFlags
);
3421 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3422 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
3426 MENU_FreeItemData( item
);
3428 if (--menu
->nItems
== 0)
3430 HeapFree( SystemHeap
, 0, menu
->items
);
3435 while(nPos
< menu
->nItems
)
3441 menu
->items
= HeapReAlloc( SystemHeap
, 0, menu
->items
,
3442 menu
->nItems
* sizeof(MENUITEM
) );
3448 /**********************************************************************
3449 * DeleteMenu16 (USER.413)
3451 BOOL16 WINAPI
DeleteMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3453 return DeleteMenu( hMenu
, nPos
, wFlags
);
3457 /**********************************************************************
3458 * DeleteMenu32 (USER32.129)
3460 BOOL WINAPI
DeleteMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3462 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
3463 if (!item
) return FALSE
;
3464 if (item
->fType
& MF_POPUP
) DestroyMenu( item
->hSubMenu
);
3465 /* nPos is now the position of the item */
3466 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
3471 /*******************************************************************
3472 * ModifyMenu16 (USER.414)
3474 BOOL16 WINAPI
ModifyMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3475 UINT16 id
, SEGPTR data
)
3477 if (IS_STRING_ITEM(flags
))
3478 return ModifyMenuA( hMenu
, pos
, flags
, id
,
3479 (LPSTR
)PTR_SEG_TO_LIN(data
) );
3480 return ModifyMenuA( hMenu
, pos
, flags
, id
, (LPSTR
)data
);
3484 /*******************************************************************
3485 * ModifyMenu32A (USER32.397)
3487 BOOL WINAPI
ModifyMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3488 UINT id
, LPCSTR str
)
3492 if (IS_STRING_ITEM(flags
))
3494 TRACE(menu
, "%04x %d %04x %04x '%s'\n",
3495 hMenu
, pos
, flags
, id
, str
? str
: "#NULL#" );
3496 if (!str
) return FALSE
;
3500 TRACE(menu
, "%04x %d %04x %04x %08lx\n",
3501 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3504 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
3505 return MENU_SetItemData( item
, flags
, id
, str
);
3509 /*******************************************************************
3510 * ModifyMenu32W (USER32.398)
3512 BOOL WINAPI
ModifyMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3513 UINT id
, LPCWSTR str
)
3517 if (IS_STRING_ITEM(flags
) && str
)
3519 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
3520 ret
= ModifyMenuA( hMenu
, pos
, flags
, id
, newstr
);
3521 HeapFree( GetProcessHeap(), 0, newstr
);
3524 else return ModifyMenuA( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
3528 /**********************************************************************
3529 * CreatePopupMenu16 (USER.415)
3531 HMENU16 WINAPI
CreatePopupMenu16(void)
3533 return CreatePopupMenu();
3537 /**********************************************************************
3538 * CreatePopupMenu32 (USER32.82)
3540 HMENU WINAPI
CreatePopupMenu(void)
3545 if (!(hmenu
= CreateMenu())) return 0;
3546 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
3547 menu
->wFlags
|= MF_POPUP
;
3552 /**********************************************************************
3553 * GetMenuCheckMarkDimensions (USER.417) (USER32.258)
3555 DWORD WINAPI
GetMenuCheckMarkDimensions(void)
3557 return MAKELONG( check_bitmap_width
, check_bitmap_height
);
3561 /**********************************************************************
3562 * SetMenuItemBitmaps16 (USER.418)
3564 BOOL16 WINAPI
SetMenuItemBitmaps16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
,
3565 HBITMAP16 hNewUnCheck
, HBITMAP16 hNewCheck
)
3567 return SetMenuItemBitmaps( hMenu
, nPos
, wFlags
, hNewUnCheck
, hNewCheck
);
3571 /**********************************************************************
3572 * SetMenuItemBitmaps32 (USER32.490)
3574 BOOL WINAPI
SetMenuItemBitmaps( HMENU hMenu
, UINT nPos
, UINT wFlags
,
3575 HBITMAP hNewUnCheck
, HBITMAP hNewCheck
)
3578 TRACE(menu
,"(%04x, %04x, %04x, %04x, %04x)\n",
3579 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
3580 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3582 if (!hNewCheck
&& !hNewUnCheck
)
3584 item
->fState
&= ~MF_USECHECKBITMAPS
;
3586 else /* Install new bitmaps */
3588 item
->hCheckBit
= hNewCheck
;
3589 item
->hUnCheckBit
= hNewUnCheck
;
3590 item
->fState
|= MF_USECHECKBITMAPS
;
3596 /**********************************************************************
3597 * CreateMenu16 (USER.151)
3599 HMENU16 WINAPI
CreateMenu16(void)
3601 return CreateMenu();
3605 /**********************************************************************
3606 * CreateMenu (USER32.81)
3608 HMENU WINAPI
CreateMenu(void)
3612 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) ))) return 0;
3613 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3615 ZeroMemory(menu
, sizeof(POPUPMENU
));
3616 menu
->wMagic
= MENU_MAGIC
;
3617 menu
->FocusedItem
= NO_SELECTED_ITEM
;
3619 TRACE(menu
, "return %04x\n", hMenu
);
3624 /**********************************************************************
3625 * DestroyMenu16 (USER.152)
3627 BOOL16 WINAPI
DestroyMenu16( HMENU16 hMenu
)
3629 return DestroyMenu( hMenu
);
3633 /**********************************************************************
3634 * DestroyMenu32 (USER32.134)
3636 BOOL WINAPI
DestroyMenu( HMENU hMenu
)
3638 TRACE(menu
,"(%04x)\n", hMenu
);
3640 /* Silently ignore attempts to destroy default system popup */
3642 if (hMenu
&& hMenu
!= MENU_DefSysPopup
)
3644 LPPOPUPMENU lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3645 WND
*pTPWnd
= MENU_GetTopPopupWnd();
3647 if( pTPWnd
&& (hMenu
== *(HMENU
*)pTPWnd
->wExtra
) )
3648 *(UINT
*)pTPWnd
->wExtra
= 0;
3650 if (IS_A_MENU( lppop
))
3652 lppop
->wMagic
= 0; /* Mark it as destroyed */
3654 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
&&
3655 (!pTPWnd
|| (lppop
->hWnd
!= pTPWnd
->hwndSelf
)))
3656 DestroyWindow( lppop
->hWnd
);
3658 if (lppop
->items
) /* recursively destroy submenus */
3661 MENUITEM
*item
= lppop
->items
;
3662 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
3664 if (item
->fType
& MF_POPUP
) DestroyMenu(item
->hSubMenu
);
3665 MENU_FreeItemData( item
);
3667 HeapFree( SystemHeap
, 0, lppop
->items
);
3669 USER_HEAP_FREE( hMenu
);
3670 MENU_ReleaseTopPopupWnd();
3674 MENU_ReleaseTopPopupWnd();
3678 return (hMenu
!= MENU_DefSysPopup
);
3682 /**********************************************************************
3683 * GetSystemMenu16 (USER.156)
3685 HMENU16 WINAPI
GetSystemMenu16( HWND16 hWnd
, BOOL16 bRevert
)
3687 return GetSystemMenu( hWnd
, bRevert
);
3691 /**********************************************************************
3692 * GetSystemMenu32 (USER32.291)
3694 HMENU WINAPI
GetSystemMenu( HWND hWnd
, BOOL bRevert
)
3696 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
3700 if( wndPtr
->hSysMenu
)
3704 DestroyMenu(wndPtr
->hSysMenu
);
3705 wndPtr
->hSysMenu
= 0;
3709 POPUPMENU
*menu
= (POPUPMENU
*)
3710 USER_HEAP_LIN_ADDR(wndPtr
->hSysMenu
);
3711 if( menu
->items
[0].hSubMenu
== MENU_DefSysPopup
)
3712 menu
->items
[0].hSubMenu
= MENU_CopySysPopup();
3716 if(!wndPtr
->hSysMenu
&& (wndPtr
->dwStyle
& WS_SYSMENU
) )
3717 wndPtr
->hSysMenu
= MENU_GetSysMenu( hWnd
, (HMENU
)(-1) );
3719 if( wndPtr
->hSysMenu
)
3721 HMENU retvalue
= GetSubMenu16(wndPtr
->hSysMenu
, 0);
3722 WIN_ReleaseWndPtr(wndPtr
);
3725 WIN_ReleaseWndPtr(wndPtr
);
3731 /*******************************************************************
3732 * SetSystemMenu16 (USER.280)
3734 BOOL16 WINAPI
SetSystemMenu16( HWND16 hwnd
, HMENU16 hMenu
)
3736 return SetSystemMenu( hwnd
, hMenu
);
3740 /*******************************************************************
3741 * SetSystemMenu32 (USER32.508)
3743 BOOL WINAPI
SetSystemMenu( HWND hwnd
, HMENU hMenu
)
3745 WND
*wndPtr
= WIN_FindWndPtr(hwnd
);
3749 if (wndPtr
->hSysMenu
) DestroyMenu( wndPtr
->hSysMenu
);
3750 wndPtr
->hSysMenu
= MENU_GetSysMenu( hwnd
, hMenu
);
3751 WIN_ReleaseWndPtr(wndPtr
);
3758 /**********************************************************************
3759 * GetMenu16 (USER.157)
3761 HMENU16 WINAPI
GetMenu16( HWND16 hWnd
)
3764 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
3765 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
3767 retvalue
= (HMENU16
)wndPtr
->wIDmenu
;
3772 WIN_ReleaseWndPtr(wndPtr
);
3777 /**********************************************************************
3778 * GetMenu32 (USER32.257)
3780 HMENU WINAPI
GetMenu( HWND hWnd
)
3783 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
3784 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
3786 retvalue
= (HMENU
)wndPtr
->wIDmenu
;
3791 WIN_ReleaseWndPtr(wndPtr
);
3796 /**********************************************************************
3797 * SetMenu16 (USER.158)
3799 BOOL16 WINAPI
SetMenu16( HWND16 hWnd
, HMENU16 hMenu
)
3801 return SetMenu( hWnd
, hMenu
);
3805 /**********************************************************************
3806 * SetMenu32 (USER32.487)
3808 BOOL WINAPI
SetMenu( HWND hWnd
, HMENU hMenu
)
3810 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
3812 TRACE(menu
,"(%04x, %04x);\n", hWnd
, hMenu
);
3814 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
3816 if (GetCapture() == hWnd
) ReleaseCapture();
3818 wndPtr
->wIDmenu
= (UINT
)hMenu
;
3823 if (!(lpmenu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
)))
3825 WIN_ReleaseWndPtr(wndPtr
);
3828 lpmenu
->hWnd
= hWnd
;
3829 lpmenu
->wFlags
&= ~MF_POPUP
; /* Can't be a popup */
3830 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
3832 if (IsWindowVisible(hWnd
))
3833 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3834 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3835 WIN_ReleaseWndPtr(wndPtr
);
3838 WIN_ReleaseWndPtr(wndPtr
);
3844 /**********************************************************************
3845 * GetSubMenu16 (USER.159)
3847 HMENU16 WINAPI
GetSubMenu16( HMENU16 hMenu
, INT16 nPos
)
3849 return GetSubMenu( hMenu
, nPos
);
3853 /**********************************************************************
3854 * GetSubMenu32 (USER32.288)
3856 HMENU WINAPI
GetSubMenu( HMENU hMenu
, INT nPos
)
3860 if (!(lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return 0;
3861 if ((UINT
)nPos
>= lppop
->nItems
) return 0;
3862 if (!(lppop
->items
[nPos
].fType
& MF_POPUP
)) return 0;
3863 return lppop
->items
[nPos
].hSubMenu
;
3867 /**********************************************************************
3868 * DrawMenuBar16 (USER.160)
3870 void WINAPI
DrawMenuBar16( HWND16 hWnd
)
3872 DrawMenuBar( hWnd
);
3876 /**********************************************************************
3877 * DrawMenuBar (USER32.161)
3879 BOOL WINAPI
DrawMenuBar( HWND hWnd
)
3882 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
3883 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
) && wndPtr
->wIDmenu
)
3885 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR((HMENU16
)wndPtr
->wIDmenu
);
3888 WIN_ReleaseWndPtr(wndPtr
);
3892 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
3893 lppop
->hwndOwner
= hWnd
;
3894 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
3895 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
3896 WIN_ReleaseWndPtr(wndPtr
);
3899 WIN_ReleaseWndPtr(wndPtr
);
3904 /***********************************************************************
3905 * EndMenu (USER.187) (USER32.175)
3907 void WINAPI
EndMenu(void)
3910 * FIXME: NOT ENOUGH! This has to cancel menu tracking right away.
3917 /***********************************************************************
3918 * LookupMenuHandle (USER.217)
3920 HMENU16 WINAPI
LookupMenuHandle16( HMENU16 hmenu
, INT16 id
)
3922 HMENU hmenu32
= hmenu
;
3924 if (!MENU_FindItem( &hmenu32
, &id32
, MF_BYCOMMAND
)) return 0;
3925 else return hmenu32
;
3929 /**********************************************************************
3930 * LoadMenu16 (USER.150)
3932 HMENU16 WINAPI
LoadMenu16( HINSTANCE16 instance
, SEGPTR name
)
3940 char *str
= (char *)PTR_SEG_TO_LIN( name
);
3941 TRACE(menu
, "(%04x,'%s')\n", instance
, str
);
3942 if (str
[0] == '#') name
= (SEGPTR
)atoi( str
+ 1 );
3945 TRACE(menu
,"(%04x,%04x)\n",instance
,LOWORD(name
));
3947 if (!name
) return 0;
3949 /* check for Win32 module */
3950 if (HIWORD(instance
))
3951 return LoadMenuA(instance
,PTR_SEG_TO_LIN(name
));
3952 instance
= GetExePtr( instance
);
3954 if (!(hRsrc
= FindResource16( instance
, name
, RT_MENU16
))) return 0;
3955 if (!(handle
= LoadResource16( instance
, hRsrc
))) return 0;
3956 hMenu
= LoadMenuIndirect16(LockResource16(handle
));
3957 FreeResource16( handle
);
3962 /*****************************************************************
3963 * LoadMenu32A (USER32.370)
3965 HMENU WINAPI
LoadMenuA( HINSTANCE instance
, LPCSTR name
)
3967 HRSRC hrsrc
= FindResourceA( instance
, name
, RT_MENUA
);
3968 if (!hrsrc
) return 0;
3969 return LoadMenuIndirectA( (LPCVOID
)LoadResource( instance
, hrsrc
));
3973 /*****************************************************************
3974 * LoadMenu32W (USER32.373)
3976 HMENU WINAPI
LoadMenuW( HINSTANCE instance
, LPCWSTR name
)
3978 HRSRC hrsrc
= FindResourceW( instance
, name
, RT_MENUW
);
3979 if (!hrsrc
) return 0;
3980 return LoadMenuIndirectW( (LPCVOID
)LoadResource( instance
, hrsrc
));
3984 /**********************************************************************
3985 * LoadMenuIndirect16 (USER.220)
3987 HMENU16 WINAPI
LoadMenuIndirect16( LPCVOID
template )
3990 WORD version
, offset
;
3991 LPCSTR p
= (LPCSTR
)template;
3993 TRACE(menu
,"(%p)\n", template );
3994 version
= GET_WORD(p
);
3998 WARN(menu
, "version must be 0 for Win16\n" );
4001 offset
= GET_WORD(p
);
4002 p
+= sizeof(WORD
) + offset
;
4003 if (!(hMenu
= CreateMenu())) return 0;
4004 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
4006 DestroyMenu( hMenu
);
4013 /**********************************************************************
4014 * LoadMenuIndirect32A (USER32.371)
4016 HMENU WINAPI
LoadMenuIndirectA( LPCVOID
template )
4019 WORD version
, offset
;
4020 LPCSTR p
= (LPCSTR
)template;
4022 TRACE(menu
,"%p\n", template );
4023 version
= GET_WORD(p
);
4028 offset
= GET_WORD(p
);
4029 p
+= sizeof(WORD
) + offset
;
4030 if (!(hMenu
= CreateMenu())) return 0;
4031 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
4033 DestroyMenu( hMenu
);
4038 offset
= GET_WORD(p
);
4039 p
+= sizeof(WORD
) + offset
;
4040 if (!(hMenu
= CreateMenu())) return 0;
4041 if (!MENUEX_ParseResource( p
, hMenu
))
4043 DestroyMenu( hMenu
);
4048 ERR(menu
, "version %d not supported.\n", version
);
4054 /**********************************************************************
4055 * LoadMenuIndirect32W (USER32.372)
4057 HMENU WINAPI
LoadMenuIndirectW( LPCVOID
template )
4059 /* FIXME: is there anything different between A and W? */
4060 return LoadMenuIndirectA( template );
4064 /**********************************************************************
4065 * IsMenu16 (USER.358)
4067 BOOL16 WINAPI
IsMenu16( HMENU16 hmenu
)
4069 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
4070 return IS_A_MENU(menu
);
4074 /**********************************************************************
4075 * IsMenu32 (USER32.346)
4077 BOOL WINAPI
IsMenu(HMENU hmenu
)
4079 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
4080 return IS_A_MENU(menu
);
4083 /**********************************************************************
4084 * GetMenuItemInfo32_common
4087 static BOOL
GetMenuItemInfo_common ( HMENU hmenu
, UINT item
, BOOL bypos
,
4088 LPMENUITEMINFOA lpmii
, BOOL unicode
)
4090 MENUITEM
*menu
= MENU_FindItem (&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0);
4092 debug_print_menuitem("GetMenuItemInfo32_common: ", menu
, "");
4097 if (lpmii
->fMask
& MIIM_TYPE
) {
4098 lpmii
->fType
= menu
->fType
;
4099 switch (MENU_ITEM_TYPE(menu
->fType
)) {
4101 if (menu
->text
&& lpmii
->dwTypeData
&& lpmii
->cch
) {
4103 lstrcpynAtoW((LPWSTR
) lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4104 lpmii
->cch
= lstrlenW((LPWSTR
)menu
->text
);
4106 lstrcpynA(lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4107 lpmii
->cch
= lstrlenA(menu
->text
);
4113 lpmii
->dwTypeData
= menu
->text
;
4120 if (lpmii
->fMask
& MIIM_STRING
) {
4122 lstrcpynAtoW((LPWSTR
) lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4123 lpmii
->cch
= lstrlenW((LPWSTR
)menu
->text
);
4125 lstrcpynA(lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4126 lpmii
->cch
= lstrlenA(menu
->text
);
4130 if (lpmii
->fMask
& MIIM_FTYPE
)
4131 lpmii
->fType
= menu
->fType
;
4133 if (lpmii
->fMask
& MIIM_BITMAP
)
4134 lpmii
->hbmpItem
= menu
->hbmpItem
;
4136 if (lpmii
->fMask
& MIIM_STATE
)
4137 lpmii
->fState
= menu
->fState
;
4139 if (lpmii
->fMask
& MIIM_ID
)
4140 lpmii
->wID
= menu
->wID
;
4142 if (lpmii
->fMask
& MIIM_SUBMENU
)
4143 lpmii
->hSubMenu
= menu
->hSubMenu
;
4145 if (lpmii
->fMask
& MIIM_CHECKMARKS
) {
4146 lpmii
->hbmpChecked
= menu
->hCheckBit
;
4147 lpmii
->hbmpUnchecked
= menu
->hUnCheckBit
;
4149 if (lpmii
->fMask
& MIIM_DATA
)
4150 lpmii
->dwItemData
= menu
->dwItemData
;
4155 /**********************************************************************
4156 * GetMenuItemInfoA (USER32.264)
4158 BOOL WINAPI
GetMenuItemInfoA( HMENU hmenu
, UINT item
, BOOL bypos
,
4159 LPMENUITEMINFOA lpmii
)
4161 return GetMenuItemInfo_common (hmenu
, item
, bypos
, lpmii
, FALSE
);
4164 /**********************************************************************
4165 * GetMenuItemInfoW (USER32.265)
4167 BOOL WINAPI
GetMenuItemInfoW( HMENU hmenu
, UINT item
, BOOL bypos
,
4168 LPMENUITEMINFOW lpmii
)
4170 return GetMenuItemInfo_common (hmenu
, item
, bypos
,
4171 (LPMENUITEMINFOA
)lpmii
, TRUE
);
4174 /**********************************************************************
4175 * SetMenuItemInfo32_common
4178 static BOOL
SetMenuItemInfo_common(MENUITEM
* menu
,
4179 const MENUITEMINFOA
*lpmii
,
4182 if (!menu
) return FALSE
;
4184 if (lpmii
->fMask
& MIIM_TYPE
) {
4185 /* Get rid of old string. */
4186 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4187 HeapFree(SystemHeap
, 0, menu
->text
);
4191 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4192 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4193 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4195 menu
->text
= lpmii
->dwTypeData
;
4197 if (IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4199 menu
->text
= HEAP_strdupWtoA(SystemHeap
, 0, (LPWSTR
) lpmii
->dwTypeData
);
4201 menu
->text
= HEAP_strdupA(SystemHeap
, 0, lpmii
->dwTypeData
);
4205 if (lpmii
->fMask
& MIIM_FTYPE
) {
4206 /* free the string when the type is changing */
4207 if ( (!IS_STRING_ITEM(lpmii
->fType
)) && IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4208 HeapFree(SystemHeap
, 0, menu
->text
);
4211 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4212 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4215 if (lpmii
->fMask
& MIIM_STRING
) {
4216 /* free the string when used */
4217 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4218 HeapFree(SystemHeap
, 0, menu
->text
);
4220 menu
->text
= HEAP_strdupWtoA(SystemHeap
, 0, (LPWSTR
) lpmii
->dwTypeData
);
4222 menu
->text
= HEAP_strdupA(SystemHeap
, 0, lpmii
->dwTypeData
);
4226 if (lpmii
->fMask
& MIIM_STATE
)
4227 menu
->fState
= lpmii
->fState
;
4229 if (lpmii
->fMask
& MIIM_ID
)
4230 menu
->wID
= lpmii
->wID
;
4232 if (lpmii
->fMask
& MIIM_SUBMENU
) {
4233 menu
->hSubMenu
= lpmii
->hSubMenu
;
4234 if (menu
->hSubMenu
) {
4235 POPUPMENU
*subMenu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR((UINT16
)menu
->hSubMenu
);
4236 if (IS_A_MENU(subMenu
)) {
4237 subMenu
->wFlags
|= MF_POPUP
;
4238 menu
->fType
|= MF_POPUP
;
4241 /* FIXME: Return an error ? */
4242 menu
->fType
&= ~MF_POPUP
;
4245 menu
->fType
&= ~MF_POPUP
;
4248 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
4250 menu
->hCheckBit
= lpmii
->hbmpChecked
;
4251 menu
->hUnCheckBit
= lpmii
->hbmpUnchecked
;
4253 if (lpmii
->fMask
& MIIM_DATA
)
4254 menu
->dwItemData
= lpmii
->dwItemData
;
4256 debug_print_menuitem("SetMenuItemInfo32_common: ", menu
, "");
4260 /**********************************************************************
4261 * SetMenuItemInfo32A (USER32.491)
4263 BOOL WINAPI
SetMenuItemInfoA(HMENU hmenu
, UINT item
, BOOL bypos
,
4264 const MENUITEMINFOA
*lpmii
)
4266 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4270 /**********************************************************************
4271 * SetMenuItemInfo32W (USER32.492)
4273 BOOL WINAPI
SetMenuItemInfoW(HMENU hmenu
, UINT item
, BOOL bypos
,
4274 const MENUITEMINFOW
*lpmii
)
4276 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4277 (const MENUITEMINFOA
*)lpmii
, TRUE
);
4280 /**********************************************************************
4281 * SetMenuDefaultItem32 (USER32.489)
4283 BOOL WINAPI
SetMenuDefaultItem(HMENU hmenu
, UINT item
, UINT bypos
)
4285 MENUITEM
*menuitem
= MENU_FindItem(&hmenu
, &item
, bypos
);
4288 if (!menuitem
) return FALSE
;
4289 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hmenu
))) return FALSE
;
4291 menu
->defitem
= item
; /* position */
4293 debug_print_menuitem("SetMenuDefaultItem32: ", menuitem
, "");
4294 FIXME(menu
, "(0x%x,%d,%d), empty stub!\n",
4295 hmenu
, item
, bypos
);
4299 /**********************************************************************
4300 * GetMenuDefaultItem32 (USER32.260)
4302 UINT WINAPI
GetMenuDefaultItem(HMENU hmenu
, UINT bypos
, UINT flags
)
4306 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hmenu
)))
4309 FIXME(menu
, "(0x%x,%d,%d), stub!\n", hmenu
, bypos
, flags
);
4310 if (bypos
& MF_BYPOSITION
)
4311 return menu
->defitem
;
4313 FIXME (menu
, "default item 0x%x\n", menu
->defitem
);
4314 if ((menu
->defitem
> 0) && (menu
->defitem
< menu
->nItems
))
4315 return menu
->items
[menu
->defitem
].wID
;
4320 /*******************************************************************
4321 * InsertMenuItem16 (USER.441)
4325 BOOL16 WINAPI
InsertMenuItem16( HMENU16 hmenu
, UINT16 pos
, BOOL16 byposition
,
4326 const MENUITEMINFO16
*mii
)
4330 miia
.cbSize
= sizeof(miia
);
4331 miia
.fMask
= mii
->fMask
;
4332 miia
.dwTypeData
= mii
->dwTypeData
;
4333 miia
.fType
= mii
->fType
;
4334 miia
.fState
= mii
->fState
;
4335 miia
.wID
= mii
->wID
;
4336 miia
.hSubMenu
= mii
->hSubMenu
;
4337 miia
.hbmpChecked
= mii
->hbmpChecked
;
4338 miia
.hbmpUnchecked
= mii
->hbmpUnchecked
;
4339 miia
.dwItemData
= mii
->dwItemData
;
4340 miia
.cch
= mii
->cch
;
4341 if (IS_STRING_ITEM(miia
.fType
))
4342 miia
.dwTypeData
= PTR_SEG_TO_LIN(miia
.dwTypeData
);
4343 return InsertMenuItemA( hmenu
, pos
, byposition
, &miia
);
4347 /**********************************************************************
4348 * InsertMenuItem32A (USER32.323)
4350 BOOL WINAPI
InsertMenuItemA(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4351 const MENUITEMINFOA
*lpmii
)
4353 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4354 return SetMenuItemInfo_common(item
, lpmii
, FALSE
);
4358 /**********************************************************************
4359 * InsertMenuItem32W (USER32.324)
4361 BOOL WINAPI
InsertMenuItemW(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4362 const MENUITEMINFOW
*lpmii
)
4364 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4365 return SetMenuItemInfo_common(item
, (const MENUITEMINFOA
*)lpmii
, TRUE
);
4368 /**********************************************************************
4369 * CheckMenuRadioItem32 (USER32.47)
4372 BOOL WINAPI
CheckMenuRadioItem(HMENU hMenu
,
4373 UINT first
, UINT last
, UINT check
,
4376 MENUITEM
*mifirst
, *milast
, *micheck
;
4377 HMENU mfirst
= hMenu
, mlast
= hMenu
, mcheck
= hMenu
;
4379 TRACE(menu
, "ox%x: %d-%d, check %d, bypos=%d\n",
4380 hMenu
, first
, last
, check
, bypos
);
4382 mifirst
= MENU_FindItem (&mfirst
, &first
, bypos
);
4383 milast
= MENU_FindItem (&mlast
, &last
, bypos
);
4384 micheck
= MENU_FindItem (&mcheck
, &check
, bypos
);
4386 if (mifirst
== NULL
|| milast
== NULL
|| micheck
== NULL
||
4387 mifirst
> milast
|| mfirst
!= mlast
|| mfirst
!= mcheck
||
4388 micheck
> milast
|| micheck
< mifirst
)
4391 while (mifirst
<= milast
)
4393 if (mifirst
== micheck
)
4395 mifirst
->fType
|= MFT_RADIOCHECK
;
4396 mifirst
->fState
|= MFS_CHECKED
;
4398 mifirst
->fType
&= ~MFT_RADIOCHECK
;
4399 mifirst
->fState
&= ~MFS_CHECKED
;
4407 /**********************************************************************
4408 * CheckMenuRadioItem16 (not a Windows API)
4411 BOOL16 WINAPI
CheckMenuRadioItem16(HMENU16 hMenu
,
4412 UINT16 first
, UINT16 last
, UINT16 check
,
4415 return CheckMenuRadioItem (hMenu
, first
, last
, check
, bypos
);
4418 /**********************************************************************
4419 * GetMenuItemRect32 (USER32.266)
4421 * ATTENTION: Here, the returned values in rect are the screen
4422 * coordinates of the item just like if the menu was
4423 * always on the upper left side of the application.
4426 BOOL WINAPI
GetMenuItemRect (HWND hwnd
, HMENU hMenu
, UINT uItem
,
4429 POPUPMENU
*itemMenu
;
4433 TRACE(menu
, "(0x%x,0x%x,%d,%p)\n", hwnd
, hMenu
, uItem
, rect
);
4435 item
= MENU_FindItem (&hMenu
, &uItem
, MF_BYPOSITION
);
4436 referenceHwnd
= hwnd
;
4440 itemMenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
4441 if (itemMenu
== NULL
)
4444 if(itemMenu
->hWnd
== 0)
4446 referenceHwnd
= itemMenu
->hWnd
;
4449 if ((rect
== NULL
) || (item
== NULL
))
4454 MapWindowPoints(referenceHwnd
, 0, (LPPOINT
)rect
, 2);
4459 /**********************************************************************
4460 * GetMenuItemRect16 (USER.665)
4463 BOOL16 WINAPI
GetMenuItemRect16 (HWND16 hwnd
, HMENU16 hMenu
, UINT16 uItem
,
4469 if (!rect
) return FALSE
;
4470 res
= GetMenuItemRect (hwnd
, hMenu
, uItem
, &r32
);
4471 CONV_RECT32TO16 (&r32
, rect
);
4475 /**********************************************************************
4479 * MIM_APPLYTOSUBMENUS
4480 * actually use the items to draw the menu
4482 BOOL WINAPI
SetMenuInfo (HMENU hMenu
, LPCMENUINFO lpmi
)
4486 TRACE(menu
,"(0x%04x %p)\n", hMenu
, lpmi
);
4488 if (lpmi
&& (lpmi
->cbSize
==sizeof(MENUINFO
)) && (menu
=(POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
)))
4491 if (lpmi
->fMask
& MIM_BACKGROUND
)
4492 menu
->hbrBack
= lpmi
->hbrBack
;
4494 if (lpmi
->fMask
& MIM_HELPID
)
4495 menu
->dwContextHelpID
= lpmi
->dwContextHelpID
;
4497 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4498 menu
->cyMax
= lpmi
->cyMax
;
4500 if (lpmi
->fMask
& MIM_MENUDATA
)
4501 menu
->dwMenuData
= lpmi
->dwMenuData
;
4503 if (lpmi
->fMask
& MIM_STYLE
)
4504 menu
->dwStyle
= lpmi
->dwStyle
;
4511 /**********************************************************************
4518 BOOL WINAPI
GetMenuInfo (HMENU hMenu
, LPMENUINFO lpmi
)
4521 TRACE(menu
,"(0x%04x %p)\n", hMenu
, lpmi
);
4523 if (lpmi
&& (menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
)))
4526 if (lpmi
->fMask
& MIM_BACKGROUND
)
4527 lpmi
->hbrBack
= menu
->hbrBack
;
4529 if (lpmi
->fMask
& MIM_HELPID
)
4530 lpmi
->dwContextHelpID
= menu
->dwContextHelpID
;
4532 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4533 lpmi
->cyMax
= menu
->cyMax
;
4535 if (lpmi
->fMask
& MIM_MENUDATA
)
4536 lpmi
->dwMenuData
= menu
->dwMenuData
;
4538 if (lpmi
->fMask
& MIM_STYLE
)
4539 lpmi
->dwStyle
= menu
->dwStyle
;
4546 /**********************************************************************
4547 * SetMenuContextHelpId16 (USER.384)
4549 BOOL16 WINAPI
SetMenuContextHelpId16( HMENU16 hMenu
, DWORD dwContextHelpID
)
4551 return SetMenuContextHelpId( hMenu
, dwContextHelpID
);
4555 /**********************************************************************
4556 * SetMenuContextHelpId (USER32.488)
4558 BOOL WINAPI
SetMenuContextHelpId( HMENU hMenu
, DWORD dwContextHelpID
)
4562 TRACE(menu
,"(0x%04x 0x%08lx)\n", hMenu
, dwContextHelpID
);
4564 if ((menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
)))
4566 menu
->dwContextHelpID
= dwContextHelpID
;
4572 /**********************************************************************
4573 * GetMenuContextHelpId16 (USER.385)
4575 DWORD WINAPI
GetMenuContextHelpId16( HMENU16 hMenu
)
4577 return GetMenuContextHelpId( hMenu
);
4580 /**********************************************************************
4581 * GetMenuContextHelpId (USER32.488)
4583 DWORD WINAPI
GetMenuContextHelpId( HMENU hMenu
)
4587 TRACE(menu
,"(0x%04x)\n", hMenu
);
4589 if ((menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
)))
4591 return menu
->dwContextHelpID
;