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.
23 #include "wine/winbase16.h"
24 #include "wine/winuser16.h"
25 #include "wine/unicode.h"
26 #include "wine/port.h"
31 #include "nonclient.h"
36 #include "debugtools.h"
38 DEFAULT_DEBUG_CHANNEL(menu
);
39 DECLARE_DEBUG_CHANNEL(accel
);
41 /* internal popup menu window messages */
43 #define MM_SETMENUHANDLE (WM_USER + 0)
44 #define MM_GETMENUHANDLE (WM_USER + 1)
46 /* Menu item structure */
48 /* ----------- MENUITEMINFO Stuff ----------- */
49 UINT fType
; /* Item type. */
50 UINT fState
; /* Item state. */
51 UINT wID
; /* Item id. */
52 HMENU hSubMenu
; /* Pop-up menu. */
53 HBITMAP hCheckBit
; /* Bitmap when checked. */
54 HBITMAP hUnCheckBit
; /* Bitmap when unchecked. */
55 LPWSTR text
; /* Item text or bitmap handle. */
56 DWORD dwItemData
; /* Application defined. */
57 DWORD dwTypeData
; /* depends on fMask */
58 HBITMAP hbmpItem
; /* bitmap in win98 style menus */
59 /* ----------- Wine stuff ----------- */
60 RECT rect
; /* Item area (relative to menu window) */
61 UINT xTab
; /* X position of text after Tab */
64 /* Popup menu structure */
66 WORD wFlags
; /* Menu flags (MF_POPUP, MF_SYSMENU) */
67 WORD wMagic
; /* Magic number */
68 HQUEUE16 hTaskQ
; /* Task queue for this menu */
69 WORD Width
; /* Width of the whole menu */
70 WORD Height
; /* Height of the whole menu */
71 WORD nItems
; /* Number of items in the menu */
72 HWND hWnd
; /* Window containing the menu */
73 MENUITEM
*items
; /* Array of menu items */
74 UINT FocusedItem
; /* Currently focused item */
75 HWND hwndOwner
; /* window receiving the messages for ownerdraw */
76 BOOL bTimeToHide
; /* Request hiding when receiving a second click in the top-level menu item */
77 /* ------------ MENUINFO members ------ */
78 DWORD dwStyle
; /* Extended mennu style */
79 UINT cyMax
; /* max hight of the whole menu, 0 is screen hight */
80 HBRUSH hbrBack
; /* brush for menu background */
81 DWORD dwContextHelpID
;
82 DWORD dwMenuData
; /* application defined value */
83 HMENU hSysMenuOwner
; /* Handle to the dummy sys menu holder */
84 } POPUPMENU
, *LPPOPUPMENU
;
86 /* internal flags for menu tracking */
88 #define TF_ENDMENU 0x0001
89 #define TF_SUSPENDPOPUP 0x0002
90 #define TF_SKIPREMOVE 0x0004
95 HMENU hCurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
96 HMENU hTopMenu
; /* initial menu */
97 HWND hOwnerWnd
; /* where notifications are sent */
101 #define MENU_MAGIC 0x554d /* 'MU' */
102 #define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
107 /* Internal MENU_TrackMenu() flags */
108 #define TPM_INTERNAL 0xF0000000
109 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
110 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
111 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
113 /* popup menu shade thickness */
114 #define POPUP_XSHADE 4
115 #define POPUP_YSHADE 4
117 /* Space between 2 menu bar items */
118 #define MENU_BAR_ITEMS_SPACE 12
120 /* Minimum width of a tab character */
121 #define MENU_TAB_SPACE 8
123 /* Height of a separator item */
124 #define SEPARATOR_HEIGHT 5
126 /* (other menu->FocusedItem values give the position of the focused item) */
127 #define NO_SELECTED_ITEM 0xffff
129 #define MENU_ITEM_TYPE(flags) \
130 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
132 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
133 #define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
134 #define IS_MAGIC_ITEM(text) (LOWORD((int)text)<12)
136 #define IS_SYSTEM_MENU(menu) \
137 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
139 #define IS_SYSTEM_POPUP(menu) \
140 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
142 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
143 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
144 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
145 MF_POPUP | MF_SYSMENU | MF_HELP)
146 #define STATE_MASK (~TYPE_MASK)
148 /* Dimension of the menu bitmaps */
149 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 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
;
177 static LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
);
180 /*********************************************************************
181 * menu class descriptor
183 const struct builtin_class_descr MENU_builtin_class
=
185 POPUPMENU_CLASS_ATOM
, /* name */
186 CS_GLOBALCLASS
| CS_SAVEBITS
, /* style */
187 NULL
, /* procA (winproc is Unicode only) */
188 PopupMenuWndProc
, /* procW */
189 sizeof(HMENU
), /* extra */
190 IDC_ARROWA
, /* cursor */
191 COLOR_MENU
+1 /* brush */
195 /***********************************************************************
196 * debug_print_menuitem
198 * Print a menuitem in readable form.
201 #define debug_print_menuitem(pre, mp, post) \
202 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
204 #define MENUOUT(text) \
205 DPRINTF("%s%s", (count++ ? "," : ""), (text))
207 #define MENUFLAG(bit,text) \
209 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
212 static void do_debug_print_menuitem(const char *prefix
, MENUITEM
* mp
,
215 TRACE("%s ", prefix
);
217 UINT flags
= mp
->fType
;
218 int typ
= MENU_ITEM_TYPE(flags
);
219 DPRINTF( "{ ID=0x%x", mp
->wID
);
220 if (flags
& MF_POPUP
)
221 DPRINTF( ", Sub=0x%x", mp
->hSubMenu
);
225 if (typ
== MFT_STRING
)
227 else if (typ
== MFT_SEPARATOR
)
229 else if (typ
== MFT_OWNERDRAW
)
231 else if (typ
== MFT_BITMAP
)
237 MENUFLAG(MF_POPUP
, "pop");
238 MENUFLAG(MFT_MENUBARBREAK
, "barbrk");
239 MENUFLAG(MFT_MENUBREAK
, "brk");
240 MENUFLAG(MFT_RADIOCHECK
, "radio");
241 MENUFLAG(MFT_RIGHTORDER
, "rorder");
242 MENUFLAG(MF_SYSMENU
, "sys");
243 MENUFLAG(MFT_RIGHTJUSTIFY
, "right"); /* same as MF_HELP */
246 DPRINTF( "+0x%x", flags
);
251 DPRINTF( ", State=");
252 MENUFLAG(MFS_GRAYED
, "grey");
253 MENUFLAG(MFS_DEFAULT
, "default");
254 MENUFLAG(MFS_DISABLED
, "dis");
255 MENUFLAG(MFS_CHECKED
, "check");
256 MENUFLAG(MFS_HILITE
, "hi");
257 MENUFLAG(MF_USECHECKBITMAPS
, "usebit");
258 MENUFLAG(MF_MOUSESELECT
, "mouse");
260 DPRINTF( "+0x%x", flags
);
263 DPRINTF( ", Chk=0x%x", mp
->hCheckBit
);
265 DPRINTF( ", Unc=0x%x", mp
->hUnCheckBit
);
267 if (typ
== MFT_STRING
) {
269 DPRINTF( ", Text=%s", debugstr_w(mp
->text
));
271 DPRINTF( ", Text=Null");
272 } else if (mp
->text
== NULL
)
275 DPRINTF( ", Text=%p", mp
->text
);
277 DPRINTF( ", ItemData=0x%08lx", mp
->dwItemData
);
283 DPRINTF(" %s\n", postfix
);
290 /***********************************************************************
293 * Validate the given menu handle and returns the menu structure pointer.
295 POPUPMENU
*MENU_GetMenu(HMENU hMenu
)
298 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
299 if (!IS_A_MENU(menu
))
301 WARN("invalid menu handle=%x, ptr=%p, magic=%x\n", hMenu
, menu
, menu
? menu
->wMagic
:0);
307 /***********************************************************************
310 * Return the default system menu.
312 static HMENU
MENU_CopySysPopup(void)
314 HMENU hMenu
= LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
317 POPUPMENU
* menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
318 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
319 SetMenuDefaultItem(hMenu
, SC_CLOSE
, FALSE
);
323 ERR("Unable to load default system menu\n" );
326 TRACE("returning %x.\n", hMenu
);
331 /***********************************************************************
332 * MENU_GetTopPopupWnd()
334 * Return the locked pointer pTopPopupWnd.
336 static WND
*MENU_GetTopPopupWnd()
338 return WIN_LockWndPtr(pTopPopupWnd
);
340 /***********************************************************************
341 * MENU_ReleaseTopPopupWnd()
343 * Release the locked pointer pTopPopupWnd.
345 static void MENU_ReleaseTopPopupWnd()
347 WIN_ReleaseWndPtr(pTopPopupWnd
);
349 /***********************************************************************
350 * MENU_DestroyTopPopupWnd()
352 * Destroy the locked pointer pTopPopupWnd.
354 static void MENU_DestroyTopPopupWnd()
356 WND
*tmpWnd
= pTopPopupWnd
;
358 WIN_ReleaseWndPtr(tmpWnd
);
363 /**********************************************************************
366 * Create a copy of the system menu. System menu in Windows is
367 * a special menu bar with the single entry - system menu popup.
368 * This popup is presented to the outside world as a "system menu".
369 * However, the real system menu handle is sometimes seen in the
370 * WM_MENUSELECT parameters (and Word 6 likes it this way).
372 HMENU
MENU_GetSysMenu( HWND hWnd
, HMENU hPopupMenu
)
376 if ((hMenu
= CreateMenu()))
378 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
379 menu
->wFlags
= MF_SYSMENU
;
382 if (hPopupMenu
== (HMENU
)(-1))
383 hPopupMenu
= MENU_CopySysPopup();
384 else if( !hPopupMenu
) hPopupMenu
= MENU_DefSysPopup
;
388 InsertMenuA( hMenu
, -1, MF_SYSMENU
| MF_POPUP
| MF_BYPOSITION
, hPopupMenu
, NULL
);
390 menu
->items
[0].fType
= MF_SYSMENU
| MF_POPUP
;
391 menu
->items
[0].fState
= 0;
392 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hPopupMenu
);
393 menu
->wFlags
|= MF_SYSMENU
;
395 TRACE("GetSysMenu hMenu=%04x (%04x)\n", hMenu
, hPopupMenu
);
398 DestroyMenu( hMenu
);
400 ERR("failed to load system menu!\n");
405 /***********************************************************************
408 * Menus initialisation.
413 NONCLIENTMETRICSA ncm
;
415 static unsigned char shade_bits
[16] = { 0x55, 0, 0xAA, 0,
420 /* Load menu bitmaps */
421 hStdMnArrow
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW
));
422 /* Load system buttons bitmaps */
423 hBmpMinimize
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCE
));
424 hBmpMinimizeD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCED
));
425 hBmpMaximize
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORE
));
426 hBmpMaximizeD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORED
));
427 hBmpClose
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSE
));
428 hBmpCloseD
= LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSED
));
433 GetObjectA( hStdMnArrow
, sizeof(bm
), &bm
);
434 arrow_bitmap_width
= bm
.bmWidth
;
435 arrow_bitmap_height
= bm
.bmHeight
;
439 if (! (hBitmap
= CreateBitmap( 8, 8, 1, 1, shade_bits
)))
442 if(!(hShadeBrush
= CreatePatternBrush( hBitmap
)))
445 DeleteObject( hBitmap
);
446 if (!(MENU_DefSysPopup
= MENU_CopySysPopup()))
449 ncm
.cbSize
= sizeof (NONCLIENTMETRICSA
);
450 if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS
, sizeof(NONCLIENTMETRICSA
), &ncm
, 0)))
453 if (!(hMenuFont
= CreateFontIndirectA( &ncm
.lfMenuFont
)))
456 ncm
.lfMenuFont
.lfWeight
+= 300;
457 if ( ncm
.lfMenuFont
.lfWeight
> 1000)
458 ncm
.lfMenuFont
.lfWeight
= 1000;
460 if (!(hMenuFontBold
= CreateFontIndirectA( &ncm
.lfMenuFont
)))
466 /***********************************************************************
467 * MENU_InitSysMenuPopup
469 * Grey the appropriate items in System menu.
471 static void MENU_InitSysMenuPopup( HMENU hmenu
, DWORD style
, DWORD clsStyle
)
475 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
476 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
477 gray
= ((style
& WS_MAXIMIZE
) != 0);
478 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
479 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
480 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
481 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
482 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
483 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
484 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
485 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
487 /* The menu item must keep its state if it's disabled */
489 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
493 /******************************************************************************
495 * UINT MENU_GetStartOfNextColumn(
498 *****************************************************************************/
500 static UINT
MENU_GetStartOfNextColumn(
503 POPUPMENU
*menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
504 UINT i
= menu
->FocusedItem
+ 1;
507 return NO_SELECTED_ITEM
;
509 if( i
== NO_SELECTED_ITEM
)
512 for( ; i
< menu
->nItems
; ++i
) {
513 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
517 return NO_SELECTED_ITEM
;
521 /******************************************************************************
523 * UINT MENU_GetStartOfPrevColumn(
526 *****************************************************************************/
528 static UINT
MENU_GetStartOfPrevColumn(
531 POPUPMENU
const *menu
= (POPUPMENU
*)USER_HEAP_LIN_ADDR(hMenu
);
535 return NO_SELECTED_ITEM
;
537 if( menu
->FocusedItem
== 0 || menu
->FocusedItem
== NO_SELECTED_ITEM
)
538 return NO_SELECTED_ITEM
;
540 /* Find the start of the column */
542 for(i
= menu
->FocusedItem
; i
!= 0 &&
543 !(menu
->items
[i
].fType
& MF_MENUBARBREAK
);
547 return NO_SELECTED_ITEM
;
549 for(--i
; i
!= 0; --i
) {
550 if (menu
->items
[i
].fType
& MF_MENUBARBREAK
)
554 TRACE("ret %d.\n", i
);
561 /***********************************************************************
564 * Find a menu item. Return a pointer on the item, and modifies *hmenu
565 * in case the item was in a sub-menu.
567 static MENUITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
572 if (((*hmenu
)==0xffff) || (!(menu
= MENU_GetMenu(*hmenu
)))) return NULL
;
573 if (wFlags
& MF_BYPOSITION
)
575 if (*nPos
>= menu
->nItems
) return NULL
;
576 return &menu
->items
[*nPos
];
580 MENUITEM
*item
= menu
->items
;
581 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
583 if (item
->wID
== *nPos
)
588 else if (item
->fType
& MF_POPUP
)
590 HMENU hsubmenu
= item
->hSubMenu
;
591 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
603 /***********************************************************************
606 * Find a Sub menu. Return the position of the submenu, and modifies
607 * *hmenu in case it is found in another sub-menu.
608 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
610 UINT
MENU_FindSubMenu( HMENU
*hmenu
, HMENU hSubTarget
)
615 if (((*hmenu
)==0xffff) ||
616 (!(menu
= MENU_GetMenu(*hmenu
))))
617 return NO_SELECTED_ITEM
;
619 for (i
= 0; i
< menu
->nItems
; i
++, item
++) {
620 if(!(item
->fType
& MF_POPUP
)) continue;
621 if (item
->hSubMenu
== hSubTarget
) {
625 HMENU hsubmenu
= item
->hSubMenu
;
626 UINT pos
= MENU_FindSubMenu( &hsubmenu
, hSubTarget
);
627 if (pos
!= NO_SELECTED_ITEM
) {
633 return NO_SELECTED_ITEM
;
636 /***********************************************************************
639 static void MENU_FreeItemData( MENUITEM
* item
)
642 if (IS_STRING_ITEM(item
->fType
) && item
->text
)
643 HeapFree( SystemHeap
, 0, item
->text
);
646 /***********************************************************************
647 * MENU_FindItemByCoords
649 * Find the item at the specified coordinates (screen coords). Does
650 * not work for child windows and therefore should not be called for
651 * an arbitrary system menu.
653 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
,
654 POINT pt
, UINT
*pos
)
660 if (!GetWindowRect(menu
->hWnd
,&wrect
)) return NULL
;
661 pt
.x
-= wrect
.left
;pt
.y
-= wrect
.top
;
663 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
665 if ((pt
.x
>= item
->rect
.left
) && (pt
.x
< item
->rect
.right
) &&
666 (pt
.y
>= item
->rect
.top
) && (pt
.y
< item
->rect
.bottom
))
676 /***********************************************************************
679 * Find the menu item selected by a key press.
680 * Return item id, -1 if none, -2 if we should close the menu.
682 static UINT
MENU_FindItemByKey( HWND hwndOwner
, HMENU hmenu
,
683 UINT key
, BOOL forceMenuChar
)
685 TRACE("\tlooking for '%c' in [%04x]\n", (char)key
, (UINT16
)hmenu
);
687 if (!IsMenu( hmenu
))
689 WND
* w
= WIN_FindWndPtr(hwndOwner
);
690 hmenu
= GetSubMenu(w
->hSysMenu
, 0);
691 WIN_ReleaseWndPtr(w
);
696 POPUPMENU
*menu
= MENU_GetMenu( hmenu
);
697 MENUITEM
*item
= menu
->items
;
705 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
707 if (item
->text
&& (IS_STRING_ITEM(item
->fType
)))
709 WCHAR
*p
= item
->text
- 2;
712 p
= strchrW (p
+ 2, '&');
714 while (p
!= NULL
&& p
[1] == '&');
715 if (p
&& (toupper(p
[1]) == key
)) return i
;
719 menuchar
= SendMessageA( hwndOwner
, WM_MENUCHAR
,
720 MAKEWPARAM( key
, menu
->wFlags
), hmenu
);
721 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
722 if (HIWORD(menuchar
) == 1) return (UINT
)(-2);
726 /***********************************************************************
729 * Load the bitmap associated with the magic menu item and its style
732 static HBITMAP
MENU_LoadMagicItem(UINT id
, BOOL hilite
, DWORD dwItemData
)
735 * Magic menu item id's section
736 * These magic id's are used by windows to insert "standard" mdi
737 * buttons (minimize,restore,close) on menu. Under windows,
738 * these magic id's make sure the right things appear when those
739 * bitmap buttons are pressed/selected/released.
743 { case HBMMENU_SYSTEM
:
744 return (dwItemData
) ?
745 (HBITMAP
)dwItemData
:
746 (hilite
? hBmpMinimizeD
: hBmpMinimize
);
747 case HBMMENU_MBAR_RESTORE
:
748 return (hilite
? hBmpMaximizeD
: hBmpMaximize
);
749 case HBMMENU_MBAR_MINIMIZE
:
750 return (hilite
? hBmpMinimizeD
: hBmpMinimize
);
751 case HBMMENU_MBAR_CLOSE
:
752 return (hilite
? hBmpCloseD
: hBmpClose
);
753 case HBMMENU_CALLBACK
:
754 case HBMMENU_MBAR_CLOSE_D
:
755 case HBMMENU_MBAR_MINIMIZE_D
:
756 case HBMMENU_POPUP_CLOSE
:
757 case HBMMENU_POPUP_RESTORE
:
758 case HBMMENU_POPUP_MAXIMIZE
:
759 case HBMMENU_POPUP_MINIMIZE
:
761 FIXME("Magic 0x%08x not implemented\n", id
);
767 /***********************************************************************
770 * Calculate the size of the menu item and store it in lpitem->rect.
772 static void MENU_CalcItemSize( HDC hdc
, MENUITEM
*lpitem
, HWND hwndOwner
,
773 INT orgX
, INT orgY
, BOOL menuBar
)
776 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
778 TRACE("dc=0x%04x owner=0x%04x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
779 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem
,
780 (menuBar
? " (MenuBar)" : ""));
782 SetRect( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
784 if (lpitem
->fType
& MF_OWNERDRAW
)
787 ** Experimentation under Windows reveals that an owner-drawn
788 ** menu is expected to return the size of the content part of
789 ** the menu item, not including the checkmark nor the submenu
790 ** arrow. Windows adds those values itself and returns the
791 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
793 MEASUREITEMSTRUCT mis
;
794 mis
.CtlType
= ODT_MENU
;
796 mis
.itemID
= lpitem
->wID
;
797 mis
.itemData
= (DWORD
)lpitem
->dwItemData
;
800 SendMessageA( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
801 lpitem
->rect
.right
+= mis
.itemWidth
;
805 lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
808 /* under at least win95 you seem to be given a standard
809 height for the menu and the height value is ignored */
811 if (TWEAK_WineLook
== WIN31_LOOK
)
812 lpitem
->rect
.bottom
+= GetSystemMetrics(SM_CYMENU
);
814 lpitem
->rect
.bottom
+= GetSystemMetrics(SM_CYMENU
)-1;
817 lpitem
->rect
.bottom
+= mis
.itemHeight
;
819 TRACE("id=%04x size=%dx%d\n",
820 lpitem
->wID
, mis
.itemWidth
, mis
.itemHeight
);
821 /* Fall through to get check/arrow width calculation. */
824 if (lpitem
->fType
& MF_SEPARATOR
)
826 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
832 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
833 if (lpitem
->fType
& MF_POPUP
)
834 lpitem
->rect
.right
+= arrow_bitmap_width
;
837 if (lpitem
->fType
& MF_OWNERDRAW
)
840 if (IS_BITMAP_ITEM(lpitem
->fType
))
845 /* Check if there is a magic menu item associated with this item */
846 if (IS_MAGIC_ITEM(lpitem
->text
))
848 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
, (lpitem
->fType
& MF_HILITE
),
852 resBmp
= (HBITMAP
)lpitem
->text
;
854 if (GetObjectA(resBmp
, sizeof(bm
), &bm
))
856 lpitem
->rect
.right
+= bm
.bmWidth
;
857 lpitem
->rect
.bottom
+= bm
.bmHeight
;
858 if (TWEAK_WineLook
== WIN98_LOOK
) {
859 /* Leave space for the sunken border */
860 lpitem
->rect
.right
+= 2;
861 lpitem
->rect
.bottom
+= 2;
868 /* If we get here, then it must be a text item */
869 if (IS_STRING_ITEM( lpitem
->fType
))
872 GetTextExtentPoint32W(hdc
, lpitem
->text
, strlenW(lpitem
->text
), &size
);
874 lpitem
->rect
.right
+= size
.cx
;
875 if (TWEAK_WineLook
== WIN31_LOOK
)
876 lpitem
->rect
.bottom
+= max( size
.cy
, GetSystemMetrics(SM_CYMENU
) );
878 lpitem
->rect
.bottom
+= max(size
.cy
, GetSystemMetrics(SM_CYMENU
)-1);
883 lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
885 else if ((p
= strchrW( lpitem
->text
, '\t' )) != NULL
)
887 /* Item contains a tab (only meaningful in popup menus) */
888 GetTextExtentPoint32W(hdc
, lpitem
->text
, (int)(p
- lpitem
->text
) , &size
);
889 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+ size
.cx
;
890 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
894 if (strchrW( lpitem
->text
, '\b' ))
895 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
896 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
897 - arrow_bitmap_width
;
900 TRACE("(%d,%d)-(%d,%d)\n", lpitem
->rect
.left
, lpitem
->rect
.top
, lpitem
->rect
.right
, lpitem
->rect
.bottom
);
904 /***********************************************************************
905 * MENU_PopupMenuCalcSize
907 * Calculate the size of a popup menu.
909 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND hwndOwner
)
914 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
916 lppop
->Width
= lppop
->Height
= 0;
917 if (lppop
->nItems
== 0) return;
920 SelectObject( hdc
, hMenuFont
);
923 maxX
= (TWEAK_WineLook
== WIN31_LOOK
) ? GetSystemMetrics(SM_CXBORDER
) : 2+1 ;
925 while (start
< lppop
->nItems
)
927 lpitem
= &lppop
->items
[start
];
929 orgY
= (TWEAK_WineLook
== WIN31_LOOK
) ? GetSystemMetrics(SM_CYBORDER
) : 2;
931 maxTab
= maxTabWidth
= 0;
933 /* Parse items until column break or end of menu */
934 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
937 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
939 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
941 if (lpitem
->fType
& MF_MENUBARBREAK
) orgX
++;
942 maxX
= max( maxX
, lpitem
->rect
.right
);
943 orgY
= lpitem
->rect
.bottom
;
944 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
946 maxTab
= max( maxTab
, lpitem
->xTab
);
947 maxTabWidth
= max(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
951 /* Finish the column (set all items to the largest width found) */
952 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
953 for (lpitem
= &lppop
->items
[start
]; start
< i
; start
++, lpitem
++)
955 lpitem
->rect
.right
= maxX
;
956 if (IS_STRING_ITEM(lpitem
->fType
) && lpitem
->xTab
)
957 lpitem
->xTab
= maxTab
;
960 lppop
->Height
= max( lppop
->Height
, orgY
);
965 /* space for 3d border */
966 if(TWEAK_WineLook
> WIN31_LOOK
)
976 /***********************************************************************
977 * MENU_MenuBarCalcSize
979 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
980 * height is off by 1 pixel which causes lengthy window relocations when
981 * active document window is maximized/restored.
983 * Calculate the size of the menu bar.
985 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
,
986 LPPOPUPMENU lppop
, HWND hwndOwner
)
989 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
991 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
992 if (lppop
->nItems
== 0) return;
993 TRACE("left=%d top=%d right=%d bottom=%d\n",
994 lprect
->left
, lprect
->top
, lprect
->right
, lprect
->bottom
);
995 lppop
->Width
= lprect
->right
- lprect
->left
;
997 maxY
= lprect
->top
+1;
1000 while (start
< lppop
->nItems
)
1002 lpitem
= &lppop
->items
[start
];
1003 orgX
= lprect
->left
;
1006 /* Parse items until line break or end of menu */
1007 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
1009 if ((helpPos
== -1) && (lpitem
->fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
1011 (lpitem
->fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1013 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
1015 debug_print_menuitem (" item: ", lpitem
, "");
1016 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
1018 if (lpitem
->rect
.right
> lprect
->right
)
1020 if (i
!= start
) break;
1021 else lpitem
->rect
.right
= lprect
->right
;
1023 maxY
= max( maxY
, lpitem
->rect
.bottom
);
1024 orgX
= lpitem
->rect
.right
;
1027 /* Finish the line (set all items to the largest height found) */
1028 while (start
< i
) lppop
->items
[start
++].rect
.bottom
= maxY
;
1031 lprect
->bottom
= maxY
;
1032 lppop
->Height
= lprect
->bottom
- lprect
->top
;
1034 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1035 /* the last item (if several lines, only move the last line) */
1036 lpitem
= &lppop
->items
[lppop
->nItems
-1];
1037 orgY
= lpitem
->rect
.top
;
1038 orgX
= lprect
->right
;
1039 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--) {
1040 if ( (helpPos
==-1) || (helpPos
>i
) )
1042 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
1043 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
1044 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
1045 lpitem
->rect
.right
= orgX
;
1046 orgX
= lpitem
->rect
.left
;
1050 /***********************************************************************
1053 * Draw a single menu item.
1055 static void MENU_DrawMenuItem( HWND hwnd
, HMENU hmenu
, HWND hwndOwner
, HDC hdc
, MENUITEM
*lpitem
,
1056 UINT height
, BOOL menuBar
, UINT odaction
)
1060 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem
, "");
1062 if (lpitem
->fType
& MF_SYSMENU
)
1064 if( !IsIconic(hwnd
) ) {
1065 if (TWEAK_WineLook
> WIN31_LOOK
)
1066 NC_DrawSysButton95( hwnd
, hdc
,
1068 (MF_HILITE
| MF_MOUSESELECT
) );
1070 NC_DrawSysButton( hwnd
, hdc
,
1072 (MF_HILITE
| MF_MOUSESELECT
) );
1078 if (lpitem
->fType
& MF_OWNERDRAW
)
1081 ** Experimentation under Windows reveals that an owner-drawn
1082 ** menu is given the rectangle which includes the space it requested
1083 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1084 ** and a popup-menu arrow. This is the value of lpitem->rect.
1085 ** Windows will leave all drawing to the application except for
1086 ** the popup-menu arrow. Windows always draws that itself, after
1087 ** the menu owner has finished drawing.
1091 dis
.CtlType
= ODT_MENU
;
1093 dis
.itemID
= lpitem
->wID
;
1094 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1096 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1097 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
;
1098 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1099 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1100 dis
.hwndItem
= hmenu
;
1102 dis
.rcItem
= lpitem
->rect
;
1103 TRACE("Ownerdraw: owner=%04x itemID=%d, itemState=%d, itemAction=%d, "
1104 "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n", hwndOwner
,
1105 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1106 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1108 SendMessageA( hwndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&dis
);
1109 /* Fall through to draw popup-menu arrow */
1112 TRACE("rect={%d,%d,%d,%d}\n", lpitem
->rect
.left
, lpitem
->rect
.top
,
1113 lpitem
->rect
.right
,lpitem
->rect
.bottom
);
1115 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1117 rect
= lpitem
->rect
;
1119 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1121 if (lpitem
->fState
& MF_HILITE
)
1123 if(TWEAK_WineLook
== WIN98_LOOK
)
1126 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1128 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1130 else /* Not Win98 Look */
1132 if(!IS_BITMAP_ITEM(lpitem
->fType
))
1133 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1137 FillRect( hdc
, &rect
, GetSysColorBrush(COLOR_MENU
) );
1140 SetBkMode( hdc
, TRANSPARENT
);
1142 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1144 /* vertical separator */
1145 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1147 if (TWEAK_WineLook
> WIN31_LOOK
)
1151 rc
.bottom
= height
- 3;
1152 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1156 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1157 MoveToEx( hdc
, rect
.left
, 0, NULL
);
1158 LineTo( hdc
, rect
.left
, height
);
1162 /* horizontal separator */
1163 if (lpitem
->fType
& MF_SEPARATOR
)
1165 if (TWEAK_WineLook
> WIN31_LOOK
)
1170 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1171 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1175 SelectObject( hdc
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1176 MoveToEx( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2, NULL
);
1177 LineTo( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
1185 if (lpitem
->fState
& MF_HILITE
)
1187 if(TWEAK_WineLook
== WIN98_LOOK
)
1190 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1191 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1193 if(lpitem
->fState
& MF_GRAYED
)
1194 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1196 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1197 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1200 else /* Not Win98 Look */
1202 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1203 if(!IS_BITMAP_ITEM(lpitem
->fType
))
1204 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1209 if (lpitem
->fState
& MF_GRAYED
)
1210 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1212 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1213 SetBkColor( hdc
, GetSysColor( COLOR_MENU
) );
1216 /* helper lines for debugging */
1217 /* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1218 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1219 MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
1220 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1225 INT y
= rect
.top
+ rect
.bottom
;
1226 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1227 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1229 if (!(lpitem
->fType
& MF_OWNERDRAW
))
1231 /* Draw the check mark
1234 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1236 HBITMAP bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hCheckBit
: lpitem
->hUnCheckBit
;
1237 if (bm
) /* we have a custom bitmap */
1239 HDC hdcMem
= CreateCompatibleDC( hdc
);
1240 SelectObject( hdcMem
, bm
);
1241 BitBlt( hdc
, rect
.left
, (y
- check_bitmap_height
) / 2,
1242 check_bitmap_width
, check_bitmap_height
,
1243 hdcMem
, 0, 0, SRCCOPY
);
1246 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1249 HBITMAP bm
= CreateBitmap( check_bitmap_width
, check_bitmap_height
, 1, 1, NULL
);
1250 HDC hdcMem
= CreateCompatibleDC( hdc
);
1251 SelectObject( hdcMem
, bm
);
1252 SetRect( &r
, 0, 0, check_bitmap_width
, check_bitmap_height
);
1253 DrawFrameControl( hdcMem
, &r
, DFC_MENU
,
1254 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1255 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1256 BitBlt( hdc
, rect
.left
, (y
- r
.bottom
) / 2, r
.right
, r
.bottom
,
1257 hdcMem
, 0, 0, SRCCOPY
);
1263 /* Draw the popup-menu arrow */
1264 if (lpitem
->fType
& MF_POPUP
)
1266 HDC hdcMem
= CreateCompatibleDC( hdc
);
1267 HBITMAP hOrigBitmap
;
1269 hOrigBitmap
= SelectObject( hdcMem
, hStdMnArrow
);
1270 BitBlt( hdc
, rect
.right
- arrow_bitmap_width
- 1,
1271 (y
- arrow_bitmap_height
) / 2,
1272 arrow_bitmap_width
, arrow_bitmap_height
,
1273 hdcMem
, 0, 0, SRCCOPY
);
1274 SelectObject( hdcMem
, hOrigBitmap
);
1278 rect
.left
+= check_bitmap_width
;
1279 rect
.right
-= arrow_bitmap_width
;
1282 /* Done for owner-drawn */
1283 if (lpitem
->fType
& MF_OWNERDRAW
)
1286 /* Draw the item text or bitmap */
1287 if (IS_BITMAP_ITEM(lpitem
->fType
))
1294 HDC hdcMem
= CreateCompatibleDC( hdc
);
1297 * Check if there is a magic menu item associated with this item
1298 * and load the appropriate bitmap
1300 if (IS_MAGIC_ITEM(lpitem
->text
))
1302 resBmp
= MENU_LoadMagicItem((int)lpitem
->text
, (lpitem
->fState
& MF_HILITE
),
1303 lpitem
->dwItemData
);
1306 resBmp
= (HBITMAP
)lpitem
->text
;
1311 GetObjectA( resBmp
, sizeof(bm
), &bm
);
1313 SelectObject(hdcMem
,resBmp
);
1315 /* handle fontsize > bitmap_height */
1316 h
=rect
.bottom
- rect
.top
;
1317 top
= (h
>bm
.bmHeight
) ?
1318 rect
.top
+(h
-bm
.bmHeight
)/2 : rect
.top
;
1319 w
=rect
.right
- rect
.left
;
1321 if (TWEAK_WineLook
== WIN95_LOOK
) {
1322 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_ITEM(lpitem
->text
)) ? NOTSRCCOPY
: SRCCOPY
;
1323 if ((lpitem
->fState
& MF_HILITE
) && IS_BITMAP_ITEM(lpitem
->fType
))
1324 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1328 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_ITEM(lpitem
->text
) && (!menuBar
)) ? MERGEPAINT
: SRCCOPY
;
1330 BitBlt( hdc
, left
, top
, w
,
1339 /* No bitmap - process text if present */
1340 else if (IS_STRING_ITEM(lpitem
->fType
))
1345 UINT uFormat
= (menuBar
) ?
1346 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
1347 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1349 if ( lpitem
->fState
& MFS_DEFAULT
)
1351 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
1356 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1357 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1358 i
= strlenW( lpitem
->text
);
1362 for (i
= 0; lpitem
->text
[i
]; i
++)
1363 if ((lpitem
->text
[i
] == '\t') || (lpitem
->text
[i
] == '\b'))
1367 if( !(TWEAK_WineLook
== WIN31_LOOK
) && (lpitem
->fState
& MF_GRAYED
))
1369 if (!(lpitem
->fState
& MF_HILITE
) )
1371 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1372 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1373 DrawTextW( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1374 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1376 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1379 DrawTextW( hdc
, lpitem
->text
, i
, &rect
, uFormat
);
1381 /* paint the shortcut text */
1382 if (lpitem
->text
[i
]) /* There's a tab or flush-right char */
1384 if (lpitem
->text
[i
] == '\t')
1386 rect
.left
= lpitem
->xTab
;
1387 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1391 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1394 if( !(TWEAK_WineLook
== WIN31_LOOK
) && (lpitem
->fState
& MF_GRAYED
))
1396 if (!(lpitem
->fState
& MF_HILITE
) )
1398 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1399 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1400 DrawTextW( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1401 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1403 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1405 DrawTextW( hdc
, lpitem
->text
+ i
+ 1, -1, &rect
, uFormat
);
1409 SelectObject (hdc
, hfontOld
);
1414 /***********************************************************************
1415 * MENU_DrawPopupMenu
1417 * Paint a popup menu.
1419 static void MENU_DrawPopupMenu( HWND hwnd
, HDC hdc
, HMENU hmenu
)
1421 HBRUSH hPrevBrush
= 0;
1424 TRACE("wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd
, hdc
, hmenu
);
1426 GetClientRect( hwnd
, &rect
);
1428 if(TWEAK_WineLook
== WIN31_LOOK
)
1430 rect
.bottom
-= POPUP_YSHADE
* GetSystemMetrics(SM_CYBORDER
);
1431 rect
.right
-= POPUP_XSHADE
* GetSystemMetrics(SM_CXBORDER
);
1434 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1435 && (SelectObject( hdc
, hMenuFont
)))
1439 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1441 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1447 /* draw 3-d shade */
1448 if(TWEAK_WineLook
== WIN31_LOOK
) {
1449 SelectObject( hdc
, hShadeBrush
);
1450 SetBkMode( hdc
, TRANSPARENT
);
1451 ropPrev
= SetROP2( hdc
, R2_MASKPEN
);
1453 i
= rect
.right
; /* why SetBrushOrg() doesn't? */
1454 PatBlt( hdc
, i
& 0xfffffffe,
1455 rect
.top
+ POPUP_YSHADE
*GetSystemMetrics(SM_CYBORDER
),
1456 i
%2 + POPUP_XSHADE
*GetSystemMetrics(SM_CXBORDER
),
1457 rect
.bottom
- rect
.top
, 0x00a000c9 );
1459 PatBlt( hdc
, rect
.left
+ POPUP_XSHADE
*GetSystemMetrics(SM_CXBORDER
),
1460 i
& 0xfffffffe,rect
.right
- rect
.left
,
1461 i
%2 + POPUP_YSHADE
*GetSystemMetrics(SM_CYBORDER
), 0x00a000c9 );
1462 SelectObject( hdc
, hPrevPen
);
1463 SelectObject( hdc
, hPrevBrush
);
1464 SetROP2( hdc
, ropPrev
);
1467 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1469 /* draw menu items */
1471 menu
= MENU_GetMenu( hmenu
);
1472 if (menu
&& menu
->nItems
)
1477 for (u
= menu
->nItems
, item
= menu
->items
; u
> 0; u
--, item
++)
1478 MENU_DrawMenuItem( hwnd
, hmenu
, menu
->hwndOwner
, hdc
, item
,
1479 menu
->Height
, FALSE
, ODA_DRAWENTIRE
);
1484 SelectObject( hdc
, hPrevBrush
);
1489 /***********************************************************************
1492 * Paint a menu bar. Returns the height of the menu bar.
1493 * called from [windows/nonclient.c]
1495 UINT
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1502 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1504 lppop
= MENU_GetMenu ((HMENU
)wndPtr
->wIDmenu
);
1505 if (lppop
== NULL
|| lprect
== NULL
)
1507 retvalue
= GetSystemMetrics(SM_CYMENU
);
1511 TRACE("(%04x, %p, %p)\n", hDC
, lprect
, lppop
);
1513 hfontOld
= SelectObject( hDC
, hMenuFont
);
1515 if (lppop
->Height
== 0)
1516 MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
1518 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
1522 retvalue
= lppop
->Height
;
1526 FillRect(hDC
, lprect
, GetSysColorBrush(COLOR_MENU
) );
1528 if (TWEAK_WineLook
== WIN31_LOOK
)
1530 SelectObject( hDC
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1531 MoveToEx( hDC
, lprect
->left
, lprect
->bottom
, NULL
);
1532 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1536 SelectObject( hDC
, GetSysColorPen(COLOR_3DFACE
));
1537 MoveToEx( hDC
, lprect
->left
, lprect
->bottom
, NULL
);
1538 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
1541 if (lppop
->nItems
== 0)
1543 retvalue
= GetSystemMetrics(SM_CYMENU
);
1547 for (i
= 0; i
< lppop
->nItems
; i
++)
1549 MENU_DrawMenuItem( hwnd
, (HMENU
)wndPtr
->wIDmenu
, hwnd
,
1550 hDC
, &lppop
->items
[i
], lppop
->Height
, TRUE
, ODA_DRAWENTIRE
);
1552 retvalue
= lppop
->Height
;
1556 SelectObject (hDC
, hfontOld
);
1558 WIN_ReleaseWndPtr(wndPtr
);
1562 /***********************************************************************
1563 * MENU_PatchResidentPopup
1565 BOOL
MENU_PatchResidentPopup( HQUEUE16 checkQueue
, WND
* checkWnd
)
1567 WND
*pTPWnd
= MENU_GetTopPopupWnd();
1573 TRACE("patching resident popup: %04x %04x [%04x %04x]\n",
1574 checkQueue
, checkWnd
? checkWnd
->hwndSelf
: 0, pTPWnd
->hmemTaskQ
,
1575 pTPWnd
->owner
? pTPWnd
->owner
->hwndSelf
: 0);
1577 switch( checkQueue
)
1579 case 0: /* checkWnd is the new popup owner */
1582 pTPWnd
->owner
= checkWnd
;
1583 if( pTPWnd
->hmemTaskQ
!= checkWnd
->hmemTaskQ
)
1584 hTask
= QUEUE_GetQueueTask( checkWnd
->hmemTaskQ
);
1588 case 0xFFFF: /* checkWnd is destroyed */
1589 if( pTPWnd
->owner
== checkWnd
)
1590 pTPWnd
->owner
= NULL
;
1591 MENU_ReleaseTopPopupWnd();
1594 default: /* checkQueue is exiting */
1595 if( pTPWnd
->hmemTaskQ
== checkQueue
)
1597 hTask
= QUEUE_GetQueueTask( pTPWnd
->hmemTaskQ
);
1598 hTask
= TASK_GetNextTask( hTask
);
1605 TDB
* task
= (TDB
*)GlobalLock16( hTask
);
1608 pTPWnd
->hInstance
= task
->hInstance
;
1609 pTPWnd
->hmemTaskQ
= task
->hQueue
;
1610 MENU_ReleaseTopPopupWnd();
1613 else WARN("failed to patch resident popup.\n");
1616 MENU_ReleaseTopPopupWnd();
1620 /***********************************************************************
1623 * Display a popup menu.
1625 static BOOL
MENU_ShowPopup( HWND hwndOwner
, HMENU hmenu
, UINT id
,
1626 INT x
, INT y
, INT xanchor
, INT yanchor
)
1629 WND
*wndOwner
= NULL
;
1631 TRACE("owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1632 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
1634 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
1635 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1637 menu
->items
[menu
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1638 menu
->FocusedItem
= NO_SELECTED_ITEM
;
1641 /* store the owner for DrawItem */
1642 menu
->hwndOwner
= hwndOwner
;
1644 if( (wndOwner
= WIN_FindWndPtr( hwndOwner
)) )
1648 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
1650 /* adjust popup menu pos so that it fits within the desktop */
1652 width
= menu
->Width
+ GetSystemMetrics(SM_CXBORDER
);
1653 height
= menu
->Height
+ GetSystemMetrics(SM_CYBORDER
);
1655 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1658 x
-= width
- xanchor
;
1659 if( x
+ width
> GetSystemMetrics(SM_CXSCREEN
))
1660 x
= GetSystemMetrics(SM_CXSCREEN
) - width
;
1664 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1667 y
-= height
+ yanchor
;
1668 if( y
+ height
> GetSystemMetrics(SM_CYSCREEN
))
1669 y
= GetSystemMetrics(SM_CYSCREEN
) - height
;
1673 if( TWEAK_WineLook
== WIN31_LOOK
)
1675 width
+= POPUP_XSHADE
* GetSystemMetrics(SM_CXBORDER
); /* add space for shading */
1676 height
+= POPUP_YSHADE
* GetSystemMetrics(SM_CYBORDER
);
1679 /* NOTE: In Windows, top menu popup is not owned. */
1680 if (!pTopPopupWnd
) /* create top level popup menu window */
1682 assert( uSubPWndLevel
== 0 );
1684 pTopPopupWnd
= WIN_FindWndPtr(CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1685 WS_POPUP
, x
, y
, width
, height
,
1686 hwndOwner
, 0, wndOwner
->hInstance
,
1690 WIN_ReleaseWndPtr(wndOwner
);
1693 menu
->hWnd
= pTopPopupWnd
->hwndSelf
;
1694 MENU_ReleaseTopPopupWnd();
1699 /* create a new window for the submenu */
1701 menu
->hWnd
= CreateWindowA( POPUPMENU_CLASS_ATOM
, NULL
,
1702 WS_POPUP
, x
, y
, width
, height
,
1703 hwndOwner
, 0, wndOwner
->hInstance
,
1707 WIN_ReleaseWndPtr(wndOwner
);
1711 else /* top level popup menu window already exists */
1713 WND
*pTPWnd
= MENU_GetTopPopupWnd();
1714 menu
->hWnd
= pTPWnd
->hwndSelf
;
1716 MENU_PatchResidentPopup( 0, wndOwner
);
1717 SendMessageA( pTPWnd
->hwndSelf
, MM_SETMENUHANDLE
, (WPARAM16
)hmenu
, 0L);
1719 /* adjust its size */
1721 SetWindowPos( menu
->hWnd
, 0, x
, y
, width
, height
,
1722 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_NOREDRAW
);
1723 MENU_ReleaseTopPopupWnd();
1726 uSubPWndLevel
++; /* menu level counter */
1728 /* Display the window */
1730 SetWindowPos( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
1731 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1732 UpdateWindow( menu
->hWnd
);
1733 WIN_ReleaseWndPtr(wndOwner
);
1740 /***********************************************************************
1743 static void MENU_SelectItem( HWND hwndOwner
, HMENU hmenu
, UINT wIndex
,
1744 BOOL sendMenuSelect
, HMENU topmenu
)
1749 TRACE("owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
1751 lppop
= MENU_GetMenu( hmenu
);
1752 if ((!lppop
) || (!lppop
->nItems
)) return;
1754 if (lppop
->FocusedItem
== wIndex
) return;
1755 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC( lppop
->hWnd
);
1756 else hdc
= GetDCEx( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
1758 SelectObject( hdc
, hMenuFont
);
1760 /* Clear previous highlighted item */
1761 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1763 lppop
->items
[lppop
->FocusedItem
].fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1764 MENU_DrawMenuItem(lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,&lppop
->items
[lppop
->FocusedItem
],
1765 lppop
->Height
, !(lppop
->wFlags
& MF_POPUP
),
1769 /* Highlight new item (if any) */
1770 lppop
->FocusedItem
= wIndex
;
1771 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
1773 if(!(lppop
->items
[wIndex
].fType
& MF_SEPARATOR
)) {
1774 lppop
->items
[wIndex
].fState
|= MF_HILITE
;
1775 MENU_DrawMenuItem( lppop
->hWnd
, hmenu
, hwndOwner
, hdc
,
1776 &lppop
->items
[wIndex
], lppop
->Height
,
1777 !(lppop
->wFlags
& MF_POPUP
), ODA_SELECT
);
1781 MENUITEM
*ip
= &lppop
->items
[lppop
->FocusedItem
];
1782 SendMessageA( hwndOwner
, WM_MENUSELECT
,
1783 MAKELONG(ip
->fType
& MF_POPUP
? wIndex
: ip
->wID
,
1784 ip
->fType
| ip
->fState
| MF_MOUSESELECT
|
1785 (lppop
->wFlags
& MF_SYSMENU
)), hmenu
);
1788 else if (sendMenuSelect
) {
1791 if((pos
=MENU_FindSubMenu(&topmenu
, hmenu
))!=NO_SELECTED_ITEM
){
1792 POPUPMENU
*ptm
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( topmenu
);
1793 MENUITEM
*ip
= &ptm
->items
[pos
];
1794 SendMessageA( hwndOwner
, WM_MENUSELECT
, MAKELONG(pos
,
1795 ip
->fType
| ip
->fState
| MF_MOUSESELECT
|
1796 (ptm
->wFlags
& MF_SYSMENU
)), topmenu
);
1800 ReleaseDC( lppop
->hWnd
, hdc
);
1804 /***********************************************************************
1805 * MENU_MoveSelection
1807 * Moves currently selected item according to the offset parameter.
1808 * If there is no selection then it should select the last item if
1809 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1811 static void MENU_MoveSelection( HWND hwndOwner
, HMENU hmenu
, INT offset
)
1816 TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner
, hmenu
, offset
);
1818 menu
= MENU_GetMenu( hmenu
);
1819 if ((!menu
) || (!menu
->items
)) return;
1821 if ( menu
->FocusedItem
!= NO_SELECTED_ITEM
)
1823 if( menu
->nItems
== 1 ) return; else
1824 for (i
= menu
->FocusedItem
+ offset
; i
>= 0 && i
< menu
->nItems
1826 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1828 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
1833 for ( i
= (offset
> 0) ? 0 : menu
->nItems
- 1;
1834 i
>= 0 && i
< menu
->nItems
; i
+= offset
)
1835 if (!(menu
->items
[i
].fType
& MF_SEPARATOR
))
1837 MENU_SelectItem( hwndOwner
, hmenu
, i
, TRUE
, 0 );
1843 /**********************************************************************
1846 * Set an item flags, id and text ptr. Called by InsertMenu() and
1849 static BOOL
MENU_SetItemData( MENUITEM
*item
, UINT flags
, UINT id
,
1852 LPWSTR prevText
= IS_STRING_ITEM(item
->fType
) ? item
->text
: NULL
;
1854 debug_print_menuitem("MENU_SetItemData from: ", item
, "");
1856 if (IS_STRING_ITEM(flags
))
1860 flags
|= MF_SEPARATOR
;
1866 /* Item beginning with a backspace is a help item */
1872 if (!(text
= HEAP_strdupW( SystemHeap
, 0, str
))) return FALSE
;
1876 else if (IS_BITMAP_ITEM(flags
))
1877 item
->text
= (LPWSTR
)(HBITMAP
)LOWORD(str
);
1878 else item
->text
= NULL
;
1880 if (flags
& MF_OWNERDRAW
)
1881 item
->dwItemData
= (DWORD
)str
;
1883 item
->dwItemData
= 0;
1885 if ((item
->fType
& MF_POPUP
) && (flags
& MF_POPUP
) && (item
->hSubMenu
!= id
) )
1886 DestroyMenu( item
->hSubMenu
); /* ModifyMenu() spec */
1888 if (flags
& MF_POPUP
)
1890 POPUPMENU
*menu
= MENU_GetMenu((UINT16
)id
);
1891 if (menu
) menu
->wFlags
|= MF_POPUP
;
1903 if (flags
& MF_POPUP
)
1904 item
->hSubMenu
= id
;
1906 if ((item
->fType
& MF_POPUP
) && !(flags
& MF_POPUP
) )
1907 flags
|= MF_POPUP
; /* keep popup */
1909 item
->fType
= flags
& TYPE_MASK
;
1910 item
->fState
= (flags
& STATE_MASK
) &
1911 ~(MF_HILITE
| MF_MOUSESELECT
| MF_BYPOSITION
);
1914 /* Don't call SetRectEmpty here! */
1917 if (prevText
) HeapFree( SystemHeap
, 0, prevText
);
1919 debug_print_menuitem("MENU_SetItemData to : ", item
, "");
1924 /**********************************************************************
1927 * Insert a new item into a menu.
1929 static MENUITEM
*MENU_InsertItem( HMENU hMenu
, UINT pos
, UINT flags
)
1934 if (!(menu
= MENU_GetMenu(hMenu
)))
1937 /* Find where to insert new item */
1939 if (flags
& MF_BYPOSITION
) {
1940 if (pos
> menu
->nItems
)
1943 if (!MENU_FindItem( &hMenu
, &pos
, flags
))
1946 if (!(menu
= MENU_GetMenu( hMenu
)))
1951 /* Create new items array */
1953 newItems
= HeapAlloc( SystemHeap
, 0, sizeof(MENUITEM
) * (menu
->nItems
+1) );
1956 WARN("allocation failed\n" );
1959 if (menu
->nItems
> 0)
1961 /* Copy the old array into the new one */
1962 if (pos
> 0) memcpy( newItems
, menu
->items
, pos
* sizeof(MENUITEM
) );
1963 if (pos
< menu
->nItems
) memcpy( &newItems
[pos
+1], &menu
->items
[pos
],
1964 (menu
->nItems
-pos
)*sizeof(MENUITEM
) );
1965 HeapFree( SystemHeap
, 0, menu
->items
);
1967 menu
->items
= newItems
;
1969 memset( &newItems
[pos
], 0, sizeof(*newItems
) );
1970 menu
->Height
= 0; /* force size recalculate */
1971 return &newItems
[pos
];
1975 /**********************************************************************
1976 * MENU_ParseResource
1978 * Parse a standard menu resource and add items to the menu.
1979 * Return a pointer to the end of the resource.
1981 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1988 flags
= GET_WORD(res
);
1989 res
+= sizeof(WORD
);
1990 if (!(flags
& MF_POPUP
))
1993 res
+= sizeof(WORD
);
1995 if (!IS_STRING_ITEM(flags
))
1996 ERR("not a string item %04x\n", flags
);
1998 if (!unicode
) res
+= strlen(str
) + 1;
1999 else res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
2000 if (flags
& MF_POPUP
)
2002 HMENU hSubMenu
= CreatePopupMenu();
2003 if (!hSubMenu
) return NULL
;
2004 if (!(res
= MENU_ParseResource( res
, hSubMenu
, unicode
)))
2006 if (!unicode
) AppendMenuA( hMenu
, flags
, (UINT
)hSubMenu
, str
);
2007 else AppendMenuW( hMenu
, flags
, (UINT
)hSubMenu
, (LPCWSTR
)str
);
2009 else /* Not a popup */
2011 if (!unicode
) AppendMenuA( hMenu
, flags
, id
, *str
? str
: NULL
);
2012 else AppendMenuW( hMenu
, flags
, id
,
2013 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
2015 } while (!(flags
& MF_END
));
2020 /**********************************************************************
2021 * MENUEX_ParseResource
2023 * Parse an extended menu resource and add items to the menu.
2024 * Return a pointer to the end of the resource.
2026 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
2032 mii
.cbSize
= sizeof(mii
);
2033 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
2034 mii
.fType
= GET_DWORD(res
);
2035 res
+= sizeof(DWORD
);
2036 mii
.fState
= GET_DWORD(res
);
2037 res
+= sizeof(DWORD
);
2038 mii
.wID
= GET_DWORD(res
);
2039 res
+= sizeof(DWORD
);
2040 resinfo
= GET_WORD(res
); /* FIXME: for 16-bit apps this is a byte. */
2041 res
+= sizeof(WORD
);
2042 /* Align the text on a word boundary. */
2043 res
+= (~((int)res
- 1)) & 1;
2044 mii
.dwTypeData
= (LPWSTR
) res
;
2045 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
2046 /* Align the following fields on a dword boundary. */
2047 res
+= (~((int)res
- 1)) & 3;
2049 /* FIXME: This is inefficient and cannot be optimised away by gcc. */
2051 LPSTR newstr
= HEAP_strdupWtoA(GetProcessHeap(),
2053 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
2054 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, newstr
);
2055 HeapFree( GetProcessHeap(), 0, newstr
);
2058 if (resinfo
& 1) { /* Pop-up? */
2059 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2060 res
+= sizeof(DWORD
);
2061 mii
.hSubMenu
= CreatePopupMenu();
2064 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
2065 DestroyMenu(mii
.hSubMenu
);
2068 mii
.fMask
|= MIIM_SUBMENU
;
2069 mii
.fType
|= MF_POPUP
;
2071 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
2072 } while (!(resinfo
& MF_END
));
2077 /***********************************************************************
2080 * Return the handle of the selected sub-popup menu (if any).
2082 static HMENU
MENU_GetSubPopup( HMENU hmenu
)
2087 menu
= MENU_GetMenu( hmenu
);
2089 if ((!menu
) || (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return 0;
2091 item
= &menu
->items
[menu
->FocusedItem
];
2092 if ((item
->fType
& MF_POPUP
) && (item
->fState
& MF_MOUSESELECT
))
2093 return item
->hSubMenu
;
2098 /***********************************************************************
2099 * MENU_HideSubPopups
2101 * Hide the sub-popup menus of this menu.
2103 static void MENU_HideSubPopups( HWND hwndOwner
, HMENU hmenu
,
2104 BOOL sendMenuSelect
)
2106 POPUPMENU
*menu
= MENU_GetMenu( hmenu
);
2108 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner
, hmenu
, sendMenuSelect
);
2110 if (menu
&& uSubPWndLevel
)
2116 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
2118 item
= &menu
->items
[menu
->FocusedItem
];
2119 if (!(item
->fType
& MF_POPUP
) ||
2120 !(item
->fState
& MF_MOUSESELECT
)) return;
2121 item
->fState
&= ~MF_MOUSESELECT
;
2122 hsubmenu
= item
->hSubMenu
;
2125 submenu
= MENU_GetMenu( hsubmenu
);
2126 MENU_HideSubPopups( hwndOwner
, hsubmenu
, FALSE
);
2127 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
, sendMenuSelect
, 0 );
2129 if (submenu
->hWnd
== MENU_GetTopPopupWnd()->hwndSelf
)
2131 ShowWindow( submenu
->hWnd
, SW_HIDE
);
2136 DestroyWindow( submenu
->hWnd
);
2139 MENU_ReleaseTopPopupWnd();
2144 /***********************************************************************
2147 * Display the sub-menu of the selected item of this menu.
2148 * Return the handle of the submenu, or hmenu if no submenu to display.
2150 static HMENU
MENU_ShowSubPopup( HWND hwndOwner
, HMENU hmenu
,
2151 BOOL selectFirst
, UINT wFlags
)
2159 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner
, hmenu
, selectFirst
);
2161 if (!(menu
= MENU_GetMenu( hmenu
))) return hmenu
;
2163 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
)) ||
2164 (menu
->FocusedItem
== NO_SELECTED_ITEM
))
2166 WIN_ReleaseWndPtr(wndPtr
);
2170 item
= &menu
->items
[menu
->FocusedItem
];
2171 if (!(item
->fType
& MF_POPUP
) ||
2172 (item
->fState
& (MF_GRAYED
| MF_DISABLED
)))
2174 WIN_ReleaseWndPtr(wndPtr
);
2178 /* message must be sent before using item,
2179 because nearly everything may be changed by the application ! */
2181 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2182 if (!(wFlags
& TPM_NONOTIFY
))
2183 SendMessageA( hwndOwner
, WM_INITMENUPOPUP
, item
->hSubMenu
,
2184 MAKELONG( menu
->FocusedItem
, IS_SYSTEM_MENU(menu
) ));
2186 item
= &menu
->items
[menu
->FocusedItem
];
2189 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2190 if (!(item
->fState
& MF_HILITE
))
2192 if (menu
->wFlags
& MF_POPUP
) hdc
= GetDC( menu
->hWnd
);
2193 else hdc
= GetDCEx( menu
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2195 SelectObject( hdc
, hMenuFont
);
2197 item
->fState
|= MF_HILITE
;
2198 MENU_DrawMenuItem( menu
->hWnd
, hmenu
, hwndOwner
, hdc
, item
, menu
->Height
, !(menu
->wFlags
& MF_POPUP
), ODA_DRAWENTIRE
);
2199 ReleaseDC( menu
->hWnd
, hdc
);
2201 if (!item
->rect
.top
&& !item
->rect
.left
&& !item
->rect
.bottom
&& !item
->rect
.right
)
2204 item
->fState
|= MF_MOUSESELECT
;
2206 if (IS_SYSTEM_MENU(menu
))
2208 MENU_InitSysMenuPopup(item
->hSubMenu
, wndPtr
->dwStyle
, GetClassLongA(wndPtr
->hwndSelf
, GCL_STYLE
));
2210 NC_GetSysPopupPos( wndPtr
, &rect
);
2211 rect
.top
= rect
.bottom
;
2212 rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2213 rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2217 if (menu
->wFlags
& MF_POPUP
)
2219 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2220 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.top
;
2221 rect
.right
= item
->rect
.left
- item
->rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2222 rect
.bottom
= item
->rect
.top
- item
->rect
.bottom
;
2226 rect
.left
= wndPtr
->rectWindow
.left
+ item
->rect
.left
;
2227 rect
.top
= wndPtr
->rectWindow
.top
+ item
->rect
.bottom
;
2228 rect
.right
= item
->rect
.right
- item
->rect
.left
;
2229 rect
.bottom
= item
->rect
.bottom
- item
->rect
.top
;
2233 MENU_ShowPopup( hwndOwner
, item
->hSubMenu
, menu
->FocusedItem
,
2234 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
2236 MENU_MoveSelection( hwndOwner
, item
->hSubMenu
, ITEM_NEXT
);
2237 WIN_ReleaseWndPtr(wndPtr
);
2238 return item
->hSubMenu
;
2243 /**********************************************************************
2246 BOOL
MENU_IsMenuActive(void)
2248 return pTopPopupWnd
&& (pTopPopupWnd
->dwStyle
& WS_VISIBLE
);
2251 /***********************************************************************
2254 * Walks menu chain trying to find a menu pt maps to.
2256 static HMENU
MENU_PtMenu( HMENU hMenu
, POINT pt
)
2258 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2259 register UINT ht
= menu
->FocusedItem
;
2261 /* try subpopup first (if any) */
2262 ht
= (ht
!= NO_SELECTED_ITEM
&&
2263 (menu
->items
[ht
].fType
& MF_POPUP
) &&
2264 (menu
->items
[ht
].fState
& MF_MOUSESELECT
))
2265 ? (UINT
) MENU_PtMenu(menu
->items
[ht
].hSubMenu
, pt
) : 0;
2267 if( !ht
) /* check the current window (avoiding WM_HITTEST) */
2269 ht
= (UINT
)NC_HandleNCHitTest( menu
->hWnd
, pt
);
2270 if( menu
->wFlags
& MF_POPUP
)
2271 ht
= (ht
!= (UINT
)HTNOWHERE
&&
2272 ht
!= (UINT
)HTERROR
) ? (UINT
)hMenu
: 0;
2275 WND
* wndPtr
= WIN_FindWndPtr(menu
->hWnd
);
2277 ht
= ( ht
== HTSYSMENU
) ? (UINT
)(wndPtr
->hSysMenu
)
2278 : ( ht
== HTMENU
) ? (UINT
)(wndPtr
->wIDmenu
) : 0;
2279 WIN_ReleaseWndPtr(wndPtr
);
2285 /***********************************************************************
2286 * MENU_ExecFocusedItem
2288 * Execute a menu item (for instance when user pressed Enter).
2289 * Return the wID of the executed item. Otherwise, -1 indicating
2290 * that no menu item was executed;
2291 * Have to receive the flags for the TrackPopupMenu options to avoid
2292 * sending unwanted message.
2295 static INT
MENU_ExecFocusedItem( MTRACKER
* pmt
, HMENU hMenu
, UINT wFlags
)
2298 POPUPMENU
*menu
= MENU_GetMenu( hMenu
);
2300 TRACE("%p hmenu=0x%04x\n", pmt
, hMenu
);
2302 if (!menu
|| !menu
->nItems
||
2303 (menu
->FocusedItem
== NO_SELECTED_ITEM
)) return -1;
2305 item
= &menu
->items
[menu
->FocusedItem
];
2307 TRACE("%08x %08x %08x\n",
2308 hMenu
, item
->wID
, item
->hSubMenu
);
2310 if (!(item
->fType
& MF_POPUP
))
2312 if (!(item
->fState
& (MF_GRAYED
| MF_DISABLED
)) && !(item
->fType
& MF_SEPARATOR
))
2314 /* If TPM_RETURNCMD is set you return the id, but
2315 do not send a message to the owner */
2316 if(!(wFlags
& TPM_RETURNCMD
))
2318 if( menu
->wFlags
& MF_SYSMENU
)
2319 PostMessageA( pmt
->hOwnerWnd
, WM_SYSCOMMAND
, item
->wID
,
2320 MAKELPARAM((INT16
)pmt
->pt
.x
, (INT16
)pmt
->pt
.y
) );
2322 PostMessageA( pmt
->hOwnerWnd
, WM_COMMAND
, item
->wID
, 0 );
2328 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hMenu
, TRUE
, wFlags
);
2333 /***********************************************************************
2334 * MENU_SwitchTracking
2336 * Helper function for menu navigation routines.
2338 static void MENU_SwitchTracking( MTRACKER
* pmt
, HMENU hPtMenu
, UINT id
)
2340 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2341 POPUPMENU
*topmenu
= MENU_GetMenu( pmt
->hTopMenu
);
2343 TRACE("%p hmenu=0x%04x 0x%04x\n", pmt
, hPtMenu
, id
);
2345 if( pmt
->hTopMenu
!= hPtMenu
&&
2346 !((ptmenu
->wFlags
| topmenu
->wFlags
) & MF_POPUP
) )
2348 /* both are top level menus (system and menu-bar) */
2349 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2350 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
2351 pmt
->hTopMenu
= hPtMenu
;
2353 else MENU_HideSubPopups( pmt
->hOwnerWnd
, hPtMenu
, FALSE
);
2354 MENU_SelectItem( pmt
->hOwnerWnd
, hPtMenu
, id
, TRUE
, 0 );
2358 /***********************************************************************
2361 * Return TRUE if we can go on with menu tracking.
2363 static BOOL
MENU_ButtonDown( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2365 TRACE("%p hmenu=0x%04x\n", pmt
, hPtMenu
);
2370 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2373 if( IS_SYSTEM_MENU(ptmenu
) )
2374 item
= ptmenu
->items
;
2376 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2380 if( ptmenu
->FocusedItem
!= id
)
2381 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2383 /* If the popup menu is not already "popped" */
2384 if(!(item
->fState
& MF_MOUSESELECT
))
2386 pmt
->hCurrentMenu
= MENU_ShowSubPopup( pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2388 /* In win31, a newly popped menu always remains opened for the next buttonup */
2389 if(TWEAK_WineLook
== WIN31_LOOK
)
2390 ptmenu
->bTimeToHide
= FALSE
;
2395 /* Else the click was on the menu bar, finish the tracking */
2400 /***********************************************************************
2403 * Return the value of MENU_ExecFocusedItem if
2404 * the selected item was not a popup. Else open the popup.
2405 * A -1 return value indicates that we go on with menu tracking.
2408 static INT
MENU_ButtonUp( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2410 TRACE("%p hmenu=0x%04x\n", pmt
, hPtMenu
);
2415 POPUPMENU
*ptmenu
= MENU_GetMenu( hPtMenu
);
2418 if( IS_SYSTEM_MENU(ptmenu
) )
2419 item
= ptmenu
->items
;
2421 item
= MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2423 if( item
&& (ptmenu
->FocusedItem
== id
))
2425 if( !(item
->fType
& MF_POPUP
) )
2426 return MENU_ExecFocusedItem( pmt
, hPtMenu
, wFlags
);
2428 /* If we are dealing with the top-level menu */
2429 /* and this is a click on an already "popped" item: */
2430 /* Stop the menu tracking and close the opened submenus */
2431 if((pmt
->hTopMenu
== hPtMenu
) && (ptmenu
->bTimeToHide
== TRUE
))
2434 ptmenu
->bTimeToHide
= TRUE
;
2440 /***********************************************************************
2443 * Return TRUE if we can go on with menu tracking.
2445 static BOOL
MENU_MouseMove( MTRACKER
* pmt
, HMENU hPtMenu
, UINT wFlags
)
2447 UINT id
= NO_SELECTED_ITEM
;
2448 POPUPMENU
*ptmenu
= NULL
;
2452 ptmenu
= MENU_GetMenu( hPtMenu
);
2453 if( IS_SYSTEM_MENU(ptmenu
) )
2456 MENU_FindItemByCoords( ptmenu
, pmt
->pt
, &id
);
2459 if( id
== NO_SELECTED_ITEM
)
2461 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2462 NO_SELECTED_ITEM
, TRUE
, pmt
->hTopMenu
);
2465 else if( ptmenu
->FocusedItem
!= id
)
2467 MENU_SwitchTracking( pmt
, hPtMenu
, id
);
2468 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hPtMenu
, FALSE
, wFlags
);
2474 /***********************************************************************
2477 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2479 static LRESULT
MENU_DoNextMenu( MTRACKER
* pmt
, UINT vk
)
2481 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2483 if( (vk
== VK_LEFT
&& menu
->FocusedItem
== 0 ) ||
2484 (vk
== VK_RIGHT
&& menu
->FocusedItem
== menu
->nItems
- 1))
2490 LRESULT l
= SendMessageA( pmt
->hOwnerWnd
, WM_NEXTMENU
, vk
,
2491 (IS_SYSTEM_MENU(menu
)) ? GetSubMenu16(pmt
->hTopMenu
,0) : pmt
->hTopMenu
);
2493 TRACE("%04x [%04x] -> %04x [%04x]\n",
2494 (UINT16
)pmt
->hCurrentMenu
, (UINT16
)pmt
->hOwnerWnd
, LOWORD(l
), HIWORD(l
) );
2498 wndPtr
= WIN_FindWndPtr(pmt
->hOwnerWnd
);
2500 hNewWnd
= pmt
->hOwnerWnd
;
2501 if( IS_SYSTEM_MENU(menu
) )
2503 /* switch to the menu bar */
2505 if( wndPtr
->dwStyle
& WS_CHILD
|| !wndPtr
->wIDmenu
)
2507 WIN_ReleaseWndPtr(wndPtr
);
2511 hNewMenu
= wndPtr
->wIDmenu
;
2514 menu
= MENU_GetMenu( hNewMenu
);
2515 id
= menu
->nItems
- 1;
2518 else if( wndPtr
->dwStyle
& WS_SYSMENU
)
2520 /* switch to the system menu */
2521 hNewMenu
= wndPtr
->hSysMenu
;
2525 WIN_ReleaseWndPtr(wndPtr
);
2528 WIN_ReleaseWndPtr(wndPtr
);
2530 else /* application returned a new menu to switch to */
2532 hNewMenu
= LOWORD(l
); hNewWnd
= HIWORD(l
);
2534 if( IsMenu(hNewMenu
) && IsWindow(hNewWnd
) )
2536 wndPtr
= WIN_FindWndPtr(hNewWnd
);
2538 if( wndPtr
->dwStyle
& WS_SYSMENU
&&
2539 GetSubMenu16(wndPtr
->hSysMenu
, 0) == hNewMenu
)
2541 /* get the real system menu */
2542 hNewMenu
= wndPtr
->hSysMenu
;
2544 else if( wndPtr
->dwStyle
& WS_CHILD
|| wndPtr
->wIDmenu
!= hNewMenu
)
2546 /* FIXME: Not sure what to do here;
2547 * perhaps try to track hNewMenu as a popup? */
2549 TRACE(" -- got confused.\n");
2550 WIN_ReleaseWndPtr(wndPtr
);
2553 WIN_ReleaseWndPtr(wndPtr
);
2558 if( hNewMenu
!= pmt
->hTopMenu
)
2560 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, NO_SELECTED_ITEM
,
2562 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2563 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2566 if( hNewWnd
!= pmt
->hOwnerWnd
)
2569 pmt
->hOwnerWnd
= hNewWnd
;
2570 EVENT_Capture( pmt
->hOwnerWnd
, HTMENU
);
2573 pmt
->hTopMenu
= pmt
->hCurrentMenu
= hNewMenu
; /* all subpopups are hidden */
2574 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hTopMenu
, id
, TRUE
, 0 );
2581 /***********************************************************************
2584 * The idea is not to show the popup if the next input message is
2585 * going to hide it anyway.
2587 static BOOL
MENU_SuspendPopup( MTRACKER
* pmt
, UINT16 uMsg
)
2591 msg
.hwnd
= pmt
->hOwnerWnd
;
2593 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2594 pmt
->trackFlags
|= TF_SKIPREMOVE
;
2599 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2600 if( msg
.message
== WM_KEYUP
|| msg
.message
== WM_PAINT
)
2602 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
2603 PeekMessageA( &msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
2604 if( msg
.message
== WM_KEYDOWN
&&
2605 (msg
.wParam
== VK_LEFT
|| msg
.wParam
== VK_RIGHT
))
2607 pmt
->trackFlags
|= TF_SUSPENDPOPUP
;
2614 /* failures go through this */
2615 pmt
->trackFlags
&= ~TF_SUSPENDPOPUP
;
2619 /***********************************************************************
2622 * Handle a VK_LEFT key event in a menu.
2624 static void MENU_KeyLeft( MTRACKER
* pmt
, UINT wFlags
)
2627 HMENU hmenutmp
, hmenuprev
;
2630 hmenuprev
= hmenutmp
= pmt
->hTopMenu
;
2631 menu
= MENU_GetMenu( hmenutmp
);
2633 /* Try to move 1 column left (if possible) */
2634 if( (prevcol
= MENU_GetStartOfPrevColumn( pmt
->hCurrentMenu
)) !=
2635 NO_SELECTED_ITEM
) {
2637 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2642 /* close topmost popup */
2643 while (hmenutmp
!= pmt
->hCurrentMenu
)
2645 hmenuprev
= hmenutmp
;
2646 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
2649 MENU_HideSubPopups( pmt
->hOwnerWnd
, hmenuprev
, TRUE
);
2650 pmt
->hCurrentMenu
= hmenuprev
;
2652 if ( (hmenuprev
== pmt
->hTopMenu
) && !(menu
->wFlags
& MF_POPUP
) )
2654 /* move menu bar selection if no more popups are left */
2656 if( !MENU_DoNextMenu( pmt
, VK_LEFT
) )
2657 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_PREV
);
2659 if ( hmenuprev
!= hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2661 /* A sublevel menu was displayed - display the next one
2662 * unless there is another displacement coming up */
2664 if( !MENU_SuspendPopup( pmt
, WM_KEYDOWN
) )
2665 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2666 pmt
->hTopMenu
, TRUE
, wFlags
);
2672 /***********************************************************************
2675 * Handle a VK_RIGHT key event in a menu.
2677 static void MENU_KeyRight( MTRACKER
* pmt
, UINT wFlags
)
2680 POPUPMENU
*menu
= MENU_GetMenu( pmt
->hTopMenu
);
2683 TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2685 debugstr_w((MENU_GetMenu(pmt
->hCurrentMenu
))->
2687 pmt
->hTopMenu
, debugstr_w(menu
->items
[0].text
) );
2689 if ( (menu
->wFlags
& MF_POPUP
) || (pmt
->hCurrentMenu
!= pmt
->hTopMenu
))
2691 /* If already displaying a popup, try to display sub-popup */
2693 hmenutmp
= pmt
->hCurrentMenu
;
2694 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
, hmenutmp
, TRUE
, wFlags
);
2696 /* if subpopup was displayed then we are done */
2697 if (hmenutmp
!= pmt
->hCurrentMenu
) return;
2700 /* Check to see if there's another column */
2701 if( (nextcol
= MENU_GetStartOfNextColumn( pmt
->hCurrentMenu
)) !=
2702 NO_SELECTED_ITEM
) {
2703 TRACE("Going to %d.\n", nextcol
);
2704 MENU_SelectItem( pmt
->hOwnerWnd
, pmt
->hCurrentMenu
,
2709 if (!(menu
->wFlags
& MF_POPUP
)) /* menu bar tracking */
2711 if( pmt
->hCurrentMenu
!= pmt
->hTopMenu
)
2713 MENU_HideSubPopups( pmt
->hOwnerWnd
, pmt
->hTopMenu
, FALSE
);
2714 hmenutmp
= pmt
->hCurrentMenu
= pmt
->hTopMenu
;
2715 } else hmenutmp
= 0;
2717 /* try to move to the next item */
2718 if( !MENU_DoNextMenu( pmt
, VK_RIGHT
) )
2719 MENU_MoveSelection( pmt
->hOwnerWnd
, pmt
->hTopMenu
, ITEM_NEXT
);
2721 if( hmenutmp
|| pmt
->trackFlags
& TF_SUSPENDPOPUP
)
2722 if( !MENU_SuspendPopup(pmt
, WM_KEYDOWN
) )
2723 pmt
->hCurrentMenu
= MENU_ShowSubPopup(pmt
->hOwnerWnd
,
2724 pmt
->hTopMenu
, TRUE
, wFlags
);
2728 /***********************************************************************
2731 * Menu tracking code.
2733 static INT
MENU_TrackMenu( HMENU hmenu
, UINT wFlags
, INT x
, INT y
,
2734 HWND hwnd
, const RECT
*lprect
)
2739 INT executedMenuId
= -1;
2741 BOOL enterIdleSent
= FALSE
;
2744 mt
.hCurrentMenu
= hmenu
;
2745 mt
.hTopMenu
= hmenu
;
2746 mt
.hOwnerWnd
= hwnd
;
2750 TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2751 hmenu
, wFlags
, x
, y
, hwnd
, (lprect
) ? lprect
->left
: 0, (lprect
) ? lprect
->top
: 0,
2752 (lprect
) ? lprect
->right
: 0, (lprect
) ? lprect
->bottom
: 0);
2755 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
2757 if (wFlags
& TPM_BUTTONDOWN
)
2759 /* Get the result in order to start the tracking or not */
2760 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
2761 fEndMenu
= !fRemove
;
2764 EVENT_Capture( mt
.hOwnerWnd
, HTMENU
);
2768 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
2769 if (!menu
) /* sometimes happens if I do a window manager close */
2771 msg
.hwnd
= (wFlags
& TPM_ENTERIDLEEX
&& menu
->wFlags
& MF_POPUP
) ? menu
->hWnd
: 0;
2773 /* we have to keep the message in the queue until it's
2774 * clear that menu loop is not over yet. */
2776 if (!MSG_InternalGetMessage( QMSG_WIN32A
, &msg
, msg
.hwnd
, mt
.hOwnerWnd
,
2777 MSGF_MENU
, PM_NOREMOVE
, !enterIdleSent
, &enterIdleSent
)) break;
2779 /* check if EndMenu() tried to cancel us, by posting this message */
2780 if(msg
.message
== WM_CANCELMODE
)
2782 /* we are now out of the loop */
2785 /* remove the message from the queue */
2786 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2788 /* break out of internal loop, ala ESCAPE */
2792 TranslateMessage( &msg
);
2795 if ( (msg
.hwnd
==menu
->hWnd
) || (msg
.message
!=WM_TIMER
) )
2796 enterIdleSent
=FALSE
;
2799 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
2802 * use the mouse coordinates in lParam instead of those in the MSG
2803 * struct to properly handle synthetic messages. lParam coords are
2804 * relative to client area, so they must be converted; since they can
2805 * be negative, we must use SLOWORD/SHIWORD instead of LOWORD/HIWORD.
2807 mt
.pt
.x
= SLOWORD(msg
.lParam
);
2808 mt
.pt
.y
= SHIWORD(msg
.lParam
);
2809 ClientToScreen(msg
.hwnd
,&mt
.pt
);
2811 /* Find a menu for this mouse event */
2812 hmenu
= MENU_PtMenu( mt
.hTopMenu
, mt
.pt
);
2816 /* no WM_NC... messages in captured state */
2818 case WM_RBUTTONDBLCLK
:
2819 case WM_RBUTTONDOWN
:
2820 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2822 case WM_LBUTTONDBLCLK
:
2823 case WM_LBUTTONDOWN
:
2824 /* If the message belongs to the menu, removes it from the queue */
2825 /* Else, end menu tracking */
2826 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
2827 fEndMenu
= !fRemove
;
2831 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2834 /* Check if a menu was selected by the mouse */
2837 executedMenuId
= MENU_ButtonUp( &mt
, hmenu
, wFlags
);
2839 /* End the loop if executedMenuId is an item ID */
2840 /* or if the job was done (executedMenuId = 0). */
2841 fEndMenu
= fRemove
= (executedMenuId
!= -1);
2843 /* No menu was selected by the mouse */
2844 /* if the function was called by TrackPopupMenu, continue
2845 with the menu tracking. If not, stop it */
2847 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
2852 /* In win95 winelook, the selected menu item must be changed every time the
2853 mouse moves. In Win31 winelook, the mouse button has to be held down */
2855 if ( (TWEAK_WineLook
> WIN31_LOOK
) ||
2856 ( (msg
.wParam
& MK_LBUTTON
) ||
2857 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
.wParam
& MK_RBUTTON
))) )
2859 fEndMenu
|= !MENU_MouseMove( &mt
, hmenu
, wFlags
);
2861 } /* switch(msg.message) - mouse */
2863 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
2865 fRemove
= TRUE
; /* Keyboard messages are always removed */
2873 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2874 NO_SELECTED_ITEM
, FALSE
, 0 );
2877 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2878 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
2881 case VK_DOWN
: /* If on menu bar, pull-down the menu */
2883 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
2884 if (!(menu
->wFlags
& MF_POPUP
))
2885 mt
.hCurrentMenu
= MENU_ShowSubPopup(mt
.hOwnerWnd
, mt
.hTopMenu
, TRUE
, wFlags
);
2886 else /* otherwise try to move selection */
2887 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
, ITEM_NEXT
);
2891 MENU_KeyLeft( &mt
, wFlags
);
2895 MENU_KeyRight( &mt
, wFlags
);
2905 hi
.cbSize
= sizeof(HELPINFO
);
2906 hi
.iContextType
= HELPINFO_MENUITEM
;
2907 if (menu
->FocusedItem
== NO_SELECTED_ITEM
)
2910 hi
.iCtrlId
= menu
->items
[menu
->FocusedItem
].wID
;
2911 hi
.hItemHandle
= hmenu
;
2912 hi
.dwContextId
= menu
->dwContextHelpID
;
2913 hi
.MousePos
= msg
.pt
;
2914 SendMessageA(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
2921 break; /* WM_KEYDOWN */
2931 break; /* WM_SYSKEYDOWN */
2937 if (msg
.wParam
== '\r' || msg
.wParam
== ' ')
2939 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2940 fEndMenu
= (executedMenuId
!= -1);
2945 /* Hack to avoid control chars. */
2946 /* We will find a better way real soon... */
2947 if ((msg
.wParam
<= 32) || (msg
.wParam
>= 127)) break;
2949 pos
= MENU_FindItemByKey( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2950 LOWORD(msg
.wParam
), FALSE
);
2951 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
2952 else if (pos
== (UINT
)-1) MessageBeep(0);
2955 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
, pos
,
2957 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2958 fEndMenu
= (executedMenuId
!= -1);
2962 } /* switch(msg.message) - kbd */
2966 DispatchMessageA( &msg
);
2969 if (!fEndMenu
) fRemove
= TRUE
;
2971 /* finally remove message from the queue */
2973 if (fRemove
&& !(mt
.trackFlags
& TF_SKIPREMOVE
) )
2974 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2975 else mt
.trackFlags
&= ~TF_SKIPREMOVE
;
2980 /* If dropdown is still painted and the close box is clicked on
2981 then the menu will be destroyed as part of the DispatchMessage above.
2982 This will then invalidate the menu handle in mt.hTopMenu. We should
2983 check for this first. */
2984 if( IsMenu( mt
.hTopMenu
) )
2986 menu
= MENU_GetMenu( mt
.hTopMenu
);
2988 if( IsWindow( mt
.hOwnerWnd
) )
2990 MENU_HideSubPopups( mt
.hOwnerWnd
, mt
.hTopMenu
, FALSE
);
2992 if (menu
&& menu
->wFlags
& MF_POPUP
)
2994 ShowWindow( menu
->hWnd
, SW_HIDE
);
2997 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
2998 SendMessageA( mt
.hOwnerWnd
, WM_MENUSELECT
, MAKELONG(0,0xffff), 0 );
3001 /* Reset the variable for hiding menu */
3002 if( menu
) menu
->bTimeToHide
= FALSE
;
3005 /* The return value is only used by TrackPopupMenu */
3006 return ((executedMenuId
!= -1) ? executedMenuId
: 0);
3009 /***********************************************************************
3012 static BOOL
MENU_InitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
3014 TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd
, hMenu
);
3018 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
3019 if (!(wFlags
& TPM_NONOTIFY
))
3020 SendMessageA( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
3022 SendMessageA( hWnd
, WM_SETCURSOR
, hWnd
, HTCAPTION
);
3024 if (!(wFlags
& TPM_NONOTIFY
))
3025 SendMessageA( hWnd
, WM_INITMENU
, hMenu
, 0 );
3029 /***********************************************************************
3032 static BOOL
MENU_ExitTracking(HWND hWnd
)
3034 TRACE("hwnd=0x%04x\n", hWnd
);
3036 SendMessageA( hWnd
, WM_EXITMENULOOP
, 0, 0 );
3041 /***********************************************************************
3042 * MENU_TrackMouseMenuBar
3044 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
3046 void MENU_TrackMouseMenuBar( WND
* wndPtr
, INT ht
, POINT pt
)
3048 HWND hWnd
= wndPtr
->hwndSelf
;
3049 HMENU hMenu
= (ht
== HTSYSMENU
) ? wndPtr
->hSysMenu
: wndPtr
->wIDmenu
;
3050 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3052 TRACE("pwnd=%p ht=0x%04x (%ld,%ld)\n", wndPtr
, ht
, pt
.x
, pt
.y
);
3056 MENU_InitTracking( hWnd
, hMenu
, FALSE
, wFlags
);
3057 MENU_TrackMenu( hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
3058 MENU_ExitTracking(hWnd
);
3063 /***********************************************************************
3064 * MENU_TrackKbdMenuBar
3066 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3068 void MENU_TrackKbdMenuBar( WND
* wndPtr
, UINT wParam
, INT vkey
)
3070 UINT uItem
= NO_SELECTED_ITEM
;
3072 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3074 /* find window that has a menu */
3076 while( wndPtr
->dwStyle
& WS_CHILD
)
3077 if( !(wndPtr
= wndPtr
->parent
) ) return;
3079 /* check if we have to track a system menu */
3081 if( (wndPtr
->dwStyle
& (WS_CHILD
| WS_MINIMIZE
)) ||
3082 !wndPtr
->wIDmenu
|| vkey
== VK_SPACE
)
3084 if( !(wndPtr
->dwStyle
& WS_SYSMENU
) ) return;
3085 hTrackMenu
= wndPtr
->hSysMenu
;
3087 wParam
|= HTSYSMENU
; /* prevent item lookup */
3090 hTrackMenu
= wndPtr
->wIDmenu
;
3092 if (IsMenu( hTrackMenu
))
3094 MENU_InitTracking( wndPtr
->hwndSelf
, hTrackMenu
, FALSE
, wFlags
);
3096 if( vkey
&& vkey
!= VK_SPACE
)
3098 uItem
= MENU_FindItemByKey( wndPtr
->hwndSelf
, hTrackMenu
,
3099 vkey
, (wParam
& HTSYSMENU
) );
3100 if( uItem
>= (UINT
)(-2) )
3102 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3109 MENU_SelectItem( wndPtr
->hwndSelf
, hTrackMenu
, uItem
, TRUE
, 0 );
3111 if( uItem
== NO_SELECTED_ITEM
)
3112 MENU_MoveSelection( wndPtr
->hwndSelf
, hTrackMenu
, ITEM_NEXT
);
3114 PostMessageA( wndPtr
->hwndSelf
, WM_KEYDOWN
, VK_DOWN
, 0L );
3116 MENU_TrackMenu( hTrackMenu
, wFlags
, 0, 0, wndPtr
->hwndSelf
, NULL
);
3119 MENU_ExitTracking (wndPtr
->hwndSelf
);
3124 /**********************************************************************
3125 * TrackPopupMenu16 (USER.416)
3127 BOOL16 WINAPI
TrackPopupMenu16( HMENU16 hMenu
, UINT16 wFlags
, INT16 x
, INT16 y
,
3128 INT16 nReserved
, HWND16 hWnd
, const RECT16
*lpRect
)
3132 CONV_RECT16TO32( lpRect
, &r
);
3133 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, nReserved
, hWnd
,
3134 lpRect
? &r
: NULL
);
3138 /**********************************************************************
3139 * TrackPopupMenu (USER32.@)
3141 * Like the win32 API, the function return the command ID only if the
3142 * flag TPM_RETURNCMD is on.
3145 BOOL WINAPI
TrackPopupMenu( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3146 INT nReserved
, HWND hWnd
, const RECT
*lpRect
)
3150 MENU_InitTracking(hWnd
, hMenu
, TRUE
, wFlags
);
3152 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3153 if (!(wFlags
& TPM_NONOTIFY
))
3154 SendMessageA( hWnd
, WM_INITMENUPOPUP
, hMenu
, 0);
3156 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
, 0, 0 ))
3157 ret
= MENU_TrackMenu( hMenu
, wFlags
| TPM_POPUPMENU
, 0, 0, hWnd
, lpRect
);
3158 MENU_ExitTracking(hWnd
);
3160 if( (!(wFlags
& TPM_RETURNCMD
)) && (ret
!= FALSE
) )
3166 /**********************************************************************
3167 * TrackPopupMenuEx (USER32.@)
3169 BOOL WINAPI
TrackPopupMenuEx( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3170 HWND hWnd
, LPTPMPARAMS lpTpm
)
3172 FIXME("not fully implemented\n" );
3173 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, 0, hWnd
,
3174 lpTpm
? &lpTpm
->rcExclude
: NULL
);
3177 /***********************************************************************
3180 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3182 static LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
3184 TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
3185 hwnd
, message
, wParam
, lParam
);
3191 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*)lParam
;
3192 SetWindowLongW( hwnd
, 0, (LONG
)cs
->lpCreateParams
);
3196 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
3197 return MA_NOACTIVATE
;
3202 BeginPaint( hwnd
, &ps
);
3203 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
3204 (HMENU
)GetWindowLongA( hwnd
, 0 ) );
3205 EndPaint( hwnd
, &ps
);
3213 /* zero out global pointer in case resident popup window
3214 * was somehow destroyed. */
3216 if(MENU_GetTopPopupWnd() )
3218 if( hwnd
== pTopPopupWnd
->hwndSelf
)
3220 ERR("resident popup destroyed!\n");
3222 MENU_DestroyTopPopupWnd();
3227 MENU_ReleaseTopPopupWnd();
3235 if (!GetWindowLongW( hwnd
, 0 )) ERR("no menu to display\n");
3238 SetWindowLongW( hwnd
, 0, 0 );
3241 case MM_SETMENUHANDLE
:
3242 SetWindowLongW( hwnd
, 0, wParam
);
3245 case MM_GETMENUHANDLE
:
3246 return GetWindowLongW( hwnd
, 0 );
3249 return DefWindowProcW( hwnd
, message
, wParam
, lParam
);
3255 /***********************************************************************
3256 * MENU_GetMenuBarHeight
3258 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3260 UINT
MENU_GetMenuBarHeight( HWND hwnd
, UINT menubarWidth
,
3261 INT orgX
, INT orgY
)
3269 TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3270 hwnd
, menubarWidth
, orgX
, orgY
);
3272 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
3275 if (!(lppop
= MENU_GetMenu((HMENU16
)wndPtr
->wIDmenu
)))
3277 WIN_ReleaseWndPtr(wndPtr
);
3281 hdc
= GetDCEx( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3282 SelectObject( hdc
, hMenuFont
);
3283 SetRect(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+GetSystemMetrics(SM_CYMENU
));
3284 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
3285 ReleaseDC( hwnd
, hdc
);
3286 retvalue
= lppop
->Height
;
3287 WIN_ReleaseWndPtr(wndPtr
);
3292 /*******************************************************************
3293 * ChangeMenu16 (USER.153)
3295 BOOL16 WINAPI
ChangeMenu16( HMENU16 hMenu
, UINT16 pos
, SEGPTR data
,
3296 UINT16 id
, UINT16 flags
)
3298 TRACE("menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
3299 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3300 if (flags
& MF_APPEND
) return AppendMenu16( hMenu
, flags
& ~MF_APPEND
,
3303 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
3304 /* for MF_DELETE. We should check the parameters for all others */
3305 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
3307 if (flags
& MF_DELETE
) return DeleteMenu16(hMenu
, pos
, flags
& ~MF_DELETE
);
3308 if (flags
& MF_CHANGE
) return ModifyMenu16(hMenu
, pos
, flags
& ~MF_CHANGE
,
3310 if (flags
& MF_REMOVE
) return RemoveMenu16(hMenu
,
3311 flags
& MF_BYPOSITION
? pos
: id
,
3312 flags
& ~MF_REMOVE
);
3313 /* Default: MF_INSERT */
3314 return InsertMenu16( hMenu
, pos
, flags
, id
, data
);
3318 /*******************************************************************
3319 * ChangeMenuA (USER32.@)
3321 BOOL WINAPI
ChangeMenuA( HMENU hMenu
, UINT pos
, LPCSTR data
,
3322 UINT id
, UINT flags
)
3324 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3325 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3326 if (flags
& MF_APPEND
) return AppendMenuA( hMenu
, flags
& ~MF_APPEND
,
3328 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3329 if (flags
& MF_CHANGE
) return ModifyMenuA(hMenu
, pos
, flags
& ~MF_CHANGE
,
3331 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3332 flags
& MF_BYPOSITION
? pos
: id
,
3333 flags
& ~MF_REMOVE
);
3334 /* Default: MF_INSERT */
3335 return InsertMenuA( hMenu
, pos
, flags
, id
, data
);
3339 /*******************************************************************
3340 * ChangeMenuW (USER32.@)
3342 BOOL WINAPI
ChangeMenuW( HMENU hMenu
, UINT pos
, LPCWSTR data
,
3343 UINT id
, UINT flags
)
3345 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3346 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3347 if (flags
& MF_APPEND
) return AppendMenuW( hMenu
, flags
& ~MF_APPEND
,
3349 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3350 if (flags
& MF_CHANGE
) return ModifyMenuW(hMenu
, pos
, flags
& ~MF_CHANGE
,
3352 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3353 flags
& MF_BYPOSITION
? pos
: id
,
3354 flags
& ~MF_REMOVE
);
3355 /* Default: MF_INSERT */
3356 return InsertMenuW( hMenu
, pos
, flags
, id
, data
);
3360 /*******************************************************************
3361 * CheckMenuItem16 (USER.154)
3363 BOOL16 WINAPI
CheckMenuItem16( HMENU16 hMenu
, UINT16 id
, UINT16 flags
)
3365 return (BOOL16
)CheckMenuItem( hMenu
, id
, flags
);
3369 /*******************************************************************
3370 * CheckMenuItem (USER32.@)
3372 DWORD WINAPI
CheckMenuItem( HMENU hMenu
, UINT id
, UINT flags
)
3377 TRACE("menu=%04x id=%04x flags=%04x\n", hMenu
, id
, flags
);
3378 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
3379 ret
= item
->fState
& MF_CHECKED
;
3380 if (flags
& MF_CHECKED
) item
->fState
|= MF_CHECKED
;
3381 else item
->fState
&= ~MF_CHECKED
;
3386 /**********************************************************************
3387 * EnableMenuItem16 (USER.155)
3389 UINT16 WINAPI
EnableMenuItem16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3391 return EnableMenuItem( hMenu
, wItemID
, wFlags
);
3395 /**********************************************************************
3396 * EnableMenuItem (USER32.@)
3398 UINT WINAPI
EnableMenuItem( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3404 TRACE("(%04x, %04X, %04X) !\n",
3405 hMenu
, wItemID
, wFlags
);
3407 /* Get the Popupmenu to access the owner menu */
3408 if (!(menu
= MENU_GetMenu(hMenu
)))
3411 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
)))
3414 oldflags
= item
->fState
& (MF_GRAYED
| MF_DISABLED
);
3415 item
->fState
^= (oldflags
^ wFlags
) & (MF_GRAYED
| MF_DISABLED
);
3417 /* In win95 if the close item in the system menu change update the close button */
3418 if (TWEAK_WineLook
== WIN95_LOOK
)
3419 if((item
->wID
== SC_CLOSE
) && (oldflags
!= wFlags
))
3421 if (menu
->hSysMenuOwner
!= 0)
3423 POPUPMENU
* parentMenu
;
3425 /* Get the parent menu to access*/
3426 if (!(parentMenu
= MENU_GetMenu(menu
->hSysMenuOwner
)))
3429 /* Refresh the frame to reflect the change*/
3430 SetWindowPos(parentMenu
->hWnd
, 0, 0, 0, 0, 0,
3431 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
3439 /*******************************************************************
3440 * GetMenuString16 (USER.161)
3442 INT16 WINAPI
GetMenuString16( HMENU16 hMenu
, UINT16 wItemID
,
3443 LPSTR str
, INT16 nMaxSiz
, UINT16 wFlags
)
3445 return GetMenuStringA( hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3449 /*******************************************************************
3450 * GetMenuStringA (USER32.@)
3452 INT WINAPI
GetMenuStringA(
3453 HMENU hMenu
, /* [in] menuhandle */
3454 UINT wItemID
, /* [in] menu item (dep. on wFlags) */
3455 LPSTR str
, /* [out] outbuffer. If NULL, func returns entry length*/
3456 INT nMaxSiz
, /* [in] length of buffer. if 0, func returns entry len*/
3457 UINT wFlags
/* [in] MF_ flags */
3461 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3462 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3463 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3464 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3465 if (!str
|| !nMaxSiz
) return strlenW(item
->text
);
3467 if (!WideCharToMultiByte( CP_ACP
, 0, item
->text
, -1, str
, nMaxSiz
, NULL
, NULL
))
3469 TRACE("returning '%s'\n", str
);
3474 /*******************************************************************
3475 * GetMenuStringW (USER32.@)
3477 INT WINAPI
GetMenuStringW( HMENU hMenu
, UINT wItemID
,
3478 LPWSTR str
, INT nMaxSiz
, UINT wFlags
)
3482 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3483 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3484 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3485 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3486 if (!str
|| !nMaxSiz
) return strlenW(item
->text
);
3488 lstrcpynW( str
, item
->text
, nMaxSiz
);
3489 return strlenW(str
);
3493 /**********************************************************************
3494 * HiliteMenuItem16 (USER.162)
3496 BOOL16 WINAPI
HiliteMenuItem16( HWND16 hWnd
, HMENU16 hMenu
, UINT16 wItemID
,
3499 return HiliteMenuItem( hWnd
, hMenu
, wItemID
, wHilite
);
3503 /**********************************************************************
3504 * HiliteMenuItem (USER32.@)
3506 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
3510 TRACE("(%04x, %04x, %04x, %04x);\n",
3511 hWnd
, hMenu
, wItemID
, wHilite
);
3512 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
3513 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3514 if (menu
->FocusedItem
== wItemID
) return TRUE
;
3515 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
3516 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
, 0 );
3521 /**********************************************************************
3522 * GetMenuState16 (USER.250)
3524 UINT16 WINAPI
GetMenuState16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3526 return GetMenuState( hMenu
, wItemID
, wFlags
);
3530 /**********************************************************************
3531 * GetMenuState (USER32.@)
3533 UINT WINAPI
GetMenuState( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3536 TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
3537 hMenu
, wItemID
, wFlags
);
3538 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
3539 debug_print_menuitem (" item: ", item
, "");
3540 if (item
->fType
& MF_POPUP
)
3542 POPUPMENU
*menu
= MENU_GetMenu( item
->hSubMenu
);
3543 if (!menu
) return -1;
3544 else return (menu
->nItems
<< 8) | ((item
->fState
|item
->fType
) & 0xff);
3548 /* We used to (from way back then) mask the result to 0xff. */
3549 /* I don't know why and it seems wrong as the documented */
3550 /* return flag MF_SEPARATOR is outside that mask. */
3551 return (item
->fType
| item
->fState
);
3556 /**********************************************************************
3557 * GetMenuItemCount16 (USER.263)
3559 INT16 WINAPI
GetMenuItemCount16( HMENU16 hMenu
)
3561 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3562 if (!menu
) return -1;
3563 TRACE("(%04x) returning %d\n",
3564 hMenu
, menu
->nItems
);
3565 return menu
->nItems
;
3569 /**********************************************************************
3570 * GetMenuItemCount (USER32.@)
3572 INT WINAPI
GetMenuItemCount( HMENU hMenu
)
3574 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3575 if (!menu
) return -1;
3576 TRACE("(%04x) returning %d\n",
3577 hMenu
, menu
->nItems
);
3578 return menu
->nItems
;
3581 /**********************************************************************
3582 * GetMenuItemID16 (USER.264)
3584 UINT16 WINAPI
GetMenuItemID16( HMENU16 hMenu
, INT16 nPos
)
3586 return (UINT16
) GetMenuItemID (hMenu
, nPos
);
3589 /**********************************************************************
3590 * GetMenuItemID (USER32.@)
3592 UINT WINAPI
GetMenuItemID( HMENU hMenu
, INT nPos
)
3596 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return 0;
3597 if (lpmi
->fType
& MF_POPUP
) return -1;
3602 /*******************************************************************
3603 * InsertMenu16 (USER.410)
3605 BOOL16 WINAPI
InsertMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3606 UINT16 id
, SEGPTR data
)
3608 UINT pos32
= (UINT
)pos
;
3609 if ((pos
== (UINT16
)-1) && (flags
& MF_BYPOSITION
)) pos32
= (UINT
)-1;
3610 if (IS_STRING_ITEM(flags
) && data
)
3611 return InsertMenuA( hMenu
, pos32
, flags
, id
, MapSL(data
) );
3612 return InsertMenuA( hMenu
, pos32
, flags
, id
, (LPSTR
)data
);
3616 /*******************************************************************
3617 * InsertMenuW (USER32.@)
3619 BOOL WINAPI
InsertMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3620 UINT id
, LPCWSTR str
)
3624 if (IS_STRING_ITEM(flags
) && str
)
3625 TRACE("hMenu %04x, pos %d, flags %08x, "
3626 "id %04x, str '%s'\n",
3627 hMenu
, pos
, flags
, id
, debugstr_w(str
) );
3628 else TRACE("hMenu %04x, pos %d, flags %08x, "
3629 "id %04x, str %08lx (not a string)\n",
3630 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3632 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
3634 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
3636 RemoveMenu( hMenu
, pos
, flags
);
3640 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
3641 (MENU_GetMenu((HMENU16
)id
))->wFlags
|= MF_POPUP
;
3643 item
->hCheckBit
= item
->hUnCheckBit
= 0;
3648 /*******************************************************************
3649 * InsertMenuA (USER32.@)
3651 BOOL WINAPI
InsertMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3652 UINT id
, LPCSTR str
)
3656 if (IS_STRING_ITEM(flags
) && str
)
3658 LPWSTR newstr
= HEAP_strdupAtoW( GetProcessHeap(), 0, str
);
3659 ret
= InsertMenuW( hMenu
, pos
, flags
, id
, newstr
);
3660 HeapFree( GetProcessHeap(), 0, newstr
);
3663 else return InsertMenuW( hMenu
, pos
, flags
, id
, (LPCWSTR
)str
);
3667 /*******************************************************************
3668 * AppendMenu16 (USER.411)
3670 BOOL16 WINAPI
AppendMenu16(HMENU16 hMenu
, UINT16 flags
, UINT16 id
, SEGPTR data
)
3672 return InsertMenu16( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3676 /*******************************************************************
3677 * AppendMenuA (USER32.@)
3679 BOOL WINAPI
AppendMenuA( HMENU hMenu
, UINT flags
,
3680 UINT id
, LPCSTR data
)
3682 return InsertMenuA( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3686 /*******************************************************************
3687 * AppendMenuW (USER32.@)
3689 BOOL WINAPI
AppendMenuW( HMENU hMenu
, UINT flags
,
3690 UINT id
, LPCWSTR data
)
3692 return InsertMenuW( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3696 /**********************************************************************
3697 * RemoveMenu16 (USER.412)
3699 BOOL16 WINAPI
RemoveMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3701 return RemoveMenu( hMenu
, nPos
, wFlags
);
3705 /**********************************************************************
3706 * RemoveMenu (USER32.@)
3708 BOOL WINAPI
RemoveMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3713 TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu
, nPos
, wFlags
);
3714 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3715 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3719 MENU_FreeItemData( item
);
3721 if (--menu
->nItems
== 0)
3723 HeapFree( SystemHeap
, 0, menu
->items
);
3728 while(nPos
< menu
->nItems
)
3734 menu
->items
= HeapReAlloc( SystemHeap
, 0, menu
->items
,
3735 menu
->nItems
* sizeof(MENUITEM
) );
3741 /**********************************************************************
3742 * DeleteMenu16 (USER.413)
3744 BOOL16 WINAPI
DeleteMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3746 return DeleteMenu( hMenu
, nPos
, wFlags
);
3750 /**********************************************************************
3751 * DeleteMenu (USER32.@)
3753 BOOL WINAPI
DeleteMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3755 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
3756 if (!item
) return FALSE
;
3757 if (item
->fType
& MF_POPUP
) DestroyMenu( item
->hSubMenu
);
3758 /* nPos is now the position of the item */
3759 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
3764 /*******************************************************************
3765 * ModifyMenu16 (USER.414)
3767 BOOL16 WINAPI
ModifyMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3768 UINT16 id
, SEGPTR data
)
3770 if (IS_STRING_ITEM(flags
))
3771 return ModifyMenuA( hMenu
, pos
, flags
, id
, MapSL(data
) );
3772 return ModifyMenuA( hMenu
, pos
, flags
, id
, (LPSTR
)data
);
3776 /*******************************************************************
3777 * ModifyMenuW (USER32.@)
3779 BOOL WINAPI
ModifyMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3780 UINT id
, LPCWSTR str
)
3784 if (IS_STRING_ITEM(flags
))
3786 TRACE("%04x %d %04x %04x '%s'\n",
3787 hMenu
, pos
, flags
, id
, str
? debugstr_w(str
) : "#NULL#" );
3788 if (!str
) return FALSE
;
3792 TRACE("%04x %d %04x %04x %08lx\n",
3793 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3796 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
3797 return MENU_SetItemData( item
, flags
, id
, str
);
3801 /*******************************************************************
3802 * ModifyMenuA (USER32.@)
3804 BOOL WINAPI
ModifyMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3805 UINT id
, LPCSTR str
)
3809 if (IS_STRING_ITEM(flags
) && str
)
3811 LPWSTR newstr
= HEAP_strdupAtoW( GetProcessHeap(), 0, str
);
3812 ret
= ModifyMenuW( hMenu
, pos
, flags
, id
, newstr
);
3813 HeapFree( GetProcessHeap(), 0, newstr
);
3816 else return ModifyMenuW( hMenu
, pos
, flags
, id
, (LPCWSTR
)str
);
3820 /**********************************************************************
3821 * CreatePopupMenu16 (USER.415)
3823 HMENU16 WINAPI
CreatePopupMenu16(void)
3825 return CreatePopupMenu();
3829 /**********************************************************************
3830 * CreatePopupMenu (USER32.@)
3832 HMENU WINAPI
CreatePopupMenu(void)
3837 if (!(hmenu
= CreateMenu())) return 0;
3838 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
3839 menu
->wFlags
|= MF_POPUP
;
3840 menu
->bTimeToHide
= FALSE
;
3845 /**********************************************************************
3846 * GetMenuCheckMarkDimensions (USER.417) (USER32.@)
3848 DWORD WINAPI
GetMenuCheckMarkDimensions(void)
3850 return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK
), GetSystemMetrics(SM_CYMENUCHECK
) );
3854 /**********************************************************************
3855 * SetMenuItemBitmaps16 (USER.418)
3857 BOOL16 WINAPI
SetMenuItemBitmaps16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
,
3858 HBITMAP16 hNewUnCheck
, HBITMAP16 hNewCheck
)
3860 return SetMenuItemBitmaps( hMenu
, nPos
, wFlags
, hNewUnCheck
, hNewCheck
);
3864 /**********************************************************************
3865 * SetMenuItemBitmaps (USER32.@)
3867 BOOL WINAPI
SetMenuItemBitmaps( HMENU hMenu
, UINT nPos
, UINT wFlags
,
3868 HBITMAP hNewUnCheck
, HBITMAP hNewCheck
)
3871 TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3872 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
3873 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3875 if (!hNewCheck
&& !hNewUnCheck
)
3877 item
->fState
&= ~MF_USECHECKBITMAPS
;
3879 else /* Install new bitmaps */
3881 item
->hCheckBit
= hNewCheck
;
3882 item
->hUnCheckBit
= hNewUnCheck
;
3883 item
->fState
|= MF_USECHECKBITMAPS
;
3889 /**********************************************************************
3890 * CreateMenu16 (USER.151)
3892 HMENU16 WINAPI
CreateMenu16(void)
3894 return CreateMenu();
3898 /**********************************************************************
3899 * CreateMenu (USER32.@)
3901 HMENU WINAPI
CreateMenu(void)
3905 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) ))) return 0;
3906 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3908 ZeroMemory(menu
, sizeof(POPUPMENU
));
3909 menu
->wMagic
= MENU_MAGIC
;
3910 menu
->FocusedItem
= NO_SELECTED_ITEM
;
3911 menu
->bTimeToHide
= FALSE
;
3913 TRACE("return %04x\n", hMenu
);
3919 /**********************************************************************
3920 * DestroyMenu16 (USER.152)
3922 BOOL16 WINAPI
DestroyMenu16( HMENU16 hMenu
)
3924 return DestroyMenu( hMenu
);
3928 /**********************************************************************
3929 * DestroyMenu (USER32.@)
3931 BOOL WINAPI
DestroyMenu( HMENU hMenu
)
3933 TRACE("(%04x)\n", hMenu
);
3935 /* Silently ignore attempts to destroy default system popup */
3937 if (hMenu
&& hMenu
!= MENU_DefSysPopup
)
3939 LPPOPUPMENU lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3940 WND
*pTPWnd
= MENU_GetTopPopupWnd();
3942 if( pTPWnd
&& (hMenu
== *(HMENU
*)pTPWnd
->wExtra
) )
3943 *(UINT
*)pTPWnd
->wExtra
= 0;
3945 if (!IS_A_MENU(lppop
)) lppop
= NULL
;
3948 lppop
->wMagic
= 0; /* Mark it as destroyed */
3950 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
&&
3951 (!pTPWnd
|| (lppop
->hWnd
!= pTPWnd
->hwndSelf
)))
3952 DestroyWindow( lppop
->hWnd
);
3954 if (lppop
->items
) /* recursively destroy submenus */
3957 MENUITEM
*item
= lppop
->items
;
3958 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
3960 if (item
->fType
& MF_POPUP
) DestroyMenu(item
->hSubMenu
);
3961 MENU_FreeItemData( item
);
3963 HeapFree( SystemHeap
, 0, lppop
->items
);
3965 USER_HEAP_FREE( hMenu
);
3966 MENU_ReleaseTopPopupWnd();
3970 MENU_ReleaseTopPopupWnd();
3974 return (hMenu
!= MENU_DefSysPopup
);
3978 /**********************************************************************
3979 * GetSystemMenu16 (USER.156)
3981 HMENU16 WINAPI
GetSystemMenu16( HWND16 hWnd
, BOOL16 bRevert
)
3983 return GetSystemMenu( hWnd
, bRevert
);
3987 /**********************************************************************
3988 * GetSystemMenu (USER32.@)
3990 HMENU WINAPI
GetSystemMenu( HWND hWnd
, BOOL bRevert
)
3992 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
3997 if( wndPtr
->hSysMenu
)
4001 DestroyMenu(wndPtr
->hSysMenu
);
4002 wndPtr
->hSysMenu
= 0;
4006 POPUPMENU
*menu
= MENU_GetMenu( wndPtr
->hSysMenu
);
4009 if( menu
->nItems
> 0 && menu
->items
[0].hSubMenu
== MENU_DefSysPopup
)
4010 menu
->items
[0].hSubMenu
= MENU_CopySysPopup();
4014 WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
4015 wndPtr
->hSysMenu
, hWnd
);
4016 wndPtr
->hSysMenu
= 0;
4021 if(!wndPtr
->hSysMenu
&& (wndPtr
->dwStyle
& WS_SYSMENU
) )
4022 wndPtr
->hSysMenu
= MENU_GetSysMenu( hWnd
, (HMENU
)(-1) );
4024 if( wndPtr
->hSysMenu
)
4027 retvalue
= GetSubMenu16(wndPtr
->hSysMenu
, 0);
4029 /* Store the dummy sysmenu handle to facilitate the refresh */
4030 /* of the close button if the SC_CLOSE item change */
4031 menu
= MENU_GetMenu(retvalue
);
4033 menu
->hSysMenuOwner
= wndPtr
->hSysMenu
;
4035 WIN_ReleaseWndPtr(wndPtr
);
4037 return bRevert
? 0 : retvalue
;
4041 /*******************************************************************
4042 * SetSystemMenu16 (USER.280)
4044 BOOL16 WINAPI
SetSystemMenu16( HWND16 hwnd
, HMENU16 hMenu
)
4046 return SetSystemMenu( hwnd
, hMenu
);
4050 /*******************************************************************
4051 * SetSystemMenu (USER32.@)
4053 BOOL WINAPI
SetSystemMenu( HWND hwnd
, HMENU hMenu
)
4055 WND
*wndPtr
= WIN_FindWndPtr(hwnd
);
4059 if (wndPtr
->hSysMenu
) DestroyMenu( wndPtr
->hSysMenu
);
4060 wndPtr
->hSysMenu
= MENU_GetSysMenu( hwnd
, hMenu
);
4061 WIN_ReleaseWndPtr(wndPtr
);
4068 /**********************************************************************
4069 * GetMenu16 (USER.157)
4071 HMENU16 WINAPI
GetMenu16( HWND16 hWnd
)
4073 return (HMENU16
)GetMenu(hWnd
);
4077 /**********************************************************************
4078 * GetMenu (USER32.@)
4080 HMENU WINAPI
GetMenu( HWND hWnd
)
4083 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
4085 if (!wndPtr
) return 0;
4087 retvalue
= (HMENU
)wndPtr
->wIDmenu
;
4088 TRACE("for %swindow %04x returning %04x\n",
4089 (wndPtr
->dwStyle
& WS_CHILD
) ? "child " : "", hWnd
, retvalue
);
4090 WIN_ReleaseWndPtr(wndPtr
);
4095 /**********************************************************************
4096 * SetMenu16 (USER.158)
4098 BOOL16 WINAPI
SetMenu16( HWND16 hWnd
, HMENU16 hMenu
)
4100 return SetMenu( hWnd
, hMenu
);
4104 /**********************************************************************
4105 * SetMenu (USER32.@)
4107 BOOL WINAPI
SetMenu( HWND hWnd
, HMENU hMenu
)
4109 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
4112 TRACE("(%04x, %04x);\n", hWnd
, hMenu
);
4114 if (hMenu
&& !IsMenu(hMenu
))
4116 WARN("hMenu is not a menu handle\n");
4120 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
4122 if (GetCapture() == hWnd
) ReleaseCapture();
4124 wndPtr
->wIDmenu
= (UINT
)hMenu
;
4129 if (!(lpmenu
= MENU_GetMenu(hMenu
)))
4132 lpmenu
->hWnd
= hWnd
;
4133 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
4135 if (IsWindowVisible(hWnd
))
4136 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4137 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4141 WIN_ReleaseWndPtr(wndPtr
);
4147 /**********************************************************************
4148 * GetSubMenu16 (USER.159)
4150 HMENU16 WINAPI
GetSubMenu16( HMENU16 hMenu
, INT16 nPos
)
4152 return GetSubMenu( hMenu
, nPos
);
4156 /**********************************************************************
4157 * GetSubMenu (USER32.@)
4159 HMENU WINAPI
GetSubMenu( HMENU hMenu
, INT nPos
)
4163 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return 0;
4164 if (!(lpmi
->fType
& MF_POPUP
)) return 0;
4165 return lpmi
->hSubMenu
;
4169 /**********************************************************************
4170 * DrawMenuBar16 (USER.160)
4172 void WINAPI
DrawMenuBar16( HWND16 hWnd
)
4174 DrawMenuBar( hWnd
);
4178 /**********************************************************************
4179 * DrawMenuBar (USER32.@)
4181 BOOL WINAPI
DrawMenuBar( HWND hWnd
)
4184 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
4185 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
) && wndPtr
->wIDmenu
)
4187 lppop
= MENU_GetMenu((HMENU16
)wndPtr
->wIDmenu
);
4190 WIN_ReleaseWndPtr(wndPtr
);
4194 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
4195 lppop
->hwndOwner
= hWnd
;
4196 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4197 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4198 WIN_ReleaseWndPtr(wndPtr
);
4201 WIN_ReleaseWndPtr(wndPtr
);
4206 /***********************************************************************
4207 * EndMenu (USER.187) (USER32.@)
4209 void WINAPI
EndMenu(void)
4211 /* if we are in the menu code, and it is active */
4212 if (fEndMenu
== FALSE
&& MENU_IsMenuActive())
4214 /* terminate the menu handling code */
4217 /* needs to be posted to wakeup the internal menu handler */
4218 /* which will now terminate the menu, in the event that */
4219 /* the main window was minimized, or lost focus, so we */
4220 /* don't end up with an orphaned menu */
4221 PostMessageA( pTopPopupWnd
->hwndSelf
, WM_CANCELMODE
, 0, 0);
4226 /***********************************************************************
4227 * LookupMenuHandle (USER.217)
4229 HMENU16 WINAPI
LookupMenuHandle16( HMENU16 hmenu
, INT16 id
)
4231 HMENU hmenu32
= hmenu
;
4233 if (!MENU_FindItem( &hmenu32
, &id32
, MF_BYCOMMAND
)) return 0;
4234 else return hmenu32
;
4238 /**********************************************************************
4239 * LoadMenu16 (USER.150)
4241 HMENU16 WINAPI
LoadMenu16( HINSTANCE16 instance
, LPCSTR name
)
4247 TRACE("(%04x,%s)\n", instance
, debugres_a(name
) );
4251 if (name
[0] == '#') name
= (LPCSTR
)atoi( name
+ 1 );
4254 if (!name
) return 0;
4256 /* check for Win32 module */
4257 if (HIWORD(instance
)) return LoadMenuA( instance
, name
);
4258 instance
= GetExePtr( instance
);
4260 if (!(hRsrc
= FindResource16( instance
, name
, RT_MENUA
))) return 0;
4261 if (!(handle
= LoadResource16( instance
, hRsrc
))) return 0;
4262 hMenu
= LoadMenuIndirect16(LockResource16(handle
));
4263 FreeResource16( handle
);
4268 /*****************************************************************
4269 * LoadMenuA (USER32.@)
4271 HMENU WINAPI
LoadMenuA( HINSTANCE instance
, LPCSTR name
)
4273 HRSRC hrsrc
= FindResourceA( instance
, name
, RT_MENUA
);
4274 if (!hrsrc
) return 0;
4275 return LoadMenuIndirectA( (LPCVOID
)LoadResource( instance
, hrsrc
));
4279 /*****************************************************************
4280 * LoadMenuW (USER32.@)
4282 HMENU WINAPI
LoadMenuW( HINSTANCE instance
, LPCWSTR name
)
4284 HRSRC hrsrc
= FindResourceW( instance
, name
, RT_MENUW
);
4285 if (!hrsrc
) return 0;
4286 return LoadMenuIndirectW( (LPCVOID
)LoadResource( instance
, hrsrc
));
4290 /**********************************************************************
4291 * LoadMenuIndirect16 (USER.220)
4293 HMENU16 WINAPI
LoadMenuIndirect16( LPCVOID
template )
4296 WORD version
, offset
;
4297 LPCSTR p
= (LPCSTR
)template;
4299 TRACE("(%p)\n", template );
4300 version
= GET_WORD(p
);
4304 WARN("version must be 0 for Win16\n" );
4307 offset
= GET_WORD(p
);
4308 p
+= sizeof(WORD
) + offset
;
4309 if (!(hMenu
= CreateMenu())) return 0;
4310 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
4312 DestroyMenu( hMenu
);
4319 /**********************************************************************
4320 * LoadMenuIndirectA (USER32.@)
4322 HMENU WINAPI
LoadMenuIndirectA( LPCVOID
template )
4325 WORD version
, offset
;
4326 LPCSTR p
= (LPCSTR
)template;
4328 TRACE("%p\n", template );
4329 version
= GET_WORD(p
);
4334 offset
= GET_WORD(p
);
4335 p
+= sizeof(WORD
) + offset
;
4336 if (!(hMenu
= CreateMenu())) return 0;
4337 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
4339 DestroyMenu( hMenu
);
4344 offset
= GET_WORD(p
);
4345 p
+= sizeof(WORD
) + offset
;
4346 if (!(hMenu
= CreateMenu())) return 0;
4347 if (!MENUEX_ParseResource( p
, hMenu
))
4349 DestroyMenu( hMenu
);
4354 ERR("version %d not supported.\n", version
);
4360 /**********************************************************************
4361 * LoadMenuIndirectW (USER32.@)
4363 HMENU WINAPI
LoadMenuIndirectW( LPCVOID
template )
4365 /* FIXME: is there anything different between A and W? */
4366 return LoadMenuIndirectA( template );
4370 /**********************************************************************
4371 * IsMenu16 (USER.358)
4373 BOOL16 WINAPI
IsMenu16( HMENU16 hmenu
)
4375 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
4376 return IS_A_MENU(menu
);
4380 /**********************************************************************
4383 BOOL WINAPI
IsMenu(HMENU hmenu
)
4385 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
4386 return IS_A_MENU(menu
);
4389 /**********************************************************************
4390 * GetMenuItemInfo_common
4393 static BOOL
GetMenuItemInfo_common ( HMENU hmenu
, UINT item
, BOOL bypos
,
4394 LPMENUITEMINFOW lpmii
, BOOL unicode
)
4396 MENUITEM
*menu
= MENU_FindItem (&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0);
4398 debug_print_menuitem("GetMenuItemInfo_common: ", menu
, "");
4403 if (lpmii
->fMask
& MIIM_TYPE
) {
4404 lpmii
->fType
= menu
->fType
;
4405 switch (MENU_ITEM_TYPE(menu
->fType
)) {
4407 break; /* will be done below */
4410 lpmii
->dwTypeData
= menu
->text
;
4417 /* copy the text string */
4418 if ((lpmii
->fMask
& (MIIM_TYPE
|MIIM_STRING
)) &&
4419 (MENU_ITEM_TYPE(menu
->fType
) == MF_STRING
) && menu
->text
)
4424 len
= strlenW(menu
->text
);
4425 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4426 lstrcpynW(lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4430 len
= WideCharToMultiByte( CP_ACP
, 0, menu
->text
, -1, NULL
, 0, NULL
, NULL
);
4431 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4432 if (!WideCharToMultiByte( CP_ACP
, 0, menu
->text
, -1,
4433 (LPSTR
)lpmii
->dwTypeData
, lpmii
->cch
, NULL
, NULL
))
4434 ((LPSTR
)lpmii
->dwTypeData
)[lpmii
->cch
-1] = 0;
4436 /* if we've copied a substring we return its length */
4437 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4439 if (lpmii
->cch
<= len
) lpmii
->cch
--;
4441 else /* return length of string */
4445 if (lpmii
->fMask
& MIIM_FTYPE
)
4446 lpmii
->fType
= menu
->fType
;
4448 if (lpmii
->fMask
& MIIM_BITMAP
)
4449 lpmii
->hbmpItem
= menu
->hbmpItem
;
4451 if (lpmii
->fMask
& MIIM_STATE
)
4452 lpmii
->fState
= menu
->fState
;
4454 if (lpmii
->fMask
& MIIM_ID
)
4455 lpmii
->wID
= menu
->wID
;
4457 if (lpmii
->fMask
& MIIM_SUBMENU
)
4458 lpmii
->hSubMenu
= menu
->hSubMenu
;
4460 if (lpmii
->fMask
& MIIM_CHECKMARKS
) {
4461 lpmii
->hbmpChecked
= menu
->hCheckBit
;
4462 lpmii
->hbmpUnchecked
= menu
->hUnCheckBit
;
4464 if (lpmii
->fMask
& MIIM_DATA
)
4465 lpmii
->dwItemData
= menu
->dwItemData
;
4470 /**********************************************************************
4471 * GetMenuItemInfoA (USER32.@)
4473 BOOL WINAPI
GetMenuItemInfoA( HMENU hmenu
, UINT item
, BOOL bypos
,
4474 LPMENUITEMINFOA lpmii
)
4476 return GetMenuItemInfo_common (hmenu
, item
, bypos
,
4477 (LPMENUITEMINFOW
)lpmii
, FALSE
);
4480 /**********************************************************************
4481 * GetMenuItemInfoW (USER32.@)
4483 BOOL WINAPI
GetMenuItemInfoW( HMENU hmenu
, UINT item
, BOOL bypos
,
4484 LPMENUITEMINFOW lpmii
)
4486 return GetMenuItemInfo_common (hmenu
, item
, bypos
,
4490 /**********************************************************************
4491 * SetMenuItemInfo_common
4494 static BOOL
SetMenuItemInfo_common(MENUITEM
* menu
,
4495 const MENUITEMINFOW
*lpmii
,
4498 if (!menu
) return FALSE
;
4500 if (lpmii
->fMask
& MIIM_TYPE
) {
4501 /* Get rid of old string. */
4502 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4503 HeapFree(SystemHeap
, 0, menu
->text
);
4507 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4508 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4509 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4511 menu
->text
= lpmii
->dwTypeData
;
4513 if (IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4515 menu
->text
= HEAP_strdupW(SystemHeap
, 0, lpmii
->dwTypeData
);
4517 menu
->text
= HEAP_strdupAtoW(SystemHeap
, 0, (LPSTR
)lpmii
->dwTypeData
);
4521 if (lpmii
->fMask
& MIIM_FTYPE
) {
4522 /* free the string when the type is changing */
4523 if ( (!IS_STRING_ITEM(lpmii
->fType
)) && IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4524 HeapFree(SystemHeap
, 0, menu
->text
);
4527 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4528 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4531 if (lpmii
->fMask
& MIIM_STRING
) {
4532 /* free the string when used */
4533 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4534 HeapFree(SystemHeap
, 0, menu
->text
);
4536 menu
->text
= HEAP_strdupW(SystemHeap
, 0, lpmii
->dwTypeData
);
4538 menu
->text
= HEAP_strdupAtoW(SystemHeap
, 0, (LPSTR
) lpmii
->dwTypeData
);
4542 if (lpmii
->fMask
& MIIM_STATE
)
4544 /* fixme: MFS_DEFAULT do we have to reset the other menu items? */
4545 menu
->fState
= lpmii
->fState
;
4548 if (lpmii
->fMask
& MIIM_ID
)
4549 menu
->wID
= lpmii
->wID
;
4551 if (lpmii
->fMask
& MIIM_SUBMENU
) {
4552 menu
->hSubMenu
= lpmii
->hSubMenu
;
4553 if (menu
->hSubMenu
) {
4554 POPUPMENU
*subMenu
= MENU_GetMenu((UINT16
)menu
->hSubMenu
);
4556 subMenu
->wFlags
|= MF_POPUP
;
4557 menu
->fType
|= MF_POPUP
;
4560 /* FIXME: Return an error ? */
4561 menu
->fType
&= ~MF_POPUP
;
4564 menu
->fType
&= ~MF_POPUP
;
4567 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
4569 if (lpmii
->fType
& MFT_RADIOCHECK
)
4570 menu
->fType
|= MFT_RADIOCHECK
;
4572 menu
->hCheckBit
= lpmii
->hbmpChecked
;
4573 menu
->hUnCheckBit
= lpmii
->hbmpUnchecked
;
4575 if (lpmii
->fMask
& MIIM_DATA
)
4576 menu
->dwItemData
= lpmii
->dwItemData
;
4578 debug_print_menuitem("SetMenuItemInfo_common: ", menu
, "");
4582 /**********************************************************************
4583 * SetMenuItemInfoA (USER32.@)
4585 BOOL WINAPI
SetMenuItemInfoA(HMENU hmenu
, UINT item
, BOOL bypos
,
4586 const MENUITEMINFOA
*lpmii
)
4588 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4589 (const MENUITEMINFOW
*)lpmii
, FALSE
);
4592 /**********************************************************************
4593 * SetMenuItemInfoW (USER32.@)
4595 BOOL WINAPI
SetMenuItemInfoW(HMENU hmenu
, UINT item
, BOOL bypos
,
4596 const MENUITEMINFOW
*lpmii
)
4598 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4602 /**********************************************************************
4603 * SetMenuDefaultItem (USER32.@)
4606 BOOL WINAPI
SetMenuDefaultItem(HMENU hmenu
, UINT uItem
, UINT bypos
)
4612 TRACE("(0x%x,%d,%d)\n", hmenu
, uItem
, bypos
);
4614 if (!(menu
= MENU_GetMenu(hmenu
))) return FALSE
;
4616 /* reset all default-item flags */
4618 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4620 item
->fState
&= ~MFS_DEFAULT
;
4623 /* no default item */
4632 if ( uItem
>= menu
->nItems
) return FALSE
;
4633 item
[uItem
].fState
|= MFS_DEFAULT
;
4638 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4640 if (item
->wID
== uItem
)
4642 item
->fState
|= MFS_DEFAULT
;
4651 /**********************************************************************
4652 * GetMenuDefaultItem (USER32.@)
4654 UINT WINAPI
GetMenuDefaultItem(HMENU hmenu
, UINT bypos
, UINT flags
)
4660 TRACE("(0x%x,%d,%d)\n", hmenu
, bypos
, flags
);
4662 if (!(menu
= MENU_GetMenu(hmenu
))) return -1;
4664 /* find default item */
4668 if (! item
) return -1;
4670 while ( !( item
->fState
& MFS_DEFAULT
) )
4673 if (i
>= menu
->nItems
) return -1;
4676 /* default: don't return disabled items */
4677 if ( (!(GMDI_USEDISABLED
& flags
)) && (item
->fState
& MFS_DISABLED
)) return -1;
4679 /* search rekursiv when needed */
4680 if ( (item
->fType
& MF_POPUP
) && (flags
& GMDI_GOINTOPOPUPS
) )
4683 ret
= GetMenuDefaultItem( item
->hSubMenu
, bypos
, flags
);
4684 if ( -1 != ret
) return ret
;
4686 /* when item not found in submenu, return the popup item */
4688 return ( bypos
) ? i
: item
->wID
;
4692 /*******************************************************************
4693 * InsertMenuItem16 (USER.441)
4697 BOOL16 WINAPI
InsertMenuItem16( HMENU16 hmenu
, UINT16 pos
, BOOL16 byposition
,
4698 const MENUITEMINFO16
*mii
)
4702 miia
.cbSize
= sizeof(miia
);
4703 miia
.fMask
= mii
->fMask
;
4704 miia
.dwTypeData
= (LPSTR
)mii
->dwTypeData
;
4705 miia
.fType
= mii
->fType
;
4706 miia
.fState
= mii
->fState
;
4707 miia
.wID
= mii
->wID
;
4708 miia
.hSubMenu
= mii
->hSubMenu
;
4709 miia
.hbmpChecked
= mii
->hbmpChecked
;
4710 miia
.hbmpUnchecked
= mii
->hbmpUnchecked
;
4711 miia
.dwItemData
= mii
->dwItemData
;
4712 miia
.cch
= mii
->cch
;
4713 if (IS_STRING_ITEM(miia
.fType
))
4714 miia
.dwTypeData
= MapSL(mii
->dwTypeData
);
4715 return InsertMenuItemA( hmenu
, pos
, byposition
, &miia
);
4719 /**********************************************************************
4720 * InsertMenuItemA (USER32.@)
4722 BOOL WINAPI
InsertMenuItemA(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4723 const MENUITEMINFOA
*lpmii
)
4725 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4726 return SetMenuItemInfo_common(item
, (const MENUITEMINFOW
*)lpmii
, FALSE
);
4730 /**********************************************************************
4731 * InsertMenuItemW (USER32.@)
4733 BOOL WINAPI
InsertMenuItemW(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4734 const MENUITEMINFOW
*lpmii
)
4736 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4737 return SetMenuItemInfo_common(item
, lpmii
, TRUE
);
4740 /**********************************************************************
4741 * CheckMenuRadioItem (USER32.@)
4744 BOOL WINAPI
CheckMenuRadioItem(HMENU hMenu
,
4745 UINT first
, UINT last
, UINT check
,
4748 MENUITEM
*mifirst
, *milast
, *micheck
;
4749 HMENU mfirst
= hMenu
, mlast
= hMenu
, mcheck
= hMenu
;
4751 TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4752 hMenu
, first
, last
, check
, bypos
);
4754 mifirst
= MENU_FindItem (&mfirst
, &first
, bypos
);
4755 milast
= MENU_FindItem (&mlast
, &last
, bypos
);
4756 micheck
= MENU_FindItem (&mcheck
, &check
, bypos
);
4758 if (mifirst
== NULL
|| milast
== NULL
|| micheck
== NULL
||
4759 mifirst
> milast
|| mfirst
!= mlast
|| mfirst
!= mcheck
||
4760 micheck
> milast
|| micheck
< mifirst
)
4763 while (mifirst
<= milast
)
4765 if (mifirst
== micheck
)
4767 mifirst
->fType
|= MFT_RADIOCHECK
;
4768 mifirst
->fState
|= MFS_CHECKED
;
4770 mifirst
->fType
&= ~MFT_RADIOCHECK
;
4771 mifirst
->fState
&= ~MFS_CHECKED
;
4779 /**********************************************************************
4780 * CheckMenuRadioItem16 (not a Windows API)
4783 BOOL16 WINAPI
CheckMenuRadioItem16(HMENU16 hMenu
,
4784 UINT16 first
, UINT16 last
, UINT16 check
,
4787 return CheckMenuRadioItem (hMenu
, first
, last
, check
, bypos
);
4790 /**********************************************************************
4791 * GetMenuItemRect (USER32.@)
4793 * ATTENTION: Here, the returned values in rect are the screen
4794 * coordinates of the item just like if the menu was
4795 * always on the upper left side of the application.
4798 BOOL WINAPI
GetMenuItemRect (HWND hwnd
, HMENU hMenu
, UINT uItem
,
4801 POPUPMENU
*itemMenu
;
4805 TRACE("(0x%x,0x%x,%d,%p)\n", hwnd
, hMenu
, uItem
, rect
);
4807 item
= MENU_FindItem (&hMenu
, &uItem
, MF_BYPOSITION
);
4808 referenceHwnd
= hwnd
;
4812 itemMenu
= MENU_GetMenu(hMenu
);
4813 if (itemMenu
== NULL
)
4816 if(itemMenu
->hWnd
== 0)
4818 referenceHwnd
= itemMenu
->hWnd
;
4821 if ((rect
== NULL
) || (item
== NULL
))
4826 MapWindowPoints(referenceHwnd
, 0, (LPPOINT
)rect
, 2);
4831 /**********************************************************************
4832 * GetMenuItemRect16 (USER.665)
4835 BOOL16 WINAPI
GetMenuItemRect16 (HWND16 hwnd
, HMENU16 hMenu
, UINT16 uItem
,
4841 if (!rect
) return FALSE
;
4842 res
= GetMenuItemRect (hwnd
, hMenu
, uItem
, &r32
);
4843 CONV_RECT32TO16 (&r32
, rect
);
4847 /**********************************************************************
4848 * SetMenuInfo (USER32.@)
4851 * MIM_APPLYTOSUBMENUS
4852 * actually use the items to draw the menu
4854 BOOL WINAPI
SetMenuInfo (HMENU hMenu
, LPCMENUINFO lpmi
)
4858 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4860 if (lpmi
&& (lpmi
->cbSize
==sizeof(MENUINFO
)) && (menu
= MENU_GetMenu(hMenu
)))
4863 if (lpmi
->fMask
& MIM_BACKGROUND
)
4864 menu
->hbrBack
= lpmi
->hbrBack
;
4866 if (lpmi
->fMask
& MIM_HELPID
)
4867 menu
->dwContextHelpID
= lpmi
->dwContextHelpID
;
4869 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4870 menu
->cyMax
= lpmi
->cyMax
;
4872 if (lpmi
->fMask
& MIM_MENUDATA
)
4873 menu
->dwMenuData
= lpmi
->dwMenuData
;
4875 if (lpmi
->fMask
& MIM_STYLE
)
4876 menu
->dwStyle
= lpmi
->dwStyle
;
4883 /**********************************************************************
4884 * GetMenuInfo (USER32.@)
4890 BOOL WINAPI
GetMenuInfo (HMENU hMenu
, LPMENUINFO lpmi
)
4893 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4895 if (lpmi
&& (menu
= MENU_GetMenu(hMenu
)))
4898 if (lpmi
->fMask
& MIM_BACKGROUND
)
4899 lpmi
->hbrBack
= menu
->hbrBack
;
4901 if (lpmi
->fMask
& MIM_HELPID
)
4902 lpmi
->dwContextHelpID
= menu
->dwContextHelpID
;
4904 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4905 lpmi
->cyMax
= menu
->cyMax
;
4907 if (lpmi
->fMask
& MIM_MENUDATA
)
4908 lpmi
->dwMenuData
= menu
->dwMenuData
;
4910 if (lpmi
->fMask
& MIM_STYLE
)
4911 lpmi
->dwStyle
= menu
->dwStyle
;
4918 /**********************************************************************
4919 * SetMenuContextHelpId16 (USER.384)
4921 BOOL16 WINAPI
SetMenuContextHelpId16( HMENU16 hMenu
, DWORD dwContextHelpID
)
4923 return SetMenuContextHelpId( hMenu
, dwContextHelpID
);
4927 /**********************************************************************
4928 * SetMenuContextHelpId (USER32.@)
4930 BOOL WINAPI
SetMenuContextHelpId( HMENU hMenu
, DWORD dwContextHelpID
)
4934 TRACE("(0x%04x 0x%08lx)\n", hMenu
, dwContextHelpID
);
4936 if ((menu
= MENU_GetMenu(hMenu
)))
4938 menu
->dwContextHelpID
= dwContextHelpID
;
4944 /**********************************************************************
4945 * GetMenuContextHelpId16 (USER.385)
4947 DWORD WINAPI
GetMenuContextHelpId16( HMENU16 hMenu
)
4949 return GetMenuContextHelpId( hMenu
);
4952 /**********************************************************************
4953 * GetMenuContextHelpId (USER32.@)
4955 DWORD WINAPI
GetMenuContextHelpId( HMENU hMenu
)
4959 TRACE("(0x%04x)\n", hMenu
);
4961 if ((menu
= MENU_GetMenu(hMenu
)))
4963 return menu
->dwContextHelpID
;
4968 /**********************************************************************
4969 * MenuItemFromPoint (USER32.@)
4971 UINT WINAPI
MenuItemFromPoint(HWND hWnd
, HMENU hMenu
, POINT ptScreen
)
4973 FIXME("(0x%04x,0x%04x,(%ld,%ld)):stub\n",
4974 hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4979 /**********************************************************************
4980 * translate_accelerator
4982 static BOOL
translate_accelerator( HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
,
4983 BYTE fVirt
, WORD key
, WORD cmd
)
4987 if (wParam
!= key
) return FALSE
;
4989 if (message
== WM_CHAR
)
4991 if ( !(fVirt
& FALT
) && !(fVirt
& FVIRTKEY
) )
4993 TRACE_(accel
)("found accel for WM_CHAR: ('%c')\n", wParam
& 0xff);
4999 if(fVirt
& FVIRTKEY
)
5002 TRACE_(accel
)("found accel for virt_key %04x (scan %04x)\n",
5003 wParam
, 0xff & HIWORD(lParam
));
5004 if(GetKeyState(VK_SHIFT
) & 0x8000) mask
|= FSHIFT
;
5005 if(GetKeyState(VK_CONTROL
) & 0x8000) mask
|= FCONTROL
;
5006 if(GetKeyState(VK_MENU
) & 0x8000) mask
|= FALT
;
5007 if(mask
== (fVirt
& (FSHIFT
| FCONTROL
| FALT
))) goto found
;
5008 TRACE_(accel
)(", but incorrect SHIFT/CTRL/ALT-state\n");
5012 if (!(lParam
& 0x01000000)) /* no special_key */
5014 if ((fVirt
& FALT
) && (lParam
& 0x20000000))
5015 { /* ^^ ALT pressed */
5016 TRACE_(accel
)("found accel for Alt-%c\n", wParam
& 0xff);
5025 if (message
== WM_KEYUP
|| message
== WM_SYSKEYUP
)
5027 else if (GetCapture())
5029 else if (!IsWindowEnabled(hWnd
))
5033 HMENU hMenu
, hSubMenu
, hSysMenu
;
5034 UINT uSysStat
= (UINT
)-1, uStat
= (UINT
)-1, nPos
;
5035 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
5037 hMenu
= (wndPtr
->dwStyle
& WS_CHILD
) ? 0 : (HMENU
)wndPtr
->wIDmenu
;
5038 hSysMenu
= wndPtr
->hSysMenu
;
5039 WIN_ReleaseWndPtr(wndPtr
);
5041 /* find menu item and ask application to initialize it */
5042 /* 1. in the system menu */
5043 hSubMenu
= hSysMenu
;
5045 if(MENU_FindItem(&hSubMenu
, &nPos
, MF_BYCOMMAND
))
5047 SendMessageA(hWnd
, WM_INITMENU
, (WPARAM
)hSysMenu
, 0L);
5048 if(hSubMenu
!= hSysMenu
)
5050 nPos
= MENU_FindSubMenu(&hSysMenu
, hSubMenu
);
5051 TRACE_(accel
)("hSysMenu = %04x, hSubMenu = %04x, nPos = %d\n", hSysMenu
, hSubMenu
, nPos
);
5052 SendMessageA(hWnd
, WM_INITMENUPOPUP
, (WPARAM
)hSubMenu
, MAKELPARAM(nPos
, TRUE
));
5054 uSysStat
= GetMenuState(GetSubMenu(hSysMenu
, 0), cmd
, MF_BYCOMMAND
);
5056 else /* 2. in the window's menu */
5060 if(MENU_FindItem(&hSubMenu
, &nPos
, MF_BYCOMMAND
))
5062 SendMessageA(hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0L);
5063 if(hSubMenu
!= hMenu
)
5065 nPos
= MENU_FindSubMenu(&hMenu
, hSubMenu
);
5066 TRACE_(accel
)("hMenu = %04x, hSubMenu = %04x, nPos = %d\n", hMenu
, hSubMenu
, nPos
);
5067 SendMessageA(hWnd
, WM_INITMENUPOPUP
, (WPARAM
)hSubMenu
, MAKELPARAM(nPos
, FALSE
));
5069 uStat
= GetMenuState(hMenu
, cmd
, MF_BYCOMMAND
);
5073 if (uSysStat
!= (UINT
)-1)
5075 if (uSysStat
& (MF_DISABLED
|MF_GRAYED
))
5082 if (uStat
!= (UINT
)-1)
5088 if (uStat
& (MF_DISABLED
|MF_GRAYED
))
5099 if( mesg
==WM_COMMAND
)
5101 TRACE_(accel
)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd
);
5102 SendMessageA(hWnd
, mesg
, 0x10000 | cmd
, 0L);
5104 else if( mesg
==WM_SYSCOMMAND
)
5106 TRACE_(accel
)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd
);
5107 SendMessageA(hWnd
, mesg
, cmd
, 0x00010000L
);
5111 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
5112 * #0: unknown (please report!)
5113 * #1: for WM_KEYUP,WM_SYSKEYUP
5114 * #2: mouse is captured
5115 * #3: window is disabled
5116 * #4: it's a disabled system menu option
5117 * #5: it's a menu option, but window is iconic
5118 * #6: it's a menu option, but disabled
5120 TRACE_(accel
)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg
);
5122 ERR_(accel
)(" unknown reason - please report!");
5127 /**********************************************************************
5128 * TranslateAccelerator (USER32.@)
5130 INT WINAPI
TranslateAccelerator( HWND hWnd
, HACCEL hAccel
, LPMSG msg
)
5133 LPACCEL16 lpAccelTbl
;
5138 WARN_(accel
)("msg null; should hang here to be win compatible\n");
5141 if (!hAccel
|| !(lpAccelTbl
= (LPACCEL16
) LockResource16(hAccel
)))
5143 WARN_(accel
)("invalid accel handle=%x\n", hAccel
);
5146 if ((msg
->message
!= WM_KEYDOWN
&&
5147 msg
->message
!= WM_KEYUP
&&
5148 msg
->message
!= WM_SYSKEYDOWN
&&
5149 msg
->message
!= WM_SYSKEYUP
&&
5150 msg
->message
!= WM_CHAR
)) return 0;
5152 TRACE_(accel
)("TranslateAccelerators hAccel=%04x, hWnd=%04x,"
5153 "msg->hwnd=%04x, msg->message=%04x, wParam=%08x, lParam=%lx\n",
5154 hAccel
,hWnd
,msg
->hwnd
,msg
->message
,msg
->wParam
,msg
->lParam
);
5159 if (translate_accelerator( hWnd
, msg
->message
, msg
->wParam
, msg
->lParam
,
5160 lpAccelTbl
[i
].fVirt
, lpAccelTbl
[i
].key
, lpAccelTbl
[i
].cmd
))
5162 } while ((lpAccelTbl
[i
++].fVirt
& 0x80) == 0);
5163 WARN_(accel
)("couldn't translate accelerator key\n");
5168 /**********************************************************************
5169 * TranslateAccelerator16 (USER.178)
5171 INT16 WINAPI
TranslateAccelerator16( HWND16 hWnd
, HACCEL16 hAccel
, LPMSG16 msg
)
5173 LPACCEL16 lpAccelTbl
;
5178 WARN_(accel
)("msg null; should hang here to be win compatible\n");
5181 if (!hAccel
|| !(lpAccelTbl
= (LPACCEL16
) LockResource16(hAccel
)))
5183 WARN_(accel
)("invalid accel handle=%x\n", hAccel
);
5186 if ((msg
->message
!= WM_KEYDOWN
&&
5187 msg
->message
!= WM_KEYUP
&&
5188 msg
->message
!= WM_SYSKEYDOWN
&&
5189 msg
->message
!= WM_SYSKEYUP
&&
5190 msg
->message
!= WM_CHAR
)) return 0;
5192 TRACE_(accel
)("TranslateAccelerators hAccel=%04x, hWnd=%04x,"
5193 "msg->hwnd=%04x, msg->message=%04x, wParam=%04x, lParam=%lx\n",
5194 hAccel
,hWnd
,msg
->hwnd
,msg
->message
,msg
->wParam
,msg
->lParam
);
5199 if (translate_accelerator( hWnd
, msg
->message
, msg
->wParam
, msg
->lParam
,
5200 lpAccelTbl
[i
].fVirt
, lpAccelTbl
[i
].key
, lpAccelTbl
[i
].cmd
))
5202 } while ((lpAccelTbl
[i
++].fVirt
& 0x80) == 0);
5203 WARN_(accel
)("couldn't translate accelerator key\n");