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 msg
.hwnd
= (wFlags
& TPM_ENTERIDLEEX
&& menu
->wFlags
& MF_POPUP
) ? menu
->hWnd
: 0;
2771 /* we have to keep the message in the queue until it's
2772 * clear that menu loop is not over yet. */
2774 if (!MSG_InternalGetMessage( QMSG_WIN32A
, &msg
, msg
.hwnd
, mt
.hOwnerWnd
,
2775 MSGF_MENU
, PM_NOREMOVE
, !enterIdleSent
, &enterIdleSent
)) break;
2777 /* check if EndMenu() tried to cancel us, by posting this message */
2778 if(msg
.message
== WM_CANCELMODE
)
2780 /* we are now out of the loop */
2783 /* remove the message from the queue */
2784 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2786 /* break out of internal loop, ala ESCAPE */
2790 TranslateMessage( &msg
);
2793 if ( (msg
.hwnd
==menu
->hWnd
) || (msg
.message
!=WM_TIMER
) )
2794 enterIdleSent
=FALSE
;
2797 if ((msg
.message
>= WM_MOUSEFIRST
) && (msg
.message
<= WM_MOUSELAST
))
2800 * use the mouse coordinates in lParam instead of those in the MSG
2801 * struct to properly handle synthetic messages. lParam coords are
2802 * relative to client area, so they must be converted; since they can
2803 * be negative, we must use SLOWORD/SHIWORD instead of LOWORD/HIWORD.
2805 mt
.pt
.x
= SLOWORD(msg
.lParam
);
2806 mt
.pt
.y
= SHIWORD(msg
.lParam
);
2807 ClientToScreen(msg
.hwnd
,&mt
.pt
);
2809 /* Find a menu for this mouse event */
2810 hmenu
= MENU_PtMenu( mt
.hTopMenu
, mt
.pt
);
2814 /* no WM_NC... messages in captured state */
2816 case WM_RBUTTONDBLCLK
:
2817 case WM_RBUTTONDOWN
:
2818 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2820 case WM_LBUTTONDBLCLK
:
2821 case WM_LBUTTONDOWN
:
2822 /* If the message belongs to the menu, removes it from the queue */
2823 /* Else, end menu tracking */
2824 fRemove
= MENU_ButtonDown( &mt
, hmenu
, wFlags
);
2825 fEndMenu
= !fRemove
;
2829 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
2832 /* Check if a menu was selected by the mouse */
2835 executedMenuId
= MENU_ButtonUp( &mt
, hmenu
, wFlags
);
2837 /* End the loop if executedMenuId is an item ID */
2838 /* or if the job was done (executedMenuId = 0). */
2839 fEndMenu
= fRemove
= (executedMenuId
!= -1);
2841 /* No menu was selected by the mouse */
2842 /* if the function was called by TrackPopupMenu, continue
2843 with the menu tracking. If not, stop it */
2845 fEndMenu
= ((wFlags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
2850 /* In win95 winelook, the selected menu item must be changed every time the
2851 mouse moves. In Win31 winelook, the mouse button has to be held down */
2853 if ( (TWEAK_WineLook
> WIN31_LOOK
) ||
2854 ( (msg
.wParam
& MK_LBUTTON
) ||
2855 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
.wParam
& MK_RBUTTON
))) )
2857 fEndMenu
|= !MENU_MouseMove( &mt
, hmenu
, wFlags
);
2859 } /* switch(msg.message) - mouse */
2861 else if ((msg
.message
>= WM_KEYFIRST
) && (msg
.message
<= WM_KEYLAST
))
2863 fRemove
= TRUE
; /* Keyboard messages are always removed */
2871 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2872 NO_SELECTED_ITEM
, FALSE
, 0 );
2875 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2876 (msg
.wParam
== VK_HOME
)? ITEM_NEXT
: ITEM_PREV
);
2879 case VK_DOWN
: /* If on menu bar, pull-down the menu */
2881 menu
= MENU_GetMenu( mt
.hCurrentMenu
);
2882 if (!(menu
->wFlags
& MF_POPUP
))
2883 mt
.hCurrentMenu
= MENU_ShowSubPopup(mt
.hOwnerWnd
, mt
.hTopMenu
, TRUE
, wFlags
);
2884 else /* otherwise try to move selection */
2885 MENU_MoveSelection( mt
.hOwnerWnd
, mt
.hCurrentMenu
, ITEM_NEXT
);
2889 MENU_KeyLeft( &mt
, wFlags
);
2893 MENU_KeyRight( &mt
, wFlags
);
2903 hi
.cbSize
= sizeof(HELPINFO
);
2904 hi
.iContextType
= HELPINFO_MENUITEM
;
2905 if (menu
->FocusedItem
== NO_SELECTED_ITEM
)
2908 hi
.iCtrlId
= menu
->items
[menu
->FocusedItem
].wID
;
2909 hi
.hItemHandle
= hmenu
;
2910 hi
.dwContextId
= menu
->dwContextHelpID
;
2911 hi
.MousePos
= msg
.pt
;
2912 SendMessageA(hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
2919 break; /* WM_KEYDOWN */
2929 break; /* WM_SYSKEYDOWN */
2935 if (msg
.wParam
== '\r' || msg
.wParam
== ' ')
2937 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2938 fEndMenu
= (executedMenuId
!= -1);
2943 /* Hack to avoid control chars. */
2944 /* We will find a better way real soon... */
2945 if ((msg
.wParam
<= 32) || (msg
.wParam
>= 127)) break;
2947 pos
= MENU_FindItemByKey( mt
.hOwnerWnd
, mt
.hCurrentMenu
,
2948 LOWORD(msg
.wParam
), FALSE
);
2949 if (pos
== (UINT
)-2) fEndMenu
= TRUE
;
2950 else if (pos
== (UINT
)-1) MessageBeep(0);
2953 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hCurrentMenu
, pos
,
2955 executedMenuId
= MENU_ExecFocusedItem(&mt
,mt
.hCurrentMenu
, wFlags
);
2956 fEndMenu
= (executedMenuId
!= -1);
2960 } /* switch(msg.message) - kbd */
2964 DispatchMessageA( &msg
);
2967 if (!fEndMenu
) fRemove
= TRUE
;
2969 /* finally remove message from the queue */
2971 if (fRemove
&& !(mt
.trackFlags
& TF_SKIPREMOVE
) )
2972 PeekMessageA( &msg
, 0, msg
.message
, msg
.message
, PM_REMOVE
);
2973 else mt
.trackFlags
&= ~TF_SKIPREMOVE
;
2978 /* If dropdown is still painted and the close box is clicked on
2979 then the menu will be destroyed as part of the DispatchMessage above.
2980 This will then invalidate the menu handle in mt.hTopMenu. We should
2981 check for this first. */
2982 if( IsMenu( mt
.hTopMenu
) )
2984 menu
= MENU_GetMenu( mt
.hTopMenu
);
2986 if( IsWindow( mt
.hOwnerWnd
) )
2988 MENU_HideSubPopups( mt
.hOwnerWnd
, mt
.hTopMenu
, FALSE
);
2990 if (menu
&& menu
->wFlags
& MF_POPUP
)
2992 ShowWindow( menu
->hWnd
, SW_HIDE
);
2995 MENU_SelectItem( mt
.hOwnerWnd
, mt
.hTopMenu
, NO_SELECTED_ITEM
, FALSE
, 0 );
2996 SendMessageA( mt
.hOwnerWnd
, WM_MENUSELECT
, MAKELONG(0,0xffff), 0 );
2999 /* Reset the variable for hiding menu */
3000 if( menu
) menu
->bTimeToHide
= FALSE
;
3003 /* The return value is only used by TrackPopupMenu */
3004 return ((executedMenuId
!= -1) ? executedMenuId
: 0);
3007 /***********************************************************************
3010 static BOOL
MENU_InitTracking(HWND hWnd
, HMENU hMenu
, BOOL bPopup
, UINT wFlags
)
3012 TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd
, hMenu
);
3016 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
3017 if (!(wFlags
& TPM_NONOTIFY
))
3018 SendMessageA( hWnd
, WM_ENTERMENULOOP
, bPopup
, 0 );
3020 SendMessageA( hWnd
, WM_SETCURSOR
, hWnd
, HTCAPTION
);
3022 if (!(wFlags
& TPM_NONOTIFY
))
3023 SendMessageA( hWnd
, WM_INITMENU
, hMenu
, 0 );
3027 /***********************************************************************
3030 static BOOL
MENU_ExitTracking(HWND hWnd
)
3032 TRACE("hwnd=0x%04x\n", hWnd
);
3034 SendMessageA( hWnd
, WM_EXITMENULOOP
, 0, 0 );
3039 /***********************************************************************
3040 * MENU_TrackMouseMenuBar
3042 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
3044 void MENU_TrackMouseMenuBar( WND
* wndPtr
, INT ht
, POINT pt
)
3046 HWND hWnd
= wndPtr
->hwndSelf
;
3047 HMENU hMenu
= (ht
== HTSYSMENU
) ? wndPtr
->hSysMenu
: wndPtr
->wIDmenu
;
3048 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3050 TRACE("pwnd=%p ht=0x%04x (%ld,%ld)\n", wndPtr
, ht
, pt
.x
, pt
.y
);
3054 MENU_InitTracking( hWnd
, hMenu
, FALSE
, wFlags
);
3055 MENU_TrackMenu( hMenu
, wFlags
, pt
.x
, pt
.y
, hWnd
, NULL
);
3056 MENU_ExitTracking(hWnd
);
3061 /***********************************************************************
3062 * MENU_TrackKbdMenuBar
3064 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3066 void MENU_TrackKbdMenuBar( WND
* wndPtr
, UINT wParam
, INT vkey
)
3068 UINT uItem
= NO_SELECTED_ITEM
;
3070 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3072 /* find window that has a menu */
3074 while( wndPtr
->dwStyle
& WS_CHILD
)
3075 if( !(wndPtr
= wndPtr
->parent
) ) return;
3077 /* check if we have to track a system menu */
3079 if( (wndPtr
->dwStyle
& (WS_CHILD
| WS_MINIMIZE
)) ||
3080 !wndPtr
->wIDmenu
|| vkey
== VK_SPACE
)
3082 if( !(wndPtr
->dwStyle
& WS_SYSMENU
) ) return;
3083 hTrackMenu
= wndPtr
->hSysMenu
;
3085 wParam
|= HTSYSMENU
; /* prevent item lookup */
3088 hTrackMenu
= wndPtr
->wIDmenu
;
3090 if (IsMenu( hTrackMenu
))
3092 MENU_InitTracking( wndPtr
->hwndSelf
, hTrackMenu
, FALSE
, wFlags
);
3094 if( vkey
&& vkey
!= VK_SPACE
)
3096 uItem
= MENU_FindItemByKey( wndPtr
->hwndSelf
, hTrackMenu
,
3097 vkey
, (wParam
& HTSYSMENU
) );
3098 if( uItem
>= (UINT
)(-2) )
3100 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3107 MENU_SelectItem( wndPtr
->hwndSelf
, hTrackMenu
, uItem
, TRUE
, 0 );
3109 if( uItem
== NO_SELECTED_ITEM
)
3110 MENU_MoveSelection( wndPtr
->hwndSelf
, hTrackMenu
, ITEM_NEXT
);
3112 PostMessageA( wndPtr
->hwndSelf
, WM_KEYDOWN
, VK_DOWN
, 0L );
3114 MENU_TrackMenu( hTrackMenu
, wFlags
, 0, 0, wndPtr
->hwndSelf
, NULL
);
3117 MENU_ExitTracking (wndPtr
->hwndSelf
);
3122 /**********************************************************************
3123 * TrackPopupMenu16 (USER.416)
3125 BOOL16 WINAPI
TrackPopupMenu16( HMENU16 hMenu
, UINT16 wFlags
, INT16 x
, INT16 y
,
3126 INT16 nReserved
, HWND16 hWnd
, const RECT16
*lpRect
)
3130 CONV_RECT16TO32( lpRect
, &r
);
3131 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, nReserved
, hWnd
,
3132 lpRect
? &r
: NULL
);
3136 /**********************************************************************
3137 * TrackPopupMenu (USER32.@)
3139 * Like the win32 API, the function return the command ID only if the
3140 * flag TPM_RETURNCMD is on.
3143 BOOL WINAPI
TrackPopupMenu( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3144 INT nReserved
, HWND hWnd
, const RECT
*lpRect
)
3148 MENU_InitTracking(hWnd
, hMenu
, TRUE
, wFlags
);
3150 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3151 if (!(wFlags
& TPM_NONOTIFY
))
3152 SendMessageA( hWnd
, WM_INITMENUPOPUP
, hMenu
, 0);
3154 if (MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
, 0, 0 ))
3155 ret
= MENU_TrackMenu( hMenu
, wFlags
| TPM_POPUPMENU
, 0, 0, hWnd
, lpRect
);
3156 MENU_ExitTracking(hWnd
);
3158 if( (!(wFlags
& TPM_RETURNCMD
)) && (ret
!= FALSE
) )
3164 /**********************************************************************
3165 * TrackPopupMenuEx (USER32.@)
3167 BOOL WINAPI
TrackPopupMenuEx( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
3168 HWND hWnd
, LPTPMPARAMS lpTpm
)
3170 FIXME("not fully implemented\n" );
3171 return TrackPopupMenu( hMenu
, wFlags
, x
, y
, 0, hWnd
,
3172 lpTpm
? &lpTpm
->rcExclude
: NULL
);
3175 /***********************************************************************
3178 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3180 static LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
3182 TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
3183 hwnd
, message
, wParam
, lParam
);
3189 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*)lParam
;
3190 SetWindowLongW( hwnd
, 0, (LONG
)cs
->lpCreateParams
);
3194 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
3195 return MA_NOACTIVATE
;
3200 BeginPaint( hwnd
, &ps
);
3201 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
3202 (HMENU
)GetWindowLongA( hwnd
, 0 ) );
3203 EndPaint( hwnd
, &ps
);
3211 /* zero out global pointer in case resident popup window
3212 * was somehow destroyed. */
3214 if(MENU_GetTopPopupWnd() )
3216 if( hwnd
== pTopPopupWnd
->hwndSelf
)
3218 ERR("resident popup destroyed!\n");
3220 MENU_DestroyTopPopupWnd();
3225 MENU_ReleaseTopPopupWnd();
3233 if (!GetWindowLongW( hwnd
, 0 )) ERR("no menu to display\n");
3236 SetWindowLongW( hwnd
, 0, 0 );
3239 case MM_SETMENUHANDLE
:
3240 SetWindowLongW( hwnd
, 0, wParam
);
3243 case MM_GETMENUHANDLE
:
3244 return GetWindowLongW( hwnd
, 0 );
3247 return DefWindowProcW( hwnd
, message
, wParam
, lParam
);
3253 /***********************************************************************
3254 * MENU_GetMenuBarHeight
3256 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3258 UINT
MENU_GetMenuBarHeight( HWND hwnd
, UINT menubarWidth
,
3259 INT orgX
, INT orgY
)
3267 TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3268 hwnd
, menubarWidth
, orgX
, orgY
);
3270 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
3273 if (!(lppop
= MENU_GetMenu((HMENU16
)wndPtr
->wIDmenu
)))
3275 WIN_ReleaseWndPtr(wndPtr
);
3279 hdc
= GetDCEx( hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
3280 SelectObject( hdc
, hMenuFont
);
3281 SetRect(&rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+GetSystemMetrics(SM_CYMENU
));
3282 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
3283 ReleaseDC( hwnd
, hdc
);
3284 retvalue
= lppop
->Height
;
3285 WIN_ReleaseWndPtr(wndPtr
);
3290 /*******************************************************************
3291 * ChangeMenu16 (USER.153)
3293 BOOL16 WINAPI
ChangeMenu16( HMENU16 hMenu
, UINT16 pos
, SEGPTR data
,
3294 UINT16 id
, UINT16 flags
)
3296 TRACE("menu=%04x pos=%d data=%08lx id=%04x flags=%04x\n",
3297 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3298 if (flags
& MF_APPEND
) return AppendMenu16( hMenu
, flags
& ~MF_APPEND
,
3301 /* FIXME: Word passes the item id in 'pos' and 0 or 0xffff as id */
3302 /* for MF_DELETE. We should check the parameters for all others */
3303 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
3305 if (flags
& MF_DELETE
) return DeleteMenu16(hMenu
, pos
, flags
& ~MF_DELETE
);
3306 if (flags
& MF_CHANGE
) return ModifyMenu16(hMenu
, pos
, flags
& ~MF_CHANGE
,
3308 if (flags
& MF_REMOVE
) return RemoveMenu16(hMenu
,
3309 flags
& MF_BYPOSITION
? pos
: id
,
3310 flags
& ~MF_REMOVE
);
3311 /* Default: MF_INSERT */
3312 return InsertMenu16( hMenu
, pos
, flags
, id
, data
);
3316 /*******************************************************************
3317 * ChangeMenuA (USER32.@)
3319 BOOL WINAPI
ChangeMenuA( HMENU hMenu
, UINT pos
, LPCSTR data
,
3320 UINT id
, UINT flags
)
3322 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3323 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3324 if (flags
& MF_APPEND
) return AppendMenuA( hMenu
, flags
& ~MF_APPEND
,
3326 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3327 if (flags
& MF_CHANGE
) return ModifyMenuA(hMenu
, pos
, flags
& ~MF_CHANGE
,
3329 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3330 flags
& MF_BYPOSITION
? pos
: id
,
3331 flags
& ~MF_REMOVE
);
3332 /* Default: MF_INSERT */
3333 return InsertMenuA( hMenu
, pos
, flags
, id
, data
);
3337 /*******************************************************************
3338 * ChangeMenuW (USER32.@)
3340 BOOL WINAPI
ChangeMenuW( HMENU hMenu
, UINT pos
, LPCWSTR data
,
3341 UINT id
, UINT flags
)
3343 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3344 hMenu
, pos
, (DWORD
)data
, id
, flags
);
3345 if (flags
& MF_APPEND
) return AppendMenuW( hMenu
, flags
& ~MF_APPEND
,
3347 if (flags
& MF_DELETE
) return DeleteMenu(hMenu
, pos
, flags
& ~MF_DELETE
);
3348 if (flags
& MF_CHANGE
) return ModifyMenuW(hMenu
, pos
, flags
& ~MF_CHANGE
,
3350 if (flags
& MF_REMOVE
) return RemoveMenu( hMenu
,
3351 flags
& MF_BYPOSITION
? pos
: id
,
3352 flags
& ~MF_REMOVE
);
3353 /* Default: MF_INSERT */
3354 return InsertMenuW( hMenu
, pos
, flags
, id
, data
);
3358 /*******************************************************************
3359 * CheckMenuItem16 (USER.154)
3361 BOOL16 WINAPI
CheckMenuItem16( HMENU16 hMenu
, UINT16 id
, UINT16 flags
)
3363 return (BOOL16
)CheckMenuItem( hMenu
, id
, flags
);
3367 /*******************************************************************
3368 * CheckMenuItem (USER32.@)
3370 DWORD WINAPI
CheckMenuItem( HMENU hMenu
, UINT id
, UINT flags
)
3375 TRACE("menu=%04x id=%04x flags=%04x\n", hMenu
, id
, flags
);
3376 if (!(item
= MENU_FindItem( &hMenu
, &id
, flags
))) return -1;
3377 ret
= item
->fState
& MF_CHECKED
;
3378 if (flags
& MF_CHECKED
) item
->fState
|= MF_CHECKED
;
3379 else item
->fState
&= ~MF_CHECKED
;
3384 /**********************************************************************
3385 * EnableMenuItem16 (USER.155)
3387 UINT16 WINAPI
EnableMenuItem16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3389 return EnableMenuItem( hMenu
, wItemID
, wFlags
);
3393 /**********************************************************************
3394 * EnableMenuItem (USER32.@)
3396 UINT WINAPI
EnableMenuItem( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3402 TRACE("(%04x, %04X, %04X) !\n",
3403 hMenu
, wItemID
, wFlags
);
3405 /* Get the Popupmenu to access the owner menu */
3406 if (!(menu
= MENU_GetMenu(hMenu
)))
3409 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
)))
3412 oldflags
= item
->fState
& (MF_GRAYED
| MF_DISABLED
);
3413 item
->fState
^= (oldflags
^ wFlags
) & (MF_GRAYED
| MF_DISABLED
);
3415 /* In win95 if the close item in the system menu change update the close button */
3416 if (TWEAK_WineLook
== WIN95_LOOK
)
3417 if((item
->wID
== SC_CLOSE
) && (oldflags
!= wFlags
))
3419 if (menu
->hSysMenuOwner
!= 0)
3421 POPUPMENU
* parentMenu
;
3423 /* Get the parent menu to access*/
3424 if (!(parentMenu
= MENU_GetMenu(menu
->hSysMenuOwner
)))
3427 /* Refresh the frame to reflect the change*/
3428 SetWindowPos(parentMenu
->hWnd
, 0, 0, 0, 0, 0,
3429 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
3437 /*******************************************************************
3438 * GetMenuString16 (USER.161)
3440 INT16 WINAPI
GetMenuString16( HMENU16 hMenu
, UINT16 wItemID
,
3441 LPSTR str
, INT16 nMaxSiz
, UINT16 wFlags
)
3443 return GetMenuStringA( hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3447 /*******************************************************************
3448 * GetMenuStringA (USER32.@)
3450 INT WINAPI
GetMenuStringA(
3451 HMENU hMenu
, /* [in] menuhandle */
3452 UINT wItemID
, /* [in] menu item (dep. on wFlags) */
3453 LPSTR str
, /* [out] outbuffer. If NULL, func returns entry length*/
3454 INT nMaxSiz
, /* [in] length of buffer. if 0, func returns entry len*/
3455 UINT wFlags
/* [in] MF_ flags */
3459 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3460 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3461 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3462 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3463 if (!str
|| !nMaxSiz
) return strlenW(item
->text
);
3465 if (!WideCharToMultiByte( CP_ACP
, 0, item
->text
, -1, str
, nMaxSiz
, NULL
, NULL
))
3467 TRACE("returning '%s'\n", str
);
3472 /*******************************************************************
3473 * GetMenuStringW (USER32.@)
3475 INT WINAPI
GetMenuStringW( HMENU hMenu
, UINT wItemID
,
3476 LPWSTR str
, INT nMaxSiz
, UINT wFlags
)
3480 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3481 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
3482 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
3483 if (!IS_STRING_ITEM(item
->fType
)) return 0;
3484 if (!str
|| !nMaxSiz
) return strlenW(item
->text
);
3486 lstrcpynW( str
, item
->text
, nMaxSiz
);
3487 return strlenW(str
);
3491 /**********************************************************************
3492 * HiliteMenuItem16 (USER.162)
3494 BOOL16 WINAPI
HiliteMenuItem16( HWND16 hWnd
, HMENU16 hMenu
, UINT16 wItemID
,
3497 return HiliteMenuItem( hWnd
, hMenu
, wItemID
, wHilite
);
3501 /**********************************************************************
3502 * HiliteMenuItem (USER32.@)
3504 BOOL WINAPI
HiliteMenuItem( HWND hWnd
, HMENU hMenu
, UINT wItemID
,
3508 TRACE("(%04x, %04x, %04x, %04x);\n",
3509 hWnd
, hMenu
, wItemID
, wHilite
);
3510 if (!MENU_FindItem( &hMenu
, &wItemID
, wHilite
)) return FALSE
;
3511 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3512 if (menu
->FocusedItem
== wItemID
) return TRUE
;
3513 MENU_HideSubPopups( hWnd
, hMenu
, FALSE
);
3514 MENU_SelectItem( hWnd
, hMenu
, wItemID
, TRUE
, 0 );
3519 /**********************************************************************
3520 * GetMenuState16 (USER.250)
3522 UINT16 WINAPI
GetMenuState16( HMENU16 hMenu
, UINT16 wItemID
, UINT16 wFlags
)
3524 return GetMenuState( hMenu
, wItemID
, wFlags
);
3528 /**********************************************************************
3529 * GetMenuState (USER32.@)
3531 UINT WINAPI
GetMenuState( HMENU hMenu
, UINT wItemID
, UINT wFlags
)
3534 TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
3535 hMenu
, wItemID
, wFlags
);
3536 if (!(item
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
3537 debug_print_menuitem (" item: ", item
, "");
3538 if (item
->fType
& MF_POPUP
)
3540 POPUPMENU
*menu
= MENU_GetMenu( item
->hSubMenu
);
3541 if (!menu
) return -1;
3542 else return (menu
->nItems
<< 8) | ((item
->fState
|item
->fType
) & 0xff);
3546 /* We used to (from way back then) mask the result to 0xff. */
3547 /* I don't know why and it seems wrong as the documented */
3548 /* return flag MF_SEPARATOR is outside that mask. */
3549 return (item
->fType
| item
->fState
);
3554 /**********************************************************************
3555 * GetMenuItemCount16 (USER.263)
3557 INT16 WINAPI
GetMenuItemCount16( HMENU16 hMenu
)
3559 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3560 if (!menu
) return -1;
3561 TRACE("(%04x) returning %d\n",
3562 hMenu
, menu
->nItems
);
3563 return menu
->nItems
;
3567 /**********************************************************************
3568 * GetMenuItemCount (USER32.@)
3570 INT WINAPI
GetMenuItemCount( HMENU hMenu
)
3572 LPPOPUPMENU menu
= MENU_GetMenu(hMenu
);
3573 if (!menu
) return -1;
3574 TRACE("(%04x) returning %d\n",
3575 hMenu
, menu
->nItems
);
3576 return menu
->nItems
;
3579 /**********************************************************************
3580 * GetMenuItemID16 (USER.264)
3582 UINT16 WINAPI
GetMenuItemID16( HMENU16 hMenu
, INT16 nPos
)
3584 return (UINT16
) GetMenuItemID (hMenu
, nPos
);
3587 /**********************************************************************
3588 * GetMenuItemID (USER32.@)
3590 UINT WINAPI
GetMenuItemID( HMENU hMenu
, INT nPos
)
3594 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return 0;
3595 if (lpmi
->fType
& MF_POPUP
) return -1;
3600 /*******************************************************************
3601 * InsertMenu16 (USER.410)
3603 BOOL16 WINAPI
InsertMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3604 UINT16 id
, SEGPTR data
)
3606 UINT pos32
= (UINT
)pos
;
3607 if ((pos
== (UINT16
)-1) && (flags
& MF_BYPOSITION
)) pos32
= (UINT
)-1;
3608 if (IS_STRING_ITEM(flags
) && data
)
3609 return InsertMenuA( hMenu
, pos32
, flags
, id
, MapSL(data
) );
3610 return InsertMenuA( hMenu
, pos32
, flags
, id
, (LPSTR
)data
);
3614 /*******************************************************************
3615 * InsertMenuW (USER32.@)
3617 BOOL WINAPI
InsertMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3618 UINT id
, LPCWSTR str
)
3622 if (IS_STRING_ITEM(flags
) && str
)
3623 TRACE("hMenu %04x, pos %d, flags %08x, "
3624 "id %04x, str '%s'\n",
3625 hMenu
, pos
, flags
, id
, debugstr_w(str
) );
3626 else TRACE("hMenu %04x, pos %d, flags %08x, "
3627 "id %04x, str %08lx (not a string)\n",
3628 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3630 if (!(item
= MENU_InsertItem( hMenu
, pos
, flags
))) return FALSE
;
3632 if (!(MENU_SetItemData( item
, flags
, id
, str
)))
3634 RemoveMenu( hMenu
, pos
, flags
);
3638 if (flags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
3639 (MENU_GetMenu((HMENU16
)id
))->wFlags
|= MF_POPUP
;
3641 item
->hCheckBit
= item
->hUnCheckBit
= 0;
3646 /*******************************************************************
3647 * InsertMenuA (USER32.@)
3649 BOOL WINAPI
InsertMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3650 UINT id
, LPCSTR str
)
3654 if (IS_STRING_ITEM(flags
) && str
)
3656 LPWSTR newstr
= HEAP_strdupAtoW( GetProcessHeap(), 0, str
);
3657 ret
= InsertMenuW( hMenu
, pos
, flags
, id
, newstr
);
3658 HeapFree( GetProcessHeap(), 0, newstr
);
3661 else return InsertMenuW( hMenu
, pos
, flags
, id
, (LPCWSTR
)str
);
3665 /*******************************************************************
3666 * AppendMenu16 (USER.411)
3668 BOOL16 WINAPI
AppendMenu16(HMENU16 hMenu
, UINT16 flags
, UINT16 id
, SEGPTR data
)
3670 return InsertMenu16( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3674 /*******************************************************************
3675 * AppendMenuA (USER32.@)
3677 BOOL WINAPI
AppendMenuA( HMENU hMenu
, UINT flags
,
3678 UINT id
, LPCSTR data
)
3680 return InsertMenuA( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3684 /*******************************************************************
3685 * AppendMenuW (USER32.@)
3687 BOOL WINAPI
AppendMenuW( HMENU hMenu
, UINT flags
,
3688 UINT id
, LPCWSTR data
)
3690 return InsertMenuW( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
3694 /**********************************************************************
3695 * RemoveMenu16 (USER.412)
3697 BOOL16 WINAPI
RemoveMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3699 return RemoveMenu( hMenu
, nPos
, wFlags
);
3703 /**********************************************************************
3704 * RemoveMenu (USER32.@)
3706 BOOL WINAPI
RemoveMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3711 TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu
, nPos
, wFlags
);
3712 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3713 if (!(menu
= MENU_GetMenu(hMenu
))) return FALSE
;
3717 MENU_FreeItemData( item
);
3719 if (--menu
->nItems
== 0)
3721 HeapFree( SystemHeap
, 0, menu
->items
);
3726 while(nPos
< menu
->nItems
)
3732 menu
->items
= HeapReAlloc( SystemHeap
, 0, menu
->items
,
3733 menu
->nItems
* sizeof(MENUITEM
) );
3739 /**********************************************************************
3740 * DeleteMenu16 (USER.413)
3742 BOOL16 WINAPI
DeleteMenu16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
)
3744 return DeleteMenu( hMenu
, nPos
, wFlags
);
3748 /**********************************************************************
3749 * DeleteMenu (USER32.@)
3751 BOOL WINAPI
DeleteMenu( HMENU hMenu
, UINT nPos
, UINT wFlags
)
3753 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
3754 if (!item
) return FALSE
;
3755 if (item
->fType
& MF_POPUP
) DestroyMenu( item
->hSubMenu
);
3756 /* nPos is now the position of the item */
3757 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
3762 /*******************************************************************
3763 * ModifyMenu16 (USER.414)
3765 BOOL16 WINAPI
ModifyMenu16( HMENU16 hMenu
, UINT16 pos
, UINT16 flags
,
3766 UINT16 id
, SEGPTR data
)
3768 if (IS_STRING_ITEM(flags
))
3769 return ModifyMenuA( hMenu
, pos
, flags
, id
, MapSL(data
) );
3770 return ModifyMenuA( hMenu
, pos
, flags
, id
, (LPSTR
)data
);
3774 /*******************************************************************
3775 * ModifyMenuW (USER32.@)
3777 BOOL WINAPI
ModifyMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
3778 UINT id
, LPCWSTR str
)
3782 if (IS_STRING_ITEM(flags
))
3784 TRACE("%04x %d %04x %04x '%s'\n",
3785 hMenu
, pos
, flags
, id
, str
? debugstr_w(str
) : "#NULL#" );
3786 if (!str
) return FALSE
;
3790 TRACE("%04x %d %04x %04x %08lx\n",
3791 hMenu
, pos
, flags
, id
, (DWORD
)str
);
3794 if (!(item
= MENU_FindItem( &hMenu
, &pos
, flags
))) return FALSE
;
3795 return MENU_SetItemData( item
, flags
, id
, str
);
3799 /*******************************************************************
3800 * ModifyMenuA (USER32.@)
3802 BOOL WINAPI
ModifyMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
3803 UINT id
, LPCSTR str
)
3807 if (IS_STRING_ITEM(flags
) && str
)
3809 LPWSTR newstr
= HEAP_strdupAtoW( GetProcessHeap(), 0, str
);
3810 ret
= ModifyMenuW( hMenu
, pos
, flags
, id
, newstr
);
3811 HeapFree( GetProcessHeap(), 0, newstr
);
3814 else return ModifyMenuW( hMenu
, pos
, flags
, id
, (LPCWSTR
)str
);
3818 /**********************************************************************
3819 * CreatePopupMenu16 (USER.415)
3821 HMENU16 WINAPI
CreatePopupMenu16(void)
3823 return CreatePopupMenu();
3827 /**********************************************************************
3828 * CreatePopupMenu (USER32.@)
3830 HMENU WINAPI
CreatePopupMenu(void)
3835 if (!(hmenu
= CreateMenu())) return 0;
3836 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
3837 menu
->wFlags
|= MF_POPUP
;
3838 menu
->bTimeToHide
= FALSE
;
3843 /**********************************************************************
3844 * GetMenuCheckMarkDimensions (USER.417) (USER32.@)
3846 DWORD WINAPI
GetMenuCheckMarkDimensions(void)
3848 return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK
), GetSystemMetrics(SM_CYMENUCHECK
) );
3852 /**********************************************************************
3853 * SetMenuItemBitmaps16 (USER.418)
3855 BOOL16 WINAPI
SetMenuItemBitmaps16( HMENU16 hMenu
, UINT16 nPos
, UINT16 wFlags
,
3856 HBITMAP16 hNewUnCheck
, HBITMAP16 hNewCheck
)
3858 return SetMenuItemBitmaps( hMenu
, nPos
, wFlags
, hNewUnCheck
, hNewCheck
);
3862 /**********************************************************************
3863 * SetMenuItemBitmaps (USER32.@)
3865 BOOL WINAPI
SetMenuItemBitmaps( HMENU hMenu
, UINT nPos
, UINT wFlags
,
3866 HBITMAP hNewUnCheck
, HBITMAP hNewCheck
)
3869 TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3870 hMenu
, nPos
, wFlags
, hNewCheck
, hNewUnCheck
);
3871 if (!(item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
3873 if (!hNewCheck
&& !hNewUnCheck
)
3875 item
->fState
&= ~MF_USECHECKBITMAPS
;
3877 else /* Install new bitmaps */
3879 item
->hCheckBit
= hNewCheck
;
3880 item
->hUnCheckBit
= hNewUnCheck
;
3881 item
->fState
|= MF_USECHECKBITMAPS
;
3887 /**********************************************************************
3888 * CreateMenu16 (USER.151)
3890 HMENU16 WINAPI
CreateMenu16(void)
3892 return CreateMenu();
3896 /**********************************************************************
3897 * CreateMenu (USER32.@)
3899 HMENU WINAPI
CreateMenu(void)
3903 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) ))) return 0;
3904 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3906 ZeroMemory(menu
, sizeof(POPUPMENU
));
3907 menu
->wMagic
= MENU_MAGIC
;
3908 menu
->FocusedItem
= NO_SELECTED_ITEM
;
3909 menu
->bTimeToHide
= FALSE
;
3911 TRACE("return %04x\n", hMenu
);
3917 /**********************************************************************
3918 * DestroyMenu16 (USER.152)
3920 BOOL16 WINAPI
DestroyMenu16( HMENU16 hMenu
)
3922 return DestroyMenu( hMenu
);
3926 /**********************************************************************
3927 * DestroyMenu (USER32.@)
3929 BOOL WINAPI
DestroyMenu( HMENU hMenu
)
3931 TRACE("(%04x)\n", hMenu
);
3933 /* Silently ignore attempts to destroy default system popup */
3935 if (hMenu
&& hMenu
!= MENU_DefSysPopup
)
3937 LPPOPUPMENU lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
3938 WND
*pTPWnd
= MENU_GetTopPopupWnd();
3940 if( pTPWnd
&& (hMenu
== *(HMENU
*)pTPWnd
->wExtra
) )
3941 *(UINT
*)pTPWnd
->wExtra
= 0;
3943 if (!IS_A_MENU(lppop
)) lppop
= NULL
;
3946 lppop
->wMagic
= 0; /* Mark it as destroyed */
3948 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
&&
3949 (!pTPWnd
|| (lppop
->hWnd
!= pTPWnd
->hwndSelf
)))
3950 DestroyWindow( lppop
->hWnd
);
3952 if (lppop
->items
) /* recursively destroy submenus */
3955 MENUITEM
*item
= lppop
->items
;
3956 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
3958 if (item
->fType
& MF_POPUP
) DestroyMenu(item
->hSubMenu
);
3959 MENU_FreeItemData( item
);
3961 HeapFree( SystemHeap
, 0, lppop
->items
);
3963 USER_HEAP_FREE( hMenu
);
3964 MENU_ReleaseTopPopupWnd();
3968 MENU_ReleaseTopPopupWnd();
3972 return (hMenu
!= MENU_DefSysPopup
);
3976 /**********************************************************************
3977 * GetSystemMenu16 (USER.156)
3979 HMENU16 WINAPI
GetSystemMenu16( HWND16 hWnd
, BOOL16 bRevert
)
3981 return GetSystemMenu( hWnd
, bRevert
);
3985 /**********************************************************************
3986 * GetSystemMenu (USER32.@)
3988 HMENU WINAPI
GetSystemMenu( HWND hWnd
, BOOL bRevert
)
3990 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
3995 if( wndPtr
->hSysMenu
)
3999 DestroyMenu(wndPtr
->hSysMenu
);
4000 wndPtr
->hSysMenu
= 0;
4004 POPUPMENU
*menu
= MENU_GetMenu( wndPtr
->hSysMenu
);
4007 if( menu
->nItems
> 0 && menu
->items
[0].hSubMenu
== MENU_DefSysPopup
)
4008 menu
->items
[0].hSubMenu
= MENU_CopySysPopup();
4012 WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
4013 wndPtr
->hSysMenu
, hWnd
);
4014 wndPtr
->hSysMenu
= 0;
4019 if(!wndPtr
->hSysMenu
&& (wndPtr
->dwStyle
& WS_SYSMENU
) )
4020 wndPtr
->hSysMenu
= MENU_GetSysMenu( hWnd
, (HMENU
)(-1) );
4022 if( wndPtr
->hSysMenu
)
4025 retvalue
= GetSubMenu16(wndPtr
->hSysMenu
, 0);
4027 /* Store the dummy sysmenu handle to facilitate the refresh */
4028 /* of the close button if the SC_CLOSE item change */
4029 menu
= MENU_GetMenu(retvalue
);
4031 menu
->hSysMenuOwner
= wndPtr
->hSysMenu
;
4033 WIN_ReleaseWndPtr(wndPtr
);
4035 return bRevert
? 0 : retvalue
;
4039 /*******************************************************************
4040 * SetSystemMenu16 (USER.280)
4042 BOOL16 WINAPI
SetSystemMenu16( HWND16 hwnd
, HMENU16 hMenu
)
4044 return SetSystemMenu( hwnd
, hMenu
);
4048 /*******************************************************************
4049 * SetSystemMenu (USER32.@)
4051 BOOL WINAPI
SetSystemMenu( HWND hwnd
, HMENU hMenu
)
4053 WND
*wndPtr
= WIN_FindWndPtr(hwnd
);
4057 if (wndPtr
->hSysMenu
) DestroyMenu( wndPtr
->hSysMenu
);
4058 wndPtr
->hSysMenu
= MENU_GetSysMenu( hwnd
, hMenu
);
4059 WIN_ReleaseWndPtr(wndPtr
);
4066 /**********************************************************************
4067 * GetMenu16 (USER.157)
4069 HMENU16 WINAPI
GetMenu16( HWND16 hWnd
)
4071 return (HMENU16
)GetMenu(hWnd
);
4075 /**********************************************************************
4076 * GetMenu (USER32.@)
4078 HMENU WINAPI
GetMenu( HWND hWnd
)
4081 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
4083 if (!wndPtr
) return 0;
4085 retvalue
= (HMENU
)wndPtr
->wIDmenu
;
4086 TRACE("for %swindow %04x returning %04x\n",
4087 (wndPtr
->dwStyle
& WS_CHILD
) ? "child " : "", hWnd
, retvalue
);
4088 WIN_ReleaseWndPtr(wndPtr
);
4093 /**********************************************************************
4094 * SetMenu16 (USER.158)
4096 BOOL16 WINAPI
SetMenu16( HWND16 hWnd
, HMENU16 hMenu
)
4098 return SetMenu( hWnd
, hMenu
);
4102 /**********************************************************************
4103 * SetMenu (USER32.@)
4105 BOOL WINAPI
SetMenu( HWND hWnd
, HMENU hMenu
)
4107 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
4110 TRACE("(%04x, %04x);\n", hWnd
, hMenu
);
4112 if (hMenu
&& !IsMenu(hMenu
))
4114 WARN("hMenu is not a menu handle\n");
4118 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
))
4120 if (GetCapture() == hWnd
) ReleaseCapture();
4122 wndPtr
->wIDmenu
= (UINT
)hMenu
;
4127 if (!(lpmenu
= MENU_GetMenu(hMenu
)))
4130 lpmenu
->hWnd
= hWnd
;
4131 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
4133 if (IsWindowVisible(hWnd
))
4134 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4135 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4139 WIN_ReleaseWndPtr(wndPtr
);
4145 /**********************************************************************
4146 * GetSubMenu16 (USER.159)
4148 HMENU16 WINAPI
GetSubMenu16( HMENU16 hMenu
, INT16 nPos
)
4150 return GetSubMenu( hMenu
, nPos
);
4154 /**********************************************************************
4155 * GetSubMenu (USER32.@)
4157 HMENU WINAPI
GetSubMenu( HMENU hMenu
, INT nPos
)
4161 if (!(lpmi
= MENU_FindItem(&hMenu
,&nPos
,MF_BYPOSITION
))) return 0;
4162 if (!(lpmi
->fType
& MF_POPUP
)) return 0;
4163 return lpmi
->hSubMenu
;
4167 /**********************************************************************
4168 * DrawMenuBar16 (USER.160)
4170 void WINAPI
DrawMenuBar16( HWND16 hWnd
)
4172 DrawMenuBar( hWnd
);
4176 /**********************************************************************
4177 * DrawMenuBar (USER32.@)
4179 BOOL WINAPI
DrawMenuBar( HWND hWnd
)
4182 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
4183 if (wndPtr
&& !(wndPtr
->dwStyle
& WS_CHILD
) && wndPtr
->wIDmenu
)
4185 lppop
= MENU_GetMenu((HMENU16
)wndPtr
->wIDmenu
);
4188 WIN_ReleaseWndPtr(wndPtr
);
4192 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
4193 lppop
->hwndOwner
= hWnd
;
4194 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
4195 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
4196 WIN_ReleaseWndPtr(wndPtr
);
4199 WIN_ReleaseWndPtr(wndPtr
);
4204 /***********************************************************************
4205 * EndMenu (USER.187) (USER32.@)
4207 void WINAPI
EndMenu(void)
4209 /* if we are in the menu code, and it is active */
4210 if (fEndMenu
== FALSE
&& MENU_IsMenuActive())
4212 /* terminate the menu handling code */
4215 /* needs to be posted to wakeup the internal menu handler */
4216 /* which will now terminate the menu, in the event that */
4217 /* the main window was minimized, or lost focus, so we */
4218 /* don't end up with an orphaned menu */
4219 PostMessageA( pTopPopupWnd
->hwndSelf
, WM_CANCELMODE
, 0, 0);
4224 /***********************************************************************
4225 * LookupMenuHandle (USER.217)
4227 HMENU16 WINAPI
LookupMenuHandle16( HMENU16 hmenu
, INT16 id
)
4229 HMENU hmenu32
= hmenu
;
4231 if (!MENU_FindItem( &hmenu32
, &id32
, MF_BYCOMMAND
)) return 0;
4232 else return hmenu32
;
4236 /**********************************************************************
4237 * LoadMenu16 (USER.150)
4239 HMENU16 WINAPI
LoadMenu16( HINSTANCE16 instance
, LPCSTR name
)
4245 TRACE("(%04x,%s)\n", instance
, debugres_a(name
) );
4249 if (name
[0] == '#') name
= (LPCSTR
)atoi( name
+ 1 );
4252 if (!name
) return 0;
4254 /* check for Win32 module */
4255 if (HIWORD(instance
)) return LoadMenuA( instance
, name
);
4256 instance
= GetExePtr( instance
);
4258 if (!(hRsrc
= FindResource16( instance
, name
, RT_MENUA
))) return 0;
4259 if (!(handle
= LoadResource16( instance
, hRsrc
))) return 0;
4260 hMenu
= LoadMenuIndirect16(LockResource16(handle
));
4261 FreeResource16( handle
);
4266 /*****************************************************************
4267 * LoadMenuA (USER32.@)
4269 HMENU WINAPI
LoadMenuA( HINSTANCE instance
, LPCSTR name
)
4271 HRSRC hrsrc
= FindResourceA( instance
, name
, RT_MENUA
);
4272 if (!hrsrc
) return 0;
4273 return LoadMenuIndirectA( (LPCVOID
)LoadResource( instance
, hrsrc
));
4277 /*****************************************************************
4278 * LoadMenuW (USER32.@)
4280 HMENU WINAPI
LoadMenuW( HINSTANCE instance
, LPCWSTR name
)
4282 HRSRC hrsrc
= FindResourceW( instance
, name
, RT_MENUW
);
4283 if (!hrsrc
) return 0;
4284 return LoadMenuIndirectW( (LPCVOID
)LoadResource( instance
, hrsrc
));
4288 /**********************************************************************
4289 * LoadMenuIndirect16 (USER.220)
4291 HMENU16 WINAPI
LoadMenuIndirect16( LPCVOID
template )
4294 WORD version
, offset
;
4295 LPCSTR p
= (LPCSTR
)template;
4297 TRACE("(%p)\n", template );
4298 version
= GET_WORD(p
);
4302 WARN("version must be 0 for Win16\n" );
4305 offset
= GET_WORD(p
);
4306 p
+= sizeof(WORD
) + offset
;
4307 if (!(hMenu
= CreateMenu())) return 0;
4308 if (!MENU_ParseResource( p
, hMenu
, FALSE
))
4310 DestroyMenu( hMenu
);
4317 /**********************************************************************
4318 * LoadMenuIndirectA (USER32.@)
4320 HMENU WINAPI
LoadMenuIndirectA( LPCVOID
template )
4323 WORD version
, offset
;
4324 LPCSTR p
= (LPCSTR
)template;
4326 TRACE("%p\n", template );
4327 version
= GET_WORD(p
);
4332 offset
= GET_WORD(p
);
4333 p
+= sizeof(WORD
) + offset
;
4334 if (!(hMenu
= CreateMenu())) return 0;
4335 if (!MENU_ParseResource( p
, hMenu
, TRUE
))
4337 DestroyMenu( hMenu
);
4342 offset
= GET_WORD(p
);
4343 p
+= sizeof(WORD
) + offset
;
4344 if (!(hMenu
= CreateMenu())) return 0;
4345 if (!MENUEX_ParseResource( p
, hMenu
))
4347 DestroyMenu( hMenu
);
4352 ERR("version %d not supported.\n", version
);
4358 /**********************************************************************
4359 * LoadMenuIndirectW (USER32.@)
4361 HMENU WINAPI
LoadMenuIndirectW( LPCVOID
template )
4363 /* FIXME: is there anything different between A and W? */
4364 return LoadMenuIndirectA( template );
4368 /**********************************************************************
4369 * IsMenu16 (USER.358)
4371 BOOL16 WINAPI
IsMenu16( HMENU16 hmenu
)
4373 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
4374 return IS_A_MENU(menu
);
4378 /**********************************************************************
4381 BOOL WINAPI
IsMenu(HMENU hmenu
)
4383 LPPOPUPMENU menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hmenu
);
4384 return IS_A_MENU(menu
);
4387 /**********************************************************************
4388 * GetMenuItemInfo_common
4391 static BOOL
GetMenuItemInfo_common ( HMENU hmenu
, UINT item
, BOOL bypos
,
4392 LPMENUITEMINFOW lpmii
, BOOL unicode
)
4394 MENUITEM
*menu
= MENU_FindItem (&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0);
4396 debug_print_menuitem("GetMenuItemInfo_common: ", menu
, "");
4401 if (lpmii
->fMask
& MIIM_TYPE
) {
4402 lpmii
->fType
= menu
->fType
;
4403 switch (MENU_ITEM_TYPE(menu
->fType
)) {
4405 break; /* will be done below */
4408 lpmii
->dwTypeData
= menu
->text
;
4415 /* copy the text string */
4416 if ((lpmii
->fMask
& (MIIM_TYPE
|MIIM_STRING
)) &&
4417 (MENU_ITEM_TYPE(menu
->fType
) == MF_STRING
) && menu
->text
)
4422 len
= strlenW(menu
->text
);
4423 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4424 lstrcpynW(lpmii
->dwTypeData
, menu
->text
, lpmii
->cch
);
4428 len
= WideCharToMultiByte( CP_ACP
, 0, menu
->text
, -1, NULL
, 0, NULL
, NULL
);
4429 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4430 if (!WideCharToMultiByte( CP_ACP
, 0, menu
->text
, -1,
4431 (LPSTR
)lpmii
->dwTypeData
, lpmii
->cch
, NULL
, NULL
))
4432 ((LPSTR
)lpmii
->dwTypeData
)[lpmii
->cch
-1] = 0;
4434 /* if we've copied a substring we return its length */
4435 if(lpmii
->dwTypeData
&& lpmii
->cch
)
4437 if (lpmii
->cch
<= len
) lpmii
->cch
--;
4439 else /* return length of string */
4443 if (lpmii
->fMask
& MIIM_FTYPE
)
4444 lpmii
->fType
= menu
->fType
;
4446 if (lpmii
->fMask
& MIIM_BITMAP
)
4447 lpmii
->hbmpItem
= menu
->hbmpItem
;
4449 if (lpmii
->fMask
& MIIM_STATE
)
4450 lpmii
->fState
= menu
->fState
;
4452 if (lpmii
->fMask
& MIIM_ID
)
4453 lpmii
->wID
= menu
->wID
;
4455 if (lpmii
->fMask
& MIIM_SUBMENU
)
4456 lpmii
->hSubMenu
= menu
->hSubMenu
;
4458 if (lpmii
->fMask
& MIIM_CHECKMARKS
) {
4459 lpmii
->hbmpChecked
= menu
->hCheckBit
;
4460 lpmii
->hbmpUnchecked
= menu
->hUnCheckBit
;
4462 if (lpmii
->fMask
& MIIM_DATA
)
4463 lpmii
->dwItemData
= menu
->dwItemData
;
4468 /**********************************************************************
4469 * GetMenuItemInfoA (USER32.@)
4471 BOOL WINAPI
GetMenuItemInfoA( HMENU hmenu
, UINT item
, BOOL bypos
,
4472 LPMENUITEMINFOA lpmii
)
4474 return GetMenuItemInfo_common (hmenu
, item
, bypos
,
4475 (LPMENUITEMINFOW
)lpmii
, FALSE
);
4478 /**********************************************************************
4479 * GetMenuItemInfoW (USER32.@)
4481 BOOL WINAPI
GetMenuItemInfoW( HMENU hmenu
, UINT item
, BOOL bypos
,
4482 LPMENUITEMINFOW lpmii
)
4484 return GetMenuItemInfo_common (hmenu
, item
, bypos
,
4488 /**********************************************************************
4489 * SetMenuItemInfo_common
4492 static BOOL
SetMenuItemInfo_common(MENUITEM
* menu
,
4493 const MENUITEMINFOW
*lpmii
,
4496 if (!menu
) return FALSE
;
4498 if (lpmii
->fMask
& MIIM_TYPE
) {
4499 /* Get rid of old string. */
4500 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4501 HeapFree(SystemHeap
, 0, menu
->text
);
4505 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4506 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4507 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4509 menu
->text
= lpmii
->dwTypeData
;
4511 if (IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4513 menu
->text
= HEAP_strdupW(SystemHeap
, 0, lpmii
->dwTypeData
);
4515 menu
->text
= HEAP_strdupAtoW(SystemHeap
, 0, (LPSTR
)lpmii
->dwTypeData
);
4519 if (lpmii
->fMask
& MIIM_FTYPE
) {
4520 /* free the string when the type is changing */
4521 if ( (!IS_STRING_ITEM(lpmii
->fType
)) && IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4522 HeapFree(SystemHeap
, 0, menu
->text
);
4525 menu
->fType
&= ~MENU_ITEM_TYPE(menu
->fType
);
4526 menu
->fType
|= MENU_ITEM_TYPE(lpmii
->fType
);
4529 if (lpmii
->fMask
& MIIM_STRING
) {
4530 /* free the string when used */
4531 if ( IS_STRING_ITEM(menu
->fType
) && menu
->text
) {
4532 HeapFree(SystemHeap
, 0, menu
->text
);
4534 menu
->text
= HEAP_strdupW(SystemHeap
, 0, lpmii
->dwTypeData
);
4536 menu
->text
= HEAP_strdupAtoW(SystemHeap
, 0, (LPSTR
) lpmii
->dwTypeData
);
4540 if (lpmii
->fMask
& MIIM_STATE
)
4542 /* fixme: MFS_DEFAULT do we have to reset the other menu items? */
4543 menu
->fState
= lpmii
->fState
;
4546 if (lpmii
->fMask
& MIIM_ID
)
4547 menu
->wID
= lpmii
->wID
;
4549 if (lpmii
->fMask
& MIIM_SUBMENU
) {
4550 menu
->hSubMenu
= lpmii
->hSubMenu
;
4551 if (menu
->hSubMenu
) {
4552 POPUPMENU
*subMenu
= MENU_GetMenu((UINT16
)menu
->hSubMenu
);
4554 subMenu
->wFlags
|= MF_POPUP
;
4555 menu
->fType
|= MF_POPUP
;
4558 /* FIXME: Return an error ? */
4559 menu
->fType
&= ~MF_POPUP
;
4562 menu
->fType
&= ~MF_POPUP
;
4565 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
4567 if (lpmii
->fType
& MFT_RADIOCHECK
)
4568 menu
->fType
|= MFT_RADIOCHECK
;
4570 menu
->hCheckBit
= lpmii
->hbmpChecked
;
4571 menu
->hUnCheckBit
= lpmii
->hbmpUnchecked
;
4573 if (lpmii
->fMask
& MIIM_DATA
)
4574 menu
->dwItemData
= lpmii
->dwItemData
;
4576 debug_print_menuitem("SetMenuItemInfo_common: ", menu
, "");
4580 /**********************************************************************
4581 * SetMenuItemInfoA (USER32.@)
4583 BOOL WINAPI
SetMenuItemInfoA(HMENU hmenu
, UINT item
, BOOL bypos
,
4584 const MENUITEMINFOA
*lpmii
)
4586 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4587 (const MENUITEMINFOW
*)lpmii
, FALSE
);
4590 /**********************************************************************
4591 * SetMenuItemInfoW (USER32.@)
4593 BOOL WINAPI
SetMenuItemInfoW(HMENU hmenu
, UINT item
, BOOL bypos
,
4594 const MENUITEMINFOW
*lpmii
)
4596 return SetMenuItemInfo_common(MENU_FindItem(&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0),
4600 /**********************************************************************
4601 * SetMenuDefaultItem (USER32.@)
4604 BOOL WINAPI
SetMenuDefaultItem(HMENU hmenu
, UINT uItem
, UINT bypos
)
4610 TRACE("(0x%x,%d,%d)\n", hmenu
, uItem
, bypos
);
4612 if (!(menu
= MENU_GetMenu(hmenu
))) return FALSE
;
4614 /* reset all default-item flags */
4616 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4618 item
->fState
&= ~MFS_DEFAULT
;
4621 /* no default item */
4630 if ( uItem
>= menu
->nItems
) return FALSE
;
4631 item
[uItem
].fState
|= MFS_DEFAULT
;
4636 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
4638 if (item
->wID
== uItem
)
4640 item
->fState
|= MFS_DEFAULT
;
4649 /**********************************************************************
4650 * GetMenuDefaultItem (USER32.@)
4652 UINT WINAPI
GetMenuDefaultItem(HMENU hmenu
, UINT bypos
, UINT flags
)
4658 TRACE("(0x%x,%d,%d)\n", hmenu
, bypos
, flags
);
4660 if (!(menu
= MENU_GetMenu(hmenu
))) return -1;
4662 /* find default item */
4666 if (! item
) return -1;
4668 while ( !( item
->fState
& MFS_DEFAULT
) )
4671 if (i
>= menu
->nItems
) return -1;
4674 /* default: don't return disabled items */
4675 if ( (!(GMDI_USEDISABLED
& flags
)) && (item
->fState
& MFS_DISABLED
)) return -1;
4677 /* search rekursiv when needed */
4678 if ( (item
->fType
& MF_POPUP
) && (flags
& GMDI_GOINTOPOPUPS
) )
4681 ret
= GetMenuDefaultItem( item
->hSubMenu
, bypos
, flags
);
4682 if ( -1 != ret
) return ret
;
4684 /* when item not found in submenu, return the popup item */
4686 return ( bypos
) ? i
: item
->wID
;
4690 /*******************************************************************
4691 * InsertMenuItem16 (USER.441)
4695 BOOL16 WINAPI
InsertMenuItem16( HMENU16 hmenu
, UINT16 pos
, BOOL16 byposition
,
4696 const MENUITEMINFO16
*mii
)
4700 miia
.cbSize
= sizeof(miia
);
4701 miia
.fMask
= mii
->fMask
;
4702 miia
.dwTypeData
= (LPSTR
)mii
->dwTypeData
;
4703 miia
.fType
= mii
->fType
;
4704 miia
.fState
= mii
->fState
;
4705 miia
.wID
= mii
->wID
;
4706 miia
.hSubMenu
= mii
->hSubMenu
;
4707 miia
.hbmpChecked
= mii
->hbmpChecked
;
4708 miia
.hbmpUnchecked
= mii
->hbmpUnchecked
;
4709 miia
.dwItemData
= mii
->dwItemData
;
4710 miia
.cch
= mii
->cch
;
4711 if (IS_STRING_ITEM(miia
.fType
))
4712 miia
.dwTypeData
= MapSL(mii
->dwTypeData
);
4713 return InsertMenuItemA( hmenu
, pos
, byposition
, &miia
);
4717 /**********************************************************************
4718 * InsertMenuItemA (USER32.@)
4720 BOOL WINAPI
InsertMenuItemA(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4721 const MENUITEMINFOA
*lpmii
)
4723 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4724 return SetMenuItemInfo_common(item
, (const MENUITEMINFOW
*)lpmii
, FALSE
);
4728 /**********************************************************************
4729 * InsertMenuItemW (USER32.@)
4731 BOOL WINAPI
InsertMenuItemW(HMENU hMenu
, UINT uItem
, BOOL bypos
,
4732 const MENUITEMINFOW
*lpmii
)
4734 MENUITEM
*item
= MENU_InsertItem(hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0 );
4735 return SetMenuItemInfo_common(item
, lpmii
, TRUE
);
4738 /**********************************************************************
4739 * CheckMenuRadioItem (USER32.@)
4742 BOOL WINAPI
CheckMenuRadioItem(HMENU hMenu
,
4743 UINT first
, UINT last
, UINT check
,
4746 MENUITEM
*mifirst
, *milast
, *micheck
;
4747 HMENU mfirst
= hMenu
, mlast
= hMenu
, mcheck
= hMenu
;
4749 TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4750 hMenu
, first
, last
, check
, bypos
);
4752 mifirst
= MENU_FindItem (&mfirst
, &first
, bypos
);
4753 milast
= MENU_FindItem (&mlast
, &last
, bypos
);
4754 micheck
= MENU_FindItem (&mcheck
, &check
, bypos
);
4756 if (mifirst
== NULL
|| milast
== NULL
|| micheck
== NULL
||
4757 mifirst
> milast
|| mfirst
!= mlast
|| mfirst
!= mcheck
||
4758 micheck
> milast
|| micheck
< mifirst
)
4761 while (mifirst
<= milast
)
4763 if (mifirst
== micheck
)
4765 mifirst
->fType
|= MFT_RADIOCHECK
;
4766 mifirst
->fState
|= MFS_CHECKED
;
4768 mifirst
->fType
&= ~MFT_RADIOCHECK
;
4769 mifirst
->fState
&= ~MFS_CHECKED
;
4777 /**********************************************************************
4778 * CheckMenuRadioItem16 (not a Windows API)
4781 BOOL16 WINAPI
CheckMenuRadioItem16(HMENU16 hMenu
,
4782 UINT16 first
, UINT16 last
, UINT16 check
,
4785 return CheckMenuRadioItem (hMenu
, first
, last
, check
, bypos
);
4788 /**********************************************************************
4789 * GetMenuItemRect (USER32.@)
4791 * ATTENTION: Here, the returned values in rect are the screen
4792 * coordinates of the item just like if the menu was
4793 * always on the upper left side of the application.
4796 BOOL WINAPI
GetMenuItemRect (HWND hwnd
, HMENU hMenu
, UINT uItem
,
4799 POPUPMENU
*itemMenu
;
4803 TRACE("(0x%x,0x%x,%d,%p)\n", hwnd
, hMenu
, uItem
, rect
);
4805 item
= MENU_FindItem (&hMenu
, &uItem
, MF_BYPOSITION
);
4806 referenceHwnd
= hwnd
;
4810 itemMenu
= MENU_GetMenu(hMenu
);
4811 if (itemMenu
== NULL
)
4814 if(itemMenu
->hWnd
== 0)
4816 referenceHwnd
= itemMenu
->hWnd
;
4819 if ((rect
== NULL
) || (item
== NULL
))
4824 MapWindowPoints(referenceHwnd
, 0, (LPPOINT
)rect
, 2);
4829 /**********************************************************************
4830 * GetMenuItemRect16 (USER.665)
4833 BOOL16 WINAPI
GetMenuItemRect16 (HWND16 hwnd
, HMENU16 hMenu
, UINT16 uItem
,
4839 if (!rect
) return FALSE
;
4840 res
= GetMenuItemRect (hwnd
, hMenu
, uItem
, &r32
);
4841 CONV_RECT32TO16 (&r32
, rect
);
4845 /**********************************************************************
4846 * SetMenuInfo (USER32.@)
4849 * MIM_APPLYTOSUBMENUS
4850 * actually use the items to draw the menu
4852 BOOL WINAPI
SetMenuInfo (HMENU hMenu
, LPCMENUINFO lpmi
)
4856 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4858 if (lpmi
&& (lpmi
->cbSize
==sizeof(MENUINFO
)) && (menu
= MENU_GetMenu(hMenu
)))
4861 if (lpmi
->fMask
& MIM_BACKGROUND
)
4862 menu
->hbrBack
= lpmi
->hbrBack
;
4864 if (lpmi
->fMask
& MIM_HELPID
)
4865 menu
->dwContextHelpID
= lpmi
->dwContextHelpID
;
4867 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4868 menu
->cyMax
= lpmi
->cyMax
;
4870 if (lpmi
->fMask
& MIM_MENUDATA
)
4871 menu
->dwMenuData
= lpmi
->dwMenuData
;
4873 if (lpmi
->fMask
& MIM_STYLE
)
4874 menu
->dwStyle
= lpmi
->dwStyle
;
4881 /**********************************************************************
4882 * GetMenuInfo (USER32.@)
4888 BOOL WINAPI
GetMenuInfo (HMENU hMenu
, LPMENUINFO lpmi
)
4891 TRACE("(0x%04x %p)\n", hMenu
, lpmi
);
4893 if (lpmi
&& (menu
= MENU_GetMenu(hMenu
)))
4896 if (lpmi
->fMask
& MIM_BACKGROUND
)
4897 lpmi
->hbrBack
= menu
->hbrBack
;
4899 if (lpmi
->fMask
& MIM_HELPID
)
4900 lpmi
->dwContextHelpID
= menu
->dwContextHelpID
;
4902 if (lpmi
->fMask
& MIM_MAXHEIGHT
)
4903 lpmi
->cyMax
= menu
->cyMax
;
4905 if (lpmi
->fMask
& MIM_MENUDATA
)
4906 lpmi
->dwMenuData
= menu
->dwMenuData
;
4908 if (lpmi
->fMask
& MIM_STYLE
)
4909 lpmi
->dwStyle
= menu
->dwStyle
;
4916 /**********************************************************************
4917 * SetMenuContextHelpId16 (USER.384)
4919 BOOL16 WINAPI
SetMenuContextHelpId16( HMENU16 hMenu
, DWORD dwContextHelpID
)
4921 return SetMenuContextHelpId( hMenu
, dwContextHelpID
);
4925 /**********************************************************************
4926 * SetMenuContextHelpId (USER32.@)
4928 BOOL WINAPI
SetMenuContextHelpId( HMENU hMenu
, DWORD dwContextHelpID
)
4932 TRACE("(0x%04x 0x%08lx)\n", hMenu
, dwContextHelpID
);
4934 if ((menu
= MENU_GetMenu(hMenu
)))
4936 menu
->dwContextHelpID
= dwContextHelpID
;
4942 /**********************************************************************
4943 * GetMenuContextHelpId16 (USER.385)
4945 DWORD WINAPI
GetMenuContextHelpId16( HMENU16 hMenu
)
4947 return GetMenuContextHelpId( hMenu
);
4950 /**********************************************************************
4951 * GetMenuContextHelpId (USER32.@)
4953 DWORD WINAPI
GetMenuContextHelpId( HMENU hMenu
)
4957 TRACE("(0x%04x)\n", hMenu
);
4959 if ((menu
= MENU_GetMenu(hMenu
)))
4961 return menu
->dwContextHelpID
;
4966 /**********************************************************************
4967 * MenuItemFromPoint (USER32.@)
4969 UINT WINAPI
MenuItemFromPoint(HWND hWnd
, HMENU hMenu
, POINT ptScreen
)
4971 FIXME("(0x%04x,0x%04x,(%ld,%ld)):stub\n",
4972 hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4977 /**********************************************************************
4978 * translate_accelerator
4980 static BOOL
translate_accelerator( HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
,
4981 BYTE fVirt
, WORD key
, WORD cmd
)
4985 if (wParam
!= key
) return FALSE
;
4987 if (message
== WM_CHAR
)
4989 if ( !(fVirt
& FALT
) && !(fVirt
& FVIRTKEY
) )
4991 TRACE_(accel
)("found accel for WM_CHAR: ('%c')\n", wParam
& 0xff);
4997 if(fVirt
& FVIRTKEY
)
5000 TRACE_(accel
)("found accel for virt_key %04x (scan %04x)\n",
5001 wParam
, 0xff & HIWORD(lParam
));
5002 if(GetKeyState(VK_SHIFT
) & 0x8000) mask
|= FSHIFT
;
5003 if(GetKeyState(VK_CONTROL
) & 0x8000) mask
|= FCONTROL
;
5004 if(GetKeyState(VK_MENU
) & 0x8000) mask
|= FALT
;
5005 if(mask
== (fVirt
& (FSHIFT
| FCONTROL
| FALT
))) goto found
;
5006 TRACE_(accel
)(", but incorrect SHIFT/CTRL/ALT-state\n");
5010 if (!(lParam
& 0x01000000)) /* no special_key */
5012 if ((fVirt
& FALT
) && (lParam
& 0x20000000))
5013 { /* ^^ ALT pressed */
5014 TRACE_(accel
)("found accel for Alt-%c\n", wParam
& 0xff);
5023 if (message
== WM_KEYUP
|| message
== WM_SYSKEYUP
)
5025 else if (GetCapture())
5027 else if (!IsWindowEnabled(hWnd
))
5031 HMENU hMenu
, hSubMenu
, hSysMenu
;
5032 UINT uSysStat
= (UINT
)-1, uStat
= (UINT
)-1, nPos
;
5033 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
5035 hMenu
= (wndPtr
->dwStyle
& WS_CHILD
) ? 0 : (HMENU
)wndPtr
->wIDmenu
;
5036 hSysMenu
= wndPtr
->hSysMenu
;
5037 WIN_ReleaseWndPtr(wndPtr
);
5039 /* find menu item and ask application to initialize it */
5040 /* 1. in the system menu */
5041 hSubMenu
= hSysMenu
;
5043 if(MENU_FindItem(&hSubMenu
, &nPos
, MF_BYCOMMAND
))
5045 SendMessageA(hWnd
, WM_INITMENU
, (WPARAM
)hSysMenu
, 0L);
5046 if(hSubMenu
!= hSysMenu
)
5048 nPos
= MENU_FindSubMenu(&hSysMenu
, hSubMenu
);
5049 TRACE_(accel
)("hSysMenu = %04x, hSubMenu = %04x, nPos = %d\n", hSysMenu
, hSubMenu
, nPos
);
5050 SendMessageA(hWnd
, WM_INITMENUPOPUP
, (WPARAM
)hSubMenu
, MAKELPARAM(nPos
, TRUE
));
5052 uSysStat
= GetMenuState(GetSubMenu(hSysMenu
, 0), cmd
, MF_BYCOMMAND
);
5054 else /* 2. in the window's menu */
5058 if(MENU_FindItem(&hSubMenu
, &nPos
, MF_BYCOMMAND
))
5060 SendMessageA(hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0L);
5061 if(hSubMenu
!= hMenu
)
5063 nPos
= MENU_FindSubMenu(&hMenu
, hSubMenu
);
5064 TRACE_(accel
)("hMenu = %04x, hSubMenu = %04x, nPos = %d\n", hMenu
, hSubMenu
, nPos
);
5065 SendMessageA(hWnd
, WM_INITMENUPOPUP
, (WPARAM
)hSubMenu
, MAKELPARAM(nPos
, FALSE
));
5067 uStat
= GetMenuState(hMenu
, cmd
, MF_BYCOMMAND
);
5071 if (uSysStat
!= (UINT
)-1)
5073 if (uSysStat
& (MF_DISABLED
|MF_GRAYED
))
5080 if (uStat
!= (UINT
)-1)
5086 if (uStat
& (MF_DISABLED
|MF_GRAYED
))
5097 if( mesg
==WM_COMMAND
)
5099 TRACE_(accel
)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd
);
5100 SendMessageA(hWnd
, mesg
, 0x10000 | cmd
, 0L);
5102 else if( mesg
==WM_SYSCOMMAND
)
5104 TRACE_(accel
)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd
);
5105 SendMessageA(hWnd
, mesg
, cmd
, 0x00010000L
);
5109 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
5110 * #0: unknown (please report!)
5111 * #1: for WM_KEYUP,WM_SYSKEYUP
5112 * #2: mouse is captured
5113 * #3: window is disabled
5114 * #4: it's a disabled system menu option
5115 * #5: it's a menu option, but window is iconic
5116 * #6: it's a menu option, but disabled
5118 TRACE_(accel
)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg
);
5120 ERR_(accel
)(" unknown reason - please report!");
5125 /**********************************************************************
5126 * TranslateAccelerator (USER32.@)
5128 INT WINAPI
TranslateAccelerator( HWND hWnd
, HACCEL hAccel
, LPMSG msg
)
5131 LPACCEL16 lpAccelTbl
;
5136 WARN_(accel
)("msg null; should hang here to be win compatible\n");
5139 if (!hAccel
|| !(lpAccelTbl
= (LPACCEL16
) LockResource16(hAccel
)))
5141 WARN_(accel
)("invalid accel handle=%x\n", hAccel
);
5144 if ((msg
->message
!= WM_KEYDOWN
&&
5145 msg
->message
!= WM_KEYUP
&&
5146 msg
->message
!= WM_SYSKEYDOWN
&&
5147 msg
->message
!= WM_SYSKEYUP
&&
5148 msg
->message
!= WM_CHAR
)) return 0;
5150 TRACE_(accel
)("TranslateAccelerators hAccel=%04x, hWnd=%04x,"
5151 "msg->hwnd=%04x, msg->message=%04x, wParam=%08x, lParam=%lx\n",
5152 hAccel
,hWnd
,msg
->hwnd
,msg
->message
,msg
->wParam
,msg
->lParam
);
5157 if (translate_accelerator( hWnd
, msg
->message
, msg
->wParam
, msg
->lParam
,
5158 lpAccelTbl
[i
].fVirt
, lpAccelTbl
[i
].key
, lpAccelTbl
[i
].cmd
))
5160 } while ((lpAccelTbl
[i
++].fVirt
& 0x80) == 0);
5161 WARN_(accel
)("couldn't translate accelerator key\n");
5166 /**********************************************************************
5167 * TranslateAccelerator16 (USER.178)
5169 INT16 WINAPI
TranslateAccelerator16( HWND16 hWnd
, HACCEL16 hAccel
, LPMSG16 msg
)
5171 LPACCEL16 lpAccelTbl
;
5176 WARN_(accel
)("msg null; should hang here to be win compatible\n");
5179 if (!hAccel
|| !(lpAccelTbl
= (LPACCEL16
) LockResource16(hAccel
)))
5181 WARN_(accel
)("invalid accel handle=%x\n", hAccel
);
5184 if ((msg
->message
!= WM_KEYDOWN
&&
5185 msg
->message
!= WM_KEYUP
&&
5186 msg
->message
!= WM_SYSKEYDOWN
&&
5187 msg
->message
!= WM_SYSKEYUP
&&
5188 msg
->message
!= WM_CHAR
)) return 0;
5190 TRACE_(accel
)("TranslateAccelerators hAccel=%04x, hWnd=%04x,"
5191 "msg->hwnd=%04x, msg->message=%04x, wParam=%04x, lParam=%lx\n",
5192 hAccel
,hWnd
,msg
->hwnd
,msg
->message
,msg
->wParam
,msg
->lParam
);
5197 if (translate_accelerator( hWnd
, msg
->message
, msg
->wParam
, msg
->lParam
,
5198 lpAccelTbl
[i
].fVirt
, lpAccelTbl
[i
].key
, lpAccelTbl
[i
].cmd
))
5200 } while ((lpAccelTbl
[i
++].fVirt
& 0x80) == 0);
5201 WARN_(accel
)("couldn't translate accelerator key\n");