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"
24 #include "wine/winestring.h"
29 #include "nonclient.h"
35 #include "debugtools.h"
37 DEFAULT_DEBUG_CHANNEL(menu
)
40 /* internal popup menu window messages */
42 #define MM_SETMENUHANDLE (WM_USER + 0)
43 #define MM_GETMENUHANDLE (WM_USER + 1)
45 /* Menu item structure */
47 /* ----------- MENUITEMINFO Stuff ----------- */
48 UINT fType
; /* Item type. */
49 UINT fState
; /* Item state. */
50 UINT wID
; /* Item id. */
51 HMENU hSubMenu
; /* Pop-up menu. */
52 HBITMAP hCheckBit
; /* Bitmap when checked. */
53 HBITMAP hUnCheckBit
; /* Bitmap when unchecked. */
54 LPSTR text
; /* Item text or bitmap handle. */
55 DWORD dwItemData
; /* Application defined. */
56 DWORD dwTypeData
; /* depends on fMask */
57 HBITMAP hbmpItem
; /* bitmap in win98 style menus */
58 /* ----------- Wine stuff ----------- */
59 RECT rect
; /* Item area (relative to menu window) */
60 UINT xTab
; /* X position of text after Tab */
63 /* Popup menu structure */
65 WORD wFlags
; /* Menu flags (MF_POPUP, MF_SYSMENU) */
66 WORD wMagic
; /* Magic number */
67 HQUEUE16 hTaskQ
; /* Task queue for this menu */
68 WORD Width
; /* Width of the whole menu */
69 WORD Height
; /* Height of the whole menu */
70 WORD nItems
; /* Number of items in the menu */
71 HWND hWnd
; /* Window containing the menu */
72 MENUITEM
*items
; /* Array of menu items */
73 UINT FocusedItem
; /* Currently focused item */
74 HWND hwndOwner
; /* window receiving the messages for ownerdraw */
75 BOOL bTimeToHide
; /* Request hiding when receiving a second click in the top-level menu item */
76 /* ------------ MENUINFO members ------ */
77 DWORD dwStyle
; /* Extended mennu style */
78 UINT cyMax
; /* max hight of the whole menu, 0 is screen hight */
79 HBRUSH hbrBack
; /* brush for menu background */
80 DWORD dwContextHelpID
;
81 DWORD dwMenuData
; /* application defined value */
82 HMENU hSysMenuOwner
; /* Handle to the dummy sys menu holder */
83 } POPUPMENU
, *LPPOPUPMENU
;
85 /* internal flags for menu tracking */
87 #define TF_ENDMENU 0x0001
88 #define TF_SUSPENDPOPUP 0x0002
89 #define TF_SKIPREMOVE 0x0004
94 HMENU hCurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
95 HMENU hTopMenu
; /* initial menu */
96 HWND hOwnerWnd
; /* where notifications are sent */
100 #define MENU_MAGIC 0x554d /* 'MU' */
101 #define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
106 /* Internal MENU_TrackMenu() flags */
107 #define TPM_INTERNAL 0xF0000000
108 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
109 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
110 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
112 /* popup menu shade thickness */
113 #define POPUP_XSHADE 4
114 #define POPUP_YSHADE 4
116 /* Space between 2 menu bar items */
117 #define MENU_BAR_ITEMS_SPACE 12
119 /* Minimum width of a tab character */
120 #define MENU_TAB_SPACE 8
122 /* Height of a separator item */
123 #define SEPARATOR_HEIGHT 5
125 /* (other menu->FocusedItem values give the position of the focused item) */
126 #define NO_SELECTED_ITEM 0xffff
128 #define MENU_ITEM_TYPE(flags) \
129 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
131 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
132 #define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
134 #define IS_SYSTEM_MENU(menu) \
135 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
137 #define IS_SYSTEM_POPUP(menu) \
138 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
140 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
141 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
142 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
143 MF_POPUP | MF_SYSMENU | MF_HELP)
144 #define STATE_MASK (~TYPE_MASK)
146 /* Dimension of the menu bitmaps */
147 static WORD check_bitmap_width
= 0, check_bitmap_height
= 0;
148 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
150 static HBITMAP hStdRadioCheck
= 0;
151 static HBITMAP hStdCheck
= 0;
152 static HBITMAP hStdMnArrow
= 0;
154 /* Minimze/restore/close buttons to be inserted in menubar */
155 static HBITMAP hBmpMinimize
= 0;
156 static HBITMAP hBmpMinimizeD
= 0;
157 static HBITMAP hBmpMaximize
= 0;
158 static HBITMAP hBmpMaximizeD
= 0;
159 static HBITMAP hBmpClose
= 0;
160 static HBITMAP hBmpCloseD
= 0;
163 static HBRUSH hShadeBrush
= 0;
164 static HFONT hMenuFont
= 0;
165 static HFONT hMenuFontBold
= 0;
167 static HMENU MENU_DefSysPopup
= 0; /* Default system menu popup */
169 /* Use global popup window because there's no way 2 menus can
170 * be tracked at the same time. */
172 static WND
* pTopPopupWnd
= 0;
173 static UINT uSubPWndLevel
= 0;
175 /* Flag set by EndMenu() to force an exit from menu tracking */
176 static BOOL fEndMenu
= FALSE
;
179 /***********************************************************************
180 * debug_print_menuitem
182 * Print a menuitem in readable form.
185 #define debug_print_menuitem(pre, mp, post) \
186 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
188 #define MENUOUT(text) \
189 DPRINTF("%s%s", (count++ ? "," : ""), (text))
191 #define MENUFLAG(bit,text) \
193 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
196 static void do_debug_print_menuitem(const char *prefix
, MENUITEM
* mp
,
199 TRACE("%s ", prefix
);
201 UINT flags
= mp
->fType
;
202 int typ
= MENU_ITEM_TYPE(flags
);
203 DPRINTF( "{ ID=0x%x", mp
->wID
);
204 if (flags
& MF_POPUP
)
205 DPRINTF( ", Sub=0x%x", mp
->hSubMenu
);
209 if (typ
== MFT_STRING
)
211 else if (typ
== MFT_SEPARATOR
)
213 else if (typ
== MFT_OWNERDRAW
)
215 else if (typ
== MFT_BITMAP
)
221 MENUFLAG(MF_POPUP
, "pop");
222 MENUFLAG(MFT_MENUBARBREAK
, "barbrk");
223 MENUFLAG(MFT_MENUBREAK
, "brk");
224 MENUFLAG(MFT_RADIOCHECK
, "radio");
225 MENUFLAG(MFT_RIGHTORDER
, "rorder");
226 MENUFLAG(MF_SYSMENU
, "sys");
227 MENUFLAG(MFT_RIGHTJUSTIFY
, "right"); /* same as MF_HELP */
230 DPRINTF( "+0x%x", flags
);
235 DPRINTF( ", State=");
236 MENUFLAG(MFS_GRAYED
, "grey");
237 MENUFLAG(MFS_DEFAULT
, "default");
238 MENUFLAG(MFS_DISABLED
, "dis");
239 MENUFLAG(MFS_CHECKED
, "check");
240 MENUFLAG(MFS_HILITE
, "hi");
241 MENUFLAG(MF_USECHECKBITMAPS
, "usebit");
242 MENUFLAG(MF_MOUSESELECT
, "mouse");
244 DPRINTF( "+0x%x", flags
);
247 DPRINTF( ", Chk=0x%x", mp
->hCheckBit
);
249 DPRINTF( ", Unc=0x%x", mp
->hUnCheckBit
);
251 if (typ
== MFT_STRING
) {
253 DPRINTF( ", Text=\"%s\"", mp
->text
);
255 DPRINTF( ", Text=Null");
256 } else if (mp
->text
== NULL
)
259 DPRINTF( ", Text=%p", mp
->text
);
261 DPRINTF( ", ItemData=0x%08lx", mp
->dwItemData
);
267 DPRINTF(" %s\n", postfix
);
274 /***********************************************************************
277 * Validate the given menu handle and returns the menu structure pointer.
279 POPUPMENU
*MENU_GetMenu(HMENU hMenu
)
282 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
283 if (!IS_A_MENU(menu
))
285 WARN("invalid menu handle=%x, ptr=%p, magic=%x\n", hMenu
, menu
, menu
? menu
->wMagic
:0);
291 /***********************************************************************
294 * Return the default system menu.
296 static HMENU
MENU_CopySysPopup(void)
298 HMENU hMenu
= LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
301 POPUPMENU
* menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
302 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
303 SetMenuDefaultItem(hMenu
, SC_CLOSE
, FALSE
);
307 ERR("Unable to load default system menu\n" );
310 TRACE("returning %x.\n", hMenu
);
315 /***********************************************************************
316 * MENU_GetTopPopupWnd()
318 * Return the locked pointer pTopPopupWnd.
320 static WND
*MENU_GetTopPopupWnd()
322 return WIN_LockWndPtr(pTopPopupWnd
);
324 /***********************************************************************
325 * MENU_ReleaseTopPopupWnd()
327 * Realease the locked pointer pTopPopupWnd.
329 static void MENU_ReleaseTopPopupWnd()
331 WIN_ReleaseWndPtr(pTopPopupWnd
);
333 /***********************************************************************
334 * MENU_DestroyTopPopupWnd()
336 * Destroy the locked pointer pTopPopupWnd.
338 static void MENU_DestroyTopPopupWnd()
340 WND
*tmpWnd
= pTopPopupWnd
;
342 WIN_ReleaseWndPtr(tmpWnd
);
347 /**********************************************************************
350 * Create a copy of the system menu. System menu in Windows is
351 * a special menu-bar with the single entry - system menu popup.
352 * This popup is presented to the outside world as a "system menu".
353 * However, the real system menu handle is sometimes seen in the
354 * WM_MENUSELECT paramemters (and Word 6 likes it this way).
356 HMENU
MENU_GetSysMenu( HWND hWnd
, HMENU hPopupMenu
)
360 if ((hMenu
= CreateMenu()))
362 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
363 menu
->wFlags
= MF_SYSMENU
;
366 if (hPopupMenu
== (HMENU
)(-1))
367 hPopupMenu
= MENU_CopySysPopup();
368 else if( !hPopupMenu
) hPopupMenu
= MENU_DefSysPopup
;
372 InsertMenuA( hMenu
, -1, MF_SYSMENU
| MF_POPUP
| MF_BYPOSITION
, hPopupMenu
, NULL
);
374 menu
->items
[0].fType
= MF_SYSMENU
| MF_POPUP
;
375 menu
->items
[0].fState
= 0;
376 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hPopupMenu
);
377 menu
->wFlags
|= MF_SYSMENU
;
379 TRACE("GetSysMenu hMenu=%04x (%04x)\n", hMenu
, hPopupMenu
);
382 DestroyMenu( hMenu
);
384 ERR("failed to load system menu!\n");
389 /***********************************************************************
392 * Menus initialisation.
397 NONCLIENTMETRICSA ncm
;
399 static unsigned char shade_bits
[16] = { 0x55, 0, 0xAA, 0,
404 /* Load menu bitmaps */
405 hStdCheck
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CHECK
));
406 hStdRadioCheck
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_RADIOCHECK
));
407 hStdMnArrow
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW
));
408 /* Load system buttons bitmaps */
409 hBmpMinimize
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCE
));
410 hBmpMinimizeD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCED
));
411 hBmpMaximize
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORE
));
412 hBmpMaximizeD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORED
));
413 hBmpClose
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSE
));
414 hBmpCloseD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSED
));
419 GetObjectA( hStdCheck
, sizeof(bm
), &bm
);
420 check_bitmap_width
= bm
.bmWidth
;
421 check_bitmap_height
= bm
.bmHeight
;
425 /* Assume that radio checks have the same size as regular check. */
432 GetObjectA( hStdMnArrow
, sizeof(bm
), &bm
);
433 arrow_bitmap_width
= bm
.bmWidth
;
434 arrow_bitmap_height
= bm
.bmHeight
;
438 if (! (hBitmap
= CreateBitmap( 8, 8, 1, 1, shade_bits
)))
441 if(!(hShadeBrush
= CreatePatternBrush( hBitmap
)))
444 DeleteObject( hBitmap
);
445 if (!(MENU_DefSysPopup
= MENU_CopySysPopup()))
448 ncm
.cbSize
= sizeof (NONCLIENTMETRICSA
);
449 if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS
, sizeof(NONCLIENTMETRICSA
), &ncm
, 0)))
452 if (!(hMenuFont
= CreateFontIndirectA( &ncm
.lfMenuFont
)))
455 ncm
.lfMenuFont
.lfWeight
+= 300;
456 if ( ncm
.lfMenuFont
.lfWeight
> 1000)
457 ncm
.lfMenuFont
.lfWeight
= 1000;
459 if (!(hMenuFontBold
= CreateFontIndirectA( &ncm
.lfMenuFont
)))
465 /***********************************************************************
466 * MENU_InitSysMenuPopup
468 * Grey the appropriate items in System menu.
470 static void MENU_InitSysMenuPopup( HMENU hmenu
, DWORD style
, DWORD clsStyle
)
474 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
475 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
476 gray
= ((style
& WS_MAXIMIZE
) != 0);
477 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
478 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
479 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
480 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
481 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
482 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
483 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
484 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
486 /* The menu item must keep its state if it's disabled */
488 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
492 /******************************************************************************
494 * UINT MENU_GetStartOfNextColumn(
497 *****************************************************************************/
499 static UINT
MENU_GetStartOfNextColumn(
502 POPUPMENU
*menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
503 UINT i
= menu
->FocusedItem
+ 1;
506 return NO_SELECTED_ITEM
;
508 if( i
== NO_SELECTED_ITEM
)
511 for( ; i
< menu
->nItems
; ++i
) {
512 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
516 return NO_SELECTED_ITEM
;
520 /******************************************************************************
522 * UINT MENU_GetStartOfPrevColumn(
525 *****************************************************************************/
527 static UINT
MENU_GetStartOfPrevColumn(
530 POPUPMENU
const *menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
534 return NO_SELECTED_ITEM
;
536 if( menu
->FocusedItem
== 0 || menu
->FocusedItem
== NO_SELECTED_ITEM
)
537 return NO_SELECTED_ITEM
;
539 /* Find the start of the column */
541 for(i
= menu
->FocusedItem
; i
!= 0 &&
542 !(menu
->items
[i
].fType
& MF_MENUBARBREAK
);
546 return NO_SELECTED_ITEM
;
548 for(--i
; i
!= 0; --i
) {
549 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
553 TRACE("ret %d.\n", i
);
560 /***********************************************************************
563 * Find a menu item. Return a pointer on the item, and modifies *hmenu
564 * in case the item was in a sub-menu.
566 static MENUITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
571 if (((*hmenu
)==0xffff) || (!(menu
= MENU_GetMenu(*hmenu
)))) return NULL
;
572 if (wFlags
& MF_BYPOSITION
)
574 if (*nPos
>= menu
->nItems
) return NULL
;
575 return &menu
->items
[*nPos
];
579 MENUITEM
*item
= menu
->items
;
580 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
582 if (item
->wID
== *nPos
)
587 else if (item
->fType
& MF_POPUP
)
589 HMENU hsubmenu
= item
->hSubMenu
;
590 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
602 /***********************************************************************
605 * Find a Sub menu. Return the position of the submenu, and modifies
606 * *hmenu in case it is found in another sub-menu.
607 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
609 UINT
MENU_FindSubMenu( HMENU
*hmenu
, HMENU hSubTarget
)
614 if (((*hmenu
)==0xffff) ||
615 (!(menu
= MENU_GetMenu(*hmenu
))))
616 return NO_SELECTED_ITEM
;
618 for (i
= 0; i
< menu
->nItems
; i
++, item
++) {
619 if(!(item
->fType
& MF_POPUP
)) continue;
620 if (item
->hSubMenu
== hSubTarget
) {
624 HMENU hsubmenu
= item
->hSubMenu
;
625 UINT pos
= MENU_FindSubMenu( &hsubmenu
, hSubTarget
);
626 if (pos
!= NO_SELECTED_ITEM
) {
632 return NO_SELECTED_ITEM
;
635 /***********************************************************************
638 static void MENU_FreeItemData( MENUITEM
* item
)
641 if (IS_STRING_ITEM(item
->fType
) && item
->text
)
642 HeapFree( SystemHeap
, 0, item
->text
);
645 /***********************************************************************
646 * MENU_FindItemByCoords
648 * Find the item at the specified coordinates (screen coords). Does
649 * not work for child windows and therefore should not be called for
650 * an arbitrary system menu.
652 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
,
653 POINT pt
, UINT
*pos
)
659 if (!GetWindowRect(menu
->hWnd
,&wrect
)) return NULL
;
660 pt
.x
-= wrect
.left
;pt
.y
-= wrect
.top
;
662 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
664 if ((pt
.x
>= item
->rect
.left
) && (pt
.x
< item
->rect
.right
) &&
665 (pt
.y
>= item
->rect
.top
) && (pt
.y
< item
->rect
.bottom
))
675 /***********************************************************************
678 * Find the menu item selected by a key press.
679 * Return item id, -1 if none, -2 if we should close the menu.
681 static UINT
MENU_FindItemByKey( HWND hwndOwner
, HMENU hmenu
,
682 UINT key
, BOOL forceMenuChar
)
684 TRACE("\tlooking for '%c' in [%04x]\n", (char)key
, (UINT16
)hmenu
);
686 if (!IsMenu( hmenu
))
688 WND
* w
= WIN_FindWndPtr(hwndOwner
);
689 hmenu
= GetSubMenu(w
->hSysMenu
, 0);
690 WIN_ReleaseWndPtr(w
);
695 POPUPMENU
*menu
= MENU_GetMenu( hmenu
);
696 MENUITEM
*item
= menu
->items
;
704 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
706 if (item
->text
&& (IS_STRING_ITEM(item
->fType
)))
708 char *p
= item
->text
- 2;
711 p
= strchr (p
+ 2, '&');
713 while (p
!= NULL
&& p
[1] == '&');
714 if (p
&& (toupper(p
[1]) == key
)) return i
;
718 menuchar
= SendMessageA( hwndOwner
, WM_MENUCHAR
,
719 MAKEWPARAM( key
, menu
->wFlags
), hmenu
);
720 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
721 if (HIWORD(menuchar
) == 1) return (UINT
)(-2);
725 /***********************************************************************
728 * Load the bitmap associated with the magic menu item and its style
731 static HBITMAP
MENU_LoadMagicItem(UINT id
, BOOL hilite
, DWORD dwItemData
)
734 * Magic menu item id's section
735 * These magic id's are used by windows to insert "standard" mdi
736 * buttons (minimize,restore,close) on menu. Under windows,
737 * these magic id's make sure the right things appear when those
738 * bitmap buttons are pressed/selected/released.
742 { case HBMMENU_SYSTEM
:
743 return (dwItemData
) ?
744 (HBITMAP
)dwItemData
:
745 (hilite
? hBmpMinimizeD
: hBmpMinimize
);
746 case HBMMENU_MBAR_RESTORE
:
747 return (hilite
? hBmpMaximizeD
: hBmpMaximize
);
748 case HBMMENU_MBAR_MINIMIZE
:
749 return (hilite
? hBmpMinimizeD
: hBmpMinimize
);
750 case HBMMENU_MBAR_CLOSE
:
751 return (hilite
? hBmpCloseD
: hBmpClose
);
752 case HBMMENU_CALLBACK
:
753 case HBMMENU_MBAR_CLOSE_D
:
754 case HBMMENU_MBAR_MINIMIZE_D
:
755 case HBMMENU_POPUP_CLOSE
:
756 case HBMMENU_POPUP_RESTORE
:
757 case HBMMENU_POPUP_MAXIMIZE
:
758 case HBMMENU_POPUP_MINIMIZE
:
760 FIXME("Magic 0x%08x not implemented\n", id
);
766 /***********************************************************************
769 * Calculate the size of the menu item and store it in lpitem->rect.
771 static void MENU_CalcItemSize( HDC hdc
, MENUITEM
*lpitem
, HWND hwndOwner
,
772 INT orgX
, INT orgY
, BOOL menuBar
)
776 TRACE("dc=0x%04x owner=0x%04x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
777 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem
,
778 (menuBar
? " (MenuBar)" : ""));
780 SetRect( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
782 if (lpitem
->fType
& MF_OWNERDRAW
)
785 ** Experimentation under Windows reveals that an owner-drawn
786 ** menu is expected to return the size of the content part of
787 ** the menu item, not including the checkmark nor the submenu
788 ** arrow. Windows adds those values itself and returns the
789 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
791 MEASUREITEMSTRUCT mis
;
792 mis
.CtlType
= ODT_MENU
;
794 mis
.itemID
= lpitem
->wID
;
795 mis
.itemData
= (DWORD
)lpitem
->dwItemData
;
798 SendMessageA( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
799 lpitem
->rect
.right
+= mis
.itemWidth
;
803 lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
806 /* under at least win95 you seem to be given a standard
807 height for the menu and the height value is ignored */
809 if (TWEAK_WineLook
== WIN31_LOOK
)
810 lpitem
->rect
.bottom
+= GetSystemMetrics(SM_CYMENU
);
812 lpitem
->rect
.bottom
+= GetSystemMetrics(SM_CYMENU
)-1;
815 lpitem
->rect
.bottom
+= mis
.itemHeight
;
817 TRACE("id=%04x size=%dx%d\n",
818 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
819 /* Fall through to get check/arrow width calculation. */
822 if (lpitem
->fType
& MF_SEPARATOR
)
824 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
830 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
831 if (lpitem
->fType
& MF_POPUP
)
832 lpitem
->rect
.right
+= arrow_bitmap_width
;
835 if (lpitem
->fType
& MF_OWNERDRAW
)
838 if (IS_BITMAP_ITEM(lpitem
->fType
))
843 /* Check if there is a magic menu item associated with this item */
844 if((LOWORD((int)lpitem
->text
))<12)
846 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
, (lpitem
->fType
& MF_HILITE
),
850 resBmp
= (HBITMAP
)lpitem
->text
;
852 if (GetObjectA(resBmp
, sizeof(bm
), &bm
))
854 lpitem
->rect
.right
+= bm
.bmWidth
;
855 lpitem
->rect
.bottom
+= bm
.bmHeight
;
861 /* If we get here, then it must be a text item */
862 if (IS_STRING_ITEM( lpitem
->fType
))
865 GetTextExtentPoint32A(hdc
, lpitem
->text
, strlen(lpitem
->text
), &size
);
867 lpitem
->rect
.right
+= size
.cx
;
868 if (TWEAK_WineLook
== WIN31_LOOK
)
869 lpitem
->rect
.bottom
+= max( size
.cy
, GetSystemMetrics(SM_CYMENU
) );
871 lpitem
->rect
.bottom
+= max(size
.cy
, GetSystemMetrics(SM_CYMENU
)-1);
876 lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
878 else if ((p
= strchr( lpitem
->text
, '\t' )) != NULL
)
880 /* Item contains a tab (only meaningful in popup menus) */
881 GetTextExtentPoint32A(hdc
, lpitem
->text
, (int)(p
- lpitem
->text
) , &size
);
882 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+ size
.cx
;
883 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
887 if (strchr( lpitem
->text
, '\b' ))
888 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
889 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
890 - arrow_bitmap_width
;
893 TRACE("(%d,%d)-(%d,%d)\n", lpitem
->rect
.left
, lpitem
->rect
.top
, lpitem
->rect
.right
, lpitem
->rect
.bottom
);
897 /***********************************************************************
898 * MENU_PopupMenuCalcSize
900 * Calculate the size of a popup menu.
902 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND hwndOwner
)
907 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
909 lppop
->Width
= lppop
->Height
= 0;
910 if (lppop
->nItems
== 0) return;
913 SelectObject( hdc
, hMenuFont
);
916 maxX
= (TWEAK_WineLook
== WIN31_LOOK
) ? GetSystemMetrics(SM_CXBORDER
) : 2 ;
918 while (start
< lppop
->nItems
)
920 lpitem
= &lppop
->items
[start
];
922 orgY
= (TWEAK_WineLook
== WIN31_LOOK
) ? GetSystemMetrics(SM_CYBORDER
) : 2;
924 maxTab
= maxTabWidth
= 0;
926 /* Parse items until column break or end of menu */
927 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
930 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
932 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
934 if (lpitem
->fType
& MF_MENUBARBREAK
) orgX
++;
935 maxX
= max( maxX
, lpitem
->rect
.right
);
936 orgY
= lpitem
->rect
.bottom
;
937 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
939 maxTab
= max( maxTab
, lpitem
->xTab
);
940 maxTabWidth
= max(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
944 /* Finish the column (set all items to the largest width found) */
945 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
946 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
948 lpitem
->rect
.right
= maxX
;
949 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
950 lpitem
->xTab
= maxTab
;
953 lppop
->Height
= max( lppop
->Height
, orgY
);
958 /* space for 3d border */
959 if(TWEAK_WineLook
> WIN31_LOOK
)
969 /***********************************************************************
970 * MENU_MenuBarCalcSize
972 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
973 * height is off by 1 pixel which causes lengthy window relocations when
974 * active document window is maximized/restored.
976 * Calculate the size of the menu bar.
978 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
,
979 LPPOPUPMENU lppop
, HWND hwndOwner
)
982 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
984 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
985 if (lppop
->nItems
== 0) return;
986 TRACE("left=%d top=%d right=%d bottom=%d\n",
987 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
988 lppop
->Width
= lprect
->right
- lprect
->left
;
993 while (start
< lppop
->nItems
)
995 lpitem
= &lppop
->items
[start
];
999 /* Parse items until line break or end of menu */
1000 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
1002 if ((helpPos
== -1) && (lpitem
->fType
& MF_HELP
)) helpPos
= i
;
1004 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1006 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
1008 debug_print_menuitem (" item: ", lpitem
, "");
1009 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
1011 if (lpitem
->rect
.right
> lprect
->right
)
1013 if (i
!= start
) break;
1014 else lpitem
->rect
.right
= lprect
->right
;
1016 maxY
= max( maxY
, lpitem
->rect
.bottom
);
1017 orgX
= lpitem
->rect
.right
;
1020 /* Finish the line (set all items to the largest height found) */
1021 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
1024 lprect
->bottom
= maxY
;
1025 lppop
->Height
= lprect
->bottom
- lprect
->top
;
1027 /* Flush right all magic items and items between the MF_HELP and */
1028 /* the last item (if several lines, only move the last line) */
1029 lpitem
= &lppop
->items
[lppop
->nItems
-1];
1030 orgY
= lpitem
->rect
.top
;
1031 orgX
= lprect
->right
;
1032 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--)
1034 if ( !IS_BITMAP_ITEM(lpitem
->fType
) && ((helpPos
==-1) ? TRUE
: (helpPos
>i
) ))
1036 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
1037 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
1038 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
1039 lpitem
->rect
.right
= orgX
;
1040 orgX
= lpitem
->rect
.left
;
1044 /***********************************************************************
1047 * Draw a single menu item.
1049 static void MENU_DrawMenuItem( HWND hwnd
, HMENU hmenu
, HWND hwndOwner
, HDC hdc
, MENUITEM
*lpitem
,
1050 UINT height
, BOOL menuBar
, UINT odaction
)
1054 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem
, "");
1056 if (lpitem
->fType
& MF_SYSMENU
)
1058 if( !IsIconic(hwnd
) ) {
1059 if (TWEAK_WineLook
> WIN31_LOOK
)
1060 NC_DrawSysButton95( hwnd
, hdc
,
1062 (MF_HILITE
| MF_MOUSESELECT
) );
1064 NC_DrawSysButton( hwnd
, hdc
,
1066 (MF_HILITE
| MF_MOUSESELECT
) );
1072 if (lpitem
->fType
& MF_OWNERDRAW
)
1075 ** Experimentation under Windows reveals that an owner-drawn
1076 ** menu is given the rectangle which includes the space it requested
1077 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1078 ** and a popup-menu arrow. This is the value of lpitem->rect.
1079 ** Windows will leave all drawing to the application except for
1080 ** the popup-menu arrow. Windows always draws that itself, after
1081 ** the menu owner has finished drawing.
1085 dis
.CtlType
= ODT_MENU
;
1087 dis
.itemID
= lpitem
->wID
;
1088 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1090 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1091 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
;
1092 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1093 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1094 dis
.hwndItem
= hmenu
;
1096 dis
.rcItem
= lpitem
->rect
;
1097 TRACE("Ownerdraw: owner=%04x itemID=%d, itemState=%d, itemAction=%d, "
1098 "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n", hwndOwner
,
1099 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1100 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1102 SendMessageA( hwndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
1103 /* Fall through to draw popup-menu arrow */
1106 TRACE("rect={%d,%d,%d,%d}\n", lpitem
->rect
.left
, lpitem
->rect
.top
,
1107 lpitem
->rect
.right
,lpitem
->rect
.bottom
);
1109 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1111 rect
= lpitem
->rect
;
1113 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1115 if ((lpitem
->fState
& MF_HILITE
) && !(IS_BITMAP_ITEM(lpitem
->fType
)))
1116 if ((menuBar
) && (TWEAK_WineLook
==WIN98_LOOK
))
1117 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1119 FillRect( hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
) );
1121 FillRect( hdc
, &rect
, GetSysColorBrush(COLOR_MENU
) );
1124 SetBkMode( hdc
, TRANSPARENT
);
1126 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1128 /* vertical separator */
1129 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1131 if (TWEAK_WineLook
> WIN31_LOOK
)
1135 rc
.bottom
= height
- 3;
1136 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1140 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1141 MoveToEx( hdc
, rect
.left
, 0, NULL
);
1142 LineTo( hdc
, rect
.left
, height
);
1146 /* horizontal separator */
1147 if (lpitem
->fType
& MF_SEPARATOR
)
1149 if (TWEAK_WineLook
> WIN31_LOOK
)
1154 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1155 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1159 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1160 MoveToEx( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2, NULL
);
1161 LineTo( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
1169 if ((lpitem
->fState
& MF_HILITE
) && !(IS_BITMAP_ITEM(lpitem
->fType
)) )
1171 if (lpitem
->fState
& MF_GRAYED
)
1172 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1174 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
1175 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
1179 if (lpitem
->fState
& MF_GRAYED
)
1180 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1182 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1183 SetBkColor( hdc
, GetSysColor( COLOR_MENU
) );
1186 /* helper lines for debugging */
1187 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1188 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1189 MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
1190 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1195 INT y
= rect
.top
+ rect
.bottom
;
1197 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1199 /* Draw the check mark
1202 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1205 if (lpitem
->fState
& MF_CHECKED
)
1207 HBITMAP bm
= lpitem
->hCheckBit
? lpitem
->hCheckBit
:
1208 ((lpitem
->fType
& MFT_RADIOCHECK
) ? hStdRadioCheck
: hStdCheck
);
1209 HDC hdcMem
= CreateCompatibleDC( hdc
);
1211 SelectObject( hdcMem
, bm
);
1212 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1213 check_bitmap_width
, check_bitmap_height
,
1214 hdcMem
, 0, 0, SRCCOPY
);
1217 else if (lpitem
->hUnCheckBit
)
1219 HDC hdcMem
= CreateCompatibleDC( hdc
);
1221 SelectObject( hdcMem
, lpitem
->hUnCheckBit
);
1222 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1223 check_bitmap_width
, check_bitmap_height
,
1224 hdcMem
, 0, 0, SRCCOPY
);
1229 /* Draw the popup-menu arrow */
1230 if (lpitem
->fType
& MF_POPUP
)
1232 HDC hdcMem
= CreateCompatibleDC( hdc
);
1233 HBITMAP hOrigBitmap
;
1235 hOrigBitmap
= SelectObject( hdcMem
, hStdMnArrow
);
1236 BitBlt( hdc
, rect
.right
- arrow_bitmap_width
- 1,
1237 (y
- arrow_bitmap_height
) / 2,
1238 arrow_bitmap_width
, arrow_bitmap_height
,
1239 hdcMem
, 0, 0, SRCCOPY
);
1240 SelectObject( hdcMem
, hOrigBitmap
);
1244 rect
.left
+= check_bitmap_width
;
1245 rect
.right
-= arrow_bitmap_width
;
1248 /* Done for owner-drawn */
1249 if (lpitem
->fType
& MF_OWNERDRAW
)
1252 /* Draw the item text or bitmap */
1253 if (IS_BITMAP_ITEM(lpitem
->fType
))
1258 HDC hdcMem
= CreateCompatibleDC( hdc
);
1261 * Check if there is a magic menu item associated with this item
1262 * and load the appropriate bitmap
1264 if((LOWORD((int)lpitem
->text
)) < 12)
1266 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
, (lpitem
->fState
& MF_HILITE
),
1267 lpitem
->dwItemData
);
1270 resBmp
= (HBITMAP
)lpitem
->text
;
1275 GetObjectA( resBmp
, sizeof(bm
), &bm
);
1277 SelectObject(hdcMem
,resBmp
);
1279 /* handle fontsize > bitmap_height */
1280 top
= ((rect
.bottom
-rect
.top
)>bm
.bmHeight
) ?
1281 rect
.top
+(rect
.bottom
-rect
.top
-bm
.bmHeight
)/2 : rect
.top
;
1283 BitBlt( hdc
, rect
.left
, top
, rect
.right
- rect
.left
,
1284 rect
.bottom
- rect
.top
, hdcMem
, 0, 0, SRCCOPY
);
1291 /* No bitmap - process text if present */
1292 else if (IS_STRING_ITEM(lpitem
->fType
))
1297 UINT uFormat
= (menuBar
) ?
1298 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
1299 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1301 if ( lpitem
->fState
& MFS_DEFAULT
)
1303 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
1308 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1309 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1310 i
= strlen( lpitem
->text
);
1314 for (i
= 0; lpitem
->text
[i
]; i
++)
1315 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
1319 if( !(TWEAK_WineLook
== WIN31_LOOK
) && (lpitem
->fState
& MF_GRAYED
))
1321 if (!(lpitem
->fState
& MF_HILITE
) )
1323 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1324 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1325 DrawTextA( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1326 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1328 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1331 DrawTextA( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1333 /* paint the shortcut text */
1334 if (lpitem
->text
[i
]) /* There's a tab or flush-right char */
1336 if (lpitem
->text
[i
] == '\t')
1338 rect
.left
= lpitem
->xTab
;
1339 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1343 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1346 if( !(TWEAK_WineLook
== WIN31_LOOK
) && (lpitem
->fState
& MF_GRAYED
))
1348 if (!(lpitem
->fState
& MF_HILITE
) )
1350 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1351 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1352 DrawTextA( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1353 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1355 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1357 DrawTextA( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1361 SelectObject (hdc
, hfontOld
);
1366 /***********************************************************************
1367 * MENU_DrawPopupMenu
1369 * Paint a popup menu.
1371 static void MENU_DrawPopupMenu( HWND hwnd
, HDC hdc
, HMENU hmenu
)
1373 HBRUSH hPrevBrush
= 0;
1376 TRACE("wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd
, hdc
, hmenu
);
1378 GetClientRect( hwnd
, &rect
);
1380 if(TWEAK_WineLook
== WIN31_LOOK
)
1382 rect
.bottom
-= POPUP_YSHADE
* GetSystemMetrics(SM_CYBORDER
);
1383 rect
.right
-= POPUP_XSHADE
* GetSystemMetrics(SM_CXBORDER
);
1386 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1387 && (SelectObject( hdc
, hMenuFont
)))
1391 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1393 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1399 /* draw 3-d shade */
1400 if(TWEAK_WineLook
== WIN31_LOOK
) {
1401 SelectObject( hdc
, hShadeBrush
);
1402 SetBkMode( hdc
, TRANSPARENT
);
1403 ropPrev
= SetROP2( hdc
, R2_MASKPEN
);
1405 i
= rect
.right
; /* why SetBrushOrg() doesn't? */
1406 PatBlt( hdc
, i
& 0xfffffffe,
1407 rect
.top
+ POPUP_YSHADE
*GetSystemMetrics(SM_CYBORDER
),
1408 i
%2 + POPUP_XSHADE
*GetSystemMetrics(SM_CXBORDER
),
1409 rect
.bottom
- rect
.top
, 0x00a000c9 );
1411 PatBlt( hdc
, rect
.left
+ POPUP_XSHADE
*GetSystemMetrics(SM_CXBORDER
),
1412 i
& 0xfffffffe,rect
.right
- rect
.left
,
1413 i
%2 + POPUP_YSHADE
*GetSystemMetrics(SM_CYBORDER
), 0x00a000c9 );
1414 SelectObject( hdc
, hPrevPen
);
1415 SelectObject( hdc
, hPrevBrush
);
1416 SetROP2( hdc
, ropPrev
);
1419 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1421 /* draw menu items */
1423 menu
= MENU_GetMenu( hmenu
);
1424 if (menu
&& menu
->nItems
)
1429 for (u
= menu
->nItems
, item
= menu
->items
; u
> 0; u
--, item
++)
1430 MENU_DrawMenuItem( hwnd
, hmenu
, menu
->hwndOwner
, hdc
, item
,
1431 menu
->Height
, FALSE
, ODA_DRAWENTIRE
);
1436 SelectObject( hdc
, hPrevBrush
);
1441 /***********************************************************************
1444 * Paint a menu bar. Returns the height of the menu bar.
1445 * called from [windows/nonclient.c]
1447 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1454 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1456 lppop
= MENU_GetMenu ((HMENU
)wndPtr
->wIDmenu
);
1457 if (lppop
== NULL
|| lprect
== NULL
)
1459 retvalue
= GetSystemMetrics(SM_CYMENU
);
1463 TRACE("(%04x, %p, %p)\n", hDC
, lprect
, lppop
);
1465 hfontOld
= SelectObject( hDC
, hMenuFont
);
1467 if (lppop
->Height
== 0)
1468 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
1470 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
1474 retvalue
= lppop
->Height
;
1478 FillRect(hDC
, lprect
, GetSysColorBrush(COLOR_MENU
) );
1480 if (TWEAK_WineLook
== WIN31_LOOK
)
1482 SelectObject( hDC
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1483 MoveToEx( hDC
, lprect
->left
, lprect
->bottom
, NULL
);
1484 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1488 SelectObject( hDC
, GetSysColorPen(COLOR_3DFACE
));
1489 MoveToEx( hDC
, lprect
->left
, lprect
->bottom
, NULL
);
1490 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1493 if (lppop
->nItems
== 0)
1495 retvalue
= GetSystemMetrics(SM_CYMENU
);
1499 for (i
= 0; i
< lppop
->nItems
; i
++)
1501 MENU_DrawMenuItem( hwnd
, (HMENU
)wndPtr
->wIDmenu
, hwnd
,
1502 hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
, ODA_DRAWENTIRE
);
1504 retvalue
= lppop
->Height
;
1508 SelectObject (hDC
, hfontOld
);
1510 WIN_ReleaseWndPtr(wndPtr
);
1514 /***********************************************************************
1515 * MENU_PatchResidentPopup
1517 BOOL
MENU_PatchResidentPopup( HQUEUE16 checkQueue
, WND
* checkWnd
)
1519 WND
*pTPWnd
= MENU_GetTopPopupWnd();
1525 TRACE("patching resident popup: %04x %04x [%04x %04x]\n",
1526 checkQueue
, checkWnd
? checkWnd
->hwndSelf
: 0, pTPWnd
->hmemTaskQ
,
1527 pTPWnd
->owner
? pTPWnd
->owner
->hwndSelf
: 0);
1529 switch( checkQueue
)
1531 case 0: /* checkWnd is the new popup owner */
1534 pTPWnd
->owner
= checkWnd
;
1535 if( pTPWnd
->hmemTaskQ
!= checkWnd
->hmemTaskQ
)
1536 hTask
= QUEUE_GetQueueTask( checkWnd
->hmemTaskQ
);
1540 case 0xFFFF: /* checkWnd is destroyed */
1541 if( pTPWnd
->owner
== checkWnd
)
1542 pTPWnd
->owner
= NULL
;
1543 MENU_ReleaseTopPopupWnd();
1546 default: /* checkQueue is exiting */
1547 if( pTPWnd
->hmemTaskQ
== checkQueue
)
1549 hTask
= QUEUE_GetQueueTask( pTPWnd
->hmemTaskQ
);
1550 hTask
= TASK_GetNextTask( hTask
);
1557 TDB
* task
= (TDB
*)GlobalLock16( hTask
);
1560 pTPWnd
->hInstance
= task
->hInstance
;
1561 pTPWnd
->hmemTaskQ
= task
->hQueue
;
1562 MENU_ReleaseTopPopupWnd();
1565 else WARN("failed to patch resident popup.\n");
1568 MENU_ReleaseTopPopupWnd();
1572 /***********************************************************************
1575 * Display a popup menu.
1577 static BOOL
MENU_ShowPopup( HWND hwndOwner
, HMENU hmenu
, UINT id
,
1578 INT x
, INT y
, INT xanchor
, INT yanchor
)
1581 WND
*wndOwner
= NULL
;
1583 TRACE("owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1584 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1586 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
1587 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1589 menu
->items
[menu
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1590 menu
->FocusedItem
= NO_SELECTED_ITEM
;
1593 /* store the owner for DrawItem*/
1594 menu
->hwndOwner
= hwndOwner
;
1596 if( (wndOwner
= WIN_FindWndPtr( hwndOwner
)) )
1600 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
1602 /* adjust popup menu pos so that it fits within the desktop */
1604 width
= menu
->Width
+ GetSystemMetrics(SM_CXBORDER
);
1605 height
= menu
->Height
+ GetSystemMetrics(SM_CYBORDER
);
1607 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1610 x
-= width
- xanchor
;
1611 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1612 x
= GetSystemMetrics(SM_CXSCREEN
) - width
;
1616 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1619 y
-= height
+ yanchor
;
1620 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1621 y
= GetSystemMetrics(SM_CYSCREEN
) - height
;
1625 if( TWEAK_WineLook
== WIN31_LOOK
)
1627 width
+= POPUP_XSHADE
* GetSystemMetrics(SM_CXBORDER
); /* add space for shading */
1628 height
+= POPUP_YSHADE
* GetSystemMetrics(SM_CYBORDER
);
1631 /* NOTE: In Windows, top menu popup is not owned. */
1632 if (!pTopPopupWnd
) /* create top level popup menu window */
1634 assert( uSubPWndLevel
== 0 );
1636 pTopPopupWnd
= WIN_FindWndPtr(CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1637 WS_POPUP
, x
, y
, width
, height
,
1638 hwndOwner
, 0, wndOwner
->hInstance
,
1642 WIN_ReleaseWndPtr(wndOwner
);
1645 menu
->hWnd
= pTopPopupWnd
->hwndSelf
;
1646 MENU_ReleaseTopPopupWnd();
1651 /* create a new window for the submenu */
1653 menu
->hWnd
= CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1654 WS_POPUP
, x
, y
, width
, height
,
1655 hwndOwner
, 0, wndOwner
->hInstance
,
1659 WIN_ReleaseWndPtr(wndOwner
);
1663 else /* top level popup menu window already exists */
1665 WND
*pTPWnd
= MENU_GetTopPopupWnd();
1666 menu
->hWnd
= pTPWnd
->hwndSelf
;
1668 MENU_PatchResidentPopup( 0, wndOwner
);
1669 SendMessageA( pTPWnd
->hwndSelf
, MM_SETMENUHANDLE
, (WPARAM16
)hmenu
, 0L);
1671 /* adjust its size */
1673 SetWindowPos( menu
->hWnd
, 0, x
, y
, width
, height
,
1674 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_NOREDRAW
);
1675 MENU_ReleaseTopPopupWnd();
1678 uSubPWndLevel
++; /* menu level counter */
1680 /* Display the window */
1682 SetWindowPos( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
1683 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1684 UpdateWindow( menu
->hWnd
);
1685 WIN_ReleaseWndPtr(wndOwner
);
1692 /***********************************************************************
1695 static void MENU_SelectItem( HWND hwndOwner
, HMENU hmenu
, UINT wIndex
,
1696 BOOL sendMenuSelect
, HMENU topmenu
)
1701 TRACE("owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1703 lppop
= MENU_GetMenu( hmenu
);
1704 if ((!lppop
) || (!lppop
->nItems
)) return;
1706 if (lppop
->FocusedItem
== wIndex
) return;
1707 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC( lppop
->hWnd
);
1708 else hdc
= GetDCEx( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1710 SelectObject( hdc
, hMenuFont
);
1712 /* Clear previous highlighted item */
1713 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1715 lppop
->items
[lppop
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1716 MENU_DrawMenuItem(lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,&lppop
->items
[lppop
->FocusedItem
],
1717 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
),
1721 /* Highlight new item (if any) */
1722 lppop
->FocusedItem
= wIndex
;
1723 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1725 if(!(lppop
->items
[wIndex
].fType
& MF_SEPARATOR
)) {
1726 lppop
->items
[wIndex
].fState
|= MF_HILITE
;
1727 MENU_DrawMenuItem( lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,
1728 &lppop
->items
[wIndex
], lppop
->Height
,
1729 !(lppop
->wFlags
& MF_POPUP
), ODA_SELECT
);
1733 MENUITEM
*ip
= &lppop
->items
[lppop
->FocusedItem
];
1734 SendMessageA( hwndOwner
, WM_MENUSELECT
,
1735 MAKELONG(ip
->fType
& MF_POPUP
? wIndex
: ip
->wID
,
1736 ip
->fType
| ip
->fState
| MF_MOUSESELECT
|
1737 (lppop
->wFlags
& MF_SYSMENU
)), hmenu
);
1740 else if (sendMenuSelect
) {
1743 if((pos
=MENU_FindSubMenu(&topmenu
, hmenu
))!=NO_SELECTED_ITEM
){
1744 POPUPMENU
*ptm
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( topmenu
);
1745 MENUITEM
*ip
= &ptm
->items
[pos
];
1746 SendMessageA( hwndOwner
, WM_MENUSELECT
, MAKELONG(pos
,
1747 ip
->fType
| ip
->fState
| MF_MOUSESELECT
|
1748 (ptm
->wFlags
& MF_SYSMENU
)), topmenu
);
1752 ReleaseDC( lppop
->hWnd
, hdc
);
1756 /***********************************************************************
1757 * MENU_MoveSelection
1759 * Moves currently selected item according to the offset parameter.
1760 * If there is no selection then it should select the last item if
1761 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1763 static void MENU_MoveSelection( HWND hwndOwner
, HMENU hmenu
, INT offset
)
1768 TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner
, hmenu
, offset
);
1770 menu
= MENU_GetMenu( hmenu
);
1771 if ((!menu
) || (!menu
->items
)) return;
1773 if ( menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1775 if( menu
->nItems
== 1 ) return; else
1776 for (i
= menu
->FocusedItem
+ offset
; i
>= 0 && i
< menu
->nItems
1778 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1780 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
1785 for ( i
= (offset
> 0) ? 0 : menu
->nItems
- 1;
1786 i
>= 0 && i
< menu
->nItems
; i
+= offset
)
1787 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1789 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
1795 /**********************************************************************
1798 * Set an item flags, id and text ptr. Called by InsertMenu() and
1801 static BOOL
MENU_SetItemData( MENUITEM
*item
, UINT flags
, UINT id
,
1804 LPSTR prevText
= IS_STRING_ITEM(item
->fType
) ? item
->text
: NULL
;
1806 debug_print_menuitem("MENU_SetItemData from: ", item
, "");
1808 if (IS_STRING_ITEM(flags
))
1812 flags
|= MF_SEPARATOR
;
1818 /* Item beginning with a backspace is a help item */
1824 if (!(text
= HEAP_strdupA( SystemHeap
, 0, str
))) return FALSE
;
1828 else if (IS_BITMAP_ITEM(flags
))
1829 item
->text
= (LPSTR
)(HBITMAP
)LOWORD(str
);
1830 else item
->text
= NULL
;
1832 if (flags
& MF_OWNERDRAW
)
1833 item
->dwItemData
= (DWORD
)str
;
1835 item
->dwItemData
= 0;
1837 if ((item
->fType
& MF_POPUP
) && (flags
& MF_POPUP
) && (item
->hSubMenu
!= id
) )
1838 DestroyMenu( item
->hSubMenu
); /* ModifyMenu() spec */
1840 if (flags
& MF_POPUP
)
1842 POPUPMENU
*menu
= MENU_GetMenu((UINT16
)id
);
1843 if (menu
) menu
->wFlags
|= MF_POPUP
;
1855 if (flags
& MF_POPUP
)
1856 item
->hSubMenu
= id
;
1858 if ((item
->fType
& MF_POPUP
) && !(flags
& MF_POPUP
) )
1859 flags
|= MF_POPUP
; /* keep popup */
1861 item
->fType
= flags
& TYPE_MASK
;
1862 item
->fState
= (flags
& STATE_MASK
) &
1863 ~(MF_HILITE
| MF_MOUSESELECT
| MF_BYPOSITION
);
1866 /* Don't call SetRectEmpty here! */
1869 if (prevText
) HeapFree( SystemHeap
, 0, prevText
);
1871 debug_print_menuitem("MENU_SetItemData to : ", item
, "");
1876 /**********************************************************************
1879 * Insert a new item into a menu.
1881 static MENUITEM
*MENU_InsertItem( HMENU hMenu
, UINT pos
, UINT flags
)
1886 if (!(menu
= MENU_GetMenu(hMenu
)))
1889 /* Find where to insert new item */
1891 if (flags
& MF_BYPOSITION
) {
1892 if (pos
> menu
->nItems
)
1895 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
1898 if (!(menu
= MENU_GetMenu( hMenu
)))
1903 /* Create new items array */
1905 newItems
= HeapAlloc( SystemHeap
, 0, sizeof(MENUITEM
) * (menu
->nItems
+1) );
1908 WARN("allocation failed\n" );
1911 if (menu
->nItems
> 0)
1913 /* Copy the old array into the new */
1914 if (pos
> 0) memcpy( newItems
, menu
->items
, pos
* sizeof(MENUITEM
) );
1915 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &menu
->items
[pos
],
1916 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
1917 HeapFree( SystemHeap
, 0, menu
->items
);
1919 menu
->items
= newItems
;
1921 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
1922 menu
->Height
= 0; /* force size recalculate */
1923 return &newItems
[pos
];
1927 /**********************************************************************
1928 * MENU_ParseResource
1930 * Parse a standard menu resource and add items to the menu.
1931 * Return a pointer to the end of the resource.
1933 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1940 flags
= GET_WORD(res
);
1941 res
+= sizeof(WORD
);
1942 if (!(flags
& MF_POPUP
))
1945 res
+= sizeof(WORD
);
1947 if (!IS_STRING_ITEM(flags
))
1948 ERR("not a string item %04x\n", flags
);
1950 if (!unicode
) res
+= strlen(str
) + 1;
1951 else res
+= (lstrlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1952 if (flags
& MF_POPUP
)
1954 HMENU hSubMenu
= CreatePopupMenu();
1955 if (!hSubMenu
) return NULL
;
1956 if (!(res
= MENU_ParseResource( res
, hSubMenu
, unicode
)))
1958 if (!unicode
) AppendMenuA( hMenu
, flags
, (UINT
)hSubMenu
, str
);
1959 else AppendMenuW( hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1961 else /* Not a popup */
1963 if (!unicode
) AppendMenuA( hMenu
, flags
, id
, *str
? str
: NULL
);
1964 else AppendMenuW( hMenu
, flags
, id
,
1965 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1967 } while (!(flags
& MF_END
));
1972 /**********************************************************************
1973 * MENUEX_ParseResource
1975 * Parse an extended menu resource and add items to the menu.
1976 * Return a pointer to the end of the resource.
1978 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
1984 mii
.cbSize
= sizeof(mii
);
1985 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
1986 mii
.fType
= GET_DWORD(res
);
1987 res
+= sizeof(DWORD
);
1988 mii
.fState
= GET_DWORD(res
);
1989 res
+= sizeof(DWORD
);
1990 mii
.wID
= GET_DWORD(res
);
1991 res
+= sizeof(DWORD
);
1992 resinfo
= GET_WORD(res
); /* FIXME: for 16-bit apps this is a byte. */
1993 res
+= sizeof(WORD
);
1994 /* Align the text on a word boundary. */
1995 res
+= (~((int)res
- 1)) & 1;
1996 mii
.dwTypeData
= (LPWSTR
) res
;
1997 res
+= (1 + lstrlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
1998 /* Align the following fields on a dword boundary. */
1999 res
+= (~((int)res
- 1)) & 3;
2001 /* FIXME: This is inefficient and cannot be optimised away by gcc. */
2003 LPSTR newstr
= HEAP_strdupWtoA(GetProcessHeap(),
2005 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
2006 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, newstr
);
2007 HeapFree( GetProcessHeap(), 0, newstr
);
2010 if (resinfo
& 1) { /* Pop-up? */
2011 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2012 res
+= sizeof(DWORD
);
2013 mii
.hSubMenu
= CreatePopupMenu();
2016 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
2017 DestroyMenu(mii
.hSubMenu
);
2020 mii
.fMask
|= MIIM_SUBMENU
;
2021 mii
.fType
|= MF_POPUP
;
2023 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
2024 } while (!(resinfo
& MF_END
));
2029 /***********************************************************************
2032 * Return the handle of the selected sub-popup menu (if any).
2034 static HMENU
MENU_GetSubPopup( HMENU hmenu
)
2039 menu
= MENU_GetMenu( hmenu
);
2041 if ((!menu
) || (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return 0;
2043 item
= &menu
->items
[menu
->FocusedItem
];
2044 if ((item
->fType
& MF_POPUP
) && (item
->fState
& MF_MOUSESELECT
))
2045 return item
->hSubMenu
;
2050 /***********************************************************************
2051 * MENU_HideSubPopups
2053 * Hide the sub-popup menus of this menu.
2055 static void MENU_HideSubPopups( HWND hwndOwner
, HMENU hmenu
,
2056 BOOL sendMenuSelect
)
2058 POPUPMENU
*menu
= MENU_GetMenu( hmenu
);
2060 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner
, hmenu
, sendMenuSelect
);
2062 if (menu
&& uSubPWndLevel
)
2068 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
2070 item
= &menu
->items
[menu
->FocusedItem
];
2071 if (!(item
->fType
& MF_POPUP
) ||
2072 !(item
->fState
& MF_MOUSESELECT
)) return;
2073 item
->fState
&= ~MF_MOUSESELECT
;
2074 hsubmenu
= item
->hSubMenu
;
2077 submenu
= MENU_GetMenu( hsubmenu
);
2078 MENU_HideSubPopups( hwndOwner
, hsubmenu
, FALSE
);
2079 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, sendMenuSelect
, 0 );
2081 if (submenu
->hWnd
== MENU_GetTopPopupWnd()->hwndSelf
)
2083 ShowWindow( submenu
->hWnd
, SW_HIDE
);
2088 DestroyWindow( submenu
->hWnd
);
2091 MENU_ReleaseTopPopupWnd();
2096 /***********************************************************************
2099 * Display the sub-menu of the selected item of this menu.
2100 * Return the handle of the submenu, or hmenu if no submenu to display.
2102 static HMENU
MENU_ShowSubPopup( HWND hwndOwner
, HMENU hmenu
,
2103 BOOL selectFirst
, UINT wFlags
)
2111 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner
, hmenu
, selectFirst
);
2113 if (!(menu
= MENU_GetMenu( hmenu
))) return hmenu
;
2115 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
)) ||
2116 (menu
->FocusedItem
== NO_SELECTED_ITEM
))
2118 WIN_ReleaseWndPtr(wndPtr
);
2122 item
= &menu
->items
[menu
->FocusedItem
];
2123 if (!(item
->fType
& MF_POPUP
) ||
2124 (item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
2126 WIN_ReleaseWndPtr(wndPtr
);
2130 /* message must be send before using item,
2131 because nearly everything may by changed by the application ! */
2133 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2134 if (!(wFlags
& TPM_NONOTIFY
))
2135 SendMessageA( hwndOwner
, WM_INITMENUPOPUP
, item
->hSubMenu
,
2136 MAKELONG( menu
->FocusedItem
, IS_SYSTEM_MENU(menu
) ));
2138 item
= &menu
->items
[menu
->FocusedItem
];
2141 /* correct item if modified as a reaction to WM_INITMENUPOPUP-message */
2142 if (!(item
->fState
& MF_HILITE
))
2144 if (menu
->wFlags
& MF_POPUP
) hdc
= GetDC( menu
->hWnd
);
2145 else hdc
= GetDCEx( menu
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2147 SelectObject( hdc
, hMenuFont
);
2149 item
->fState
|= MF_HILITE
;
2150 MENU_DrawMenuItem( menu
->hWnd
, hmenu
, hwndOwner
, hdc
, item
, menu
->Height
, !(menu
->wFlags
& MF_POPUP
), ODA_DRAWENTIRE
);
2151 ReleaseDC( menu
->hWnd
, hdc
);
2153 if (!item
->rect
.top
&& !item
->rect
.left
&& !item
->rect
.bottom
&& !item
->rect
.right
)
2156 item
->fState
|= MF_MOUSESELECT
;
2158 if (IS_SYSTEM_MENU(menu
))
2160 MENU_InitSysMenuPopup(item
->hSubMenu
, wndPtr
->dwStyle
, GetClassLongA(wndPtr
->hwndSelf
, GCL_STYLE
));
2162 NC_GetSysPopupPos( wndPtr
, &rect
);
2163 rect
.top
= rect
.bottom
;
2164 rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2165 rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2169 if (menu
->wFlags
& MF_POPUP
)
2171 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2172 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.top
;
2173 rect
.right
= item
->rect
.left
- item
->rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2174 rect
.bottom
= item
->rect
.top
- item
->rect
.bottom
;
2178 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.left
;
2179 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.bottom
;
2180 rect
.right
= item
->rect
.right
- item
->rect
.left
;
2181 rect
.bottom
= item
->rect
.bottom
- item
->rect
.top
;
2185 MENU_ShowPopup( hwndOwner
, item
->hSubMenu
, menu
->FocusedItem
,
2186 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2188 MENU_MoveSelection( hwndOwner
, item
->hSubMenu
, ITEM_NEXT
);
2189 WIN_ReleaseWndPtr(wndPtr
);
2190 return item
->hSubMenu
;
2195 /**********************************************************************
2198 BOOL
MENU_IsMenuActive(void)
2200 return pTopPopupWnd
&& (pTopPopupWnd
->dwStyle
& WS_VISIBLE
);
2203 /***********************************************************************
2206 * Walks menu chain trying to find a menu pt maps to.
2208 static HMENU
MENU_PtMenu( HMENU hMenu
, POINT pt
)
2210 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2211 register UINT ht
= menu
->FocusedItem
;
2213 /* try subpopup first (if any) */
2214 ht
= (ht
!= NO_SELECTED_ITEM
&&
2215 (menu
->items
[ht
].fType
& MF_POPUP
) &&
2216 (menu
->items
[ht
].fState
& MF_MOUSESELECT
))
2217 ? (UINT
) MENU_PtMenu(menu
->items
[ht
].hSubMenu
, pt
) : 0;
2219 if( !ht
) /* check the current window (avoiding WM_HITTEST) */
2221 ht
= (UINT
)NC_HandleNCHitTest( menu
->hWnd
, pt
);
2222 if( menu
->wFlags
& MF_POPUP
)
2223 ht
= (ht
!= (UINT
)HTNOWHERE
&&
2224 ht
!= (UINT
)HTERROR
) ? (UINT
)hMenu
: 0;
2227 WND
* wndPtr
= WIN_FindWndPtr(menu
->hWnd
);
2229 ht
= ( ht
== HTSYSMENU
) ? (UINT
)(wndPtr
->hSysMenu
)
2230 : ( ht
== HTMENU
) ? (UINT
)(wndPtr
->wIDmenu
) : 0;
2231 WIN_ReleaseWndPtr(wndPtr
);
2237 /***********************************************************************
2238 * MENU_ExecFocusedItem
2240 * Execute a menu item (for instance when user pressed Enter).
2241 * Return the wID of the executed item. Otherwise, -1 indicating
2242 * that no menu item was executed;
2243 * Have to receive the flags for the TrackPopupMenu options to avoid
2244 * sending unwanted message.
2247 static INT
MENU_ExecFocusedItem( MTRACKER
* pmt
, HMENU hMenu
, UINT wFlags
)
2250 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2252 TRACE("%p hmenu=0x%04x\n", pmt
, hMenu
);
2254 if (!menu
|| !menu
->nItems
||
2255 (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return -1;
2257 item
= &menu
->items
[menu
->FocusedItem
];
2259 TRACE("%08x %08x %08x\n",
2260 hMenu
, item
->wID
, item
->hSubMenu
);
2262 if (!(item
->fType
& MF_POPUP
))
2264 if (!(item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
2266 /* If TPM_RETURNCMD is set you return the id, but
2267 do not send a message to the owner */
2268 if(!(wFlags
& TPM_RETURNCMD
))
2270 if( menu
->wFlags
& MF_SYSMENU
)
2271 PostMessageA( pmt
->hOwnerWnd
, WM_SYSCOMMAND
, item
->wID
,
2272 MAKELPARAM((INT16
)pmt
->pt
.x
, (INT16
)pmt
->pt
.y
) );
2274 PostMessageA( pmt
->hOwnerWnd
, WM_COMMAND
, item
->wID
, 0 );
2280 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hMenu
, TRUE
, wFlags
);
2285 /***********************************************************************
2286 * MENU_SwitchTracking
2288 * Helper function for menu navigation routines.
2290 static void MENU_SwitchTracking( MTRACKER
* pmt
, HMENU hPtMenu
, UINT id
)
2292 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2293 POPUPMENU
*topmenu
= MENU_GetMenu( pmt
->hTopMenu
);
2295 TRACE("%p hmenu=0x%04x 0x%04x\n", pmt
, hPtMenu
, id
);
2297 if( pmt
->hTopMenu
!= hPtMenu
&&
2298 !((ptmenu
->wFlags
| topmenu
->wFlags
) & MF_POPUP
) )
2300 /* both are top level menus (system and menu-bar) */
2301 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2302 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
2303 pmt
->hTopMenu
= hPtMenu
;
2305 else MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
2306 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, id
, TRUE
, 0 );
2310 /***********************************************************************
2313 * Return TRUE if we can go on with menu tracking.
2315 static BOOL
MENU_ButtonDown( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2317 TRACE("%p hmenu=0x%04x\n", pmt
, hPtMenu
);
2322 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2325 if( IS_SYSTEM_MENU(ptmenu
) )
2326 item
= ptmenu
->items
;
2328 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2332 if( ptmenu
->FocusedItem
!= id
)
2333 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2335 /* If the popup menu is not already "popped" */
2336 if(!(item
->fState
& MF_MOUSESELECT
))
2338 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2340 /* In win31, a newly popped menu always remain opened for the next buttonup */
2341 if(TWEAK_WineLook
== WIN31_LOOK
)
2342 ptmenu
->bTimeToHide
= FALSE
;
2347 /* Else the click was on the menu bar, finish the tracking */
2352 /***********************************************************************
2355 * Return the value of MENU_ExecFocusedItem if
2356 * the selected item was not a popup. Else open the popup.
2357 * A -1 return value indicates that we go on with menu tracking.
2360 static INT
MENU_ButtonUp( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2362 TRACE("%p hmenu=0x%04x\n", pmt
, hPtMenu
);
2367 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2370 if( IS_SYSTEM_MENU(ptmenu
) )
2371 item
= ptmenu
->items
;
2373 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2375 if( item
&& (ptmenu
->FocusedItem
== id
))
2377 if( !(item
->fType
& MF_POPUP
) )
2378 return MENU_ExecFocusedItem( pmt
, hPtMenu
, wFlags
);
2380 /* If we are dealing with the top-level menu and that this */
2381 /* is a click on an already "poppped" item */
2382 /* Stop the menu tracking and close the opened submenus */
2383 if((pmt
->hTopMenu
== hPtMenu
) && (ptmenu
->bTimeToHide
== TRUE
))
2386 ptmenu
->bTimeToHide
= TRUE
;
2392 /***********************************************************************
2395 * Return TRUE if we can go on with menu tracking.
2397 static BOOL
MENU_MouseMove( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2399 UINT id
= NO_SELECTED_ITEM
;
2400 POPUPMENU
*ptmenu
= NULL
;
2404 ptmenu
= MENU_GetMenu( hPtMenu
);
2405 if( IS_SYSTEM_MENU(ptmenu
) )
2408 MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2411 if( id
== NO_SELECTED_ITEM
)
2413 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2414 NO_SELECTED_ITEM
, TRUE
, pmt
->hTopMenu
);
2417 else if( ptmenu
->FocusedItem
!= id
)
2419 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2420 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2426 /***********************************************************************
2429 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2431 static LRESULT
MENU_DoNextMenu( MTRACKER
* pmt
, UINT vk
)
2433 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2435 if( (vk
== VK_LEFT
&& menu
->FocusedItem
== 0 ) ||
2436 (vk
== VK_RIGHT
&& menu
->FocusedItem
== menu
->nItems
- 1))
2442 LRESULT l
= SendMessageA( pmt
->hOwnerWnd
, WM_NEXTMENU
, vk
,
2443 (IS_SYSTEM_MENU(menu
)) ? GetSubMenu16(pmt
->hTopMenu
,0) : pmt
->hTopMenu
);
2445 TRACE("%04x [%04x] -> %04x [%04x]\n",
2446 (UINT16
)pmt
->hCurrentMenu
, (UINT16
)pmt
->hOwnerWnd
, LOWORD(l
), HIWORD(l
) );
2450 wndPtr
= WIN_FindWndPtr(pmt
->hOwnerWnd
);
2452 hNewWnd
= pmt
->hOwnerWnd
;
2453 if( IS_SYSTEM_MENU(menu
) )
2455 /* switch to the menu bar */
2457 if( wndPtr
->dwStyle
& WS_CHILD
|| !wndPtr
->wIDmenu
)
2459 WIN_ReleaseWndPtr(wndPtr
);
2463 hNewMenu
= wndPtr
->wIDmenu
;
2466 menu
= MENU_GetMenu( hNewMenu
);
2467 id
= menu
->nItems
- 1;
2470 else if( wndPtr
->dwStyle
& WS_SYSMENU
)
2472 /* switch to the system menu */
2473 hNewMenu
= wndPtr
->hSysMenu
;
2477 WIN_ReleaseWndPtr(wndPtr
);
2480 WIN_ReleaseWndPtr(wndPtr
);
2482 else /* application returned a new menu to switch to */
2484 hNewMenu
= LOWORD(l
); hNewWnd
= HIWORD(l
);
2486 if( IsMenu(hNewMenu
) && IsWindow(hNewWnd
) )
2488 wndPtr
= WIN_FindWndPtr(hNewWnd
);
2490 if( wndPtr
->dwStyle
& WS_SYSMENU
&&
2491 GetSubMenu16(wndPtr
->hSysMenu
, 0) == hNewMenu
)
2493 /* get the real system menu */
2494 hNewMenu
= wndPtr
->hSysMenu
;
2496 else if( wndPtr
->dwStyle
& WS_CHILD
|| wndPtr
->wIDmenu
!= hNewMenu
)
2498 /* FIXME: Not sure what to do here, perhaps,
2499 * try to track hNewMenu as a popup? */
2501 TRACE(" -- got confused.\n");
2502 WIN_ReleaseWndPtr(wndPtr
);
2505 WIN_ReleaseWndPtr(wndPtr
);
2510 if( hNewMenu
!= pmt
->hTopMenu
)
2512 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
,
2514 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2515 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2518 if( hNewWnd
!= pmt
->hOwnerWnd
)
2521 pmt
->hOwnerWnd
= hNewWnd
;
2522 EVENT_Capture( pmt
->hOwnerWnd
, HTMENU
);
2525 pmt
->hTopMenu
= pmt
->hCurrentMenu
= hNewMenu
; /* all subpopups are hidden */
2526 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, id
, TRUE
, 0 );
2533 /***********************************************************************
2536 * The idea is not to show the popup if the next input message is
2537 * going to hide it anyway.
2539 static BOOL
MENU_SuspendPopup( MTRACKER
* pmt
, UINT16 uMsg
)
2543 msg
.hwnd
= pmt
->hOwnerWnd
;
2545 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2546 pmt
->trackFlags
|= TF_SKIPREMOVE
;
2551 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2552 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
2554 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2555 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2556 if( msg
.message
== WM_KEYDOWN
&&
2557 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
2559 pmt
->trackFlags
|= TF_SUSPENDPOPUP
;
2566 /* failures go through this */
2567 pmt
->trackFlags
&= ~TF_SUSPENDPOPUP
;
2571 /***********************************************************************
2574 * Handle a VK_LEFT key event in a menu.
2576 static void MENU_KeyLeft( MTRACKER
* pmt
, UINT wFlags
)
2579 HMENU hmenutmp
, hmenuprev
;
2582 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
2583 menu
= MENU_GetMenu( hmenutmp
);
2585 /* Try to move 1 column left (if possible) */
2586 if( (prevcol
= MENU_GetStartOfPrevColumn( pmt
->hCurrentMenu
)) !=
2587 NO_SELECTED_ITEM
) {
2589 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2594 /* close topmost popup */
2595 while (hmenutmp
!= pmt
->hCurrentMenu
)
2597 hmenuprev
= hmenutmp
;
2598 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
2601 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
);
2602 pmt
->hCurrentMenu
= hmenuprev
;
2604 if ( (hmenuprev
== pmt
->hTopMenu
) && !(menu
->wFlags
& MF_POPUP
) )
2606 /* move menu bar selection if no more popups are left */
2608 if( !MENU_DoNextMenu( pmt
, VK_LEFT
) )
2609 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_PREV
);
2611 if ( hmenuprev
!= hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2613 /* A sublevel menu was displayed - display the next one
2614 * unless there is another displacement coming up */
2616 if( !MENU_SuspendPopup( pmt
, WM_KEYDOWN
) )
2617 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2618 pmt
->hTopMenu
, TRUE
, wFlags
);
2624 /***********************************************************************
2627 * Handle a VK_RIGHT key event in a menu.
2629 static void MENU_KeyRight( MTRACKER
* pmt
, UINT wFlags
)
2632 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2635 TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2637 (MENU_GetMenu(pmt
->hCurrentMenu
))->
2639 pmt
->hTopMenu
, menu
->items
[0].text
);
2641 if ( (menu
->wFlags
& MF_POPUP
) || (pmt
->hCurrentMenu
!= pmt
->hTopMenu
))
2643 /* If already displaying a popup, try to display sub-popup */
2645 hmenutmp
= pmt
->hCurrentMenu
;
2646 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hmenutmp
, TRUE
, wFlags
);
2648 /* if subpopup was displayed then we are done */
2649 if (hmenutmp
!= pmt
->hCurrentMenu
) return;
2652 /* Check to see if there's another column */
2653 if( (nextcol
= MENU_GetStartOfNextColumn( pmt
->hCurrentMenu
)) !=
2654 NO_SELECTED_ITEM
) {
2655 TRACE("Going to %d.\n", nextcol
);
2656 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2661 if (!(menu
->wFlags
& MF_POPUP
)) /* menu bar tracking */
2663 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2665 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2666 hmenutmp
= pmt
->hCurrentMenu
= pmt
->hTopMenu
;
2667 } else hmenutmp
= 0;
2669 /* try to move to the next item */
2670 if( !MENU_DoNextMenu( pmt
, VK_RIGHT
) )
2671 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_NEXT
);
2673 if( hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2674 if( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
2675 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2676 pmt
->hTopMenu
, TRUE
, wFlags
);
2680 /***********************************************************************
2683 * Menu tracking code.
2685 static INT
MENU_TrackMenu( HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
2686 HWND hwnd
, const RECT
*lprect
)
2691 INT executedMenuId
= -1;
2693 BOOL enterIdleSent
= FALSE
;
2696 mt
.hCurrentMenu
= hmenu
;
2697 mt
.hTopMenu
= hmenu
;
2698 mt
.hOwnerWnd
= hwnd
;
2702 TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2703 hmenu
, wFlags
, x
, y
, hwnd
, (lprect
) ? lprect
->left
: 0, (lprect
) ? lprect
->top
: 0,
2704 (lprect
) ? lprect
->right
: 0, (lprect
) ? lprect
->bottom
: 0);
2707 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
2709 if (wFlags
& TPM_BUTTONDOWN
)
2711 /* Get the result in order to start the tracking or not */
2712 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
2713 fEndMenu
= !fRemove
;
2716 EVENT_Capture( mt
.hOwnerWnd
, HTMENU
);
2720 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
2721 msg
.hwnd
= (wFlags
& TPM_ENTERIDLEEX
&& menu
->wFlags
& MF_POPUP
) ? menu
->hWnd
: 0;
2723 /* we have to keep the message in the queue until it's
2724 * clear that menu loop is not over yet. */
2726 if (!MSG_InternalGetMessage( QMSG_WIN32A
, &msg
, msg
.hwnd
, mt
.hOwnerWnd
,
2727 MSGF_MENU
, PM_NOREMOVE
, !enterIdleSent
, &enterIdleSent
)) break;
2729 /* check if EndMenu() tried to cancel us, by posting this message */
2730 if(msg
.message
== WM_CANCELMODE
)
2732 /* we are now out of the loop */
2735 /* remove the message from the queue */
2736 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2738 /* break out of internal loop, ala ESCAPE */
2742 TranslateMessage( &msg
);
2745 if ( (msg
.hwnd
==menu
->hWnd
) || (msg
.message
!=WM_TIMER
) )
2746 enterIdleSent
=FALSE
;
2749 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
2751 /* Find a menu for this mouse event */
2752 hmenu
= MENU_PtMenu( mt
.hTopMenu
, msg
.pt
);
2756 /* no WM_NC... messages in captured state */
2758 case WM_RBUTTONDBLCLK
:
2759 case WM_RBUTTONDOWN
:
2760 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2762 case WM_LBUTTONDBLCLK
:
2763 case WM_LBUTTONDOWN
:
2764 /* If the message belongs to the menu, removes it from the queue */
2765 /* Else, end menu tracking */
2766 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
2767 fEndMenu
= !fRemove
;
2771 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2774 /* Check if a menu was selected by the mouse */
2777 executedMenuId
= MENU_ButtonUp( &mt
, hmenu
, wFlags
);
2779 /* End the loop if executedMenuId is an item ID */
2780 /* or if the job was done (executedMenuId = 0). */
2781 fEndMenu
= fRemove
= (executedMenuId
!= -1);
2783 /* No menu was selected by the mouse */
2784 /* if the function was called by TrackPopupMenu, continue
2785 with the menu tracking. If not, stop it */
2787 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
2792 /* In win95 winelook, the selected menu item must be changed every time the
2793 mouse moves. In Win31 winelook, the mouse button has to be held down */
2795 if ( (TWEAK_WineLook
> WIN31_LOOK
) ||
2796 ( (msg
.wParam
& MK_LBUTTON
) ||
2797 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
.wParam
& MK_RBUTTON
))) )
2799 fEndMenu
|= !MENU_MouseMove( &mt
, hmenu
, wFlags
);
2801 } /* switch(msg.message) - mouse */
2803 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
2805 fRemove
= TRUE
; /* Keyboard messages are always removed */
2813 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2814 NO_SELECTED_ITEM
, FALSE
, 0 );
2817 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2818 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
2821 case VK_DOWN
: /* If on menu bar, pull-down the menu */
2823 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
2824 if (!(menu
->wFlags
& MF_POPUP
))
2825 mt
.hCurrentMenu
= MENU_ShowSubPopup(mt
.hOwnerWnd
, mt
.hTopMenu
, TRUE
, wFlags
);
2826 else /* otherwise try to move selection */
2827 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
, ITEM_NEXT
);
2831 MENU_KeyLeft( &mt
, wFlags
);
2835 MENU_KeyRight( &mt
, wFlags
);
2845 hi
.cbSize
= sizeof(HELPINFO
);
2846 hi
.iContextType
= HELPINFO_MENUITEM
;
2847 if (menu
->FocusedItem
== NO_SELECTED_ITEM
)
2850 hi
.iCtrlId
= menu
->items
[menu
->FocusedItem
].wID
;
2851 hi
.hItemHandle
= hmenu
;
2852 hi
.dwContextId
= menu
->dwContextHelpID
;
2853 hi
.MousePos
= msg
.pt
;
2854 SendMessageA(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
2861 break; /* WM_KEYDOWN */
2871 break; /* WM_SYSKEYDOWN */
2877 if (msg
.wParam
== '\r' || msg
.wParam
== ' ')
2879 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2880 fEndMenu
= (executedMenuId
!= -1);
2885 /* Hack to avoid control chars. */
2886 /* We will find a better way real soon... */
2887 if ((msg
.wParam
<= 32) || (msg
.wParam
>= 127)) break;
2889 pos
= MENU_FindItemByKey( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2890 LOWORD(msg
.wParam
), FALSE
);
2891 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
2892 else if (pos
== (UINT
)-1) MessageBeep(0);
2895 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
, pos
,
2897 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2898 fEndMenu
= (executedMenuId
!= -1);
2902 } /* switch(msg.message) - kbd */
2906 DispatchMessageA( &msg
);
2909 if (!fEndMenu
) fRemove
= TRUE
;
2911 /* finally remove message from the queue */
2913 if (fRemove
&& !(mt
.trackFlags
& TF_SKIPREMOVE
) )
2914 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2915 else mt
.trackFlags
&= ~TF_SKIPREMOVE
;
2920 /* If dropdown is still painted and the close box is clicked on
2921 then the menu will be destroyed as part of the DispatchMessage above.
2922 This will then invalidate the menu handle in mt.hTopMenu. We should
2923 check for this first. */
2924 if( IsMenu( mt
.hTopMenu
) )
2926 menu
= MENU_GetMenu( mt
.hTopMenu
);
2928 if( IsWindow( mt
.hOwnerWnd
) )
2930 MENU_HideSubPopups( mt
.hOwnerWnd
, mt
.hTopMenu
, FALSE
);
2932 if (menu
&& menu
->wFlags
& MF_POPUP
)
2934 ShowWindow( menu
->hWnd
, SW_HIDE
);
2937 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
2938 SendMessageA( mt
.hOwnerWnd
, WM_MENUSELECT
, MAKELONG(0,0xffff), 0 );
2941 /* Reset the variable for hiding menu */
2942 if( menu
) menu
->bTimeToHide
= FALSE
;
2945 /* The return value is only used by TrackPopupMenu */
2946 return ((executedMenuId
!= -1) ? executedMenuId
: 0);
2949 /***********************************************************************
2952 static BOOL
MENU_InitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
2954 TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd
, hMenu
);
2958 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
2959 if (!(wFlags
& TPM_NONOTIFY
))
2960 SendMessageA( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
2962 SendMessageA( hWnd
, WM_SETCURSOR
, hWnd
, HTCAPTION
);
2964 if (!(wFlags
& TPM_NONOTIFY
))
2965 SendMessageA( hWnd
, WM_INITMENU
, hMenu
, 0 );
2969 /***********************************************************************
2972 static BOOL
MENU_ExitTracking(HWND hWnd
)
2974 TRACE("hwnd=0x%04x\n", hWnd
);
2976 SendMessageA( hWnd
, WM_EXITMENULOOP
, 0, 0 );
2981 /***********************************************************************
2982 * MENU_TrackMouseMenuBar
2984 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2986 void MENU_TrackMouseMenuBar( WND
* wndPtr
, INT ht
, POINT pt
)
2988 HWND hWnd
= wndPtr
->hwndSelf
;
2989 HMENU hMenu
= (ht
== HTSYSMENU
) ? wndPtr
->hSysMenu
: wndPtr
->wIDmenu
;
2990 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
2992 TRACE("pwnd=%p ht=0x%04x (%ld,%ld)\n", wndPtr
, ht
, pt
.x
, pt
.y
);
2996 MENU_InitTracking( hWnd
, hMenu
, FALSE
, wFlags
);
2997 MENU_TrackMenu( hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
2998 MENU_ExitTracking(hWnd
);
3003 /***********************************************************************
3004 * MENU_TrackKbdMenuBar
3006 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3008 void MENU_TrackKbdMenuBar( WND
* wndPtr
, UINT wParam
, INT vkey
)
3010 UINT uItem
= NO_SELECTED_ITEM
;
3012 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3014 /* find window that has a menu */
3016 while( wndPtr
->dwStyle
& WS_CHILD
)
3017 if( !(wndPtr
= wndPtr
->parent
) ) return;
3019 /* check if we have to track a system menu */
3021 if( (wndPtr
->dwStyle
& (WS_CHILD
| WS_MINIMIZE
)) ||
3022 !wndPtr
->wIDmenu
|| vkey
== VK_SPACE
)
3024 if( !(wndPtr
->dwStyle
& WS_SYSMENU
) ) return;
3025 hTrackMenu
= wndPtr
->hSysMenu
;
3027 wParam
|= HTSYSMENU
; /* prevent item lookup */
3030 hTrackMenu
= wndPtr
->wIDmenu
;
3032 if (IsMenu( hTrackMenu
))
3034 MENU_InitTracking( wndPtr
->hwndSelf
, hTrackMenu
, FALSE
, wFlags
);
3036 if( vkey
&& vkey
!= VK_SPACE
)
3038 uItem
= MENU_FindItemByKey( wndPtr
->hwndSelf
, hTrackMenu
,
3039 vkey
, (wParam
& HTSYSMENU
) );
3040 if( uItem
>= (UINT
)(-2) )
3042 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3049 MENU_SelectItem( wndPtr
->hwndSelf
, hTrackMenu
, uItem
, TRUE
, 0 );
3051 if( uItem
== NO_SELECTED_ITEM
)
3052 MENU_MoveSelection( wndPtr
->hwndSelf
, hTrackMenu
, ITEM_NEXT
);
3054 PostMessageA( wndPtr
->hwndSelf
, WM_KEYDOWN
, VK_DOWN
, 0L );
3056 MENU_TrackMenu( hTrackMenu
, wFlags
, 0, 0, wndPtr
->hwndSelf
, NULL
);
3059 MENU_ExitTracking (wndPtr
->hwndSelf
);
3064 /**********************************************************************
3065 * TrackPopupMenu16 (USER.416)
3067 BOOL16 WINAPI
TrackPopupMenu16( HMENU16 hMenu
, UINT16 wFlags
, INT16 x
, INT16 y
,
3068 INT16 nReserved
, HWND16 hWnd
, const RECT16
*lpRect
)
3072 CONV_RECT16TO32( lpRect
, &r
);
3073 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, nReserved
, hWnd
,
3074 lpRect
? &r
: NULL
);
3078 /**********************************************************************
3079 * TrackPopupMenu (USER32.549)
3081 * Like the win32 API, the function return the command ID only if the
3082 * flag TPM_RETURNCMD is on.
3085 BOOL WINAPI
TrackPopupMenu( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3086 INT nReserved
, HWND hWnd
, const RECT
*lpRect
)
3090 MENU_InitTracking(hWnd
, hMenu
, TRUE
, wFlags
);
3092 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3093 if (!(wFlags
& TPM_NONOTIFY
))
3094 SendMessageA( hWnd
, WM_INITMENUPOPUP
, hMenu
, 0);
3096 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
, 0, 0 ))
3097 ret
= MENU_TrackMenu( hMenu
, wFlags
| TPM_POPUPMENU
, 0, 0, hWnd
, lpRect
);
3098 MENU_ExitTracking(hWnd
);
3100 if( (!(wFlags
& TPM_RETURNCMD
)) && (ret
!= FALSE
) )
3106 /**********************************************************************
3107 * TrackPopupMenuEx (USER32.550)
3109 BOOL WINAPI
TrackPopupMenuEx( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3110 HWND hWnd
, LPTPMPARAMS lpTpm
)
3112 FIXME("not fully implemented\n" );
3113 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, 0, hWnd
,
3114 lpTpm
? &lpTpm
->rcExclude
: NULL
);
3117 /***********************************************************************
3120 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3122 LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
,
3125 WND
* wndPtr
= WIN_FindWndPtr(hwnd
);
3128 TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
3129 hwnd
, message
, wParam
, lParam
);
3135 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*)lParam
;
3136 SetWindowLongA( hwnd
, 0, (LONG
)cs
->lpCreateParams
);
3141 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
3142 retvalue
= MA_NOACTIVATE
;
3148 BeginPaint( hwnd
, &ps
);
3149 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
3150 (HMENU
)GetWindowLongA( hwnd
, 0 ) );
3151 EndPaint( hwnd
, &ps
);
3161 /* zero out global pointer in case resident popup window
3162 * was somehow destroyed. */
3164 if(MENU_GetTopPopupWnd() )
3166 if( hwnd
== pTopPopupWnd
->hwndSelf
)
3168 ERR("resident popup destroyed!\n");
3170 MENU_DestroyTopPopupWnd();
3175 MENU_ReleaseTopPopupWnd();
3183 if( !(*(HMENU
*)wndPtr
->wExtra
) )
3184 ERR("no menu to display\n");
3187 *(HMENU
*)wndPtr
->wExtra
= 0;
3190 case MM_SETMENUHANDLE
:
3192 *(HMENU
*)wndPtr
->wExtra
= (HMENU
)wParam
;
3195 case MM_GETMENUHANDLE
:
3197 retvalue
= *(HMENU
*)wndPtr
->wExtra
;
3201 retvalue
= DefWindowProcA( hwnd
, message
, wParam
, lParam
);
3206 WIN_ReleaseWndPtr(wndPtr
);
3211 /***********************************************************************
3212 * MENU_GetMenuBarHeight
3214 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3216 UINT
MENU_GetMenuBarHeight( HWND hwnd
, UINT menubarWidth
,
3217 INT orgX
, INT orgY
)
3225 TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3226 hwnd
, menubarWidth
, orgX
, orgY
);
3228 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
3231 if (!(lppop
= MENU_GetMenu((HMENU16
)wndPtr
->wIDmenu
)))
3233 WIN_ReleaseWndPtr(wndPtr
);
3237 hdc
= GetDCEx( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3238 SelectObject( hdc
, hMenuFont
);
3239 SetRect(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+GetSystemMetrics(SM_CYMENU
));
3240 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
3241 ReleaseDC( hwnd
, hdc
);
3242 retvalue
= lppop
->Height
;
3243 WIN_ReleaseWndPtr(wndPtr
);
3248 /*******************************************************************
3249 * ChangeMenu16 (USER.153)
3251 BOOL16 WINAPI
ChangeMenu16( HMENU16 hMenu
, UINT16 pos
, SEGPTR data
,
3252 UINT16 id
, UINT16 flags
)
3254 TRACE("menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
3255 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3256 if (flags
& MF_APPEND
) return AppendMenu16( hMenu
, flags
& ~MF_APPEND
,
3259 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
3260 /* for MF_DELETE. We should check the parameters for all others */
3261 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
3263 if (flags
& MF_DELETE
) return DeleteMenu16(hMenu
, pos
, flags
& ~MF_DELETE
);
3264 if (flags
& MF_CHANGE
) return ModifyMenu16(hMenu
, pos
, flags
& ~MF_CHANGE
,
3266 if (flags
& MF_REMOVE
) return RemoveMenu16(hMenu
,
3267 flags
& MF_BYPOSITION
? pos
: id
,
3268 flags
& ~MF_REMOVE
);
3269 /* Default: MF_INSERT */
3270 return InsertMenu16( hMenu
, pos
, flags
, id
, data
);
3274 /*******************************************************************
3275 * ChangeMenuA (USER32.23)
3277 BOOL WINAPI
ChangeMenuA( HMENU hMenu
, UINT pos
, LPCSTR data
,
3278 UINT id
, UINT flags
)
3280 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3281 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3282 if (flags
& MF_APPEND
) return AppendMenuA( hMenu
, flags
& ~MF_APPEND
,
3284 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3285 if (flags
& MF_CHANGE
) return ModifyMenuA(hMenu
, pos
, flags
& ~MF_CHANGE
,
3287 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3288 flags
& MF_BYPOSITION
? pos
: id
,
3289 flags
& ~MF_REMOVE
);
3290 /* Default: MF_INSERT */
3291 return InsertMenuA( hMenu
, pos
, flags
, id
, data
);
3295 /*******************************************************************
3296 * ChangeMenuW (USER32.24)
3298 BOOL WINAPI
ChangeMenuW( HMENU hMenu
, UINT pos
, LPCWSTR data
,
3299 UINT id
, UINT flags
)
3301 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3302 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3303 if (flags
& MF_APPEND
) return AppendMenuW( hMenu
, flags
& ~MF_APPEND
,
3305 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3306 if (flags
& MF_CHANGE
) return ModifyMenuW(hMenu
, pos
, flags
& ~MF_CHANGE
,
3308 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3309 flags
& MF_BYPOSITION
? pos
: id
,
3310 flags
& ~MF_REMOVE
);
3311 /* Default: MF_INSERT */
3312 return InsertMenuW( hMenu
, pos
, flags
, id
, data
);
3316 /*******************************************************************
3317 * CheckMenuItem16 (USER.154)
3319 BOOL16 WINAPI
CheckMenuItem16( HMENU16 hMenu
, UINT16 id
, UINT16 flags
)
3321 return (BOOL16
)CheckMenuItem( hMenu
, id
, flags
);
3325 /*******************************************************************
3326 * CheckMenuItem (USER32.46)
3328 DWORD WINAPI
CheckMenuItem( HMENU hMenu
, UINT id
, UINT flags
)
3333 TRACE("menu=%04x id=%04x flags=%04x\n", hMenu
, id
, flags
);
3334 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
3335 ret
= item
->fState
& MF_CHECKED
;
3336 if (flags
& MF_CHECKED
) item
->fState
|= MF_CHECKED
;
3337 else item
->fState
&= ~MF_CHECKED
;
3342 /**********************************************************************
3343 * EnableMenuItem16 (USER.155)
3345 UINT16 WINAPI
EnableMenuItem16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3347 return EnableMenuItem( hMenu
, wItemID
, wFlags
);
3351 /**********************************************************************
3352 * EnableMenuItem (USER32.170)
3354 UINT WINAPI
EnableMenuItem( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3360 TRACE("(%04x, %04X, %04X) !\n",
3361 hMenu
, wItemID
, wFlags
);
3363 /* Get the Popupmenu to access the owner menu */
3364 if (!(menu
= MENU_GetMenu(hMenu
)))
3367 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
)))
3370 oldflags
= item
->fState
& (MF_GRAYED
| MF_DISABLED
);
3371 item
->fState
^= (oldflags
^ wFlags
) & (MF_GRAYED
| MF_DISABLED
);
3373 /* In win95 if the close item in the system menu change update the close button */
3374 if (TWEAK_WineLook
== WIN95_LOOK
)
3375 if((item
->wID
== SC_CLOSE
) && (oldflags
!= wFlags
))
3377 if (menu
->hSysMenuOwner
!= 0)
3379 POPUPMENU
* parentMenu
;
3381 /* Get the parent menu to access*/
3382 if (!(parentMenu
= MENU_GetMenu(menu
->hSysMenuOwner
)))
3385 /* Refresh the frame to reflect the change*/
3386 SetWindowPos(parentMenu
->hWnd
, 0, 0, 0, 0, 0,
3387 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
3395 /*******************************************************************
3396 * GetMenuString16 (USER.161)
3398 INT16 WINAPI
GetMenuString16( HMENU16 hMenu
, UINT16 wItemID
,
3399 LPSTR str
, INT16 nMaxSiz
, UINT16 wFlags
)
3401 return GetMenuStringA( hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3405 /*******************************************************************
3406 * GetMenuStringA (USER32.268)
3408 INT WINAPI
GetMenuStringA(
3409 HMENU hMenu
, /* [in] menuhandle */
3410 UINT wItemID
, /* [in] menu item (dep. on wFlags) */
3411 LPSTR str
, /* [out] outbuffer. If NULL, func returns entry length*/
3412 INT nMaxSiz
, /* [in] length of buffer. if 0, func returns entry len*/
3413 UINT wFlags
/* [in] MF_ flags */
3417 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3418 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3419 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3420 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3421 if (!str
|| !nMaxSiz
) return strlen(item
->text
);
3423 lstrcpynA( str
, item
->text
, nMaxSiz
);
3424 TRACE("returning '%s'\n", str
);
3429 /*******************************************************************
3430 * GetMenuStringW (USER32.269)
3432 INT WINAPI
GetMenuStringW( HMENU hMenu
, UINT wItemID
,
3433 LPWSTR str
, INT nMaxSiz
, UINT wFlags
)
3437 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3438 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3439 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3440 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3441 if (!str
|| !nMaxSiz
) return strlen(item
->text
);
3443 lstrcpynAtoW( str
, item
->text
, nMaxSiz
);
3444 return lstrlenW(str
);
3448 /**********************************************************************
3449 * HiliteMenuItem16 (USER.162)
3451 BOOL16 WINAPI
HiliteMenuItem16( HWND16 hWnd
, HMENU16 hMenu
, UINT16 wItemID
,
3454 return HiliteMenuItem( hWnd
, hMenu
, wItemID
, wHilite
);
3458 /**********************************************************************
3459 * HiliteMenuItem (USER32.318)
3461 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
3465 TRACE("(%04x, %04x, %04x, %04x);\n",
3466 hWnd
, hMenu
, wItemID
, wHilite
);
3467 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
3468 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3469 if (menu
->FocusedItem
== wItemID
) return TRUE
;
3470 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
3471 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
, 0 );
3476 /**********************************************************************
3477 * GetMenuState16 (USER.250)
3479 UINT16 WINAPI
GetMenuState16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3481 return GetMenuState( hMenu
, wItemID
, wFlags
);
3485 /**********************************************************************
3486 * GetMenuState (USER32.267)
3488 UINT WINAPI
GetMenuState( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3491 TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
3492 hMenu
, wItemID
, wFlags
);
3493 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
3494 debug_print_menuitem (" item: ", item
, "");
3495 if (item
->fType
& MF_POPUP
)
3497 POPUPMENU
*menu
= MENU_GetMenu( item
->hSubMenu
);
3498 if (!menu
) return -1;
3499 else return (menu
->nItems
<< 8) | ((item
->fState
|item
->fType
) & 0xff);
3503 /* We used to (from way back then) mask the result to 0xff. */
3504 /* I don't know why and it seems wrong as the documented */
3505 /* return flag MF_SEPARATOR is outside that mask. */
3506 return (item
->fType
| item
->fState
);
3511 /**********************************************************************
3512 * GetMenuItemCount16 (USER.263)
3514 INT16 WINAPI
GetMenuItemCount16( HMENU16 hMenu
)
3516 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3517 if (!menu
) return -1;
3518 TRACE("(%04x) returning %d\n",
3519 hMenu
, menu
->nItems
);
3520 return menu
->nItems
;
3524 /**********************************************************************
3525 * GetMenuItemCount (USER32.262)
3527 INT WINAPI
GetMenuItemCount( HMENU hMenu
)
3529 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3530 if (!menu
) return -1;
3531 TRACE("(%04x) returning %d\n",
3532 hMenu
, menu
->nItems
);
3533 return menu
->nItems
;
3536 /**********************************************************************
3537 * GetMenuItemID16 (USER.264)
3539 UINT16 WINAPI
GetMenuItemID16( HMENU16 hMenu
, INT16 nPos
)
3541 return (UINT16
) GetMenuItemID (hMenu
, nPos
);
3544 /**********************************************************************
3545 * GetMenuItemID (USER32.263)
3547 UINT WINAPI
GetMenuItemID( HMENU hMenu
, INT nPos
)
3551 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return 0;
3552 if (lpmi
->fType
& MF_POPUP
) return -1;
3557 /*******************************************************************
3558 * InsertMenu16 (USER.410)
3560 BOOL16 WINAPI
InsertMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3561 UINT16 id
, SEGPTR data
)
3563 UINT pos32
= (UINT
)pos
;
3564 if ((pos
== (UINT16
)-1) && (flags
& MF_BYPOSITION
)) pos32
= (UINT
)-1;
3565 if (IS_STRING_ITEM(flags
) && data
)
3566 return InsertMenuA( hMenu
, pos32
, flags
, id
,
3567 (LPSTR
)PTR_SEG_TO_LIN(data
) );
3568 return InsertMenuA( hMenu
, pos32
, flags
, id
, (LPSTR
)data
);
3572 /*******************************************************************
3573 * InsertMenuA (USER32.322)
3575 BOOL WINAPI
InsertMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3576 UINT id
, LPCSTR str
)
3580 if (IS_STRING_ITEM(flags
) && str
)
3581 TRACE("hMenu %04x, pos %d, flags %08x, "
3582 "id %04x, str '%s'\n",
3583 hMenu
, pos
, flags
, id
, str
);
3584 else TRACE("hMenu %04x, pos %d, flags %08x, "
3585 "id %04x, str %08lx (not a string)\n",
3586 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3588 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
3590 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
3592 RemoveMenu( hMenu
, pos
, flags
);
3596 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
3597 (MENU_GetMenu((HMENU16
)id
))->wFlags
|= MF_POPUP
;
3599 item
->hCheckBit
= item
->hUnCheckBit
= 0;
3604 /*******************************************************************
3605 * InsertMenuW (USER32.325)
3607 BOOL WINAPI
InsertMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3608 UINT id
, LPCWSTR str
)
3612 if (IS_STRING_ITEM(flags
) && str
)
3614 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
3615 ret
= InsertMenuA( hMenu
, pos
, flags
, id
, newstr
);
3616 HeapFree( GetProcessHeap(), 0, newstr
);
3619 else return InsertMenuA( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
3623 /*******************************************************************
3624 * AppendMenu16 (USER.411)
3626 BOOL16 WINAPI
AppendMenu16(HMENU16 hMenu
, UINT16 flags
, UINT16 id
, SEGPTR data
)
3628 return InsertMenu16( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3632 /*******************************************************************
3633 * AppendMenuA (USER32.5)
3635 BOOL WINAPI
AppendMenuA( HMENU hMenu
, UINT flags
,
3636 UINT id
, LPCSTR data
)
3638 return InsertMenuA( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3642 /*******************************************************************
3643 * AppendMenuW (USER32.6)
3645 BOOL WINAPI
AppendMenuW( HMENU hMenu
, UINT flags
,
3646 UINT id
, LPCWSTR data
)
3648 return InsertMenuW( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3652 /**********************************************************************
3653 * RemoveMenu16 (USER.412)
3655 BOOL16 WINAPI
RemoveMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3657 return RemoveMenu( hMenu
, nPos
, wFlags
);
3661 /**********************************************************************
3662 * RemoveMenu (USER32.441)
3664 BOOL WINAPI
RemoveMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3669 TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu
, nPos
, wFlags
);
3670 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3671 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3675 MENU_FreeItemData( item
);
3677 if (--menu
->nItems
== 0)
3679 HeapFree( SystemHeap
, 0, menu
->items
);
3684 while(nPos
< menu
->nItems
)
3690 menu
->items
= HeapReAlloc( SystemHeap
, 0, menu
->items
,
3691 menu
->nItems
* sizeof(MENUITEM
) );
3697 /**********************************************************************
3698 * DeleteMenu16 (USER.413)
3700 BOOL16 WINAPI
DeleteMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3702 return DeleteMenu( hMenu
, nPos
, wFlags
);
3706 /**********************************************************************
3707 * DeleteMenu (USER32.129)
3709 BOOL WINAPI
DeleteMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3711 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
3712 if (!item
) return FALSE
;
3713 if (item
->fType
& MF_POPUP
) DestroyMenu( item
->hSubMenu
);
3714 /* nPos is now the position of the item */
3715 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
3720 /*******************************************************************
3721 * ModifyMenu16 (USER.414)
3723 BOOL16 WINAPI
ModifyMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3724 UINT16 id
, SEGPTR data
)
3726 if (IS_STRING_ITEM(flags
))
3727 return ModifyMenuA( hMenu
, pos
, flags
, id
,
3728 (LPSTR
)PTR_SEG_TO_LIN(data
) );
3729 return ModifyMenuA( hMenu
, pos
, flags
, id
, (LPSTR
)data
);
3733 /*******************************************************************
3734 * ModifyMenuA (USER32.397)
3736 BOOL WINAPI
ModifyMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3737 UINT id
, LPCSTR str
)
3741 if (IS_STRING_ITEM(flags
))
3743 TRACE("%04x %d %04x %04x '%s'\n",
3744 hMenu
, pos
, flags
, id
, str
? str
: "#NULL#" );
3745 if (!str
) return FALSE
;
3749 TRACE("%04x %d %04x %04x %08lx\n",
3750 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3753 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
3754 return MENU_SetItemData( item
, flags
, id
, str
);
3758 /*******************************************************************
3759 * ModifyMenuW (USER32.398)
3761 BOOL WINAPI
ModifyMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3762 UINT id
, LPCWSTR str
)
3766 if (IS_STRING_ITEM(flags
) && str
)
3768 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
3769 ret
= ModifyMenuA( hMenu
, pos
, flags
, id
, newstr
);
3770 HeapFree( GetProcessHeap(), 0, newstr
);
3773 else return ModifyMenuA( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
3777 /**********************************************************************
3778 * CreatePopupMenu16 (USER.415)
3780 HMENU16 WINAPI
CreatePopupMenu16(void)
3782 return CreatePopupMenu();
3786 /**********************************************************************
3787 * CreatePopupMenu (USER32.82)
3789 HMENU WINAPI
CreatePopupMenu(void)
3794 if (!(hmenu
= CreateMenu())) return 0;
3795 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
3796 menu
->wFlags
|= MF_POPUP
;
3797 menu
->bTimeToHide
= FALSE
;
3802 /**********************************************************************
3803 * GetMenuCheckMarkDimensions (USER.417) (USER32.258)
3805 DWORD WINAPI
GetMenuCheckMarkDimensions(void)
3807 return MAKELONG( check_bitmap_width
, check_bitmap_height
);
3811 /**********************************************************************
3812 * SetMenuItemBitmaps16 (USER.418)
3814 BOOL16 WINAPI
SetMenuItemBitmaps16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
,
3815 HBITMAP16 hNewUnCheck
, HBITMAP16 hNewCheck
)
3817 return SetMenuItemBitmaps( hMenu
, nPos
, wFlags
, hNewUnCheck
, hNewCheck
);
3821 /**********************************************************************
3822 * SetMenuItemBitmaps (USER32.490)
3824 BOOL WINAPI
SetMenuItemBitmaps( HMENU hMenu
, UINT nPos
, UINT wFlags
,
3825 HBITMAP hNewUnCheck
, HBITMAP hNewCheck
)
3828 TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3829 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
3830 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3832 if (!hNewCheck
&& !hNewUnCheck
)
3834 item
->fState
&= ~MF_USECHECKBITMAPS
;
3836 else /* Install new bitmaps */
3838 item
->hCheckBit
= hNewCheck
;
3839 item
->hUnCheckBit
= hNewUnCheck
;
3840 item
->fState
|= MF_USECHECKBITMAPS
;
3846 /**********************************************************************
3847 * CreateMenu16 (USER.151)
3849 HMENU16 WINAPI
CreateMenu16(void)
3851 return CreateMenu();
3855 /**********************************************************************
3856 * CreateMenu (USER32.81)
3858 HMENU WINAPI
CreateMenu(void)
3862 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) ))) return 0;
3863 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3865 ZeroMemory(menu
, sizeof(POPUPMENU
));
3866 menu
->wMagic
= MENU_MAGIC
;
3867 menu
->FocusedItem
= NO_SELECTED_ITEM
;
3868 menu
->bTimeToHide
= FALSE
;
3870 TRACE("return %04x\n", hMenu
);
3876 /**********************************************************************
3877 * DestroyMenu16 (USER.152)
3879 BOOL16 WINAPI
DestroyMenu16( HMENU16 hMenu
)
3881 return DestroyMenu( hMenu
);
3885 /**********************************************************************
3886 * DestroyMenu (USER32.134)
3888 BOOL WINAPI
DestroyMenu( HMENU hMenu
)
3890 TRACE("(%04x)\n", hMenu
);
3892 /* Silently ignore attempts to destroy default system popup */
3894 if (hMenu
&& hMenu
!= MENU_DefSysPopup
)
3896 LPPOPUPMENU lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3897 WND
*pTPWnd
= MENU_GetTopPopupWnd();
3899 if( pTPWnd
&& (hMenu
== *(HMENU
*)pTPWnd
->wExtra
) )
3900 *(UINT
*)pTPWnd
->wExtra
= 0;
3902 if (!IS_A_MENU(lppop
)) lppop
= NULL
;
3905 lppop
->wMagic
= 0; /* Mark it as destroyed */
3907 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
&&
3908 (!pTPWnd
|| (lppop
->hWnd
!= pTPWnd
->hwndSelf
)))
3909 DestroyWindow( lppop
->hWnd
);
3911 if (lppop
->items
) /* recursively destroy submenus */
3914 MENUITEM
*item
= lppop
->items
;
3915 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
3917 if (item
->fType
& MF_POPUP
) DestroyMenu(item
->hSubMenu
);
3918 MENU_FreeItemData( item
);
3920 HeapFree( SystemHeap
, 0, lppop
->items
);
3922 USER_HEAP_FREE( hMenu
);
3923 MENU_ReleaseTopPopupWnd();
3927 MENU_ReleaseTopPopupWnd();
3931 return (hMenu
!= MENU_DefSysPopup
);
3935 /**********************************************************************
3936 * GetSystemMenu16 (USER.156)
3938 HMENU16 WINAPI
GetSystemMenu16( HWND16 hWnd
, BOOL16 bRevert
)
3940 return GetSystemMenu( hWnd
, bRevert
);
3944 /**********************************************************************
3945 * GetSystemMenu (USER32.291)
3947 HMENU WINAPI
GetSystemMenu( HWND hWnd
, BOOL bRevert
)
3949 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
3954 if( wndPtr
->hSysMenu
)
3958 DestroyMenu(wndPtr
->hSysMenu
);
3959 wndPtr
->hSysMenu
= 0;
3963 POPUPMENU
*menu
= MENU_GetMenu( wndPtr
->hSysMenu
);
3966 if( menu
->nItems
> 0 && menu
->items
[0].hSubMenu
== MENU_DefSysPopup
)
3967 menu
->items
[0].hSubMenu
= MENU_CopySysPopup();
3971 WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
3972 wndPtr
->hSysMenu
, hWnd
);
3973 wndPtr
->hSysMenu
= 0;
3978 if(!wndPtr
->hSysMenu
&& (wndPtr
->dwStyle
& WS_SYSMENU
) )
3979 wndPtr
->hSysMenu
= MENU_GetSysMenu( hWnd
, (HMENU
)(-1) );
3981 if( wndPtr
->hSysMenu
)
3984 retvalue
= GetSubMenu16(wndPtr
->hSysMenu
, 0);
3986 /* Store the dummy sysmenu handle to facilitate the refresh */
3987 /* of the close button if the SC_CLOSE item change */
3988 menu
= MENU_GetMenu(retvalue
);
3990 menu
->hSysMenuOwner
= wndPtr
->hSysMenu
;
3992 WIN_ReleaseWndPtr(wndPtr
);
3994 return bRevert
? 0 : retvalue
;
3998 /*******************************************************************
3999 * SetSystemMenu16 (USER.280)
4001 BOOL16 WINAPI
SetSystemMenu16( HWND16 hwnd
, HMENU16 hMenu
)
4003 return SetSystemMenu( hwnd
, hMenu
);
4007 /*******************************************************************
4008 * SetSystemMenu (USER32.508)
4010 BOOL WINAPI
SetSystemMenu( HWND hwnd
, HMENU hMenu
)
4012 WND
*wndPtr
= WIN_FindWndPtr(hwnd
);
4016 if (wndPtr
->hSysMenu
) DestroyMenu( wndPtr
->hSysMenu
);
4017 wndPtr
->hSysMenu
= MENU_GetSysMenu( hwnd
, hMenu
);
4018 WIN_ReleaseWndPtr(wndPtr
);
4025 /**********************************************************************
4026 * GetMenu16 (USER.157)
4028 HMENU16 WINAPI
GetMenu16( HWND16 hWnd
)
4030 return (HMENU16
)GetMenu(hWnd
);
4034 /**********************************************************************
4035 * GetMenu (USER32.257)
4037 HMENU WINAPI
GetMenu( HWND hWnd
)
4040 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
4042 if (!wndPtr
) return 0;
4044 retvalue
= (HMENU
)wndPtr
->wIDmenu
;
4045 TRACE("for %swindow %04x returning %04x\n",
4046 (wndPtr
->dwStyle
& WS_CHILD
) ? "child " : "", hWnd
, retvalue
);
4047 WIN_ReleaseWndPtr(wndPtr
);
4052 /**********************************************************************
4053 * SetMenu16 (USER.158)
4055 BOOL16 WINAPI
SetMenu16( HWND16 hWnd
, HMENU16 hMenu
)
4057 return SetMenu( hWnd
, hMenu
);
4061 /**********************************************************************
4062 * SetMenu (USER32.487)
4064 BOOL WINAPI
SetMenu( HWND hWnd
, HMENU hMenu
)
4066 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
4069 TRACE("(%04x, %04x);\n", hWnd
, hMenu
);
4071 if (hMenu
&& !IsMenu(hMenu
))
4073 WARN("hMenu is not a menu handle\n");
4077 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
4079 if (GetCapture() == hWnd
) ReleaseCapture();
4081 wndPtr
->wIDmenu
= (UINT
)hMenu
;
4086 if (!(lpmenu
= MENU_GetMenu(hMenu
)))
4089 lpmenu
->hWnd
= hWnd
;
4090 lpmenu
->wFlags
&= ~MF_POPUP
; /* Can't be a popup */
4091 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
4093 if (IsWindowVisible(hWnd
))
4094 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4095 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4099 WIN_ReleaseWndPtr(wndPtr
);
4105 /**********************************************************************
4106 * GetSubMenu16 (USER.159)
4108 HMENU16 WINAPI
GetSubMenu16( HMENU16 hMenu
, INT16 nPos
)
4110 return GetSubMenu( hMenu
, nPos
);
4114 /**********************************************************************
4115 * GetSubMenu (USER32.288)
4117 HMENU WINAPI
GetSubMenu( HMENU hMenu
, INT nPos
)
4121 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return 0;
4122 if (!(lpmi
->fType
& MF_POPUP
)) return 0;
4123 return lpmi
->hSubMenu
;
4127 /**********************************************************************
4128 * DrawMenuBar16 (USER.160)
4130 void WINAPI
DrawMenuBar16( HWND16 hWnd
)
4132 DrawMenuBar( hWnd
);
4136 /**********************************************************************
4137 * DrawMenuBar (USER32.161)
4139 BOOL WINAPI
DrawMenuBar( HWND hWnd
)
4142 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
4143 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
) && wndPtr
->wIDmenu
)
4145 lppop
= MENU_GetMenu((HMENU16
)wndPtr
->wIDmenu
);
4148 WIN_ReleaseWndPtr(wndPtr
);
4152 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
4153 lppop
->hwndOwner
= hWnd
;
4154 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4155 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4156 WIN_ReleaseWndPtr(wndPtr
);
4159 WIN_ReleaseWndPtr(wndPtr
);
4164 /***********************************************************************
4165 * EndMenu (USER.187) (USER32.175)
4167 void WINAPI
EndMenu(void)
4169 /* if we are in the menu code, and it is active */
4170 if (fEndMenu
== FALSE
&& MENU_IsMenuActive())
4172 /* terminate the menu handling code */
4175 /* needs to be posted to wakeup the internal menu handler */
4176 /* which will now terminate the menu, in the event that */
4177 /* the main window was minimized, or lost focus, so we */
4178 /* don't end up with an orphaned menu */
4179 PostMessageA( pTopPopupWnd
->hwndSelf
, WM_CANCELMODE
, 0, 0);
4184 /***********************************************************************
4185 * LookupMenuHandle (USER.217)
4187 HMENU16 WINAPI
LookupMenuHandle16( HMENU16 hmenu
, INT16 id
)
4189 HMENU hmenu32
= hmenu
;
4191 if (!MENU_FindItem( &hmenu32
, &id32
, MF_BYCOMMAND
)) return 0;
4192 else return hmenu32
;
4196 /**********************************************************************
4197 * LoadMenu16 (USER.150)
4199 HMENU16 WINAPI
LoadMenu16( HINSTANCE16 instance
, SEGPTR name
)
4207 char *str
= (char *)PTR_SEG_TO_LIN( name
);
4208 TRACE("(%04x,'%s')\n", instance
, str
);
4209 if (str
[0] == '#') name
= (SEGPTR
)atoi( str
+ 1 );
4212 TRACE("(%04x,%04x)\n",instance
,LOWORD(name
));
4214 if (!name
) return 0;
4216 /* check for Win32 module */
4217 if (HIWORD(instance
))
4218 return LoadMenuA(instance
,PTR_SEG_TO_LIN(name
));
4219 instance
= GetExePtr( instance
);
4221 if (!(hRsrc
= FindResource16( instance
, name
, RT_MENU16
))) return 0;
4222 if (!(handle
= LoadResource16( instance
, hRsrc
))) return 0;
4223 hMenu
= LoadMenuIndirect16(LockResource16(handle
));
4224 FreeResource16( handle
);
4229 /*****************************************************************
4230 * LoadMenuA (USER32.370)
4232 HMENU WINAPI
LoadMenuA( HINSTANCE instance
, LPCSTR name
)
4234 HRSRC hrsrc
= FindResourceA( instance
, name
, RT_MENUA
);
4235 if (!hrsrc
) return 0;
4236 return LoadMenuIndirectA( (LPCVOID
)LoadResource( instance
, hrsrc
));
4240 /*****************************************************************
4241 * LoadMenuW (USER32.373)
4243 HMENU WINAPI
LoadMenuW( HINSTANCE instance
, LPCWSTR name
)
4245 HRSRC hrsrc
= FindResourceW( instance
, name
, RT_MENUW
);
4246 if (!hrsrc
) return 0;
4247 return LoadMenuIndirectW( (LPCVOID
)LoadResource( instance
, hrsrc
));
4251 /**********************************************************************
4252 * LoadMenuIndirect16 (USER.220)
4254 HMENU16 WINAPI
LoadMenuIndirect16( LPCVOID
template )
4257 WORD version
, offset
;
4258 LPCSTR p
= (LPCSTR
)template;
4260 TRACE("(%p)\n", template );
4261 version
= GET_WORD(p
);
4265 WARN("version must be 0 for Win16\n" );
4268 offset
= GET_WORD(p
);
4269 p
+= sizeof(WORD
) + offset
;
4270 if (!(hMenu
= CreateMenu())) return 0;
4271 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
4273 DestroyMenu( hMenu
);
4280 /**********************************************************************
4281 * LoadMenuIndirectA (USER32.371)
4283 HMENU WINAPI
LoadMenuIndirectA( LPCVOID
template )
4286 WORD version
, offset
;
4287 LPCSTR p
= (LPCSTR
)template;
4289 TRACE("%p\n", template );
4290 version
= GET_WORD(p
);
4295 offset
= GET_WORD(p
);
4296 p
+= sizeof(WORD
) + offset
;
4297 if (!(hMenu
= CreateMenu())) return 0;
4298 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
4300 DestroyMenu( hMenu
);
4305 offset
= GET_WORD(p
);
4306 p
+= sizeof(WORD
) + offset
;
4307 if (!(hMenu
= CreateMenu())) return 0;
4308 if (!MENUEX_ParseResource( p
, hMenu
))
4310 DestroyMenu( hMenu
);
4315 ERR("version %d not supported.\n", version
);
4321 /**********************************************************************
4322 * LoadMenuIndirectW (USER32.372)
4324 HMENU WINAPI
LoadMenuIndirectW( LPCVOID
template )
4326 /* FIXME: is there anything different between A and W? */
4327 return LoadMenuIndirectA( template );
4331 /**********************************************************************
4332 * IsMenu16 (USER.358)
4334 BOOL16 WINAPI
IsMenu16( HMENU16 hmenu
)
4336 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
4337 return IS_A_MENU(menu
);
4341 /**********************************************************************
4342 * IsMenu (USER32.346)
4344 BOOL WINAPI
IsMenu(HMENU hmenu
)
4346 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
4347 return IS_A_MENU(menu
);
4350 /**********************************************************************
4351 * GetMenuItemInfo_common
4354 static BOOL
GetMenuItemInfo_common ( HMENU hmenu
, UINT item
, BOOL bypos
,
4355 LPMENUITEMINFOA lpmii
, BOOL unicode
)
4357 MENUITEM
*menu
= MENU_FindItem (&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0);
4359 debug_print_menuitem("GetMenuItemInfo_common: ", menu
, "");
4364 if (lpmii
->fMask
& MIIM_TYPE
) {
4365 lpmii
->fType
= menu
->fType
;
4366 switch (MENU_ITEM_TYPE(menu
->fType
)) {
4369 int len
= strlen(menu
->text
);
4370 if(lpmii
->dwTypeData
&& lpmii
->cch
) {
4372 lstrcpynAtoW((LPWSTR
) lpmii
->dwTypeData
, menu
->text
,
4375 lstrcpynA(lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4376 /* if we've copied a substring we return its length */
4377 if(lpmii
->cch
<= len
)
4379 } else /* return length of string */
4385 lpmii
->dwTypeData
= menu
->text
;
4392 if (lpmii
->fMask
& MIIM_STRING
) {
4393 if(lpmii
->dwTypeData
&& lpmii
->cch
) {
4395 lstrcpynAtoW((LPWSTR
) lpmii
->dwTypeData
, menu
->text
,
4398 lstrcpynA(lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4400 lpmii
->cch
= strlen(menu
->text
);
4403 if (lpmii
->fMask
& MIIM_FTYPE
)
4404 lpmii
->fType
= menu
->fType
;
4406 if (lpmii
->fMask
& MIIM_BITMAP
)
4407 lpmii
->hbmpItem
= menu
->hbmpItem
;
4409 if (lpmii
->fMask
& MIIM_STATE
)
4410 lpmii
->fState
= menu
->fState
;
4412 if (lpmii
->fMask
& MIIM_ID
)
4413 lpmii
->wID
= menu
->wID
;
4415 if (lpmii
->fMask
& MIIM_SUBMENU
)
4416 lpmii
->hSubMenu
= menu
->hSubMenu
;
4418 if (lpmii
->fMask
& MIIM_CHECKMARKS
) {
4419 lpmii
->hbmpChecked
= menu
->hCheckBit
;
4420 lpmii
->hbmpUnchecked
= menu
->hUnCheckBit
;
4422 if (lpmii
->fMask
& MIIM_DATA
)
4423 lpmii
->dwItemData
= menu
->dwItemData
;
4428 /**********************************************************************
4429 * GetMenuItemInfoA (USER32.264)
4431 BOOL WINAPI
GetMenuItemInfoA( HMENU hmenu
, UINT item
, BOOL bypos
,
4432 LPMENUITEMINFOA lpmii
)
4434 return GetMenuItemInfo_common (hmenu
, item
, bypos
, lpmii
, FALSE
);
4437 /**********************************************************************
4438 * GetMenuItemInfoW (USER32.265)
4440 BOOL WINAPI
GetMenuItemInfoW( HMENU hmenu
, UINT item
, BOOL bypos
,
4441 LPMENUITEMINFOW lpmii
)
4443 return GetMenuItemInfo_common (hmenu
, item
, bypos
,
4444 (LPMENUITEMINFOA
)lpmii
, TRUE
);
4447 /**********************************************************************
4448 * SetMenuItemInfo_common
4451 static BOOL
SetMenuItemInfo_common(MENUITEM
* menu
,
4452 const MENUITEMINFOA
*lpmii
,
4455 if (!menu
) return FALSE
;
4457 if (lpmii
->fMask
& MIIM_TYPE
) {
4458 /* Get rid of old string. */
4459 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4460 HeapFree(SystemHeap
, 0, menu
->text
);
4464 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4465 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4466 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4468 menu
->text
= lpmii
->dwTypeData
;
4470 if (IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4472 menu
->text
= HEAP_strdupWtoA(SystemHeap
, 0, (LPWSTR
) lpmii
->dwTypeData
);
4474 menu
->text
= HEAP_strdupA(SystemHeap
, 0, lpmii
->dwTypeData
);
4478 if (lpmii
->fMask
& MIIM_FTYPE
) {
4479 /* free the string when the type is changing */
4480 if ( (!IS_STRING_ITEM(lpmii
->fType
)) && IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4481 HeapFree(SystemHeap
, 0, menu
->text
);
4484 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4485 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4488 if (lpmii
->fMask
& MIIM_STRING
) {
4489 /* free the string when used */
4490 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4491 HeapFree(SystemHeap
, 0, menu
->text
);
4493 menu
->text
= HEAP_strdupWtoA(SystemHeap
, 0, (LPWSTR
) lpmii
->dwTypeData
);
4495 menu
->text
= HEAP_strdupA(SystemHeap
, 0, lpmii
->dwTypeData
);
4499 if (lpmii
->fMask
& MIIM_STATE
)
4501 /* fixme: MFS_DEFAULT do we have to reset the other menu items? */
4502 menu
->fState
= lpmii
->fState
;
4505 if (lpmii
->fMask
& MIIM_ID
)
4506 menu
->wID
= lpmii
->wID
;
4508 if (lpmii
->fMask
& MIIM_SUBMENU
) {
4509 menu
->hSubMenu
= lpmii
->hSubMenu
;
4510 if (menu
->hSubMenu
) {
4511 POPUPMENU
*subMenu
= MENU_GetMenu((UINT16
)menu
->hSubMenu
);
4513 subMenu
->wFlags
|= MF_POPUP
;
4514 menu
->fType
|= MF_POPUP
;
4517 /* FIXME: Return an error ? */
4518 menu
->fType
&= ~MF_POPUP
;
4521 menu
->fType
&= ~MF_POPUP
;
4524 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
4526 if (lpmii
->fType
& MFT_RADIOCHECK
)
4527 menu
->fType
|= MFT_RADIOCHECK
;
4529 menu
->hCheckBit
= lpmii
->hbmpChecked
;
4530 menu
->hUnCheckBit
= lpmii
->hbmpUnchecked
;
4532 if (lpmii
->fMask
& MIIM_DATA
)
4533 menu
->dwItemData
= lpmii
->dwItemData
;
4535 debug_print_menuitem("SetMenuItemInfo_common: ", menu
, "");
4539 /**********************************************************************
4540 * SetMenuItemInfoA (USER32.491)
4542 BOOL WINAPI
SetMenuItemInfoA(HMENU hmenu
, UINT item
, BOOL bypos
,
4543 const MENUITEMINFOA
*lpmii
)
4545 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4549 /**********************************************************************
4550 * SetMenuItemInfoW (USER32.492)
4552 BOOL WINAPI
SetMenuItemInfoW(HMENU hmenu
, UINT item
, BOOL bypos
,
4553 const MENUITEMINFOW
*lpmii
)
4555 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4556 (const MENUITEMINFOA
*)lpmii
, TRUE
);
4559 /**********************************************************************
4560 * SetMenuDefaultItem (USER32.489)
4563 BOOL WINAPI
SetMenuDefaultItem(HMENU hmenu
, UINT uItem
, UINT bypos
)
4569 TRACE("(0x%x,%d,%d)\n", hmenu
, uItem
, bypos
);
4571 if (!(menu
= MENU_GetMenu(hmenu
))) return FALSE
;
4573 /* reset all default-item flags */
4575 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4577 item
->fState
&= ~MFS_DEFAULT
;
4580 /* no default item */
4589 if ( uItem
>= menu
->nItems
) return FALSE
;
4590 item
[uItem
].fState
|= MFS_DEFAULT
;
4595 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4597 if (item
->wID
== uItem
)
4599 item
->fState
|= MFS_DEFAULT
;
4608 /**********************************************************************
4609 * GetMenuDefaultItem (USER32.260)
4611 UINT WINAPI
GetMenuDefaultItem(HMENU hmenu
, UINT bypos
, UINT flags
)
4617 TRACE("(0x%x,%d,%d)\n", hmenu
, bypos
, flags
);
4619 if (!(menu
= MENU_GetMenu(hmenu
))) return -1;
4621 /* find default item */
4625 if (! item
) return -1;
4627 while ( !( item
->fState
& MFS_DEFAULT
) )
4630 if (i
>= menu
->nItems
) return -1;
4633 /* default: don't return disabled items */
4634 if ( (!(GMDI_USEDISABLED
& flags
)) && (item
->fState
& MFS_DISABLED
)) return -1;
4636 /* search rekursiv when needed */
4637 if ( (item
->fType
& MF_POPUP
) && (flags
& GMDI_GOINTOPOPUPS
) )
4640 ret
= GetMenuDefaultItem( item
->hSubMenu
, bypos
, flags
);
4641 if ( -1 != ret
) return ret
;
4643 /* when item not found in submenu, return the popup item */
4645 return ( bypos
) ? i
: item
->wID
;
4649 /*******************************************************************
4650 * InsertMenuItem16 (USER.441)
4654 BOOL16 WINAPI
InsertMenuItem16( HMENU16 hmenu
, UINT16 pos
, BOOL16 byposition
,
4655 const MENUITEMINFO16
*mii
)
4659 miia
.cbSize
= sizeof(miia
);
4660 miia
.fMask
= mii
->fMask
;
4661 miia
.dwTypeData
= mii
->dwTypeData
;
4662 miia
.fType
= mii
->fType
;
4663 miia
.fState
= mii
->fState
;
4664 miia
.wID
= mii
->wID
;
4665 miia
.hSubMenu
= mii
->hSubMenu
;
4666 miia
.hbmpChecked
= mii
->hbmpChecked
;
4667 miia
.hbmpUnchecked
= mii
->hbmpUnchecked
;
4668 miia
.dwItemData
= mii
->dwItemData
;
4669 miia
.cch
= mii
->cch
;
4670 if (IS_STRING_ITEM(miia
.fType
))
4671 miia
.dwTypeData
= PTR_SEG_TO_LIN(miia
.dwTypeData
);
4672 return InsertMenuItemA( hmenu
, pos
, byposition
, &miia
);
4676 /**********************************************************************
4677 * InsertMenuItemA (USER32.323)
4679 BOOL WINAPI
InsertMenuItemA(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4680 const MENUITEMINFOA
*lpmii
)
4682 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4683 return SetMenuItemInfo_common(item
, lpmii
, FALSE
);
4687 /**********************************************************************
4688 * InsertMenuItemW (USER32.324)
4690 BOOL WINAPI
InsertMenuItemW(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4691 const MENUITEMINFOW
*lpmii
)
4693 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4694 return SetMenuItemInfo_common(item
, (const MENUITEMINFOA
*)lpmii
, TRUE
);
4697 /**********************************************************************
4698 * CheckMenuRadioItem (USER32.47)
4701 BOOL WINAPI
CheckMenuRadioItem(HMENU hMenu
,
4702 UINT first
, UINT last
, UINT check
,
4705 MENUITEM
*mifirst
, *milast
, *micheck
;
4706 HMENU mfirst
= hMenu
, mlast
= hMenu
, mcheck
= hMenu
;
4708 TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4709 hMenu
, first
, last
, check
, bypos
);
4711 mifirst
= MENU_FindItem (&mfirst
, &first
, bypos
);
4712 milast
= MENU_FindItem (&mlast
, &last
, bypos
);
4713 micheck
= MENU_FindItem (&mcheck
, &check
, bypos
);
4715 if (mifirst
== NULL
|| milast
== NULL
|| micheck
== NULL
||
4716 mifirst
> milast
|| mfirst
!= mlast
|| mfirst
!= mcheck
||
4717 micheck
> milast
|| micheck
< mifirst
)
4720 while (mifirst
<= milast
)
4722 if (mifirst
== micheck
)
4724 mifirst
->fType
|= MFT_RADIOCHECK
;
4725 mifirst
->fState
|= MFS_CHECKED
;
4727 mifirst
->fType
&= ~MFT_RADIOCHECK
;
4728 mifirst
->fState
&= ~MFS_CHECKED
;
4736 /**********************************************************************
4737 * CheckMenuRadioItem16 (not a Windows API)
4740 BOOL16 WINAPI
CheckMenuRadioItem16(HMENU16 hMenu
,
4741 UINT16 first
, UINT16 last
, UINT16 check
,
4744 return CheckMenuRadioItem (hMenu
, first
, last
, check
, bypos
);
4747 /**********************************************************************
4748 * GetMenuItemRect (USER32.266)
4750 * ATTENTION: Here, the returned values in rect are the screen
4751 * coordinates of the item just like if the menu was
4752 * always on the upper left side of the application.
4755 BOOL WINAPI
GetMenuItemRect (HWND hwnd
, HMENU hMenu
, UINT uItem
,
4758 POPUPMENU
*itemMenu
;
4762 TRACE("(0x%x,0x%x,%d,%p)\n", hwnd
, hMenu
, uItem
, rect
);
4764 item
= MENU_FindItem (&hMenu
, &uItem
, MF_BYPOSITION
);
4765 referenceHwnd
= hwnd
;
4769 itemMenu
= MENU_GetMenu(hMenu
);
4770 if (itemMenu
== NULL
)
4773 if(itemMenu
->hWnd
== 0)
4775 referenceHwnd
= itemMenu
->hWnd
;
4778 if ((rect
== NULL
) || (item
== NULL
))
4783 MapWindowPoints(referenceHwnd
, 0, (LPPOINT
)rect
, 2);
4788 /**********************************************************************
4789 * GetMenuItemRect16 (USER.665)
4792 BOOL16 WINAPI
GetMenuItemRect16 (HWND16 hwnd
, HMENU16 hMenu
, UINT16 uItem
,
4798 if (!rect
) return FALSE
;
4799 res
= GetMenuItemRect (hwnd
, hMenu
, uItem
, &r32
);
4800 CONV_RECT32TO16 (&r32
, rect
);
4804 /**********************************************************************
4808 * MIM_APPLYTOSUBMENUS
4809 * actually use the items to draw the menu
4811 BOOL WINAPI
SetMenuInfo (HMENU hMenu
, LPCMENUINFO lpmi
)
4815 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4817 if (lpmi
&& (lpmi
->cbSize
==sizeof(MENUINFO
)) && (menu
= MENU_GetMenu(hMenu
)))
4820 if (lpmi
->fMask
& MIM_BACKGROUND
)
4821 menu
->hbrBack
= lpmi
->hbrBack
;
4823 if (lpmi
->fMask
& MIM_HELPID
)
4824 menu
->dwContextHelpID
= lpmi
->dwContextHelpID
;
4826 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4827 menu
->cyMax
= lpmi
->cyMax
;
4829 if (lpmi
->fMask
& MIM_MENUDATA
)
4830 menu
->dwMenuData
= lpmi
->dwMenuData
;
4832 if (lpmi
->fMask
& MIM_STYLE
)
4833 menu
->dwStyle
= lpmi
->dwStyle
;
4840 /**********************************************************************
4847 BOOL WINAPI
GetMenuInfo (HMENU hMenu
, LPMENUINFO lpmi
)
4850 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4852 if (lpmi
&& (menu
= MENU_GetMenu(hMenu
)))
4855 if (lpmi
->fMask
& MIM_BACKGROUND
)
4856 lpmi
->hbrBack
= menu
->hbrBack
;
4858 if (lpmi
->fMask
& MIM_HELPID
)
4859 lpmi
->dwContextHelpID
= menu
->dwContextHelpID
;
4861 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4862 lpmi
->cyMax
= menu
->cyMax
;
4864 if (lpmi
->fMask
& MIM_MENUDATA
)
4865 lpmi
->dwMenuData
= menu
->dwMenuData
;
4867 if (lpmi
->fMask
& MIM_STYLE
)
4868 lpmi
->dwStyle
= menu
->dwStyle
;
4875 /**********************************************************************
4876 * SetMenuContextHelpId16 (USER.384)
4878 BOOL16 WINAPI
SetMenuContextHelpId16( HMENU16 hMenu
, DWORD dwContextHelpID
)
4880 return SetMenuContextHelpId( hMenu
, dwContextHelpID
);
4884 /**********************************************************************
4885 * SetMenuContextHelpId (USER32.488)
4887 BOOL WINAPI
SetMenuContextHelpId( HMENU hMenu
, DWORD dwContextHelpID
)
4891 TRACE("(0x%04x 0x%08lx)\n", hMenu
, dwContextHelpID
);
4893 if ((menu
= MENU_GetMenu(hMenu
)))
4895 menu
->dwContextHelpID
= dwContextHelpID
;
4901 /**********************************************************************
4902 * GetMenuContextHelpId16 (USER.385)
4904 DWORD WINAPI
GetMenuContextHelpId16( HMENU16 hMenu
)
4906 return GetMenuContextHelpId( hMenu
);
4909 /**********************************************************************
4910 * GetMenuContextHelpId (USER32.488)
4912 DWORD WINAPI
GetMenuContextHelpId( HMENU hMenu
)
4916 TRACE("(0x%04x)\n", hMenu
);
4918 if ((menu
= MENU_GetMenu(hMenu
)))
4920 return menu
->dwContextHelpID
;
4925 /**********************************************************************
4926 * MenuItemFromPoint (USER32.387)
4928 UINT WINAPI
MenuItemFromPoint(HWND hWnd
, HMENU hMenu
, POINT ptScreen
)
4930 FIXME("(0x%04x,0x%04x,(%ld,%ld)):stub\n",
4931 hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);