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 WARN("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
)
784 ** Experimentation under Windows reveals that an owner-drawn
785 ** menu is expected to return the size of the content part of
786 ** the menu item, not including the checkmark nor the submenu
787 ** arrow. Windows adds those values itself and returns the
788 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
790 MEASUREITEMSTRUCT mis
;
791 mis
.CtlType
= ODT_MENU
;
793 mis
.itemID
= lpitem
->wID
;
794 mis
.itemData
= (DWORD
)lpitem
->dwItemData
;
797 SendMessageA( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
798 lpitem
->rect
.right
+= mis
.itemWidth
;
802 lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
805 /* under at least win95 you seem to be given a standard
806 height for the menu and the height value is ignored */
808 if (TWEAK_WineLook
== WIN31_LOOK
)
809 lpitem
->rect
.bottom
+= GetSystemMetrics(SM_CYMENU
);
811 lpitem
->rect
.bottom
+= GetSystemMetrics(SM_CYMENU
)-1;
814 lpitem
->rect
.bottom
+= mis
.itemHeight
;
816 TRACE("id=%04x size=%dx%d\n",
817 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
818 /* Fall through to get check/arrow width calculation. */
821 if (lpitem
->fType
& MF_SEPARATOR
)
823 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
829 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
830 if (lpitem
->fType
& MF_POPUP
)
831 lpitem
->rect
.right
+= arrow_bitmap_width
;
834 if (lpitem
->fType
& MF_OWNERDRAW
)
837 if (IS_BITMAP_ITEM(lpitem
->fType
))
842 /* Check if there is a magic menu item associated with this item */
843 if((LOWORD((int)lpitem
->text
))<12)
845 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
, (lpitem
->fType
& MF_HILITE
),
849 resBmp
= (HBITMAP
)lpitem
->text
;
851 if (GetObjectA(resBmp
, sizeof(bm
), &bm
))
853 lpitem
->rect
.right
+= bm
.bmWidth
;
854 lpitem
->rect
.bottom
+= bm
.bmHeight
;
860 /* If we get here, then it must be a text item */
861 if (IS_STRING_ITEM( lpitem
->fType
))
864 GetTextExtentPoint32A(hdc
, lpitem
->text
, strlen(lpitem
->text
), &size
);
866 lpitem
->rect
.right
+= size
.cx
;
867 if (TWEAK_WineLook
== WIN31_LOOK
)
868 lpitem
->rect
.bottom
+= max( size
.cy
, GetSystemMetrics(SM_CYMENU
) );
870 lpitem
->rect
.bottom
+= max(size
.cy
, GetSystemMetrics(SM_CYMENU
)-1);
875 lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
877 else if ((p
= strchr( lpitem
->text
, '\t' )) != NULL
)
879 /* Item contains a tab (only meaningful in popup menus) */
880 GetTextExtentPoint32A(hdc
, lpitem
->text
, (int)(p
- lpitem
->text
) , &size
);
881 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+ size
.cx
;
882 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
886 if (strchr( lpitem
->text
, '\b' ))
887 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
888 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
889 - arrow_bitmap_width
;
892 TRACE("(%d,%d)-(%d,%d)\n", lpitem
->rect
.left
, lpitem
->rect
.top
, lpitem
->rect
.right
, lpitem
->rect
.bottom
);
896 /***********************************************************************
897 * MENU_PopupMenuCalcSize
899 * Calculate the size of a popup menu.
901 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND hwndOwner
)
906 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
908 lppop
->Width
= lppop
->Height
= 0;
909 if (lppop
->nItems
== 0) return;
912 SelectObject( hdc
, hMenuFont
);
915 maxX
= (TWEAK_WineLook
== WIN31_LOOK
) ? GetSystemMetrics(SM_CXBORDER
) : 2 ;
917 while (start
< lppop
->nItems
)
919 lpitem
= &lppop
->items
[start
];
921 orgY
= (TWEAK_WineLook
== WIN31_LOOK
) ? GetSystemMetrics(SM_CYBORDER
) : 2;
923 maxTab
= maxTabWidth
= 0;
925 /* Parse items until column break or end of menu */
926 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
929 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
931 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
933 if (lpitem
->fType
& MF_MENUBARBREAK
) orgX
++;
934 maxX
= max( maxX
, lpitem
->rect
.right
);
935 orgY
= lpitem
->rect
.bottom
;
936 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
938 maxTab
= max( maxTab
, lpitem
->xTab
);
939 maxTabWidth
= max(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
943 /* Finish the column (set all items to the largest width found) */
944 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
945 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
947 lpitem
->rect
.right
= maxX
;
948 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
949 lpitem
->xTab
= maxTab
;
952 lppop
->Height
= max( lppop
->Height
, orgY
);
957 /* space for 3d border */
958 if(TWEAK_WineLook
> WIN31_LOOK
)
968 /***********************************************************************
969 * MENU_MenuBarCalcSize
971 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
972 * height is off by 1 pixel which causes lengthy window relocations when
973 * active document window is maximized/restored.
975 * Calculate the size of the menu bar.
977 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
,
978 LPPOPUPMENU lppop
, HWND hwndOwner
)
981 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
983 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
984 if (lppop
->nItems
== 0) return;
985 TRACE("left=%d top=%d right=%d bottom=%d\n",
986 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
987 lppop
->Width
= lprect
->right
- lprect
->left
;
992 while (start
< lppop
->nItems
)
994 lpitem
= &lppop
->items
[start
];
998 /* Parse items until line break or end of menu */
999 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
1001 if ((helpPos
== -1) && (lpitem
->fType
& MF_HELP
)) helpPos
= i
;
1003 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1005 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
1007 debug_print_menuitem (" item: ", lpitem
, "");
1008 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
1010 if (lpitem
->rect
.right
> lprect
->right
)
1012 if (i
!= start
) break;
1013 else lpitem
->rect
.right
= lprect
->right
;
1015 maxY
= max( maxY
, lpitem
->rect
.bottom
);
1016 orgX
= lpitem
->rect
.right
;
1019 /* Finish the line (set all items to the largest height found) */
1020 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
1023 lprect
->bottom
= maxY
;
1024 lppop
->Height
= lprect
->bottom
- lprect
->top
;
1026 /* Flush right all magic items and items between the MF_HELP and */
1027 /* the last item (if several lines, only move the last line) */
1028 lpitem
= &lppop
->items
[lppop
->nItems
-1];
1029 orgY
= lpitem
->rect
.top
;
1030 orgX
= lprect
->right
;
1031 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--)
1033 if ( !IS_BITMAP_ITEM(lpitem
->fType
) && ((helpPos
==-1) ? TRUE
: (helpPos
>i
) ))
1035 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
1036 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
1037 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
1038 lpitem
->rect
.right
= orgX
;
1039 orgX
= lpitem
->rect
.left
;
1043 /***********************************************************************
1046 * Draw a single menu item.
1048 static void MENU_DrawMenuItem( HWND hwnd
, HMENU hmenu
, HWND hwndOwner
, HDC hdc
, MENUITEM
*lpitem
,
1049 UINT height
, BOOL menuBar
, UINT odaction
)
1053 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem
, "");
1055 if (lpitem
->fType
& MF_SYSMENU
)
1057 if( !IsIconic(hwnd
) ) {
1058 if (TWEAK_WineLook
> WIN31_LOOK
)
1059 NC_DrawSysButton95( hwnd
, hdc
,
1061 (MF_HILITE
| MF_MOUSESELECT
) );
1063 NC_DrawSysButton( hwnd
, hdc
,
1065 (MF_HILITE
| MF_MOUSESELECT
) );
1071 if (lpitem
->fType
& MF_OWNERDRAW
)
1074 ** Experimentation under Windows reveals that an owner-drawn
1075 ** menu is given the rectangle which includes the space it requested
1076 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1077 ** and a popup-menu arrow. This is the value of lpitem->rect.
1078 ** Windows will leave all drawing to the application except for
1079 ** the popup-menu arrow. Windows always draws that itself, after
1080 ** the menu owner has finished drawing.
1084 dis
.CtlType
= ODT_MENU
;
1086 dis
.itemID
= lpitem
->wID
;
1087 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1089 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1090 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
;
1091 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1092 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1093 dis
.hwndItem
= hmenu
;
1095 dis
.rcItem
= lpitem
->rect
;
1096 TRACE("Ownerdraw: owner=%04x itemID=%d, itemState=%d, itemAction=%d, "
1097 "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n", hwndOwner
,
1098 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1099 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1101 SendMessageA( hwndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
1102 /* Fall through to draw popup-menu arrow */
1105 TRACE("rect={%d,%d,%d,%d}\n", lpitem
->rect
.left
, lpitem
->rect
.top
,
1106 lpitem
->rect
.right
,lpitem
->rect
.bottom
);
1108 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1110 rect
= lpitem
->rect
;
1112 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1114 if ((lpitem
->fState
& MF_HILITE
) && !(IS_BITMAP_ITEM(lpitem
->fType
)))
1115 if ((menuBar
) && (TWEAK_WineLook
==WIN98_LOOK
))
1116 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1118 FillRect( hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
) );
1120 FillRect( hdc
, &rect
, GetSysColorBrush(COLOR_MENU
) );
1123 SetBkMode( hdc
, TRANSPARENT
);
1125 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1127 /* vertical separator */
1128 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1130 if (TWEAK_WineLook
> WIN31_LOOK
)
1134 rc
.bottom
= height
- 3;
1135 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1139 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1140 MoveTo16( hdc
, rect
.left
, 0 );
1141 LineTo( hdc
, rect
.left
, height
);
1145 /* horizontal separator */
1146 if (lpitem
->fType
& MF_SEPARATOR
)
1148 if (TWEAK_WineLook
> WIN31_LOOK
)
1153 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1154 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1158 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1159 MoveTo16( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
1160 LineTo( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
1168 if ((lpitem
->fState
& MF_HILITE
) && !(IS_BITMAP_ITEM(lpitem
->fType
)) )
1170 if (lpitem
->fState
& MF_GRAYED
)
1171 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1173 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
1174 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
1178 if (lpitem
->fState
& MF_GRAYED
)
1179 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1181 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1182 SetBkColor( hdc
, GetSysColor( COLOR_MENU
) );
1185 /* helper lines for debugging */
1186 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1187 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1188 MoveTo16( hdc, rect.left, (rect.top + rect.bottom)/2 );
1189 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1194 INT y
= rect
.top
+ rect
.bottom
;
1196 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1198 /* Draw the check mark
1201 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1204 if (lpitem
->fState
& MF_CHECKED
)
1206 HBITMAP bm
= lpitem
->hCheckBit
? lpitem
->hCheckBit
:
1207 ((lpitem
->fType
& MFT_RADIOCHECK
) ? hStdRadioCheck
: hStdCheck
);
1208 HDC hdcMem
= CreateCompatibleDC( hdc
);
1210 SelectObject( hdcMem
, bm
);
1211 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1212 check_bitmap_width
, check_bitmap_height
,
1213 hdcMem
, 0, 0, SRCCOPY
);
1216 else if (lpitem
->hUnCheckBit
)
1218 HDC hdcMem
= CreateCompatibleDC( hdc
);
1220 SelectObject( hdcMem
, lpitem
->hUnCheckBit
);
1221 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1222 check_bitmap_width
, check_bitmap_height
,
1223 hdcMem
, 0, 0, SRCCOPY
);
1228 /* Draw the popup-menu arrow */
1229 if (lpitem
->fType
& MF_POPUP
)
1231 HDC hdcMem
= CreateCompatibleDC( hdc
);
1232 HBITMAP hOrigBitmap
;
1234 hOrigBitmap
= SelectObject( hdcMem
, hStdMnArrow
);
1235 BitBlt( hdc
, rect
.right
- arrow_bitmap_width
- 1,
1236 (y
- arrow_bitmap_height
) / 2,
1237 arrow_bitmap_width
, arrow_bitmap_height
,
1238 hdcMem
, 0, 0, SRCCOPY
);
1239 SelectObject( hdcMem
, hOrigBitmap
);
1243 rect
.left
+= check_bitmap_width
;
1244 rect
.right
-= arrow_bitmap_width
;
1247 /* Done for owner-drawn */
1248 if (lpitem
->fType
& MF_OWNERDRAW
)
1251 /* Draw the item text or bitmap */
1252 if (IS_BITMAP_ITEM(lpitem
->fType
))
1257 HDC hdcMem
= CreateCompatibleDC( hdc
);
1260 * Check if there is a magic menu item associated with this item
1261 * and load the appropriate bitmap
1263 if((LOWORD((int)lpitem
->text
)) < 12)
1265 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
, (lpitem
->fState
& MF_HILITE
),
1266 lpitem
->dwItemData
);
1269 resBmp
= (HBITMAP
)lpitem
->text
;
1274 GetObjectA( resBmp
, sizeof(bm
), &bm
);
1276 SelectObject(hdcMem
,resBmp
);
1278 /* handle fontsize > bitmap_height */
1279 top
= ((rect
.bottom
-rect
.top
)>bm
.bmHeight
) ?
1280 rect
.top
+(rect
.bottom
-rect
.top
-bm
.bmHeight
)/2 : rect
.top
;
1282 BitBlt( hdc
, rect
.left
, top
, rect
.right
- rect
.left
,
1283 rect
.bottom
- rect
.top
, hdcMem
, 0, 0, SRCCOPY
);
1290 /* No bitmap - process text if present */
1291 else if (IS_STRING_ITEM(lpitem
->fType
))
1296 UINT uFormat
= (menuBar
) ?
1297 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
1298 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1300 if ( lpitem
->fState
& MFS_DEFAULT
)
1302 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
1307 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1308 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1309 i
= strlen( lpitem
->text
);
1313 for (i
= 0; lpitem
->text
[i
]; i
++)
1314 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
1318 if( !(TWEAK_WineLook
== WIN31_LOOK
) && (lpitem
->fState
& MF_GRAYED
))
1320 if (!(lpitem
->fState
& MF_HILITE
) )
1322 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1323 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1324 DrawTextA( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1325 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1327 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1330 DrawTextA( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1332 /* paint the shortcut text */
1333 if (lpitem
->text
[i
]) /* There's a tab or flush-right char */
1335 if (lpitem
->text
[i
] == '\t')
1337 rect
.left
= lpitem
->xTab
;
1338 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1342 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1345 if( !(TWEAK_WineLook
== WIN31_LOOK
) && (lpitem
->fState
& MF_GRAYED
))
1347 if (!(lpitem
->fState
& MF_HILITE
) )
1349 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1350 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1351 DrawTextA( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1352 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1354 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1356 DrawTextA( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1360 SelectObject (hdc
, hfontOld
);
1365 /***********************************************************************
1366 * MENU_DrawPopupMenu
1368 * Paint a popup menu.
1370 static void MENU_DrawPopupMenu( HWND hwnd
, HDC hdc
, HMENU hmenu
)
1372 HBRUSH hPrevBrush
= 0;
1375 TRACE("wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd
, hdc
, hmenu
);
1377 GetClientRect( hwnd
, &rect
);
1379 if(TWEAK_WineLook
== WIN31_LOOK
)
1381 rect
.bottom
-= POPUP_YSHADE
* GetSystemMetrics(SM_CYBORDER
);
1382 rect
.right
-= POPUP_XSHADE
* GetSystemMetrics(SM_CXBORDER
);
1385 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1386 && (SelectObject( hdc
, hMenuFont
)))
1390 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1392 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1398 /* draw 3-d shade */
1399 if(TWEAK_WineLook
== WIN31_LOOK
) {
1400 SelectObject( hdc
, hShadeBrush
);
1401 SetBkMode( hdc
, TRANSPARENT
);
1402 ropPrev
= SetROP2( hdc
, R2_MASKPEN
);
1404 i
= rect
.right
; /* why SetBrushOrg() doesn't? */
1405 PatBlt( hdc
, i
& 0xfffffffe,
1406 rect
.top
+ POPUP_YSHADE
*GetSystemMetrics(SM_CYBORDER
),
1407 i
%2 + POPUP_XSHADE
*GetSystemMetrics(SM_CXBORDER
),
1408 rect
.bottom
- rect
.top
, 0x00a000c9 );
1410 PatBlt( hdc
, rect
.left
+ POPUP_XSHADE
*GetSystemMetrics(SM_CXBORDER
),
1411 i
& 0xfffffffe,rect
.right
- rect
.left
,
1412 i
%2 + POPUP_YSHADE
*GetSystemMetrics(SM_CYBORDER
), 0x00a000c9 );
1413 SelectObject( hdc
, hPrevPen
);
1414 SelectObject( hdc
, hPrevBrush
);
1415 SetROP2( hdc
, ropPrev
);
1418 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1420 /* draw menu items */
1422 menu
= MENU_GetMenu( hmenu
);
1423 if (menu
&& menu
->nItems
)
1428 for (u
= menu
->nItems
, item
= menu
->items
; u
> 0; u
--, item
++)
1429 MENU_DrawMenuItem( hwnd
, hmenu
, menu
->hwndOwner
, hdc
, item
,
1430 menu
->Height
, FALSE
, ODA_DRAWENTIRE
);
1435 SelectObject( hdc
, hPrevBrush
);
1440 /***********************************************************************
1443 * Paint a menu bar. Returns the height of the menu bar.
1444 * called from [windows/nonclient.c]
1446 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1453 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1455 lppop
= MENU_GetMenu ((HMENU
)wndPtr
->wIDmenu
);
1456 if (lppop
== NULL
|| lprect
== NULL
)
1458 retvalue
= GetSystemMetrics(SM_CYMENU
);
1462 TRACE("(%04x, %p, %p)\n", hDC
, lprect
, lppop
);
1464 hfontOld
= SelectObject( hDC
, hMenuFont
);
1466 if (lppop
->Height
== 0)
1467 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
1469 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
1473 retvalue
= lppop
->Height
;
1477 FillRect(hDC
, lprect
, GetSysColorBrush(COLOR_MENU
) );
1479 if (TWEAK_WineLook
== WIN31_LOOK
)
1481 SelectObject( hDC
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1482 MoveTo16( hDC
, lprect
->left
, lprect
->bottom
);
1483 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1487 SelectObject( hDC
, GetSysColorPen(COLOR_3DFACE
));
1488 MoveTo16( hDC
, lprect
->left
, lprect
->bottom
);
1489 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1492 if (lppop
->nItems
== 0)
1494 retvalue
= GetSystemMetrics(SM_CYMENU
);
1498 for (i
= 0; i
< lppop
->nItems
; i
++)
1500 MENU_DrawMenuItem( hwnd
, (HMENU
)wndPtr
->wIDmenu
, hwnd
,
1501 hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
, ODA_DRAWENTIRE
);
1503 retvalue
= lppop
->Height
;
1507 SelectObject (hDC
, hfontOld
);
1509 WIN_ReleaseWndPtr(wndPtr
);
1513 /***********************************************************************
1514 * MENU_PatchResidentPopup
1516 BOOL
MENU_PatchResidentPopup( HQUEUE16 checkQueue
, WND
* checkWnd
)
1518 WND
*pTPWnd
= MENU_GetTopPopupWnd();
1524 TRACE("patching resident popup: %04x %04x [%04x %04x]\n",
1525 checkQueue
, checkWnd
? checkWnd
->hwndSelf
: 0, pTPWnd
->hmemTaskQ
,
1526 pTPWnd
->owner
? pTPWnd
->owner
->hwndSelf
: 0);
1528 switch( checkQueue
)
1530 case 0: /* checkWnd is the new popup owner */
1533 pTPWnd
->owner
= checkWnd
;
1534 if( pTPWnd
->hmemTaskQ
!= checkWnd
->hmemTaskQ
)
1535 hTask
= QUEUE_GetQueueTask( checkWnd
->hmemTaskQ
);
1539 case 0xFFFF: /* checkWnd is destroyed */
1540 if( pTPWnd
->owner
== checkWnd
)
1541 pTPWnd
->owner
= NULL
;
1542 MENU_ReleaseTopPopupWnd();
1545 default: /* checkQueue is exiting */
1546 if( pTPWnd
->hmemTaskQ
== checkQueue
)
1548 hTask
= QUEUE_GetQueueTask( pTPWnd
->hmemTaskQ
);
1549 hTask
= TASK_GetNextTask( hTask
);
1556 TDB
* task
= (TDB
*)GlobalLock16( hTask
);
1559 pTPWnd
->hInstance
= task
->hInstance
;
1560 pTPWnd
->hmemTaskQ
= task
->hQueue
;
1561 MENU_ReleaseTopPopupWnd();
1564 else WARN("failed to patch resident popup.\n");
1567 MENU_ReleaseTopPopupWnd();
1571 /***********************************************************************
1574 * Display a popup menu.
1576 static BOOL
MENU_ShowPopup( HWND hwndOwner
, HMENU hmenu
, UINT id
,
1577 INT x
, INT y
, INT xanchor
, INT yanchor
)
1580 WND
*wndOwner
= NULL
;
1582 TRACE("owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1583 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1585 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
1586 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1588 menu
->items
[menu
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1589 menu
->FocusedItem
= NO_SELECTED_ITEM
;
1592 /* store the owner for DrawItem*/
1593 menu
->hwndOwner
= hwndOwner
;
1595 if( (wndOwner
= WIN_FindWndPtr( hwndOwner
)) )
1599 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
1601 /* adjust popup menu pos so that it fits within the desktop */
1603 width
= menu
->Width
+ GetSystemMetrics(SM_CXBORDER
);
1604 height
= menu
->Height
+ GetSystemMetrics(SM_CYBORDER
);
1606 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1609 x
-= width
- xanchor
;
1610 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1611 x
= GetSystemMetrics(SM_CXSCREEN
) - width
;
1615 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1618 y
-= height
+ yanchor
;
1619 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1620 y
= GetSystemMetrics(SM_CYSCREEN
) - height
;
1624 if( TWEAK_WineLook
== WIN31_LOOK
)
1626 width
+= POPUP_XSHADE
* GetSystemMetrics(SM_CXBORDER
); /* add space for shading */
1627 height
+= POPUP_YSHADE
* GetSystemMetrics(SM_CYBORDER
);
1630 /* NOTE: In Windows, top menu popup is not owned. */
1631 if (!pTopPopupWnd
) /* create top level popup menu window */
1633 assert( uSubPWndLevel
== 0 );
1635 pTopPopupWnd
= WIN_FindWndPtr(CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1636 WS_POPUP
, x
, y
, width
, height
,
1637 hwndOwner
, 0, wndOwner
->hInstance
,
1641 WIN_ReleaseWndPtr(wndOwner
);
1644 menu
->hWnd
= pTopPopupWnd
->hwndSelf
;
1645 MENU_ReleaseTopPopupWnd();
1650 /* create a new window for the submenu */
1652 menu
->hWnd
= CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1653 WS_POPUP
, x
, y
, width
, height
,
1654 hwndOwner
, 0, wndOwner
->hInstance
,
1658 WIN_ReleaseWndPtr(wndOwner
);
1662 else /* top level popup menu window already exists */
1664 WND
*pTPWnd
= MENU_GetTopPopupWnd();
1665 menu
->hWnd
= pTPWnd
->hwndSelf
;
1667 MENU_PatchResidentPopup( 0, wndOwner
);
1668 SendMessageA( pTPWnd
->hwndSelf
, MM_SETMENUHANDLE
, (WPARAM16
)hmenu
, 0L);
1670 /* adjust its size */
1672 SetWindowPos( menu
->hWnd
, 0, x
, y
, width
, height
,
1673 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_NOREDRAW
);
1674 MENU_ReleaseTopPopupWnd();
1677 uSubPWndLevel
++; /* menu level counter */
1679 /* Display the window */
1681 SetWindowPos( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
1682 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1683 UpdateWindow( menu
->hWnd
);
1684 WIN_ReleaseWndPtr(wndOwner
);
1691 /***********************************************************************
1694 static void MENU_SelectItem( HWND hwndOwner
, HMENU hmenu
, UINT wIndex
,
1695 BOOL sendMenuSelect
, HMENU topmenu
)
1700 TRACE("owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1702 lppop
= MENU_GetMenu( hmenu
);
1703 if ((!lppop
) || (!lppop
->nItems
)) return;
1705 if (lppop
->FocusedItem
== wIndex
) return;
1706 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC( lppop
->hWnd
);
1707 else hdc
= GetDCEx( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1709 SelectObject( hdc
, hMenuFont
);
1711 /* Clear previous highlighted item */
1712 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1714 lppop
->items
[lppop
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1715 MENU_DrawMenuItem(lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,&lppop
->items
[lppop
->FocusedItem
],
1716 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
),
1720 /* Highlight new item (if any) */
1721 lppop
->FocusedItem
= wIndex
;
1722 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1724 if(!(lppop
->items
[wIndex
].fType
& MF_SEPARATOR
)) {
1725 lppop
->items
[wIndex
].fState
|= MF_HILITE
;
1726 MENU_DrawMenuItem( lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,
1727 &lppop
->items
[wIndex
], lppop
->Height
,
1728 !(lppop
->wFlags
& MF_POPUP
), ODA_SELECT
);
1732 MENUITEM
*ip
= &lppop
->items
[lppop
->FocusedItem
];
1733 SendMessageA( hwndOwner
, WM_MENUSELECT
,
1734 MAKELONG(ip
->fType
& MF_POPUP
? wIndex
: ip
->wID
,
1735 ip
->fType
| ip
->fState
| MF_MOUSESELECT
|
1736 (lppop
->wFlags
& MF_SYSMENU
)), hmenu
);
1739 else if (sendMenuSelect
) {
1742 if((pos
=MENU_FindSubMenu(&topmenu
, hmenu
))!=NO_SELECTED_ITEM
){
1743 POPUPMENU
*ptm
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( topmenu
);
1744 MENUITEM
*ip
= &ptm
->items
[pos
];
1745 SendMessageA( hwndOwner
, WM_MENUSELECT
, MAKELONG(pos
,
1746 ip
->fType
| ip
->fState
| MF_MOUSESELECT
|
1747 (ptm
->wFlags
& MF_SYSMENU
)), topmenu
);
1751 ReleaseDC( lppop
->hWnd
, hdc
);
1755 /***********************************************************************
1756 * MENU_MoveSelection
1758 * Moves currently selected item according to the offset parameter.
1759 * If there is no selection then it should select the last item if
1760 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1762 static void MENU_MoveSelection( HWND hwndOwner
, HMENU hmenu
, INT offset
)
1767 TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner
, hmenu
, offset
);
1769 menu
= MENU_GetMenu( hmenu
);
1770 if ((!menu
) || (!menu
->items
)) return;
1772 if ( menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1774 if( menu
->nItems
== 1 ) return; else
1775 for (i
= menu
->FocusedItem
+ offset
; i
>= 0 && i
< menu
->nItems
1777 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1779 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
1784 for ( i
= (offset
> 0) ? 0 : menu
->nItems
- 1;
1785 i
>= 0 && i
< menu
->nItems
; i
+= offset
)
1786 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1788 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
1794 /**********************************************************************
1797 * Set an item flags, id and text ptr. Called by InsertMenu() and
1800 static BOOL
MENU_SetItemData( MENUITEM
*item
, UINT flags
, UINT id
,
1803 LPSTR prevText
= IS_STRING_ITEM(item
->fType
) ? item
->text
: NULL
;
1805 debug_print_menuitem("MENU_SetItemData from: ", item
, "");
1807 if (IS_STRING_ITEM(flags
))
1811 flags
|= MF_SEPARATOR
;
1817 /* Item beginning with a backspace is a help item */
1823 if (!(text
= HEAP_strdupA( SystemHeap
, 0, str
))) return FALSE
;
1827 else if (IS_BITMAP_ITEM(flags
))
1828 item
->text
= (LPSTR
)(HBITMAP
)LOWORD(str
);
1829 else item
->text
= NULL
;
1831 if (flags
& MF_OWNERDRAW
)
1832 item
->dwItemData
= (DWORD
)str
;
1834 item
->dwItemData
= 0;
1836 if ((item
->fType
& MF_POPUP
) && (flags
& MF_POPUP
) && (item
->hSubMenu
!= id
) )
1837 DestroyMenu( item
->hSubMenu
); /* ModifyMenu() spec */
1839 if (flags
& MF_POPUP
)
1841 POPUPMENU
*menu
= MENU_GetMenu((UINT16
)id
);
1842 if (menu
) menu
->wFlags
|= MF_POPUP
;
1854 if (flags
& MF_POPUP
)
1855 item
->hSubMenu
= id
;
1857 if ((item
->fType
& MF_POPUP
) && !(flags
& MF_POPUP
) )
1858 flags
|= MF_POPUP
; /* keep popup */
1860 item
->fType
= flags
& TYPE_MASK
;
1861 item
->fState
= (flags
& STATE_MASK
) &
1862 ~(MF_HILITE
| MF_MOUSESELECT
| MF_BYPOSITION
);
1865 /* Don't call SetRectEmpty here! */
1868 if (prevText
) HeapFree( SystemHeap
, 0, prevText
);
1870 debug_print_menuitem("MENU_SetItemData to : ", item
, "");
1875 /**********************************************************************
1878 * Insert a new item into a menu.
1880 static MENUITEM
*MENU_InsertItem( HMENU hMenu
, UINT pos
, UINT flags
)
1885 if (!(menu
= MENU_GetMenu(hMenu
)))
1888 /* Find where to insert new item */
1890 if (flags
& MF_BYPOSITION
) {
1891 if (pos
> menu
->nItems
)
1894 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
1897 if (!(menu
= MENU_GetMenu( hMenu
)))
1902 /* Create new items array */
1904 newItems
= HeapAlloc( SystemHeap
, 0, sizeof(MENUITEM
) * (menu
->nItems
+1) );
1907 WARN("allocation failed\n" );
1910 if (menu
->nItems
> 0)
1912 /* Copy the old array into the new */
1913 if (pos
> 0) memcpy( newItems
, menu
->items
, pos
* sizeof(MENUITEM
) );
1914 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &menu
->items
[pos
],
1915 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
1916 HeapFree( SystemHeap
, 0, menu
->items
);
1918 menu
->items
= newItems
;
1920 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
1921 menu
->Height
= 0; /* force size recalculate */
1922 return &newItems
[pos
];
1926 /**********************************************************************
1927 * MENU_ParseResource
1929 * Parse a standard menu resource and add items to the menu.
1930 * Return a pointer to the end of the resource.
1932 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1939 flags
= GET_WORD(res
);
1940 res
+= sizeof(WORD
);
1941 if (!(flags
& MF_POPUP
))
1944 res
+= sizeof(WORD
);
1946 if (!IS_STRING_ITEM(flags
))
1947 ERR("not a string item %04x\n", flags
);
1949 if (!unicode
) res
+= strlen(str
) + 1;
1950 else res
+= (lstrlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1951 if (flags
& MF_POPUP
)
1953 HMENU hSubMenu
= CreatePopupMenu();
1954 if (!hSubMenu
) return NULL
;
1955 if (!(res
= MENU_ParseResource( res
, hSubMenu
, unicode
)))
1957 if (!unicode
) AppendMenuA( hMenu
, flags
, (UINT
)hSubMenu
, str
);
1958 else AppendMenuW( hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1960 else /* Not a popup */
1962 if (!unicode
) AppendMenuA( hMenu
, flags
, id
, *str
? str
: NULL
);
1963 else AppendMenuW( hMenu
, flags
, id
,
1964 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1966 } while (!(flags
& MF_END
));
1971 /**********************************************************************
1972 * MENUEX_ParseResource
1974 * Parse an extended menu resource and add items to the menu.
1975 * Return a pointer to the end of the resource.
1977 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
1983 mii
.cbSize
= sizeof(mii
);
1984 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
1985 mii
.fType
= GET_DWORD(res
);
1986 res
+= sizeof(DWORD
);
1987 mii
.fState
= GET_DWORD(res
);
1988 res
+= sizeof(DWORD
);
1989 mii
.wID
= GET_DWORD(res
);
1990 res
+= sizeof(DWORD
);
1991 resinfo
= GET_WORD(res
); /* FIXME: for 16-bit apps this is a byte. */
1992 res
+= sizeof(WORD
);
1993 /* Align the text on a word boundary. */
1994 res
+= (~((int)res
- 1)) & 1;
1995 mii
.dwTypeData
= (LPWSTR
) res
;
1996 res
+= (1 + lstrlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
1997 /* Align the following fields on a dword boundary. */
1998 res
+= (~((int)res
- 1)) & 3;
2000 /* FIXME: This is inefficient and cannot be optimised away by gcc. */
2002 LPSTR newstr
= HEAP_strdupWtoA(GetProcessHeap(),
2004 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
2005 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, newstr
);
2006 HeapFree( GetProcessHeap(), 0, newstr
);
2009 if (resinfo
& 1) { /* Pop-up? */
2010 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2011 res
+= sizeof(DWORD
);
2012 mii
.hSubMenu
= CreatePopupMenu();
2015 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
2016 DestroyMenu(mii
.hSubMenu
);
2019 mii
.fMask
|= MIIM_SUBMENU
;
2020 mii
.fType
|= MF_POPUP
;
2022 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
2023 } while (!(resinfo
& MF_END
));
2028 /***********************************************************************
2031 * Return the handle of the selected sub-popup menu (if any).
2033 static HMENU
MENU_GetSubPopup( HMENU hmenu
)
2038 menu
= MENU_GetMenu( hmenu
);
2040 if ((!menu
) || (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return 0;
2042 item
= &menu
->items
[menu
->FocusedItem
];
2043 if ((item
->fType
& MF_POPUP
) && (item
->fState
& MF_MOUSESELECT
))
2044 return item
->hSubMenu
;
2049 /***********************************************************************
2050 * MENU_HideSubPopups
2052 * Hide the sub-popup menus of this menu.
2054 static void MENU_HideSubPopups( HWND hwndOwner
, HMENU hmenu
,
2055 BOOL sendMenuSelect
)
2057 POPUPMENU
*menu
= MENU_GetMenu( hmenu
);
2059 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner
, hmenu
, sendMenuSelect
);
2061 if (menu
&& uSubPWndLevel
)
2067 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
2069 item
= &menu
->items
[menu
->FocusedItem
];
2070 if (!(item
->fType
& MF_POPUP
) ||
2071 !(item
->fState
& MF_MOUSESELECT
)) return;
2072 item
->fState
&= ~MF_MOUSESELECT
;
2073 hsubmenu
= item
->hSubMenu
;
2076 submenu
= MENU_GetMenu( hsubmenu
);
2077 MENU_HideSubPopups( hwndOwner
, hsubmenu
, FALSE
);
2078 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, sendMenuSelect
, 0 );
2080 if (submenu
->hWnd
== MENU_GetTopPopupWnd()->hwndSelf
)
2082 ShowWindow( submenu
->hWnd
, SW_HIDE
);
2087 DestroyWindow( submenu
->hWnd
);
2090 MENU_ReleaseTopPopupWnd();
2095 /***********************************************************************
2098 * Display the sub-menu of the selected item of this menu.
2099 * Return the handle of the submenu, or hmenu if no submenu to display.
2101 static HMENU
MENU_ShowSubPopup( HWND hwndOwner
, HMENU hmenu
,
2102 BOOL selectFirst
, UINT wFlags
)
2110 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner
, hmenu
, selectFirst
);
2112 if (!(menu
= MENU_GetMenu( hmenu
))) return hmenu
;
2114 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
)) ||
2115 (menu
->FocusedItem
== NO_SELECTED_ITEM
))
2117 WIN_ReleaseWndPtr(wndPtr
);
2121 item
= &menu
->items
[menu
->FocusedItem
];
2122 if (!(item
->fType
& MF_POPUP
) ||
2123 (item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
2125 WIN_ReleaseWndPtr(wndPtr
);
2129 /* message must be send before using item,
2130 because nearly everything may by changed by the application ! */
2132 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2133 if (!(wFlags
& TPM_NONOTIFY
))
2134 SendMessageA( hwndOwner
, WM_INITMENUPOPUP
, item
->hSubMenu
,
2135 MAKELONG( menu
->FocusedItem
, IS_SYSTEM_MENU(menu
) ));
2137 item
= &menu
->items
[menu
->FocusedItem
];
2140 /* correct item if modified as a reaction to WM_INITMENUPOPUP-message */
2141 if (!(item
->fState
& MF_HILITE
))
2143 if (menu
->wFlags
& MF_POPUP
) hdc
= GetDC( menu
->hWnd
);
2144 else hdc
= GetDCEx( menu
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2146 SelectObject( hdc
, hMenuFont
);
2148 item
->fState
|= MF_HILITE
;
2149 MENU_DrawMenuItem( menu
->hWnd
, hmenu
, hwndOwner
, hdc
, item
, menu
->Height
, !(menu
->wFlags
& MF_POPUP
), ODA_DRAWENTIRE
);
2150 ReleaseDC( menu
->hWnd
, hdc
);
2152 if (!item
->rect
.top
&& !item
->rect
.left
&& !item
->rect
.bottom
&& !item
->rect
.right
)
2155 item
->fState
|= MF_MOUSESELECT
;
2157 if (IS_SYSTEM_MENU(menu
))
2159 MENU_InitSysMenuPopup(item
->hSubMenu
, wndPtr
->dwStyle
, GetClassLongA(wndPtr
->hwndSelf
, GCL_STYLE
));
2161 NC_GetSysPopupPos( wndPtr
, &rect
);
2162 rect
.top
= rect
.bottom
;
2163 rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2164 rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2168 if (menu
->wFlags
& MF_POPUP
)
2170 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2171 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.top
;
2172 rect
.right
= item
->rect
.left
- item
->rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2173 rect
.bottom
= item
->rect
.top
- item
->rect
.bottom
;
2177 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.left
;
2178 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.bottom
;
2179 rect
.right
= item
->rect
.right
- item
->rect
.left
;
2180 rect
.bottom
= item
->rect
.bottom
- item
->rect
.top
;
2184 MENU_ShowPopup( hwndOwner
, item
->hSubMenu
, menu
->FocusedItem
,
2185 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2187 MENU_MoveSelection( hwndOwner
, item
->hSubMenu
, ITEM_NEXT
);
2188 WIN_ReleaseWndPtr(wndPtr
);
2189 return item
->hSubMenu
;
2194 /**********************************************************************
2197 BOOL
MENU_IsMenuActive(void)
2199 return pTopPopupWnd
&& (pTopPopupWnd
->dwStyle
& WS_VISIBLE
);
2202 /***********************************************************************
2205 * Walks menu chain trying to find a menu pt maps to.
2207 static HMENU
MENU_PtMenu( HMENU hMenu
, POINT16 pt
)
2209 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2210 register UINT ht
= menu
->FocusedItem
;
2212 /* try subpopup first (if any) */
2213 ht
= (ht
!= NO_SELECTED_ITEM
&&
2214 (menu
->items
[ht
].fType
& MF_POPUP
) &&
2215 (menu
->items
[ht
].fState
& MF_MOUSESELECT
))
2216 ? (UINT
) MENU_PtMenu(menu
->items
[ht
].hSubMenu
, pt
) : 0;
2218 if( !ht
) /* check the current window (avoiding WM_HITTEST) */
2220 ht
= (UINT
)NC_HandleNCHitTest( menu
->hWnd
, pt
);
2221 if( menu
->wFlags
& MF_POPUP
)
2222 ht
= (ht
!= (UINT
)HTNOWHERE
&&
2223 ht
!= (UINT
)HTERROR
) ? (UINT
)hMenu
: 0;
2226 WND
* wndPtr
= WIN_FindWndPtr(menu
->hWnd
);
2228 ht
= ( ht
== HTSYSMENU
) ? (UINT
)(wndPtr
->hSysMenu
)
2229 : ( ht
== HTMENU
) ? (UINT
)(wndPtr
->wIDmenu
) : 0;
2230 WIN_ReleaseWndPtr(wndPtr
);
2236 /***********************************************************************
2237 * MENU_ExecFocusedItem
2239 * Execute a menu item (for instance when user pressed Enter).
2240 * Return the wID of the executed item. Otherwise, -1 indicating
2241 * that no menu item wase executed;
2242 * Have to receive the flags for the TrackPopupMenu options to avoid
2243 * sending unwanted message.
2246 static INT
MENU_ExecFocusedItem( MTRACKER
* pmt
, HMENU hMenu
, UINT wFlags
)
2249 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2251 TRACE("%p hmenu=0x%04x\n", pmt
, hMenu
);
2253 if (!menu
|| !menu
->nItems
||
2254 (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return -1;
2256 item
= &menu
->items
[menu
->FocusedItem
];
2258 TRACE("%08x %08x %08x\n",
2259 hMenu
, item
->wID
, item
->hSubMenu
);
2261 if (!(item
->fType
& MF_POPUP
))
2263 if (!(item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
2265 /* If TPM_RETURNCMD is set you return the id, but
2266 do not send a message to the owner */
2267 if(!(wFlags
& TPM_RETURNCMD
))
2269 if( menu
->wFlags
& MF_SYSMENU
)
2270 PostMessageA( pmt
->hOwnerWnd
, WM_SYSCOMMAND
, item
->wID
,
2271 MAKELPARAM((INT16
)pmt
->pt
.x
, (INT16
)pmt
->pt
.y
) );
2273 PostMessageA( pmt
->hOwnerWnd
, WM_COMMAND
, item
->wID
, 0 );
2279 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hMenu
, TRUE
, wFlags
);
2284 /***********************************************************************
2285 * MENU_SwitchTracking
2287 * Helper function for menu navigation routines.
2289 static void MENU_SwitchTracking( MTRACKER
* pmt
, HMENU hPtMenu
, UINT id
)
2291 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2292 POPUPMENU
*topmenu
= MENU_GetMenu( pmt
->hTopMenu
);
2294 TRACE("%p hmenu=0x%04x 0x%04x\n", pmt
, hPtMenu
, id
);
2296 if( pmt
->hTopMenu
!= hPtMenu
&&
2297 !((ptmenu
->wFlags
| topmenu
->wFlags
) & MF_POPUP
) )
2299 /* both are top level menus (system and menu-bar) */
2300 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2301 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
2302 pmt
->hTopMenu
= hPtMenu
;
2304 else MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
2305 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, id
, TRUE
, 0 );
2309 /***********************************************************************
2312 * Return TRUE if we can go on with menu tracking.
2314 static BOOL
MENU_ButtonDown( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2316 TRACE("%p hmenu=0x%04x\n", pmt
, hPtMenu
);
2321 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2324 if( IS_SYSTEM_MENU(ptmenu
) )
2325 item
= ptmenu
->items
;
2327 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2331 if( ptmenu
->FocusedItem
!= id
)
2332 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2334 /* If the popup menu is not already "popped" */
2335 if(!(item
->fState
& MF_MOUSESELECT
))
2337 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2339 /* In win31, a newly popped menu always remain opened for the next buttonup */
2340 if(TWEAK_WineLook
== WIN31_LOOK
)
2341 ptmenu
->bTimeToHide
= FALSE
;
2346 /* Else the click was on the menu bar, finish the tracking */
2351 /***********************************************************************
2354 * Return the value of MENU_ExecFocusedItem if
2355 * the selected item was not a popup. Else open the popup.
2356 * A -1 return value indicates that we go on with menu tracking.
2359 static INT
MENU_ButtonUp( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2361 TRACE("%p hmenu=0x%04x\n", pmt
, hPtMenu
);
2366 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2369 if( IS_SYSTEM_MENU(ptmenu
) )
2370 item
= ptmenu
->items
;
2372 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2374 if( item
&& (ptmenu
->FocusedItem
== id
))
2376 if( !(item
->fType
& MF_POPUP
) )
2377 return MENU_ExecFocusedItem( pmt
, hPtMenu
, wFlags
);
2379 /* If we are dealing with the top-level menu and that this */
2380 /* is a click on an already "poppped" item */
2381 /* Stop the menu tracking and close the opened submenus */
2382 if((pmt
->hTopMenu
== hPtMenu
) && (ptmenu
->bTimeToHide
== TRUE
))
2385 ptmenu
->bTimeToHide
= TRUE
;
2391 /***********************************************************************
2394 * Return TRUE if we can go on with menu tracking.
2396 static BOOL
MENU_MouseMove( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2398 UINT id
= NO_SELECTED_ITEM
;
2399 POPUPMENU
*ptmenu
= NULL
;
2403 ptmenu
= MENU_GetMenu( hPtMenu
);
2404 if( IS_SYSTEM_MENU(ptmenu
) )
2407 MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2410 if( id
== NO_SELECTED_ITEM
)
2412 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2413 NO_SELECTED_ITEM
, TRUE
, pmt
->hTopMenu
);
2416 else if( ptmenu
->FocusedItem
!= id
)
2418 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2419 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2425 /***********************************************************************
2428 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2430 static LRESULT
MENU_DoNextMenu( MTRACKER
* pmt
, UINT vk
)
2432 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2434 if( (vk
== VK_LEFT
&& menu
->FocusedItem
== 0 ) ||
2435 (vk
== VK_RIGHT
&& menu
->FocusedItem
== menu
->nItems
- 1))
2441 LRESULT l
= SendMessageA( pmt
->hOwnerWnd
, WM_NEXTMENU
, vk
,
2442 (IS_SYSTEM_MENU(menu
)) ? GetSubMenu16(pmt
->hTopMenu
,0) : pmt
->hTopMenu
);
2444 TRACE("%04x [%04x] -> %04x [%04x]\n",
2445 (UINT16
)pmt
->hCurrentMenu
, (UINT16
)pmt
->hOwnerWnd
, LOWORD(l
), HIWORD(l
) );
2449 wndPtr
= WIN_FindWndPtr(pmt
->hOwnerWnd
);
2451 hNewWnd
= pmt
->hOwnerWnd
;
2452 if( IS_SYSTEM_MENU(menu
) )
2454 /* switch to the menu bar */
2456 if( wndPtr
->dwStyle
& WS_CHILD
|| !wndPtr
->wIDmenu
)
2458 WIN_ReleaseWndPtr(wndPtr
);
2462 hNewMenu
= wndPtr
->wIDmenu
;
2465 menu
= MENU_GetMenu( hNewMenu
);
2466 id
= menu
->nItems
- 1;
2469 else if( wndPtr
->dwStyle
& WS_SYSMENU
)
2471 /* switch to the system menu */
2472 hNewMenu
= wndPtr
->hSysMenu
;
2476 WIN_ReleaseWndPtr(wndPtr
);
2479 WIN_ReleaseWndPtr(wndPtr
);
2481 else /* application returned a new menu to switch to */
2483 hNewMenu
= LOWORD(l
); hNewWnd
= HIWORD(l
);
2485 if( IsMenu(hNewMenu
) && IsWindow(hNewWnd
) )
2487 wndPtr
= WIN_FindWndPtr(hNewWnd
);
2489 if( wndPtr
->dwStyle
& WS_SYSMENU
&&
2490 GetSubMenu16(wndPtr
->hSysMenu
, 0) == hNewMenu
)
2492 /* get the real system menu */
2493 hNewMenu
= wndPtr
->hSysMenu
;
2495 else if( wndPtr
->dwStyle
& WS_CHILD
|| wndPtr
->wIDmenu
!= hNewMenu
)
2497 /* FIXME: Not sure what to do here, perhaps,
2498 * try to track hNewMenu as a popup? */
2500 TRACE(" -- got confused.\n");
2501 WIN_ReleaseWndPtr(wndPtr
);
2504 WIN_ReleaseWndPtr(wndPtr
);
2509 if( hNewMenu
!= pmt
->hTopMenu
)
2511 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
,
2513 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2514 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2517 if( hNewWnd
!= pmt
->hOwnerWnd
)
2520 pmt
->hOwnerWnd
= hNewWnd
;
2521 EVENT_Capture( pmt
->hOwnerWnd
, HTMENU
);
2524 pmt
->hTopMenu
= pmt
->hCurrentMenu
= hNewMenu
; /* all subpopups are hidden */
2525 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, id
, TRUE
, 0 );
2532 /***********************************************************************
2535 * The idea is not to show the popup if the next input message is
2536 * going to hide it anyway.
2538 static BOOL
MENU_SuspendPopup( MTRACKER
* pmt
, UINT16 uMsg
)
2542 msg
.hwnd
= pmt
->hOwnerWnd
;
2544 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2545 pmt
->trackFlags
|= TF_SKIPREMOVE
;
2550 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2551 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
2553 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2554 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2555 if( msg
.message
== WM_KEYDOWN
&&
2556 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
2558 pmt
->trackFlags
|= TF_SUSPENDPOPUP
;
2565 /* failures go through this */
2566 pmt
->trackFlags
&= ~TF_SUSPENDPOPUP
;
2570 /***********************************************************************
2573 * Handle a VK_LEFT key event in a menu.
2575 static void MENU_KeyLeft( MTRACKER
* pmt
, UINT wFlags
)
2578 HMENU hmenutmp
, hmenuprev
;
2581 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
2582 menu
= MENU_GetMenu( hmenutmp
);
2584 /* Try to move 1 column left (if possible) */
2585 if( (prevcol
= MENU_GetStartOfPrevColumn( pmt
->hCurrentMenu
)) !=
2586 NO_SELECTED_ITEM
) {
2588 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2593 /* close topmost popup */
2594 while (hmenutmp
!= pmt
->hCurrentMenu
)
2596 hmenuprev
= hmenutmp
;
2597 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
2600 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
);
2601 pmt
->hCurrentMenu
= hmenuprev
;
2603 if ( (hmenuprev
== pmt
->hTopMenu
) && !(menu
->wFlags
& MF_POPUP
) )
2605 /* move menu bar selection if no more popups are left */
2607 if( !MENU_DoNextMenu( pmt
, VK_LEFT
) )
2608 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_PREV
);
2610 if ( hmenuprev
!= hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2612 /* A sublevel menu was displayed - display the next one
2613 * unless there is another displacement coming up */
2615 if( !MENU_SuspendPopup( pmt
, WM_KEYDOWN
) )
2616 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2617 pmt
->hTopMenu
, TRUE
, wFlags
);
2623 /***********************************************************************
2626 * Handle a VK_RIGHT key event in a menu.
2628 static void MENU_KeyRight( MTRACKER
* pmt
, UINT wFlags
)
2631 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2634 TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2636 (MENU_GetMenu(pmt
->hCurrentMenu
))->
2638 pmt
->hTopMenu
, menu
->items
[0].text
);
2640 if ( (menu
->wFlags
& MF_POPUP
) || (pmt
->hCurrentMenu
!= pmt
->hTopMenu
))
2642 /* If already displaying a popup, try to display sub-popup */
2644 hmenutmp
= pmt
->hCurrentMenu
;
2645 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hmenutmp
, TRUE
, wFlags
);
2647 /* if subpopup was displayed then we are done */
2648 if (hmenutmp
!= pmt
->hCurrentMenu
) return;
2651 /* Check to see if there's another column */
2652 if( (nextcol
= MENU_GetStartOfNextColumn( pmt
->hCurrentMenu
)) !=
2653 NO_SELECTED_ITEM
) {
2654 TRACE("Going to %d.\n", nextcol
);
2655 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2660 if (!(menu
->wFlags
& MF_POPUP
)) /* menu bar tracking */
2662 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2664 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2665 hmenutmp
= pmt
->hCurrentMenu
= pmt
->hTopMenu
;
2666 } else hmenutmp
= 0;
2668 /* try to move to the next item */
2669 if( !MENU_DoNextMenu( pmt
, VK_RIGHT
) )
2670 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_NEXT
);
2672 if( hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2673 if( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
2674 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2675 pmt
->hTopMenu
, TRUE
, wFlags
);
2679 /***********************************************************************
2682 * Menu tracking code.
2684 static INT
MENU_TrackMenu( HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
2685 HWND hwnd
, const RECT
*lprect
)
2690 INT executedMenuId
= -1;
2692 BOOL enterIdleSent
= FALSE
;
2695 mt
.hCurrentMenu
= hmenu
;
2696 mt
.hTopMenu
= hmenu
;
2697 mt
.hOwnerWnd
= hwnd
;
2701 TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2702 hmenu
, wFlags
, x
, y
, hwnd
, (lprect
) ? lprect
->left
: 0, (lprect
) ? lprect
->top
: 0,
2703 (lprect
) ? lprect
->right
: 0, (lprect
) ? lprect
->bottom
: 0);
2706 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
2708 if (wFlags
& TPM_BUTTONDOWN
)
2710 /* Get the result in order to start the tracking or not */
2711 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
2712 fEndMenu
= !fRemove
;
2715 EVENT_Capture( mt
.hOwnerWnd
, HTMENU
);
2719 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
2720 msg
.hwnd
= (wFlags
& TPM_ENTERIDLEEX
&& menu
->wFlags
& MF_POPUP
) ? menu
->hWnd
: 0;
2722 /* we have to keep the message in the queue until it's
2723 * clear that menu loop is not over yet. */
2725 if (!MSG_InternalGetMessage( QMSG_WIN32A
, &msg
, msg
.hwnd
, mt
.hOwnerWnd
,
2726 MSGF_MENU
, PM_NOREMOVE
, !enterIdleSent
, &enterIdleSent
)) break;
2728 TranslateMessage( &msg
);
2731 if ( (msg
.hwnd
==menu
->hWnd
) || (msg
.message
!=WM_TIMER
) )
2732 enterIdleSent
=FALSE
;
2735 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
2737 /* Find a menu for this mouse event */
2739 CONV_POINT32TO16( &msg
.pt
, &pt16
);
2740 hmenu
= MENU_PtMenu( mt
.hTopMenu
, pt16
);
2744 /* no WM_NC... messages in captured state */
2746 case WM_RBUTTONDBLCLK
:
2747 case WM_RBUTTONDOWN
:
2748 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2750 case WM_LBUTTONDBLCLK
:
2751 case WM_LBUTTONDOWN
:
2752 /* If the message belongs to the menu, removes it from the queue */
2753 /* Else, end menu tracking */
2754 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
2755 fEndMenu
= !fRemove
;
2759 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2762 /* Check if a menu was selected by the mouse */
2765 executedMenuId
= MENU_ButtonUp( &mt
, hmenu
, wFlags
);
2767 /* End the loop if executedMenuId is an item ID */
2768 /* or if the job was done (executedMenuId = 0). */
2769 fEndMenu
= fRemove
= (executedMenuId
!= -1);
2771 /* No menu was selected by the mouse */
2772 /* if the function was called by TrackPopupMenu, continue
2773 with the menu tracking. If not, stop it */
2775 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
2780 /* In win95 winelook, the selected menu item must be changed every time the
2781 mouse moves. In Win31 winelook, the mouse button has to be held down */
2783 if ( (TWEAK_WineLook
> WIN31_LOOK
) ||
2784 ( (msg
.wParam
& MK_LBUTTON
) ||
2785 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
.wParam
& MK_RBUTTON
))) )
2787 fEndMenu
|= !MENU_MouseMove( &mt
, hmenu
, wFlags
);
2789 } /* switch(msg.message) - mouse */
2791 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
2793 fRemove
= TRUE
; /* Keyboard messages are always removed */
2801 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2802 NO_SELECTED_ITEM
, FALSE
, 0 );
2805 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2806 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
2809 case VK_DOWN
: /* If on menu bar, pull-down the menu */
2811 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
2812 if (!(menu
->wFlags
& MF_POPUP
))
2813 mt
.hCurrentMenu
= MENU_ShowSubPopup(mt
.hOwnerWnd
, mt
.hTopMenu
, TRUE
, wFlags
);
2814 else /* otherwise try to move selection */
2815 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
, ITEM_NEXT
);
2819 MENU_KeyLeft( &mt
, wFlags
);
2823 MENU_KeyRight( &mt
, wFlags
);
2833 hi
.cbSize
= sizeof(HELPINFO
);
2834 hi
.iContextType
= HELPINFO_MENUITEM
;
2835 if (menu
->FocusedItem
== NO_SELECTED_ITEM
)
2838 hi
.iCtrlId
= menu
->items
[menu
->FocusedItem
].wID
;
2839 hi
.hItemHandle
= hmenu
;
2840 hi
.dwContextId
= menu
->dwContextHelpID
;
2841 hi
.MousePos
= msg
.pt
;
2842 SendMessageA(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
2849 break; /* WM_KEYDOWN */
2859 break; /* WM_SYSKEYDOWN */
2865 if (msg
.wParam
== '\r' || msg
.wParam
== ' ')
2867 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2868 fEndMenu
= (executedMenuId
!= -1);
2873 /* Hack to avoid control chars. */
2874 /* We will find a better way real soon... */
2875 if ((msg
.wParam
<= 32) || (msg
.wParam
>= 127)) break;
2877 pos
= MENU_FindItemByKey( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2878 LOWORD(msg
.wParam
), FALSE
);
2879 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
2880 else if (pos
== (UINT
)-1) MessageBeep(0);
2883 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
, pos
,
2885 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2886 fEndMenu
= (executedMenuId
!= -1);
2890 } /* switch(msg.message) - kbd */
2894 DispatchMessageA( &msg
);
2897 if (!fEndMenu
) fRemove
= TRUE
;
2899 /* finally remove message from the queue */
2901 if (fRemove
&& !(mt
.trackFlags
& TF_SKIPREMOVE
) )
2902 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2903 else mt
.trackFlags
&= ~TF_SKIPREMOVE
;
2908 /* If dropdown is still painted and the close box is clicked on
2909 then the menu will be destroyed as part of the DispatchMessage above.
2910 This will then invalidate the menu handle in mt.hTopMenu. We should
2911 check for this first. */
2912 if( IsMenu( mt
.hTopMenu
) )
2914 menu
= MENU_GetMenu( mt
.hTopMenu
);
2916 if( IsWindow( mt
.hOwnerWnd
) )
2918 MENU_HideSubPopups( mt
.hOwnerWnd
, mt
.hTopMenu
, FALSE
);
2920 if (menu
&& menu
->wFlags
& MF_POPUP
)
2922 ShowWindow( menu
->hWnd
, SW_HIDE
);
2925 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
2926 SendMessageA( mt
.hOwnerWnd
, WM_MENUSELECT
, MAKELONG(0,0xffff), 0 );
2929 /* Reset the variable for hiding menu */
2930 if( menu
) menu
->bTimeToHide
= FALSE
;
2933 /* The return value is only used by TrackPopupMenu */
2934 return ((executedMenuId
!= -1) ? executedMenuId
: 0);
2937 /***********************************************************************
2940 static BOOL
MENU_InitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
2942 TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd
, hMenu
);
2946 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
2947 if (!(wFlags
& TPM_NONOTIFY
))
2948 SendMessageA( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
2950 SendMessageA( hWnd
, WM_SETCURSOR
, hWnd
, HTCAPTION
);
2952 if (!(wFlags
& TPM_NONOTIFY
))
2953 SendMessageA( hWnd
, WM_INITMENU
, hMenu
, 0 );
2957 /***********************************************************************
2960 static BOOL
MENU_ExitTracking(HWND hWnd
)
2962 TRACE("hwnd=0x%04x\n", hWnd
);
2964 SendMessageA( hWnd
, WM_EXITMENULOOP
, 0, 0 );
2969 /***********************************************************************
2970 * MENU_TrackMouseMenuBar
2972 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2974 void MENU_TrackMouseMenuBar( WND
* wndPtr
, INT ht
, POINT pt
)
2976 HWND hWnd
= wndPtr
->hwndSelf
;
2977 HMENU hMenu
= (ht
== HTSYSMENU
) ? wndPtr
->hSysMenu
: wndPtr
->wIDmenu
;
2978 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
2980 TRACE("pwnd=%p ht=0x%04x (%ld,%ld)\n", wndPtr
, ht
, pt
.x
, pt
.y
);
2984 MENU_InitTracking( hWnd
, hMenu
, FALSE
, wFlags
);
2985 MENU_TrackMenu( hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
2986 MENU_ExitTracking(hWnd
);
2991 /***********************************************************************
2992 * MENU_TrackKbdMenuBar
2994 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
2996 void MENU_TrackKbdMenuBar( WND
* wndPtr
, UINT wParam
, INT vkey
)
2998 UINT uItem
= NO_SELECTED_ITEM
;
3000 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3002 /* find window that has a menu */
3004 while( wndPtr
->dwStyle
& WS_CHILD
)
3005 if( !(wndPtr
= wndPtr
->parent
) ) return;
3007 /* check if we have to track a system menu */
3009 if( (wndPtr
->dwStyle
& (WS_CHILD
| WS_MINIMIZE
)) ||
3010 !wndPtr
->wIDmenu
|| vkey
== VK_SPACE
)
3012 if( !(wndPtr
->dwStyle
& WS_SYSMENU
) ) return;
3013 hTrackMenu
= wndPtr
->hSysMenu
;
3015 wParam
|= HTSYSMENU
; /* prevent item lookup */
3018 hTrackMenu
= wndPtr
->wIDmenu
;
3020 if (IsMenu( hTrackMenu
))
3022 MENU_InitTracking( wndPtr
->hwndSelf
, hTrackMenu
, FALSE
, wFlags
);
3024 if( vkey
&& vkey
!= VK_SPACE
)
3026 uItem
= MENU_FindItemByKey( wndPtr
->hwndSelf
, hTrackMenu
,
3027 vkey
, (wParam
& HTSYSMENU
) );
3028 if( uItem
>= (UINT
)(-2) )
3030 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3037 MENU_SelectItem( wndPtr
->hwndSelf
, hTrackMenu
, uItem
, TRUE
, 0 );
3039 if( uItem
== NO_SELECTED_ITEM
)
3040 MENU_MoveSelection( wndPtr
->hwndSelf
, hTrackMenu
, ITEM_NEXT
);
3042 PostMessageA( wndPtr
->hwndSelf
, WM_KEYDOWN
, VK_DOWN
, 0L );
3044 MENU_TrackMenu( hTrackMenu
, wFlags
, 0, 0, wndPtr
->hwndSelf
, NULL
);
3047 MENU_ExitTracking (wndPtr
->hwndSelf
);
3052 /**********************************************************************
3053 * TrackPopupMenu16 (USER.416)
3055 BOOL16 WINAPI
TrackPopupMenu16( HMENU16 hMenu
, UINT16 wFlags
, INT16 x
, INT16 y
,
3056 INT16 nReserved
, HWND16 hWnd
, const RECT16
*lpRect
)
3060 CONV_RECT16TO32( lpRect
, &r
);
3061 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, nReserved
, hWnd
,
3062 lpRect
? &r
: NULL
);
3066 /**********************************************************************
3067 * TrackPopupMenu (USER32.549)
3069 * Like the win32 API, the function return the command ID only if the
3070 * flag TPM_RETURNCMD is on.
3073 BOOL WINAPI
TrackPopupMenu( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3074 INT nReserved
, HWND hWnd
, const RECT
*lpRect
)
3078 MENU_InitTracking(hWnd
, hMenu
, TRUE
, wFlags
);
3080 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3081 if (!(wFlags
& TPM_NONOTIFY
))
3082 SendMessageA( hWnd
, WM_INITMENUPOPUP
, hMenu
, 0);
3084 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
, 0, 0 ))
3085 ret
= MENU_TrackMenu( hMenu
, wFlags
| TPM_POPUPMENU
, 0, 0, hWnd
, lpRect
);
3086 MENU_ExitTracking(hWnd
);
3088 if( (!(wFlags
& TPM_RETURNCMD
)) && (ret
!= FALSE
) )
3094 /**********************************************************************
3095 * TrackPopupMenuEx (USER32.550)
3097 BOOL WINAPI
TrackPopupMenuEx( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3098 HWND hWnd
, LPTPMPARAMS lpTpm
)
3100 FIXME("not fully implemented\n" );
3101 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, 0, hWnd
,
3102 lpTpm
? &lpTpm
->rcExclude
: NULL
);
3105 /***********************************************************************
3108 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3110 LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
,
3113 WND
* wndPtr
= WIN_FindWndPtr(hwnd
);
3116 TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
3117 hwnd
, message
, wParam
, lParam
);
3123 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*)lParam
;
3124 SetWindowLongA( hwnd
, 0, (LONG
)cs
->lpCreateParams
);
3129 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
3130 retvalue
= MA_NOACTIVATE
;
3136 BeginPaint( hwnd
, &ps
);
3137 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
3138 (HMENU
)GetWindowLongA( hwnd
, 0 ) );
3139 EndPaint( hwnd
, &ps
);
3149 /* zero out global pointer in case resident popup window
3150 * was somehow destroyed. */
3152 if(MENU_GetTopPopupWnd() )
3154 if( hwnd
== pTopPopupWnd
->hwndSelf
)
3156 ERR("resident popup destroyed!\n");
3158 MENU_DestroyTopPopupWnd();
3163 MENU_ReleaseTopPopupWnd();
3171 if( !(*(HMENU
*)wndPtr
->wExtra
) )
3172 ERR("no menu to display\n");
3175 *(HMENU
*)wndPtr
->wExtra
= 0;
3178 case MM_SETMENUHANDLE
:
3180 *(HMENU
*)wndPtr
->wExtra
= (HMENU
)wParam
;
3183 case MM_GETMENUHANDLE
:
3185 retvalue
= *(HMENU
*)wndPtr
->wExtra
;
3189 retvalue
= DefWindowProcA( hwnd
, message
, wParam
, lParam
);
3194 WIN_ReleaseWndPtr(wndPtr
);
3199 /***********************************************************************
3200 * MENU_GetMenuBarHeight
3202 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3204 UINT
MENU_GetMenuBarHeight( HWND hwnd
, UINT menubarWidth
,
3205 INT orgX
, INT orgY
)
3213 TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3214 hwnd
, menubarWidth
, orgX
, orgY
);
3216 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
3219 if (!(lppop
= MENU_GetMenu((HMENU16
)wndPtr
->wIDmenu
)))
3221 WIN_ReleaseWndPtr(wndPtr
);
3225 hdc
= GetDCEx( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3226 SelectObject( hdc
, hMenuFont
);
3227 SetRect(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+GetSystemMetrics(SM_CYMENU
));
3228 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
3229 ReleaseDC( hwnd
, hdc
);
3230 retvalue
= lppop
->Height
;
3231 WIN_ReleaseWndPtr(wndPtr
);
3236 /*******************************************************************
3237 * ChangeMenu16 (USER.153)
3239 BOOL16 WINAPI
ChangeMenu16( HMENU16 hMenu
, UINT16 pos
, SEGPTR data
,
3240 UINT16 id
, UINT16 flags
)
3242 TRACE("menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
3243 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3244 if (flags
& MF_APPEND
) return AppendMenu16( hMenu
, flags
& ~MF_APPEND
,
3247 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
3248 /* for MF_DELETE. We should check the parameters for all others */
3249 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
3251 if (flags
& MF_DELETE
) return DeleteMenu16(hMenu
, pos
, flags
& ~MF_DELETE
);
3252 if (flags
& MF_CHANGE
) return ModifyMenu16(hMenu
, pos
, flags
& ~MF_CHANGE
,
3254 if (flags
& MF_REMOVE
) return RemoveMenu16(hMenu
,
3255 flags
& MF_BYPOSITION
? pos
: id
,
3256 flags
& ~MF_REMOVE
);
3257 /* Default: MF_INSERT */
3258 return InsertMenu16( hMenu
, pos
, flags
, id
, data
);
3262 /*******************************************************************
3263 * ChangeMenuA (USER32.23)
3265 BOOL WINAPI
ChangeMenuA( HMENU hMenu
, UINT pos
, LPCSTR data
,
3266 UINT id
, UINT flags
)
3268 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3269 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3270 if (flags
& MF_APPEND
) return AppendMenuA( hMenu
, flags
& ~MF_APPEND
,
3272 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3273 if (flags
& MF_CHANGE
) return ModifyMenuA(hMenu
, pos
, flags
& ~MF_CHANGE
,
3275 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3276 flags
& MF_BYPOSITION
? pos
: id
,
3277 flags
& ~MF_REMOVE
);
3278 /* Default: MF_INSERT */
3279 return InsertMenuA( hMenu
, pos
, flags
, id
, data
);
3283 /*******************************************************************
3284 * ChangeMenuW (USER32.24)
3286 BOOL WINAPI
ChangeMenuW( HMENU hMenu
, UINT pos
, LPCWSTR data
,
3287 UINT id
, UINT flags
)
3289 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3290 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3291 if (flags
& MF_APPEND
) return AppendMenuW( hMenu
, flags
& ~MF_APPEND
,
3293 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3294 if (flags
& MF_CHANGE
) return ModifyMenuW(hMenu
, pos
, flags
& ~MF_CHANGE
,
3296 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3297 flags
& MF_BYPOSITION
? pos
: id
,
3298 flags
& ~MF_REMOVE
);
3299 /* Default: MF_INSERT */
3300 return InsertMenuW( hMenu
, pos
, flags
, id
, data
);
3304 /*******************************************************************
3305 * CheckMenuItem16 (USER.154)
3307 BOOL16 WINAPI
CheckMenuItem16( HMENU16 hMenu
, UINT16 id
, UINT16 flags
)
3309 return (BOOL16
)CheckMenuItem( hMenu
, id
, flags
);
3313 /*******************************************************************
3314 * CheckMenuItem (USER32.46)
3316 DWORD WINAPI
CheckMenuItem( HMENU hMenu
, UINT id
, UINT flags
)
3321 TRACE("menu=%04x id=%04x flags=%04x\n", hMenu
, id
, flags
);
3322 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
3323 ret
= item
->fState
& MF_CHECKED
;
3324 if (flags
& MF_CHECKED
) item
->fState
|= MF_CHECKED
;
3325 else item
->fState
&= ~MF_CHECKED
;
3330 /**********************************************************************
3331 * EnableMenuItem16 (USER.155)
3333 UINT16 WINAPI
EnableMenuItem16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3335 return EnableMenuItem( hMenu
, wItemID
, wFlags
);
3339 /**********************************************************************
3340 * EnableMenuItem (USER32.170)
3342 UINT WINAPI
EnableMenuItem( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3348 TRACE("(%04x, %04X, %04X) !\n",
3349 hMenu
, wItemID
, wFlags
);
3351 /* Get the Popupmenu to access the owner menu */
3352 if (!(menu
= MENU_GetMenu(hMenu
)))
3355 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
)))
3358 oldflags
= item
->fState
& (MF_GRAYED
| MF_DISABLED
);
3359 item
->fState
^= (oldflags
^ wFlags
) & (MF_GRAYED
| MF_DISABLED
);
3361 /* In win95 if the close item in the system menu change update the close button */
3362 if (TWEAK_WineLook
== WIN95_LOOK
)
3363 if((item
->wID
== SC_CLOSE
) && (oldflags
!= wFlags
))
3365 if (menu
->hSysMenuOwner
!= 0)
3367 POPUPMENU
* parentMenu
;
3369 /* Get the parent menu to access*/
3370 if (!(parentMenu
= MENU_GetMenu(menu
->hSysMenuOwner
)))
3373 /* Refresh the frame to reflect the change*/
3374 SetWindowPos(parentMenu
->hWnd
, 0, 0, 0, 0, 0,
3375 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
3383 /*******************************************************************
3384 * GetMenuString16 (USER.161)
3386 INT16 WINAPI
GetMenuString16( HMENU16 hMenu
, UINT16 wItemID
,
3387 LPSTR str
, INT16 nMaxSiz
, UINT16 wFlags
)
3389 return GetMenuStringA( hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3393 /*******************************************************************
3394 * GetMenuStringA (USER32.268)
3396 INT WINAPI
GetMenuStringA(
3397 HMENU hMenu
, /* [in] menuhandle */
3398 UINT wItemID
, /* [in] menu item (dep. on wFlags) */
3399 LPSTR str
, /* [out] outbuffer. If NULL, func returns entry length*/
3400 INT nMaxSiz
, /* [in] length of buffer. if 0, func returns entry len*/
3401 UINT wFlags
/* [in] MF_ flags */
3405 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3406 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3407 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3408 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3409 if (!str
|| !nMaxSiz
) return strlen(item
->text
);
3411 lstrcpynA( str
, item
->text
, nMaxSiz
);
3412 TRACE("returning '%s'\n", str
);
3417 /*******************************************************************
3418 * GetMenuStringW (USER32.269)
3420 INT WINAPI
GetMenuStringW( HMENU hMenu
, UINT wItemID
,
3421 LPWSTR str
, INT nMaxSiz
, UINT wFlags
)
3425 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3426 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3427 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3428 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3429 if (!str
|| !nMaxSiz
) return strlen(item
->text
);
3431 lstrcpynAtoW( str
, item
->text
, nMaxSiz
);
3432 return lstrlenW(str
);
3436 /**********************************************************************
3437 * HiliteMenuItem16 (USER.162)
3439 BOOL16 WINAPI
HiliteMenuItem16( HWND16 hWnd
, HMENU16 hMenu
, UINT16 wItemID
,
3442 return HiliteMenuItem( hWnd
, hMenu
, wItemID
, wHilite
);
3446 /**********************************************************************
3447 * HiliteMenuItem (USER32.318)
3449 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
3453 TRACE("(%04x, %04x, %04x, %04x);\n",
3454 hWnd
, hMenu
, wItemID
, wHilite
);
3455 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
3456 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3457 if (menu
->FocusedItem
== wItemID
) return TRUE
;
3458 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
3459 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
, 0 );
3464 /**********************************************************************
3465 * GetMenuState16 (USER.250)
3467 UINT16 WINAPI
GetMenuState16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3469 return GetMenuState( hMenu
, wItemID
, wFlags
);
3473 /**********************************************************************
3474 * GetMenuState (USER32.267)
3476 UINT WINAPI
GetMenuState( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3479 TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
3480 hMenu
, wItemID
, wFlags
);
3481 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
3482 debug_print_menuitem (" item: ", item
, "");
3483 if (item
->fType
& MF_POPUP
)
3485 POPUPMENU
*menu
= MENU_GetMenu( item
->hSubMenu
);
3486 if (!menu
) return -1;
3487 else return (menu
->nItems
<< 8) | ((item
->fState
|item
->fType
) & 0xff);
3491 /* We used to (from way back then) mask the result to 0xff. */
3492 /* I don't know why and it seems wrong as the documented */
3493 /* return flag MF_SEPARATOR is outside that mask. */
3494 return (item
->fType
| item
->fState
);
3499 /**********************************************************************
3500 * GetMenuItemCount16 (USER.263)
3502 INT16 WINAPI
GetMenuItemCount16( HMENU16 hMenu
)
3504 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3505 if (!menu
) return -1;
3506 TRACE("(%04x) returning %d\n",
3507 hMenu
, menu
->nItems
);
3508 return menu
->nItems
;
3512 /**********************************************************************
3513 * GetMenuItemCount (USER32.262)
3515 INT WINAPI
GetMenuItemCount( HMENU hMenu
)
3517 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3518 if (!menu
) return -1;
3519 TRACE("(%04x) returning %d\n",
3520 hMenu
, menu
->nItems
);
3521 return menu
->nItems
;
3524 /**********************************************************************
3525 * GetMenuItemID16 (USER.264)
3527 UINT16 WINAPI
GetMenuItemID16( HMENU16 hMenu
, INT16 nPos
)
3529 return (UINT16
) GetMenuItemID (hMenu
, nPos
);
3532 /**********************************************************************
3533 * GetMenuItemID (USER32.263)
3535 UINT WINAPI
GetMenuItemID( HMENU hMenu
, INT nPos
)
3539 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return 0;
3540 if (lpmi
->fType
& MF_POPUP
) return -1;
3545 /*******************************************************************
3546 * InsertMenu16 (USER.410)
3548 BOOL16 WINAPI
InsertMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3549 UINT16 id
, SEGPTR data
)
3551 UINT pos32
= (UINT
)pos
;
3552 if ((pos
== (UINT16
)-1) && (flags
& MF_BYPOSITION
)) pos32
= (UINT
)-1;
3553 if (IS_STRING_ITEM(flags
) && data
)
3554 return InsertMenuA( hMenu
, pos32
, flags
, id
,
3555 (LPSTR
)PTR_SEG_TO_LIN(data
) );
3556 return InsertMenuA( hMenu
, pos32
, flags
, id
, (LPSTR
)data
);
3560 /*******************************************************************
3561 * InsertMenuA (USER32.322)
3563 BOOL WINAPI
InsertMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3564 UINT id
, LPCSTR str
)
3568 if (IS_STRING_ITEM(flags
) && str
)
3569 TRACE("hMenu %04x, pos %d, flags %08x, "
3570 "id %04x, str '%s'\n",
3571 hMenu
, pos
, flags
, id
, str
);
3572 else TRACE("hMenu %04x, pos %d, flags %08x, "
3573 "id %04x, str %08lx (not a string)\n",
3574 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3576 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
3578 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
3580 RemoveMenu( hMenu
, pos
, flags
);
3584 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
3585 (MENU_GetMenu((HMENU16
)id
))->wFlags
|= MF_POPUP
;
3587 item
->hCheckBit
= item
->hUnCheckBit
= 0;
3592 /*******************************************************************
3593 * InsertMenuW (USER32.325)
3595 BOOL WINAPI
InsertMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3596 UINT id
, LPCWSTR str
)
3600 if (IS_STRING_ITEM(flags
) && str
)
3602 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
3603 ret
= InsertMenuA( hMenu
, pos
, flags
, id
, newstr
);
3604 HeapFree( GetProcessHeap(), 0, newstr
);
3607 else return InsertMenuA( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
3611 /*******************************************************************
3612 * AppendMenu16 (USER.411)
3614 BOOL16 WINAPI
AppendMenu16(HMENU16 hMenu
, UINT16 flags
, UINT16 id
, SEGPTR data
)
3616 return InsertMenu16( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3620 /*******************************************************************
3621 * AppendMenuA (USER32.5)
3623 BOOL WINAPI
AppendMenuA( HMENU hMenu
, UINT flags
,
3624 UINT id
, LPCSTR data
)
3626 return InsertMenuA( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3630 /*******************************************************************
3631 * AppendMenuW (USER32.6)
3633 BOOL WINAPI
AppendMenuW( HMENU hMenu
, UINT flags
,
3634 UINT id
, LPCWSTR data
)
3636 return InsertMenuW( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3640 /**********************************************************************
3641 * RemoveMenu16 (USER.412)
3643 BOOL16 WINAPI
RemoveMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3645 return RemoveMenu( hMenu
, nPos
, wFlags
);
3649 /**********************************************************************
3650 * RemoveMenu (USER32.441)
3652 BOOL WINAPI
RemoveMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3657 TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu
, nPos
, wFlags
);
3658 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3659 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3663 MENU_FreeItemData( item
);
3665 if (--menu
->nItems
== 0)
3667 HeapFree( SystemHeap
, 0, menu
->items
);
3672 while(nPos
< menu
->nItems
)
3678 menu
->items
= HeapReAlloc( SystemHeap
, 0, menu
->items
,
3679 menu
->nItems
* sizeof(MENUITEM
) );
3685 /**********************************************************************
3686 * DeleteMenu16 (USER.413)
3688 BOOL16 WINAPI
DeleteMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3690 return DeleteMenu( hMenu
, nPos
, wFlags
);
3694 /**********************************************************************
3695 * DeleteMenu (USER32.129)
3697 BOOL WINAPI
DeleteMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3699 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
3700 if (!item
) return FALSE
;
3701 if (item
->fType
& MF_POPUP
) DestroyMenu( item
->hSubMenu
);
3702 /* nPos is now the position of the item */
3703 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
3708 /*******************************************************************
3709 * ModifyMenu16 (USER.414)
3711 BOOL16 WINAPI
ModifyMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3712 UINT16 id
, SEGPTR data
)
3714 if (IS_STRING_ITEM(flags
))
3715 return ModifyMenuA( hMenu
, pos
, flags
, id
,
3716 (LPSTR
)PTR_SEG_TO_LIN(data
) );
3717 return ModifyMenuA( hMenu
, pos
, flags
, id
, (LPSTR
)data
);
3721 /*******************************************************************
3722 * ModifyMenuA (USER32.397)
3724 BOOL WINAPI
ModifyMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3725 UINT id
, LPCSTR str
)
3729 if (IS_STRING_ITEM(flags
))
3731 TRACE("%04x %d %04x %04x '%s'\n",
3732 hMenu
, pos
, flags
, id
, str
? str
: "#NULL#" );
3733 if (!str
) return FALSE
;
3737 TRACE("%04x %d %04x %04x %08lx\n",
3738 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3741 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
3742 return MENU_SetItemData( item
, flags
, id
, str
);
3746 /*******************************************************************
3747 * ModifyMenuW (USER32.398)
3749 BOOL WINAPI
ModifyMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3750 UINT id
, LPCWSTR str
)
3754 if (IS_STRING_ITEM(flags
) && str
)
3756 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
3757 ret
= ModifyMenuA( hMenu
, pos
, flags
, id
, newstr
);
3758 HeapFree( GetProcessHeap(), 0, newstr
);
3761 else return ModifyMenuA( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
3765 /**********************************************************************
3766 * CreatePopupMenu16 (USER.415)
3768 HMENU16 WINAPI
CreatePopupMenu16(void)
3770 return CreatePopupMenu();
3774 /**********************************************************************
3775 * CreatePopupMenu (USER32.82)
3777 HMENU WINAPI
CreatePopupMenu(void)
3782 if (!(hmenu
= CreateMenu())) return 0;
3783 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
3784 menu
->wFlags
|= MF_POPUP
;
3785 menu
->bTimeToHide
= FALSE
;
3790 /**********************************************************************
3791 * GetMenuCheckMarkDimensions (USER.417) (USER32.258)
3793 DWORD WINAPI
GetMenuCheckMarkDimensions(void)
3795 return MAKELONG( check_bitmap_width
, check_bitmap_height
);
3799 /**********************************************************************
3800 * SetMenuItemBitmaps16 (USER.418)
3802 BOOL16 WINAPI
SetMenuItemBitmaps16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
,
3803 HBITMAP16 hNewUnCheck
, HBITMAP16 hNewCheck
)
3805 return SetMenuItemBitmaps( hMenu
, nPos
, wFlags
, hNewUnCheck
, hNewCheck
);
3809 /**********************************************************************
3810 * SetMenuItemBitmaps (USER32.490)
3812 BOOL WINAPI
SetMenuItemBitmaps( HMENU hMenu
, UINT nPos
, UINT wFlags
,
3813 HBITMAP hNewUnCheck
, HBITMAP hNewCheck
)
3816 TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3817 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
3818 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3820 if (!hNewCheck
&& !hNewUnCheck
)
3822 item
->fState
&= ~MF_USECHECKBITMAPS
;
3824 else /* Install new bitmaps */
3826 item
->hCheckBit
= hNewCheck
;
3827 item
->hUnCheckBit
= hNewUnCheck
;
3828 item
->fState
|= MF_USECHECKBITMAPS
;
3834 /**********************************************************************
3835 * CreateMenu16 (USER.151)
3837 HMENU16 WINAPI
CreateMenu16(void)
3839 return CreateMenu();
3843 /**********************************************************************
3844 * CreateMenu (USER32.81)
3846 HMENU WINAPI
CreateMenu(void)
3850 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) ))) return 0;
3851 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3853 ZeroMemory(menu
, sizeof(POPUPMENU
));
3854 menu
->wMagic
= MENU_MAGIC
;
3855 menu
->FocusedItem
= NO_SELECTED_ITEM
;
3856 menu
->bTimeToHide
= FALSE
;
3858 TRACE("return %04x\n", hMenu
);
3864 /**********************************************************************
3865 * DestroyMenu16 (USER.152)
3867 BOOL16 WINAPI
DestroyMenu16( HMENU16 hMenu
)
3869 return DestroyMenu( hMenu
);
3873 /**********************************************************************
3874 * DestroyMenu (USER32.134)
3876 BOOL WINAPI
DestroyMenu( HMENU hMenu
)
3878 TRACE("(%04x)\n", hMenu
);
3880 /* Silently ignore attempts to destroy default system popup */
3882 if (hMenu
&& hMenu
!= MENU_DefSysPopup
)
3884 LPPOPUPMENU lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3885 WND
*pTPWnd
= MENU_GetTopPopupWnd();
3887 if( pTPWnd
&& (hMenu
== *(HMENU
*)pTPWnd
->wExtra
) )
3888 *(UINT
*)pTPWnd
->wExtra
= 0;
3890 if (!IS_A_MENU(lppop
)) lppop
= NULL
;
3893 lppop
->wMagic
= 0; /* Mark it as destroyed */
3895 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
&&
3896 (!pTPWnd
|| (lppop
->hWnd
!= pTPWnd
->hwndSelf
)))
3897 DestroyWindow( lppop
->hWnd
);
3899 if (lppop
->items
) /* recursively destroy submenus */
3902 MENUITEM
*item
= lppop
->items
;
3903 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
3905 if (item
->fType
& MF_POPUP
) DestroyMenu(item
->hSubMenu
);
3906 MENU_FreeItemData( item
);
3908 HeapFree( SystemHeap
, 0, lppop
->items
);
3910 USER_HEAP_FREE( hMenu
);
3911 MENU_ReleaseTopPopupWnd();
3915 MENU_ReleaseTopPopupWnd();
3919 return (hMenu
!= MENU_DefSysPopup
);
3923 /**********************************************************************
3924 * GetSystemMenu16 (USER.156)
3926 HMENU16 WINAPI
GetSystemMenu16( HWND16 hWnd
, BOOL16 bRevert
)
3928 return GetSystemMenu( hWnd
, bRevert
);
3932 /**********************************************************************
3933 * GetSystemMenu (USER32.291)
3935 HMENU WINAPI
GetSystemMenu( HWND hWnd
, BOOL bRevert
)
3937 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
3942 if( wndPtr
->hSysMenu
)
3946 DestroyMenu(wndPtr
->hSysMenu
);
3947 wndPtr
->hSysMenu
= 0;
3951 POPUPMENU
*menu
= MENU_GetMenu( wndPtr
->hSysMenu
);
3954 if( menu
->nItems
> 0 && menu
->items
[0].hSubMenu
== MENU_DefSysPopup
)
3955 menu
->items
[0].hSubMenu
= MENU_CopySysPopup();
3959 WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
3960 wndPtr
->hSysMenu
, hWnd
);
3961 wndPtr
->hSysMenu
= 0;
3966 if(!wndPtr
->hSysMenu
&& (wndPtr
->dwStyle
& WS_SYSMENU
) )
3967 wndPtr
->hSysMenu
= MENU_GetSysMenu( hWnd
, (HMENU
)(-1) );
3969 if( wndPtr
->hSysMenu
)
3972 retvalue
= GetSubMenu16(wndPtr
->hSysMenu
, 0);
3974 /* Store the dummy sysmenu handle to facilitate the refresh */
3975 /* of the close button if the SC_CLOSE item change */
3976 menu
= MENU_GetMenu(retvalue
);
3978 menu
->hSysMenuOwner
= wndPtr
->hSysMenu
;
3980 WIN_ReleaseWndPtr(wndPtr
);
3986 /*******************************************************************
3987 * SetSystemMenu16 (USER.280)
3989 BOOL16 WINAPI
SetSystemMenu16( HWND16 hwnd
, HMENU16 hMenu
)
3991 return SetSystemMenu( hwnd
, hMenu
);
3995 /*******************************************************************
3996 * SetSystemMenu (USER32.508)
3998 BOOL WINAPI
SetSystemMenu( HWND hwnd
, HMENU hMenu
)
4000 WND
*wndPtr
= WIN_FindWndPtr(hwnd
);
4004 if (wndPtr
->hSysMenu
) DestroyMenu( wndPtr
->hSysMenu
);
4005 wndPtr
->hSysMenu
= MENU_GetSysMenu( hwnd
, hMenu
);
4006 WIN_ReleaseWndPtr(wndPtr
);
4013 /**********************************************************************
4014 * GetMenu16 (USER.157)
4016 HMENU16 WINAPI
GetMenu16( HWND16 hWnd
)
4018 return (HMENU16
)GetMenu(hWnd
);
4022 /**********************************************************************
4023 * GetMenu (USER32.257)
4025 HMENU WINAPI
GetMenu( HWND hWnd
)
4028 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
4029 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
4031 retvalue
= (HMENU
)wndPtr
->wIDmenu
;
4036 WIN_ReleaseWndPtr(wndPtr
);
4041 /**********************************************************************
4042 * SetMenu16 (USER.158)
4044 BOOL16 WINAPI
SetMenu16( HWND16 hWnd
, HMENU16 hMenu
)
4046 return SetMenu( hWnd
, hMenu
);
4050 /**********************************************************************
4051 * SetMenu (USER32.487)
4053 BOOL WINAPI
SetMenu( HWND hWnd
, HMENU hMenu
)
4055 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
4057 TRACE("(%04x, %04x);\n", hWnd
, hMenu
);
4059 if (hMenu
&& !IsMenu(hMenu
))
4061 WARN("hMenu is not a menu handle\n");
4066 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
4068 if (GetCapture() == hWnd
) ReleaseCapture();
4070 wndPtr
->wIDmenu
= (UINT
)hMenu
;
4075 if (!(lpmenu
= MENU_GetMenu(hMenu
)))
4077 WIN_ReleaseWndPtr(wndPtr
);
4080 lpmenu
->hWnd
= hWnd
;
4081 lpmenu
->wFlags
&= ~MF_POPUP
; /* Can't be a popup */
4082 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
4084 if (IsWindowVisible(hWnd
))
4085 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4086 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4087 WIN_ReleaseWndPtr(wndPtr
);
4090 WIN_ReleaseWndPtr(wndPtr
);
4096 /**********************************************************************
4097 * GetSubMenu16 (USER.159)
4099 HMENU16 WINAPI
GetSubMenu16( HMENU16 hMenu
, INT16 nPos
)
4101 return GetSubMenu( hMenu
, nPos
);
4105 /**********************************************************************
4106 * GetSubMenu (USER32.288)
4108 HMENU WINAPI
GetSubMenu( HMENU hMenu
, INT nPos
)
4112 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return 0;
4113 if (!(lpmi
->fType
& MF_POPUP
)) return 0;
4114 return lpmi
->hSubMenu
;
4118 /**********************************************************************
4119 * DrawMenuBar16 (USER.160)
4121 void WINAPI
DrawMenuBar16( HWND16 hWnd
)
4123 DrawMenuBar( hWnd
);
4127 /**********************************************************************
4128 * DrawMenuBar (USER32.161)
4130 BOOL WINAPI
DrawMenuBar( HWND hWnd
)
4133 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
4134 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
) && wndPtr
->wIDmenu
)
4136 lppop
= MENU_GetMenu((HMENU16
)wndPtr
->wIDmenu
);
4139 WIN_ReleaseWndPtr(wndPtr
);
4143 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
4144 lppop
->hwndOwner
= hWnd
;
4145 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4146 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4147 WIN_ReleaseWndPtr(wndPtr
);
4150 WIN_ReleaseWndPtr(wndPtr
);
4155 /***********************************************************************
4156 * EndMenu (USER.187) (USER32.175)
4158 void WINAPI
EndMenu(void)
4161 * FIXME: NOT ENOUGH! This has to cancel menu tracking right away.
4168 /***********************************************************************
4169 * LookupMenuHandle (USER.217)
4171 HMENU16 WINAPI
LookupMenuHandle16( HMENU16 hmenu
, INT16 id
)
4173 HMENU hmenu32
= hmenu
;
4175 if (!MENU_FindItem( &hmenu32
, &id32
, MF_BYCOMMAND
)) return 0;
4176 else return hmenu32
;
4180 /**********************************************************************
4181 * LoadMenu16 (USER.150)
4183 HMENU16 WINAPI
LoadMenu16( HINSTANCE16 instance
, SEGPTR name
)
4191 char *str
= (char *)PTR_SEG_TO_LIN( name
);
4192 TRACE("(%04x,'%s')\n", instance
, str
);
4193 if (str
[0] == '#') name
= (SEGPTR
)atoi( str
+ 1 );
4196 TRACE("(%04x,%04x)\n",instance
,LOWORD(name
));
4198 if (!name
) return 0;
4200 /* check for Win32 module */
4201 if (HIWORD(instance
))
4202 return LoadMenuA(instance
,PTR_SEG_TO_LIN(name
));
4203 instance
= GetExePtr( instance
);
4205 if (!(hRsrc
= FindResource16( instance
, name
, RT_MENU16
))) return 0;
4206 if (!(handle
= LoadResource16( instance
, hRsrc
))) return 0;
4207 hMenu
= LoadMenuIndirect16(LockResource16(handle
));
4208 FreeResource16( handle
);
4213 /*****************************************************************
4214 * LoadMenuA (USER32.370)
4216 HMENU WINAPI
LoadMenuA( HINSTANCE instance
, LPCSTR name
)
4218 HRSRC hrsrc
= FindResourceA( instance
, name
, RT_MENUA
);
4219 if (!hrsrc
) return 0;
4220 return LoadMenuIndirectA( (LPCVOID
)LoadResource( instance
, hrsrc
));
4224 /*****************************************************************
4225 * LoadMenuW (USER32.373)
4227 HMENU WINAPI
LoadMenuW( HINSTANCE instance
, LPCWSTR name
)
4229 HRSRC hrsrc
= FindResourceW( instance
, name
, RT_MENUW
);
4230 if (!hrsrc
) return 0;
4231 return LoadMenuIndirectW( (LPCVOID
)LoadResource( instance
, hrsrc
));
4235 /**********************************************************************
4236 * LoadMenuIndirect16 (USER.220)
4238 HMENU16 WINAPI
LoadMenuIndirect16( LPCVOID
template )
4241 WORD version
, offset
;
4242 LPCSTR p
= (LPCSTR
)template;
4244 TRACE("(%p)\n", template );
4245 version
= GET_WORD(p
);
4249 WARN("version must be 0 for Win16\n" );
4252 offset
= GET_WORD(p
);
4253 p
+= sizeof(WORD
) + offset
;
4254 if (!(hMenu
= CreateMenu())) return 0;
4255 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
4257 DestroyMenu( hMenu
);
4264 /**********************************************************************
4265 * LoadMenuIndirectA (USER32.371)
4267 HMENU WINAPI
LoadMenuIndirectA( LPCVOID
template )
4270 WORD version
, offset
;
4271 LPCSTR p
= (LPCSTR
)template;
4273 TRACE("%p\n", template );
4274 version
= GET_WORD(p
);
4279 offset
= GET_WORD(p
);
4280 p
+= sizeof(WORD
) + offset
;
4281 if (!(hMenu
= CreateMenu())) return 0;
4282 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
4284 DestroyMenu( hMenu
);
4289 offset
= GET_WORD(p
);
4290 p
+= sizeof(WORD
) + offset
;
4291 if (!(hMenu
= CreateMenu())) return 0;
4292 if (!MENUEX_ParseResource( p
, hMenu
))
4294 DestroyMenu( hMenu
);
4299 ERR("version %d not supported.\n", version
);
4305 /**********************************************************************
4306 * LoadMenuIndirectW (USER32.372)
4308 HMENU WINAPI
LoadMenuIndirectW( LPCVOID
template )
4310 /* FIXME: is there anything different between A and W? */
4311 return LoadMenuIndirectA( template );
4315 /**********************************************************************
4316 * IsMenu16 (USER.358)
4318 BOOL16 WINAPI
IsMenu16( HMENU16 hmenu
)
4320 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
4321 return IS_A_MENU(menu
);
4325 /**********************************************************************
4326 * IsMenu (USER32.346)
4328 BOOL WINAPI
IsMenu(HMENU hmenu
)
4330 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
4331 return IS_A_MENU(menu
);
4334 /**********************************************************************
4335 * GetMenuItemInfo_common
4338 static BOOL
GetMenuItemInfo_common ( HMENU hmenu
, UINT item
, BOOL bypos
,
4339 LPMENUITEMINFOA lpmii
, BOOL unicode
)
4341 MENUITEM
*menu
= MENU_FindItem (&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0);
4343 debug_print_menuitem("GetMenuItemInfo_common: ", menu
, "");
4348 if (lpmii
->fMask
& MIIM_TYPE
) {
4349 lpmii
->fType
= menu
->fType
;
4350 switch (MENU_ITEM_TYPE(menu
->fType
)) {
4353 int len
= lstrlenA(menu
->text
);
4354 if(lpmii
->dwTypeData
&& lpmii
->cch
) {
4356 lstrcpynAtoW((LPWSTR
) lpmii
->dwTypeData
, menu
->text
,
4359 lstrcpynA(lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4360 /* if we've copied a substring we return its length */
4361 if(lpmii
->cch
<= len
)
4363 } else /* return length of string */
4369 lpmii
->dwTypeData
= menu
->text
;
4376 if (lpmii
->fMask
& MIIM_STRING
) {
4377 if(lpmii
->dwTypeData
&& lpmii
->cch
) {
4379 lstrcpynAtoW((LPWSTR
) lpmii
->dwTypeData
, menu
->text
,
4382 lstrcpynA(lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4384 lpmii
->cch
= lstrlenA(menu
->text
);
4387 if (lpmii
->fMask
& MIIM_FTYPE
)
4388 lpmii
->fType
= menu
->fType
;
4390 if (lpmii
->fMask
& MIIM_BITMAP
)
4391 lpmii
->hbmpItem
= menu
->hbmpItem
;
4393 if (lpmii
->fMask
& MIIM_STATE
)
4394 lpmii
->fState
= menu
->fState
;
4396 if (lpmii
->fMask
& MIIM_ID
)
4397 lpmii
->wID
= menu
->wID
;
4399 if (lpmii
->fMask
& MIIM_SUBMENU
)
4400 lpmii
->hSubMenu
= menu
->hSubMenu
;
4402 if (lpmii
->fMask
& MIIM_CHECKMARKS
) {
4403 lpmii
->hbmpChecked
= menu
->hCheckBit
;
4404 lpmii
->hbmpUnchecked
= menu
->hUnCheckBit
;
4406 if (lpmii
->fMask
& MIIM_DATA
)
4407 lpmii
->dwItemData
= menu
->dwItemData
;
4412 /**********************************************************************
4413 * GetMenuItemInfoA (USER32.264)
4415 BOOL WINAPI
GetMenuItemInfoA( HMENU hmenu
, UINT item
, BOOL bypos
,
4416 LPMENUITEMINFOA lpmii
)
4418 return GetMenuItemInfo_common (hmenu
, item
, bypos
, lpmii
, FALSE
);
4421 /**********************************************************************
4422 * GetMenuItemInfoW (USER32.265)
4424 BOOL WINAPI
GetMenuItemInfoW( HMENU hmenu
, UINT item
, BOOL bypos
,
4425 LPMENUITEMINFOW lpmii
)
4427 return GetMenuItemInfo_common (hmenu
, item
, bypos
,
4428 (LPMENUITEMINFOA
)lpmii
, TRUE
);
4431 /**********************************************************************
4432 * SetMenuItemInfo_common
4435 static BOOL
SetMenuItemInfo_common(MENUITEM
* menu
,
4436 const MENUITEMINFOA
*lpmii
,
4439 if (!menu
) return FALSE
;
4441 if (lpmii
->fMask
& MIIM_TYPE
) {
4442 /* Get rid of old string. */
4443 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4444 HeapFree(SystemHeap
, 0, menu
->text
);
4448 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4449 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4450 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4452 menu
->text
= lpmii
->dwTypeData
;
4454 if (IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4456 menu
->text
= HEAP_strdupWtoA(SystemHeap
, 0, (LPWSTR
) lpmii
->dwTypeData
);
4458 menu
->text
= HEAP_strdupA(SystemHeap
, 0, lpmii
->dwTypeData
);
4462 if (lpmii
->fMask
& MIIM_FTYPE
) {
4463 /* free the string when the type is changing */
4464 if ( (!IS_STRING_ITEM(lpmii
->fType
)) && IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4465 HeapFree(SystemHeap
, 0, menu
->text
);
4468 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4469 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4472 if (lpmii
->fMask
& MIIM_STRING
) {
4473 /* free the string when used */
4474 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4475 HeapFree(SystemHeap
, 0, menu
->text
);
4477 menu
->text
= HEAP_strdupWtoA(SystemHeap
, 0, (LPWSTR
) lpmii
->dwTypeData
);
4479 menu
->text
= HEAP_strdupA(SystemHeap
, 0, lpmii
->dwTypeData
);
4483 if (lpmii
->fMask
& MIIM_STATE
)
4485 /* fixme: MFS_DEFAULT do we have to reset the other menu items? */
4486 menu
->fState
= lpmii
->fState
;
4489 if (lpmii
->fMask
& MIIM_ID
)
4490 menu
->wID
= lpmii
->wID
;
4492 if (lpmii
->fMask
& MIIM_SUBMENU
) {
4493 menu
->hSubMenu
= lpmii
->hSubMenu
;
4494 if (menu
->hSubMenu
) {
4495 POPUPMENU
*subMenu
= MENU_GetMenu((UINT16
)menu
->hSubMenu
);
4497 subMenu
->wFlags
|= MF_POPUP
;
4498 menu
->fType
|= MF_POPUP
;
4501 /* FIXME: Return an error ? */
4502 menu
->fType
&= ~MF_POPUP
;
4505 menu
->fType
&= ~MF_POPUP
;
4508 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
4510 if (lpmii
->fType
& MFT_RADIOCHECK
)
4511 menu
->fType
|= MFT_RADIOCHECK
;
4513 menu
->hCheckBit
= lpmii
->hbmpChecked
;
4514 menu
->hUnCheckBit
= lpmii
->hbmpUnchecked
;
4516 if (lpmii
->fMask
& MIIM_DATA
)
4517 menu
->dwItemData
= lpmii
->dwItemData
;
4519 debug_print_menuitem("SetMenuItemInfo_common: ", menu
, "");
4523 /**********************************************************************
4524 * SetMenuItemInfoA (USER32.491)
4526 BOOL WINAPI
SetMenuItemInfoA(HMENU hmenu
, UINT item
, BOOL bypos
,
4527 const MENUITEMINFOA
*lpmii
)
4529 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4533 /**********************************************************************
4534 * SetMenuItemInfoW (USER32.492)
4536 BOOL WINAPI
SetMenuItemInfoW(HMENU hmenu
, UINT item
, BOOL bypos
,
4537 const MENUITEMINFOW
*lpmii
)
4539 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4540 (const MENUITEMINFOA
*)lpmii
, TRUE
);
4543 /**********************************************************************
4544 * SetMenuDefaultItem (USER32.489)
4547 BOOL WINAPI
SetMenuDefaultItem(HMENU hmenu
, UINT uItem
, UINT bypos
)
4553 TRACE("(0x%x,%d,%d)\n", hmenu
, uItem
, bypos
);
4555 if (!(menu
= MENU_GetMenu(hmenu
))) return FALSE
;
4557 /* reset all default-item flags */
4559 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4561 item
->fState
&= ~MFS_DEFAULT
;
4564 /* no default item */
4573 if ( uItem
>= menu
->nItems
) return FALSE
;
4574 item
[uItem
].fState
|= MFS_DEFAULT
;
4579 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4581 if (item
->wID
== uItem
)
4583 item
->fState
|= MFS_DEFAULT
;
4592 /**********************************************************************
4593 * GetMenuDefaultItem (USER32.260)
4595 UINT WINAPI
GetMenuDefaultItem(HMENU hmenu
, UINT bypos
, UINT flags
)
4601 TRACE("(0x%x,%d,%d)\n", hmenu
, bypos
, flags
);
4603 if (!(menu
= MENU_GetMenu(hmenu
))) return -1;
4605 /* find default item */
4609 if (! item
) return -1;
4611 while ( !( item
->fState
& MFS_DEFAULT
) )
4614 if (i
>= menu
->nItems
) return -1;
4617 /* default: don't return disabled items */
4618 if ( (!(GMDI_USEDISABLED
& flags
)) && (item
->fState
& MFS_DISABLED
)) return -1;
4620 /* search rekursiv when needed */
4621 if ( (item
->fType
& MF_POPUP
) && (flags
& GMDI_GOINTOPOPUPS
) )
4624 ret
= GetMenuDefaultItem( item
->hSubMenu
, bypos
, flags
);
4625 if ( -1 != ret
) return ret
;
4627 /* when item not found in submenu, return the popup item */
4629 return ( bypos
) ? i
: item
->wID
;
4633 /*******************************************************************
4634 * InsertMenuItem16 (USER.441)
4638 BOOL16 WINAPI
InsertMenuItem16( HMENU16 hmenu
, UINT16 pos
, BOOL16 byposition
,
4639 const MENUITEMINFO16
*mii
)
4643 miia
.cbSize
= sizeof(miia
);
4644 miia
.fMask
= mii
->fMask
;
4645 miia
.dwTypeData
= mii
->dwTypeData
;
4646 miia
.fType
= mii
->fType
;
4647 miia
.fState
= mii
->fState
;
4648 miia
.wID
= mii
->wID
;
4649 miia
.hSubMenu
= mii
->hSubMenu
;
4650 miia
.hbmpChecked
= mii
->hbmpChecked
;
4651 miia
.hbmpUnchecked
= mii
->hbmpUnchecked
;
4652 miia
.dwItemData
= mii
->dwItemData
;
4653 miia
.cch
= mii
->cch
;
4654 if (IS_STRING_ITEM(miia
.fType
))
4655 miia
.dwTypeData
= PTR_SEG_TO_LIN(miia
.dwTypeData
);
4656 return InsertMenuItemA( hmenu
, pos
, byposition
, &miia
);
4660 /**********************************************************************
4661 * InsertMenuItemA (USER32.323)
4663 BOOL WINAPI
InsertMenuItemA(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4664 const MENUITEMINFOA
*lpmii
)
4666 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4667 return SetMenuItemInfo_common(item
, lpmii
, FALSE
);
4671 /**********************************************************************
4672 * InsertMenuItemW (USER32.324)
4674 BOOL WINAPI
InsertMenuItemW(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4675 const MENUITEMINFOW
*lpmii
)
4677 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4678 return SetMenuItemInfo_common(item
, (const MENUITEMINFOA
*)lpmii
, TRUE
);
4681 /**********************************************************************
4682 * CheckMenuRadioItem (USER32.47)
4685 BOOL WINAPI
CheckMenuRadioItem(HMENU hMenu
,
4686 UINT first
, UINT last
, UINT check
,
4689 MENUITEM
*mifirst
, *milast
, *micheck
;
4690 HMENU mfirst
= hMenu
, mlast
= hMenu
, mcheck
= hMenu
;
4692 TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4693 hMenu
, first
, last
, check
, bypos
);
4695 mifirst
= MENU_FindItem (&mfirst
, &first
, bypos
);
4696 milast
= MENU_FindItem (&mlast
, &last
, bypos
);
4697 micheck
= MENU_FindItem (&mcheck
, &check
, bypos
);
4699 if (mifirst
== NULL
|| milast
== NULL
|| micheck
== NULL
||
4700 mifirst
> milast
|| mfirst
!= mlast
|| mfirst
!= mcheck
||
4701 micheck
> milast
|| micheck
< mifirst
)
4704 while (mifirst
<= milast
)
4706 if (mifirst
== micheck
)
4708 mifirst
->fType
|= MFT_RADIOCHECK
;
4709 mifirst
->fState
|= MFS_CHECKED
;
4711 mifirst
->fType
&= ~MFT_RADIOCHECK
;
4712 mifirst
->fState
&= ~MFS_CHECKED
;
4720 /**********************************************************************
4721 * CheckMenuRadioItem16 (not a Windows API)
4724 BOOL16 WINAPI
CheckMenuRadioItem16(HMENU16 hMenu
,
4725 UINT16 first
, UINT16 last
, UINT16 check
,
4728 return CheckMenuRadioItem (hMenu
, first
, last
, check
, bypos
);
4731 /**********************************************************************
4732 * GetMenuItemRect (USER32.266)
4734 * ATTENTION: Here, the returned values in rect are the screen
4735 * coordinates of the item just like if the menu was
4736 * always on the upper left side of the application.
4739 BOOL WINAPI
GetMenuItemRect (HWND hwnd
, HMENU hMenu
, UINT uItem
,
4742 POPUPMENU
*itemMenu
;
4746 TRACE("(0x%x,0x%x,%d,%p)\n", hwnd
, hMenu
, uItem
, rect
);
4748 item
= MENU_FindItem (&hMenu
, &uItem
, MF_BYPOSITION
);
4749 referenceHwnd
= hwnd
;
4753 itemMenu
= MENU_GetMenu(hMenu
);
4754 if (itemMenu
== NULL
)
4757 if(itemMenu
->hWnd
== 0)
4759 referenceHwnd
= itemMenu
->hWnd
;
4762 if ((rect
== NULL
) || (item
== NULL
))
4767 MapWindowPoints(referenceHwnd
, 0, (LPPOINT
)rect
, 2);
4772 /**********************************************************************
4773 * GetMenuItemRect16 (USER.665)
4776 BOOL16 WINAPI
GetMenuItemRect16 (HWND16 hwnd
, HMENU16 hMenu
, UINT16 uItem
,
4782 if (!rect
) return FALSE
;
4783 res
= GetMenuItemRect (hwnd
, hMenu
, uItem
, &r32
);
4784 CONV_RECT32TO16 (&r32
, rect
);
4788 /**********************************************************************
4792 * MIM_APPLYTOSUBMENUS
4793 * actually use the items to draw the menu
4795 BOOL WINAPI
SetMenuInfo (HMENU hMenu
, LPCMENUINFO lpmi
)
4799 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4801 if (lpmi
&& (lpmi
->cbSize
==sizeof(MENUINFO
)) && (menu
= MENU_GetMenu(hMenu
)))
4804 if (lpmi
->fMask
& MIM_BACKGROUND
)
4805 menu
->hbrBack
= lpmi
->hbrBack
;
4807 if (lpmi
->fMask
& MIM_HELPID
)
4808 menu
->dwContextHelpID
= lpmi
->dwContextHelpID
;
4810 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4811 menu
->cyMax
= lpmi
->cyMax
;
4813 if (lpmi
->fMask
& MIM_MENUDATA
)
4814 menu
->dwMenuData
= lpmi
->dwMenuData
;
4816 if (lpmi
->fMask
& MIM_STYLE
)
4817 menu
->dwStyle
= lpmi
->dwStyle
;
4824 /**********************************************************************
4831 BOOL WINAPI
GetMenuInfo (HMENU hMenu
, LPMENUINFO lpmi
)
4834 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4836 if (lpmi
&& (menu
= MENU_GetMenu(hMenu
)))
4839 if (lpmi
->fMask
& MIM_BACKGROUND
)
4840 lpmi
->hbrBack
= menu
->hbrBack
;
4842 if (lpmi
->fMask
& MIM_HELPID
)
4843 lpmi
->dwContextHelpID
= menu
->dwContextHelpID
;
4845 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4846 lpmi
->cyMax
= menu
->cyMax
;
4848 if (lpmi
->fMask
& MIM_MENUDATA
)
4849 lpmi
->dwMenuData
= menu
->dwMenuData
;
4851 if (lpmi
->fMask
& MIM_STYLE
)
4852 lpmi
->dwStyle
= menu
->dwStyle
;
4859 /**********************************************************************
4860 * SetMenuContextHelpId16 (USER.384)
4862 BOOL16 WINAPI
SetMenuContextHelpId16( HMENU16 hMenu
, DWORD dwContextHelpID
)
4864 return SetMenuContextHelpId( hMenu
, dwContextHelpID
);
4868 /**********************************************************************
4869 * SetMenuContextHelpId (USER32.488)
4871 BOOL WINAPI
SetMenuContextHelpId( HMENU hMenu
, DWORD dwContextHelpID
)
4875 TRACE("(0x%04x 0x%08lx)\n", hMenu
, dwContextHelpID
);
4877 if ((menu
= MENU_GetMenu(hMenu
)))
4879 menu
->dwContextHelpID
= dwContextHelpID
;
4885 /**********************************************************************
4886 * GetMenuContextHelpId16 (USER.385)
4888 DWORD WINAPI
GetMenuContextHelpId16( HMENU16 hMenu
)
4890 return GetMenuContextHelpId( hMenu
);
4893 /**********************************************************************
4894 * GetMenuContextHelpId (USER32.488)
4896 DWORD WINAPI
GetMenuContextHelpId( HMENU hMenu
)
4900 TRACE("(0x%04x)\n", hMenu
);
4902 if ((menu
= MENU_GetMenu(hMenu
)))
4904 return menu
->dwContextHelpID
;
4909 /**********************************************************************
4910 * MenuItemFromPoint (USER32.387)
4912 UINT WINAPI
MenuItemFromPoint(HWND hWnd
, HMENU hMenu
, POINT ptScreen
)
4914 FIXME("(0x%04x,0x%04x,(%ld,%ld)):stub\n",
4915 hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);