4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
6 * Copyright 1997 Morten Welinder
10 * Note: the style MF_MOUSESELECT is used to mark popup items that
11 * have been selected, i.e. their popup menu is currently displayed.
12 * This is probably not the meaning this style has in MS-Windows.
22 #include "wine/winbase16.h"
23 #include "wine/winuser16.h"
28 #include "nonclient.h"
34 #include "debugtools.h"
36 DEFAULT_DEBUG_CHANNEL(menu
)
39 /* internal popup menu window messages */
41 #define MM_SETMENUHANDLE (WM_USER + 0)
42 #define MM_GETMENUHANDLE (WM_USER + 1)
44 /* Menu item structure */
46 /* ----------- MENUITEMINFO Stuff ----------- */
47 UINT fType
; /* Item type. */
48 UINT fState
; /* Item state. */
49 UINT wID
; /* Item id. */
50 HMENU hSubMenu
; /* Pop-up menu. */
51 HBITMAP hCheckBit
; /* Bitmap when checked. */
52 HBITMAP hUnCheckBit
; /* Bitmap when unchecked. */
53 LPSTR text
; /* Item text or bitmap handle. */
54 DWORD dwItemData
; /* Application defined. */
55 DWORD dwTypeData
; /* depends on fMask */
56 HBITMAP hbmpItem
; /* bitmap in win98 style menus */
57 /* ----------- Wine stuff ----------- */
58 RECT rect
; /* Item area (relative to menu window) */
59 UINT xTab
; /* X position of text after Tab */
62 /* Popup menu structure */
64 WORD wFlags
; /* Menu flags (MF_POPUP, MF_SYSMENU) */
65 WORD wMagic
; /* Magic number */
66 HQUEUE16 hTaskQ
; /* Task queue for this menu */
67 WORD Width
; /* Width of the whole menu */
68 WORD Height
; /* Height of the whole menu */
69 WORD nItems
; /* Number of items in the menu */
70 HWND hWnd
; /* Window containing the menu */
71 MENUITEM
*items
; /* Array of menu items */
72 UINT FocusedItem
; /* Currently focused item */
73 HWND hwndOwner
; /* window receiving the messages for ownerdraw */
74 BOOL bTimeToHide
; /* Request hiding when receiving a second click in the top-level menu item */
75 /* ------------ MENUINFO members ------ */
76 DWORD dwStyle
; /* Extended mennu style */
77 UINT cyMax
; /* max hight of the whole menu, 0 is screen hight */
78 HBRUSH hbrBack
; /* brush for menu background */
79 DWORD dwContextHelpID
;
80 DWORD dwMenuData
; /* application defined value */
81 HMENU hSysMenuOwner
; /* Handle to the dummy sys menu holder */
82 } POPUPMENU
, *LPPOPUPMENU
;
84 /* internal flags for menu tracking */
86 #define TF_ENDMENU 0x0001
87 #define TF_SUSPENDPOPUP 0x0002
88 #define TF_SKIPREMOVE 0x0004
93 HMENU hCurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
94 HMENU hTopMenu
; /* initial menu */
95 HWND hOwnerWnd
; /* where notifications are sent */
99 #define MENU_MAGIC 0x554d /* 'MU' */
100 #define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
105 /* Internal MENU_TrackMenu() flags */
106 #define TPM_INTERNAL 0xF0000000
107 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
108 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
109 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
111 /* popup menu shade thickness */
112 #define POPUP_XSHADE 4
113 #define POPUP_YSHADE 4
115 /* Space between 2 menu bar items */
116 #define MENU_BAR_ITEMS_SPACE 12
118 /* Minimum width of a tab character */
119 #define MENU_TAB_SPACE 8
121 /* Height of a separator item */
122 #define SEPARATOR_HEIGHT 5
124 /* (other menu->FocusedItem values give the position of the focused item) */
125 #define NO_SELECTED_ITEM 0xffff
127 #define MENU_ITEM_TYPE(flags) \
128 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
130 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
131 #define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
133 #define IS_SYSTEM_MENU(menu) \
134 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
136 #define IS_SYSTEM_POPUP(menu) \
137 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
139 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
140 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
141 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
142 MF_POPUP | MF_SYSMENU | MF_HELP)
143 #define STATE_MASK (~TYPE_MASK)
145 /* Dimension of the menu bitmaps */
146 static WORD check_bitmap_width
= 0, check_bitmap_height
= 0;
147 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
149 static HBITMAP hStdRadioCheck
= 0;
150 static HBITMAP hStdCheck
= 0;
151 static HBITMAP hStdMnArrow
= 0;
153 /* Minimze/restore/close buttons to be inserted in menubar */
154 static HBITMAP hBmpMinimize
= 0;
155 static HBITMAP hBmpMinimizeD
= 0;
156 static HBITMAP hBmpMaximize
= 0;
157 static HBITMAP hBmpMaximizeD
= 0;
158 static HBITMAP hBmpClose
= 0;
159 static HBITMAP hBmpCloseD
= 0;
162 static HBRUSH hShadeBrush
= 0;
163 static HFONT hMenuFont
= 0;
164 static HFONT hMenuFontBold
= 0;
166 static HMENU MENU_DefSysPopup
= 0; /* Default system menu popup */
168 /* Use global popup window because there's no way 2 menus can
169 * be tracked at the same time. */
171 static WND
* pTopPopupWnd
= 0;
172 static UINT uSubPWndLevel
= 0;
174 /* Flag set by EndMenu() to force an exit from menu tracking */
175 static BOOL fEndMenu
= FALSE
;
178 /***********************************************************************
179 * debug_print_menuitem
181 * Print a menuitem in readable form.
184 #define debug_print_menuitem(pre, mp, post) \
185 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
187 #define MENUOUT(text) \
188 DPRINTF("%s%s", (count++ ? "," : ""), (text))
190 #define MENUFLAG(bit,text) \
192 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
195 static void do_debug_print_menuitem(const char *prefix
, MENUITEM
* mp
,
198 TRACE("%s ", prefix
);
200 UINT flags
= mp
->fType
;
201 int typ
= MENU_ITEM_TYPE(flags
);
202 DPRINTF( "{ ID=0x%x", mp
->wID
);
203 if (flags
& MF_POPUP
)
204 DPRINTF( ", Sub=0x%x", mp
->hSubMenu
);
208 if (typ
== MFT_STRING
)
210 else if (typ
== MFT_SEPARATOR
)
212 else if (typ
== MFT_OWNERDRAW
)
214 else if (typ
== MFT_BITMAP
)
220 MENUFLAG(MF_POPUP
, "pop");
221 MENUFLAG(MFT_MENUBARBREAK
, "barbrk");
222 MENUFLAG(MFT_MENUBREAK
, "brk");
223 MENUFLAG(MFT_RADIOCHECK
, "radio");
224 MENUFLAG(MFT_RIGHTORDER
, "rorder");
225 MENUFLAG(MF_SYSMENU
, "sys");
226 MENUFLAG(MFT_RIGHTJUSTIFY
, "right"); /* same as MF_HELP */
229 DPRINTF( "+0x%x", flags
);
234 DPRINTF( ", State=");
235 MENUFLAG(MFS_GRAYED
, "grey");
236 MENUFLAG(MFS_DEFAULT
, "default");
237 MENUFLAG(MFS_DISABLED
, "dis");
238 MENUFLAG(MFS_CHECKED
, "check");
239 MENUFLAG(MFS_HILITE
, "hi");
240 MENUFLAG(MF_USECHECKBITMAPS
, "usebit");
241 MENUFLAG(MF_MOUSESELECT
, "mouse");
243 DPRINTF( "+0x%x", flags
);
246 DPRINTF( ", Chk=0x%x", mp
->hCheckBit
);
248 DPRINTF( ", Unc=0x%x", mp
->hUnCheckBit
);
250 if (typ
== MFT_STRING
) {
252 DPRINTF( ", Text=\"%s\"", mp
->text
);
254 DPRINTF( ", Text=Null");
255 } else if (mp
->text
== NULL
)
258 DPRINTF( ", Text=%p", mp
->text
);
260 DPRINTF( ", ItemData=0x%08lx", mp
->dwItemData
);
266 DPRINTF(" %s\n", postfix
);
273 /***********************************************************************
276 * Validate the given menu handle and returns the menu structure pointer.
278 POPUPMENU
*MENU_GetMenu(HMENU hMenu
)
281 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
282 if (!IS_A_MENU(menu
))
284 WARN("invalid menu handle=%x, ptr=%p, magic=%x\n", hMenu
, menu
, menu
? menu
->wMagic
:0);
290 /***********************************************************************
293 * Return the default system menu.
295 static HMENU
MENU_CopySysPopup(void)
297 HMENU hMenu
= LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
300 POPUPMENU
* menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
301 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
302 SetMenuDefaultItem(hMenu
, SC_CLOSE
, FALSE
);
306 ERR("Unable to load default system menu\n" );
309 TRACE("returning %x.\n", hMenu
);
314 /***********************************************************************
315 * MENU_GetTopPopupWnd()
317 * Return the locked pointer pTopPopupWnd.
319 static WND
*MENU_GetTopPopupWnd()
321 return WIN_LockWndPtr(pTopPopupWnd
);
323 /***********************************************************************
324 * MENU_ReleaseTopPopupWnd()
326 * Realease the locked pointer pTopPopupWnd.
328 static void MENU_ReleaseTopPopupWnd()
330 WIN_ReleaseWndPtr(pTopPopupWnd
);
332 /***********************************************************************
333 * MENU_DestroyTopPopupWnd()
335 * Destroy the locked pointer pTopPopupWnd.
337 static void MENU_DestroyTopPopupWnd()
339 WND
*tmpWnd
= pTopPopupWnd
;
341 WIN_ReleaseWndPtr(tmpWnd
);
346 /**********************************************************************
349 * Create a copy of the system menu. System menu in Windows is
350 * a special menu-bar with the single entry - system menu popup.
351 * This popup is presented to the outside world as a "system menu".
352 * However, the real system menu handle is sometimes seen in the
353 * WM_MENUSELECT paramemters (and Word 6 likes it this way).
355 HMENU
MENU_GetSysMenu( HWND hWnd
, HMENU hPopupMenu
)
359 if ((hMenu
= CreateMenu()))
361 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
362 menu
->wFlags
= MF_SYSMENU
;
365 if (hPopupMenu
== (HMENU
)(-1))
366 hPopupMenu
= MENU_CopySysPopup();
367 else if( !hPopupMenu
) hPopupMenu
= MENU_DefSysPopup
;
371 InsertMenuA( hMenu
, -1, MF_SYSMENU
| MF_POPUP
| MF_BYPOSITION
, hPopupMenu
, NULL
);
373 menu
->items
[0].fType
= MF_SYSMENU
| MF_POPUP
;
374 menu
->items
[0].fState
= 0;
375 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hPopupMenu
);
376 menu
->wFlags
|= MF_SYSMENU
;
378 TRACE("GetSysMenu hMenu=%04x (%04x)\n", hMenu
, hPopupMenu
);
381 DestroyMenu( hMenu
);
383 ERR("failed to load system menu!\n");
388 /***********************************************************************
391 * Menus initialisation.
396 NONCLIENTMETRICSA ncm
;
398 static unsigned char shade_bits
[16] = { 0x55, 0, 0xAA, 0,
403 /* Load menu bitmaps */
404 hStdCheck
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CHECK
));
405 hStdRadioCheck
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_RADIOCHECK
));
406 hStdMnArrow
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW
));
407 /* Load system buttons bitmaps */
408 hBmpMinimize
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCE
));
409 hBmpMinimizeD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCED
));
410 hBmpMaximize
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORE
));
411 hBmpMaximizeD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORED
));
412 hBmpClose
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSE
));
413 hBmpCloseD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSED
));
418 GetObjectA( hStdCheck
, sizeof(bm
), &bm
);
419 check_bitmap_width
= bm
.bmWidth
;
420 check_bitmap_height
= bm
.bmHeight
;
424 /* Assume that radio checks have the same size as regular check. */
431 GetObjectA( hStdMnArrow
, sizeof(bm
), &bm
);
432 arrow_bitmap_width
= bm
.bmWidth
;
433 arrow_bitmap_height
= bm
.bmHeight
;
437 if (! (hBitmap
= CreateBitmap( 8, 8, 1, 1, shade_bits
)))
440 if(!(hShadeBrush
= CreatePatternBrush( hBitmap
)))
443 DeleteObject( hBitmap
);
444 if (!(MENU_DefSysPopup
= MENU_CopySysPopup()))
447 ncm
.cbSize
= sizeof (NONCLIENTMETRICSA
);
448 if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS
, sizeof(NONCLIENTMETRICSA
), &ncm
, 0)))
451 if (!(hMenuFont
= CreateFontIndirectA( &ncm
.lfMenuFont
)))
454 ncm
.lfMenuFont
.lfWeight
+= 300;
455 if ( ncm
.lfMenuFont
.lfWeight
> 1000)
456 ncm
.lfMenuFont
.lfWeight
= 1000;
458 if (!(hMenuFontBold
= CreateFontIndirectA( &ncm
.lfMenuFont
)))
464 /***********************************************************************
465 * MENU_InitSysMenuPopup
467 * Grey the appropriate items in System menu.
469 static void MENU_InitSysMenuPopup( HMENU hmenu
, DWORD style
, DWORD clsStyle
)
473 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
474 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
475 gray
= ((style
& WS_MAXIMIZE
) != 0);
476 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
477 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
478 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
479 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
480 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
481 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
482 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
483 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
485 /* The menu item must keep its state if it's disabled */
487 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
491 /******************************************************************************
493 * UINT MENU_GetStartOfNextColumn(
496 *****************************************************************************/
498 static UINT
MENU_GetStartOfNextColumn(
501 POPUPMENU
*menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
502 UINT i
= menu
->FocusedItem
+ 1;
505 return NO_SELECTED_ITEM
;
507 if( i
== NO_SELECTED_ITEM
)
510 for( ; i
< menu
->nItems
; ++i
) {
511 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
515 return NO_SELECTED_ITEM
;
519 /******************************************************************************
521 * UINT MENU_GetStartOfPrevColumn(
524 *****************************************************************************/
526 static UINT
MENU_GetStartOfPrevColumn(
529 POPUPMENU
const *menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
533 return NO_SELECTED_ITEM
;
535 if( menu
->FocusedItem
== 0 || menu
->FocusedItem
== NO_SELECTED_ITEM
)
536 return NO_SELECTED_ITEM
;
538 /* Find the start of the column */
540 for(i
= menu
->FocusedItem
; i
!= 0 &&
541 !(menu
->items
[i
].fType
& MF_MENUBARBREAK
);
545 return NO_SELECTED_ITEM
;
547 for(--i
; i
!= 0; --i
) {
548 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
552 TRACE("ret %d.\n", i
);
559 /***********************************************************************
562 * Find a menu item. Return a pointer on the item, and modifies *hmenu
563 * in case the item was in a sub-menu.
565 static MENUITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
570 if (((*hmenu
)==0xffff) || (!(menu
= MENU_GetMenu(*hmenu
)))) return NULL
;
571 if (wFlags
& MF_BYPOSITION
)
573 if (*nPos
>= menu
->nItems
) return NULL
;
574 return &menu
->items
[*nPos
];
578 MENUITEM
*item
= menu
->items
;
579 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
581 if (item
->wID
== *nPos
)
586 else if (item
->fType
& MF_POPUP
)
588 HMENU hsubmenu
= item
->hSubMenu
;
589 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
601 /***********************************************************************
604 * Find a Sub menu. Return the position of the submenu, and modifies
605 * *hmenu in case it is found in another sub-menu.
606 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
608 UINT
MENU_FindSubMenu( HMENU
*hmenu
, HMENU hSubTarget
)
613 if (((*hmenu
)==0xffff) ||
614 (!(menu
= MENU_GetMenu(*hmenu
))))
615 return NO_SELECTED_ITEM
;
617 for (i
= 0; i
< menu
->nItems
; i
++, item
++) {
618 if(!(item
->fType
& MF_POPUP
)) continue;
619 if (item
->hSubMenu
== hSubTarget
) {
623 HMENU hsubmenu
= item
->hSubMenu
;
624 UINT pos
= MENU_FindSubMenu( &hsubmenu
, hSubTarget
);
625 if (pos
!= NO_SELECTED_ITEM
) {
631 return NO_SELECTED_ITEM
;
634 /***********************************************************************
637 static void MENU_FreeItemData( MENUITEM
* item
)
640 if (IS_STRING_ITEM(item
->fType
) && item
->text
)
641 HeapFree( SystemHeap
, 0, item
->text
);
644 /***********************************************************************
645 * MENU_FindItemByCoords
647 * Find the item at the specified coordinates (screen coords). Does
648 * not work for child windows and therefore should not be called for
649 * an arbitrary system menu.
651 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
,
652 POINT pt
, UINT
*pos
)
658 if (!GetWindowRect(menu
->hWnd
,&wrect
)) return NULL
;
659 pt
.x
-= wrect
.left
;pt
.y
-= wrect
.top
;
661 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
663 if ((pt
.x
>= item
->rect
.left
) && (pt
.x
< item
->rect
.right
) &&
664 (pt
.y
>= item
->rect
.top
) && (pt
.y
< item
->rect
.bottom
))
674 /***********************************************************************
677 * Find the menu item selected by a key press.
678 * Return item id, -1 if none, -2 if we should close the menu.
680 static UINT
MENU_FindItemByKey( HWND hwndOwner
, HMENU hmenu
,
681 UINT key
, BOOL forceMenuChar
)
683 TRACE("\tlooking for '%c' in [%04x]\n", (char)key
, (UINT16
)hmenu
);
685 if (!IsMenu( hmenu
))
687 WND
* w
= WIN_FindWndPtr(hwndOwner
);
688 hmenu
= GetSubMenu(w
->hSysMenu
, 0);
689 WIN_ReleaseWndPtr(w
);
694 POPUPMENU
*menu
= MENU_GetMenu( hmenu
);
695 MENUITEM
*item
= menu
->items
;
703 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
705 if (item
->text
&& (IS_STRING_ITEM(item
->fType
)))
707 char *p
= item
->text
- 2;
710 p
= strchr (p
+ 2, '&');
712 while (p
!= NULL
&& p
[1] == '&');
713 if (p
&& (toupper(p
[1]) == key
)) return i
;
717 menuchar
= SendMessageA( hwndOwner
, WM_MENUCHAR
,
718 MAKEWPARAM( key
, menu
->wFlags
), hmenu
);
719 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
720 if (HIWORD(menuchar
) == 1) return (UINT
)(-2);
724 /***********************************************************************
727 * Load the bitmap associated with the magic menu item and its style
730 static HBITMAP
MENU_LoadMagicItem(UINT id
, BOOL hilite
, DWORD dwItemData
)
733 * Magic menu item id's section
734 * These magic id's are used by windows to insert "standard" mdi
735 * buttons (minimize,restore,close) on menu. Under windows,
736 * these magic id's make sure the right things appear when those
737 * bitmap buttons are pressed/selected/released.
741 { case HBMMENU_SYSTEM
:
742 return (dwItemData
) ?
743 (HBITMAP
)dwItemData
:
744 (hilite
? hBmpMinimizeD
: hBmpMinimize
);
745 case HBMMENU_MBAR_RESTORE
:
746 return (hilite
? hBmpMaximizeD
: hBmpMaximize
);
747 case HBMMENU_MBAR_MINIMIZE
:
748 return (hilite
? hBmpMinimizeD
: hBmpMinimize
);
749 case HBMMENU_MBAR_CLOSE
:
750 return (hilite
? hBmpCloseD
: hBmpClose
);
751 case HBMMENU_CALLBACK
:
752 case HBMMENU_MBAR_CLOSE_D
:
753 case HBMMENU_MBAR_MINIMIZE_D
:
754 case HBMMENU_POPUP_CLOSE
:
755 case HBMMENU_POPUP_RESTORE
:
756 case HBMMENU_POPUP_MAXIMIZE
:
757 case HBMMENU_POPUP_MINIMIZE
:
759 FIXME("Magic 0x%08x not implemented\n", id
);
765 /***********************************************************************
768 * Calculate the size of the menu item and store it in lpitem->rect.
770 static void MENU_CalcItemSize( HDC hdc
, MENUITEM
*lpitem
, HWND hwndOwner
,
771 INT orgX
, INT orgY
, BOOL menuBar
)
775 TRACE("dc=0x%04x owner=0x%04x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
776 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem
,
777 (menuBar
? " (MenuBar)" : ""));
779 SetRect( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
781 if (lpitem
->fType
& MF_OWNERDRAW
)
784 ** Experimentation under Windows reveals that an owner-drawn
785 ** menu is expected to return the size of the content part of
786 ** the menu item, not including the checkmark nor the submenu
787 ** arrow. Windows adds those values itself and returns the
788 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
790 MEASUREITEMSTRUCT mis
;
791 mis
.CtlType
= ODT_MENU
;
793 mis
.itemID
= lpitem
->wID
;
794 mis
.itemData
= (DWORD
)lpitem
->dwItemData
;
797 SendMessageA( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
798 lpitem
->rect
.right
+= mis
.itemWidth
;
802 lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
805 /* under at least win95 you seem to be given a standard
806 height for the menu and the height value is ignored */
808 if (TWEAK_WineLook
== WIN31_LOOK
)
809 lpitem
->rect
.bottom
+= GetSystemMetrics(SM_CYMENU
);
811 lpitem
->rect
.bottom
+= GetSystemMetrics(SM_CYMENU
)-1;
814 lpitem
->rect
.bottom
+= mis
.itemHeight
;
816 TRACE("id=%04x size=%dx%d\n",
817 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
818 /* Fall through to get check/arrow width calculation. */
821 if (lpitem
->fType
& MF_SEPARATOR
)
823 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
829 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
830 if (lpitem
->fType
& MF_POPUP
)
831 lpitem
->rect
.right
+= arrow_bitmap_width
;
834 if (lpitem
->fType
& MF_OWNERDRAW
)
837 if (IS_BITMAP_ITEM(lpitem
->fType
))
842 /* Check if there is a magic menu item associated with this item */
843 if((LOWORD((int)lpitem
->text
))<12)
845 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
, (lpitem
->fType
& MF_HILITE
),
849 resBmp
= (HBITMAP
)lpitem
->text
;
851 if (GetObjectA(resBmp
, sizeof(bm
), &bm
))
853 lpitem
->rect
.right
+= bm
.bmWidth
;
854 lpitem
->rect
.bottom
+= bm
.bmHeight
;
860 /* If we get here, then it must be a text item */
861 if (IS_STRING_ITEM( lpitem
->fType
))
864 GetTextExtentPoint32A(hdc
, lpitem
->text
, strlen(lpitem
->text
), &size
);
866 lpitem
->rect
.right
+= size
.cx
;
867 if (TWEAK_WineLook
== WIN31_LOOK
)
868 lpitem
->rect
.bottom
+= max( size
.cy
, GetSystemMetrics(SM_CYMENU
) );
870 lpitem
->rect
.bottom
+= max(size
.cy
, GetSystemMetrics(SM_CYMENU
)-1);
875 lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
877 else if ((p
= strchr( lpitem
->text
, '\t' )) != NULL
)
879 /* Item contains a tab (only meaningful in popup menus) */
880 GetTextExtentPoint32A(hdc
, lpitem
->text
, (int)(p
- lpitem
->text
) , &size
);
881 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+ size
.cx
;
882 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
886 if (strchr( lpitem
->text
, '\b' ))
887 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
888 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
889 - arrow_bitmap_width
;
892 TRACE("(%d,%d)-(%d,%d)\n", lpitem
->rect
.left
, lpitem
->rect
.top
, lpitem
->rect
.right
, lpitem
->rect
.bottom
);
896 /***********************************************************************
897 * MENU_PopupMenuCalcSize
899 * Calculate the size of a popup menu.
901 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND hwndOwner
)
906 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
908 lppop
->Width
= lppop
->Height
= 0;
909 if (lppop
->nItems
== 0) return;
912 SelectObject( hdc
, hMenuFont
);
915 maxX
= (TWEAK_WineLook
== WIN31_LOOK
) ? GetSystemMetrics(SM_CXBORDER
) : 2 ;
917 while (start
< lppop
->nItems
)
919 lpitem
= &lppop
->items
[start
];
921 orgY
= (TWEAK_WineLook
== WIN31_LOOK
) ? GetSystemMetrics(SM_CYBORDER
) : 2;
923 maxTab
= maxTabWidth
= 0;
925 /* Parse items until column break or end of menu */
926 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
929 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
931 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
933 if (lpitem
->fType
& MF_MENUBARBREAK
) orgX
++;
934 maxX
= max( maxX
, lpitem
->rect
.right
);
935 orgY
= lpitem
->rect
.bottom
;
936 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
938 maxTab
= max( maxTab
, lpitem
->xTab
);
939 maxTabWidth
= max(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
943 /* Finish the column (set all items to the largest width found) */
944 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
945 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
947 lpitem
->rect
.right
= maxX
;
948 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
949 lpitem
->xTab
= maxTab
;
952 lppop
->Height
= max( lppop
->Height
, orgY
);
957 /* space for 3d border */
958 if(TWEAK_WineLook
> WIN31_LOOK
)
968 /***********************************************************************
969 * MENU_MenuBarCalcSize
971 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
972 * height is off by 1 pixel which causes lengthy window relocations when
973 * active document window is maximized/restored.
975 * Calculate the size of the menu bar.
977 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
,
978 LPPOPUPMENU lppop
, HWND hwndOwner
)
981 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
983 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
984 if (lppop
->nItems
== 0) return;
985 TRACE("left=%d top=%d right=%d bottom=%d\n",
986 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
987 lppop
->Width
= lprect
->right
- lprect
->left
;
992 while (start
< lppop
->nItems
)
994 lpitem
= &lppop
->items
[start
];
998 /* Parse items until line break or end of menu */
999 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
1001 if ((helpPos
== -1) && (lpitem
->fType
& MF_HELP
)) helpPos
= i
;
1003 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1005 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
1007 debug_print_menuitem (" item: ", lpitem
, "");
1008 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
1010 if (lpitem
->rect
.right
> lprect
->right
)
1012 if (i
!= start
) break;
1013 else lpitem
->rect
.right
= lprect
->right
;
1015 maxY
= max( maxY
, lpitem
->rect
.bottom
);
1016 orgX
= lpitem
->rect
.right
;
1019 /* Finish the line (set all items to the largest height found) */
1020 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
1023 lprect
->bottom
= maxY
;
1024 lppop
->Height
= lprect
->bottom
- lprect
->top
;
1026 /* Flush right all magic items and items between the MF_HELP and */
1027 /* the last item (if several lines, only move the last line) */
1028 lpitem
= &lppop
->items
[lppop
->nItems
-1];
1029 orgY
= lpitem
->rect
.top
;
1030 orgX
= lprect
->right
;
1031 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--)
1033 if ( !IS_BITMAP_ITEM(lpitem
->fType
) && ((helpPos
==-1) ? TRUE
: (helpPos
>i
) ))
1035 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
1036 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
1037 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
1038 lpitem
->rect
.right
= orgX
;
1039 orgX
= lpitem
->rect
.left
;
1043 /***********************************************************************
1046 * Draw a single menu item.
1048 static void MENU_DrawMenuItem( HWND hwnd
, HMENU hmenu
, HWND hwndOwner
, HDC hdc
, MENUITEM
*lpitem
,
1049 UINT height
, BOOL menuBar
, UINT odaction
)
1053 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem
, "");
1055 if (lpitem
->fType
& MF_SYSMENU
)
1057 if( !IsIconic(hwnd
) ) {
1058 if (TWEAK_WineLook
> WIN31_LOOK
)
1059 NC_DrawSysButton95( hwnd
, hdc
,
1061 (MF_HILITE
| MF_MOUSESELECT
) );
1063 NC_DrawSysButton( hwnd
, hdc
,
1065 (MF_HILITE
| MF_MOUSESELECT
) );
1071 if (lpitem
->fType
& MF_OWNERDRAW
)
1074 ** Experimentation under Windows reveals that an owner-drawn
1075 ** menu is given the rectangle which includes the space it requested
1076 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1077 ** and a popup-menu arrow. This is the value of lpitem->rect.
1078 ** Windows will leave all drawing to the application except for
1079 ** the popup-menu arrow. Windows always draws that itself, after
1080 ** the menu owner has finished drawing.
1084 dis
.CtlType
= ODT_MENU
;
1086 dis
.itemID
= lpitem
->wID
;
1087 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1089 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1090 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
;
1091 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1092 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1093 dis
.hwndItem
= hmenu
;
1095 dis
.rcItem
= lpitem
->rect
;
1096 TRACE("Ownerdraw: owner=%04x itemID=%d, itemState=%d, itemAction=%d, "
1097 "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n", hwndOwner
,
1098 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1099 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1101 SendMessageA( hwndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
1102 /* Fall through to draw popup-menu arrow */
1105 TRACE("rect={%d,%d,%d,%d}\n", lpitem
->rect
.left
, lpitem
->rect
.top
,
1106 lpitem
->rect
.right
,lpitem
->rect
.bottom
);
1108 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1110 rect
= lpitem
->rect
;
1112 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1114 if ((lpitem
->fState
& MF_HILITE
) && !(IS_BITMAP_ITEM(lpitem
->fType
)))
1115 if ((menuBar
) && (TWEAK_WineLook
==WIN98_LOOK
))
1116 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1118 FillRect( hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
) );
1120 FillRect( hdc
, &rect
, GetSysColorBrush(COLOR_MENU
) );
1123 SetBkMode( hdc
, TRANSPARENT
);
1125 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1127 /* vertical separator */
1128 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1130 if (TWEAK_WineLook
> WIN31_LOOK
)
1134 rc
.bottom
= height
- 3;
1135 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1139 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1140 MoveToEx( hdc
, rect
.left
, 0, NULL
);
1141 LineTo( hdc
, rect
.left
, height
);
1145 /* horizontal separator */
1146 if (lpitem
->fType
& MF_SEPARATOR
)
1148 if (TWEAK_WineLook
> WIN31_LOOK
)
1153 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1154 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1158 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1159 MoveToEx( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2, NULL
);
1160 LineTo( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
1168 if ((lpitem
->fState
& MF_HILITE
) && !(IS_BITMAP_ITEM(lpitem
->fType
)) )
1170 if (lpitem
->fState
& MF_GRAYED
)
1171 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1173 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
1174 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
1178 if (lpitem
->fState
& MF_GRAYED
)
1179 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1181 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1182 SetBkColor( hdc
, GetSysColor( COLOR_MENU
) );
1185 /* helper lines for debugging */
1186 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1187 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1188 MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
1189 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1194 INT y
= rect
.top
+ rect
.bottom
;
1196 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1198 /* Draw the check mark
1201 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1204 if (lpitem
->fState
& MF_CHECKED
)
1206 HBITMAP bm
= lpitem
->hCheckBit
? lpitem
->hCheckBit
:
1207 ((lpitem
->fType
& MFT_RADIOCHECK
) ? hStdRadioCheck
: hStdCheck
);
1208 HDC hdcMem
= CreateCompatibleDC( hdc
);
1210 SelectObject( hdcMem
, bm
);
1211 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1212 check_bitmap_width
, check_bitmap_height
,
1213 hdcMem
, 0, 0, SRCCOPY
);
1216 else if (lpitem
->hUnCheckBit
)
1218 HDC hdcMem
= CreateCompatibleDC( hdc
);
1220 SelectObject( hdcMem
, lpitem
->hUnCheckBit
);
1221 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1222 check_bitmap_width
, check_bitmap_height
,
1223 hdcMem
, 0, 0, SRCCOPY
);
1228 /* Draw the popup-menu arrow */
1229 if (lpitem
->fType
& MF_POPUP
)
1231 HDC hdcMem
= CreateCompatibleDC( hdc
);
1232 HBITMAP hOrigBitmap
;
1234 hOrigBitmap
= SelectObject( hdcMem
, hStdMnArrow
);
1235 BitBlt( hdc
, rect
.right
- arrow_bitmap_width
- 1,
1236 (y
- arrow_bitmap_height
) / 2,
1237 arrow_bitmap_width
, arrow_bitmap_height
,
1238 hdcMem
, 0, 0, SRCCOPY
);
1239 SelectObject( hdcMem
, hOrigBitmap
);
1243 rect
.left
+= check_bitmap_width
;
1244 rect
.right
-= arrow_bitmap_width
;
1247 /* Done for owner-drawn */
1248 if (lpitem
->fType
& MF_OWNERDRAW
)
1251 /* Draw the item text or bitmap */
1252 if (IS_BITMAP_ITEM(lpitem
->fType
))
1257 HDC hdcMem
= CreateCompatibleDC( hdc
);
1260 * Check if there is a magic menu item associated with this item
1261 * and load the appropriate bitmap
1263 if((LOWORD((int)lpitem
->text
)) < 12)
1265 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
, (lpitem
->fState
& MF_HILITE
),
1266 lpitem
->dwItemData
);
1269 resBmp
= (HBITMAP
)lpitem
->text
;
1274 GetObjectA( resBmp
, sizeof(bm
), &bm
);
1276 SelectObject(hdcMem
,resBmp
);
1278 /* handle fontsize > bitmap_height */
1279 top
= ((rect
.bottom
-rect
.top
)>bm
.bmHeight
) ?
1280 rect
.top
+(rect
.bottom
-rect
.top
-bm
.bmHeight
)/2 : rect
.top
;
1282 BitBlt( hdc
, rect
.left
, top
, rect
.right
- rect
.left
,
1283 rect
.bottom
- rect
.top
, hdcMem
, 0, 0, SRCCOPY
);
1290 /* No bitmap - process text if present */
1291 else if (IS_STRING_ITEM(lpitem
->fType
))
1296 UINT uFormat
= (menuBar
) ?
1297 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
1298 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1300 if ( lpitem
->fState
& MFS_DEFAULT
)
1302 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
1307 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1308 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1309 i
= strlen( lpitem
->text
);
1313 for (i
= 0; lpitem
->text
[i
]; i
++)
1314 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
1318 if( !(TWEAK_WineLook
== WIN31_LOOK
) && (lpitem
->fState
& MF_GRAYED
))
1320 if (!(lpitem
->fState
& MF_HILITE
) )
1322 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1323 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1324 DrawTextA( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1325 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1327 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1330 DrawTextA( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1332 /* paint the shortcut text */
1333 if (lpitem
->text
[i
]) /* There's a tab or flush-right char */
1335 if (lpitem
->text
[i
] == '\t')
1337 rect
.left
= lpitem
->xTab
;
1338 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1342 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1345 if( !(TWEAK_WineLook
== WIN31_LOOK
) && (lpitem
->fState
& MF_GRAYED
))
1347 if (!(lpitem
->fState
& MF_HILITE
) )
1349 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1350 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1351 DrawTextA( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1352 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1354 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1356 DrawTextA( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1360 SelectObject (hdc
, hfontOld
);
1365 /***********************************************************************
1366 * MENU_DrawPopupMenu
1368 * Paint a popup menu.
1370 static void MENU_DrawPopupMenu( HWND hwnd
, HDC hdc
, HMENU hmenu
)
1372 HBRUSH hPrevBrush
= 0;
1375 TRACE("wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd
, hdc
, hmenu
);
1377 GetClientRect( hwnd
, &rect
);
1379 if(TWEAK_WineLook
== WIN31_LOOK
)
1381 rect
.bottom
-= POPUP_YSHADE
* GetSystemMetrics(SM_CYBORDER
);
1382 rect
.right
-= POPUP_XSHADE
* GetSystemMetrics(SM_CXBORDER
);
1385 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1386 && (SelectObject( hdc
, hMenuFont
)))
1390 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1392 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1398 /* draw 3-d shade */
1399 if(TWEAK_WineLook
== WIN31_LOOK
) {
1400 SelectObject( hdc
, hShadeBrush
);
1401 SetBkMode( hdc
, TRANSPARENT
);
1402 ropPrev
= SetROP2( hdc
, R2_MASKPEN
);
1404 i
= rect
.right
; /* why SetBrushOrg() doesn't? */
1405 PatBlt( hdc
, i
& 0xfffffffe,
1406 rect
.top
+ POPUP_YSHADE
*GetSystemMetrics(SM_CYBORDER
),
1407 i
%2 + POPUP_XSHADE
*GetSystemMetrics(SM_CXBORDER
),
1408 rect
.bottom
- rect
.top
, 0x00a000c9 );
1410 PatBlt( hdc
, rect
.left
+ POPUP_XSHADE
*GetSystemMetrics(SM_CXBORDER
),
1411 i
& 0xfffffffe,rect
.right
- rect
.left
,
1412 i
%2 + POPUP_YSHADE
*GetSystemMetrics(SM_CYBORDER
), 0x00a000c9 );
1413 SelectObject( hdc
, hPrevPen
);
1414 SelectObject( hdc
, hPrevBrush
);
1415 SetROP2( hdc
, ropPrev
);
1418 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1420 /* draw menu items */
1422 menu
= MENU_GetMenu( hmenu
);
1423 if (menu
&& menu
->nItems
)
1428 for (u
= menu
->nItems
, item
= menu
->items
; u
> 0; u
--, item
++)
1429 MENU_DrawMenuItem( hwnd
, hmenu
, menu
->hwndOwner
, hdc
, item
,
1430 menu
->Height
, FALSE
, ODA_DRAWENTIRE
);
1435 SelectObject( hdc
, hPrevBrush
);
1440 /***********************************************************************
1443 * Paint a menu bar. Returns the height of the menu bar.
1444 * called from [windows/nonclient.c]
1446 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1453 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1455 lppop
= MENU_GetMenu ((HMENU
)wndPtr
->wIDmenu
);
1456 if (lppop
== NULL
|| lprect
== NULL
)
1458 retvalue
= GetSystemMetrics(SM_CYMENU
);
1462 TRACE("(%04x, %p, %p)\n", hDC
, lprect
, lppop
);
1464 hfontOld
= SelectObject( hDC
, hMenuFont
);
1466 if (lppop
->Height
== 0)
1467 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
1469 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
1473 retvalue
= lppop
->Height
;
1477 FillRect(hDC
, lprect
, GetSysColorBrush(COLOR_MENU
) );
1479 if (TWEAK_WineLook
== WIN31_LOOK
)
1481 SelectObject( hDC
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1482 MoveToEx( hDC
, lprect
->left
, lprect
->bottom
, NULL
);
1483 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1487 SelectObject( hDC
, GetSysColorPen(COLOR_3DFACE
));
1488 MoveToEx( hDC
, lprect
->left
, lprect
->bottom
, NULL
);
1489 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1492 if (lppop
->nItems
== 0)
1494 retvalue
= GetSystemMetrics(SM_CYMENU
);
1498 for (i
= 0; i
< lppop
->nItems
; i
++)
1500 MENU_DrawMenuItem( hwnd
, (HMENU
)wndPtr
->wIDmenu
, hwnd
,
1501 hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
, ODA_DRAWENTIRE
);
1503 retvalue
= lppop
->Height
;
1507 SelectObject (hDC
, hfontOld
);
1509 WIN_ReleaseWndPtr(wndPtr
);
1513 /***********************************************************************
1514 * MENU_PatchResidentPopup
1516 BOOL
MENU_PatchResidentPopup( HQUEUE16 checkQueue
, WND
* checkWnd
)
1518 WND
*pTPWnd
= MENU_GetTopPopupWnd();
1524 TRACE("patching resident popup: %04x %04x [%04x %04x]\n",
1525 checkQueue
, checkWnd
? checkWnd
->hwndSelf
: 0, pTPWnd
->hmemTaskQ
,
1526 pTPWnd
->owner
? pTPWnd
->owner
->hwndSelf
: 0);
1528 switch( checkQueue
)
1530 case 0: /* checkWnd is the new popup owner */
1533 pTPWnd
->owner
= checkWnd
;
1534 if( pTPWnd
->hmemTaskQ
!= checkWnd
->hmemTaskQ
)
1535 hTask
= QUEUE_GetQueueTask( checkWnd
->hmemTaskQ
);
1539 case 0xFFFF: /* checkWnd is destroyed */
1540 if( pTPWnd
->owner
== checkWnd
)
1541 pTPWnd
->owner
= NULL
;
1542 MENU_ReleaseTopPopupWnd();
1545 default: /* checkQueue is exiting */
1546 if( pTPWnd
->hmemTaskQ
== checkQueue
)
1548 hTask
= QUEUE_GetQueueTask( pTPWnd
->hmemTaskQ
);
1549 hTask
= TASK_GetNextTask( hTask
);
1556 TDB
* task
= (TDB
*)GlobalLock16( hTask
);
1559 pTPWnd
->hInstance
= task
->hInstance
;
1560 pTPWnd
->hmemTaskQ
= task
->hQueue
;
1561 MENU_ReleaseTopPopupWnd();
1564 else WARN("failed to patch resident popup.\n");
1567 MENU_ReleaseTopPopupWnd();
1571 /***********************************************************************
1574 * Display a popup menu.
1576 static BOOL
MENU_ShowPopup( HWND hwndOwner
, HMENU hmenu
, UINT id
,
1577 INT x
, INT y
, INT xanchor
, INT yanchor
)
1580 WND
*wndOwner
= NULL
;
1582 TRACE("owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1583 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1585 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
1586 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1588 menu
->items
[menu
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1589 menu
->FocusedItem
= NO_SELECTED_ITEM
;
1592 /* store the owner for DrawItem*/
1593 menu
->hwndOwner
= hwndOwner
;
1595 if( (wndOwner
= WIN_FindWndPtr( hwndOwner
)) )
1599 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
1601 /* adjust popup menu pos so that it fits within the desktop */
1603 width
= menu
->Width
+ GetSystemMetrics(SM_CXBORDER
);
1604 height
= menu
->Height
+ GetSystemMetrics(SM_CYBORDER
);
1606 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1609 x
-= width
- xanchor
;
1610 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1611 x
= GetSystemMetrics(SM_CXSCREEN
) - width
;
1615 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1618 y
-= height
+ yanchor
;
1619 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1620 y
= GetSystemMetrics(SM_CYSCREEN
) - height
;
1624 if( TWEAK_WineLook
== WIN31_LOOK
)
1626 width
+= POPUP_XSHADE
* GetSystemMetrics(SM_CXBORDER
); /* add space for shading */
1627 height
+= POPUP_YSHADE
* GetSystemMetrics(SM_CYBORDER
);
1630 /* NOTE: In Windows, top menu popup is not owned. */
1631 if (!pTopPopupWnd
) /* create top level popup menu window */
1633 assert( uSubPWndLevel
== 0 );
1635 pTopPopupWnd
= WIN_FindWndPtr(CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1636 WS_POPUP
, x
, y
, width
, height
,
1637 hwndOwner
, 0, wndOwner
->hInstance
,
1641 WIN_ReleaseWndPtr(wndOwner
);
1644 menu
->hWnd
= pTopPopupWnd
->hwndSelf
;
1645 MENU_ReleaseTopPopupWnd();
1650 /* create a new window for the submenu */
1652 menu
->hWnd
= CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1653 WS_POPUP
, x
, y
, width
, height
,
1654 hwndOwner
, 0, wndOwner
->hInstance
,
1658 WIN_ReleaseWndPtr(wndOwner
);
1662 else /* top level popup menu window already exists */
1664 WND
*pTPWnd
= MENU_GetTopPopupWnd();
1665 menu
->hWnd
= pTPWnd
->hwndSelf
;
1667 MENU_PatchResidentPopup( 0, wndOwner
);
1668 SendMessageA( pTPWnd
->hwndSelf
, MM_SETMENUHANDLE
, (WPARAM16
)hmenu
, 0L);
1670 /* adjust its size */
1672 SetWindowPos( menu
->hWnd
, 0, x
, y
, width
, height
,
1673 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_NOREDRAW
);
1674 MENU_ReleaseTopPopupWnd();
1677 uSubPWndLevel
++; /* menu level counter */
1679 /* Display the window */
1681 SetWindowPos( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
1682 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1683 UpdateWindow( menu
->hWnd
);
1684 WIN_ReleaseWndPtr(wndOwner
);
1691 /***********************************************************************
1694 static void MENU_SelectItem( HWND hwndOwner
, HMENU hmenu
, UINT wIndex
,
1695 BOOL sendMenuSelect
, HMENU topmenu
)
1700 TRACE("owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1702 lppop
= MENU_GetMenu( hmenu
);
1703 if ((!lppop
) || (!lppop
->nItems
)) return;
1705 if (lppop
->FocusedItem
== wIndex
) return;
1706 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC( lppop
->hWnd
);
1707 else hdc
= GetDCEx( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1709 SelectObject( hdc
, hMenuFont
);
1711 /* Clear previous highlighted item */
1712 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1714 lppop
->items
[lppop
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1715 MENU_DrawMenuItem(lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,&lppop
->items
[lppop
->FocusedItem
],
1716 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
),
1720 /* Highlight new item (if any) */
1721 lppop
->FocusedItem
= wIndex
;
1722 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1724 if(!(lppop
->items
[wIndex
].fType
& MF_SEPARATOR
)) {
1725 lppop
->items
[wIndex
].fState
|= MF_HILITE
;
1726 MENU_DrawMenuItem( lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,
1727 &lppop
->items
[wIndex
], lppop
->Height
,
1728 !(lppop
->wFlags
& MF_POPUP
), ODA_SELECT
);
1732 MENUITEM
*ip
= &lppop
->items
[lppop
->FocusedItem
];
1733 SendMessageA( hwndOwner
, WM_MENUSELECT
,
1734 MAKELONG(ip
->fType
& MF_POPUP
? wIndex
: ip
->wID
,
1735 ip
->fType
| ip
->fState
| MF_MOUSESELECT
|
1736 (lppop
->wFlags
& MF_SYSMENU
)), hmenu
);
1739 else if (sendMenuSelect
) {
1742 if((pos
=MENU_FindSubMenu(&topmenu
, hmenu
))!=NO_SELECTED_ITEM
){
1743 POPUPMENU
*ptm
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( topmenu
);
1744 MENUITEM
*ip
= &ptm
->items
[pos
];
1745 SendMessageA( hwndOwner
, WM_MENUSELECT
, MAKELONG(pos
,
1746 ip
->fType
| ip
->fState
| MF_MOUSESELECT
|
1747 (ptm
->wFlags
& MF_SYSMENU
)), topmenu
);
1751 ReleaseDC( lppop
->hWnd
, hdc
);
1755 /***********************************************************************
1756 * MENU_MoveSelection
1758 * Moves currently selected item according to the offset parameter.
1759 * If there is no selection then it should select the last item if
1760 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1762 static void MENU_MoveSelection( HWND hwndOwner
, HMENU hmenu
, INT offset
)
1767 TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner
, hmenu
, offset
);
1769 menu
= MENU_GetMenu( hmenu
);
1770 if ((!menu
) || (!menu
->items
)) return;
1772 if ( menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1774 if( menu
->nItems
== 1 ) return; else
1775 for (i
= menu
->FocusedItem
+ offset
; i
>= 0 && i
< menu
->nItems
1777 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1779 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
1784 for ( i
= (offset
> 0) ? 0 : menu
->nItems
- 1;
1785 i
>= 0 && i
< menu
->nItems
; i
+= offset
)
1786 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1788 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
1794 /**********************************************************************
1797 * Set an item flags, id and text ptr. Called by InsertMenu() and
1800 static BOOL
MENU_SetItemData( MENUITEM
*item
, UINT flags
, UINT id
,
1803 LPSTR prevText
= IS_STRING_ITEM(item
->fType
) ? item
->text
: NULL
;
1805 debug_print_menuitem("MENU_SetItemData from: ", item
, "");
1807 if (IS_STRING_ITEM(flags
))
1811 flags
|= MF_SEPARATOR
;
1817 /* Item beginning with a backspace is a help item */
1823 if (!(text
= HEAP_strdupA( SystemHeap
, 0, str
))) return FALSE
;
1827 else if (IS_BITMAP_ITEM(flags
))
1828 item
->text
= (LPSTR
)(HBITMAP
)LOWORD(str
);
1829 else item
->text
= NULL
;
1831 if (flags
& MF_OWNERDRAW
)
1832 item
->dwItemData
= (DWORD
)str
;
1834 item
->dwItemData
= 0;
1836 if ((item
->fType
& MF_POPUP
) && (flags
& MF_POPUP
) && (item
->hSubMenu
!= id
) )
1837 DestroyMenu( item
->hSubMenu
); /* ModifyMenu() spec */
1839 if (flags
& MF_POPUP
)
1841 POPUPMENU
*menu
= MENU_GetMenu((UINT16
)id
);
1842 if (menu
) menu
->wFlags
|= MF_POPUP
;
1854 if (flags
& MF_POPUP
)
1855 item
->hSubMenu
= id
;
1857 if ((item
->fType
& MF_POPUP
) && !(flags
& MF_POPUP
) )
1858 flags
|= MF_POPUP
; /* keep popup */
1860 item
->fType
= flags
& TYPE_MASK
;
1861 item
->fState
= (flags
& STATE_MASK
) &
1862 ~(MF_HILITE
| MF_MOUSESELECT
| MF_BYPOSITION
);
1865 /* Don't call SetRectEmpty here! */
1868 if (prevText
) HeapFree( SystemHeap
, 0, prevText
);
1870 debug_print_menuitem("MENU_SetItemData to : ", item
, "");
1875 /**********************************************************************
1878 * Insert a new item into a menu.
1880 static MENUITEM
*MENU_InsertItem( HMENU hMenu
, UINT pos
, UINT flags
)
1885 if (!(menu
= MENU_GetMenu(hMenu
)))
1888 /* Find where to insert new item */
1890 if (flags
& MF_BYPOSITION
) {
1891 if (pos
> menu
->nItems
)
1894 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
1897 if (!(menu
= MENU_GetMenu( hMenu
)))
1902 /* Create new items array */
1904 newItems
= HeapAlloc( SystemHeap
, 0, sizeof(MENUITEM
) * (menu
->nItems
+1) );
1907 WARN("allocation failed\n" );
1910 if (menu
->nItems
> 0)
1912 /* Copy the old array into the new */
1913 if (pos
> 0) memcpy( newItems
, menu
->items
, pos
* sizeof(MENUITEM
) );
1914 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &menu
->items
[pos
],
1915 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
1916 HeapFree( SystemHeap
, 0, menu
->items
);
1918 menu
->items
= newItems
;
1920 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
1921 menu
->Height
= 0; /* force size recalculate */
1922 return &newItems
[pos
];
1926 /**********************************************************************
1927 * MENU_ParseResource
1929 * Parse a standard menu resource and add items to the menu.
1930 * Return a pointer to the end of the resource.
1932 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1939 flags
= GET_WORD(res
);
1940 res
+= sizeof(WORD
);
1941 if (!(flags
& MF_POPUP
))
1944 res
+= sizeof(WORD
);
1946 if (!IS_STRING_ITEM(flags
))
1947 ERR("not a string item %04x\n", flags
);
1949 if (!unicode
) res
+= strlen(str
) + 1;
1950 else res
+= (lstrlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1951 if (flags
& MF_POPUP
)
1953 HMENU hSubMenu
= CreatePopupMenu();
1954 if (!hSubMenu
) return NULL
;
1955 if (!(res
= MENU_ParseResource( res
, hSubMenu
, unicode
)))
1957 if (!unicode
) AppendMenuA( hMenu
, flags
, (UINT
)hSubMenu
, str
);
1958 else AppendMenuW( hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
1960 else /* Not a popup */
1962 if (!unicode
) AppendMenuA( hMenu
, flags
, id
, *str
? str
: NULL
);
1963 else AppendMenuW( hMenu
, flags
, id
,
1964 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1966 } while (!(flags
& MF_END
));
1971 /**********************************************************************
1972 * MENUEX_ParseResource
1974 * Parse an extended menu resource and add items to the menu.
1975 * Return a pointer to the end of the resource.
1977 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
1983 mii
.cbSize
= sizeof(mii
);
1984 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
1985 mii
.fType
= GET_DWORD(res
);
1986 res
+= sizeof(DWORD
);
1987 mii
.fState
= GET_DWORD(res
);
1988 res
+= sizeof(DWORD
);
1989 mii
.wID
= GET_DWORD(res
);
1990 res
+= sizeof(DWORD
);
1991 resinfo
= GET_WORD(res
); /* FIXME: for 16-bit apps this is a byte. */
1992 res
+= sizeof(WORD
);
1993 /* Align the text on a word boundary. */
1994 res
+= (~((int)res
- 1)) & 1;
1995 mii
.dwTypeData
= (LPWSTR
) res
;
1996 res
+= (1 + lstrlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
1997 /* Align the following fields on a dword boundary. */
1998 res
+= (~((int)res
- 1)) & 3;
2000 /* FIXME: This is inefficient and cannot be optimised away by gcc. */
2002 LPSTR newstr
= HEAP_strdupWtoA(GetProcessHeap(),
2004 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
2005 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, newstr
);
2006 HeapFree( GetProcessHeap(), 0, newstr
);
2009 if (resinfo
& 1) { /* Pop-up? */
2010 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2011 res
+= sizeof(DWORD
);
2012 mii
.hSubMenu
= CreatePopupMenu();
2015 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
2016 DestroyMenu(mii
.hSubMenu
);
2019 mii
.fMask
|= MIIM_SUBMENU
;
2020 mii
.fType
|= MF_POPUP
;
2022 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
2023 } while (!(resinfo
& MF_END
));
2028 /***********************************************************************
2031 * Return the handle of the selected sub-popup menu (if any).
2033 static HMENU
MENU_GetSubPopup( HMENU hmenu
)
2038 menu
= MENU_GetMenu( hmenu
);
2040 if ((!menu
) || (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return 0;
2042 item
= &menu
->items
[menu
->FocusedItem
];
2043 if ((item
->fType
& MF_POPUP
) && (item
->fState
& MF_MOUSESELECT
))
2044 return item
->hSubMenu
;
2049 /***********************************************************************
2050 * MENU_HideSubPopups
2052 * Hide the sub-popup menus of this menu.
2054 static void MENU_HideSubPopups( HWND hwndOwner
, HMENU hmenu
,
2055 BOOL sendMenuSelect
)
2057 POPUPMENU
*menu
= MENU_GetMenu( hmenu
);
2059 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner
, hmenu
, sendMenuSelect
);
2061 if (menu
&& uSubPWndLevel
)
2067 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
2069 item
= &menu
->items
[menu
->FocusedItem
];
2070 if (!(item
->fType
& MF_POPUP
) ||
2071 !(item
->fState
& MF_MOUSESELECT
)) return;
2072 item
->fState
&= ~MF_MOUSESELECT
;
2073 hsubmenu
= item
->hSubMenu
;
2076 submenu
= MENU_GetMenu( hsubmenu
);
2077 MENU_HideSubPopups( hwndOwner
, hsubmenu
, FALSE
);
2078 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, sendMenuSelect
, 0 );
2080 if (submenu
->hWnd
== MENU_GetTopPopupWnd()->hwndSelf
)
2082 ShowWindow( submenu
->hWnd
, SW_HIDE
);
2087 DestroyWindow( submenu
->hWnd
);
2090 MENU_ReleaseTopPopupWnd();
2095 /***********************************************************************
2098 * Display the sub-menu of the selected item of this menu.
2099 * Return the handle of the submenu, or hmenu if no submenu to display.
2101 static HMENU
MENU_ShowSubPopup( HWND hwndOwner
, HMENU hmenu
,
2102 BOOL selectFirst
, UINT wFlags
)
2110 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner
, hmenu
, selectFirst
);
2112 if (!(menu
= MENU_GetMenu( hmenu
))) return hmenu
;
2114 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
)) ||
2115 (menu
->FocusedItem
== NO_SELECTED_ITEM
))
2117 WIN_ReleaseWndPtr(wndPtr
);
2121 item
= &menu
->items
[menu
->FocusedItem
];
2122 if (!(item
->fType
& MF_POPUP
) ||
2123 (item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
2125 WIN_ReleaseWndPtr(wndPtr
);
2129 /* message must be send before using item,
2130 because nearly everything may by changed by the application ! */
2132 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2133 if (!(wFlags
& TPM_NONOTIFY
))
2134 SendMessageA( hwndOwner
, WM_INITMENUPOPUP
, item
->hSubMenu
,
2135 MAKELONG( menu
->FocusedItem
, IS_SYSTEM_MENU(menu
) ));
2137 item
= &menu
->items
[menu
->FocusedItem
];
2140 /* correct item if modified as a reaction to WM_INITMENUPOPUP-message */
2141 if (!(item
->fState
& MF_HILITE
))
2143 if (menu
->wFlags
& MF_POPUP
) hdc
= GetDC( menu
->hWnd
);
2144 else hdc
= GetDCEx( menu
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2146 SelectObject( hdc
, hMenuFont
);
2148 item
->fState
|= MF_HILITE
;
2149 MENU_DrawMenuItem( menu
->hWnd
, hmenu
, hwndOwner
, hdc
, item
, menu
->Height
, !(menu
->wFlags
& MF_POPUP
), ODA_DRAWENTIRE
);
2150 ReleaseDC( menu
->hWnd
, hdc
);
2152 if (!item
->rect
.top
&& !item
->rect
.left
&& !item
->rect
.bottom
&& !item
->rect
.right
)
2155 item
->fState
|= MF_MOUSESELECT
;
2157 if (IS_SYSTEM_MENU(menu
))
2159 MENU_InitSysMenuPopup(item
->hSubMenu
, wndPtr
->dwStyle
, GetClassLongA(wndPtr
->hwndSelf
, GCL_STYLE
));
2161 NC_GetSysPopupPos( wndPtr
, &rect
);
2162 rect
.top
= rect
.bottom
;
2163 rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2164 rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2168 if (menu
->wFlags
& MF_POPUP
)
2170 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2171 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.top
;
2172 rect
.right
= item
->rect
.left
- item
->rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2173 rect
.bottom
= item
->rect
.top
- item
->rect
.bottom
;
2177 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.left
;
2178 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.bottom
;
2179 rect
.right
= item
->rect
.right
- item
->rect
.left
;
2180 rect
.bottom
= item
->rect
.bottom
- item
->rect
.top
;
2184 MENU_ShowPopup( hwndOwner
, item
->hSubMenu
, menu
->FocusedItem
,
2185 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2187 MENU_MoveSelection( hwndOwner
, item
->hSubMenu
, ITEM_NEXT
);
2188 WIN_ReleaseWndPtr(wndPtr
);
2189 return item
->hSubMenu
;
2194 /**********************************************************************
2197 BOOL
MENU_IsMenuActive(void)
2199 return pTopPopupWnd
&& (pTopPopupWnd
->dwStyle
& WS_VISIBLE
);
2202 /***********************************************************************
2205 * Walks menu chain trying to find a menu pt maps to.
2207 static HMENU
MENU_PtMenu( HMENU hMenu
, POINT16 pt
)
2209 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2210 register UINT ht
= menu
->FocusedItem
;
2212 /* try subpopup first (if any) */
2213 ht
= (ht
!= NO_SELECTED_ITEM
&&
2214 (menu
->items
[ht
].fType
& MF_POPUP
) &&
2215 (menu
->items
[ht
].fState
& MF_MOUSESELECT
))
2216 ? (UINT
) MENU_PtMenu(menu
->items
[ht
].hSubMenu
, pt
) : 0;
2218 if( !ht
) /* check the current window (avoiding WM_HITTEST) */
2220 ht
= (UINT
)NC_HandleNCHitTest( menu
->hWnd
, pt
);
2221 if( menu
->wFlags
& MF_POPUP
)
2222 ht
= (ht
!= (UINT
)HTNOWHERE
&&
2223 ht
!= (UINT
)HTERROR
) ? (UINT
)hMenu
: 0;
2226 WND
* wndPtr
= WIN_FindWndPtr(menu
->hWnd
);
2228 ht
= ( ht
== HTSYSMENU
) ? (UINT
)(wndPtr
->hSysMenu
)
2229 : ( ht
== HTMENU
) ? (UINT
)(wndPtr
->wIDmenu
) : 0;
2230 WIN_ReleaseWndPtr(wndPtr
);
2236 /***********************************************************************
2237 * MENU_ExecFocusedItem
2239 * Execute a menu item (for instance when user pressed Enter).
2240 * Return the wID of the executed item. Otherwise, -1 indicating
2241 * that no menu item was executed;
2242 * Have to receive the flags for the TrackPopupMenu options to avoid
2243 * sending unwanted message.
2246 static INT
MENU_ExecFocusedItem( MTRACKER
* pmt
, HMENU hMenu
, UINT wFlags
)
2249 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2251 TRACE("%p hmenu=0x%04x\n", pmt
, hMenu
);
2253 if (!menu
|| !menu
->nItems
||
2254 (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return -1;
2256 item
= &menu
->items
[menu
->FocusedItem
];
2258 TRACE("%08x %08x %08x\n",
2259 hMenu
, item
->wID
, item
->hSubMenu
);
2261 if (!(item
->fType
& MF_POPUP
))
2263 if (!(item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
2265 /* If TPM_RETURNCMD is set you return the id, but
2266 do not send a message to the owner */
2267 if(!(wFlags
& TPM_RETURNCMD
))
2269 if( menu
->wFlags
& MF_SYSMENU
)
2270 PostMessageA( pmt
->hOwnerWnd
, WM_SYSCOMMAND
, item
->wID
,
2271 MAKELPARAM((INT16
)pmt
->pt
.x
, (INT16
)pmt
->pt
.y
) );
2273 PostMessageA( pmt
->hOwnerWnd
, WM_COMMAND
, item
->wID
, 0 );
2279 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hMenu
, TRUE
, wFlags
);
2284 /***********************************************************************
2285 * MENU_SwitchTracking
2287 * Helper function for menu navigation routines.
2289 static void MENU_SwitchTracking( MTRACKER
* pmt
, HMENU hPtMenu
, UINT id
)
2291 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2292 POPUPMENU
*topmenu
= MENU_GetMenu( pmt
->hTopMenu
);
2294 TRACE("%p hmenu=0x%04x 0x%04x\n", pmt
, hPtMenu
, id
);
2296 if( pmt
->hTopMenu
!= hPtMenu
&&
2297 !((ptmenu
->wFlags
| topmenu
->wFlags
) & MF_POPUP
) )
2299 /* both are top level menus (system and menu-bar) */
2300 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2301 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
2302 pmt
->hTopMenu
= hPtMenu
;
2304 else MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
2305 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, id
, TRUE
, 0 );
2309 /***********************************************************************
2312 * Return TRUE if we can go on with menu tracking.
2314 static BOOL
MENU_ButtonDown( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2316 TRACE("%p hmenu=0x%04x\n", pmt
, hPtMenu
);
2321 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2324 if( IS_SYSTEM_MENU(ptmenu
) )
2325 item
= ptmenu
->items
;
2327 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2331 if( ptmenu
->FocusedItem
!= id
)
2332 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2334 /* If the popup menu is not already "popped" */
2335 if(!(item
->fState
& MF_MOUSESELECT
))
2337 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2339 /* In win31, a newly popped menu always remain opened for the next buttonup */
2340 if(TWEAK_WineLook
== WIN31_LOOK
)
2341 ptmenu
->bTimeToHide
= FALSE
;
2346 /* Else the click was on the menu bar, finish the tracking */
2351 /***********************************************************************
2354 * Return the value of MENU_ExecFocusedItem if
2355 * the selected item was not a popup. Else open the popup.
2356 * A -1 return value indicates that we go on with menu tracking.
2359 static INT
MENU_ButtonUp( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2361 TRACE("%p hmenu=0x%04x\n", pmt
, hPtMenu
);
2366 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2369 if( IS_SYSTEM_MENU(ptmenu
) )
2370 item
= ptmenu
->items
;
2372 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2374 if( item
&& (ptmenu
->FocusedItem
== id
))
2376 if( !(item
->fType
& MF_POPUP
) )
2377 return MENU_ExecFocusedItem( pmt
, hPtMenu
, wFlags
);
2379 /* If we are dealing with the top-level menu and that this */
2380 /* is a click on an already "poppped" item */
2381 /* Stop the menu tracking and close the opened submenus */
2382 if((pmt
->hTopMenu
== hPtMenu
) && (ptmenu
->bTimeToHide
== TRUE
))
2385 ptmenu
->bTimeToHide
= TRUE
;
2391 /***********************************************************************
2394 * Return TRUE if we can go on with menu tracking.
2396 static BOOL
MENU_MouseMove( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2398 UINT id
= NO_SELECTED_ITEM
;
2399 POPUPMENU
*ptmenu
= NULL
;
2403 ptmenu
= MENU_GetMenu( hPtMenu
);
2404 if( IS_SYSTEM_MENU(ptmenu
) )
2407 MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2410 if( id
== NO_SELECTED_ITEM
)
2412 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2413 NO_SELECTED_ITEM
, TRUE
, pmt
->hTopMenu
);
2416 else if( ptmenu
->FocusedItem
!= id
)
2418 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2419 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2425 /***********************************************************************
2428 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2430 static LRESULT
MENU_DoNextMenu( MTRACKER
* pmt
, UINT vk
)
2432 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2434 if( (vk
== VK_LEFT
&& menu
->FocusedItem
== 0 ) ||
2435 (vk
== VK_RIGHT
&& menu
->FocusedItem
== menu
->nItems
- 1))
2441 LRESULT l
= SendMessageA( pmt
->hOwnerWnd
, WM_NEXTMENU
, vk
,
2442 (IS_SYSTEM_MENU(menu
)) ? GetSubMenu16(pmt
->hTopMenu
,0) : pmt
->hTopMenu
);
2444 TRACE("%04x [%04x] -> %04x [%04x]\n",
2445 (UINT16
)pmt
->hCurrentMenu
, (UINT16
)pmt
->hOwnerWnd
, LOWORD(l
), HIWORD(l
) );
2449 wndPtr
= WIN_FindWndPtr(pmt
->hOwnerWnd
);
2451 hNewWnd
= pmt
->hOwnerWnd
;
2452 if( IS_SYSTEM_MENU(menu
) )
2454 /* switch to the menu bar */
2456 if( wndPtr
->dwStyle
& WS_CHILD
|| !wndPtr
->wIDmenu
)
2458 WIN_ReleaseWndPtr(wndPtr
);
2462 hNewMenu
= wndPtr
->wIDmenu
;
2465 menu
= MENU_GetMenu( hNewMenu
);
2466 id
= menu
->nItems
- 1;
2469 else if( wndPtr
->dwStyle
& WS_SYSMENU
)
2471 /* switch to the system menu */
2472 hNewMenu
= wndPtr
->hSysMenu
;
2476 WIN_ReleaseWndPtr(wndPtr
);
2479 WIN_ReleaseWndPtr(wndPtr
);
2481 else /* application returned a new menu to switch to */
2483 hNewMenu
= LOWORD(l
); hNewWnd
= HIWORD(l
);
2485 if( IsMenu(hNewMenu
) && IsWindow(hNewWnd
) )
2487 wndPtr
= WIN_FindWndPtr(hNewWnd
);
2489 if( wndPtr
->dwStyle
& WS_SYSMENU
&&
2490 GetSubMenu16(wndPtr
->hSysMenu
, 0) == hNewMenu
)
2492 /* get the real system menu */
2493 hNewMenu
= wndPtr
->hSysMenu
;
2495 else if( wndPtr
->dwStyle
& WS_CHILD
|| wndPtr
->wIDmenu
!= hNewMenu
)
2497 /* FIXME: Not sure what to do here, perhaps,
2498 * try to track hNewMenu as a popup? */
2500 TRACE(" -- got confused.\n");
2501 WIN_ReleaseWndPtr(wndPtr
);
2504 WIN_ReleaseWndPtr(wndPtr
);
2509 if( hNewMenu
!= pmt
->hTopMenu
)
2511 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
,
2513 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2514 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2517 if( hNewWnd
!= pmt
->hOwnerWnd
)
2520 pmt
->hOwnerWnd
= hNewWnd
;
2521 EVENT_Capture( pmt
->hOwnerWnd
, HTMENU
);
2524 pmt
->hTopMenu
= pmt
->hCurrentMenu
= hNewMenu
; /* all subpopups are hidden */
2525 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, id
, TRUE
, 0 );
2532 /***********************************************************************
2535 * The idea is not to show the popup if the next input message is
2536 * going to hide it anyway.
2538 static BOOL
MENU_SuspendPopup( MTRACKER
* pmt
, UINT16 uMsg
)
2542 msg
.hwnd
= pmt
->hOwnerWnd
;
2544 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2545 pmt
->trackFlags
|= TF_SKIPREMOVE
;
2550 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2551 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
2553 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2554 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2555 if( msg
.message
== WM_KEYDOWN
&&
2556 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
2558 pmt
->trackFlags
|= TF_SUSPENDPOPUP
;
2565 /* failures go through this */
2566 pmt
->trackFlags
&= ~TF_SUSPENDPOPUP
;
2570 /***********************************************************************
2573 * Handle a VK_LEFT key event in a menu.
2575 static void MENU_KeyLeft( MTRACKER
* pmt
, UINT wFlags
)
2578 HMENU hmenutmp
, hmenuprev
;
2581 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
2582 menu
= MENU_GetMenu( hmenutmp
);
2584 /* Try to move 1 column left (if possible) */
2585 if( (prevcol
= MENU_GetStartOfPrevColumn( pmt
->hCurrentMenu
)) !=
2586 NO_SELECTED_ITEM
) {
2588 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2593 /* close topmost popup */
2594 while (hmenutmp
!= pmt
->hCurrentMenu
)
2596 hmenuprev
= hmenutmp
;
2597 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
2600 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
);
2601 pmt
->hCurrentMenu
= hmenuprev
;
2603 if ( (hmenuprev
== pmt
->hTopMenu
) && !(menu
->wFlags
& MF_POPUP
) )
2605 /* move menu bar selection if no more popups are left */
2607 if( !MENU_DoNextMenu( pmt
, VK_LEFT
) )
2608 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_PREV
);
2610 if ( hmenuprev
!= hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2612 /* A sublevel menu was displayed - display the next one
2613 * unless there is another displacement coming up */
2615 if( !MENU_SuspendPopup( pmt
, WM_KEYDOWN
) )
2616 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2617 pmt
->hTopMenu
, TRUE
, wFlags
);
2623 /***********************************************************************
2626 * Handle a VK_RIGHT key event in a menu.
2628 static void MENU_KeyRight( MTRACKER
* pmt
, UINT wFlags
)
2631 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2634 TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2636 (MENU_GetMenu(pmt
->hCurrentMenu
))->
2638 pmt
->hTopMenu
, menu
->items
[0].text
);
2640 if ( (menu
->wFlags
& MF_POPUP
) || (pmt
->hCurrentMenu
!= pmt
->hTopMenu
))
2642 /* If already displaying a popup, try to display sub-popup */
2644 hmenutmp
= pmt
->hCurrentMenu
;
2645 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hmenutmp
, TRUE
, wFlags
);
2647 /* if subpopup was displayed then we are done */
2648 if (hmenutmp
!= pmt
->hCurrentMenu
) return;
2651 /* Check to see if there's another column */
2652 if( (nextcol
= MENU_GetStartOfNextColumn( pmt
->hCurrentMenu
)) !=
2653 NO_SELECTED_ITEM
) {
2654 TRACE("Going to %d.\n", nextcol
);
2655 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2660 if (!(menu
->wFlags
& MF_POPUP
)) /* menu bar tracking */
2662 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2664 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2665 hmenutmp
= pmt
->hCurrentMenu
= pmt
->hTopMenu
;
2666 } else hmenutmp
= 0;
2668 /* try to move to the next item */
2669 if( !MENU_DoNextMenu( pmt
, VK_RIGHT
) )
2670 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_NEXT
);
2672 if( hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2673 if( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
2674 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2675 pmt
->hTopMenu
, TRUE
, wFlags
);
2679 /***********************************************************************
2682 * Menu tracking code.
2684 static INT
MENU_TrackMenu( HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
2685 HWND hwnd
, const RECT
*lprect
)
2690 INT executedMenuId
= -1;
2692 BOOL enterIdleSent
= FALSE
;
2695 mt
.hCurrentMenu
= hmenu
;
2696 mt
.hTopMenu
= hmenu
;
2697 mt
.hOwnerWnd
= hwnd
;
2701 TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2702 hmenu
, wFlags
, x
, y
, hwnd
, (lprect
) ? lprect
->left
: 0, (lprect
) ? lprect
->top
: 0,
2703 (lprect
) ? lprect
->right
: 0, (lprect
) ? lprect
->bottom
: 0);
2706 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
2708 if (wFlags
& TPM_BUTTONDOWN
)
2710 /* Get the result in order to start the tracking or not */
2711 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
2712 fEndMenu
= !fRemove
;
2715 EVENT_Capture( mt
.hOwnerWnd
, HTMENU
);
2719 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
2720 msg
.hwnd
= (wFlags
& TPM_ENTERIDLEEX
&& menu
->wFlags
& MF_POPUP
) ? menu
->hWnd
: 0;
2722 /* we have to keep the message in the queue until it's
2723 * clear that menu loop is not over yet. */
2725 if (!MSG_InternalGetMessage( QMSG_WIN32A
, &msg
, msg
.hwnd
, mt
.hOwnerWnd
,
2726 MSGF_MENU
, PM_NOREMOVE
, !enterIdleSent
, &enterIdleSent
)) break;
2728 /* check if EndMenu() tried to cancel us, by posting this message */
2729 if(msg
.message
== WM_CANCELMODE
)
2731 /* we are now out of the loop */
2734 /* remove the message from the queue */
2735 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2737 /* break out of internal loop, ala ESCAPE */
2741 TranslateMessage( &msg
);
2744 if ( (msg
.hwnd
==menu
->hWnd
) || (msg
.message
!=WM_TIMER
) )
2745 enterIdleSent
=FALSE
;
2748 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
2750 /* Find a menu for this mouse event */
2752 CONV_POINT32TO16( &msg
.pt
, &pt16
);
2753 hmenu
= MENU_PtMenu( mt
.hTopMenu
, pt16
);
2757 /* no WM_NC... messages in captured state */
2759 case WM_RBUTTONDBLCLK
:
2760 case WM_RBUTTONDOWN
:
2761 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2763 case WM_LBUTTONDBLCLK
:
2764 case WM_LBUTTONDOWN
:
2765 /* If the message belongs to the menu, removes it from the queue */
2766 /* Else, end menu tracking */
2767 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
2768 fEndMenu
= !fRemove
;
2772 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2775 /* Check if a menu was selected by the mouse */
2778 executedMenuId
= MENU_ButtonUp( &mt
, hmenu
, wFlags
);
2780 /* End the loop if executedMenuId is an item ID */
2781 /* or if the job was done (executedMenuId = 0). */
2782 fEndMenu
= fRemove
= (executedMenuId
!= -1);
2784 /* No menu was selected by the mouse */
2785 /* if the function was called by TrackPopupMenu, continue
2786 with the menu tracking. If not, stop it */
2788 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
2793 /* In win95 winelook, the selected menu item must be changed every time the
2794 mouse moves. In Win31 winelook, the mouse button has to be held down */
2796 if ( (TWEAK_WineLook
> WIN31_LOOK
) ||
2797 ( (msg
.wParam
& MK_LBUTTON
) ||
2798 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
.wParam
& MK_RBUTTON
))) )
2800 fEndMenu
|= !MENU_MouseMove( &mt
, hmenu
, wFlags
);
2802 } /* switch(msg.message) - mouse */
2804 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
2806 fRemove
= TRUE
; /* Keyboard messages are always removed */
2814 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2815 NO_SELECTED_ITEM
, FALSE
, 0 );
2818 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2819 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
2822 case VK_DOWN
: /* If on menu bar, pull-down the menu */
2824 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
2825 if (!(menu
->wFlags
& MF_POPUP
))
2826 mt
.hCurrentMenu
= MENU_ShowSubPopup(mt
.hOwnerWnd
, mt
.hTopMenu
, TRUE
, wFlags
);
2827 else /* otherwise try to move selection */
2828 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
, ITEM_NEXT
);
2832 MENU_KeyLeft( &mt
, wFlags
);
2836 MENU_KeyRight( &mt
, wFlags
);
2846 hi
.cbSize
= sizeof(HELPINFO
);
2847 hi
.iContextType
= HELPINFO_MENUITEM
;
2848 if (menu
->FocusedItem
== NO_SELECTED_ITEM
)
2851 hi
.iCtrlId
= menu
->items
[menu
->FocusedItem
].wID
;
2852 hi
.hItemHandle
= hmenu
;
2853 hi
.dwContextId
= menu
->dwContextHelpID
;
2854 hi
.MousePos
= msg
.pt
;
2855 SendMessageA(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
2862 break; /* WM_KEYDOWN */
2872 break; /* WM_SYSKEYDOWN */
2878 if (msg
.wParam
== '\r' || msg
.wParam
== ' ')
2880 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2881 fEndMenu
= (executedMenuId
!= -1);
2886 /* Hack to avoid control chars. */
2887 /* We will find a better way real soon... */
2888 if ((msg
.wParam
<= 32) || (msg
.wParam
>= 127)) break;
2890 pos
= MENU_FindItemByKey( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2891 LOWORD(msg
.wParam
), FALSE
);
2892 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
2893 else if (pos
== (UINT
)-1) MessageBeep(0);
2896 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
, pos
,
2898 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2899 fEndMenu
= (executedMenuId
!= -1);
2903 } /* switch(msg.message) - kbd */
2907 DispatchMessageA( &msg
);
2910 if (!fEndMenu
) fRemove
= TRUE
;
2912 /* finally remove message from the queue */
2914 if (fRemove
&& !(mt
.trackFlags
& TF_SKIPREMOVE
) )
2915 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2916 else mt
.trackFlags
&= ~TF_SKIPREMOVE
;
2921 /* If dropdown is still painted and the close box is clicked on
2922 then the menu will be destroyed as part of the DispatchMessage above.
2923 This will then invalidate the menu handle in mt.hTopMenu. We should
2924 check for this first. */
2925 if( IsMenu( mt
.hTopMenu
) )
2927 menu
= MENU_GetMenu( mt
.hTopMenu
);
2929 if( IsWindow( mt
.hOwnerWnd
) )
2931 MENU_HideSubPopups( mt
.hOwnerWnd
, mt
.hTopMenu
, FALSE
);
2933 if (menu
&& menu
->wFlags
& MF_POPUP
)
2935 ShowWindow( menu
->hWnd
, SW_HIDE
);
2938 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
2939 SendMessageA( mt
.hOwnerWnd
, WM_MENUSELECT
, MAKELONG(0,0xffff), 0 );
2942 /* Reset the variable for hiding menu */
2943 if( menu
) menu
->bTimeToHide
= FALSE
;
2946 /* The return value is only used by TrackPopupMenu */
2947 return ((executedMenuId
!= -1) ? executedMenuId
: 0);
2950 /***********************************************************************
2953 static BOOL
MENU_InitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
2955 TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd
, hMenu
);
2959 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
2960 if (!(wFlags
& TPM_NONOTIFY
))
2961 SendMessageA( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
2963 SendMessageA( hWnd
, WM_SETCURSOR
, hWnd
, HTCAPTION
);
2965 if (!(wFlags
& TPM_NONOTIFY
))
2966 SendMessageA( hWnd
, WM_INITMENU
, hMenu
, 0 );
2970 /***********************************************************************
2973 static BOOL
MENU_ExitTracking(HWND hWnd
)
2975 TRACE("hwnd=0x%04x\n", hWnd
);
2977 SendMessageA( hWnd
, WM_EXITMENULOOP
, 0, 0 );
2982 /***********************************************************************
2983 * MENU_TrackMouseMenuBar
2985 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
2987 void MENU_TrackMouseMenuBar( WND
* wndPtr
, INT ht
, POINT pt
)
2989 HWND hWnd
= wndPtr
->hwndSelf
;
2990 HMENU hMenu
= (ht
== HTSYSMENU
) ? wndPtr
->hSysMenu
: wndPtr
->wIDmenu
;
2991 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
2993 TRACE("pwnd=%p ht=0x%04x (%ld,%ld)\n", wndPtr
, ht
, pt
.x
, pt
.y
);
2997 MENU_InitTracking( hWnd
, hMenu
, FALSE
, wFlags
);
2998 MENU_TrackMenu( hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
2999 MENU_ExitTracking(hWnd
);
3004 /***********************************************************************
3005 * MENU_TrackKbdMenuBar
3007 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3009 void MENU_TrackKbdMenuBar( WND
* wndPtr
, UINT wParam
, INT vkey
)
3011 UINT uItem
= NO_SELECTED_ITEM
;
3013 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3015 /* find window that has a menu */
3017 while( wndPtr
->dwStyle
& WS_CHILD
)
3018 if( !(wndPtr
= wndPtr
->parent
) ) return;
3020 /* check if we have to track a system menu */
3022 if( (wndPtr
->dwStyle
& (WS_CHILD
| WS_MINIMIZE
)) ||
3023 !wndPtr
->wIDmenu
|| vkey
== VK_SPACE
)
3025 if( !(wndPtr
->dwStyle
& WS_SYSMENU
) ) return;
3026 hTrackMenu
= wndPtr
->hSysMenu
;
3028 wParam
|= HTSYSMENU
; /* prevent item lookup */
3031 hTrackMenu
= wndPtr
->wIDmenu
;
3033 if (IsMenu( hTrackMenu
))
3035 MENU_InitTracking( wndPtr
->hwndSelf
, hTrackMenu
, FALSE
, wFlags
);
3037 if( vkey
&& vkey
!= VK_SPACE
)
3039 uItem
= MENU_FindItemByKey( wndPtr
->hwndSelf
, hTrackMenu
,
3040 vkey
, (wParam
& HTSYSMENU
) );
3041 if( uItem
>= (UINT
)(-2) )
3043 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3050 MENU_SelectItem( wndPtr
->hwndSelf
, hTrackMenu
, uItem
, TRUE
, 0 );
3052 if( uItem
== NO_SELECTED_ITEM
)
3053 MENU_MoveSelection( wndPtr
->hwndSelf
, hTrackMenu
, ITEM_NEXT
);
3055 PostMessageA( wndPtr
->hwndSelf
, WM_KEYDOWN
, VK_DOWN
, 0L );
3057 MENU_TrackMenu( hTrackMenu
, wFlags
, 0, 0, wndPtr
->hwndSelf
, NULL
);
3060 MENU_ExitTracking (wndPtr
->hwndSelf
);
3065 /**********************************************************************
3066 * TrackPopupMenu16 (USER.416)
3068 BOOL16 WINAPI
TrackPopupMenu16( HMENU16 hMenu
, UINT16 wFlags
, INT16 x
, INT16 y
,
3069 INT16 nReserved
, HWND16 hWnd
, const RECT16
*lpRect
)
3073 CONV_RECT16TO32( lpRect
, &r
);
3074 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, nReserved
, hWnd
,
3075 lpRect
? &r
: NULL
);
3079 /**********************************************************************
3080 * TrackPopupMenu (USER32.549)
3082 * Like the win32 API, the function return the command ID only if the
3083 * flag TPM_RETURNCMD is on.
3086 BOOL WINAPI
TrackPopupMenu( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3087 INT nReserved
, HWND hWnd
, const RECT
*lpRect
)
3091 MENU_InitTracking(hWnd
, hMenu
, TRUE
, wFlags
);
3093 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3094 if (!(wFlags
& TPM_NONOTIFY
))
3095 SendMessageA( hWnd
, WM_INITMENUPOPUP
, hMenu
, 0);
3097 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
, 0, 0 ))
3098 ret
= MENU_TrackMenu( hMenu
, wFlags
| TPM_POPUPMENU
, 0, 0, hWnd
, lpRect
);
3099 MENU_ExitTracking(hWnd
);
3101 if( (!(wFlags
& TPM_RETURNCMD
)) && (ret
!= FALSE
) )
3107 /**********************************************************************
3108 * TrackPopupMenuEx (USER32.550)
3110 BOOL WINAPI
TrackPopupMenuEx( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3111 HWND hWnd
, LPTPMPARAMS lpTpm
)
3113 FIXME("not fully implemented\n" );
3114 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, 0, hWnd
,
3115 lpTpm
? &lpTpm
->rcExclude
: NULL
);
3118 /***********************************************************************
3121 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3123 LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
,
3126 WND
* wndPtr
= WIN_FindWndPtr(hwnd
);
3129 TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
3130 hwnd
, message
, wParam
, lParam
);
3136 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*)lParam
;
3137 SetWindowLongA( hwnd
, 0, (LONG
)cs
->lpCreateParams
);
3142 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
3143 retvalue
= MA_NOACTIVATE
;
3149 BeginPaint( hwnd
, &ps
);
3150 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
3151 (HMENU
)GetWindowLongA( hwnd
, 0 ) );
3152 EndPaint( hwnd
, &ps
);
3162 /* zero out global pointer in case resident popup window
3163 * was somehow destroyed. */
3165 if(MENU_GetTopPopupWnd() )
3167 if( hwnd
== pTopPopupWnd
->hwndSelf
)
3169 ERR("resident popup destroyed!\n");
3171 MENU_DestroyTopPopupWnd();
3176 MENU_ReleaseTopPopupWnd();
3184 if( !(*(HMENU
*)wndPtr
->wExtra
) )
3185 ERR("no menu to display\n");
3188 *(HMENU
*)wndPtr
->wExtra
= 0;
3191 case MM_SETMENUHANDLE
:
3193 *(HMENU
*)wndPtr
->wExtra
= (HMENU
)wParam
;
3196 case MM_GETMENUHANDLE
:
3198 retvalue
= *(HMENU
*)wndPtr
->wExtra
;
3202 retvalue
= DefWindowProcA( hwnd
, message
, wParam
, lParam
);
3207 WIN_ReleaseWndPtr(wndPtr
);
3212 /***********************************************************************
3213 * MENU_GetMenuBarHeight
3215 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3217 UINT
MENU_GetMenuBarHeight( HWND hwnd
, UINT menubarWidth
,
3218 INT orgX
, INT orgY
)
3226 TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3227 hwnd
, menubarWidth
, orgX
, orgY
);
3229 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
3232 if (!(lppop
= MENU_GetMenu((HMENU16
)wndPtr
->wIDmenu
)))
3234 WIN_ReleaseWndPtr(wndPtr
);
3238 hdc
= GetDCEx( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3239 SelectObject( hdc
, hMenuFont
);
3240 SetRect(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+GetSystemMetrics(SM_CYMENU
));
3241 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
3242 ReleaseDC( hwnd
, hdc
);
3243 retvalue
= lppop
->Height
;
3244 WIN_ReleaseWndPtr(wndPtr
);
3249 /*******************************************************************
3250 * ChangeMenu16 (USER.153)
3252 BOOL16 WINAPI
ChangeMenu16( HMENU16 hMenu
, UINT16 pos
, SEGPTR data
,
3253 UINT16 id
, UINT16 flags
)
3255 TRACE("menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
3256 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3257 if (flags
& MF_APPEND
) return AppendMenu16( hMenu
, flags
& ~MF_APPEND
,
3260 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
3261 /* for MF_DELETE. We should check the parameters for all others */
3262 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
3264 if (flags
& MF_DELETE
) return DeleteMenu16(hMenu
, pos
, flags
& ~MF_DELETE
);
3265 if (flags
& MF_CHANGE
) return ModifyMenu16(hMenu
, pos
, flags
& ~MF_CHANGE
,
3267 if (flags
& MF_REMOVE
) return RemoveMenu16(hMenu
,
3268 flags
& MF_BYPOSITION
? pos
: id
,
3269 flags
& ~MF_REMOVE
);
3270 /* Default: MF_INSERT */
3271 return InsertMenu16( hMenu
, pos
, flags
, id
, data
);
3275 /*******************************************************************
3276 * ChangeMenuA (USER32.23)
3278 BOOL WINAPI
ChangeMenuA( HMENU hMenu
, UINT pos
, LPCSTR data
,
3279 UINT id
, UINT flags
)
3281 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3282 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3283 if (flags
& MF_APPEND
) return AppendMenuA( hMenu
, flags
& ~MF_APPEND
,
3285 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3286 if (flags
& MF_CHANGE
) return ModifyMenuA(hMenu
, pos
, flags
& ~MF_CHANGE
,
3288 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3289 flags
& MF_BYPOSITION
? pos
: id
,
3290 flags
& ~MF_REMOVE
);
3291 /* Default: MF_INSERT */
3292 return InsertMenuA( hMenu
, pos
, flags
, id
, data
);
3296 /*******************************************************************
3297 * ChangeMenuW (USER32.24)
3299 BOOL WINAPI
ChangeMenuW( HMENU hMenu
, UINT pos
, LPCWSTR data
,
3300 UINT id
, UINT flags
)
3302 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3303 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3304 if (flags
& MF_APPEND
) return AppendMenuW( hMenu
, flags
& ~MF_APPEND
,
3306 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3307 if (flags
& MF_CHANGE
) return ModifyMenuW(hMenu
, pos
, flags
& ~MF_CHANGE
,
3309 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3310 flags
& MF_BYPOSITION
? pos
: id
,
3311 flags
& ~MF_REMOVE
);
3312 /* Default: MF_INSERT */
3313 return InsertMenuW( hMenu
, pos
, flags
, id
, data
);
3317 /*******************************************************************
3318 * CheckMenuItem16 (USER.154)
3320 BOOL16 WINAPI
CheckMenuItem16( HMENU16 hMenu
, UINT16 id
, UINT16 flags
)
3322 return (BOOL16
)CheckMenuItem( hMenu
, id
, flags
);
3326 /*******************************************************************
3327 * CheckMenuItem (USER32.46)
3329 DWORD WINAPI
CheckMenuItem( HMENU hMenu
, UINT id
, UINT flags
)
3334 TRACE("menu=%04x id=%04x flags=%04x\n", hMenu
, id
, flags
);
3335 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
3336 ret
= item
->fState
& MF_CHECKED
;
3337 if (flags
& MF_CHECKED
) item
->fState
|= MF_CHECKED
;
3338 else item
->fState
&= ~MF_CHECKED
;
3343 /**********************************************************************
3344 * EnableMenuItem16 (USER.155)
3346 UINT16 WINAPI
EnableMenuItem16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3348 return EnableMenuItem( hMenu
, wItemID
, wFlags
);
3352 /**********************************************************************
3353 * EnableMenuItem (USER32.170)
3355 UINT WINAPI
EnableMenuItem( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3361 TRACE("(%04x, %04X, %04X) !\n",
3362 hMenu
, wItemID
, wFlags
);
3364 /* Get the Popupmenu to access the owner menu */
3365 if (!(menu
= MENU_GetMenu(hMenu
)))
3368 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
)))
3371 oldflags
= item
->fState
& (MF_GRAYED
| MF_DISABLED
);
3372 item
->fState
^= (oldflags
^ wFlags
) & (MF_GRAYED
| MF_DISABLED
);
3374 /* In win95 if the close item in the system menu change update the close button */
3375 if (TWEAK_WineLook
== WIN95_LOOK
)
3376 if((item
->wID
== SC_CLOSE
) && (oldflags
!= wFlags
))
3378 if (menu
->hSysMenuOwner
!= 0)
3380 POPUPMENU
* parentMenu
;
3382 /* Get the parent menu to access*/
3383 if (!(parentMenu
= MENU_GetMenu(menu
->hSysMenuOwner
)))
3386 /* Refresh the frame to reflect the change*/
3387 SetWindowPos(parentMenu
->hWnd
, 0, 0, 0, 0, 0,
3388 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
3396 /*******************************************************************
3397 * GetMenuString16 (USER.161)
3399 INT16 WINAPI
GetMenuString16( HMENU16 hMenu
, UINT16 wItemID
,
3400 LPSTR str
, INT16 nMaxSiz
, UINT16 wFlags
)
3402 return GetMenuStringA( hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3406 /*******************************************************************
3407 * GetMenuStringA (USER32.268)
3409 INT WINAPI
GetMenuStringA(
3410 HMENU hMenu
, /* [in] menuhandle */
3411 UINT wItemID
, /* [in] menu item (dep. on wFlags) */
3412 LPSTR str
, /* [out] outbuffer. If NULL, func returns entry length*/
3413 INT nMaxSiz
, /* [in] length of buffer. if 0, func returns entry len*/
3414 UINT wFlags
/* [in] MF_ flags */
3418 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3419 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3420 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3421 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3422 if (!str
|| !nMaxSiz
) return strlen(item
->text
);
3424 lstrcpynA( str
, item
->text
, nMaxSiz
);
3425 TRACE("returning '%s'\n", str
);
3430 /*******************************************************************
3431 * GetMenuStringW (USER32.269)
3433 INT WINAPI
GetMenuStringW( HMENU hMenu
, UINT wItemID
,
3434 LPWSTR str
, INT nMaxSiz
, UINT wFlags
)
3438 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3439 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3440 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3441 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3442 if (!str
|| !nMaxSiz
) return strlen(item
->text
);
3444 lstrcpynAtoW( str
, item
->text
, nMaxSiz
);
3445 return lstrlenW(str
);
3449 /**********************************************************************
3450 * HiliteMenuItem16 (USER.162)
3452 BOOL16 WINAPI
HiliteMenuItem16( HWND16 hWnd
, HMENU16 hMenu
, UINT16 wItemID
,
3455 return HiliteMenuItem( hWnd
, hMenu
, wItemID
, wHilite
);
3459 /**********************************************************************
3460 * HiliteMenuItem (USER32.318)
3462 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
3466 TRACE("(%04x, %04x, %04x, %04x);\n",
3467 hWnd
, hMenu
, wItemID
, wHilite
);
3468 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
3469 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3470 if (menu
->FocusedItem
== wItemID
) return TRUE
;
3471 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
3472 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
, 0 );
3477 /**********************************************************************
3478 * GetMenuState16 (USER.250)
3480 UINT16 WINAPI
GetMenuState16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3482 return GetMenuState( hMenu
, wItemID
, wFlags
);
3486 /**********************************************************************
3487 * GetMenuState (USER32.267)
3489 UINT WINAPI
GetMenuState( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3492 TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
3493 hMenu
, wItemID
, wFlags
);
3494 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
3495 debug_print_menuitem (" item: ", item
, "");
3496 if (item
->fType
& MF_POPUP
)
3498 POPUPMENU
*menu
= MENU_GetMenu( item
->hSubMenu
);
3499 if (!menu
) return -1;
3500 else return (menu
->nItems
<< 8) | ((item
->fState
|item
->fType
) & 0xff);
3504 /* We used to (from way back then) mask the result to 0xff. */
3505 /* I don't know why and it seems wrong as the documented */
3506 /* return flag MF_SEPARATOR is outside that mask. */
3507 return (item
->fType
| item
->fState
);
3512 /**********************************************************************
3513 * GetMenuItemCount16 (USER.263)
3515 INT16 WINAPI
GetMenuItemCount16( HMENU16 hMenu
)
3517 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3518 if (!menu
) return -1;
3519 TRACE("(%04x) returning %d\n",
3520 hMenu
, menu
->nItems
);
3521 return menu
->nItems
;
3525 /**********************************************************************
3526 * GetMenuItemCount (USER32.262)
3528 INT WINAPI
GetMenuItemCount( HMENU hMenu
)
3530 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3531 if (!menu
) return -1;
3532 TRACE("(%04x) returning %d\n",
3533 hMenu
, menu
->nItems
);
3534 return menu
->nItems
;
3537 /**********************************************************************
3538 * GetMenuItemID16 (USER.264)
3540 UINT16 WINAPI
GetMenuItemID16( HMENU16 hMenu
, INT16 nPos
)
3542 return (UINT16
) GetMenuItemID (hMenu
, nPos
);
3545 /**********************************************************************
3546 * GetMenuItemID (USER32.263)
3548 UINT WINAPI
GetMenuItemID( HMENU hMenu
, INT nPos
)
3552 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return 0;
3553 if (lpmi
->fType
& MF_POPUP
) return -1;
3558 /*******************************************************************
3559 * InsertMenu16 (USER.410)
3561 BOOL16 WINAPI
InsertMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3562 UINT16 id
, SEGPTR data
)
3564 UINT pos32
= (UINT
)pos
;
3565 if ((pos
== (UINT16
)-1) && (flags
& MF_BYPOSITION
)) pos32
= (UINT
)-1;
3566 if (IS_STRING_ITEM(flags
) && data
)
3567 return InsertMenuA( hMenu
, pos32
, flags
, id
,
3568 (LPSTR
)PTR_SEG_TO_LIN(data
) );
3569 return InsertMenuA( hMenu
, pos32
, flags
, id
, (LPSTR
)data
);
3573 /*******************************************************************
3574 * InsertMenuA (USER32.322)
3576 BOOL WINAPI
InsertMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3577 UINT id
, LPCSTR str
)
3581 if (IS_STRING_ITEM(flags
) && str
)
3582 TRACE("hMenu %04x, pos %d, flags %08x, "
3583 "id %04x, str '%s'\n",
3584 hMenu
, pos
, flags
, id
, str
);
3585 else TRACE("hMenu %04x, pos %d, flags %08x, "
3586 "id %04x, str %08lx (not a string)\n",
3587 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3589 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
3591 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
3593 RemoveMenu( hMenu
, pos
, flags
);
3597 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
3598 (MENU_GetMenu((HMENU16
)id
))->wFlags
|= MF_POPUP
;
3600 item
->hCheckBit
= item
->hUnCheckBit
= 0;
3605 /*******************************************************************
3606 * InsertMenuW (USER32.325)
3608 BOOL WINAPI
InsertMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3609 UINT id
, LPCWSTR str
)
3613 if (IS_STRING_ITEM(flags
) && str
)
3615 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
3616 ret
= InsertMenuA( hMenu
, pos
, flags
, id
, newstr
);
3617 HeapFree( GetProcessHeap(), 0, newstr
);
3620 else return InsertMenuA( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
3624 /*******************************************************************
3625 * AppendMenu16 (USER.411)
3627 BOOL16 WINAPI
AppendMenu16(HMENU16 hMenu
, UINT16 flags
, UINT16 id
, SEGPTR data
)
3629 return InsertMenu16( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3633 /*******************************************************************
3634 * AppendMenuA (USER32.5)
3636 BOOL WINAPI
AppendMenuA( HMENU hMenu
, UINT flags
,
3637 UINT id
, LPCSTR data
)
3639 return InsertMenuA( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3643 /*******************************************************************
3644 * AppendMenuW (USER32.6)
3646 BOOL WINAPI
AppendMenuW( HMENU hMenu
, UINT flags
,
3647 UINT id
, LPCWSTR data
)
3649 return InsertMenuW( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3653 /**********************************************************************
3654 * RemoveMenu16 (USER.412)
3656 BOOL16 WINAPI
RemoveMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3658 return RemoveMenu( hMenu
, nPos
, wFlags
);
3662 /**********************************************************************
3663 * RemoveMenu (USER32.441)
3665 BOOL WINAPI
RemoveMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3670 TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu
, nPos
, wFlags
);
3671 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3672 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3676 MENU_FreeItemData( item
);
3678 if (--menu
->nItems
== 0)
3680 HeapFree( SystemHeap
, 0, menu
->items
);
3685 while(nPos
< menu
->nItems
)
3691 menu
->items
= HeapReAlloc( SystemHeap
, 0, menu
->items
,
3692 menu
->nItems
* sizeof(MENUITEM
) );
3698 /**********************************************************************
3699 * DeleteMenu16 (USER.413)
3701 BOOL16 WINAPI
DeleteMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3703 return DeleteMenu( hMenu
, nPos
, wFlags
);
3707 /**********************************************************************
3708 * DeleteMenu (USER32.129)
3710 BOOL WINAPI
DeleteMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3712 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
3713 if (!item
) return FALSE
;
3714 if (item
->fType
& MF_POPUP
) DestroyMenu( item
->hSubMenu
);
3715 /* nPos is now the position of the item */
3716 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
3721 /*******************************************************************
3722 * ModifyMenu16 (USER.414)
3724 BOOL16 WINAPI
ModifyMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3725 UINT16 id
, SEGPTR data
)
3727 if (IS_STRING_ITEM(flags
))
3728 return ModifyMenuA( hMenu
, pos
, flags
, id
,
3729 (LPSTR
)PTR_SEG_TO_LIN(data
) );
3730 return ModifyMenuA( hMenu
, pos
, flags
, id
, (LPSTR
)data
);
3734 /*******************************************************************
3735 * ModifyMenuA (USER32.397)
3737 BOOL WINAPI
ModifyMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3738 UINT id
, LPCSTR str
)
3742 if (IS_STRING_ITEM(flags
))
3744 TRACE("%04x %d %04x %04x '%s'\n",
3745 hMenu
, pos
, flags
, id
, str
? str
: "#NULL#" );
3746 if (!str
) return FALSE
;
3750 TRACE("%04x %d %04x %04x %08lx\n",
3751 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3754 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
3755 return MENU_SetItemData( item
, flags
, id
, str
);
3759 /*******************************************************************
3760 * ModifyMenuW (USER32.398)
3762 BOOL WINAPI
ModifyMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3763 UINT id
, LPCWSTR str
)
3767 if (IS_STRING_ITEM(flags
) && str
)
3769 LPSTR newstr
= HEAP_strdupWtoA( GetProcessHeap(), 0, str
);
3770 ret
= ModifyMenuA( hMenu
, pos
, flags
, id
, newstr
);
3771 HeapFree( GetProcessHeap(), 0, newstr
);
3774 else return ModifyMenuA( hMenu
, pos
, flags
, id
, (LPCSTR
)str
);
3778 /**********************************************************************
3779 * CreatePopupMenu16 (USER.415)
3781 HMENU16 WINAPI
CreatePopupMenu16(void)
3783 return CreatePopupMenu();
3787 /**********************************************************************
3788 * CreatePopupMenu (USER32.82)
3790 HMENU WINAPI
CreatePopupMenu(void)
3795 if (!(hmenu
= CreateMenu())) return 0;
3796 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
3797 menu
->wFlags
|= MF_POPUP
;
3798 menu
->bTimeToHide
= FALSE
;
3803 /**********************************************************************
3804 * GetMenuCheckMarkDimensions (USER.417) (USER32.258)
3806 DWORD WINAPI
GetMenuCheckMarkDimensions(void)
3808 return MAKELONG( check_bitmap_width
, check_bitmap_height
);
3812 /**********************************************************************
3813 * SetMenuItemBitmaps16 (USER.418)
3815 BOOL16 WINAPI
SetMenuItemBitmaps16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
,
3816 HBITMAP16 hNewUnCheck
, HBITMAP16 hNewCheck
)
3818 return SetMenuItemBitmaps( hMenu
, nPos
, wFlags
, hNewUnCheck
, hNewCheck
);
3822 /**********************************************************************
3823 * SetMenuItemBitmaps (USER32.490)
3825 BOOL WINAPI
SetMenuItemBitmaps( HMENU hMenu
, UINT nPos
, UINT wFlags
,
3826 HBITMAP hNewUnCheck
, HBITMAP hNewCheck
)
3829 TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3830 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
3831 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3833 if (!hNewCheck
&& !hNewUnCheck
)
3835 item
->fState
&= ~MF_USECHECKBITMAPS
;
3837 else /* Install new bitmaps */
3839 item
->hCheckBit
= hNewCheck
;
3840 item
->hUnCheckBit
= hNewUnCheck
;
3841 item
->fState
|= MF_USECHECKBITMAPS
;
3847 /**********************************************************************
3848 * CreateMenu16 (USER.151)
3850 HMENU16 WINAPI
CreateMenu16(void)
3852 return CreateMenu();
3856 /**********************************************************************
3857 * CreateMenu (USER32.81)
3859 HMENU WINAPI
CreateMenu(void)
3863 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) ))) return 0;
3864 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3866 ZeroMemory(menu
, sizeof(POPUPMENU
));
3867 menu
->wMagic
= MENU_MAGIC
;
3868 menu
->FocusedItem
= NO_SELECTED_ITEM
;
3869 menu
->bTimeToHide
= FALSE
;
3871 TRACE("return %04x\n", hMenu
);
3877 /**********************************************************************
3878 * DestroyMenu16 (USER.152)
3880 BOOL16 WINAPI
DestroyMenu16( HMENU16 hMenu
)
3882 return DestroyMenu( hMenu
);
3886 /**********************************************************************
3887 * DestroyMenu (USER32.134)
3889 BOOL WINAPI
DestroyMenu( HMENU hMenu
)
3891 TRACE("(%04x)\n", hMenu
);
3893 /* Silently ignore attempts to destroy default system popup */
3895 if (hMenu
&& hMenu
!= MENU_DefSysPopup
)
3897 LPPOPUPMENU lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3898 WND
*pTPWnd
= MENU_GetTopPopupWnd();
3900 if( pTPWnd
&& (hMenu
== *(HMENU
*)pTPWnd
->wExtra
) )
3901 *(UINT
*)pTPWnd
->wExtra
= 0;
3903 if (!IS_A_MENU(lppop
)) lppop
= NULL
;
3906 lppop
->wMagic
= 0; /* Mark it as destroyed */
3908 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
&&
3909 (!pTPWnd
|| (lppop
->hWnd
!= pTPWnd
->hwndSelf
)))
3910 DestroyWindow( lppop
->hWnd
);
3912 if (lppop
->items
) /* recursively destroy submenus */
3915 MENUITEM
*item
= lppop
->items
;
3916 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
3918 if (item
->fType
& MF_POPUP
) DestroyMenu(item
->hSubMenu
);
3919 MENU_FreeItemData( item
);
3921 HeapFree( SystemHeap
, 0, lppop
->items
);
3923 USER_HEAP_FREE( hMenu
);
3924 MENU_ReleaseTopPopupWnd();
3928 MENU_ReleaseTopPopupWnd();
3932 return (hMenu
!= MENU_DefSysPopup
);
3936 /**********************************************************************
3937 * GetSystemMenu16 (USER.156)
3939 HMENU16 WINAPI
GetSystemMenu16( HWND16 hWnd
, BOOL16 bRevert
)
3941 return GetSystemMenu( hWnd
, bRevert
);
3945 /**********************************************************************
3946 * GetSystemMenu (USER32.291)
3948 HMENU WINAPI
GetSystemMenu( HWND hWnd
, BOOL bRevert
)
3950 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
3955 if( wndPtr
->hSysMenu
)
3959 DestroyMenu(wndPtr
->hSysMenu
);
3960 wndPtr
->hSysMenu
= 0;
3964 POPUPMENU
*menu
= MENU_GetMenu( wndPtr
->hSysMenu
);
3967 if( menu
->nItems
> 0 && menu
->items
[0].hSubMenu
== MENU_DefSysPopup
)
3968 menu
->items
[0].hSubMenu
= MENU_CopySysPopup();
3972 WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
3973 wndPtr
->hSysMenu
, hWnd
);
3974 wndPtr
->hSysMenu
= 0;
3979 if(!wndPtr
->hSysMenu
&& (wndPtr
->dwStyle
& WS_SYSMENU
) )
3980 wndPtr
->hSysMenu
= MENU_GetSysMenu( hWnd
, (HMENU
)(-1) );
3982 if( wndPtr
->hSysMenu
)
3985 retvalue
= GetSubMenu16(wndPtr
->hSysMenu
, 0);
3987 /* Store the dummy sysmenu handle to facilitate the refresh */
3988 /* of the close button if the SC_CLOSE item change */
3989 menu
= MENU_GetMenu(retvalue
);
3991 menu
->hSysMenuOwner
= wndPtr
->hSysMenu
;
3993 WIN_ReleaseWndPtr(wndPtr
);
3995 return bRevert
? 0 : retvalue
;
3999 /*******************************************************************
4000 * SetSystemMenu16 (USER.280)
4002 BOOL16 WINAPI
SetSystemMenu16( HWND16 hwnd
, HMENU16 hMenu
)
4004 return SetSystemMenu( hwnd
, hMenu
);
4008 /*******************************************************************
4009 * SetSystemMenu (USER32.508)
4011 BOOL WINAPI
SetSystemMenu( HWND hwnd
, HMENU hMenu
)
4013 WND
*wndPtr
= WIN_FindWndPtr(hwnd
);
4017 if (wndPtr
->hSysMenu
) DestroyMenu( wndPtr
->hSysMenu
);
4018 wndPtr
->hSysMenu
= MENU_GetSysMenu( hwnd
, hMenu
);
4019 WIN_ReleaseWndPtr(wndPtr
);
4026 /**********************************************************************
4027 * GetMenu16 (USER.157)
4029 HMENU16 WINAPI
GetMenu16( HWND16 hWnd
)
4031 return (HMENU16
)GetMenu(hWnd
);
4035 /**********************************************************************
4036 * GetMenu (USER32.257)
4038 HMENU WINAPI
GetMenu( HWND hWnd
)
4041 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
4042 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
4044 retvalue
= (HMENU
)wndPtr
->wIDmenu
;
4049 WIN_ReleaseWndPtr(wndPtr
);
4054 /**********************************************************************
4055 * SetMenu16 (USER.158)
4057 BOOL16 WINAPI
SetMenu16( HWND16 hWnd
, HMENU16 hMenu
)
4059 return SetMenu( hWnd
, hMenu
);
4063 /**********************************************************************
4064 * SetMenu (USER32.487)
4066 BOOL WINAPI
SetMenu( HWND hWnd
, HMENU hMenu
)
4068 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
4070 TRACE("(%04x, %04x);\n", hWnd
, hMenu
);
4072 if (hMenu
&& !IsMenu(hMenu
))
4074 WARN("hMenu is not a menu handle\n");
4079 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
4081 if (GetCapture() == hWnd
) ReleaseCapture();
4083 wndPtr
->wIDmenu
= (UINT
)hMenu
;
4088 if (!(lpmenu
= MENU_GetMenu(hMenu
)))
4090 WIN_ReleaseWndPtr(wndPtr
);
4093 lpmenu
->hWnd
= hWnd
;
4094 lpmenu
->wFlags
&= ~MF_POPUP
; /* Can't be a popup */
4095 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
4097 if (IsWindowVisible(hWnd
))
4098 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4099 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4100 WIN_ReleaseWndPtr(wndPtr
);
4103 WIN_ReleaseWndPtr(wndPtr
);
4109 /**********************************************************************
4110 * GetSubMenu16 (USER.159)
4112 HMENU16 WINAPI
GetSubMenu16( HMENU16 hMenu
, INT16 nPos
)
4114 return GetSubMenu( hMenu
, nPos
);
4118 /**********************************************************************
4119 * GetSubMenu (USER32.288)
4121 HMENU WINAPI
GetSubMenu( HMENU hMenu
, INT nPos
)
4125 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return 0;
4126 if (!(lpmi
->fType
& MF_POPUP
)) return 0;
4127 return lpmi
->hSubMenu
;
4131 /**********************************************************************
4132 * DrawMenuBar16 (USER.160)
4134 void WINAPI
DrawMenuBar16( HWND16 hWnd
)
4136 DrawMenuBar( hWnd
);
4140 /**********************************************************************
4141 * DrawMenuBar (USER32.161)
4143 BOOL WINAPI
DrawMenuBar( HWND hWnd
)
4146 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
4147 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
) && wndPtr
->wIDmenu
)
4149 lppop
= MENU_GetMenu((HMENU16
)wndPtr
->wIDmenu
);
4152 WIN_ReleaseWndPtr(wndPtr
);
4156 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
4157 lppop
->hwndOwner
= hWnd
;
4158 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4159 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4160 WIN_ReleaseWndPtr(wndPtr
);
4163 WIN_ReleaseWndPtr(wndPtr
);
4168 /***********************************************************************
4169 * EndMenu (USER.187) (USER32.175)
4171 void WINAPI
EndMenu(void)
4173 /* if we are in the menu code, and it is active */
4174 if (fEndMenu
== FALSE
&& MENU_IsMenuActive())
4176 /* terminate the menu handling code */
4179 /* needs to be posted to wakeup the internal menu handler */
4180 /* which will now terminate the menu, in the event that */
4181 /* the main window was minimized, or lost focus, so we */
4182 /* don't end up with an orphaned menu */
4183 PostMessageA( pTopPopupWnd
->hwndSelf
, WM_CANCELMODE
, 0, 0);
4188 /***********************************************************************
4189 * LookupMenuHandle (USER.217)
4191 HMENU16 WINAPI
LookupMenuHandle16( HMENU16 hmenu
, INT16 id
)
4193 HMENU hmenu32
= hmenu
;
4195 if (!MENU_FindItem( &hmenu32
, &id32
, MF_BYCOMMAND
)) return 0;
4196 else return hmenu32
;
4200 /**********************************************************************
4201 * LoadMenu16 (USER.150)
4203 HMENU16 WINAPI
LoadMenu16( HINSTANCE16 instance
, SEGPTR name
)
4211 char *str
= (char *)PTR_SEG_TO_LIN( name
);
4212 TRACE("(%04x,'%s')\n", instance
, str
);
4213 if (str
[0] == '#') name
= (SEGPTR
)atoi( str
+ 1 );
4216 TRACE("(%04x,%04x)\n",instance
,LOWORD(name
));
4218 if (!name
) return 0;
4220 /* check for Win32 module */
4221 if (HIWORD(instance
))
4222 return LoadMenuA(instance
,PTR_SEG_TO_LIN(name
));
4223 instance
= GetExePtr( instance
);
4225 if (!(hRsrc
= FindResource16( instance
, name
, RT_MENU16
))) return 0;
4226 if (!(handle
= LoadResource16( instance
, hRsrc
))) return 0;
4227 hMenu
= LoadMenuIndirect16(LockResource16(handle
));
4228 FreeResource16( handle
);
4233 /*****************************************************************
4234 * LoadMenuA (USER32.370)
4236 HMENU WINAPI
LoadMenuA( HINSTANCE instance
, LPCSTR name
)
4238 HRSRC hrsrc
= FindResourceA( instance
, name
, RT_MENUA
);
4239 if (!hrsrc
) return 0;
4240 return LoadMenuIndirectA( (LPCVOID
)LoadResource( instance
, hrsrc
));
4244 /*****************************************************************
4245 * LoadMenuW (USER32.373)
4247 HMENU WINAPI
LoadMenuW( HINSTANCE instance
, LPCWSTR name
)
4249 HRSRC hrsrc
= FindResourceW( instance
, name
, RT_MENUW
);
4250 if (!hrsrc
) return 0;
4251 return LoadMenuIndirectW( (LPCVOID
)LoadResource( instance
, hrsrc
));
4255 /**********************************************************************
4256 * LoadMenuIndirect16 (USER.220)
4258 HMENU16 WINAPI
LoadMenuIndirect16( LPCVOID
template )
4261 WORD version
, offset
;
4262 LPCSTR p
= (LPCSTR
)template;
4264 TRACE("(%p)\n", template );
4265 version
= GET_WORD(p
);
4269 WARN("version must be 0 for Win16\n" );
4272 offset
= GET_WORD(p
);
4273 p
+= sizeof(WORD
) + offset
;
4274 if (!(hMenu
= CreateMenu())) return 0;
4275 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
4277 DestroyMenu( hMenu
);
4284 /**********************************************************************
4285 * LoadMenuIndirectA (USER32.371)
4287 HMENU WINAPI
LoadMenuIndirectA( LPCVOID
template )
4290 WORD version
, offset
;
4291 LPCSTR p
= (LPCSTR
)template;
4293 TRACE("%p\n", template );
4294 version
= GET_WORD(p
);
4299 offset
= GET_WORD(p
);
4300 p
+= sizeof(WORD
) + offset
;
4301 if (!(hMenu
= CreateMenu())) return 0;
4302 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
4304 DestroyMenu( hMenu
);
4309 offset
= GET_WORD(p
);
4310 p
+= sizeof(WORD
) + offset
;
4311 if (!(hMenu
= CreateMenu())) return 0;
4312 if (!MENUEX_ParseResource( p
, hMenu
))
4314 DestroyMenu( hMenu
);
4319 ERR("version %d not supported.\n", version
);
4325 /**********************************************************************
4326 * LoadMenuIndirectW (USER32.372)
4328 HMENU WINAPI
LoadMenuIndirectW( LPCVOID
template )
4330 /* FIXME: is there anything different between A and W? */
4331 return LoadMenuIndirectA( template );
4335 /**********************************************************************
4336 * IsMenu16 (USER.358)
4338 BOOL16 WINAPI
IsMenu16( HMENU16 hmenu
)
4340 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
4341 return IS_A_MENU(menu
);
4345 /**********************************************************************
4346 * IsMenu (USER32.346)
4348 BOOL WINAPI
IsMenu(HMENU hmenu
)
4350 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
4351 return IS_A_MENU(menu
);
4354 /**********************************************************************
4355 * GetMenuItemInfo_common
4358 static BOOL
GetMenuItemInfo_common ( HMENU hmenu
, UINT item
, BOOL bypos
,
4359 LPMENUITEMINFOA lpmii
, BOOL unicode
)
4361 MENUITEM
*menu
= MENU_FindItem (&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0);
4363 debug_print_menuitem("GetMenuItemInfo_common: ", menu
, "");
4368 if (lpmii
->fMask
& MIIM_TYPE
) {
4369 lpmii
->fType
= menu
->fType
;
4370 switch (MENU_ITEM_TYPE(menu
->fType
)) {
4373 int len
= strlen(menu
->text
);
4374 if(lpmii
->dwTypeData
&& lpmii
->cch
) {
4376 lstrcpynAtoW((LPWSTR
) lpmii
->dwTypeData
, menu
->text
,
4379 lstrcpynA(lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4380 /* if we've copied a substring we return its length */
4381 if(lpmii
->cch
<= len
)
4383 } else /* return length of string */
4389 lpmii
->dwTypeData
= menu
->text
;
4396 if (lpmii
->fMask
& MIIM_STRING
) {
4397 if(lpmii
->dwTypeData
&& lpmii
->cch
) {
4399 lstrcpynAtoW((LPWSTR
) lpmii
->dwTypeData
, menu
->text
,
4402 lstrcpynA(lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4404 lpmii
->cch
= strlen(menu
->text
);
4407 if (lpmii
->fMask
& MIIM_FTYPE
)
4408 lpmii
->fType
= menu
->fType
;
4410 if (lpmii
->fMask
& MIIM_BITMAP
)
4411 lpmii
->hbmpItem
= menu
->hbmpItem
;
4413 if (lpmii
->fMask
& MIIM_STATE
)
4414 lpmii
->fState
= menu
->fState
;
4416 if (lpmii
->fMask
& MIIM_ID
)
4417 lpmii
->wID
= menu
->wID
;
4419 if (lpmii
->fMask
& MIIM_SUBMENU
)
4420 lpmii
->hSubMenu
= menu
->hSubMenu
;
4422 if (lpmii
->fMask
& MIIM_CHECKMARKS
) {
4423 lpmii
->hbmpChecked
= menu
->hCheckBit
;
4424 lpmii
->hbmpUnchecked
= menu
->hUnCheckBit
;
4426 if (lpmii
->fMask
& MIIM_DATA
)
4427 lpmii
->dwItemData
= menu
->dwItemData
;
4432 /**********************************************************************
4433 * GetMenuItemInfoA (USER32.264)
4435 BOOL WINAPI
GetMenuItemInfoA( HMENU hmenu
, UINT item
, BOOL bypos
,
4436 LPMENUITEMINFOA lpmii
)
4438 return GetMenuItemInfo_common (hmenu
, item
, bypos
, lpmii
, FALSE
);
4441 /**********************************************************************
4442 * GetMenuItemInfoW (USER32.265)
4444 BOOL WINAPI
GetMenuItemInfoW( HMENU hmenu
, UINT item
, BOOL bypos
,
4445 LPMENUITEMINFOW lpmii
)
4447 return GetMenuItemInfo_common (hmenu
, item
, bypos
,
4448 (LPMENUITEMINFOA
)lpmii
, TRUE
);
4451 /**********************************************************************
4452 * SetMenuItemInfo_common
4455 static BOOL
SetMenuItemInfo_common(MENUITEM
* menu
,
4456 const MENUITEMINFOA
*lpmii
,
4459 if (!menu
) return FALSE
;
4461 if (lpmii
->fMask
& MIIM_TYPE
) {
4462 /* Get rid of old string. */
4463 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4464 HeapFree(SystemHeap
, 0, menu
->text
);
4468 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4469 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4470 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4472 menu
->text
= lpmii
->dwTypeData
;
4474 if (IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4476 menu
->text
= HEAP_strdupWtoA(SystemHeap
, 0, (LPWSTR
) lpmii
->dwTypeData
);
4478 menu
->text
= HEAP_strdupA(SystemHeap
, 0, lpmii
->dwTypeData
);
4482 if (lpmii
->fMask
& MIIM_FTYPE
) {
4483 /* free the string when the type is changing */
4484 if ( (!IS_STRING_ITEM(lpmii
->fType
)) && IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4485 HeapFree(SystemHeap
, 0, menu
->text
);
4488 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4489 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4492 if (lpmii
->fMask
& MIIM_STRING
) {
4493 /* free the string when used */
4494 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4495 HeapFree(SystemHeap
, 0, menu
->text
);
4497 menu
->text
= HEAP_strdupWtoA(SystemHeap
, 0, (LPWSTR
) lpmii
->dwTypeData
);
4499 menu
->text
= HEAP_strdupA(SystemHeap
, 0, lpmii
->dwTypeData
);
4503 if (lpmii
->fMask
& MIIM_STATE
)
4505 /* fixme: MFS_DEFAULT do we have to reset the other menu items? */
4506 menu
->fState
= lpmii
->fState
;
4509 if (lpmii
->fMask
& MIIM_ID
)
4510 menu
->wID
= lpmii
->wID
;
4512 if (lpmii
->fMask
& MIIM_SUBMENU
) {
4513 menu
->hSubMenu
= lpmii
->hSubMenu
;
4514 if (menu
->hSubMenu
) {
4515 POPUPMENU
*subMenu
= MENU_GetMenu((UINT16
)menu
->hSubMenu
);
4517 subMenu
->wFlags
|= MF_POPUP
;
4518 menu
->fType
|= MF_POPUP
;
4521 /* FIXME: Return an error ? */
4522 menu
->fType
&= ~MF_POPUP
;
4525 menu
->fType
&= ~MF_POPUP
;
4528 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
4530 if (lpmii
->fType
& MFT_RADIOCHECK
)
4531 menu
->fType
|= MFT_RADIOCHECK
;
4533 menu
->hCheckBit
= lpmii
->hbmpChecked
;
4534 menu
->hUnCheckBit
= lpmii
->hbmpUnchecked
;
4536 if (lpmii
->fMask
& MIIM_DATA
)
4537 menu
->dwItemData
= lpmii
->dwItemData
;
4539 debug_print_menuitem("SetMenuItemInfo_common: ", menu
, "");
4543 /**********************************************************************
4544 * SetMenuItemInfoA (USER32.491)
4546 BOOL WINAPI
SetMenuItemInfoA(HMENU hmenu
, UINT item
, BOOL bypos
,
4547 const MENUITEMINFOA
*lpmii
)
4549 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4553 /**********************************************************************
4554 * SetMenuItemInfoW (USER32.492)
4556 BOOL WINAPI
SetMenuItemInfoW(HMENU hmenu
, UINT item
, BOOL bypos
,
4557 const MENUITEMINFOW
*lpmii
)
4559 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4560 (const MENUITEMINFOA
*)lpmii
, TRUE
);
4563 /**********************************************************************
4564 * SetMenuDefaultItem (USER32.489)
4567 BOOL WINAPI
SetMenuDefaultItem(HMENU hmenu
, UINT uItem
, UINT bypos
)
4573 TRACE("(0x%x,%d,%d)\n", hmenu
, uItem
, bypos
);
4575 if (!(menu
= MENU_GetMenu(hmenu
))) return FALSE
;
4577 /* reset all default-item flags */
4579 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4581 item
->fState
&= ~MFS_DEFAULT
;
4584 /* no default item */
4593 if ( uItem
>= menu
->nItems
) return FALSE
;
4594 item
[uItem
].fState
|= MFS_DEFAULT
;
4599 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4601 if (item
->wID
== uItem
)
4603 item
->fState
|= MFS_DEFAULT
;
4612 /**********************************************************************
4613 * GetMenuDefaultItem (USER32.260)
4615 UINT WINAPI
GetMenuDefaultItem(HMENU hmenu
, UINT bypos
, UINT flags
)
4621 TRACE("(0x%x,%d,%d)\n", hmenu
, bypos
, flags
);
4623 if (!(menu
= MENU_GetMenu(hmenu
))) return -1;
4625 /* find default item */
4629 if (! item
) return -1;
4631 while ( !( item
->fState
& MFS_DEFAULT
) )
4634 if (i
>= menu
->nItems
) return -1;
4637 /* default: don't return disabled items */
4638 if ( (!(GMDI_USEDISABLED
& flags
)) && (item
->fState
& MFS_DISABLED
)) return -1;
4640 /* search rekursiv when needed */
4641 if ( (item
->fType
& MF_POPUP
) && (flags
& GMDI_GOINTOPOPUPS
) )
4644 ret
= GetMenuDefaultItem( item
->hSubMenu
, bypos
, flags
);
4645 if ( -1 != ret
) return ret
;
4647 /* when item not found in submenu, return the popup item */
4649 return ( bypos
) ? i
: item
->wID
;
4653 /*******************************************************************
4654 * InsertMenuItem16 (USER.441)
4658 BOOL16 WINAPI
InsertMenuItem16( HMENU16 hmenu
, UINT16 pos
, BOOL16 byposition
,
4659 const MENUITEMINFO16
*mii
)
4663 miia
.cbSize
= sizeof(miia
);
4664 miia
.fMask
= mii
->fMask
;
4665 miia
.dwTypeData
= mii
->dwTypeData
;
4666 miia
.fType
= mii
->fType
;
4667 miia
.fState
= mii
->fState
;
4668 miia
.wID
= mii
->wID
;
4669 miia
.hSubMenu
= mii
->hSubMenu
;
4670 miia
.hbmpChecked
= mii
->hbmpChecked
;
4671 miia
.hbmpUnchecked
= mii
->hbmpUnchecked
;
4672 miia
.dwItemData
= mii
->dwItemData
;
4673 miia
.cch
= mii
->cch
;
4674 if (IS_STRING_ITEM(miia
.fType
))
4675 miia
.dwTypeData
= PTR_SEG_TO_LIN(miia
.dwTypeData
);
4676 return InsertMenuItemA( hmenu
, pos
, byposition
, &miia
);
4680 /**********************************************************************
4681 * InsertMenuItemA (USER32.323)
4683 BOOL WINAPI
InsertMenuItemA(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4684 const MENUITEMINFOA
*lpmii
)
4686 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4687 return SetMenuItemInfo_common(item
, lpmii
, FALSE
);
4691 /**********************************************************************
4692 * InsertMenuItemW (USER32.324)
4694 BOOL WINAPI
InsertMenuItemW(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4695 const MENUITEMINFOW
*lpmii
)
4697 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4698 return SetMenuItemInfo_common(item
, (const MENUITEMINFOA
*)lpmii
, TRUE
);
4701 /**********************************************************************
4702 * CheckMenuRadioItem (USER32.47)
4705 BOOL WINAPI
CheckMenuRadioItem(HMENU hMenu
,
4706 UINT first
, UINT last
, UINT check
,
4709 MENUITEM
*mifirst
, *milast
, *micheck
;
4710 HMENU mfirst
= hMenu
, mlast
= hMenu
, mcheck
= hMenu
;
4712 TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4713 hMenu
, first
, last
, check
, bypos
);
4715 mifirst
= MENU_FindItem (&mfirst
, &first
, bypos
);
4716 milast
= MENU_FindItem (&mlast
, &last
, bypos
);
4717 micheck
= MENU_FindItem (&mcheck
, &check
, bypos
);
4719 if (mifirst
== NULL
|| milast
== NULL
|| micheck
== NULL
||
4720 mifirst
> milast
|| mfirst
!= mlast
|| mfirst
!= mcheck
||
4721 micheck
> milast
|| micheck
< mifirst
)
4724 while (mifirst
<= milast
)
4726 if (mifirst
== micheck
)
4728 mifirst
->fType
|= MFT_RADIOCHECK
;
4729 mifirst
->fState
|= MFS_CHECKED
;
4731 mifirst
->fType
&= ~MFT_RADIOCHECK
;
4732 mifirst
->fState
&= ~MFS_CHECKED
;
4740 /**********************************************************************
4741 * CheckMenuRadioItem16 (not a Windows API)
4744 BOOL16 WINAPI
CheckMenuRadioItem16(HMENU16 hMenu
,
4745 UINT16 first
, UINT16 last
, UINT16 check
,
4748 return CheckMenuRadioItem (hMenu
, first
, last
, check
, bypos
);
4751 /**********************************************************************
4752 * GetMenuItemRect (USER32.266)
4754 * ATTENTION: Here, the returned values in rect are the screen
4755 * coordinates of the item just like if the menu was
4756 * always on the upper left side of the application.
4759 BOOL WINAPI
GetMenuItemRect (HWND hwnd
, HMENU hMenu
, UINT uItem
,
4762 POPUPMENU
*itemMenu
;
4766 TRACE("(0x%x,0x%x,%d,%p)\n", hwnd
, hMenu
, uItem
, rect
);
4768 item
= MENU_FindItem (&hMenu
, &uItem
, MF_BYPOSITION
);
4769 referenceHwnd
= hwnd
;
4773 itemMenu
= MENU_GetMenu(hMenu
);
4774 if (itemMenu
== NULL
)
4777 if(itemMenu
->hWnd
== 0)
4779 referenceHwnd
= itemMenu
->hWnd
;
4782 if ((rect
== NULL
) || (item
== NULL
))
4787 MapWindowPoints(referenceHwnd
, 0, (LPPOINT
)rect
, 2);
4792 /**********************************************************************
4793 * GetMenuItemRect16 (USER.665)
4796 BOOL16 WINAPI
GetMenuItemRect16 (HWND16 hwnd
, HMENU16 hMenu
, UINT16 uItem
,
4802 if (!rect
) return FALSE
;
4803 res
= GetMenuItemRect (hwnd
, hMenu
, uItem
, &r32
);
4804 CONV_RECT32TO16 (&r32
, rect
);
4808 /**********************************************************************
4812 * MIM_APPLYTOSUBMENUS
4813 * actually use the items to draw the menu
4815 BOOL WINAPI
SetMenuInfo (HMENU hMenu
, LPCMENUINFO lpmi
)
4819 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4821 if (lpmi
&& (lpmi
->cbSize
==sizeof(MENUINFO
)) && (menu
= MENU_GetMenu(hMenu
)))
4824 if (lpmi
->fMask
& MIM_BACKGROUND
)
4825 menu
->hbrBack
= lpmi
->hbrBack
;
4827 if (lpmi
->fMask
& MIM_HELPID
)
4828 menu
->dwContextHelpID
= lpmi
->dwContextHelpID
;
4830 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4831 menu
->cyMax
= lpmi
->cyMax
;
4833 if (lpmi
->fMask
& MIM_MENUDATA
)
4834 menu
->dwMenuData
= lpmi
->dwMenuData
;
4836 if (lpmi
->fMask
& MIM_STYLE
)
4837 menu
->dwStyle
= lpmi
->dwStyle
;
4844 /**********************************************************************
4851 BOOL WINAPI
GetMenuInfo (HMENU hMenu
, LPMENUINFO lpmi
)
4854 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4856 if (lpmi
&& (menu
= MENU_GetMenu(hMenu
)))
4859 if (lpmi
->fMask
& MIM_BACKGROUND
)
4860 lpmi
->hbrBack
= menu
->hbrBack
;
4862 if (lpmi
->fMask
& MIM_HELPID
)
4863 lpmi
->dwContextHelpID
= menu
->dwContextHelpID
;
4865 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4866 lpmi
->cyMax
= menu
->cyMax
;
4868 if (lpmi
->fMask
& MIM_MENUDATA
)
4869 lpmi
->dwMenuData
= menu
->dwMenuData
;
4871 if (lpmi
->fMask
& MIM_STYLE
)
4872 lpmi
->dwStyle
= menu
->dwStyle
;
4879 /**********************************************************************
4880 * SetMenuContextHelpId16 (USER.384)
4882 BOOL16 WINAPI
SetMenuContextHelpId16( HMENU16 hMenu
, DWORD dwContextHelpID
)
4884 return SetMenuContextHelpId( hMenu
, dwContextHelpID
);
4888 /**********************************************************************
4889 * SetMenuContextHelpId (USER32.488)
4891 BOOL WINAPI
SetMenuContextHelpId( HMENU hMenu
, DWORD dwContextHelpID
)
4895 TRACE("(0x%04x 0x%08lx)\n", hMenu
, dwContextHelpID
);
4897 if ((menu
= MENU_GetMenu(hMenu
)))
4899 menu
->dwContextHelpID
= dwContextHelpID
;
4905 /**********************************************************************
4906 * GetMenuContextHelpId16 (USER.385)
4908 DWORD WINAPI
GetMenuContextHelpId16( HMENU16 hMenu
)
4910 return GetMenuContextHelpId( hMenu
);
4913 /**********************************************************************
4914 * GetMenuContextHelpId (USER32.488)
4916 DWORD WINAPI
GetMenuContextHelpId( HMENU hMenu
)
4920 TRACE("(0x%04x)\n", hMenu
);
4922 if ((menu
= MENU_GetMenu(hMenu
)))
4924 return menu
->dwContextHelpID
;
4929 /**********************************************************************
4930 * MenuItemFromPoint (USER32.387)
4932 UINT WINAPI
MenuItemFromPoint(HWND hWnd
, HMENU hMenu
, POINT ptScreen
)
4934 FIXME("(0x%04x,0x%04x,(%ld,%ld)):stub\n",
4935 hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);