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.
22 #include "wine/winbase16.h"
23 #include "wine/winuser16.h"
28 #include "nonclient.h"
34 #include "debugtools.h"
36 DEFAULT_DEBUG_CHANNEL(menu
)
39 /* internal popup menu window messages */
41 #define MM_SETMENUHANDLE (WM_USER + 0)
42 #define MM_GETMENUHANDLE (WM_USER + 1)
44 /* Menu item structure */
46 /* ----------- MENUITEMINFO Stuff ----------- */
47 UINT fType
; /* Item type. */
48 UINT fState
; /* Item state. */
49 UINT wID
; /* Item id. */
50 HMENU hSubMenu
; /* Pop-up menu. */
51 HBITMAP hCheckBit
; /* Bitmap when checked. */
52 HBITMAP hUnCheckBit
; /* Bitmap when unchecked. */
53 LPSTR text
; /* Item text or bitmap handle. */
54 DWORD dwItemData
; /* Application defined. */
55 DWORD dwTypeData
; /* depends on fMask */
56 HBITMAP hbmpItem
; /* bitmap in win98 style menus */
57 /* ----------- Wine stuff ----------- */
58 RECT rect
; /* Item area (relative to menu window) */
59 UINT xTab
; /* X position of text after Tab */
62 /* Popup menu structure */
64 WORD wFlags
; /* Menu flags (MF_POPUP, MF_SYSMENU) */
65 WORD wMagic
; /* Magic number */
66 HQUEUE16 hTaskQ
; /* Task queue for this menu */
67 WORD Width
; /* Width of the whole menu */
68 WORD Height
; /* Height of the whole menu */
69 WORD nItems
; /* Number of items in the menu */
70 HWND hWnd
; /* Window containing the menu */
71 MENUITEM
*items
; /* Array of menu items */
72 UINT FocusedItem
; /* Currently focused item */
73 HWND hwndOwner
; /* window receiving the messages for ownerdraw */
74 BOOL bTimeToHide
; /* Request hiding when receiving a second click in the top-level menu item */
75 /* ------------ MENUINFO members ------ */
76 DWORD dwStyle
; /* Extended mennu style */
77 UINT cyMax
; /* max hight of the whole menu, 0 is screen hight */
78 HBRUSH hbrBack
; /* brush for menu background */
79 DWORD dwContextHelpID
;
80 DWORD dwMenuData
; /* application defined value */
81 HMENU hSysMenuOwner
; /* Handle to the dummy sys menu holder */
82 } POPUPMENU
, *LPPOPUPMENU
;
84 /* internal flags for menu tracking */
86 #define TF_ENDMENU 0x0001
87 #define TF_SUSPENDPOPUP 0x0002
88 #define TF_SKIPREMOVE 0x0004
93 HMENU hCurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
94 HMENU hTopMenu
; /* initial menu */
95 HWND hOwnerWnd
; /* where notifications are sent */
99 #define MENU_MAGIC 0x554d /* 'MU' */
100 #define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
105 /* Internal MENU_TrackMenu() flags */
106 #define TPM_INTERNAL 0xF0000000
107 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
108 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
109 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
111 /* popup menu shade thickness */
112 #define POPUP_XSHADE 4
113 #define POPUP_YSHADE 4
115 /* Space between 2 menu bar items */
116 #define MENU_BAR_ITEMS_SPACE 12
118 /* Minimum width of a tab character */
119 #define MENU_TAB_SPACE 8
121 /* Height of a separator item */
122 #define SEPARATOR_HEIGHT 5
124 /* (other menu->FocusedItem values give the position of the focused item) */
125 #define NO_SELECTED_ITEM 0xffff
127 #define MENU_ITEM_TYPE(flags) \
128 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
130 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
131 #define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
133 #define IS_SYSTEM_MENU(menu) \
134 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
136 #define IS_SYSTEM_POPUP(menu) \
137 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
139 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
140 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
141 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
142 MF_POPUP | MF_SYSMENU | MF_HELP)
143 #define STATE_MASK (~TYPE_MASK)
145 /* Dimension of the menu bitmaps */
146 static WORD check_bitmap_width
= 0, check_bitmap_height
= 0;
147 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
149 static HBITMAP hStdRadioCheck
= 0;
150 static HBITMAP hStdCheck
= 0;
151 static HBITMAP hStdMnArrow
= 0;
153 /* Minimze/restore/close buttons to be inserted in menubar */
154 static HBITMAP hBmpMinimize
= 0;
155 static HBITMAP hBmpMinimizeD
= 0;
156 static HBITMAP hBmpMaximize
= 0;
157 static HBITMAP hBmpMaximizeD
= 0;
158 static HBITMAP hBmpClose
= 0;
159 static HBITMAP hBmpCloseD
= 0;
162 static HBRUSH hShadeBrush
= 0;
163 static HFONT hMenuFont
= 0;
164 static HFONT hMenuFontBold
= 0;
166 static HMENU MENU_DefSysPopup
= 0; /* Default system menu popup */
168 /* Use global popup window because there's no way 2 menus can
169 * be tracked at the same time. */
171 static WND
* pTopPopupWnd
= 0;
172 static UINT uSubPWndLevel
= 0;
174 /* Flag set by EndMenu() to force an exit from menu tracking */
175 static BOOL fEndMenu
= FALSE
;
178 /***********************************************************************
179 * debug_print_menuitem
181 * Print a menuitem in readable form.
184 #define debug_print_menuitem(pre, mp, post) \
185 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
187 #define MENUOUT(text) \
188 DPRINTF("%s%s", (count++ ? "," : ""), (text))
190 #define MENUFLAG(bit,text) \
192 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
195 static void do_debug_print_menuitem(const char *prefix
, MENUITEM
* mp
,
198 TRACE("%s ", prefix
);
200 UINT flags
= mp
->fType
;
201 int typ
= MENU_ITEM_TYPE(flags
);
202 DPRINTF( "{ ID=0x%x", mp
->wID
);
203 if (flags
& MF_POPUP
)
204 DPRINTF( ", Sub=0x%x", mp
->hSubMenu
);
208 if (typ
== MFT_STRING
)
210 else if (typ
== MFT_SEPARATOR
)
212 else if (typ
== MFT_OWNERDRAW
)
214 else if (typ
== MFT_BITMAP
)
220 MENUFLAG(MF_POPUP
, "pop");
221 MENUFLAG(MFT_MENUBARBREAK
, "barbrk");
222 MENUFLAG(MFT_MENUBREAK
, "brk");
223 MENUFLAG(MFT_RADIOCHECK
, "radio");
224 MENUFLAG(MFT_RIGHTORDER
, "rorder");
225 MENUFLAG(MF_SYSMENU
, "sys");
226 MENUFLAG(MFT_RIGHTJUSTIFY
, "right"); /* same as MF_HELP */
229 DPRINTF( "+0x%x", flags
);
234 DPRINTF( ", State=");
235 MENUFLAG(MFS_GRAYED
, "grey");
236 MENUFLAG(MFS_DEFAULT
, "default");
237 MENUFLAG(MFS_DISABLED
, "dis");
238 MENUFLAG(MFS_CHECKED
, "check");
239 MENUFLAG(MFS_HILITE
, "hi");
240 MENUFLAG(MF_USECHECKBITMAPS
, "usebit");
241 MENUFLAG(MF_MOUSESELECT
, "mouse");
243 DPRINTF( "+0x%x", flags
);
246 DPRINTF( ", Chk=0x%x", mp
->hCheckBit
);
248 DPRINTF( ", Unc=0x%x", mp
->hUnCheckBit
);
250 if (typ
== MFT_STRING
) {
252 DPRINTF( ", Text=\"%s\"", mp
->text
);
254 DPRINTF( ", Text=Null");
255 } else if (mp
->text
== NULL
)
258 DPRINTF( ", Text=%p", mp
->text
);
260 DPRINTF( ", ItemData=0x%08lx", mp
->dwItemData
);
266 DPRINTF(" %s\n", postfix
);
273 /***********************************************************************
276 * Validate the given menu handle and returns the menu structure pointer.
278 POPUPMENU
*MENU_GetMenu(HMENU hMenu
)
281 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
282 if (!IS_A_MENU(menu
))
284 ERR("invalid menu handle=%x, ptr=%p, magic=%x\n", hMenu
, menu
, menu
? menu
->wMagic
:0);
290 /***********************************************************************
293 * Return the default system menu.
295 static HMENU
MENU_CopySysPopup(void)
297 HMENU hMenu
= LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
300 POPUPMENU
* menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
301 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
302 SetMenuDefaultItem(hMenu
, SC_CLOSE
, FALSE
);
306 ERR("Unable to load default system menu\n" );
309 TRACE("returning %x.\n", hMenu
);
314 /***********************************************************************
315 * MENU_GetTopPopupWnd()
317 * Return the locked pointer pTopPopupWnd.
319 static WND
*MENU_GetTopPopupWnd()
321 return WIN_LockWndPtr(pTopPopupWnd
);
323 /***********************************************************************
324 * MENU_ReleaseTopPopupWnd()
326 * Realease the locked pointer pTopPopupWnd.
328 static void MENU_ReleaseTopPopupWnd()
330 WIN_ReleaseWndPtr(pTopPopupWnd
);
332 /***********************************************************************
333 * MENU_DestroyTopPopupWnd()
335 * Destroy the locked pointer pTopPopupWnd.
337 static void MENU_DestroyTopPopupWnd()
339 WND
*tmpWnd
= pTopPopupWnd
;
341 WIN_ReleaseWndPtr(tmpWnd
);
346 /**********************************************************************
349 * Create a copy of the system menu. System menu in Windows is
350 * a special menu-bar with the single entry - system menu popup.
351 * This popup is presented to the outside world as a "system menu".
352 * However, the real system menu handle is sometimes seen in the
353 * WM_MENUSELECT paramemters (and Word 6 likes it this way).
355 HMENU
MENU_GetSysMenu( HWND hWnd
, HMENU hPopupMenu
)
359 if ((hMenu
= CreateMenu()))
361 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
362 menu
->wFlags
= MF_SYSMENU
;
365 if (hPopupMenu
== (HMENU
)(-1))
366 hPopupMenu
= MENU_CopySysPopup();
367 else if( !hPopupMenu
) hPopupMenu
= MENU_DefSysPopup
;
371 InsertMenuA( hMenu
, -1, MF_SYSMENU
| MF_POPUP
| MF_BYPOSITION
, hPopupMenu
, NULL
);
373 menu
->items
[0].fType
= MF_SYSMENU
| MF_POPUP
;
374 menu
->items
[0].fState
= 0;
375 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hPopupMenu
);
376 menu
->wFlags
|= MF_SYSMENU
;
378 TRACE("GetSysMenu hMenu=%04x (%04x)\n", hMenu
, hPopupMenu
);
381 DestroyMenu( hMenu
);
383 ERR("failed to load system menu!\n");
388 /***********************************************************************
391 * Menus initialisation.
396 NONCLIENTMETRICSA ncm
;
398 static unsigned char shade_bits
[16] = { 0x55, 0, 0xAA, 0,
403 /* Load menu bitmaps */
404 hStdCheck
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CHECK
));
405 hStdRadioCheck
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_RADIOCHECK
));
406 hStdMnArrow
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW
));
407 /* Load system buttons bitmaps */
408 hBmpMinimize
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCE
));
409 hBmpMinimizeD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCED
));
410 hBmpMaximize
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORE
));
411 hBmpMaximizeD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORED
));
412 hBmpClose
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSE
));
413 hBmpCloseD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSED
));
418 GetObjectA( hStdCheck
, sizeof(bm
), &bm
);
419 check_bitmap_width
= bm
.bmWidth
;
420 check_bitmap_height
= bm
.bmHeight
;
424 /* Assume that radio checks have the same size as regular check. */
431 GetObjectA( hStdMnArrow
, sizeof(bm
), &bm
);
432 arrow_bitmap_width
= bm
.bmWidth
;
433 arrow_bitmap_height
= bm
.bmHeight
;
437 if (! (hBitmap
= CreateBitmap( 8, 8, 1, 1, shade_bits
)))
440 if(!(hShadeBrush
= CreatePatternBrush( hBitmap
)))
443 DeleteObject( hBitmap
);
444 if (!(MENU_DefSysPopup
= MENU_CopySysPopup()))
447 ncm
.cbSize
= sizeof (NONCLIENTMETRICSA
);
448 if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS
, sizeof(NONCLIENTMETRICSA
), &ncm
, 0)))
451 if (!(hMenuFont
= CreateFontIndirectA( &ncm
.lfMenuFont
)))
454 ncm
.lfMenuFont
.lfWeight
+= 300;
455 if ( ncm
.lfMenuFont
.lfWeight
> 1000)
456 ncm
.lfMenuFont
.lfWeight
= 1000;
458 if (!(hMenuFontBold
= CreateFontIndirectA( &ncm
.lfMenuFont
)))
464 /***********************************************************************
465 * MENU_InitSysMenuPopup
467 * Grey the appropriate items in System menu.
469 static void MENU_InitSysMenuPopup( HMENU hmenu
, DWORD style
, DWORD clsStyle
)
473 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
474 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
475 gray
= ((style
& WS_MAXIMIZE
) != 0);
476 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
477 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
478 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
479 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
480 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
481 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
482 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
483 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
485 /* The menu item must keep its state if it's disabled */
487 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
491 /******************************************************************************
493 * UINT MENU_GetStartOfNextColumn(
496 *****************************************************************************/
498 static UINT
MENU_GetStartOfNextColumn(
501 POPUPMENU
*menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
502 UINT i
= menu
->FocusedItem
+ 1;
505 return NO_SELECTED_ITEM
;
507 if( i
== NO_SELECTED_ITEM
)
510 for( ; i
< menu
->nItems
; ++i
) {
511 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
515 return NO_SELECTED_ITEM
;
519 /******************************************************************************
521 * UINT MENU_GetStartOfPrevColumn(
524 *****************************************************************************/
526 static UINT
MENU_GetStartOfPrevColumn(
529 POPUPMENU
const *menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
533 return NO_SELECTED_ITEM
;
535 if( menu
->FocusedItem
== 0 || menu
->FocusedItem
== NO_SELECTED_ITEM
)
536 return NO_SELECTED_ITEM
;
538 /* Find the start of the column */
540 for(i
= menu
->FocusedItem
; i
!= 0 &&
541 !(menu
->items
[i
].fType
& MF_MENUBARBREAK
);
545 return NO_SELECTED_ITEM
;
547 for(--i
; i
!= 0; --i
) {
548 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
552 TRACE("ret %d.\n", i
);
559 /***********************************************************************
562 * Find a menu item. Return a pointer on the item, and modifies *hmenu
563 * in case the item was in a sub-menu.
565 static MENUITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
570 if (((*hmenu
)==0xffff) || (!(menu
= MENU_GetMenu(*hmenu
)))) return NULL
;
571 if (wFlags
& MF_BYPOSITION
)
573 if (*nPos
>= menu
->nItems
) return NULL
;
574 return &menu
->items
[*nPos
];
578 MENUITEM
*item
= menu
->items
;
579 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
581 if (item
->wID
== *nPos
)
586 else if (item
->fType
& MF_POPUP
)
588 HMENU hsubmenu
= item
->hSubMenu
;
589 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
601 /***********************************************************************
604 * Find a Sub menu. Return the position of the submenu, and modifies
605 * *hmenu in case it is found in another sub-menu.
606 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
608 UINT
MENU_FindSubMenu( HMENU
*hmenu
, HMENU hSubTarget
)
613 if (((*hmenu
)==0xffff) ||
614 (!(menu
= MENU_GetMenu(*hmenu
))))
615 return NO_SELECTED_ITEM
;
617 for (i
= 0; i
< menu
->nItems
; i
++, item
++) {
618 if(!(item
->fType
& MF_POPUP
)) continue;
619 if (item
->hSubMenu
== hSubTarget
) {
623 HMENU hsubmenu
= item
->hSubMenu
;
624 UINT pos
= MENU_FindSubMenu( &hsubmenu
, hSubTarget
);
625 if (pos
!= NO_SELECTED_ITEM
) {
631 return NO_SELECTED_ITEM
;
634 /***********************************************************************
637 static void MENU_FreeItemData( MENUITEM
* item
)
640 if (IS_STRING_ITEM(item
->fType
) && item
->text
)
641 HeapFree( SystemHeap
, 0, item
->text
);
644 /***********************************************************************
645 * MENU_FindItemByCoords
647 * Find the item at the specified coordinates (screen coords). Does
648 * not work for child windows and therefore should not be called for
649 * an arbitrary system menu.
651 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
,
652 POINT pt
, UINT
*pos
)
658 if (!GetWindowRect(menu
->hWnd
,&wrect
)) return NULL
;
659 pt
.x
-= wrect
.left
;pt
.y
-= wrect
.top
;
661 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
663 if ((pt
.x
>= item
->rect
.left
) && (pt
.x
< item
->rect
.right
) &&
664 (pt
.y
>= item
->rect
.top
) && (pt
.y
< item
->rect
.bottom
))
674 /***********************************************************************
677 * Find the menu item selected by a key press.
678 * Return item id, -1 if none, -2 if we should close the menu.
680 static UINT
MENU_FindItemByKey( HWND hwndOwner
, HMENU hmenu
,
681 UINT key
, BOOL forceMenuChar
)
683 TRACE("\tlooking for '%c' in [%04x]\n", (char)key
, (UINT16
)hmenu
);
685 if (!IsMenu( hmenu
))
687 WND
* w
= WIN_FindWndPtr(hwndOwner
);
688 hmenu
= GetSubMenu(w
->hSysMenu
, 0);
689 WIN_ReleaseWndPtr(w
);
694 POPUPMENU
*menu
= MENU_GetMenu( hmenu
);
695 MENUITEM
*item
= menu
->items
;
703 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
705 if (item
->text
&& (IS_STRING_ITEM(item
->fType
)))
707 char *p
= item
->text
- 2;
710 p
= strchr (p
+ 2, '&');
712 while (p
!= NULL
&& p
[1] == '&');
713 if (p
&& (toupper(p
[1]) == key
)) return i
;
717 menuchar
= SendMessageA( hwndOwner
, WM_MENUCHAR
,
718 MAKEWPARAM( key
, menu
->wFlags
), hmenu
);
719 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
720 if (HIWORD(menuchar
) == 1) return (UINT
)(-2);
724 /***********************************************************************
727 * Load the bitmap associated with the magic menu item and its style
730 static HBITMAP
MENU_LoadMagicItem(UINT id
, BOOL hilite
, DWORD dwItemData
)
733 * Magic menu item id's section
734 * These magic id's are used by windows to insert "standard" mdi
735 * buttons (minimize,restore,close) on menu. Under windows,
736 * these magic id's make sure the right things appear when those
737 * bitmap buttons are pressed/selected/released.
741 { case HBMMENU_SYSTEM
:
742 return (dwItemData
) ?
743 (HBITMAP
)dwItemData
:
744 (hilite
? hBmpMinimizeD
: hBmpMinimize
);
745 case HBMMENU_MBAR_RESTORE
:
746 return (hilite
? hBmpMaximizeD
: hBmpMaximize
);
747 case HBMMENU_MBAR_MINIMIZE
:
748 return (hilite
? hBmpMinimizeD
: hBmpMinimize
);
749 case HBMMENU_MBAR_CLOSE
:
750 return (hilite
? hBmpCloseD
: hBmpClose
);
751 case HBMMENU_CALLBACK
:
752 case HBMMENU_MBAR_CLOSE_D
:
753 case HBMMENU_MBAR_MINIMIZE_D
:
754 case HBMMENU_POPUP_CLOSE
:
755 case HBMMENU_POPUP_RESTORE
:
756 case HBMMENU_POPUP_MAXIMIZE
:
757 case HBMMENU_POPUP_MINIMIZE
:
759 FIXME("Magic 0x%08x not implemented\n", id
);
765 /***********************************************************************
768 * Calculate the size of the menu item and store it in lpitem->rect.
770 static void MENU_CalcItemSize( HDC hdc
, MENUITEM
*lpitem
, HWND hwndOwner
,
771 INT orgX
, INT orgY
, BOOL menuBar
)
775 TRACE("dc=0x%04x owner=0x%04x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
776 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem
,
777 (menuBar
? " (MenuBar)" : ""));
779 SetRect( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
781 if (lpitem
->fType
& MF_OWNERDRAW
)
783 MEASUREITEMSTRUCT mis
;
784 mis
.CtlType
= ODT_MENU
;
786 mis
.itemID
= lpitem
->wID
;
787 mis
.itemData
= (DWORD
)lpitem
->dwItemData
;
790 SendMessageA( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
791 lpitem
->rect
.bottom
+= mis
.itemHeight
;
792 lpitem
->rect
.right
+= mis
.itemWidth
;
793 TRACE("id=%04x size=%dx%d\n",
794 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
798 if (lpitem
->fType
& MF_SEPARATOR
)
800 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
806 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
807 if (lpitem
->fType
& MF_POPUP
)
808 lpitem
->rect
.right
+= arrow_bitmap_width
;
811 if (IS_BITMAP_ITEM(lpitem
->fType
))
816 /* Check if there is a magic menu item associated with this item */
817 if((LOWORD((int)lpitem
->text
))<12)
819 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
, (lpitem
->fType
& MF_HILITE
),
823 resBmp
= (HBITMAP
)lpitem
->text
;
825 if (GetObjectA(resBmp
, sizeof(bm
), &bm
))
827 lpitem
->rect
.right
+= bm
.bmWidth
;
828 lpitem
->rect
.bottom
+= bm
.bmHeight
;
834 /* If we get here, then it must be a text item */
835 if (IS_STRING_ITEM( lpitem
->fType
))
838 GetTextExtentPoint32A(hdc
, lpitem
->text
, strlen(lpitem
->text
), &size
);
840 lpitem
->rect
.right
+= size
.cx
;
841 if (TWEAK_WineLook
== WIN31_LOOK
)
842 lpitem
->rect
.bottom
+= max( size
.cy
, GetSystemMetrics(SM_CYMENU
) );
844 lpitem
->rect
.bottom
+= max(size
.cy
, GetSystemMetrics(SM_CYMENU
)-1);
849 lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
851 else if ((p
= strchr( lpitem
->text
, '\t' )) != NULL
)
853 /* Item contains a tab (only meaningful in popup menus) */
854 GetTextExtentPoint32A(hdc
, lpitem
->text
, (int)(p
- lpitem
->text
) , &size
);
855 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+ size
.cx
;
856 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
860 if (strchr( lpitem
->text
, '\b' ))
861 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
862 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
863 - arrow_bitmap_width
;
866 TRACE("(%d,%d)-(%d,%d)\n", lpitem
->rect
.left
, lpitem
->rect
.top
, lpitem
->rect
.right
, lpitem
->rect
.bottom
);
870 /***********************************************************************
871 * MENU_PopupMenuCalcSize
873 * Calculate the size of a popup menu.
875 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND hwndOwner
)
880 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
882 lppop
->Width
= lppop
->Height
= 0;
883 if (lppop
->nItems
== 0) return;
886 SelectObject( hdc
, hMenuFont
);
889 maxX
= (TWEAK_WineLook
== WIN31_LOOK
) ? GetSystemMetrics(SM_CXBORDER
) : 2 ;
891 while (start
< lppop
->nItems
)
893 lpitem
= &lppop
->items
[start
];
895 orgY
= (TWEAK_WineLook
== WIN31_LOOK
) ? GetSystemMetrics(SM_CYBORDER
) : 2;
897 maxTab
= maxTabWidth
= 0;
899 /* Parse items until column break or end of menu */
900 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
903 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
905 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
907 if (lpitem
->fType
& MF_MENUBARBREAK
) orgX
++;
908 maxX
= max( maxX
, lpitem
->rect
.right
);
909 orgY
= lpitem
->rect
.bottom
;
910 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
912 maxTab
= max( maxTab
, lpitem
->xTab
);
913 maxTabWidth
= max(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
917 /* Finish the column (set all items to the largest width found) */
918 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
919 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
921 lpitem
->rect
.right
= maxX
;
922 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
923 lpitem
->xTab
= maxTab
;
926 lppop
->Height
= max( lppop
->Height
, orgY
);
931 /* space for 3d border */
932 if(TWEAK_WineLook
> WIN31_LOOK
)
942 /***********************************************************************
943 * MENU_MenuBarCalcSize
945 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
946 * height is off by 1 pixel which causes lengthy window relocations when
947 * active document window is maximized/restored.
949 * Calculate the size of the menu bar.
951 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
,
952 LPPOPUPMENU lppop
, HWND hwndOwner
)
955 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
957 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
958 if (lppop
->nItems
== 0) return;
959 TRACE("left=%d top=%d right=%d bottom=%d\n",
960 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
961 lppop
->Width
= lprect
->right
- lprect
->left
;
966 while (start
< lppop
->nItems
)
968 lpitem
= &lppop
->items
[start
];
972 /* Parse items until line break or end of menu */
973 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
975 if ((helpPos
== -1) && (lpitem
->fType
& MF_HELP
)) helpPos
= i
;
977 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
979 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
981 debug_print_menuitem (" item: ", lpitem
, "");
982 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
984 if (lpitem
->rect
.right
> lprect
->right
)
986 if (i
!= start
) break;
987 else lpitem
->rect
.right
= lprect
->right
;
989 maxY
= max( maxY
, lpitem
->rect
.bottom
);
990 orgX
= lpitem
->rect
.right
;
993 /* Finish the line (set all items to the largest height found) */
994 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
997 lprect
->bottom
= maxY
;
998 lppop
->Height
= lprect
->bottom
- lprect
->top
;
1000 /* Flush right all magic items and items between the MF_HELP and */
1001 /* the last item (if several lines, only move the last line) */
1002 lpitem
= &lppop
->items
[lppop
->nItems
-1];
1003 orgY
= lpitem
->rect
.top
;
1004 orgX
= lprect
->right
;
1005 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--)
1007 if ( !IS_BITMAP_ITEM(lpitem
->fType
) && ((helpPos
==-1) ? TRUE
: (helpPos
>i
) ))
1009 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
1010 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
1011 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
1012 lpitem
->rect
.right
= orgX
;
1013 orgX
= lpitem
->rect
.left
;
1017 /***********************************************************************
1020 * Draw a single menu item.
1022 static void MENU_DrawMenuItem( HWND hwnd
, HMENU hmenu
, HWND hwndOwner
, HDC hdc
, MENUITEM
*lpitem
,
1023 UINT height
, BOOL menuBar
, UINT odaction
)
1027 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem
, "");
1029 if (lpitem
->fType
& MF_SYSMENU
)
1031 if( !IsIconic(hwnd
) ) {
1032 if (TWEAK_WineLook
> WIN31_LOOK
)
1033 NC_DrawSysButton95( hwnd
, hdc
,
1035 (MF_HILITE
| MF_MOUSESELECT
) );
1037 NC_DrawSysButton( hwnd
, hdc
,
1039 (MF_HILITE
| MF_MOUSESELECT
) );
1045 if (lpitem
->fType
& MF_OWNERDRAW
)
1049 dis
.CtlType
= ODT_MENU
;
1051 dis
.itemID
= lpitem
->wID
;
1052 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1054 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1055 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
;
1056 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1057 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1058 dis
.hwndItem
= hmenu
;
1060 dis
.rcItem
= lpitem
->rect
;
1061 TRACE("Ownerdraw: owner=%04x itemID=%d, itemState=%d, itemAction=%d, "
1062 "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n", hwndOwner
,
1063 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1064 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1066 SendMessageA( hwndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
1070 TRACE("rect={%d,%d,%d,%d}\n", lpitem
->rect
.left
, lpitem
->rect
.top
,
1071 lpitem
->rect
.right
,lpitem
->rect
.bottom
);
1073 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1075 rect
= lpitem
->rect
;
1077 if ((lpitem
->fState
& MF_HILITE
) && !(IS_BITMAP_ITEM(lpitem
->fType
)))
1078 if ((menuBar
) && (TWEAK_WineLook
==WIN98_LOOK
))
1079 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1081 FillRect( hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
) );
1083 FillRect( hdc
, &rect
, GetSysColorBrush(COLOR_MENU
) );
1085 SetBkMode( hdc
, TRANSPARENT
);
1087 /* vertical separator */
1088 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1090 if (TWEAK_WineLook
> WIN31_LOOK
)
1094 rc
.bottom
= height
- 3;
1095 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1099 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1100 MoveTo16( hdc
, rect
.left
, 0 );
1101 LineTo( hdc
, rect
.left
, height
);
1105 /* horizontal separator */
1106 if (lpitem
->fType
& MF_SEPARATOR
)
1108 if (TWEAK_WineLook
> WIN31_LOOK
)
1113 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1114 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1118 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1119 MoveTo16( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
1120 LineTo( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
1127 if ((lpitem
->fState
& MF_HILITE
) && !(IS_BITMAP_ITEM(lpitem
->fType
)) )
1129 if (lpitem
->fState
& MF_GRAYED
)
1130 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1132 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
1133 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
1137 if (lpitem
->fState
& MF_GRAYED
)
1138 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1140 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1141 SetBkColor( hdc
, GetSysColor( COLOR_MENU
) );
1144 /* helper lines for debugging */
1145 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1146 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1147 MoveTo16( hdc, rect.left, (rect.top + rect.bottom)/2 );
1148 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1153 INT y
= rect
.top
+ rect
.bottom
;
1155 /* Draw the check mark
1158 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1161 if (lpitem
->fState
& MF_CHECKED
)
1163 HBITMAP bm
= lpitem
->hCheckBit
? lpitem
->hCheckBit
:
1164 ((lpitem
->fType
& MFT_RADIOCHECK
) ? hStdRadioCheck
: hStdCheck
);
1165 HDC hdcMem
= CreateCompatibleDC( hdc
);
1167 SelectObject( hdcMem
, bm
);
1168 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1169 check_bitmap_width
, check_bitmap_height
,
1170 hdcMem
, 0, 0, SRCCOPY
);
1173 else if (lpitem
->hUnCheckBit
)
1175 HDC hdcMem
= CreateCompatibleDC( hdc
);
1177 SelectObject( hdcMem
, lpitem
->hUnCheckBit
);
1178 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1179 check_bitmap_width
, check_bitmap_height
,
1180 hdcMem
, 0, 0, SRCCOPY
);
1184 /* Draw the popup-menu arrow */
1185 if (lpitem
->fType
& MF_POPUP
)
1187 HDC hdcMem
= CreateCompatibleDC( hdc
);
1189 SelectObject( hdcMem
, hStdMnArrow
);
1190 BitBlt( hdc
, rect
.right
- arrow_bitmap_width
- 1,
1191 (y
- arrow_bitmap_height
) / 2,
1192 arrow_bitmap_width
, arrow_bitmap_height
,
1193 hdcMem
, 0, 0, SRCCOPY
);
1197 rect
.left
+= check_bitmap_width
;
1198 rect
.right
-= arrow_bitmap_width
;
1201 /* Draw the item text or bitmap */
1202 if (IS_BITMAP_ITEM(lpitem
->fType
))
1207 HDC hdcMem
= CreateCompatibleDC( hdc
);
1210 * Check if there is a magic menu item associated with this item
1211 * and load the appropriate bitmap
1213 if((LOWORD((int)lpitem
->text
)) < 12)
1215 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
, (lpitem
->fState
& MF_HILITE
),
1216 lpitem
->dwItemData
);
1219 resBmp
= (HBITMAP
)lpitem
->text
;
1224 GetObjectA( resBmp
, sizeof(bm
), &bm
);
1226 SelectObject(hdcMem
,resBmp
);
1228 /* handle fontsize > bitmap_height */
1229 top
= ((rect
.bottom
-rect
.top
)>bm
.bmHeight
) ?
1230 rect
.top
+(rect
.bottom
-rect
.top
-bm
.bmHeight
)/2 : rect
.top
;
1232 BitBlt( hdc
, rect
.left
, top
, rect
.right
- rect
.left
,
1233 rect
.bottom
- rect
.top
, hdcMem
, 0, 0, SRCCOPY
);
1240 /* No bitmap - process text if present */
1241 else if (IS_STRING_ITEM(lpitem
->fType
))
1246 UINT uFormat
= (menuBar
) ?
1247 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
1248 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1250 if ( lpitem
->fState
& MFS_DEFAULT
)
1252 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
1257 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1258 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1259 i
= strlen( lpitem
->text
);
1263 for (i
= 0; lpitem
->text
[i
]; i
++)
1264 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
1268 if( !(TWEAK_WineLook
== WIN31_LOOK
) && (lpitem
->fState
& MF_GRAYED
))
1270 if (!(lpitem
->fState
& MF_HILITE
) )
1272 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1273 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1274 DrawTextA( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1275 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1277 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1280 DrawTextA( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1282 /* paint the shortcut text */
1283 if (lpitem
->text
[i
]) /* There's a tab or flush-right char */
1285 if (lpitem
->text
[i
] == '\t')
1287 rect
.left
= lpitem
->xTab
;
1288 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1292 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1295 if( !(TWEAK_WineLook
== WIN31_LOOK
) && (lpitem
->fState
& MF_GRAYED
))
1297 if (!(lpitem
->fState
& MF_HILITE
) )
1299 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1300 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1301 DrawTextA( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1302 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1304 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1306 DrawTextA( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1310 SelectObject (hdc
, hfontOld
);
1315 /***********************************************************************
1316 * MENU_DrawPopupMenu
1318 * Paint a popup menu.
1320 static void MENU_DrawPopupMenu( HWND hwnd
, HDC hdc
, HMENU hmenu
)
1322 HBRUSH hPrevBrush
= 0;
1325 TRACE("wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd
, hdc
, hmenu
);
1327 GetClientRect( hwnd
, &rect
);
1329 if(TWEAK_WineLook
== WIN31_LOOK
)
1331 rect
.bottom
-= POPUP_YSHADE
* GetSystemMetrics(SM_CYBORDER
);
1332 rect
.right
-= POPUP_XSHADE
* GetSystemMetrics(SM_CXBORDER
);
1335 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1336 && (SelectObject( hdc
, hMenuFont
)))
1340 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1342 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1348 /* draw 3-d shade */
1349 if(TWEAK_WineLook
== WIN31_LOOK
) {
1350 SelectObject( hdc
, hShadeBrush
);
1351 SetBkMode( hdc
, TRANSPARENT
);
1352 ropPrev
= SetROP2( hdc
, R2_MASKPEN
);
1354 i
= rect
.right
; /* why SetBrushOrg() doesn't? */
1355 PatBlt( hdc
, i
& 0xfffffffe,
1356 rect
.top
+ POPUP_YSHADE
*GetSystemMetrics(SM_CYBORDER
),
1357 i
%2 + POPUP_XSHADE
*GetSystemMetrics(SM_CXBORDER
),
1358 rect
.bottom
- rect
.top
, 0x00a000c9 );
1360 PatBlt( hdc
, rect
.left
+ POPUP_XSHADE
*GetSystemMetrics(SM_CXBORDER
),
1361 i
& 0xfffffffe,rect
.right
- rect
.left
,
1362 i
%2 + POPUP_YSHADE
*GetSystemMetrics(SM_CYBORDER
), 0x00a000c9 );
1363 SelectObject( hdc
, hPrevPen
);
1364 SelectObject( hdc
, hPrevBrush
);
1365 SetROP2( hdc
, ropPrev
);
1368 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1370 /* draw menu items */
1372 menu
= MENU_GetMenu( hmenu
);
1373 if (menu
&& menu
->nItems
)
1378 for (u
= menu
->nItems
, item
= menu
->items
; u
> 0; u
--, item
++)
1379 MENU_DrawMenuItem( hwnd
, hmenu
, menu
->hwndOwner
, hdc
, item
,
1380 menu
->Height
, FALSE
, ODA_DRAWENTIRE
);
1385 SelectObject( hdc
, hPrevBrush
);
1390 /***********************************************************************
1393 * Paint a menu bar. Returns the height of the menu bar.
1394 * called from [windows/nonclient.c]
1396 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1403 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1405 lppop
= MENU_GetMenu ((HMENU
)wndPtr
->wIDmenu
);
1406 if (lppop
== NULL
|| lprect
== NULL
)
1408 retvalue
= GetSystemMetrics(SM_CYMENU
);
1412 TRACE("(%04x, %p, %p)\n", hDC
, lprect
, lppop
);
1414 hfontOld
= SelectObject( hDC
, hMenuFont
);
1416 if (lppop
->Height
== 0)
1417 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
1419 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
1423 retvalue
= lppop
->Height
;
1427 FillRect(hDC
, lprect
, GetSysColorBrush(COLOR_MENU
) );
1429 if (TWEAK_WineLook
== WIN31_LOOK
)
1431 SelectObject( hDC
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1432 MoveTo16( hDC
, lprect
->left
, lprect
->bottom
);
1433 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1437 SelectObject( hDC
, GetSysColorPen(COLOR_3DFACE
));
1438 MoveTo16( hDC
, lprect
->left
, lprect
->bottom
);
1439 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1442 if (lppop
->nItems
== 0)
1444 retvalue
= GetSystemMetrics(SM_CYMENU
);
1448 for (i
= 0; i
< lppop
->nItems
; i
++)
1450 MENU_DrawMenuItem( hwnd
, (HMENU
)wndPtr
->wIDmenu
, GetWindow(hwnd
,GW_OWNER
),
1451 hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
, ODA_DRAWENTIRE
);
1453 retvalue
= lppop
->Height
;
1457 SelectObject (hDC
, hfontOld
);
1459 WIN_ReleaseWndPtr(wndPtr
);
1463 /***********************************************************************
1464 * MENU_PatchResidentPopup
1466 BOOL
MENU_PatchResidentPopup( HQUEUE16 checkQueue
, WND
* checkWnd
)
1468 WND
*pTPWnd
= MENU_GetTopPopupWnd();
1474 TRACE("patching resident popup: %04x %04x [%04x %04x]\n",
1475 checkQueue
, checkWnd
? checkWnd
->hwndSelf
: 0, pTPWnd
->hmemTaskQ
,
1476 pTPWnd
->owner
? pTPWnd
->owner
->hwndSelf
: 0);
1478 switch( checkQueue
)
1480 case 0: /* checkWnd is the new popup owner */
1483 pTPWnd
->owner
= checkWnd
;
1484 if( pTPWnd
->hmemTaskQ
!= checkWnd
->hmemTaskQ
)
1485 hTask
= QUEUE_GetQueueTask( checkWnd
->hmemTaskQ
);
1489 case 0xFFFF: /* checkWnd is destroyed */
1490 if( pTPWnd
->owner
== checkWnd
)
1491 pTPWnd
->owner
= NULL
;
1492 MENU_ReleaseTopPopupWnd();
1495 default: /* checkQueue is exiting */
1496 if( pTPWnd
->hmemTaskQ
== checkQueue
)
1498 hTask
= QUEUE_GetQueueTask( pTPWnd
->hmemTaskQ
);
1499 hTask
= TASK_GetNextTask( hTask
);
1506 TDB
* task
= (TDB
*)GlobalLock16( hTask
);
1509 pTPWnd
->hInstance
= task
->hInstance
;
1510 pTPWnd
->hmemTaskQ
= task
->hQueue
;
1511 MENU_ReleaseTopPopupWnd();
1514 else WARN("failed to patch resident popup.\n");
1517 MENU_ReleaseTopPopupWnd();
1521 /***********************************************************************
1524 * Display a popup menu.
1526 static BOOL
MENU_ShowPopup( HWND hwndOwner
, HMENU hmenu
, UINT id
,
1527 INT x
, INT y
, INT xanchor
, INT yanchor
)
1530 WND
*wndOwner
= NULL
;
1532 TRACE("owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1533 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1535 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
1536 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1538 menu
->items
[menu
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1539 menu
->FocusedItem
= NO_SELECTED_ITEM
;
1542 /* store the owner for DrawItem*/
1543 menu
->hwndOwner
= hwndOwner
;
1545 if( (wndOwner
= WIN_FindWndPtr( hwndOwner
)) )
1549 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
1551 /* adjust popup menu pos so that it fits within the desktop */
1553 width
= menu
->Width
+ GetSystemMetrics(SM_CXBORDER
);
1554 height
= menu
->Height
+ GetSystemMetrics(SM_CYBORDER
);
1556 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1559 x
-= width
- xanchor
;
1560 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1561 x
= GetSystemMetrics(SM_CXSCREEN
) - width
;
1565 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1568 y
-= height
+ yanchor
;
1569 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1570 y
= GetSystemMetrics(SM_CYSCREEN
) - height
;
1574 if( TWEAK_WineLook
== WIN31_LOOK
)
1576 width
+= POPUP_XSHADE
* GetSystemMetrics(SM_CXBORDER
); /* add space for shading */
1577 height
+= POPUP_YSHADE
* GetSystemMetrics(SM_CYBORDER
);
1580 /* NOTE: In Windows, top menu popup is not owned. */
1581 if (!pTopPopupWnd
) /* create top level popup menu window */
1583 assert( uSubPWndLevel
== 0 );
1585 pTopPopupWnd
= WIN_FindWndPtr(CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1586 WS_POPUP
, x
, y
, width
, height
,
1587 hwndOwner
, 0, wndOwner
->hInstance
,
1591 WIN_ReleaseWndPtr(wndOwner
);
1594 menu
->hWnd
= pTopPopupWnd
->hwndSelf
;
1595 MENU_ReleaseTopPopupWnd();
1600 /* create a new window for the submenu */
1602 menu
->hWnd
= CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1603 WS_POPUP
, x
, y
, width
, height
,
1604 hwndOwner
, 0, wndOwner
->hInstance
,
1608 WIN_ReleaseWndPtr(wndOwner
);
1612 else /* top level popup menu window already exists */
1614 WND
*pTPWnd
= MENU_GetTopPopupWnd();
1615 menu
->hWnd
= pTPWnd
->hwndSelf
;
1617 MENU_PatchResidentPopup( 0, wndOwner
);
1618 SendMessageA( pTPWnd
->hwndSelf
, MM_SETMENUHANDLE
, (WPARAM16
)hmenu
, 0L);
1620 /* adjust its size */
1622 SetWindowPos( menu
->hWnd
, 0, x
, y
, width
, height
,
1623 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_NOREDRAW
);
1624 MENU_ReleaseTopPopupWnd();
1627 uSubPWndLevel
++; /* menu level counter */
1629 /* Display the window */
1631 SetWindowPos( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
1632 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1633 UpdateWindow( menu
->hWnd
);
1634 WIN_ReleaseWndPtr(wndOwner
);
1641 /***********************************************************************
1644 static void MENU_SelectItem( HWND hwndOwner
, HMENU hmenu
, UINT wIndex
,
1645 BOOL sendMenuSelect
, HMENU topmenu
)
1650 TRACE("owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1652 lppop
= MENU_GetMenu( hmenu
);
1653 if ((!lppop
) || (!lppop
->nItems
)) return;
1655 if (lppop
->FocusedItem
== wIndex
) return;
1656 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC( lppop
->hWnd
);
1657 else hdc
= GetDCEx( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1659 SelectObject( hdc
, hMenuFont
);
1661 /* Clear previous highlighted item */
1662 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1664 lppop
->items
[lppop
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1665 MENU_DrawMenuItem(lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,&lppop
->items
[lppop
->FocusedItem
],
1666 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
),
1670 /* Highlight new item (if any) */
1671 lppop
->FocusedItem
= wIndex
;
1672 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1674 if(!(lppop
->items
[wIndex
].fType
& MF_SEPARATOR
)) {
1675 lppop
->items
[wIndex
].fState
|= MF_HILITE
;
1676 MENU_DrawMenuItem( lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,
1677 &lppop
->items
[wIndex
], lppop
->Height
,
1678 !(lppop
->wFlags
& MF_POPUP
), ODA_SELECT
);
1682 MENUITEM
*ip
= &lppop
->items
[lppop
->FocusedItem
];
1683 SendMessageA( hwndOwner
, WM_MENUSELECT
,
1684 MAKELONG(ip
->fType
& MF_POPUP
? wIndex
: ip
->wID
,
1685 ip
->fType
| ip
->fState
| MF_MOUSESELECT
|
1686 (lppop
->wFlags
& MF_SYSMENU
)), hmenu
);
1689 else if (sendMenuSelect
) {
1692 if((pos
=MENU_FindSubMenu(&topmenu
, hmenu
))!=NO_SELECTED_ITEM
){
1693 POPUPMENU
*ptm
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( topmenu
);
1694 MENUITEM
*ip
= &ptm
->items
[pos
];
1695 SendMessageA( hwndOwner
, WM_MENUSELECT
, MAKELONG(pos
,
1696 ip
->fType
| ip
->fState
| MF_MOUSESELECT
|
1697 (ptm
->wFlags
& MF_SYSMENU
)), topmenu
);
1701 ReleaseDC( lppop
->hWnd
, hdc
);
1705 /***********************************************************************
1706 * MENU_MoveSelection
1708 * Moves currently selected item according to the offset parameter.
1709 * If there is no selection then it should select the last item if
1710 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1712 static void MENU_MoveSelection( HWND hwndOwner
, HMENU hmenu
, INT offset
)
1717 TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner
, hmenu
, offset
);
1719 menu
= MENU_GetMenu( hmenu
);
1720 if ((!menu
) || (!menu
->items
)) return;
1722 if ( menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1724 if( menu
->nItems
== 1 ) return; else
1725 for (i
= menu
->FocusedItem
+ offset
; i
>= 0 && i
< menu
->nItems
1727 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1729 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
1734 for ( i
= (offset
> 0) ? 0 : menu
->nItems
- 1;
1735 i
>= 0 && i
< menu
->nItems
; i
+= offset
)
1736 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1738 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
1744 /**********************************************************************
1747 * Set an item flags, id and text ptr. Called by InsertMenu() and
1750 static BOOL
MENU_SetItemData( MENUITEM
*item
, UINT flags
, UINT id
,
1753 LPSTR prevText
= IS_STRING_ITEM(item
->fType
) ? item
->text
: NULL
;
1755 debug_print_menuitem("MENU_SetItemData from: ", item
, "");
1757 if (IS_STRING_ITEM(flags
))
1761 flags
|= MF_SEPARATOR
;
1767 /* Item beginning with a backspace is a help item */
1773 if (!(text
= HEAP_strdupA( SystemHeap
, 0, str
))) return FALSE
;
1777 else if (IS_BITMAP_ITEM(flags
))
1778 item
->text
= (LPSTR
)(HBITMAP
)LOWORD(str
);
1779 else item
->text
= NULL
;
1781 if (flags
& MF_OWNERDRAW
)
1782 item
->dwItemData
= (DWORD
)str
;
1784 item
->dwItemData
= 0;
1786 if ((item
->fType
& MF_POPUP
) && (flags
& MF_POPUP
) && (item
->hSubMenu
!= id
) )
1787 DestroyMenu( item
->hSubMenu
); /* ModifyMenu() spec */
1789 if (flags
& MF_POPUP
)
1791 POPUPMENU
*menu
= MENU_GetMenu((UINT16
)id
);
1792 if (menu
) menu
->wFlags
|= MF_POPUP
;
1804 if (flags
& MF_POPUP
)
1805 item
->hSubMenu
= id
;
1807 if ((item
->fType
& MF_POPUP
) && !(flags
& MF_POPUP
) )
1808 flags
|= MF_POPUP
; /* keep popup */
1810 item
->fType
= flags
& TYPE_MASK
;
1811 item
->fState
= (flags
& STATE_MASK
) &
1812 ~(MF_HILITE
| MF_MOUSESELECT
| MF_BYPOSITION
);
1815 /* Don't call SetRectEmpty here! */
1818 if (prevText
) HeapFree( SystemHeap
, 0, prevText
);
1820 debug_print_menuitem("MENU_SetItemData to : ", item
, "");
1825 /**********************************************************************
1828 * Insert a new item into a menu.
1830 static MENUITEM
*MENU_InsertItem( HMENU hMenu
, UINT pos
, UINT flags
)
1835 if (!(menu
= MENU_GetMenu(hMenu
)))
1838 /* Find where to insert new item */
1840 if ((pos
==(UINT
)-1) || ((flags
& MF_BYPOSITION
) && (pos
== menu
->nItems
))) {
1841 /* Special case: append to menu */
1842 /* Some programs specify the menu length to do that */
1845 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
1847 FIXME("item %x not found\n", pos
);
1850 if (!(menu
= MENU_GetMenu(hMenu
)))
1854 /* Create new items array */
1856 newItems
= HeapAlloc( SystemHeap
, 0, sizeof(MENUITEM
) * (menu
->nItems
+1) );
1859 WARN("allocation failed\n" );
1862 if (menu
->nItems
> 0)
1864 /* Copy the old array into the new */
1865 if (pos
> 0) memcpy( newItems
, menu
->items
, pos
* sizeof(MENUITEM
) );
1866 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &menu
->items
[pos
],
1867 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
1868 HeapFree( SystemHeap
, 0, menu
->items
);
1870 menu
->items
= newItems
;
1872 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
1873 menu
->Height
= 0; /* force size recalculate */
1874 return &newItems
[pos
];
1878 /**********************************************************************
1879 * MENU_ParseResource
1881 * Parse a standard menu resource and add items to the menu.
1882 * Return a pointer to the end of the resource.
1884 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1891 flags
= GET_WORD(res
);
1892 res
+= sizeof(WORD
);
1893 if (!(flags
& MF_POPUP
))
1896 res
+= sizeof(WORD
);
1898 if (!IS_STRING_ITEM(flags
))
1899 ERR("not a string item %04x\n", flags
);
1901 if (!unicode
) res
+= strlen(str
) + 1;
1902 else res
+= (lstrlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1903 if (flags
& MF_POPUP
)
1905 HMENU hSubMenu
= CreatePopupMenu();
1906 if (!hSubMenu
) return NULL
;
1907 if (!(res
= MENU_ParseResource( res
, hSubMenu
, unicode
)))
1909 if (!unicode
) AppendMenuA( hMenu
, flags
, (UINT
)hSubMenu
, str
);
1910 else AppendMenuW( hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1912 else /* Not a popup */
1914 if (!unicode
) AppendMenuA( hMenu
, flags
, id
, *str
? str
: NULL
);
1915 else AppendMenuW( hMenu
, flags
, id
,
1916 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1918 } while (!(flags
& MF_END
));
1923 /**********************************************************************
1924 * MENUEX_ParseResource
1926 * Parse an extended menu resource and add items to the menu.
1927 * Return a pointer to the end of the resource.
1929 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
1935 mii
.cbSize
= sizeof(mii
);
1936 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
1937 mii
.fType
= GET_DWORD(res
);
1938 res
+= sizeof(DWORD
);
1939 mii
.fState
= GET_DWORD(res
);
1940 res
+= sizeof(DWORD
);
1941 mii
.wID
= GET_DWORD(res
);
1942 res
+= sizeof(DWORD
);
1943 resinfo
= GET_WORD(res
); /* FIXME: for 16-bit apps this is a byte. */
1944 res
+= sizeof(WORD
);
1945 /* Align the text on a word boundary. */
1946 res
+= (~((int)res
- 1)) & 1;
1947 mii
.dwTypeData
= (LPWSTR
) res
;
1948 res
+= (1 + lstrlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
1949 /* Align the following fields on a dword boundary. */
1950 res
+= (~((int)res
- 1)) & 3;
1952 /* FIXME: This is inefficient and cannot be optimised away by gcc. */
1954 LPSTR newstr
= HEAP_strdupWtoA(GetProcessHeap(),
1956 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
1957 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, newstr
);
1958 HeapFree( GetProcessHeap(), 0, newstr
);
1961 if (resinfo
& 1) { /* Pop-up? */
1962 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
1963 res
+= sizeof(DWORD
);
1964 mii
.hSubMenu
= CreatePopupMenu();
1967 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
1968 DestroyMenu(mii
.hSubMenu
);
1971 mii
.fMask
|= MIIM_SUBMENU
;
1972 mii
.fType
|= MF_POPUP
;
1974 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
1975 } while (!(resinfo
& MF_END
));
1980 /***********************************************************************
1983 * Return the handle of the selected sub-popup menu (if any).
1985 static HMENU
MENU_GetSubPopup( HMENU hmenu
)
1990 menu
= MENU_GetMenu( hmenu
);
1992 if ((!menu
) || (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return 0;
1994 item
= &menu
->items
[menu
->FocusedItem
];
1995 if ((item
->fType
& MF_POPUP
) && (item
->fState
& MF_MOUSESELECT
))
1996 return item
->hSubMenu
;
2001 /***********************************************************************
2002 * MENU_HideSubPopups
2004 * Hide the sub-popup menus of this menu.
2006 static void MENU_HideSubPopups( HWND hwndOwner
, HMENU hmenu
,
2007 BOOL sendMenuSelect
)
2009 POPUPMENU
*menu
= MENU_GetMenu( hmenu
);
2011 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner
, hmenu
, sendMenuSelect
);
2013 if (menu
&& uSubPWndLevel
)
2019 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
2021 item
= &menu
->items
[menu
->FocusedItem
];
2022 if (!(item
->fType
& MF_POPUP
) ||
2023 !(item
->fState
& MF_MOUSESELECT
)) return;
2024 item
->fState
&= ~MF_MOUSESELECT
;
2025 hsubmenu
= item
->hSubMenu
;
2028 submenu
= MENU_GetMenu( hsubmenu
);
2029 MENU_HideSubPopups( hwndOwner
, hsubmenu
, FALSE
);
2030 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, sendMenuSelect
, 0 );
2032 if (submenu
->hWnd
== MENU_GetTopPopupWnd()->hwndSelf
)
2034 ShowWindow( submenu
->hWnd
, SW_HIDE
);
2039 DestroyWindow( submenu
->hWnd
);
2042 MENU_ReleaseTopPopupWnd();
2047 /***********************************************************************
2050 * Display the sub-menu of the selected item of this menu.
2051 * Return the handle of the submenu, or hmenu if no submenu to display.
2053 static HMENU
MENU_ShowSubPopup( HWND hwndOwner
, HMENU hmenu
,
2054 BOOL selectFirst
, UINT wFlags
)
2062 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner
, hmenu
, selectFirst
);
2064 if (!(menu
= MENU_GetMenu( hmenu
))) return hmenu
;
2066 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
)) ||
2067 (menu
->FocusedItem
== NO_SELECTED_ITEM
))
2069 WIN_ReleaseWndPtr(wndPtr
);
2073 item
= &menu
->items
[menu
->FocusedItem
];
2074 if (!(item
->fType
& MF_POPUP
) ||
2075 (item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
2077 WIN_ReleaseWndPtr(wndPtr
);
2081 /* message must be send before using item,
2082 because nearly everything may by changed by the application ! */
2084 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2085 if (!(wFlags
& TPM_NONOTIFY
))
2086 SendMessageA( hwndOwner
, WM_INITMENUPOPUP
, item
->hSubMenu
,
2087 MAKELONG( menu
->FocusedItem
, IS_SYSTEM_MENU(menu
) ));
2089 item
= &menu
->items
[menu
->FocusedItem
];
2092 /* correct item if modified as a reaction to WM_INITMENUPOPUP-message */
2093 if (!(item
->fState
& MF_HILITE
))
2095 if (menu
->wFlags
& MF_POPUP
) hdc
= GetDC( menu
->hWnd
);
2096 else hdc
= GetDCEx( menu
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2098 SelectObject( hdc
, hMenuFont
);
2100 item
->fState
|= MF_HILITE
;
2101 MENU_DrawMenuItem( menu
->hWnd
, hmenu
, hwndOwner
, hdc
, item
, menu
->Height
, !(menu
->wFlags
& MF_POPUP
), ODA_DRAWENTIRE
);
2102 ReleaseDC( menu
->hWnd
, hdc
);
2104 if (!item
->rect
.top
&& !item
->rect
.left
&& !item
->rect
.bottom
&& !item
->rect
.right
)
2107 item
->fState
|= MF_MOUSESELECT
;
2109 if (IS_SYSTEM_MENU(menu
))
2111 MENU_InitSysMenuPopup(item
->hSubMenu
, wndPtr
->dwStyle
, GetClassLongA(wndPtr
->hwndSelf
, GCL_STYLE
));
2113 NC_GetSysPopupPos( wndPtr
, &rect
);
2114 rect
.top
= rect
.bottom
;
2115 rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2116 rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2120 if (menu
->wFlags
& MF_POPUP
)
2122 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.right
-arrow_bitmap_width
;
2123 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.top
;
2124 rect
.right
= item
->rect
.left
- item
->rect
.right
+ 2*arrow_bitmap_width
;
2125 rect
.bottom
= item
->rect
.top
- item
->rect
.bottom
;
2129 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.left
;
2130 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.bottom
;
2131 rect
.right
= item
->rect
.right
- item
->rect
.left
;
2132 rect
.bottom
= item
->rect
.bottom
- item
->rect
.top
;
2136 MENU_ShowPopup( hwndOwner
, item
->hSubMenu
, menu
->FocusedItem
,
2137 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2139 MENU_MoveSelection( hwndOwner
, item
->hSubMenu
, ITEM_NEXT
);
2140 WIN_ReleaseWndPtr(wndPtr
);
2141 return item
->hSubMenu
;
2146 /**********************************************************************
2149 BOOL
MENU_IsMenuActive(void)
2151 return pTopPopupWnd
&& (pTopPopupWnd
->dwStyle
& WS_VISIBLE
);
2154 /***********************************************************************
2157 * Walks menu chain trying to find a menu pt maps to.
2159 static HMENU
MENU_PtMenu( HMENU hMenu
, POINT16 pt
)
2161 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2162 register UINT ht
= menu
->FocusedItem
;
2164 /* try subpopup first (if any) */
2165 ht
= (ht
!= NO_SELECTED_ITEM
&&
2166 (menu
->items
[ht
].fType
& MF_POPUP
) &&
2167 (menu
->items
[ht
].fState
& MF_MOUSESELECT
))
2168 ? (UINT
) MENU_PtMenu(menu
->items
[ht
].hSubMenu
, pt
) : 0;
2170 if( !ht
) /* check the current window (avoiding WM_HITTEST) */
2172 ht
= (UINT
)NC_HandleNCHitTest( menu
->hWnd
, pt
);
2173 if( menu
->wFlags
& MF_POPUP
)
2174 ht
= (ht
!= (UINT
)HTNOWHERE
&&
2175 ht
!= (UINT
)HTERROR
) ? (UINT
)hMenu
: 0;
2178 WND
* wndPtr
= WIN_FindWndPtr(menu
->hWnd
);
2180 ht
= ( ht
== HTSYSMENU
) ? (UINT
)(wndPtr
->hSysMenu
)
2181 : ( ht
== HTMENU
) ? (UINT
)(wndPtr
->wIDmenu
) : 0;
2182 WIN_ReleaseWndPtr(wndPtr
);
2188 /***********************************************************************
2189 * MENU_ExecFocusedItem
2191 * Execute a menu item (for instance when user pressed Enter).
2192 * Return the wID of the executed item. Otherwise, -1 indicating
2193 * that no menu item wase executed;
2194 * Have to receive the flags for the TrackPopupMenu options to avoid
2195 * sending unwanted message.
2198 static INT
MENU_ExecFocusedItem( MTRACKER
* pmt
, HMENU hMenu
, UINT wFlags
)
2201 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2203 TRACE("%p hmenu=0x%04x\n", pmt
, hMenu
);
2205 if (!menu
|| !menu
->nItems
||
2206 (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return -1;
2208 item
= &menu
->items
[menu
->FocusedItem
];
2210 TRACE("%08x %08x %08x\n",
2211 hMenu
, item
->wID
, item
->hSubMenu
);
2213 if (!(item
->fType
& MF_POPUP
))
2215 if (!(item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
2217 /* If TPM_RETURNCMD is set you return the id, but
2218 do not send a message to the owner */
2219 if(!(wFlags
& TPM_RETURNCMD
))
2221 if( menu
->wFlags
& MF_SYSMENU
)
2222 PostMessageA( pmt
->hOwnerWnd
, WM_SYSCOMMAND
, item
->wID
,
2223 MAKELPARAM((INT16
)pmt
->pt
.x
, (INT16
)pmt
->pt
.y
) );
2225 PostMessageA( pmt
->hOwnerWnd
, WM_COMMAND
, item
->wID
, 0 );
2231 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hMenu
, TRUE
, wFlags
);
2236 /***********************************************************************
2237 * MENU_SwitchTracking
2239 * Helper function for menu navigation routines.
2241 static void MENU_SwitchTracking( MTRACKER
* pmt
, HMENU hPtMenu
, UINT id
)
2243 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2244 POPUPMENU
*topmenu
= MENU_GetMenu( pmt
->hTopMenu
);
2246 TRACE("%p hmenu=0x%04x 0x%04x\n", pmt
, hPtMenu
, id
);
2248 if( pmt
->hTopMenu
!= hPtMenu
&&
2249 !((ptmenu
->wFlags
| topmenu
->wFlags
) & MF_POPUP
) )
2251 /* both are top level menus (system and menu-bar) */
2252 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2253 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
2254 pmt
->hTopMenu
= hPtMenu
;
2256 else MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
2257 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, id
, TRUE
, 0 );
2261 /***********************************************************************
2264 * Return TRUE if we can go on with menu tracking.
2266 static BOOL
MENU_ButtonDown( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2268 TRACE("%p hmenu=0x%04x\n", pmt
, hPtMenu
);
2273 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2276 if( IS_SYSTEM_MENU(ptmenu
) )
2277 item
= ptmenu
->items
;
2279 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2283 if( ptmenu
->FocusedItem
!= id
)
2284 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2286 /* If the popup menu is not already "popped" */
2287 if(!(item
->fState
& MF_MOUSESELECT
))
2289 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2291 /* In win31, a newly popped menu always remain opened for the next buttonup */
2292 if(TWEAK_WineLook
== WIN31_LOOK
)
2293 ptmenu
->bTimeToHide
= FALSE
;
2298 /* Else the click was on the menu bar, finish the tracking */
2303 /***********************************************************************
2306 * Return the value of MENU_ExecFocusedItem if
2307 * the selected item was not a popup. Else open the popup.
2308 * A -1 return value indicates that we go on with menu tracking.
2311 static INT
MENU_ButtonUp( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2313 TRACE("%p hmenu=0x%04x\n", pmt
, hPtMenu
);
2318 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2321 if( IS_SYSTEM_MENU(ptmenu
) )
2322 item
= ptmenu
->items
;
2324 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2326 if( item
&& (ptmenu
->FocusedItem
== id
))
2328 if( !(item
->fType
& MF_POPUP
) )
2329 return MENU_ExecFocusedItem( pmt
, hPtMenu
, wFlags
);
2331 /* If we are dealing with the top-level menu and that this */
2332 /* is a click on an already "poppped" item */
2333 /* Stop the menu tracking and close the opened submenus */
2334 if((pmt
->hTopMenu
== hPtMenu
) && (ptmenu
->bTimeToHide
== TRUE
))
2337 ptmenu
->bTimeToHide
= TRUE
;
2343 /***********************************************************************
2346 * Return TRUE if we can go on with menu tracking.
2348 static BOOL
MENU_MouseMove( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2350 UINT id
= NO_SELECTED_ITEM
;
2351 POPUPMENU
*ptmenu
= NULL
;
2355 ptmenu
= MENU_GetMenu( hPtMenu
);
2356 if( IS_SYSTEM_MENU(ptmenu
) )
2359 MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2362 if( id
== NO_SELECTED_ITEM
)
2364 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2365 NO_SELECTED_ITEM
, TRUE
, pmt
->hTopMenu
);
2368 else if( ptmenu
->FocusedItem
!= id
)
2370 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2371 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2377 /***********************************************************************
2380 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2382 static LRESULT
MENU_DoNextMenu( MTRACKER
* pmt
, UINT vk
)
2384 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2386 if( (vk
== VK_LEFT
&& menu
->FocusedItem
== 0 ) ||
2387 (vk
== VK_RIGHT
&& menu
->FocusedItem
== menu
->nItems
- 1))
2393 LRESULT l
= SendMessageA( pmt
->hOwnerWnd
, WM_NEXTMENU
, vk
,
2394 (IS_SYSTEM_MENU(menu
)) ? GetSubMenu16(pmt
->hTopMenu
,0) : pmt
->hTopMenu
);
2396 TRACE("%04x [%04x] -> %04x [%04x]\n",
2397 (UINT16
)pmt
->hCurrentMenu
, (UINT16
)pmt
->hOwnerWnd
, LOWORD(l
), HIWORD(l
) );
2401 wndPtr
= WIN_FindWndPtr(pmt
->hOwnerWnd
);
2403 hNewWnd
= pmt
->hOwnerWnd
;
2404 if( IS_SYSTEM_MENU(menu
) )
2406 /* switch to the menu bar */
2408 if( wndPtr
->dwStyle
& WS_CHILD
|| !wndPtr
->wIDmenu
)
2410 WIN_ReleaseWndPtr(wndPtr
);
2414 hNewMenu
= wndPtr
->wIDmenu
;
2417 menu
= MENU_GetMenu( hNewMenu
);
2418 id
= menu
->nItems
- 1;
2421 else if( wndPtr
->dwStyle
& WS_SYSMENU
)
2423 /* switch to the system menu */
2424 hNewMenu
= wndPtr
->hSysMenu
;
2428 WIN_ReleaseWndPtr(wndPtr
);
2431 WIN_ReleaseWndPtr(wndPtr
);
2433 else /* application returned a new menu to switch to */
2435 hNewMenu
= LOWORD(l
); hNewWnd
= HIWORD(l
);
2437 if( IsMenu(hNewMenu
) && IsWindow(hNewWnd
) )
2439 wndPtr
= WIN_FindWndPtr(hNewWnd
);
2441 if( wndPtr
->dwStyle
& WS_SYSMENU
&&
2442 GetSubMenu16(wndPtr
->hSysMenu
, 0) == hNewMenu
)
2444 /* get the real system menu */
2445 hNewMenu
= wndPtr
->hSysMenu
;
2447 else if( wndPtr
->dwStyle
& WS_CHILD
|| wndPtr
->wIDmenu
!= hNewMenu
)
2449 /* FIXME: Not sure what to do here, perhaps,
2450 * try to track hNewMenu as a popup? */
2452 TRACE(" -- got confused.\n");
2453 WIN_ReleaseWndPtr(wndPtr
);
2456 WIN_ReleaseWndPtr(wndPtr
);
2461 if( hNewMenu
!= pmt
->hTopMenu
)
2463 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
,
2465 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2466 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2469 if( hNewWnd
!= pmt
->hOwnerWnd
)
2472 pmt
->hOwnerWnd
= hNewWnd
;
2473 EVENT_Capture( pmt
->hOwnerWnd
, HTMENU
);
2476 pmt
->hTopMenu
= pmt
->hCurrentMenu
= hNewMenu
; /* all subpopups are hidden */
2477 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, id
, TRUE
, 0 );
2484 /***********************************************************************
2487 * The idea is not to show the popup if the next input message is
2488 * going to hide it anyway.
2490 static BOOL
MENU_SuspendPopup( MTRACKER
* pmt
, UINT16 uMsg
)
2494 msg
.hwnd
= pmt
->hOwnerWnd
;
2496 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2497 pmt
->trackFlags
|= TF_SKIPREMOVE
;
2502 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2503 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
2505 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2506 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2507 if( msg
.message
== WM_KEYDOWN
&&
2508 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
2510 pmt
->trackFlags
|= TF_SUSPENDPOPUP
;
2517 /* failures go through this */
2518 pmt
->trackFlags
&= ~TF_SUSPENDPOPUP
;
2522 /***********************************************************************
2525 * Handle a VK_LEFT key event in a menu.
2527 static void MENU_KeyLeft( MTRACKER
* pmt
, UINT wFlags
)
2530 HMENU hmenutmp
, hmenuprev
;
2533 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
2534 menu
= MENU_GetMenu( hmenutmp
);
2536 /* Try to move 1 column left (if possible) */
2537 if( (prevcol
= MENU_GetStartOfPrevColumn( pmt
->hCurrentMenu
)) !=
2538 NO_SELECTED_ITEM
) {
2540 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2545 /* close topmost popup */
2546 while (hmenutmp
!= pmt
->hCurrentMenu
)
2548 hmenuprev
= hmenutmp
;
2549 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
2552 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
);
2553 pmt
->hCurrentMenu
= hmenuprev
;
2555 if ( (hmenuprev
== pmt
->hTopMenu
) && !(menu
->wFlags
& MF_POPUP
) )
2557 /* move menu bar selection if no more popups are left */
2559 if( !MENU_DoNextMenu( pmt
, VK_LEFT
) )
2560 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_PREV
);
2562 if ( hmenuprev
!= hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2564 /* A sublevel menu was displayed - display the next one
2565 * unless there is another displacement coming up */
2567 if( !MENU_SuspendPopup( pmt
, WM_KEYDOWN
) )
2568 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2569 pmt
->hTopMenu
, TRUE
, wFlags
);
2575 /***********************************************************************
2578 * Handle a VK_RIGHT key event in a menu.
2580 static void MENU_KeyRight( MTRACKER
* pmt
, UINT wFlags
)
2583 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2586 TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2588 (MENU_GetMenu(pmt
->hCurrentMenu
))->
2590 pmt
->hTopMenu
, menu
->items
[0].text
);
2592 if ( (menu
->wFlags
& MF_POPUP
) || (pmt
->hCurrentMenu
!= pmt
->hTopMenu
))
2594 /* If already displaying a popup, try to display sub-popup */
2596 hmenutmp
= pmt
->hCurrentMenu
;
2597 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hmenutmp
, TRUE
, wFlags
);
2599 /* if subpopup was displayed then we are done */
2600 if (hmenutmp
!= pmt
->hCurrentMenu
) return;
2603 /* Check to see if there's another column */
2604 if( (nextcol
= MENU_GetStartOfNextColumn( pmt
->hCurrentMenu
)) !=
2605 NO_SELECTED_ITEM
) {
2606 TRACE("Going to %d.\n", nextcol
);
2607 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2612 if (!(menu
->wFlags
& MF_POPUP
)) /* menu bar tracking */
2614 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2616 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2617 hmenutmp
= pmt
->hCurrentMenu
= pmt
->hTopMenu
;
2618 } else hmenutmp
= 0;
2620 /* try to move to the next item */
2621 if( !MENU_DoNextMenu( pmt
, VK_RIGHT
) )
2622 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_NEXT
);
2624 if( hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2625 if( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
2626 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2627 pmt
->hTopMenu
, TRUE
, wFlags
);
2631 /***********************************************************************
2634 * Menu tracking code.
2636 static INT
MENU_TrackMenu( HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
2637 HWND hwnd
, const RECT
*lprect
)
2642 INT executedMenuId
= -1;
2644 BOOL enterIdleSent
= FALSE
;
2647 mt
.hCurrentMenu
= hmenu
;
2648 mt
.hTopMenu
= hmenu
;
2649 mt
.hOwnerWnd
= hwnd
;
2653 TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2654 hmenu
, wFlags
, x
, y
, hwnd
, (lprect
) ? lprect
->left
: 0, (lprect
) ? lprect
->top
: 0,
2655 (lprect
) ? lprect
->right
: 0, (lprect
) ? lprect
->bottom
: 0);
2658 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
2660 if (wFlags
& TPM_BUTTONDOWN
)
2662 /* Get the result in order to start the tracking or not */
2663 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
2664 fEndMenu
= !fRemove
;
2667 EVENT_Capture( mt
.hOwnerWnd
, HTMENU
);
2671 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
2672 msg
.hwnd
= (wFlags
& TPM_ENTERIDLEEX
&& menu
->wFlags
& MF_POPUP
) ? menu
->hWnd
: 0;
2674 /* we have to keep the message in the queue until it's
2675 * clear that menu loop is not over yet. */
2677 if (!MSG_InternalGetMessage( QMSG_WIN32A
, &msg
, msg
.hwnd
, mt
.hOwnerWnd
,
2678 MSGF_MENU
, PM_NOREMOVE
, !enterIdleSent
, &enterIdleSent
)) break;
2680 TranslateMessage( &msg
);
2683 if ( (msg
.hwnd
==menu
->hWnd
) || (msg
.message
!=WM_TIMER
) )
2684 enterIdleSent
=FALSE
;
2687 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
2689 /* Find a menu for this mouse event */
2691 CONV_POINT32TO16( &msg
.pt
, &pt16
);
2692 hmenu
= MENU_PtMenu( mt
.hTopMenu
, pt16
);
2696 /* no WM_NC... messages in captured state */
2698 case WM_RBUTTONDBLCLK
:
2699 case WM_RBUTTONDOWN
:
2700 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2702 case WM_LBUTTONDBLCLK
:
2703 case WM_LBUTTONDOWN
:
2704 /* If the message belongs to the menu, removes it from the queue */
2705 /* Else, end menu tracking */
2706 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
2707 fEndMenu
= !fRemove
;
2711 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2714 /* Check if a menu was selected by the mouse */
2717 executedMenuId
= MENU_ButtonUp( &mt
, hmenu
, wFlags
);
2719 /* End the loop if executedMenuId is an item ID */
2720 /* or if the job was done (executedMenuId = 0). */
2721 fEndMenu
= fRemove
= (executedMenuId
!= -1);
2723 /* No menu was selected by the mouse */
2724 /* if the function was called by TrackPopupMenu, continue
2725 with the menu tracking. If not, stop it */
2727 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
2732 /* In win95 winelook, the selected menu item must be changed every time the
2733 mouse moves. In Win31 winelook, the mouse button has to be held down */
2735 if ( (TWEAK_WineLook
> WIN31_LOOK
) ||
2736 ( (msg
.wParam
& MK_LBUTTON
) ||
2737 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
.wParam
& MK_RBUTTON
))) )
2739 fEndMenu
|= !MENU_MouseMove( &mt
, hmenu
, wFlags
);
2741 } /* switch(msg.message) - mouse */
2743 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
2745 fRemove
= TRUE
; /* Keyboard messages are always removed */
2753 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2754 NO_SELECTED_ITEM
, FALSE
, 0 );
2757 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2758 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
2761 case VK_DOWN
: /* If on menu bar, pull-down the menu */
2763 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
2764 if (!(menu
->wFlags
& MF_POPUP
))
2765 mt
.hCurrentMenu
= MENU_ShowSubPopup(mt
.hOwnerWnd
, mt
.hTopMenu
, TRUE
, wFlags
);
2766 else /* otherwise try to move selection */
2767 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
, ITEM_NEXT
);
2771 MENU_KeyLeft( &mt
, wFlags
);
2775 MENU_KeyRight( &mt
, wFlags
);
2785 hi
.cbSize
= sizeof(HELPINFO
);
2786 hi
.iContextType
= HELPINFO_MENUITEM
;
2787 if (menu
->FocusedItem
== NO_SELECTED_ITEM
)
2790 hi
.iCtrlId
= menu
->items
[menu
->FocusedItem
].wID
;
2791 hi
.hItemHandle
= hmenu
;
2792 hi
.dwContextId
= menu
->dwContextHelpID
;
2793 hi
.MousePos
= msg
.pt
;
2794 SendMessageA(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
2801 break; /* WM_KEYDOWN */
2811 break; /* WM_SYSKEYDOWN */
2817 if (msg
.wParam
== '\r' || msg
.wParam
== ' ')
2819 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2820 fEndMenu
= (executedMenuId
!= -1);
2825 /* Hack to avoid control chars. */
2826 /* We will find a better way real soon... */
2827 if ((msg
.wParam
<= 32) || (msg
.wParam
>= 127)) break;
2829 pos
= MENU_FindItemByKey( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2830 LOWORD(msg
.wParam
), FALSE
);
2831 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
2832 else if (pos
== (UINT
)-1) MessageBeep(0);
2835 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
, pos
,
2837 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2838 fEndMenu
= (executedMenuId
!= -1);
2842 } /* switch(msg.message) - kbd */
2846 DispatchMessageA( &msg
);
2849 if (!fEndMenu
) fRemove
= TRUE
;
2851 /* finally remove message from the queue */
2853 if (fRemove
&& !(mt
.trackFlags
& TF_SKIPREMOVE
) )
2854 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2855 else mt
.trackFlags
&= ~TF_SKIPREMOVE
;
2860 menu
= MENU_GetMenu( mt
.hTopMenu
);
2862 if( IsWindow( mt
.hOwnerWnd
) )
2864 MENU_HideSubPopups( mt
.hOwnerWnd
, mt
.hTopMenu
, FALSE
);
2866 if (menu
&& menu
->wFlags
& MF_POPUP
)
2868 ShowWindow( menu
->hWnd
, SW_HIDE
);
2871 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
2872 SendMessageA( mt
.hOwnerWnd
, WM_MENUSELECT
, MAKELONG(0,0xffff), 0 );
2875 /* Reset the variable for hiding menu */
2876 menu
->bTimeToHide
= FALSE
;
2878 /* The return value is only used by TrackPopupMenu */
2879 return ((executedMenuId
!= -1) ? executedMenuId
: 0);
2882 /***********************************************************************
2885 static BOOL
MENU_InitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
2887 TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd
, hMenu
);
2891 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
2892 if (!(wFlags
& TPM_NONOTIFY
))
2893 SendMessageA( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
2895 SendMessageA( hWnd
, WM_SETCURSOR
, hWnd
, HTCAPTION
);
2897 if (!(wFlags
& TPM_NONOTIFY
))
2898 SendMessageA( hWnd
, WM_INITMENU
, hMenu
, 0 );
2902 /***********************************************************************
2905 static BOOL
MENU_ExitTracking(HWND hWnd
)
2907 TRACE("hwnd=0x%04x\n", hWnd
);
2909 SendMessageA( hWnd
, WM_EXITMENULOOP
, 0, 0 );
2914 /***********************************************************************
2915 * MENU_TrackMouseMenuBar
2917 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2919 void MENU_TrackMouseMenuBar( WND
* wndPtr
, INT ht
, POINT pt
)
2921 HWND hWnd
= wndPtr
->hwndSelf
;
2922 HMENU hMenu
= (ht
== HTSYSMENU
) ? wndPtr
->hSysMenu
: wndPtr
->wIDmenu
;
2923 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
2925 TRACE("pwnd=%p ht=0x%04x (%ld,%ld)\n", wndPtr
, ht
, pt
.x
, pt
.y
);
2929 MENU_InitTracking( hWnd
, hMenu
, FALSE
, wFlags
);
2930 MENU_TrackMenu( hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
2931 MENU_ExitTracking(hWnd
);
2936 /***********************************************************************
2937 * MENU_TrackKbdMenuBar
2939 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
2941 void MENU_TrackKbdMenuBar( WND
* wndPtr
, UINT wParam
, INT vkey
)
2943 UINT uItem
= NO_SELECTED_ITEM
;
2945 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
2947 /* find window that has a menu */
2949 while( wndPtr
->dwStyle
& WS_CHILD
)
2950 if( !(wndPtr
= wndPtr
->parent
) ) return;
2952 /* check if we have to track a system menu */
2954 if( (wndPtr
->dwStyle
& (WS_CHILD
| WS_MINIMIZE
)) ||
2955 !wndPtr
->wIDmenu
|| vkey
== VK_SPACE
)
2957 if( !(wndPtr
->dwStyle
& WS_SYSMENU
) ) return;
2958 hTrackMenu
= wndPtr
->hSysMenu
;
2960 wParam
|= HTSYSMENU
; /* prevent item lookup */
2963 hTrackMenu
= wndPtr
->wIDmenu
;
2965 if (IsMenu( hTrackMenu
))
2967 MENU_InitTracking( wndPtr
->hwndSelf
, hTrackMenu
, FALSE
, wFlags
);
2969 if( vkey
&& vkey
!= VK_SPACE
)
2971 uItem
= MENU_FindItemByKey( wndPtr
->hwndSelf
, hTrackMenu
,
2972 vkey
, (wParam
& HTSYSMENU
) );
2973 if( uItem
>= (UINT
)(-2) )
2975 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
2982 MENU_SelectItem( wndPtr
->hwndSelf
, hTrackMenu
, uItem
, TRUE
, 0 );
2984 if( uItem
== NO_SELECTED_ITEM
)
2985 MENU_MoveSelection( wndPtr
->hwndSelf
, hTrackMenu
, ITEM_NEXT
);
2987 PostMessageA( wndPtr
->hwndSelf
, WM_KEYDOWN
, VK_DOWN
, 0L );
2989 MENU_TrackMenu( hTrackMenu
, wFlags
, 0, 0, wndPtr
->hwndSelf
, NULL
);
2992 MENU_ExitTracking (wndPtr
->hwndSelf
);
2997 /**********************************************************************
2998 * TrackPopupMenu16 (USER.416)
3000 BOOL16 WINAPI
TrackPopupMenu16( HMENU16 hMenu
, UINT16 wFlags
, INT16 x
, INT16 y
,
3001 INT16 nReserved
, HWND16 hWnd
, const RECT16
*lpRect
)
3005 CONV_RECT16TO32( lpRect
, &r
);
3006 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, nReserved
, hWnd
,
3007 lpRect
? &r
: NULL
);
3011 /**********************************************************************
3012 * TrackPopupMenu (USER32.549)
3014 * Like the win32 API, the function return the command ID only if the
3015 * flag TPM_RETURNCMD is on.
3018 BOOL WINAPI
TrackPopupMenu( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3019 INT nReserved
, HWND hWnd
, const RECT
*lpRect
)
3023 MENU_InitTracking(hWnd
, hMenu
, TRUE
, wFlags
);
3025 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3026 if (!(wFlags
& TPM_NONOTIFY
))
3027 SendMessageA( hWnd
, WM_INITMENUPOPUP
, hMenu
, 0);
3029 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
, 0, 0 ))
3030 ret
= MENU_TrackMenu( hMenu
, wFlags
| TPM_POPUPMENU
, 0, 0, hWnd
, lpRect
);
3031 MENU_ExitTracking(hWnd
);
3033 if( (!(wFlags
& TPM_RETURNCMD
)) && (ret
!= FALSE
) )
3039 /**********************************************************************
3040 * TrackPopupMenuEx (USER32.550)
3042 BOOL WINAPI
TrackPopupMenuEx( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3043 HWND hWnd
, LPTPMPARAMS lpTpm
)
3045 FIXME("not fully implemented\n" );
3046 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, 0, hWnd
,
3047 lpTpm
? &lpTpm
->rcExclude
: NULL
);
3050 /***********************************************************************
3053 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3055 LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
,
3058 WND
* wndPtr
= WIN_FindWndPtr(hwnd
);
3061 TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
3062 hwnd
, message
, wParam
, lParam
);
3068 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*)lParam
;
3069 SetWindowLongA( hwnd
, 0, (LONG
)cs
->lpCreateParams
);
3074 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
3075 retvalue
= MA_NOACTIVATE
;
3081 BeginPaint( hwnd
, &ps
);
3082 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
3083 (HMENU
)GetWindowLongA( hwnd
, 0 ) );
3084 EndPaint( hwnd
, &ps
);
3094 /* zero out global pointer in case resident popup window
3095 * was somehow destroyed. */
3097 if(MENU_GetTopPopupWnd() )
3099 if( hwnd
== pTopPopupWnd
->hwndSelf
)
3101 ERR("resident popup destroyed!\n");
3103 MENU_DestroyTopPopupWnd();
3108 MENU_ReleaseTopPopupWnd();
3116 if( !(*(HMENU
*)wndPtr
->wExtra
) )
3117 ERR("no menu to display\n");
3120 *(HMENU
*)wndPtr
->wExtra
= 0;
3123 case MM_SETMENUHANDLE
:
3125 *(HMENU
*)wndPtr
->wExtra
= (HMENU
)wParam
;
3128 case MM_GETMENUHANDLE
:
3130 retvalue
= *(HMENU
*)wndPtr
->wExtra
;
3134 retvalue
= DefWindowProcA( hwnd
, message
, wParam
, lParam
);
3139 WIN_ReleaseWndPtr(wndPtr
);
3144 /***********************************************************************
3145 * MENU_GetMenuBarHeight
3147 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3149 UINT
MENU_GetMenuBarHeight( HWND hwnd
, UINT menubarWidth
,
3150 INT orgX
, INT orgY
)
3158 TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3159 hwnd
, menubarWidth
, orgX
, orgY
);
3161 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
3164 if (!(lppop
= MENU_GetMenu((HMENU16
)wndPtr
->wIDmenu
)))
3166 WIN_ReleaseWndPtr(wndPtr
);
3170 hdc
= GetDCEx( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3171 SelectObject( hdc
, hMenuFont
);
3172 SetRect(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+GetSystemMetrics(SM_CYMENU
));
3173 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
3174 ReleaseDC( hwnd
, hdc
);
3175 retvalue
= lppop
->Height
;
3176 WIN_ReleaseWndPtr(wndPtr
);
3181 /*******************************************************************
3182 * ChangeMenu16 (USER.153)
3184 BOOL16 WINAPI
ChangeMenu16( HMENU16 hMenu
, UINT16 pos
, SEGPTR data
,
3185 UINT16 id
, UINT16 flags
)
3187 TRACE("menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
3188 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3189 if (flags
& MF_APPEND
) return AppendMenu16( hMenu
, flags
& ~MF_APPEND
,
3192 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
3193 /* for MF_DELETE. We should check the parameters for all others */
3194 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
3196 if (flags
& MF_DELETE
) return DeleteMenu16(hMenu
, pos
, flags
& ~MF_DELETE
);
3197 if (flags
& MF_CHANGE
) return ModifyMenu16(hMenu
, pos
, flags
& ~MF_CHANGE
,
3199 if (flags
& MF_REMOVE
) return RemoveMenu16(hMenu
,
3200 flags
& MF_BYPOSITION
? pos
: id
,
3201 flags
& ~MF_REMOVE
);
3202 /* Default: MF_INSERT */
3203 return InsertMenu16( hMenu
, pos
, flags
, id
, data
);
3207 /*******************************************************************
3208 * ChangeMenuA (USER32.23)
3210 BOOL WINAPI
ChangeMenuA( HMENU hMenu
, UINT pos
, LPCSTR data
,
3211 UINT id
, UINT flags
)
3213 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3214 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3215 if (flags
& MF_APPEND
) return AppendMenuA( hMenu
, flags
& ~MF_APPEND
,
3217 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3218 if (flags
& MF_CHANGE
) return ModifyMenuA(hMenu
, pos
, flags
& ~MF_CHANGE
,
3220 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3221 flags
& MF_BYPOSITION
? pos
: id
,
3222 flags
& ~MF_REMOVE
);
3223 /* Default: MF_INSERT */
3224 return InsertMenuA( hMenu
, pos
, flags
, id
, data
);
3228 /*******************************************************************
3229 * ChangeMenuW (USER32.24)
3231 BOOL WINAPI
ChangeMenuW( HMENU hMenu
, UINT pos
, LPCWSTR data
,
3232 UINT id
, UINT flags
)
3234 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3235 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3236 if (flags
& MF_APPEND
) return AppendMenuW( hMenu
, flags
& ~MF_APPEND
,
3238 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3239 if (flags
& MF_CHANGE
) return ModifyMenuW(hMenu
, pos
, flags
& ~MF_CHANGE
,
3241 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3242 flags
& MF_BYPOSITION
? pos
: id
,
3243 flags
& ~MF_REMOVE
);
3244 /* Default: MF_INSERT */
3245 return InsertMenuW( hMenu
, pos
, flags
, id
, data
);
3249 /*******************************************************************
3250 * CheckMenuItem16 (USER.154)
3252 BOOL16 WINAPI
CheckMenuItem16( HMENU16 hMenu
, UINT16 id
, UINT16 flags
)
3254 return (BOOL16
)CheckMenuItem( hMenu
, id
, flags
);
3258 /*******************************************************************
3259 * CheckMenuItem (USER32.46)
3261 DWORD WINAPI
CheckMenuItem( HMENU hMenu
, UINT id
, UINT flags
)
3266 TRACE("menu=%04x id=%04x flags=%04x\n", hMenu
, id
, flags
);
3267 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
3268 ret
= item
->fState
& MF_CHECKED
;
3269 if (flags
& MF_CHECKED
) item
->fState
|= MF_CHECKED
;
3270 else item
->fState
&= ~MF_CHECKED
;
3275 /**********************************************************************
3276 * EnableMenuItem16 (USER.155)
3278 UINT16 WINAPI
EnableMenuItem16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3280 return EnableMenuItem( hMenu
, wItemID
, wFlags
);
3284 /**********************************************************************
3285 * EnableMenuItem (USER32.170)
3287 UINT WINAPI
EnableMenuItem( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3293 TRACE("(%04x, %04X, %04X) !\n",
3294 hMenu
, wItemID
, wFlags
);
3296 /* Get the Popupmenu to access the owner menu */
3297 if (!(menu
= MENU_GetMenu(hMenu
)))
3300 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
)))
3303 oldflags
= item
->fState
& (MF_GRAYED
| MF_DISABLED
);
3304 item
->fState
^= (oldflags
^ wFlags
) & (MF_GRAYED
| MF_DISABLED
);
3306 /* In win95 if the close item in the system menu change update the close button */
3307 if (TWEAK_WineLook
== WIN95_LOOK
)
3308 if((item
->wID
== SC_CLOSE
) && (oldflags
!= wFlags
))
3310 if (menu
->hSysMenuOwner
!= 0)
3312 POPUPMENU
* parentMenu
;
3314 /* Get the parent menu to access*/
3315 if (!(parentMenu
= MENU_GetMenu(menu
->hSysMenuOwner
)))
3318 /* Refresh the frame to reflect the change*/
3319 SetWindowPos(parentMenu
->hWnd
, 0, 0, 0, 0, 0,
3320 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
3328 /*******************************************************************
3329 * GetMenuString16 (USER.161)
3331 INT16 WINAPI
GetMenuString16( HMENU16 hMenu
, UINT16 wItemID
,
3332 LPSTR str
, INT16 nMaxSiz
, UINT16 wFlags
)
3334 return GetMenuStringA( hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3338 /*******************************************************************
3339 * GetMenuStringA (USER32.268)
3341 INT WINAPI
GetMenuStringA(
3342 HMENU hMenu
, /* [in] menuhandle */
3343 UINT wItemID
, /* [in] menu item (dep. on wFlags) */
3344 LPSTR str
, /* [out] outbuffer. If NULL, func returns entry length*/
3345 INT nMaxSiz
, /* [in] length of buffer. if 0, func returns entry len*/
3346 UINT wFlags
/* [in] MF_ flags */
3350 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3351 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3352 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3353 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3354 if (!str
|| !nMaxSiz
) return strlen(item
->text
);
3356 lstrcpynA( str
, item
->text
, nMaxSiz
);
3357 TRACE("returning '%s'\n", str
);
3362 /*******************************************************************
3363 * GetMenuStringW (USER32.269)
3365 INT WINAPI
GetMenuStringW( HMENU hMenu
, UINT wItemID
,
3366 LPWSTR str
, INT nMaxSiz
, UINT wFlags
)
3370 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3371 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3372 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3373 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3374 if (!str
|| !nMaxSiz
) return strlen(item
->text
);
3376 lstrcpynAtoW( str
, item
->text
, nMaxSiz
);
3377 return lstrlenW(str
);
3381 /**********************************************************************
3382 * HiliteMenuItem16 (USER.162)
3384 BOOL16 WINAPI
HiliteMenuItem16( HWND16 hWnd
, HMENU16 hMenu
, UINT16 wItemID
,
3387 return HiliteMenuItem( hWnd
, hMenu
, wItemID
, wHilite
);
3391 /**********************************************************************
3392 * HiliteMenuItem (USER32.318)
3394 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
3398 TRACE("(%04x, %04x, %04x, %04x);\n",
3399 hWnd
, hMenu
, wItemID
, wHilite
);
3400 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
3401 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3402 if (menu
->FocusedItem
== wItemID
) return TRUE
;
3403 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
3404 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
, 0 );
3409 /**********************************************************************
3410 * GetMenuState16 (USER.250)
3412 UINT16 WINAPI
GetMenuState16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3414 return GetMenuState( hMenu
, wItemID
, wFlags
);
3418 /**********************************************************************
3419 * GetMenuState (USER32.267)
3421 UINT WINAPI
GetMenuState( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3424 TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
3425 hMenu
, wItemID
, wFlags
);
3426 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
3427 debug_print_menuitem (" item: ", item
, "");
3428 if (item
->fType
& MF_POPUP
)
3430 POPUPMENU
*menu
= MENU_GetMenu( item
->hSubMenu
);
3431 if (!menu
) return -1;
3432 else return (menu
->nItems
<< 8) | ((item
->fState
|item
->fType
) & 0xff);
3436 /* We used to (from way back then) mask the result to 0xff. */
3437 /* I don't know why and it seems wrong as the documented */
3438 /* return flag MF_SEPARATOR is outside that mask. */
3439 return (item
->fType
| item
->fState
);
3444 /**********************************************************************
3445 * GetMenuItemCount16 (USER.263)
3447 INT16 WINAPI
GetMenuItemCount16( HMENU16 hMenu
)
3449 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3450 if (!menu
) return -1;
3451 TRACE("(%04x) returning %d\n",
3452 hMenu
, menu
->nItems
);
3453 return menu
->nItems
;
3457 /**********************************************************************
3458 * GetMenuItemCount (USER32.262)
3460 INT WINAPI
GetMenuItemCount( HMENU hMenu
)
3462 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3463 if (!menu
) return -1;
3464 TRACE("(%04x) returning %d\n",
3465 hMenu
, menu
->nItems
);
3466 return menu
->nItems
;
3469 /**********************************************************************
3470 * GetMenuItemID16 (USER.264)
3472 UINT16 WINAPI
GetMenuItemID16( HMENU16 hMenu
, INT16 nPos
)
3474 return (UINT16
) GetMenuItemID (hMenu
, nPos
);
3477 /**********************************************************************
3478 * GetMenuItemID (USER32.263)
3480 UINT WINAPI
GetMenuItemID( HMENU hMenu
, INT nPos
)
3484 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return 0;
3485 if (lpmi
->fType
& MF_POPUP
) return -1;
3490 /*******************************************************************
3491 * InsertMenu16 (USER.410)
3493 BOOL16 WINAPI
InsertMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3494 UINT16 id
, SEGPTR data
)
3496 UINT pos32
= (UINT
)pos
;
3497 if ((pos
== (UINT16
)-1) && (flags
& MF_BYPOSITION
)) pos32
= (UINT
)-1;
3498 if (IS_STRING_ITEM(flags
) && data
)
3499 return InsertMenuA( hMenu
, pos32
, flags
, id
,
3500 (LPSTR
)PTR_SEG_TO_LIN(data
) );
3501 return InsertMenuA( hMenu
, pos32
, flags
, id
, (LPSTR
)data
);
3505 /*******************************************************************
3506 * InsertMenuA (USER32.322)
3508 BOOL WINAPI
InsertMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3509 UINT id
, LPCSTR str
)
3513 if (IS_STRING_ITEM(flags
) && str
)
3514 TRACE("hMenu %04x, pos %d, flags %08x, "
3515 "id %04x, str '%s'\n",
3516 hMenu
, pos
, flags
, id
, str
);
3517 else TRACE("hMenu %04x, pos %d, flags %08x, "
3518 "id %04x, str %08lx (not a string)\n",
3519 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3521 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
3523 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
3525 RemoveMenu( hMenu
, pos
, flags
);
3529 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
3530 (MENU_GetMenu((HMENU16
)id
))->wFlags
|= MF_POPUP
;
3532 item
->hCheckBit
= item
->hUnCheckBit
= 0;
3537 /*******************************************************************
3538 * InsertMenuW (USER32.325)
3540 BOOL WINAPI
InsertMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3541 UINT id
, LPCWSTR str
)
3545 if (IS_STRING_ITEM(flags
) && str
)
3547 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
3548 ret
= InsertMenuA( hMenu
, pos
, flags
, id
, newstr
);
3549 HeapFree( GetProcessHeap(), 0, newstr
);
3552 else return InsertMenuA( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
3556 /*******************************************************************
3557 * AppendMenu16 (USER.411)
3559 BOOL16 WINAPI
AppendMenu16(HMENU16 hMenu
, UINT16 flags
, UINT16 id
, SEGPTR data
)
3561 return InsertMenu16( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3565 /*******************************************************************
3566 * AppendMenuA (USER32.5)
3568 BOOL WINAPI
AppendMenuA( HMENU hMenu
, UINT flags
,
3569 UINT id
, LPCSTR data
)
3571 return InsertMenuA( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3575 /*******************************************************************
3576 * AppendMenuW (USER32.6)
3578 BOOL WINAPI
AppendMenuW( HMENU hMenu
, UINT flags
,
3579 UINT id
, LPCWSTR data
)
3581 return InsertMenuW( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3585 /**********************************************************************
3586 * RemoveMenu16 (USER.412)
3588 BOOL16 WINAPI
RemoveMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3590 return RemoveMenu( hMenu
, nPos
, wFlags
);
3594 /**********************************************************************
3595 * RemoveMenu (USER32.441)
3597 BOOL WINAPI
RemoveMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3602 TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu
, nPos
, wFlags
);
3603 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3604 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3608 MENU_FreeItemData( item
);
3610 if (--menu
->nItems
== 0)
3612 HeapFree( SystemHeap
, 0, menu
->items
);
3617 while(nPos
< menu
->nItems
)
3623 menu
->items
= HeapReAlloc( SystemHeap
, 0, menu
->items
,
3624 menu
->nItems
* sizeof(MENUITEM
) );
3630 /**********************************************************************
3631 * DeleteMenu16 (USER.413)
3633 BOOL16 WINAPI
DeleteMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3635 return DeleteMenu( hMenu
, nPos
, wFlags
);
3639 /**********************************************************************
3640 * DeleteMenu (USER32.129)
3642 BOOL WINAPI
DeleteMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3644 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
3645 if (!item
) return FALSE
;
3646 if (item
->fType
& MF_POPUP
) DestroyMenu( item
->hSubMenu
);
3647 /* nPos is now the position of the item */
3648 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
3653 /*******************************************************************
3654 * ModifyMenu16 (USER.414)
3656 BOOL16 WINAPI
ModifyMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3657 UINT16 id
, SEGPTR data
)
3659 if (IS_STRING_ITEM(flags
))
3660 return ModifyMenuA( hMenu
, pos
, flags
, id
,
3661 (LPSTR
)PTR_SEG_TO_LIN(data
) );
3662 return ModifyMenuA( hMenu
, pos
, flags
, id
, (LPSTR
)data
);
3666 /*******************************************************************
3667 * ModifyMenuA (USER32.397)
3669 BOOL WINAPI
ModifyMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3670 UINT id
, LPCSTR str
)
3674 if (IS_STRING_ITEM(flags
))
3676 TRACE("%04x %d %04x %04x '%s'\n",
3677 hMenu
, pos
, flags
, id
, str
? str
: "#NULL#" );
3678 if (!str
) return FALSE
;
3682 TRACE("%04x %d %04x %04x %08lx\n",
3683 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3686 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
3687 return MENU_SetItemData( item
, flags
, id
, str
);
3691 /*******************************************************************
3692 * ModifyMenuW (USER32.398)
3694 BOOL WINAPI
ModifyMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3695 UINT id
, LPCWSTR str
)
3699 if (IS_STRING_ITEM(flags
) && str
)
3701 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
3702 ret
= ModifyMenuA( hMenu
, pos
, flags
, id
, newstr
);
3703 HeapFree( GetProcessHeap(), 0, newstr
);
3706 else return ModifyMenuA( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
3710 /**********************************************************************
3711 * CreatePopupMenu16 (USER.415)
3713 HMENU16 WINAPI
CreatePopupMenu16(void)
3715 return CreatePopupMenu();
3719 /**********************************************************************
3720 * CreatePopupMenu (USER32.82)
3722 HMENU WINAPI
CreatePopupMenu(void)
3727 if (!(hmenu
= CreateMenu())) return 0;
3728 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
3729 menu
->wFlags
|= MF_POPUP
;
3730 menu
->bTimeToHide
= FALSE
;
3735 /**********************************************************************
3736 * GetMenuCheckMarkDimensions (USER.417) (USER32.258)
3738 DWORD WINAPI
GetMenuCheckMarkDimensions(void)
3740 return MAKELONG( check_bitmap_width
, check_bitmap_height
);
3744 /**********************************************************************
3745 * SetMenuItemBitmaps16 (USER.418)
3747 BOOL16 WINAPI
SetMenuItemBitmaps16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
,
3748 HBITMAP16 hNewUnCheck
, HBITMAP16 hNewCheck
)
3750 return SetMenuItemBitmaps( hMenu
, nPos
, wFlags
, hNewUnCheck
, hNewCheck
);
3754 /**********************************************************************
3755 * SetMenuItemBitmaps (USER32.490)
3757 BOOL WINAPI
SetMenuItemBitmaps( HMENU hMenu
, UINT nPos
, UINT wFlags
,
3758 HBITMAP hNewUnCheck
, HBITMAP hNewCheck
)
3761 TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3762 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
3763 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3765 if (!hNewCheck
&& !hNewUnCheck
)
3767 item
->fState
&= ~MF_USECHECKBITMAPS
;
3769 else /* Install new bitmaps */
3771 item
->hCheckBit
= hNewCheck
;
3772 item
->hUnCheckBit
= hNewUnCheck
;
3773 item
->fState
|= MF_USECHECKBITMAPS
;
3779 /**********************************************************************
3780 * CreateMenu16 (USER.151)
3782 HMENU16 WINAPI
CreateMenu16(void)
3784 return CreateMenu();
3788 /**********************************************************************
3789 * CreateMenu (USER32.81)
3791 HMENU WINAPI
CreateMenu(void)
3795 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) ))) return 0;
3796 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3798 ZeroMemory(menu
, sizeof(POPUPMENU
));
3799 menu
->wMagic
= MENU_MAGIC
;
3800 menu
->FocusedItem
= NO_SELECTED_ITEM
;
3801 menu
->bTimeToHide
= FALSE
;
3803 TRACE("return %04x\n", hMenu
);
3809 /**********************************************************************
3810 * DestroyMenu16 (USER.152)
3812 BOOL16 WINAPI
DestroyMenu16( HMENU16 hMenu
)
3814 return DestroyMenu( hMenu
);
3818 /**********************************************************************
3819 * DestroyMenu (USER32.134)
3821 BOOL WINAPI
DestroyMenu( HMENU hMenu
)
3823 TRACE("(%04x)\n", hMenu
);
3825 /* Silently ignore attempts to destroy default system popup */
3827 if (hMenu
&& hMenu
!= MENU_DefSysPopup
)
3829 LPPOPUPMENU lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3830 WND
*pTPWnd
= MENU_GetTopPopupWnd();
3832 if( pTPWnd
&& (hMenu
== *(HMENU
*)pTPWnd
->wExtra
) )
3833 *(UINT
*)pTPWnd
->wExtra
= 0;
3835 if (!IS_A_MENU(lppop
)) lppop
= NULL
;
3838 lppop
->wMagic
= 0; /* Mark it as destroyed */
3840 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
&&
3841 (!pTPWnd
|| (lppop
->hWnd
!= pTPWnd
->hwndSelf
)))
3842 DestroyWindow( lppop
->hWnd
);
3844 if (lppop
->items
) /* recursively destroy submenus */
3847 MENUITEM
*item
= lppop
->items
;
3848 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
3850 if (item
->fType
& MF_POPUP
) DestroyMenu(item
->hSubMenu
);
3851 MENU_FreeItemData( item
);
3853 HeapFree( SystemHeap
, 0, lppop
->items
);
3855 USER_HEAP_FREE( hMenu
);
3856 MENU_ReleaseTopPopupWnd();
3860 MENU_ReleaseTopPopupWnd();
3864 return (hMenu
!= MENU_DefSysPopup
);
3868 /**********************************************************************
3869 * GetSystemMenu16 (USER.156)
3871 HMENU16 WINAPI
GetSystemMenu16( HWND16 hWnd
, BOOL16 bRevert
)
3873 return GetSystemMenu( hWnd
, bRevert
);
3877 /**********************************************************************
3878 * GetSystemMenu (USER32.291)
3880 HMENU WINAPI
GetSystemMenu( HWND hWnd
, BOOL bRevert
)
3882 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
3887 if( wndPtr
->hSysMenu
)
3891 DestroyMenu(wndPtr
->hSysMenu
);
3892 wndPtr
->hSysMenu
= 0;
3896 POPUPMENU
*menu
= MENU_GetMenu( wndPtr
->hSysMenu
);
3899 if( menu
->nItems
> 0 && menu
->items
[0].hSubMenu
== MENU_DefSysPopup
)
3900 menu
->items
[0].hSubMenu
= MENU_CopySysPopup();
3904 WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
3905 wndPtr
->hSysMenu
, hWnd
);
3906 wndPtr
->hSysMenu
= 0;
3911 if(!wndPtr
->hSysMenu
&& (wndPtr
->dwStyle
& WS_SYSMENU
) )
3912 wndPtr
->hSysMenu
= MENU_GetSysMenu( hWnd
, (HMENU
)(-1) );
3914 if( wndPtr
->hSysMenu
)
3917 retvalue
= GetSubMenu16(wndPtr
->hSysMenu
, 0);
3919 /* Store the dummy sysmenu handle to facilitate the refresh */
3920 /* of the close button if the SC_CLOSE item change */
3921 menu
= MENU_GetMenu(retvalue
);
3923 menu
->hSysMenuOwner
= wndPtr
->hSysMenu
;
3925 WIN_ReleaseWndPtr(wndPtr
);
3931 /*******************************************************************
3932 * SetSystemMenu16 (USER.280)
3934 BOOL16 WINAPI
SetSystemMenu16( HWND16 hwnd
, HMENU16 hMenu
)
3936 return SetSystemMenu( hwnd
, hMenu
);
3940 /*******************************************************************
3941 * SetSystemMenu (USER32.508)
3943 BOOL WINAPI
SetSystemMenu( HWND hwnd
, HMENU hMenu
)
3945 WND
*wndPtr
= WIN_FindWndPtr(hwnd
);
3949 if (wndPtr
->hSysMenu
) DestroyMenu( wndPtr
->hSysMenu
);
3950 wndPtr
->hSysMenu
= MENU_GetSysMenu( hwnd
, hMenu
);
3951 WIN_ReleaseWndPtr(wndPtr
);
3958 /**********************************************************************
3959 * GetMenu16 (USER.157)
3961 HMENU16 WINAPI
GetMenu16( HWND16 hWnd
)
3963 return (HMENU16
)GetMenu(hWnd
);
3967 /**********************************************************************
3968 * GetMenu (USER32.257)
3970 HMENU WINAPI
GetMenu( HWND hWnd
)
3973 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
3974 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
3976 retvalue
= (HMENU
)wndPtr
->wIDmenu
;
3981 WIN_ReleaseWndPtr(wndPtr
);
3986 /**********************************************************************
3987 * SetMenu16 (USER.158)
3989 BOOL16 WINAPI
SetMenu16( HWND16 hWnd
, HMENU16 hMenu
)
3991 return SetMenu( hWnd
, hMenu
);
3995 /**********************************************************************
3996 * SetMenu (USER32.487)
3998 BOOL WINAPI
SetMenu( HWND hWnd
, HMENU hMenu
)
4000 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
4002 TRACE("(%04x, %04x);\n", hWnd
, hMenu
);
4004 if (hMenu
&& !IsMenu(hMenu
))
4006 WARN("hMenu is not a menu handle\n");
4011 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
4013 if (GetCapture() == hWnd
) ReleaseCapture();
4015 wndPtr
->wIDmenu
= (UINT
)hMenu
;
4020 if (!(lpmenu
= MENU_GetMenu(hMenu
)))
4022 WIN_ReleaseWndPtr(wndPtr
);
4025 lpmenu
->hWnd
= hWnd
;
4026 lpmenu
->wFlags
&= ~MF_POPUP
; /* Can't be a popup */
4027 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
4029 if (IsWindowVisible(hWnd
))
4030 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4031 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4032 WIN_ReleaseWndPtr(wndPtr
);
4035 WIN_ReleaseWndPtr(wndPtr
);
4041 /**********************************************************************
4042 * GetSubMenu16 (USER.159)
4044 HMENU16 WINAPI
GetSubMenu16( HMENU16 hMenu
, INT16 nPos
)
4046 return GetSubMenu( hMenu
, nPos
);
4050 /**********************************************************************
4051 * GetSubMenu (USER32.288)
4053 HMENU WINAPI
GetSubMenu( HMENU hMenu
, INT nPos
)
4057 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return 0;
4058 if (!(lpmi
->fType
& MF_POPUP
)) return 0;
4059 return lpmi
->hSubMenu
;
4063 /**********************************************************************
4064 * DrawMenuBar16 (USER.160)
4066 void WINAPI
DrawMenuBar16( HWND16 hWnd
)
4068 DrawMenuBar( hWnd
);
4072 /**********************************************************************
4073 * DrawMenuBar (USER32.161)
4075 BOOL WINAPI
DrawMenuBar( HWND hWnd
)
4078 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
4079 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
) && wndPtr
->wIDmenu
)
4081 lppop
= MENU_GetMenu((HMENU16
)wndPtr
->wIDmenu
);
4084 WIN_ReleaseWndPtr(wndPtr
);
4088 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
4089 lppop
->hwndOwner
= hWnd
;
4090 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4091 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4092 WIN_ReleaseWndPtr(wndPtr
);
4095 WIN_ReleaseWndPtr(wndPtr
);
4100 /***********************************************************************
4101 * EndMenu (USER.187) (USER32.175)
4103 void WINAPI
EndMenu(void)
4106 * FIXME: NOT ENOUGH! This has to cancel menu tracking right away.
4113 /***********************************************************************
4114 * LookupMenuHandle (USER.217)
4116 HMENU16 WINAPI
LookupMenuHandle16( HMENU16 hmenu
, INT16 id
)
4118 HMENU hmenu32
= hmenu
;
4120 if (!MENU_FindItem( &hmenu32
, &id32
, MF_BYCOMMAND
)) return 0;
4121 else return hmenu32
;
4125 /**********************************************************************
4126 * LoadMenu16 (USER.150)
4128 HMENU16 WINAPI
LoadMenu16( HINSTANCE16 instance
, SEGPTR name
)
4136 char *str
= (char *)PTR_SEG_TO_LIN( name
);
4137 TRACE("(%04x,'%s')\n", instance
, str
);
4138 if (str
[0] == '#') name
= (SEGPTR
)atoi( str
+ 1 );
4141 TRACE("(%04x,%04x)\n",instance
,LOWORD(name
));
4143 if (!name
) return 0;
4145 /* check for Win32 module */
4146 if (HIWORD(instance
))
4147 return LoadMenuA(instance
,PTR_SEG_TO_LIN(name
));
4148 instance
= GetExePtr( instance
);
4150 if (!(hRsrc
= FindResource16( instance
, name
, RT_MENU16
))) return 0;
4151 if (!(handle
= LoadResource16( instance
, hRsrc
))) return 0;
4152 hMenu
= LoadMenuIndirect16(LockResource16(handle
));
4153 FreeResource16( handle
);
4158 /*****************************************************************
4159 * LoadMenuA (USER32.370)
4161 HMENU WINAPI
LoadMenuA( HINSTANCE instance
, LPCSTR name
)
4163 HRSRC hrsrc
= FindResourceA( instance
, name
, RT_MENUA
);
4164 if (!hrsrc
) return 0;
4165 return LoadMenuIndirectA( (LPCVOID
)LoadResource( instance
, hrsrc
));
4169 /*****************************************************************
4170 * LoadMenuW (USER32.373)
4172 HMENU WINAPI
LoadMenuW( HINSTANCE instance
, LPCWSTR name
)
4174 HRSRC hrsrc
= FindResourceW( instance
, name
, RT_MENUW
);
4175 if (!hrsrc
) return 0;
4176 return LoadMenuIndirectW( (LPCVOID
)LoadResource( instance
, hrsrc
));
4180 /**********************************************************************
4181 * LoadMenuIndirect16 (USER.220)
4183 HMENU16 WINAPI
LoadMenuIndirect16( LPCVOID
template )
4186 WORD version
, offset
;
4187 LPCSTR p
= (LPCSTR
)template;
4189 TRACE("(%p)\n", template );
4190 version
= GET_WORD(p
);
4194 WARN("version must be 0 for Win16\n" );
4197 offset
= GET_WORD(p
);
4198 p
+= sizeof(WORD
) + offset
;
4199 if (!(hMenu
= CreateMenu())) return 0;
4200 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
4202 DestroyMenu( hMenu
);
4209 /**********************************************************************
4210 * LoadMenuIndirectA (USER32.371)
4212 HMENU WINAPI
LoadMenuIndirectA( LPCVOID
template )
4215 WORD version
, offset
;
4216 LPCSTR p
= (LPCSTR
)template;
4218 TRACE("%p\n", template );
4219 version
= GET_WORD(p
);
4224 offset
= GET_WORD(p
);
4225 p
+= sizeof(WORD
) + offset
;
4226 if (!(hMenu
= CreateMenu())) return 0;
4227 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
4229 DestroyMenu( hMenu
);
4234 offset
= GET_WORD(p
);
4235 p
+= sizeof(WORD
) + offset
;
4236 if (!(hMenu
= CreateMenu())) return 0;
4237 if (!MENUEX_ParseResource( p
, hMenu
))
4239 DestroyMenu( hMenu
);
4244 ERR("version %d not supported.\n", version
);
4250 /**********************************************************************
4251 * LoadMenuIndirectW (USER32.372)
4253 HMENU WINAPI
LoadMenuIndirectW( LPCVOID
template )
4255 /* FIXME: is there anything different between A and W? */
4256 return LoadMenuIndirectA( template );
4260 /**********************************************************************
4261 * IsMenu16 (USER.358)
4263 BOOL16 WINAPI
IsMenu16( HMENU16 hmenu
)
4265 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
4266 return IS_A_MENU(menu
);
4270 /**********************************************************************
4271 * IsMenu (USER32.346)
4273 BOOL WINAPI
IsMenu(HMENU hmenu
)
4275 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
4276 return IS_A_MENU(menu
);
4279 /**********************************************************************
4280 * GetMenuItemInfo_common
4283 static BOOL
GetMenuItemInfo_common ( HMENU hmenu
, UINT item
, BOOL bypos
,
4284 LPMENUITEMINFOA lpmii
, BOOL unicode
)
4286 MENUITEM
*menu
= MENU_FindItem (&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0);
4288 debug_print_menuitem("GetMenuItemInfo_common: ", menu
, "");
4293 if (lpmii
->fMask
& MIIM_TYPE
) {
4294 lpmii
->fType
= menu
->fType
;
4295 switch (MENU_ITEM_TYPE(menu
->fType
)) {
4298 int len
= lstrlenA(menu
->text
);
4299 if(lpmii
->dwTypeData
&& lpmii
->cch
) {
4301 lstrcpynAtoW((LPWSTR
) lpmii
->dwTypeData
, menu
->text
,
4304 lstrcpynA(lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4305 /* if we've copied a substring we return its length */
4306 if(lpmii
->cch
<= len
)
4308 } else /* return length of string */
4314 lpmii
->dwTypeData
= menu
->text
;
4321 if (lpmii
->fMask
& MIIM_STRING
) {
4322 if(lpmii
->dwTypeData
&& lpmii
->cch
) {
4324 lstrcpynAtoW((LPWSTR
) lpmii
->dwTypeData
, menu
->text
,
4327 lstrcpynA(lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4329 lpmii
->cch
= lstrlenA(menu
->text
);
4332 if (lpmii
->fMask
& MIIM_FTYPE
)
4333 lpmii
->fType
= menu
->fType
;
4335 if (lpmii
->fMask
& MIIM_BITMAP
)
4336 lpmii
->hbmpItem
= menu
->hbmpItem
;
4338 if (lpmii
->fMask
& MIIM_STATE
)
4339 lpmii
->fState
= menu
->fState
;
4341 if (lpmii
->fMask
& MIIM_ID
)
4342 lpmii
->wID
= menu
->wID
;
4344 if (lpmii
->fMask
& MIIM_SUBMENU
)
4345 lpmii
->hSubMenu
= menu
->hSubMenu
;
4347 if (lpmii
->fMask
& MIIM_CHECKMARKS
) {
4348 lpmii
->hbmpChecked
= menu
->hCheckBit
;
4349 lpmii
->hbmpUnchecked
= menu
->hUnCheckBit
;
4351 if (lpmii
->fMask
& MIIM_DATA
)
4352 lpmii
->dwItemData
= menu
->dwItemData
;
4357 /**********************************************************************
4358 * GetMenuItemInfoA (USER32.264)
4360 BOOL WINAPI
GetMenuItemInfoA( HMENU hmenu
, UINT item
, BOOL bypos
,
4361 LPMENUITEMINFOA lpmii
)
4363 return GetMenuItemInfo_common (hmenu
, item
, bypos
, lpmii
, FALSE
);
4366 /**********************************************************************
4367 * GetMenuItemInfoW (USER32.265)
4369 BOOL WINAPI
GetMenuItemInfoW( HMENU hmenu
, UINT item
, BOOL bypos
,
4370 LPMENUITEMINFOW lpmii
)
4372 return GetMenuItemInfo_common (hmenu
, item
, bypos
,
4373 (LPMENUITEMINFOA
)lpmii
, TRUE
);
4376 /**********************************************************************
4377 * SetMenuItemInfo_common
4380 static BOOL
SetMenuItemInfo_common(MENUITEM
* menu
,
4381 const MENUITEMINFOA
*lpmii
,
4384 if (!menu
) return FALSE
;
4386 if (lpmii
->fMask
& MIIM_TYPE
) {
4387 /* Get rid of old string. */
4388 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4389 HeapFree(SystemHeap
, 0, menu
->text
);
4393 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4394 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4395 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4397 menu
->text
= lpmii
->dwTypeData
;
4399 if (IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4401 menu
->text
= HEAP_strdupWtoA(SystemHeap
, 0, (LPWSTR
) lpmii
->dwTypeData
);
4403 menu
->text
= HEAP_strdupA(SystemHeap
, 0, lpmii
->dwTypeData
);
4407 if (lpmii
->fMask
& MIIM_FTYPE
) {
4408 /* free the string when the type is changing */
4409 if ( (!IS_STRING_ITEM(lpmii
->fType
)) && IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4410 HeapFree(SystemHeap
, 0, menu
->text
);
4413 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4414 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4417 if (lpmii
->fMask
& MIIM_STRING
) {
4418 /* free the string when used */
4419 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4420 HeapFree(SystemHeap
, 0, menu
->text
);
4422 menu
->text
= HEAP_strdupWtoA(SystemHeap
, 0, (LPWSTR
) lpmii
->dwTypeData
);
4424 menu
->text
= HEAP_strdupA(SystemHeap
, 0, lpmii
->dwTypeData
);
4428 if (lpmii
->fMask
& MIIM_STATE
)
4430 /* fixme: MFS_DEFAULT do we have to reset the other menu items? */
4431 menu
->fState
= lpmii
->fState
;
4434 if (lpmii
->fMask
& MIIM_ID
)
4435 menu
->wID
= lpmii
->wID
;
4437 if (lpmii
->fMask
& MIIM_SUBMENU
) {
4438 menu
->hSubMenu
= lpmii
->hSubMenu
;
4439 if (menu
->hSubMenu
) {
4440 POPUPMENU
*subMenu
= MENU_GetMenu((UINT16
)menu
->hSubMenu
);
4442 subMenu
->wFlags
|= MF_POPUP
;
4443 menu
->fType
|= MF_POPUP
;
4446 /* FIXME: Return an error ? */
4447 menu
->fType
&= ~MF_POPUP
;
4450 menu
->fType
&= ~MF_POPUP
;
4453 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
4455 menu
->hCheckBit
= lpmii
->hbmpChecked
;
4456 menu
->hUnCheckBit
= lpmii
->hbmpUnchecked
;
4458 if (lpmii
->fMask
& MIIM_DATA
)
4459 menu
->dwItemData
= lpmii
->dwItemData
;
4461 debug_print_menuitem("SetMenuItemInfo_common: ", menu
, "");
4465 /**********************************************************************
4466 * SetMenuItemInfoA (USER32.491)
4468 BOOL WINAPI
SetMenuItemInfoA(HMENU hmenu
, UINT item
, BOOL bypos
,
4469 const MENUITEMINFOA
*lpmii
)
4471 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4475 /**********************************************************************
4476 * SetMenuItemInfoW (USER32.492)
4478 BOOL WINAPI
SetMenuItemInfoW(HMENU hmenu
, UINT item
, BOOL bypos
,
4479 const MENUITEMINFOW
*lpmii
)
4481 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4482 (const MENUITEMINFOA
*)lpmii
, TRUE
);
4485 /**********************************************************************
4486 * SetMenuDefaultItem (USER32.489)
4489 BOOL WINAPI
SetMenuDefaultItem(HMENU hmenu
, UINT uItem
, UINT bypos
)
4495 TRACE("(0x%x,%d,%d)\n", hmenu
, uItem
, bypos
);
4497 if (!(menu
= MENU_GetMenu(hmenu
))) return FALSE
;
4499 /* reset all default-item flags */
4501 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4503 item
->fState
&= ~MFS_DEFAULT
;
4506 /* no default item */
4515 if ( uItem
>= menu
->nItems
) return FALSE
;
4516 item
[uItem
].fState
|= MFS_DEFAULT
;
4521 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4523 if (item
->wID
== uItem
)
4525 item
->fState
|= MFS_DEFAULT
;
4534 /**********************************************************************
4535 * GetMenuDefaultItem (USER32.260)
4537 UINT WINAPI
GetMenuDefaultItem(HMENU hmenu
, UINT bypos
, UINT flags
)
4543 TRACE("(0x%x,%d,%d)\n", hmenu
, bypos
, flags
);
4545 if (!(menu
= MENU_GetMenu(hmenu
))) return -1;
4547 /* find default item */
4551 if (! item
) return -1;
4553 while ( !( item
->fState
& MFS_DEFAULT
) )
4556 if (i
>= menu
->nItems
) return -1;
4559 /* default: don't return disabled items */
4560 if ( (!(GMDI_USEDISABLED
& flags
)) && (item
->fState
& MFS_DISABLED
)) return -1;
4562 /* search rekursiv when needed */
4563 if ( (item
->fType
& MF_POPUP
) && (flags
& GMDI_GOINTOPOPUPS
) )
4566 ret
= GetMenuDefaultItem( item
->hSubMenu
, bypos
, flags
);
4567 if ( -1 != ret
) return ret
;
4569 /* when item not found in submenu, return the popup item */
4571 return ( bypos
) ? i
: item
->wID
;
4575 /*******************************************************************
4576 * InsertMenuItem16 (USER.441)
4580 BOOL16 WINAPI
InsertMenuItem16( HMENU16 hmenu
, UINT16 pos
, BOOL16 byposition
,
4581 const MENUITEMINFO16
*mii
)
4585 miia
.cbSize
= sizeof(miia
);
4586 miia
.fMask
= mii
->fMask
;
4587 miia
.dwTypeData
= mii
->dwTypeData
;
4588 miia
.fType
= mii
->fType
;
4589 miia
.fState
= mii
->fState
;
4590 miia
.wID
= mii
->wID
;
4591 miia
.hSubMenu
= mii
->hSubMenu
;
4592 miia
.hbmpChecked
= mii
->hbmpChecked
;
4593 miia
.hbmpUnchecked
= mii
->hbmpUnchecked
;
4594 miia
.dwItemData
= mii
->dwItemData
;
4595 miia
.cch
= mii
->cch
;
4596 if (IS_STRING_ITEM(miia
.fType
))
4597 miia
.dwTypeData
= PTR_SEG_TO_LIN(miia
.dwTypeData
);
4598 return InsertMenuItemA( hmenu
, pos
, byposition
, &miia
);
4602 /**********************************************************************
4603 * InsertMenuItemA (USER32.323)
4605 BOOL WINAPI
InsertMenuItemA(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4606 const MENUITEMINFOA
*lpmii
)
4608 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4609 return SetMenuItemInfo_common(item
, lpmii
, FALSE
);
4613 /**********************************************************************
4614 * InsertMenuItemW (USER32.324)
4616 BOOL WINAPI
InsertMenuItemW(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4617 const MENUITEMINFOW
*lpmii
)
4619 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4620 return SetMenuItemInfo_common(item
, (const MENUITEMINFOA
*)lpmii
, TRUE
);
4623 /**********************************************************************
4624 * CheckMenuRadioItem (USER32.47)
4627 BOOL WINAPI
CheckMenuRadioItem(HMENU hMenu
,
4628 UINT first
, UINT last
, UINT check
,
4631 MENUITEM
*mifirst
, *milast
, *micheck
;
4632 HMENU mfirst
= hMenu
, mlast
= hMenu
, mcheck
= hMenu
;
4634 TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4635 hMenu
, first
, last
, check
, bypos
);
4637 mifirst
= MENU_FindItem (&mfirst
, &first
, bypos
);
4638 milast
= MENU_FindItem (&mlast
, &last
, bypos
);
4639 micheck
= MENU_FindItem (&mcheck
, &check
, bypos
);
4641 if (mifirst
== NULL
|| milast
== NULL
|| micheck
== NULL
||
4642 mifirst
> milast
|| mfirst
!= mlast
|| mfirst
!= mcheck
||
4643 micheck
> milast
|| micheck
< mifirst
)
4646 while (mifirst
<= milast
)
4648 if (mifirst
== micheck
)
4650 mifirst
->fType
|= MFT_RADIOCHECK
;
4651 mifirst
->fState
|= MFS_CHECKED
;
4653 mifirst
->fType
&= ~MFT_RADIOCHECK
;
4654 mifirst
->fState
&= ~MFS_CHECKED
;
4662 /**********************************************************************
4663 * CheckMenuRadioItem16 (not a Windows API)
4666 BOOL16 WINAPI
CheckMenuRadioItem16(HMENU16 hMenu
,
4667 UINT16 first
, UINT16 last
, UINT16 check
,
4670 return CheckMenuRadioItem (hMenu
, first
, last
, check
, bypos
);
4673 /**********************************************************************
4674 * GetMenuItemRect (USER32.266)
4676 * ATTENTION: Here, the returned values in rect are the screen
4677 * coordinates of the item just like if the menu was
4678 * always on the upper left side of the application.
4681 BOOL WINAPI
GetMenuItemRect (HWND hwnd
, HMENU hMenu
, UINT uItem
,
4684 POPUPMENU
*itemMenu
;
4688 TRACE("(0x%x,0x%x,%d,%p)\n", hwnd
, hMenu
, uItem
, rect
);
4690 item
= MENU_FindItem (&hMenu
, &uItem
, MF_BYPOSITION
);
4691 referenceHwnd
= hwnd
;
4695 itemMenu
= MENU_GetMenu(hMenu
);
4696 if (itemMenu
== NULL
)
4699 if(itemMenu
->hWnd
== 0)
4701 referenceHwnd
= itemMenu
->hWnd
;
4704 if ((rect
== NULL
) || (item
== NULL
))
4709 MapWindowPoints(referenceHwnd
, 0, (LPPOINT
)rect
, 2);
4714 /**********************************************************************
4715 * GetMenuItemRect16 (USER.665)
4718 BOOL16 WINAPI
GetMenuItemRect16 (HWND16 hwnd
, HMENU16 hMenu
, UINT16 uItem
,
4724 if (!rect
) return FALSE
;
4725 res
= GetMenuItemRect (hwnd
, hMenu
, uItem
, &r32
);
4726 CONV_RECT32TO16 (&r32
, rect
);
4730 /**********************************************************************
4734 * MIM_APPLYTOSUBMENUS
4735 * actually use the items to draw the menu
4737 BOOL WINAPI
SetMenuInfo (HMENU hMenu
, LPCMENUINFO lpmi
)
4741 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4743 if (lpmi
&& (lpmi
->cbSize
==sizeof(MENUINFO
)) && (menu
= MENU_GetMenu(hMenu
)))
4746 if (lpmi
->fMask
& MIM_BACKGROUND
)
4747 menu
->hbrBack
= lpmi
->hbrBack
;
4749 if (lpmi
->fMask
& MIM_HELPID
)
4750 menu
->dwContextHelpID
= lpmi
->dwContextHelpID
;
4752 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4753 menu
->cyMax
= lpmi
->cyMax
;
4755 if (lpmi
->fMask
& MIM_MENUDATA
)
4756 menu
->dwMenuData
= lpmi
->dwMenuData
;
4758 if (lpmi
->fMask
& MIM_STYLE
)
4759 menu
->dwStyle
= lpmi
->dwStyle
;
4766 /**********************************************************************
4773 BOOL WINAPI
GetMenuInfo (HMENU hMenu
, LPMENUINFO lpmi
)
4776 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4778 if (lpmi
&& (menu
= MENU_GetMenu(hMenu
)))
4781 if (lpmi
->fMask
& MIM_BACKGROUND
)
4782 lpmi
->hbrBack
= menu
->hbrBack
;
4784 if (lpmi
->fMask
& MIM_HELPID
)
4785 lpmi
->dwContextHelpID
= menu
->dwContextHelpID
;
4787 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4788 lpmi
->cyMax
= menu
->cyMax
;
4790 if (lpmi
->fMask
& MIM_MENUDATA
)
4791 lpmi
->dwMenuData
= menu
->dwMenuData
;
4793 if (lpmi
->fMask
& MIM_STYLE
)
4794 lpmi
->dwStyle
= menu
->dwStyle
;
4801 /**********************************************************************
4802 * SetMenuContextHelpId16 (USER.384)
4804 BOOL16 WINAPI
SetMenuContextHelpId16( HMENU16 hMenu
, DWORD dwContextHelpID
)
4806 return SetMenuContextHelpId( hMenu
, dwContextHelpID
);
4810 /**********************************************************************
4811 * SetMenuContextHelpId (USER32.488)
4813 BOOL WINAPI
SetMenuContextHelpId( HMENU hMenu
, DWORD dwContextHelpID
)
4817 TRACE("(0x%04x 0x%08lx)\n", hMenu
, dwContextHelpID
);
4819 if ((menu
= MENU_GetMenu(hMenu
)))
4821 menu
->dwContextHelpID
= dwContextHelpID
;
4827 /**********************************************************************
4828 * GetMenuContextHelpId16 (USER.385)
4830 DWORD WINAPI
GetMenuContextHelpId16( HMENU16 hMenu
)
4832 return GetMenuContextHelpId( hMenu
);
4835 /**********************************************************************
4836 * GetMenuContextHelpId (USER32.488)
4838 DWORD WINAPI
GetMenuContextHelpId( HMENU hMenu
)
4842 TRACE("(0x%04x)\n", hMenu
);
4844 if ((menu
= MENU_GetMenu(hMenu
)))
4846 return menu
->dwContextHelpID
;
4851 /**********************************************************************
4852 * MenuItemFromPoint (USER32.387)
4854 UINT WINAPI
MenuItemFromPoint(HWND hWnd
, HMENU hMenu
, POINT ptScreen
)
4856 FIXME("(0x%04x,0x%04x,(%ld,%ld)):stub\n",
4857 hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);