source: trunk/src/user32/menu.c@ 10017

Last change on this file since 10017 was 10017, checked in by sandervl, 22 years ago

MENU_TrackKbdMenuBar: check for WS_EX_TOOLWINDOW before using the system menu

File size: 141.9 KB
Line 
1/*
2 * Menu functions
3 *
4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
6 * Copyright 1997 Morten Welinder
7 */
8
9/*
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.
13 */
14
15#include "config.h"
16#include "wine/port.h"
17
18#include <assert.h>
19#include <ctype.h>
20#include <stdlib.h>
21#include <string.h>
22
23#include "windef.h"
24#include "winnls.h"
25#include "wingdi.h"
26#include "wine/winbase16.h"
27#include "wine/winuser16.h"
28#include "wine/unicode.h"
29#include "win.h"
30#include "controls.h"
31#include "nonclient.h"
32#include "user.h"
33#ifndef __WIN32OS2__
34#include "message.h"
35#endif
36
37#include "debugtools.h"
38
39#ifdef __WIN32OS2__
40#include <objhandle.h>
41#include <winerror.h>
42#include "pmwindow.h"
43#include "ctrlconf.h"
44#include "oslibmsg.h"
45#include "oslibwin.h"
46
47HBRUSH WIN32API GetOS2ColorBrush(int nIndex);
48COLORREF WIN32API GetOS2Color(int nIndex);
49
50static BOOL fDisableOdinSysMenuItems = FALSE;
51
52#endif
53
54DEFAULT_DEBUG_CHANNEL(menu);
55DECLARE_DEBUG_CHANNEL(accel);
56
57#define HACCEL_16(h32) (LOWORD(h32))
58
59/* internal popup menu window messages */
60
61#define MM_SETMENUHANDLE (WM_USER + 0)
62#define MM_GETMENUHANDLE (WM_USER + 1)
63
64/* Menu item structure */
65typedef struct {
66 /* ----------- MENUITEMINFO Stuff ----------- */
67 UINT fType; /* Item type. */
68 UINT fState; /* Item state. */
69 UINT wID; /* Item id. */
70 HMENU hSubMenu; /* Pop-up menu. */
71 HBITMAP hCheckBit; /* Bitmap when checked. */
72 HBITMAP hUnCheckBit; /* Bitmap when unchecked. */
73 LPWSTR text; /* Item text or bitmap handle. */
74 DWORD dwItemData; /* Application defined. */
75 DWORD dwTypeData; /* depends on fMask */
76 HBITMAP hbmpItem; /* bitmap in win98 style menus */
77 /* ----------- Wine stuff ----------- */
78 RECT rect; /* Item area (relative to menu window) */
79 UINT xTab; /* X position of text after Tab */
80} MENUITEM;
81
82/* Popup menu structure */
83typedef struct {
84 WORD wFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */
85 WORD wMagic; /* Magic number */
86 WORD Width; /* Width of the whole menu */
87 WORD Height; /* Height of the whole menu */
88 UINT nItems; /* Number of items in the menu */
89 HWND hWnd; /* Window containing the menu */
90 MENUITEM *items; /* Array of menu items */
91 UINT FocusedItem; /* Currently focused item */
92 HWND hwndOwner; /* window receiving the messages for ownerdraw */
93 BOOL bTimeToHide; /* Request hiding when receiving a second click in the top-level menu item */
94 /* ------------ MENUINFO members ------ */
95 DWORD dwStyle; /* Extended mennu style */
96 UINT cyMax; /* max hight of the whole menu, 0 is screen hight */
97 HBRUSH hbrBack; /* brush for menu background */
98 DWORD dwContextHelpID;
99 DWORD dwMenuData; /* application defined value */
100 HMENU hSysMenuOwner; /* Handle to the dummy sys menu holder */
101} POPUPMENU, *LPPOPUPMENU;
102
103/* internal flags for menu tracking */
104
105#define TF_ENDMENU 0x0001
106#define TF_SUSPENDPOPUP 0x0002
107#define TF_SKIPREMOVE 0x0004
108
109typedef struct
110{
111 UINT trackFlags;
112 HMENU hCurrentMenu; /* current submenu (can be equal to hTopMenu)*/
113 HMENU hTopMenu; /* initial menu */
114 HWND hOwnerWnd; /* where notifications are sent */
115 POINT pt;
116} MTRACKER;
117
118#define MENU_MAGIC 0x554d /* 'MU' */
119
120#define ITEM_PREV -1
121#define ITEM_NEXT 1
122
123 /* Internal MENU_TrackMenu() flags */
124#define TPM_INTERNAL 0xF0000000
125#define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
126#define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
127#define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
128
129 /* popup menu shade thickness */
130#define POPUP_XSHADE 4
131#define POPUP_YSHADE 4
132
133 /* Space between 2 menu bar items */
134#define MENU_BAR_ITEMS_SPACE 12
135
136 /* Minimum width of a tab character */
137#define MENU_TAB_SPACE 8
138
139 /* Height of a separator item */
140#define SEPARATOR_HEIGHT 5
141
142 /* (other menu->FocusedItem values give the position of the focused item) */
143#define NO_SELECTED_ITEM 0xffff
144
145#define MENU_ITEM_TYPE(flags) \
146 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
147
148#define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
149#define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
150#define IS_MAGIC_ITEM(text) (LOWORD((int)text)<12)
151
152#define IS_SYSTEM_MENU(menu) \
153 (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
154
155#define IS_SYSTEM_POPUP(menu) \
156 ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
157
158#define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
159 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
160 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
161 MF_POPUP | MF_SYSMENU | MF_HELP)
162#define STATE_MASK (~TYPE_MASK)
163
164 /* Dimension of the menu bitmaps */
165static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
166
167static HBITMAP hStdMnArrow = 0;
168static HBITMAP hBmpSysMenu = 0;
169
170static HBRUSH hShadeBrush = 0;
171static HFONT hMenuFont = 0;
172static HFONT hMenuFontBold = 0;
173
174static HMENU MENU_DefSysPopup = 0; /* Default system menu popup */
175
176/* Use global popup window because there's no way 2 menus can
177 * be tracked at the same time. */
178static HWND top_popup;
179
180 /* Flag set by EndMenu() to force an exit from menu tracking */
181static BOOL fEndMenu = FALSE;
182
183static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
184
185
186/*********************************************************************
187 * menu class descriptor
188 */
189const struct builtin_class_descr MENU_builtin_class =
190{
191 POPUPMENU_CLASS_ATOM, /* name */
192 CS_GLOBALCLASS | CS_SAVEBITS, /* style */
193 NULL, /* procA (winproc is Unicode only) */
194 PopupMenuWndProc, /* procW */
195 sizeof(HMENU), /* extra */
196 IDC_ARROWA, /* cursor */
197 COLOR_MENU+1 /* brush */
198};
199
200
201/***********************************************************************
202 * debug_print_menuitem
203 *
204 * Print a menuitem in readable form.
205 */
206
207#define debug_print_menuitem(pre, mp, post) \
208 if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
209
210#define MENUOUT(text) \
211 DPRINTF("%s%s", (count++ ? "," : ""), (text))
212
213#define MENUFLAG(bit,text) \
214 do { \
215 if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
216 } while (0)
217
218static void do_debug_print_menuitem(const char *prefix, MENUITEM * mp,
219 const char *postfix)
220{
221 TRACE("%s ", prefix);
222 if (mp) {
223 UINT flags = mp->fType;
224 int typ = MENU_ITEM_TYPE(flags);
225 DPRINTF( "{ ID=0x%x", mp->wID);
226 if (flags & MF_POPUP)
227 DPRINTF( ", Sub=0x%x", mp->hSubMenu);
228 if (flags) {
229 int count = 0;
230 DPRINTF( ", Typ=");
231 if (typ == MFT_STRING)
232 /* Nothing */ ;
233 else if (typ == MFT_SEPARATOR)
234 MENUOUT("sep");
235 else if (typ == MFT_OWNERDRAW)
236 MENUOUT("own");
237 else if (typ == MFT_BITMAP)
238 MENUOUT("bit");
239 else
240 MENUOUT("???");
241 flags -= typ;
242
243 MENUFLAG(MF_POPUP, "pop");
244 MENUFLAG(MFT_MENUBARBREAK, "barbrk");
245 MENUFLAG(MFT_MENUBREAK, "brk");
246 MENUFLAG(MFT_RADIOCHECK, "radio");
247 MENUFLAG(MFT_RIGHTORDER, "rorder");
248 MENUFLAG(MF_SYSMENU, "sys");
249 MENUFLAG(MFT_RIGHTJUSTIFY, "right"); /* same as MF_HELP */
250
251 if (flags)
252 DPRINTF( "+0x%x", flags);
253 }
254 flags = mp->fState;
255 if (flags) {
256 int count = 0;
257 DPRINTF( ", State=");
258 MENUFLAG(MFS_GRAYED, "grey");
259 MENUFLAG(MFS_DEFAULT, "default");
260 MENUFLAG(MFS_DISABLED, "dis");
261 MENUFLAG(MFS_CHECKED, "check");
262 MENUFLAG(MFS_HILITE, "hi");
263 MENUFLAG(MF_USECHECKBITMAPS, "usebit");
264 MENUFLAG(MF_MOUSESELECT, "mouse");
265 if (flags)
266 DPRINTF( "+0x%x", flags);
267 }
268 if (mp->hCheckBit)
269 DPRINTF( ", Chk=0x%x", mp->hCheckBit);
270 if (mp->hUnCheckBit)
271 DPRINTF( ", Unc=0x%x", mp->hUnCheckBit);
272
273 if (typ == MFT_STRING) {
274 if (mp->text)
275 DPRINTF( ", Text=%s", debugstr_w(mp->text));
276 else
277 DPRINTF( ", Text=Null");
278 } else if (mp->text == NULL)
279 /* Nothing */ ;
280 else
281 DPRINTF( ", Text=%p", mp->text);
282 if (mp->dwItemData)
283 DPRINTF( ", ItemData=0x%08lx", mp->dwItemData);
284 DPRINTF( " }");
285 } else {
286 DPRINTF( "NULL");
287 }
288
289 DPRINTF(" %s\n", postfix);
290}
291
292#undef MENUOUT
293#undef MENUFLAG
294
295
296/***********************************************************************
297 * MENU_GetMenu
298 *
299 * Validate the given menu handle and returns the menu structure pointer.
300 */
301static POPUPMENU *MENU_GetMenu(HMENU hMenu)
302{
303#ifdef __WIN32OS2__
304 if(ObjQueryHandleType(hMenu) == HNDL_MENU) {
305 POPUPMENU *menu;
306
307 menu = (POPUPMENU *)ObjQueryHandleData(hMenu, HNDL_MENU);
308 return menu;
309 }
310 return NULL;
311#else
312 POPUPMENU *menu = USER_HEAP_LIN_ADDR(hMenu);
313 if (!menu || menu->wMagic != MENU_MAGIC)
314 {
315 WARN("invalid menu handle=%x, ptr=%p, magic=%x\n", hMenu, menu, menu? menu->wMagic:0);
316 menu = NULL;
317 }
318 return menu;
319#endif
320}
321
322#ifndef __WIN32OS2__
323/***********************************************************************
324 * get_win_sys_menu
325 *
326 * Get the system menu of a window
327 */
328static HMENU get_win_sys_menu( HWND hwnd )
329{
330 HMENU ret = 0;
331 WND *win = WIN_FindWndPtr( hwnd );
332 if (win)
333 {
334 ret = win->hSysMenu;
335 WIN_ReleaseWndPtr( win );
336 }
337 return ret;
338}
339#endif
340/***********************************************************************
341 * MENU_CopySysPopup
342 *
343 * Return the default system menu.
344 */
345static HMENU MENU_CopySysPopup(void)
346{
347#ifndef __WIN32OS2__
348 HMENU hMenu = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
349#else
350 HMENU hMenu;
351 hMenu = LoadMenuA(GetModuleHandleA("USER32"), fOS2Look ? "SYSMENUWARP" : "SYSMENU");
352#endif
353
354 if( hMenu ) {
355 POPUPMENU* menu = MENU_GetMenu(hMenu);
356 menu->wFlags |= MF_SYSMENU | MF_POPUP;
357 SetMenuDefaultItem(hMenu, SC_CLOSE, FALSE);
358#ifdef __WIN32OS2__
359 if(!fDisableOdinSysMenuItems) {
360 AppendMenuA(hMenu, MF_SEPARATOR, 0, NULL);
361 AppendMenuA(hMenu,MF_STRING,
362 SC_ABOUTODIN, (LPSTR)"About Odin");
363#ifdef DEBUG
364 AppendMenuA(hMenu, MF_SEPARATOR, 0, NULL);
365 AppendMenuA(hMenu,MF_STRING,
366 SC_PUTMARK, (LPSTR)"Put mark in debug log");
367 AppendMenuA(hMenu,MF_STRING,
368 SC_DEBUGINT3, (LPSTR)"Breakpoint");
369#endif
370 }
371#endif
372 }
373 else
374 ERR("Unable to load default system menu\n" );
375
376 TRACE("returning %x.\n", hMenu );
377
378 return hMenu;
379}
380
381
382/**********************************************************************
383 * MENU_GetSysMenu
384 *
385 * Create a copy of the system menu. System menu in Windows is
386 * a special menu bar with the single entry - system menu popup.
387 * This popup is presented to the outside world as a "system menu".
388 * However, the real system menu handle is sometimes seen in the
389 * WM_MENUSELECT parameters (and Word 6 likes it this way).
390 */
391HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu )
392{
393 HMENU hMenu;
394
395 if ((hMenu = CreateMenu()))
396 {
397 POPUPMENU *menu = MENU_GetMenu(hMenu);
398 menu->wFlags = MF_SYSMENU;
399 menu->hWnd = WIN_GetFullHandle( hWnd );
400
401 if (hPopupMenu == (HMENU)(-1))
402 hPopupMenu = MENU_CopySysPopup();
403 else if( !hPopupMenu ) hPopupMenu = MENU_DefSysPopup;
404
405 if (hPopupMenu)
406 {
407 InsertMenuA( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION, hPopupMenu, NULL );
408
409 menu->items[0].fType = MF_SYSMENU | MF_POPUP;
410 menu->items[0].fState = 0;
411 if ((menu = MENU_GetMenu(hPopupMenu))) menu->wFlags |= MF_SYSMENU;
412
413 TRACE("GetSysMenu hMenu=%04x (%04x)\n", hMenu, hPopupMenu );
414 return hMenu;
415 }
416 DestroyMenu( hMenu );
417 }
418 ERR("failed to load system menu!\n");
419 return 0;
420}
421
422
423/***********************************************************************
424 * MENU_Init
425 *
426 * Menus initialisation.
427 */
428BOOL MENU_Init()
429{
430 HBITMAP hBitmap;
431 NONCLIENTMETRICSA ncm;
432
433 static unsigned char shade_bits[16] = { 0x55, 0, 0xAA, 0,
434 0x55, 0, 0xAA, 0,
435 0x55, 0, 0xAA, 0,
436 0x55, 0, 0xAA, 0 };
437
438 /* Load menu bitmaps */
439 hStdMnArrow = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW));
440 /* Load system buttons bitmaps */
441 hBmpSysMenu = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CLOSE));
442
443 if (hStdMnArrow)
444 {
445 BITMAP bm;
446 GetObjectA( hStdMnArrow, sizeof(bm), &bm );
447 arrow_bitmap_width = bm.bmWidth;
448 arrow_bitmap_height = bm.bmHeight;
449 } else
450 return FALSE;
451
452 if (! (hBitmap = CreateBitmap( 8, 8, 1, 1, shade_bits)))
453 return FALSE;
454
455 if(!(hShadeBrush = CreatePatternBrush( hBitmap )))
456 return FALSE;
457
458 DeleteObject( hBitmap );
459 if (!(MENU_DefSysPopup = MENU_CopySysPopup()))
460 return FALSE;
461
462 ncm.cbSize = sizeof (NONCLIENTMETRICSA);
463 if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSA), &ncm, 0)))
464 return FALSE;
465
466 if (!(hMenuFont = CreateFontIndirectA( &ncm.lfMenuFont )))
467 return FALSE;
468
469 ncm.lfMenuFont.lfWeight += 300;
470 if ( ncm.lfMenuFont.lfWeight > 1000)
471 ncm.lfMenuFont.lfWeight = 1000;
472
473 if (!(hMenuFontBold = CreateFontIndirectA( &ncm.lfMenuFont )))
474 return FALSE;
475
476 return TRUE;
477}
478
479/***********************************************************************
480 * MENU_InitSysMenuPopup
481 *
482 * Grey the appropriate items in System menu.
483 */
484static void MENU_InitSysMenuPopup( HMENU hmenu, DWORD style, DWORD clsStyle )
485{
486 BOOL gray;
487
488 gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
489 EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
490 gray = ((style & WS_MAXIMIZE) != 0);
491 EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
492 gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
493 EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
494 gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
495 EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
496 gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
497 EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
498 gray = (clsStyle & CS_NOCLOSE) != 0;
499
500 /* The menu item must keep its state if it's disabled */
501 if(gray)
502 EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED);
503}
504
505
506/******************************************************************************
507 *
508 * UINT MENU_GetStartOfNextColumn(
509 * HMENU hMenu )
510 *
511 *****************************************************************************/
512
513static UINT MENU_GetStartOfNextColumn(
514 HMENU hMenu )
515{
516 POPUPMENU *menu = MENU_GetMenu(hMenu);
517 UINT i;
518
519 if(!menu)
520 return NO_SELECTED_ITEM;
521
522 i = menu->FocusedItem + 1;
523 if( i == NO_SELECTED_ITEM )
524 return i;
525
526 for( ; i < menu->nItems; ++i ) {
527 if (menu->items[i].fType & MF_MENUBARBREAK)
528 return i;
529 }
530
531 return NO_SELECTED_ITEM;
532}
533
534
535/******************************************************************************
536 *
537 * UINT MENU_GetStartOfPrevColumn(
538 * HMENU hMenu )
539 *
540 *****************************************************************************/
541
542static UINT MENU_GetStartOfPrevColumn(
543 HMENU hMenu )
544{
545 POPUPMENU *menu = MENU_GetMenu(hMenu);
546 UINT i;
547
548 if( !menu )
549 return NO_SELECTED_ITEM;
550
551 if( menu->FocusedItem == 0 || menu->FocusedItem == NO_SELECTED_ITEM )
552 return NO_SELECTED_ITEM;
553
554 /* Find the start of the column */
555
556 for(i = menu->FocusedItem; i != 0 &&
557 !(menu->items[i].fType & MF_MENUBARBREAK);
558 --i); /* empty */
559
560 if(i == 0)
561 return NO_SELECTED_ITEM;
562
563 for(--i; i != 0; --i) {
564 if (menu->items[i].fType & MF_MENUBARBREAK)
565 break;
566 }
567
568 TRACE("ret %d.\n", i );
569
570 return i;
571}
572
573
574
575/***********************************************************************
576 * MENU_FindItem
577 *
578 * Find a menu item. Return a pointer on the item, and modifies *hmenu
579 * in case the item was in a sub-menu.
580 */
581static MENUITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
582{
583 POPUPMENU *menu;
584 UINT i;
585
586 if (((*hmenu)==0xffff) || (!(menu = MENU_GetMenu(*hmenu)))) return NULL;
587 if (wFlags & MF_BYPOSITION)
588 {
589 if (*nPos >= menu->nItems) return NULL;
590 return &menu->items[*nPos];
591 }
592 else
593 {
594 MENUITEM *item = menu->items;
595 for (i = 0; i < menu->nItems; i++, item++)
596 {
597 if (item->wID == *nPos)
598 {
599 *nPos = i;
600 return item;
601 }
602 else if (item->fType & MF_POPUP)
603 {
604 HMENU hsubmenu = item->hSubMenu;
605 MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
606#ifdef __WIN32OS2__
607 //YD: 2000-12-01: extra check added for loops in menus
608 if (subitem && subitem!=item)
609#else
610 if (subitem)
611#endif
612 {
613 *hmenu = hsubmenu;
614 return subitem;
615 }
616 }
617 }
618 }
619 return NULL;
620}
621
622/***********************************************************************
623 * MENU_FindSubMenu
624 *
625 * Find a Sub menu. Return the position of the submenu, and modifies
626 * *hmenu in case it is found in another sub-menu.
627 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
628 */
629UINT MENU_FindSubMenu( HMENU *hmenu, HMENU hSubTarget )
630{
631 POPUPMENU *menu;
632 UINT i;
633 MENUITEM *item;
634 if (((*hmenu)==0xffff) ||
635 (!(menu = MENU_GetMenu(*hmenu))))
636 return NO_SELECTED_ITEM;
637 item = menu->items;
638 for (i = 0; i < menu->nItems; i++, item++) {
639 if(!(item->fType & MF_POPUP)) continue;
640 if (item->hSubMenu == hSubTarget) {
641 return i;
642 }
643 else {
644 HMENU hsubmenu = item->hSubMenu;
645 UINT pos = MENU_FindSubMenu( &hsubmenu, hSubTarget );
646 if (pos != NO_SELECTED_ITEM) {
647 *hmenu = hsubmenu;
648 return pos;
649 }
650 }
651 }
652 return NO_SELECTED_ITEM;
653}
654
655/***********************************************************************
656 * MENU_FreeItemData
657 */
658static void MENU_FreeItemData( MENUITEM* item )
659{
660 /* delete text */
661 if (IS_STRING_ITEM(item->fType) && item->text)
662 HeapFree( GetProcessHeap(), 0, item->text );
663}
664
665/***********************************************************************
666 * MENU_FindItemByCoords
667 *
668 * Find the item at the specified coordinates (screen coords). Does
669 * not work for child windows and therefore should not be called for
670 * an arbitrary system menu.
671 */
672static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu,
673 POINT pt, UINT *pos )
674{
675 MENUITEM *item;
676 UINT i;
677 RECT wrect;
678
679 if (!GetWindowRect(menu->hWnd,&wrect)) return NULL;
680 pt.x -= wrect.left;pt.y -= wrect.top;
681 item = menu->items;
682 for (i = 0; i < menu->nItems; i++, item++)
683 {
684 if ((pt.x >= item->rect.left) && (pt.x < item->rect.right) &&
685 (pt.y >= item->rect.top) && (pt.y < item->rect.bottom))
686 {
687 if (pos) *pos = i;
688 return item;
689 }
690 }
691 return NULL;
692}
693
694
695/***********************************************************************
696 * MENU_FindItemByKey
697 *
698 * Find the menu item selected by a key press.
699 * Return item id, -1 if none, -2 if we should close the menu.
700 */
701static UINT MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu,
702 UINT key, BOOL forceMenuChar )
703{
704 TRACE("\tlooking for '%c' in [%04x]\n", (char)key, (UINT16)hmenu );
705
706 if (!IsMenu( hmenu )) hmenu = GetSubMenu( get_win_sys_menu(hwndOwner), 0);
707
708 if (hmenu)
709 {
710 POPUPMENU *menu = MENU_GetMenu( hmenu );
711 MENUITEM *item = menu->items;
712 LONG menuchar;
713
714 if( !forceMenuChar )
715 {
716 UINT i;
717
718 key = toupper(key);
719 for (i = 0; i < menu->nItems; i++, item++)
720 {
721 if (item->text && (IS_STRING_ITEM(item->fType)))
722 {
723 WCHAR *p = item->text - 2;
724 do
725 {
726 p = strchrW (p + 2, '&');
727 }
728 while (p != NULL && p [1] == '&');
729 if (p && (toupper(p[1]) == key)) return i;
730 }
731 }
732 }
733 menuchar = SendMessageA( hwndOwner, WM_MENUCHAR,
734 MAKEWPARAM( key, menu->wFlags ), hmenu );
735 if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
736 if (HIWORD(menuchar) == 1) return (UINT)(-2);
737 }
738 return (UINT)(-1);
739}
740
741
742/***********************************************************************
743 * MENU_GetBitmapItemSize
744 *
745 * Get the size of a bitmap item.
746 */
747static void MENU_GetBitmapItemSize( UINT id, DWORD data, SIZE *size )
748{
749 BITMAP bm;
750 HBITMAP bmp = (HBITMAP)id;
751
752 size->cx = size->cy = 0;
753
754 /* check if there is a magic menu item associated with this item */
755 if (id && IS_MAGIC_ITEM( id ))
756 {
757 switch(LOWORD(id))
758 {
759 case HBMMENU_SYSTEM:
760 if (data)
761 {
762 bmp = (HBITMAP)data;
763 break;
764 }
765 /* fall through */
766 case HBMMENU_MBAR_RESTORE:
767 case HBMMENU_MBAR_MINIMIZE:
768 case HBMMENU_MBAR_MINIMIZE_D:
769 case HBMMENU_MBAR_CLOSE:
770 case HBMMENU_MBAR_CLOSE_D:
771 size->cx = GetSystemMetrics( SM_CXSIZE );
772 size->cy = GetSystemMetrics( SM_CYSIZE );
773 return;
774 case HBMMENU_CALLBACK:
775 case HBMMENU_POPUP_CLOSE:
776 case HBMMENU_POPUP_RESTORE:
777 case HBMMENU_POPUP_MAXIMIZE:
778 case HBMMENU_POPUP_MINIMIZE:
779 default:
780 FIXME("Magic 0x%08x not implemented\n", id);
781 return;
782 }
783 }
784 if (GetObjectA(bmp, sizeof(bm), &bm ))
785 {
786 size->cx = bm.bmWidth;
787 size->cy = bm.bmHeight;
788 }
789}
790
791/***********************************************************************
792 * MENU_DrawBitmapItem
793 *
794 * Draw a bitmap item.
795 */
796static void MENU_DrawBitmapItem( HDC hdc, MENUITEM *lpitem, const RECT *rect, BOOL menuBar )
797{
798 BITMAP bm;
799 DWORD rop;
800 HDC hdcMem;
801 HBITMAP bmp = (HBITMAP)lpitem->text;
802 int w = rect->right - rect->left;
803 int h = rect->bottom - rect->top;
804 int bmp_xoffset = 0;
805 int left, top;
806
807 /* Check if there is a magic menu item associated with this item */
808 if (lpitem->text && IS_MAGIC_ITEM(lpitem->text))
809 {
810 UINT flags = 0;
811 RECT r;
812
813 switch(LOWORD(lpitem->text))
814 {
815 case HBMMENU_SYSTEM:
816 if (lpitem->dwItemData)
817 {
818 bmp = (HBITMAP)lpitem->dwItemData;
819 if (!GetObjectA( bmp, sizeof(bm), &bm )) return;
820 }
821 else
822 {
823 bmp = hBmpSysMenu;
824 if (!GetObjectA( bmp, sizeof(bm), &bm )) return;
825 /* only use right half of the bitmap */
826 bmp_xoffset = bm.bmWidth / 2;
827 bm.bmWidth -= bmp_xoffset;
828 }
829 goto got_bitmap;
830 case HBMMENU_MBAR_RESTORE:
831 flags = DFCS_CAPTIONRESTORE;
832 break;
833 case HBMMENU_MBAR_MINIMIZE:
834 flags = DFCS_CAPTIONMIN;
835 break;
836 case HBMMENU_MBAR_MINIMIZE_D:
837 flags = DFCS_CAPTIONMIN | DFCS_INACTIVE;
838 break;
839 case HBMMENU_MBAR_CLOSE:
840 flags = DFCS_CAPTIONCLOSE;
841 break;
842 case HBMMENU_MBAR_CLOSE_D:
843 flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE;
844 break;
845 case HBMMENU_CALLBACK:
846 case HBMMENU_POPUP_CLOSE:
847 case HBMMENU_POPUP_RESTORE:
848 case HBMMENU_POPUP_MAXIMIZE:
849 case HBMMENU_POPUP_MINIMIZE:
850 default:
851 FIXME("Magic 0x%08x not implemented\n", LOWORD(lpitem->text));
852 return;
853 }
854 r = *rect;
855 InflateRect( &r, -1, -1 );
856 if (lpitem->fState & MF_HILITE) flags |= DFCS_PUSHED;
857 DrawFrameControl( hdc, &r, DFC_CAPTION, flags );
858 return;
859 }
860
861 if (!bmp || !GetObjectA( bmp, sizeof(bm), &bm )) return;
862
863 got_bitmap:
864 hdcMem = CreateCompatibleDC( hdc );
865 SelectObject( hdcMem, bmp );
866
867 /* handle fontsize > bitmap_height */
868 top = (h>bm.bmHeight) ? rect->top+(h-bm.bmHeight)/2 : rect->top;
869 left=rect->left;
870 if (TWEAK_WineLook == WIN95_LOOK) {
871 rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_ITEM(lpitem->text)) ? NOTSRCCOPY : SRCCOPY;
872 if ((lpitem->fState & MF_HILITE) && IS_BITMAP_ITEM(lpitem->fType))
873 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
874 } else {
875 left++;
876 w-=2;
877 rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_ITEM(lpitem->text) && (!menuBar)) ? MERGEPAINT : SRCCOPY;
878 }
879 BitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop );
880 DeleteDC( hdcMem );
881}
882
883
884/***********************************************************************
885 * MENU_CalcItemSize
886 *
887 * Calculate the size of the menu item and store it in lpitem->rect.
888 */
889static void MENU_CalcItemSize( HDC hdc, MENUITEM *lpitem, HWND hwndOwner,
890 INT orgX, INT orgY, BOOL menuBar )
891{
892 WCHAR *p;
893 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
894
895 TRACE("dc=0x%04x owner=0x%04x (%d,%d)\n", hdc, hwndOwner, orgX, orgY);
896 debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem,
897 (menuBar ? " (MenuBar)" : ""));
898
899 SetRect( &lpitem->rect, orgX, orgY, orgX, orgY );
900
901 if (lpitem->fType & MF_OWNERDRAW)
902 {
903 /*
904 ** Experimentation under Windows reveals that an owner-drawn
905 ** menu is expected to return the size of the content part of
906 ** the menu item, not including the checkmark nor the submenu
907 ** arrow. Windows adds those values itself and returns the
908 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
909 */
910 MEASUREITEMSTRUCT mis;
911 mis.CtlType = ODT_MENU;
912 mis.CtlID = 0;
913 mis.itemID = lpitem->wID;
914 mis.itemData = (DWORD)lpitem->dwItemData;
915 mis.itemHeight = 0;
916 mis.itemWidth = 0;
917 SendMessageA( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
918 lpitem->rect.right += mis.itemWidth;
919
920 if (menuBar)
921 {
922 lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
923
924
925 /* under at least win95 you seem to be given a standard
926 height for the menu and the height value is ignored */
927
928 if (TWEAK_WineLook == WIN31_LOOK)
929 lpitem->rect.bottom += GetSystemMetrics(SM_CYMENU);
930 else
931 lpitem->rect.bottom += GetSystemMetrics(SM_CYMENU)-1;
932 }
933 else
934 lpitem->rect.bottom += mis.itemHeight;
935
936 TRACE("id=%04x size=%dx%d\n",
937 lpitem->wID, mis.itemWidth, mis.itemHeight);
938 /* Fall through to get check/arrow width calculation. */
939 }
940
941 if (lpitem->fType & MF_SEPARATOR)
942 {
943 lpitem->rect.bottom += SEPARATOR_HEIGHT;
944 return;
945 }
946
947 if (!menuBar)
948 {
949 lpitem->rect.right += 2 * check_bitmap_width;
950 if (lpitem->fType & MF_POPUP)
951 lpitem->rect.right += arrow_bitmap_width;
952 }
953
954 if (lpitem->fType & MF_OWNERDRAW)
955 return;
956
957 if (IS_BITMAP_ITEM(lpitem->fType))
958 {
959 SIZE size;
960
961 MENU_GetBitmapItemSize( (int)lpitem->text, lpitem->dwItemData, &size );
962 lpitem->rect.right += size.cx;
963 lpitem->rect.bottom += size.cy;
964 if (TWEAK_WineLook == WIN98_LOOK)
965 {
966 /* Leave space for the sunken border */
967 lpitem->rect.right += 2;
968 lpitem->rect.bottom += 2;
969 }
970 }
971
972
973 /* it must be a text item - unless it's the system menu */
974 if (!(lpitem->fType & MF_SYSMENU) && IS_STRING_ITEM( lpitem->fType ))
975 { SIZE size;
976
977 GetTextExtentPoint32W(hdc, lpitem->text, strlenW(lpitem->text), &size);
978
979 lpitem->rect.right += size.cx;
980 if (TWEAK_WineLook == WIN31_LOOK)
981 lpitem->rect.bottom += max( size.cy, GetSystemMetrics(SM_CYMENU) );
982 else
983 lpitem->rect.bottom += max(size.cy, GetSystemMetrics(SM_CYMENU)-1);
984 lpitem->xTab = 0;
985
986 if (menuBar)
987 {
988 lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
989 }
990 else if ((p = strchrW( lpitem->text, '\t' )) != NULL)
991 {
992 /* Item contains a tab (only meaningful in popup menus) */
993 GetTextExtentPoint32W(hdc, lpitem->text, (int)(p - lpitem->text) , &size);
994 lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE + size.cx;
995 lpitem->rect.right += MENU_TAB_SPACE;
996 }
997 else
998 {
999 if (strchrW( lpitem->text, '\b' ))
1000 lpitem->rect.right += MENU_TAB_SPACE;
1001 lpitem->xTab = lpitem->rect.right - check_bitmap_width
1002 - arrow_bitmap_width;
1003 }
1004 }
1005 TRACE("(%d,%d)-(%d,%d)\n", lpitem->rect.left, lpitem->rect.top, lpitem->rect.right, lpitem->rect.bottom);
1006}
1007
1008
1009/***********************************************************************
1010 * MENU_PopupMenuCalcSize
1011 *
1012 * Calculate the size of a popup menu.
1013 */
1014static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
1015{
1016 MENUITEM *lpitem;
1017 HDC hdc;
1018 int start, i;
1019 int orgX, orgY, maxX, maxTab, maxTabWidth;
1020
1021 lppop->Width = lppop->Height = 0;
1022 if (lppop->nItems == 0) return;
1023#ifdef __WIN32OS2__
1024 hdc = CreateCompatibleDC( 0 );
1025#else
1026 hdc = GetDC( 0 );
1027#endif
1028
1029 SelectObject( hdc, hMenuFont);
1030
1031 start = 0;
1032 maxX = (TWEAK_WineLook == WIN31_LOOK) ? GetSystemMetrics(SM_CXBORDER) : 2+1 ;
1033
1034 while (start < lppop->nItems)
1035 {
1036 lpitem = &lppop->items[start];
1037 orgX = maxX;
1038 orgY = (TWEAK_WineLook == WIN31_LOOK) ? GetSystemMetrics(SM_CYBORDER) : 2;
1039
1040 maxTab = maxTabWidth = 0;
1041
1042 /* Parse items until column break or end of menu */
1043 for (i = start; i < lppop->nItems; i++, lpitem++)
1044 {
1045 if ((i != start) &&
1046 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
1047
1048 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
1049
1050 if (lpitem->fType & MF_MENUBARBREAK) orgX++;
1051 maxX = max( maxX, lpitem->rect.right );
1052 orgY = lpitem->rect.bottom;
1053 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
1054 {
1055 maxTab = max( maxTab, lpitem->xTab );
1056 maxTabWidth = max(maxTabWidth,lpitem->rect.right-lpitem->xTab);
1057 }
1058 }
1059
1060 /* Finish the column (set all items to the largest width found) */
1061 maxX = max( maxX, maxTab + maxTabWidth );
1062 for (lpitem = &lppop->items[start]; start < i; start++, lpitem++)
1063 {
1064 lpitem->rect.right = maxX;
1065 if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
1066 lpitem->xTab = maxTab;
1067
1068 }
1069 lppop->Height = max( lppop->Height, orgY );
1070 }
1071
1072 lppop->Width = maxX;
1073
1074 /* space for 3d border */
1075 if(TWEAK_WineLook > WIN31_LOOK)
1076 {
1077 lppop->Height += 2;
1078 lppop->Width += 2;
1079 }
1080
1081#ifdef __WIN32OS2__
1082 DeleteDC(hdc);
1083#else
1084 ReleaseDC( 0, hdc );
1085#endif
1086}
1087
1088
1089/***********************************************************************
1090 * MENU_MenuBarCalcSize
1091 *
1092 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1093 * height is off by 1 pixel which causes lengthy window relocations when
1094 * active document window is maximized/restored.
1095 *
1096 * Calculate the size of the menu bar.
1097 */
1098static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect,
1099 LPPOPUPMENU lppop, HWND hwndOwner )
1100{
1101 MENUITEM *lpitem;
1102 int start, i, orgX, orgY, maxY, helpPos;
1103
1104 if ((lprect == NULL) || (lppop == NULL)) return;
1105 if (lppop->nItems == 0) return;
1106 TRACE("left=%d top=%d right=%d bottom=%d\n",
1107 lprect->left, lprect->top, lprect->right, lprect->bottom);
1108 lppop->Width = lprect->right - lprect->left;
1109 lppop->Height = 0;
1110 maxY = lprect->top+1;
1111 start = 0;
1112 helpPos = -1;
1113 while (start < lppop->nItems)
1114 {
1115 lpitem = &lppop->items[start];
1116 orgX = lprect->left;
1117 orgY = maxY;
1118
1119 /* Parse items until line break or end of menu */
1120 for (i = start; i < lppop->nItems; i++, lpitem++)
1121 {
1122 if ((helpPos == -1) && (lpitem->fType & MF_RIGHTJUSTIFY)) helpPos = i;
1123 if ((i != start) &&
1124 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
1125
1126 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
1127 orgX, orgY );
1128 debug_print_menuitem (" item: ", lpitem, "");
1129 MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE );
1130
1131 if (lpitem->rect.right > lprect->right)
1132 {
1133 if (i != start) break;
1134 else lpitem->rect.right = lprect->right;
1135 }
1136 maxY = max( maxY, lpitem->rect.bottom );
1137 orgX = lpitem->rect.right;
1138 }
1139
1140 /* Finish the line (set all items to the largest height found) */
1141 while (start < i) lppop->items[start++].rect.bottom = maxY;
1142 }
1143
1144 lprect->bottom = maxY;
1145 lppop->Height = lprect->bottom - lprect->top;
1146
1147 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1148 /* the last item (if several lines, only move the last line) */
1149 lpitem = &lppop->items[lppop->nItems-1];
1150 orgY = lpitem->rect.top;
1151 orgX = lprect->right;
1152 for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--) {
1153 if ( (helpPos==-1) || (helpPos>i) )
1154 break; /* done */
1155 if (lpitem->rect.top != orgY) break; /* Other line */
1156 if (lpitem->rect.right >= orgX) break; /* Too far right already */
1157 lpitem->rect.left += orgX - lpitem->rect.right;
1158 lpitem->rect.right = orgX;
1159 orgX = lpitem->rect.left;
1160 }
1161}
1162
1163/***********************************************************************
1164 * MENU_DrawMenuItem
1165 *
1166 * Draw a single menu item.
1167 */
1168static void MENU_DrawMenuItem( HWND hwnd, HMENU hmenu, HWND hwndOwner, HDC hdc, MENUITEM *lpitem,
1169 UINT height, BOOL menuBar, UINT odaction )
1170{
1171 RECT rect;
1172
1173 debug_print_menuitem("MENU_DrawMenuItem: ", lpitem, "");
1174
1175 if (lpitem->fType & MF_SYSMENU)
1176 {
1177 if( !IsIconic(hwnd) ) {
1178 if (TWEAK_WineLook > WIN31_LOOK)
1179 NC_DrawSysButton95( hwnd, hdc,
1180 lpitem->fState &
1181 (MF_HILITE | MF_MOUSESELECT) );
1182 else
1183 NC_DrawSysButton( hwnd, hdc,
1184 lpitem->fState &
1185 (MF_HILITE | MF_MOUSESELECT) );
1186 }
1187
1188 return;
1189 }
1190
1191 if (lpitem->fType & MF_OWNERDRAW)
1192 {
1193 /*
1194 ** Experimentation under Windows reveals that an owner-drawn
1195 ** menu is given the rectangle which includes the space it requested
1196 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1197 ** and a popup-menu arrow. This is the value of lpitem->rect.
1198 ** Windows will leave all drawing to the application except for
1199 ** the popup-menu arrow. Windows always draws that itself, after
1200 ** the menu owner has finished drawing.
1201 */
1202 DRAWITEMSTRUCT dis;
1203
1204 dis.CtlType = ODT_MENU;
1205 dis.CtlID = 0;
1206 dis.itemID = lpitem->wID;
1207 dis.itemData = (DWORD)lpitem->dwItemData;
1208 dis.itemState = 0;
1209 if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
1210 if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED|ODS_DISABLED;
1211 if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED;
1212 dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1213 dis.hwndItem = (HWND)hmenu;
1214 dis.hDC = hdc;
1215 dis.rcItem = lpitem->rect;
1216 TRACE("Ownerdraw: owner=%04x itemID=%d, itemState=%d, itemAction=%d, "
1217 "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n", hwndOwner,
1218 dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
1219 dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
1220 dis.rcItem.bottom);
1221 SendMessageA( hwndOwner, WM_DRAWITEM, 0, (LPARAM)&dis );
1222 /* Fall through to draw popup-menu arrow */
1223 }
1224
1225 TRACE("rect={%d,%d,%d,%d}\n", lpitem->rect.left, lpitem->rect.top,
1226 lpitem->rect.right,lpitem->rect.bottom);
1227
1228 if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
1229
1230 rect = lpitem->rect;
1231
1232 if (!(lpitem->fType & MF_OWNERDRAW))
1233 {
1234 if (lpitem->fState & MF_HILITE)
1235 {
1236#ifdef __WIN32OS2__
1237 if(!fOS2Look)
1238#else
1239 if(TWEAK_WineLook == WIN98_LOOK)
1240#endif
1241 {
1242 if(menuBar)
1243 DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
1244 else
1245 FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1246 }
1247 else /* Not Win98 Look */
1248 {
1249 if(!IS_BITMAP_ITEM(lpitem->fType))
1250#ifdef __WIN32OS2__
1251 FillRect(hdc, &rect, GetOS2ColorBrush(PMSYSCLR_MENUHILITEBGND));
1252#else
1253 FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1254#endif
1255 }
1256 }
1257 else
1258 FillRect( hdc, &rect, GetSysColorBrush(COLOR_MENU) );
1259 }
1260
1261 SetBkMode( hdc, TRANSPARENT );
1262
1263 if (!(lpitem->fType & MF_OWNERDRAW))
1264 {
1265 /* vertical separator */
1266 if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
1267 {
1268 if (TWEAK_WineLook > WIN31_LOOK)
1269 {
1270 RECT rc = rect;
1271 rc.top = 3;
1272 rc.bottom = height - 3;
1273 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
1274 }
1275 else
1276 {
1277 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1278 MoveToEx( hdc, rect.left, 0, NULL );
1279 LineTo( hdc, rect.left, height );
1280 }
1281 }
1282
1283 /* horizontal separator */
1284 if (lpitem->fType & MF_SEPARATOR)
1285 {
1286 if (TWEAK_WineLook > WIN31_LOOK)
1287 {
1288 RECT rc = rect;
1289 rc.left++;
1290 rc.right--;
1291 rc.top += SEPARATOR_HEIGHT / 2;
1292 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
1293 }
1294 else
1295 {
1296 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1297 MoveToEx( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2, NULL );
1298 LineTo( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 );
1299 }
1300 return;
1301 }
1302 }
1303
1304 /* Setup colors */
1305
1306 if (lpitem->fState & MF_HILITE)
1307 {
1308#ifdef __WIN32OS2__
1309 if(!fOS2Look)
1310#else
1311 if(TWEAK_WineLook == WIN98_LOOK)
1312#endif
1313 {
1314 if(menuBar) {
1315 SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT));
1316 SetBkColor(hdc, GetSysColor(COLOR_MENU));
1317 } else {
1318 if(lpitem->fState & MF_GRAYED)
1319 SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
1320 else
1321 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1322 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1323 }
1324 }
1325 else /* Not Win98 Look */
1326 {
1327 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1328 if(!IS_BITMAP_ITEM(lpitem->fType))
1329#ifdef __WIN32OS2__
1330 SetBkColor(hdc, GetOS2Color(PMSYSCLR_MENUHILITEBGND));
1331#else
1332 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1333#endif
1334 }
1335 }
1336 else
1337 {
1338 if (lpitem->fState & MF_GRAYED)
1339 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1340 else
1341 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
1342 SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
1343 }
1344
1345 /* helper lines for debugging */
1346/* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1347 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1348 MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
1349 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1350*/
1351
1352 if (!menuBar)
1353 {
1354 INT y = rect.top + rect.bottom;
1355 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
1356 UINT check_bitmap_height = GetSystemMetrics( SM_CYMENUCHECK );
1357
1358 if (!(lpitem->fType & MF_OWNERDRAW))
1359 {
1360 /* Draw the check mark
1361 *
1362 * FIXME:
1363 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1364 */
1365 HBITMAP bm = (lpitem->fState & MF_CHECKED) ? lpitem->hCheckBit : lpitem->hUnCheckBit;
1366 if (bm) /* we have a custom bitmap */
1367 {
1368 HDC hdcMem = CreateCompatibleDC( hdc );
1369 SelectObject( hdcMem, bm );
1370 BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
1371 check_bitmap_width, check_bitmap_height,
1372 hdcMem, 0, 0, SRCCOPY );
1373 DeleteDC( hdcMem );
1374 }
1375 else if (lpitem->fState & MF_CHECKED) /* standard bitmaps */
1376 {
1377 RECT r;
1378 HBITMAP bm = CreateBitmap( check_bitmap_width, check_bitmap_height, 1, 1, NULL );
1379 HDC hdcMem = CreateCompatibleDC( hdc );
1380 SelectObject( hdcMem, bm );
1381 SetRect( &r, 0, 0, check_bitmap_width, check_bitmap_height );
1382 DrawFrameControl( hdcMem, &r, DFC_MENU,
1383 (lpitem->fType & MFT_RADIOCHECK) ?
1384 DFCS_MENUBULLET : DFCS_MENUCHECK );
1385 BitBlt( hdc, rect.left, (y - r.bottom) / 2, r.right, r.bottom,
1386 hdcMem, 0, 0, SRCCOPY );
1387 DeleteDC( hdcMem );
1388 DeleteObject( bm );
1389 }
1390 }
1391
1392 /* Draw the popup-menu arrow */
1393 if (lpitem->fType & MF_POPUP)
1394 {
1395 HDC hdcMem = CreateCompatibleDC( hdc );
1396 HBITMAP hOrigBitmap;
1397
1398 hOrigBitmap = SelectObject( hdcMem, hStdMnArrow );
1399 BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
1400 (y - arrow_bitmap_height) / 2,
1401 arrow_bitmap_width, arrow_bitmap_height,
1402 hdcMem, 0, 0, SRCCOPY );
1403 SelectObject( hdcMem, hOrigBitmap );
1404 DeleteDC( hdcMem );
1405 }
1406
1407 rect.left += check_bitmap_width;
1408 rect.right -= arrow_bitmap_width;
1409 }
1410
1411 /* Done for owner-drawn */
1412 if (lpitem->fType & MF_OWNERDRAW)
1413 return;
1414
1415 /* Draw the item text or bitmap */
1416 if (IS_BITMAP_ITEM(lpitem->fType))
1417 {
1418 MENU_DrawBitmapItem( hdc, lpitem, &rect, menuBar );
1419 return;
1420
1421 }
1422 /* No bitmap - process text if present */
1423 else if (IS_STRING_ITEM(lpitem->fType))
1424 {
1425 register int i;
1426 HFONT hfontOld = 0;
1427
1428 UINT uFormat = (menuBar) ?
1429 DT_CENTER | DT_VCENTER | DT_SINGLELINE :
1430 DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1431
1432#ifdef __WIN32OS2__
1433 if ( lpitem->fState & MFS_DEFAULT && !fOS2Look)
1434#else
1435 if ( lpitem->fState & MFS_DEFAULT )
1436#endif
1437 {
1438 hfontOld = SelectObject( hdc, hMenuFontBold);
1439 }
1440
1441 if (menuBar)
1442 {
1443 rect.left += MENU_BAR_ITEMS_SPACE / 2;
1444 rect.right -= MENU_BAR_ITEMS_SPACE / 2;
1445 }
1446
1447 for (i = 0; lpitem->text[i]; i++)
1448 if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
1449 break;
1450
1451 if( (TWEAK_WineLook != WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
1452 {
1453 if (!(lpitem->fState & MF_HILITE) )
1454 {
1455 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1456 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1457 DrawTextW( hdc, lpitem->text, i, &rect, uFormat );
1458 --rect.left; --rect.top; --rect.right; --rect.bottom;
1459 }
1460 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1461 }
1462
1463 DrawTextW( hdc, lpitem->text, i, &rect, uFormat);
1464
1465 /* paint the shortcut text */
1466 if (!menuBar && lpitem->text[i]) /* There's a tab or flush-right char */
1467 {
1468 if (lpitem->text[i] == '\t')
1469 {
1470 rect.left = lpitem->xTab;
1471 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1472 }
1473 else
1474 {
1475 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
1476 }
1477
1478 if( !(TWEAK_WineLook == WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
1479 {
1480 if (!(lpitem->fState & MF_HILITE) )
1481 {
1482 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1483 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1484 DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1485 --rect.left; --rect.top; --rect.right; --rect.bottom;
1486 }
1487 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1488 }
1489 DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1490 }
1491
1492 if (hfontOld)
1493 SelectObject (hdc, hfontOld);
1494 }
1495}
1496
1497
1498/***********************************************************************
1499 * MENU_DrawPopupMenu
1500 *
1501 * Paint a popup menu.
1502 */
1503static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
1504{
1505 HBRUSH hPrevBrush = 0;
1506 RECT rect;
1507
1508 TRACE("wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd, hdc, hmenu);
1509
1510 GetClientRect( hwnd, &rect );
1511
1512 if(TWEAK_WineLook == WIN31_LOOK)
1513 {
1514 rect.bottom -= POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
1515 rect.right -= POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER);
1516 }
1517
1518 if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) ))
1519 && (SelectObject( hdc, hMenuFont)))
1520 {
1521 HPEN hPrevPen;
1522
1523 Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
1524
1525 hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
1526 if( hPrevPen )
1527 {
1528 INT ropPrev, i;
1529 POPUPMENU *menu;
1530
1531 /* draw 3-d shade */
1532 if(TWEAK_WineLook == WIN31_LOOK) {
1533 SelectObject( hdc, hShadeBrush );
1534 SetBkMode( hdc, TRANSPARENT );
1535 ropPrev = SetROP2( hdc, R2_MASKPEN );
1536
1537 i = rect.right; /* why SetBrushOrg() doesn't? */
1538 PatBlt( hdc, i & 0xfffffffe,
1539 rect.top + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER),
1540 i%2 + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
1541 rect.bottom - rect.top, 0x00a000c9 );
1542 i = rect.bottom;
1543 PatBlt( hdc, rect.left + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
1544 i & 0xfffffffe,rect.right - rect.left,
1545 i%2 + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER), 0x00a000c9 );
1546 SelectObject( hdc, hPrevPen );
1547 SelectObject( hdc, hPrevBrush );
1548 SetROP2( hdc, ropPrev );
1549 }
1550 else
1551 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
1552
1553 /* draw menu items */
1554
1555 menu = MENU_GetMenu( hmenu );
1556 if (menu && menu->nItems)
1557 {
1558 MENUITEM *item;
1559 UINT u;
1560
1561 for (u = menu->nItems, item = menu->items; u > 0; u--, item++)
1562 MENU_DrawMenuItem( hwnd, hmenu, menu->hwndOwner, hdc, item,
1563 menu->Height, FALSE, ODA_DRAWENTIRE );
1564
1565 }
1566 } else
1567 {
1568 SelectObject( hdc, hPrevBrush );
1569 }
1570 }
1571}
1572
1573/***********************************************************************
1574 * MENU_DrawMenuBar
1575 *
1576 * Paint a menu bar. Returns the height of the menu bar.
1577 * called from [windows/nonclient.c]
1578 */
1579UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
1580 BOOL suppress_draw)
1581{
1582 LPPOPUPMENU lppop;
1583 UINT i,retvalue;
1584 HFONT hfontOld = 0;
1585 HMENU hMenu = GetMenu(hwnd);
1586
1587 lppop = MENU_GetMenu( hMenu );
1588 if (lppop == NULL || lprect == NULL)
1589 {
1590 retvalue = GetSystemMetrics(SM_CYMENU);
1591 goto END;
1592 }
1593
1594 TRACE("(%04x, %p, %p)\n", hDC, lprect, lppop);
1595
1596 hfontOld = SelectObject( hDC, hMenuFont);
1597
1598 if (lppop->Height == 0)
1599 MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
1600
1601 lprect->bottom = lprect->top + lppop->Height;
1602
1603 if (suppress_draw)
1604 {
1605 retvalue = lppop->Height;
1606 goto END;
1607 }
1608
1609 FillRect(hDC, lprect, GetSysColorBrush(COLOR_MENU) );
1610
1611 if (TWEAK_WineLook == WIN31_LOOK)
1612 {
1613 SelectObject( hDC, GetSysColorPen(COLOR_WINDOWFRAME) );
1614 MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
1615 LineTo( hDC, lprect->right, lprect->bottom );
1616 }
1617 else
1618 {
1619 SelectObject( hDC, GetSysColorPen(COLOR_3DFACE));
1620 MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
1621 LineTo( hDC, lprect->right, lprect->bottom );
1622 }
1623
1624 if (lppop->nItems == 0)
1625 {
1626 retvalue = GetSystemMetrics(SM_CYMENU);
1627 goto END;
1628 }
1629
1630 for (i = 0; i < lppop->nItems; i++)
1631 {
1632 MENU_DrawMenuItem( hwnd, hMenu, hwnd,
1633 hDC, &lppop->items[i], lppop->Height, TRUE, ODA_DRAWENTIRE );
1634 }
1635 retvalue = lppop->Height;
1636
1637END:
1638 if (hfontOld) SelectObject (hDC, hfontOld);
1639 return retvalue;
1640}
1641
1642
1643/***********************************************************************
1644 * MENU_ShowPopup
1645 *
1646 * Display a popup menu.
1647 */
1648static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id,
1649 INT x, INT y, INT xanchor, INT yanchor )
1650{
1651 POPUPMENU *menu;
1652 UINT width, height;
1653
1654 TRACE("owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1655 hwndOwner, hmenu, id, x, y, xanchor, yanchor);
1656
1657 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
1658 if (menu->FocusedItem != NO_SELECTED_ITEM)
1659 {
1660 menu->items[menu->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1661 menu->FocusedItem = NO_SELECTED_ITEM;
1662 }
1663
1664 /* store the owner for DrawItem */
1665 menu->hwndOwner = hwndOwner;
1666
1667
1668 MENU_PopupMenuCalcSize( menu, hwndOwner );
1669
1670 /* adjust popup menu pos so that it fits within the desktop */
1671
1672 width = menu->Width + GetSystemMetrics(SM_CXBORDER);
1673 height = menu->Height + GetSystemMetrics(SM_CYBORDER);
1674
1675 if( x + width > GetSystemMetrics(SM_CXSCREEN ))
1676 {
1677 if( xanchor )
1678 x -= width - xanchor;
1679 if( x + width > GetSystemMetrics(SM_CXSCREEN))
1680 x = GetSystemMetrics(SM_CXSCREEN) - width;
1681 }
1682 if( x < 0 ) x = 0;
1683
1684 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1685 {
1686 if( yanchor )
1687 y -= height + yanchor;
1688 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1689 y = GetSystemMetrics(SM_CYSCREEN) - height;
1690 }
1691 if( y < 0 ) y = 0;
1692
1693 if( TWEAK_WineLook == WIN31_LOOK )
1694 {
1695 width += POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER); /* add space for shading */
1696 height += POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
1697 }
1698
1699 /* NOTE: In Windows, top menu popup is not owned. */
1700 menu->hWnd = CreateWindowA( POPUPMENU_CLASS_ATOM, NULL,
1701 WS_POPUP, x, y, width, height,
1702 hwndOwner, 0, GetWindowLongA(hwndOwner,GWL_HINSTANCE),
1703 (LPVOID)hmenu );
1704 if( !menu->hWnd ) return FALSE;
1705 if (!top_popup) top_popup = menu->hWnd;
1706
1707 /* Display the window */
1708
1709 SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
1710 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
1711 UpdateWindow( menu->hWnd );
1712 return TRUE;
1713}
1714
1715
1716/***********************************************************************
1717 * MENU_SelectItem
1718 */
1719static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex,
1720 BOOL sendMenuSelect, HMENU topmenu )
1721{
1722 LPPOPUPMENU lppop;
1723 HDC hdc;
1724
1725 TRACE("owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
1726
1727 lppop = MENU_GetMenu( hmenu );
1728 if ((!lppop) || (!lppop->nItems) || (!lppop->hWnd)) return;
1729
1730 if (lppop->FocusedItem == wIndex) return;
1731 if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
1732 else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
1733
1734 SelectObject( hdc, hMenuFont);
1735
1736 /* Clear previous highlighted item */
1737 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1738 {
1739 lppop->items[lppop->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1740 MENU_DrawMenuItem(lppop->hWnd, hmenu, hwndOwner, hdc,&lppop->items[lppop->FocusedItem],
1741 lppop->Height, !(lppop->wFlags & MF_POPUP),
1742 ODA_SELECT );
1743 }
1744
1745 /* Highlight new item (if any) */
1746 lppop->FocusedItem = wIndex;
1747 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1748 {
1749 if(!(lppop->items[wIndex].fType & MF_SEPARATOR)) {
1750 lppop->items[wIndex].fState |= MF_HILITE;
1751 MENU_DrawMenuItem( lppop->hWnd, hmenu, hwndOwner, hdc,
1752 &lppop->items[wIndex], lppop->Height,
1753 !(lppop->wFlags & MF_POPUP), ODA_SELECT );
1754 }
1755 if (sendMenuSelect)
1756 {
1757 MENUITEM *ip = &lppop->items[lppop->FocusedItem];
1758 SendMessageA( hwndOwner, WM_MENUSELECT,
1759 MAKELONG(ip->fType & MF_POPUP ? wIndex: ip->wID,
1760 ip->fType | ip->fState | MF_MOUSESELECT |
1761 (lppop->wFlags & MF_SYSMENU)), hmenu);
1762 }
1763 }
1764 else if (sendMenuSelect) {
1765 if(topmenu){
1766 int pos;
1767 if((pos=MENU_FindSubMenu(&topmenu, hmenu))!=NO_SELECTED_ITEM){
1768 POPUPMENU *ptm = MENU_GetMenu( topmenu );
1769 MENUITEM *ip = &ptm->items[pos];
1770 SendMessageA( hwndOwner, WM_MENUSELECT, MAKELONG(pos,
1771 ip->fType | ip->fState | MF_MOUSESELECT |
1772 (ptm->wFlags & MF_SYSMENU)), topmenu);
1773 }
1774 }
1775 }
1776 ReleaseDC( lppop->hWnd, hdc );
1777}
1778
1779
1780/***********************************************************************
1781 * MENU_MoveSelection
1782 *
1783 * Moves currently selected item according to the offset parameter.
1784 * If there is no selection then it should select the last item if
1785 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1786 */
1787static void MENU_MoveSelection( HWND hwndOwner, HMENU hmenu, INT offset )
1788{
1789 INT i;
1790 POPUPMENU *menu;
1791
1792 TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner, hmenu, offset);
1793
1794 menu = MENU_GetMenu( hmenu );
1795 if ((!menu) || (!menu->items)) return;
1796
1797 if ( menu->FocusedItem != NO_SELECTED_ITEM )
1798 {
1799 if( menu->nItems == 1 ) return; else
1800 for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems
1801 ; i += offset)
1802 if (!(menu->items[i].fType & MF_SEPARATOR))
1803 {
1804 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1805 return;
1806 }
1807 }
1808
1809 for ( i = (offset > 0) ? 0 : menu->nItems - 1;
1810 i >= 0 && i < menu->nItems ; i += offset)
1811 if (!(menu->items[i].fType & MF_SEPARATOR))
1812 {
1813 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1814 return;
1815 }
1816}
1817
1818
1819/**********************************************************************
1820 * MENU_SetItemData
1821 *
1822 * Set an item flags, id and text ptr. Called by InsertMenu() and
1823 * ModifyMenu().
1824 */
1825static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT id,
1826 LPCWSTR str )
1827{
1828 LPWSTR prevText = IS_STRING_ITEM(item->fType) ? item->text : NULL;
1829
1830 debug_print_menuitem("MENU_SetItemData from: ", item, "");
1831 TRACE("flags=%x str=%p\n", flags, str);
1832
1833 if (IS_STRING_ITEM(flags))
1834 {
1835 if (!str)
1836 {
1837 flags |= MF_SEPARATOR;
1838 item->text = NULL;
1839 }
1840 else
1841 {
1842 LPWSTR text;
1843 /* Item beginning with a backspace is a help item */
1844 if (*str == '\b')
1845 {
1846 flags |= MF_HELP;
1847 str++;
1848 }
1849 if (!(text = HeapAlloc( GetProcessHeap(), 0, (strlenW(str)+1) * sizeof(WCHAR) )))
1850 return FALSE;
1851 strcpyW( text, str );
1852 item->text = text;
1853 }
1854 }
1855 else if (IS_BITMAP_ITEM(flags))
1856 item->text = (LPWSTR)(HBITMAP)LOWORD(str);
1857 else item->text = NULL;
1858
1859 if (flags & MF_OWNERDRAW)
1860 item->dwItemData = (DWORD)str;
1861 else
1862 item->dwItemData = 0;
1863
1864 if ((item->fType & MF_POPUP) && (flags & MF_POPUP) && (item->hSubMenu != id) )
1865 DestroyMenu( item->hSubMenu ); /* ModifyMenu() spec */
1866
1867 if (flags & MF_POPUP)
1868 {
1869 POPUPMENU *menu = MENU_GetMenu((UINT16)id);
1870 if (menu) menu->wFlags |= MF_POPUP;
1871 else
1872 {
1873 item->wID = 0;
1874 item->hSubMenu = 0;
1875 item->fType = 0;
1876 item->fState = 0;
1877 return FALSE;
1878 }
1879 }
1880
1881 item->wID = id;
1882 if (flags & MF_POPUP)
1883 item->hSubMenu = id;
1884
1885 if ((item->fType & MF_POPUP) && !(flags & MF_POPUP) )
1886 flags |= MF_POPUP; /* keep popup */
1887
1888 item->fType = flags & TYPE_MASK;
1889 item->fState = (flags & STATE_MASK) &
1890 ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
1891
1892
1893 /* Don't call SetRectEmpty here! */
1894
1895
1896 if (prevText) HeapFree( GetProcessHeap(), 0, prevText );
1897
1898 debug_print_menuitem("MENU_SetItemData to : ", item, "");
1899 return TRUE;
1900}
1901
1902
1903/**********************************************************************
1904 * MENU_InsertItem
1905 *
1906 * Insert a new item into a menu.
1907 */
1908static MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
1909{
1910 MENUITEM *newItems;
1911 POPUPMENU *menu;
1912
1913 if (!(menu = MENU_GetMenu(hMenu)))
1914 return NULL;
1915
1916 /* Find where to insert new item */
1917
1918 if (flags & MF_BYPOSITION) {
1919 if (pos > menu->nItems)
1920 pos = menu->nItems;
1921 } else {
1922 if (!MENU_FindItem( &hMenu, &pos, flags ))
1923 pos = menu->nItems;
1924 else {
1925 if (!(menu = MENU_GetMenu( hMenu )))
1926 return NULL;
1927 }
1928 }
1929
1930 /* Create new items array */
1931
1932 newItems = HeapAlloc( GetProcessHeap(), 0, sizeof(MENUITEM) * (menu->nItems+1) );
1933 if (!newItems)
1934 {
1935 WARN("allocation failed\n" );
1936 return NULL;
1937 }
1938 if (menu->nItems > 0)
1939 {
1940 /* Copy the old array into the new one */
1941 if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
1942 if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
1943 (menu->nItems-pos)*sizeof(MENUITEM) );
1944 HeapFree( GetProcessHeap(), 0, menu->items );
1945 }
1946 menu->items = newItems;
1947 menu->nItems++;
1948 memset( &newItems[pos], 0, sizeof(*newItems) );
1949 menu->Height = 0; /* force size recalculate */
1950 return &newItems[pos];
1951}
1952
1953
1954/**********************************************************************
1955 * MENU_ParseResource
1956 *
1957 * Parse a standard menu resource and add items to the menu.
1958 * Return a pointer to the end of the resource.
1959 */
1960static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
1961{
1962 WORD flags, id = 0;
1963 LPCSTR str;
1964
1965 do
1966 {
1967 flags = GET_WORD(res);
1968 res += sizeof(WORD);
1969 if (!(flags & MF_POPUP))
1970 {
1971 id = GET_WORD(res);
1972 res += sizeof(WORD);
1973 }
1974 str = res;
1975 if (!unicode) res += strlen(str) + 1;
1976 else res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
1977 if (flags & MF_POPUP)
1978 {
1979 HMENU hSubMenu = CreatePopupMenu();
1980 if (!hSubMenu) return NULL;
1981 if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
1982 return NULL;
1983 if (!unicode) AppendMenuA( hMenu, flags, (UINT)hSubMenu, str );
1984 else AppendMenuW( hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str );
1985 }
1986 else /* Not a popup */
1987 {
1988 if (!unicode) AppendMenuA( hMenu, flags, id, *str ? str : NULL );
1989 else AppendMenuW( hMenu, flags, id,
1990 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
1991 }
1992 } while (!(flags & MF_END));
1993 return res;
1994}
1995
1996
1997/**********************************************************************
1998 * MENUEX_ParseResource
1999 *
2000 * Parse an extended menu resource and add items to the menu.
2001 * Return a pointer to the end of the resource.
2002 */
2003static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
2004{
2005 WORD resinfo;
2006 do {
2007 MENUITEMINFOW mii;
2008
2009 mii.cbSize = sizeof(mii);
2010 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
2011 mii.fType = GET_DWORD(res);
2012 res += sizeof(DWORD);
2013 mii.fState = GET_DWORD(res);
2014 res += sizeof(DWORD);
2015 mii.wID = GET_DWORD(res);
2016 res += sizeof(DWORD);
2017 resinfo = GET_WORD(res); /* FIXME: for 16-bit apps this is a byte. */
2018 res += sizeof(WORD);
2019 /* Align the text on a word boundary. */
2020 res += (~((int)res - 1)) & 1;
2021 mii.dwTypeData = (LPWSTR) res;
2022 res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
2023 /* Align the following fields on a dword boundary. */
2024 res += (~((int)res - 1)) & 3;
2025
2026 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
2027 mii.fType, mii.fState, mii.wID, resinfo, debugstr_w(mii.dwTypeData));
2028
2029 if (resinfo & 1) { /* Pop-up? */
2030 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2031 res += sizeof(DWORD);
2032 mii.hSubMenu = CreatePopupMenu();
2033 if (!mii.hSubMenu)
2034 return NULL;
2035 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
2036 DestroyMenu(mii.hSubMenu);
2037 return NULL;
2038 }
2039 mii.fMask |= MIIM_SUBMENU;
2040 mii.fType |= MF_POPUP;
2041 }
2042 else if(!*mii.dwTypeData && !(mii.fType & MF_SEPARATOR))
2043 {
2044 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
2045 mii.wID, mii.fType);
2046 mii.fType |= MF_SEPARATOR;
2047 }
2048 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
2049 } while (!(resinfo & MF_END));
2050 return res;
2051}
2052
2053
2054/***********************************************************************
2055 * MENU_GetSubPopup
2056 *
2057 * Return the handle of the selected sub-popup menu (if any).
2058 */
2059static HMENU MENU_GetSubPopup( HMENU hmenu )
2060{
2061 POPUPMENU *menu;
2062 MENUITEM *item;
2063
2064 menu = MENU_GetMenu( hmenu );
2065
2066 if ((!menu) || (menu->FocusedItem == NO_SELECTED_ITEM)) return 0;
2067
2068 item = &menu->items[menu->FocusedItem];
2069 if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
2070 return item->hSubMenu;
2071 return 0;
2072}
2073
2074
2075/***********************************************************************
2076 * MENU_HideSubPopups
2077 *
2078 * Hide the sub-popup menus of this menu.
2079 */
2080static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
2081 BOOL sendMenuSelect )
2082{
2083 POPUPMENU *menu = MENU_GetMenu( hmenu );
2084
2085 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, sendMenuSelect);
2086
2087 if (menu && top_popup)
2088 {
2089 HMENU hsubmenu;
2090 POPUPMENU *submenu;
2091 MENUITEM *item;
2092
2093 if (menu->FocusedItem != NO_SELECTED_ITEM)
2094 {
2095 item = &menu->items[menu->FocusedItem];
2096 if (!(item->fType & MF_POPUP) ||
2097 !(item->fState & MF_MOUSESELECT)) return;
2098 item->fState &= ~MF_MOUSESELECT;
2099 hsubmenu = item->hSubMenu;
2100 } else return;
2101
2102 submenu = MENU_GetMenu( hsubmenu );
2103 MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
2104 MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect, 0 );
2105 DestroyWindow( submenu->hWnd );
2106 submenu->hWnd = 0;
2107 }
2108}
2109
2110
2111/***********************************************************************
2112 * MENU_ShowSubPopup
2113 *
2114 * Display the sub-menu of the selected item of this menu.
2115 * Return the handle of the submenu, or hmenu if no submenu to display.
2116 */
2117static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu,
2118 BOOL selectFirst, UINT wFlags )
2119{
2120 RECT rect;
2121 POPUPMENU *menu;
2122 MENUITEM *item;
2123 HDC hdc;
2124
2125 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, selectFirst);
2126
2127 if (!(menu = MENU_GetMenu( hmenu ))) return hmenu;
2128
2129 if (menu->FocusedItem == NO_SELECTED_ITEM) return hmenu;
2130
2131 item = &menu->items[menu->FocusedItem];
2132 if (!(item->fType & MF_POPUP) || (item->fState & (MF_GRAYED | MF_DISABLED)))
2133 return hmenu;
2134
2135 /* message must be sent before using item,
2136 because nearly everything may be changed by the application ! */
2137
2138 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2139 if (!(wFlags & TPM_NONOTIFY))
2140 SendMessageA( hwndOwner, WM_INITMENUPOPUP, item->hSubMenu,
2141 MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));
2142
2143 item = &menu->items[menu->FocusedItem];
2144 rect = item->rect;
2145
2146 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2147 if (!(item->fState & MF_HILITE))
2148 {
2149 if (menu->wFlags & MF_POPUP) hdc = GetDC( menu->hWnd );
2150 else hdc = GetDCEx( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
2151
2152 SelectObject( hdc, hMenuFont);
2153
2154 item->fState |= MF_HILITE;
2155 MENU_DrawMenuItem( menu->hWnd, hmenu, hwndOwner, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP), ODA_DRAWENTIRE );
2156 ReleaseDC( menu->hWnd, hdc );
2157 }
2158 if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right)
2159 item->rect = rect;
2160
2161 item->fState |= MF_MOUSESELECT;
2162
2163 if (IS_SYSTEM_MENU(menu))
2164 {
2165 MENU_InitSysMenuPopup(item->hSubMenu,
2166 GetWindowLongA( menu->hWnd, GWL_STYLE ),
2167 GetClassLongA( menu->hWnd, GCL_STYLE));
2168
2169 NC_GetSysPopupPos( menu->hWnd, &rect );
2170 rect.top = rect.bottom;
2171 rect.right = GetSystemMetrics(SM_CXSIZE);
2172 rect.bottom = GetSystemMetrics(SM_CYSIZE);
2173 }
2174 else
2175 {
2176 GetWindowRect( menu->hWnd, &rect );
2177 if (menu->wFlags & MF_POPUP)
2178 {
2179 rect.left += item->rect.right - GetSystemMetrics(SM_CXBORDER);
2180 rect.top += item->rect.top;
2181 rect.right = item->rect.left - item->rect.right + GetSystemMetrics(SM_CXBORDER);
2182 rect.bottom = item->rect.top - item->rect.bottom;
2183 }
2184 else
2185 {
2186 rect.left += item->rect.left;
2187 rect.top += item->rect.bottom;
2188 rect.right = item->rect.right - item->rect.left;
2189 rect.bottom = item->rect.bottom - item->rect.top;
2190 }
2191 }
2192
2193 MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem,
2194 rect.left, rect.top, rect.right, rect.bottom );
2195 if (selectFirst)
2196 MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT );
2197 return item->hSubMenu;
2198}
2199
2200
2201
2202/**********************************************************************
2203 * MENU_IsMenuActive
2204 */
2205BOOL MENU_IsMenuActive(void)
2206{
2207 return (top_popup != 0);
2208}
2209
2210/***********************************************************************
2211 * MENU_PtMenu
2212 *
2213 * Walks menu chain trying to find a menu pt maps to.
2214 */
2215static HMENU MENU_PtMenu( HMENU hMenu, POINT pt )
2216{
2217 POPUPMENU *menu = MENU_GetMenu( hMenu );
2218 UINT item = menu->FocusedItem;
2219 HMENU ret;
2220
2221 /* try subpopup first (if any) */
2222 ret = (item != NO_SELECTED_ITEM &&
2223 (menu->items[item].fType & MF_POPUP) &&
2224 (menu->items[item].fState & MF_MOUSESELECT))
2225 ? MENU_PtMenu(menu->items[item].hSubMenu, pt) : 0;
2226
2227 if (!ret) /* check the current window (avoiding WM_HITTEST) */
2228 {
2229 INT ht = NC_HandleNCHitTest( menu->hWnd, pt );
2230 if( menu->wFlags & MF_POPUP )
2231 {
2232 if (ht != HTNOWHERE && ht != HTERROR) ret = hMenu;
2233 }
2234 else if (ht == HTSYSMENU)
2235 ret = get_win_sys_menu( menu->hWnd );
2236 else if (ht == HTMENU)
2237 ret = GetMenu( menu->hWnd );
2238 }
2239 return ret;
2240}
2241
2242/***********************************************************************
2243 * MENU_ExecFocusedItem
2244 *
2245 * Execute a menu item (for instance when user pressed Enter).
2246 * Return the wID of the executed item. Otherwise, -1 indicating
2247 * that no menu item was executed;
2248 * Have to receive the flags for the TrackPopupMenu options to avoid
2249 * sending unwanted message.
2250 *
2251 */
2252static INT MENU_ExecFocusedItem( MTRACKER* pmt, HMENU hMenu, UINT wFlags )
2253{
2254 MENUITEM *item;
2255 POPUPMENU *menu = MENU_GetMenu( hMenu );
2256
2257 TRACE("%p hmenu=0x%04x\n", pmt, hMenu);
2258
2259 if (!menu || !menu->nItems ||
2260 (menu->FocusedItem == NO_SELECTED_ITEM)) return -1;
2261
2262 item = &menu->items[menu->FocusedItem];
2263
2264 TRACE("%08x %08x %08x\n",
2265 hMenu, item->wID, item->hSubMenu);
2266
2267 if (!(item->fType & MF_POPUP))
2268 {
2269 if (!(item->fState & (MF_GRAYED | MF_DISABLED)) && !(item->fType & MF_SEPARATOR))
2270 {
2271 /* If TPM_RETURNCMD is set you return the id, but
2272 do not send a message to the owner */
2273 if(!(wFlags & TPM_RETURNCMD))
2274 {
2275 if( menu->wFlags & MF_SYSMENU )
2276 PostMessageA( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
2277 MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
2278 else
2279 PostMessageA( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 );
2280 }
2281 return item->wID;
2282 }
2283 }
2284 else
2285 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hMenu, TRUE, wFlags);
2286
2287 return -1;
2288}
2289
2290/***********************************************************************
2291 * MENU_SwitchTracking
2292 *
2293 * Helper function for menu navigation routines.
2294 */
2295static void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id )
2296{
2297 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2298 POPUPMENU *topmenu = MENU_GetMenu( pmt->hTopMenu );
2299
2300 TRACE("%p hmenu=0x%04x 0x%04x\n", pmt, hPtMenu, id);
2301
2302 if( pmt->hTopMenu != hPtMenu &&
2303 !((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
2304 {
2305 /* both are top level menus (system and menu-bar) */
2306 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2307 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2308 pmt->hTopMenu = hPtMenu;
2309 }
2310 else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
2311 MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE, 0 );
2312}
2313
2314
2315/***********************************************************************
2316 * MENU_ButtonDown
2317 *
2318 * Return TRUE if we can go on with menu tracking.
2319 */
2320static BOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2321{
2322 TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2323
2324 if (hPtMenu)
2325 {
2326 UINT id = 0;
2327 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2328 MENUITEM *item;
2329
2330 if( IS_SYSTEM_MENU(ptmenu) )
2331 item = ptmenu->items;
2332 else
2333 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2334
2335 if( item )
2336 {
2337 if( ptmenu->FocusedItem != id )
2338 MENU_SwitchTracking( pmt, hPtMenu, id );
2339
2340 /* If the popup menu is not already "popped" */
2341 if(!(item->fState & MF_MOUSESELECT ))
2342 {
2343 pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE, wFlags );
2344
2345 /* In win31, a newly popped menu always remains opened for the next buttonup */
2346#ifdef __WIN32OS2__
2347 if(fOS2Look)
2348 ptmenu->bTimeToHide = FALSE;
2349#endif
2350 if(TWEAK_WineLook == WIN31_LOOK)
2351 ptmenu->bTimeToHide = FALSE;
2352 }
2353
2354 return TRUE;
2355 }
2356 /* Else the click was on the menu bar, finish the tracking */
2357 }
2358 return FALSE;
2359}
2360
2361/***********************************************************************
2362 * MENU_ButtonUp
2363 *
2364 * Return the value of MENU_ExecFocusedItem if
2365 * the selected item was not a popup. Else open the popup.
2366 * A -1 return value indicates that we go on with menu tracking.
2367 *
2368 */
2369static INT MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags)
2370{
2371 TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2372
2373 if (hPtMenu)
2374 {
2375 UINT id = 0;
2376 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2377 MENUITEM *item;
2378
2379 if( IS_SYSTEM_MENU(ptmenu) )
2380 item = ptmenu->items;
2381 else
2382 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2383
2384 if( item && (ptmenu->FocusedItem == id ))
2385 {
2386 if( !(item->fType & MF_POPUP) )
2387 return MENU_ExecFocusedItem( pmt, hPtMenu, wFlags);
2388
2389 /* If we are dealing with the top-level menu */
2390 /* and this is a click on an already "popped" item: */
2391 /* Stop the menu tracking and close the opened submenus */
2392 if((pmt->hTopMenu == hPtMenu) && (ptmenu->bTimeToHide == TRUE))
2393 return 0;
2394 }
2395 ptmenu->bTimeToHide = TRUE;
2396 }
2397 return -1;
2398}
2399
2400
2401/***********************************************************************
2402 * MENU_MouseMove
2403 *
2404 * Return TRUE if we can go on with menu tracking.
2405 */
2406static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2407{
2408 UINT id = NO_SELECTED_ITEM;
2409 POPUPMENU *ptmenu = NULL;
2410
2411 if( hPtMenu )
2412 {
2413 ptmenu = MENU_GetMenu( hPtMenu );
2414 if( IS_SYSTEM_MENU(ptmenu) )
2415 id = 0;
2416 else
2417 MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2418 }
2419
2420 if( id == NO_SELECTED_ITEM )
2421 {
2422 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2423 NO_SELECTED_ITEM, TRUE, pmt->hTopMenu);
2424
2425 }
2426 else if( ptmenu->FocusedItem != id )
2427 {
2428 MENU_SwitchTracking( pmt, hPtMenu, id );
2429 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hPtMenu, FALSE, wFlags);
2430 }
2431 return TRUE;
2432}
2433
2434
2435/***********************************************************************
2436 * MENU_DoNextMenu
2437 *
2438 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2439 */
2440static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
2441{
2442 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2443
2444 if( (vk == VK_LEFT && menu->FocusedItem == 0 ) ||
2445 (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
2446 {
2447 MDINEXTMENU next_menu;
2448 HMENU hNewMenu;
2449 HWND hNewWnd;
2450 UINT id = 0;
2451
2452 next_menu.hmenuIn = (IS_SYSTEM_MENU(menu)) ? GetSubMenu(pmt->hTopMenu,0) : pmt->hTopMenu;
2453 next_menu.hmenuNext = 0;
2454 next_menu.hwndNext = 0;
2455 SendMessageW( pmt->hOwnerWnd, WM_NEXTMENU, vk, (LPARAM)&next_menu );
2456
2457 TRACE("%04x [%04x] -> %04x [%04x]\n",
2458 pmt->hCurrentMenu, pmt->hOwnerWnd, next_menu.hmenuNext, next_menu.hwndNext );
2459
2460 if (!next_menu.hmenuNext || !next_menu.hwndNext)
2461 {
2462 DWORD style = GetWindowLongA( pmt->hOwnerWnd, GWL_STYLE );
2463 hNewWnd = pmt->hOwnerWnd;
2464 if( IS_SYSTEM_MENU(menu) )
2465 {
2466 /* switch to the menu bar */
2467
2468 if(style & WS_CHILD || !(hNewMenu = GetMenu(hNewWnd))) return FALSE;
2469
2470 if( vk == VK_LEFT )
2471 {
2472 menu = MENU_GetMenu( hNewMenu );
2473 id = menu->nItems - 1;
2474 }
2475 }
2476 else if (style & WS_SYSMENU )
2477 {
2478 /* switch to the system menu */
2479 hNewMenu = get_win_sys_menu( hNewWnd );
2480 }
2481 else return FALSE;
2482 }
2483 else /* application returned a new menu to switch to */
2484 {
2485 hNewMenu = next_menu.hmenuNext;
2486 hNewWnd = WIN_GetFullHandle( next_menu.hwndNext );
2487
2488 if( IsMenu(hNewMenu) && IsWindow(hNewWnd) )
2489 {
2490 DWORD style = GetWindowLongA( hNewWnd, GWL_STYLE );
2491
2492 if (style & WS_SYSMENU &&
2493 GetSubMenu(get_win_sys_menu(hNewWnd), 0) == hNewMenu )
2494 {
2495 /* get the real system menu */
2496 hNewMenu = get_win_sys_menu(hNewWnd);
2497 }
2498 else if (style & WS_CHILD || GetMenu(hNewWnd) != hNewMenu )
2499 {
2500 /* FIXME: Not sure what to do here;
2501 * perhaps try to track hNewMenu as a popup? */
2502
2503 TRACE(" -- got confused.\n");
2504 return FALSE;
2505 }
2506 }
2507 else return FALSE;
2508 }
2509
2510 if( hNewMenu != pmt->hTopMenu )
2511 {
2512 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM,
2513 FALSE, 0 );
2514 if( pmt->hCurrentMenu != pmt->hTopMenu )
2515 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2516 }
2517
2518 if( hNewWnd != pmt->hOwnerWnd )
2519 {
2520 ReleaseCapture();
2521 pmt->hOwnerWnd = hNewWnd;
2522#ifdef __WIN32OS2__
2523 SetCapture(pmt->hOwnerWnd); //SvL: Don't know if this is good enough
2524#else
2525 EVENT_Capture( pmt->hOwnerWnd, HTMENU );
2526#endif
2527 }
2528
2529 pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
2530 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE, 0 );
2531
2532 return TRUE;
2533 }
2534 return FALSE;
2535}
2536
2537/***********************************************************************
2538 * MENU_SuspendPopup
2539 *
2540 * The idea is not to show the popup if the next input message is
2541 * going to hide it anyway.
2542 */
2543static BOOL MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
2544{
2545 MSG msg;
2546
2547 msg.hwnd = pmt->hOwnerWnd;
2548
2549 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2550 pmt->trackFlags |= TF_SKIPREMOVE;
2551
2552 switch( uMsg )
2553 {
2554 case WM_KEYDOWN:
2555 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2556 if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
2557 {
2558 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2559 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2560 if( msg.message == WM_KEYDOWN &&
2561 (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
2562 {
2563 pmt->trackFlags |= TF_SUSPENDPOPUP;
2564 return TRUE;
2565 }
2566 }
2567 break;
2568 }
2569
2570 /* failures go through this */
2571 pmt->trackFlags &= ~TF_SUSPENDPOPUP;
2572 return FALSE;
2573}
2574
2575/***********************************************************************
2576 * MENU_KeyEscape
2577 *
2578 * Handle a VK_ESCAPE key event in a menu.
2579 */
2580static BOOL MENU_KeyEscape(MTRACKER* pmt, UINT wFlags)
2581{
2582 BOOL bEndMenu = TRUE;
2583
2584 if (pmt->hCurrentMenu != pmt->hTopMenu)
2585 {
2586 POPUPMENU *menu = MENU_GetMenu(pmt->hCurrentMenu);
2587
2588 if (menu->wFlags & MF_POPUP)
2589 {
2590 HMENU hmenutmp, hmenuprev;
2591
2592 hmenuprev = hmenutmp = pmt->hTopMenu;
2593
2594 /* close topmost popup */
2595 while (hmenutmp != pmt->hCurrentMenu)
2596 {
2597 hmenuprev = hmenutmp;
2598 hmenutmp = MENU_GetSubPopup( hmenuprev );
2599 }
2600
2601 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2602 pmt->hCurrentMenu = hmenuprev;
2603 bEndMenu = FALSE;
2604 }
2605 }
2606
2607 return bEndMenu;
2608}
2609
2610/***********************************************************************
2611 * MENU_KeyLeft
2612 *
2613 * Handle a VK_LEFT key event in a menu.
2614 */
2615static void MENU_KeyLeft( MTRACKER* pmt, UINT wFlags )
2616{
2617 POPUPMENU *menu;
2618 HMENU hmenutmp, hmenuprev;
2619 UINT prevcol;
2620
2621 hmenuprev = hmenutmp = pmt->hTopMenu;
2622 menu = MENU_GetMenu( hmenutmp );
2623
2624 /* Try to move 1 column left (if possible) */
2625 if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) !=
2626 NO_SELECTED_ITEM ) {
2627
2628 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2629 prevcol, TRUE, 0 );
2630 return;
2631 }
2632
2633 /* close topmost popup */
2634 while (hmenutmp != pmt->hCurrentMenu)
2635 {
2636 hmenuprev = hmenutmp;
2637 hmenutmp = MENU_GetSubPopup( hmenuprev );
2638 }
2639
2640 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2641 pmt->hCurrentMenu = hmenuprev;
2642
2643 if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
2644 {
2645 /* move menu bar selection if no more popups are left */
2646
2647 if( !MENU_DoNextMenu( pmt, VK_LEFT) )
2648 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
2649
2650 if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2651 {
2652 /* A sublevel menu was displayed - display the next one
2653 * unless there is another displacement coming up */
2654
2655 if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
2656 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2657 pmt->hTopMenu, TRUE, wFlags);
2658 }
2659 }
2660}
2661
2662
2663/***********************************************************************
2664 * MENU_KeyRight
2665 *
2666 * Handle a VK_RIGHT key event in a menu.
2667 */
2668static void MENU_KeyRight( MTRACKER* pmt, UINT wFlags )
2669{
2670 HMENU hmenutmp;
2671 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2672 UINT nextcol;
2673
2674 TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2675 pmt->hCurrentMenu,
2676 debugstr_w((MENU_GetMenu(pmt->hCurrentMenu))->
2677 items[0].text),
2678 pmt->hTopMenu, debugstr_w(menu->items[0].text) );
2679
2680 if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
2681 {
2682 /* If already displaying a popup, try to display sub-popup */
2683
2684 hmenutmp = pmt->hCurrentMenu;
2685 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hmenutmp, TRUE, wFlags);
2686
2687 /* if subpopup was displayed then we are done */
2688 if (hmenutmp != pmt->hCurrentMenu) return;
2689 }
2690
2691 /* Check to see if there's another column */
2692 if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) !=
2693 NO_SELECTED_ITEM ) {
2694 TRACE("Going to %d.\n", nextcol );
2695 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2696 nextcol, TRUE, 0 );
2697 return;
2698 }
2699
2700 if (!(menu->wFlags & MF_POPUP)) /* menu bar tracking */
2701 {
2702 if( pmt->hCurrentMenu != pmt->hTopMenu )
2703 {
2704 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2705 hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
2706 } else hmenutmp = 0;
2707
2708 /* try to move to the next item */
2709 if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
2710 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );
2711
2712 if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2713 if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
2714 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2715 pmt->hTopMenu, TRUE, wFlags);
2716 }
2717}
2718
2719/***********************************************************************
2720 * MENU_TrackMenu
2721 *
2722 * Menu tracking code.
2723 */
2724static INT MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y,
2725 HWND hwnd, const RECT *lprect )
2726{
2727 MSG msg;
2728 POPUPMENU *menu;
2729 BOOL fRemove;
2730 INT executedMenuId = -1;
2731 MTRACKER mt;
2732 BOOL enterIdleSent = FALSE;
2733#ifdef __WIN32OS2__
2734 BOOL bSysMenu = FALSE;
2735#endif
2736
2737 mt.trackFlags = 0;
2738 mt.hCurrentMenu = hmenu;
2739 mt.hTopMenu = hmenu;
2740 mt.hOwnerWnd = WIN_GetFullHandle( hwnd );
2741 mt.pt.x = x;
2742 mt.pt.y = y;
2743
2744 TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2745 hmenu, wFlags, x, y, hwnd, (lprect) ? lprect->left : 0, (lprect) ? lprect->top : 0,
2746 (lprect) ? lprect->right : 0, (lprect) ? lprect->bottom : 0);
2747
2748 fEndMenu = FALSE;
2749 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
2750
2751 if (wFlags & TPM_BUTTONDOWN)
2752 {
2753 /* Get the result in order to start the tracking or not */
2754 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2755 fEndMenu = !fRemove;
2756 }
2757
2758#ifdef __WIN32OS2__
2759 bSysMenu = IS_SYSTEM_MENU(menu);
2760
2761 //SvL: Set keyboard & mouse event capture
2762 SetCapture(mt.hOwnerWnd);
2763 //SetCapture breaks system menu (double click), must generate double
2764 //clicks manually
2765 OSLibSetMenuDoubleClick(TRUE);
2766#else
2767 EVENT_Capture( mt.hOwnerWnd, HTMENU );
2768#endif
2769 while (!fEndMenu)
2770 {
2771 menu = MENU_GetMenu( mt.hCurrentMenu );
2772 if (!menu) /* sometimes happens if I do a window manager close */
2773 break;
2774
2775 /* we have to keep the message in the queue until it's
2776 * clear that menu loop is not over yet. */
2777
2778 for (;;)
2779 {
2780 if (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
2781 {
2782#ifdef __WIN32OS2__
2783 //We need to get & remove the message immediately, otherwise
2784 //we'll run into an Odin msg handling limitation (see oslibmsg.cpp todo's)
2785 GetMessageA(&msg, 0, 0, 0);
2786#endif
2787 if (!CallMsgFilterA( &msg, MSGF_MENU )) break;
2788 /* remove the message from the queue */
2789#ifndef __WIN32OS2__
2790 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2791#endif
2792 }
2793 else
2794 {
2795 if (!enterIdleSent)
2796 {
2797 HWND win = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
2798 enterIdleSent = TRUE;
2799 SendMessageW( mt.hOwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM)win );
2800 }
2801 WaitMessage();
2802 }
2803 }
2804
2805 /* check if EndMenu() tried to cancel us, by posting this message */
2806 if(msg.message == WM_CANCELMODE)
2807 {
2808 /* we are now out of the loop */
2809 fEndMenu = TRUE;
2810
2811#ifdef __WIN32OS2__
2812 /* remove the message from the queue */
2813 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2814#endif
2815 /* break out of internal loop, ala ESCAPE */
2816 break;
2817 }
2818
2819 TranslateMessage( &msg );
2820 mt.pt = msg.pt;
2821
2822 if ( (msg.hwnd==menu->hWnd) || (msg.message!=WM_TIMER) )
2823 enterIdleSent=FALSE;
2824
2825 fRemove = FALSE;
2826 if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
2827 {
2828 /*
2829 * use the mouse coordinates in lParam instead of those in the MSG
2830 * struct to properly handle synthetic messages. lParam coords are
2831 * relative to client area, so they must be converted; since they can
2832 * be negative, we must use SLOWORD/SHIWORD instead of LOWORD/HIWORD.
2833 */
2834 mt.pt.x = SLOWORD(msg.lParam);
2835 mt.pt.y = SHIWORD(msg.lParam);
2836#ifdef __WIN32OS2__
2837 //This MUST be here (in Rewind, but not in Wine)
2838#endif
2839 ClientToScreen(msg.hwnd,&mt.pt);
2840
2841 /* Find a menu for this mouse event */
2842 hmenu = MENU_PtMenu( mt.hTopMenu, mt.pt );
2843
2844 switch(msg.message)
2845 {
2846 /* no WM_NC... messages in captured state */
2847
2848 case WM_RBUTTONDBLCLK:
2849 case WM_RBUTTONDOWN:
2850#ifdef __WIN32OS2__
2851 if (!(wFlags & TPM_RIGHTBUTTON)) {
2852 MENUITEM *item;
2853 UINT id = 0;
2854
2855 if( IS_SYSTEM_MENU(menu) )
2856 item = menu->items;
2857 else
2858 item = MENU_FindItemByCoords( menu, mt.pt, &id );
2859 //@@PF If our pointer is over the menu - do nothing
2860 if (item) break;
2861 //@@PF Time to close menu - win2k&98 checked
2862 fEndMenu = 1;
2863 break;
2864 }
2865 goto buttondown;
2866#else
2867 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2868#endif
2869 /* fall through */
2870 case WM_LBUTTONDBLCLK:
2871#ifdef __WIN32OS2__
2872 if (bSysMenu && (hmenu == mt.hTopMenu))
2873 {
2874 //double click on system menu -> close application
2875 if (!(GetClassLongA(hwnd, GCL_STYLE) & CS_NOCLOSE)) {
2876 PostMessageA(hwnd, WM_SYSCOMMAND, SC_CLOSE, msg.lParam);
2877 fEndMenu = TRUE;
2878 break;
2879 }
2880 }
2881 if(IsIconic(hwnd)) {
2882 //double click on minimized icon -> restore parent window
2883 PostMessageA(hwnd, WM_SYSCOMMAND,SC_RESTORE, msg.lParam);
2884 fEndMenu = TRUE;
2885 break;
2886 }
2887 //fall through
2888buttondown:
2889
2890#endif
2891 case WM_LBUTTONDOWN:
2892 /* If the message belongs to the menu, removes it from the queue */
2893 /* Else, end menu tracking */
2894 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2895 fEndMenu = !fRemove;
2896 break;
2897
2898 case WM_RBUTTONUP:
2899 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2900 /* fall through */
2901 case WM_LBUTTONUP:
2902 /* Check if a menu was selected by the mouse */
2903 if (hmenu)
2904 {
2905 executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);
2906
2907 /* End the loop if executedMenuId is an item ID */
2908 /* or if the job was done (executedMenuId = 0). */
2909 fEndMenu = fRemove = (executedMenuId != -1);
2910 }
2911 /* No menu was selected by the mouse */
2912 /* if the function was called by TrackPopupMenu, continue
2913 with the menu tracking. If not, stop it */
2914 else
2915 fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
2916
2917 break;
2918
2919 case WM_MOUSEMOVE:
2920 /* In win95 winelook, the selected menu item must be changed every time the
2921 mouse moves. In Win31 winelook, the mouse button has to be held down */
2922
2923#ifdef __WIN32OS2__
2924 if ( !fOS2Look ||
2925#else
2926 if ( (TWEAK_WineLook > WIN31_LOOK) ||
2927#endif
2928 ( (msg.wParam & MK_LBUTTON) ||
2929 ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON))) )
2930
2931 fEndMenu |= !MENU_MouseMove( &mt, hmenu, wFlags );
2932
2933 } /* switch(msg.message) - mouse */
2934 }
2935 else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
2936 {
2937 fRemove = TRUE; /* Keyboard messages are always removed */
2938 switch(msg.message)
2939 {
2940 case WM_KEYDOWN:
2941 switch(msg.wParam)
2942 {
2943 case VK_HOME:
2944 case VK_END:
2945 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu,
2946 NO_SELECTED_ITEM, FALSE, 0 );
2947 /* fall through */
2948 case VK_UP:
2949 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu,
2950 (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
2951 break;
2952
2953 case VK_DOWN: /* If on menu bar, pull-down the menu */
2954
2955 menu = MENU_GetMenu( mt.hCurrentMenu );
2956 if (!(menu->wFlags & MF_POPUP))
2957 mt.hCurrentMenu = MENU_ShowSubPopup(mt.hOwnerWnd, mt.hTopMenu, TRUE, wFlags);
2958 else /* otherwise try to move selection */
2959 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT );
2960 break;
2961
2962 case VK_LEFT:
2963 MENU_KeyLeft( &mt, wFlags );
2964 break;
2965
2966 case VK_RIGHT:
2967 MENU_KeyRight( &mt, wFlags );
2968 break;
2969
2970 case VK_ESCAPE:
2971 fEndMenu = MENU_KeyEscape(&mt, wFlags);
2972 break;
2973
2974 case VK_F1:
2975 {
2976 HELPINFO hi;
2977 hi.cbSize = sizeof(HELPINFO);
2978 hi.iContextType = HELPINFO_MENUITEM;
2979 if (menu->FocusedItem == NO_SELECTED_ITEM)
2980 hi.iCtrlId = 0;
2981 else
2982 hi.iCtrlId = menu->items[menu->FocusedItem].wID;
2983 hi.hItemHandle = hmenu;
2984 hi.dwContextId = menu->dwContextHelpID;
2985 hi.MousePos = msg.pt;
2986 SendMessageA(hwnd, WM_HELP, 0, (LPARAM)&hi);
2987 break;
2988 }
2989
2990 default:
2991 break;
2992 }
2993 break; /* WM_KEYDOWN */
2994
2995 case WM_SYSKEYDOWN:
2996 switch(msg.wParam)
2997 {
2998 case VK_MENU:
2999 fEndMenu = TRUE;
3000 break;
3001
3002 }
3003 break; /* WM_SYSKEYDOWN */
3004
3005 case WM_CHAR:
3006 {
3007 UINT pos;
3008
3009 if (msg.wParam == '\r' || msg.wParam == ' ')
3010 {
3011 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
3012 fEndMenu = (executedMenuId != -1);
3013
3014 break;
3015 }
3016
3017 /* Hack to avoid control chars. */
3018 /* We will find a better way real soon... */
3019 if ((msg.wParam <= 32) || (msg.wParam >= 127)) break;
3020
3021 pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu,
3022 LOWORD(msg.wParam), FALSE );
3023 if (pos == (UINT)-2) fEndMenu = TRUE;
3024 else if (pos == (UINT)-1) MessageBeep(0);
3025 else
3026 {
3027 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos,
3028 TRUE, 0 );
3029 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
3030 fEndMenu = (executedMenuId != -1);
3031 }
3032 }
3033 break;
3034 } /* switch(msg.message) - kbd */
3035 }
3036 else
3037 {
3038 DispatchMessageA( &msg );
3039 }
3040
3041 if (!fEndMenu) fRemove = TRUE;
3042
3043 /* finally remove message from the queue */
3044
3045 if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
3046#ifdef __WIN32OS2__
3047 ;
3048#else
3049 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
3050#endif
3051 else mt.trackFlags &= ~TF_SKIPREMOVE;
3052 }
3053
3054#ifdef __WIN32OS2__
3055 OSLibSetMenuDoubleClick(FALSE);
3056#endif
3057 ReleaseCapture();
3058
3059 /* If dropdown is still painted and the close box is clicked on
3060 then the menu will be destroyed as part of the DispatchMessage above.
3061 This will then invalidate the menu handle in mt.hTopMenu. We should
3062 check for this first. */
3063 if( IsMenu( mt.hTopMenu ) )
3064 {
3065 menu = MENU_GetMenu( mt.hTopMenu );
3066
3067 if( IsWindow( mt.hOwnerWnd ) )
3068 {
3069 MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
3070
3071 if (menu && menu->wFlags & MF_POPUP)
3072 {
3073 DestroyWindow( menu->hWnd );
3074 menu->hWnd = 0;
3075 }
3076 MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
3077 SendMessageA( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0xffff), 0 );
3078 }
3079
3080 /* Reset the variable for hiding menu */
3081 if( menu ) menu->bTimeToHide = FALSE;
3082 }
3083
3084 /* The return value is only used by TrackPopupMenu */
3085 return ((executedMenuId != -1) ? executedMenuId : 0);
3086}
3087
3088/***********************************************************************
3089 * MENU_InitTracking
3090 */
3091static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
3092{
3093 TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd, hMenu);
3094
3095 HideCaret(0);
3096
3097 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
3098 if (!(wFlags & TPM_NONOTIFY))
3099 SendMessageA( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
3100
3101 SendMessageA( hWnd, WM_SETCURSOR, (WPARAM)hWnd, HTCAPTION );
3102
3103 if (!(wFlags & TPM_NONOTIFY))
3104 {
3105 POPUPMENU *menu;
3106 SendMessageA( hWnd, WM_INITMENU, hMenu, 0 );
3107 if ((menu = MENU_GetMenu( hMenu )) && (!menu->Height))
3108 { /* app changed/recreated menu bar entries in WM_INITMENU
3109 Recalculate menu sizes else clicks will not work */
3110 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3111 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
3112
3113 }
3114 }
3115 return TRUE;
3116}
3117/***********************************************************************
3118 * MENU_ExitTracking
3119 */
3120static BOOL MENU_ExitTracking(HWND hWnd)
3121{
3122 TRACE("hwnd=0x%04x\n", hWnd);
3123
3124 SendMessageA( hWnd, WM_EXITMENULOOP, 0, 0 );
3125 ShowCaret(0);
3126 return TRUE;
3127}
3128
3129/***********************************************************************
3130 * MENU_TrackMouseMenuBar
3131 *
3132 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
3133 */
3134void MENU_TrackMouseMenuBar( HWND hWnd, INT ht, POINT pt )
3135{
3136 HMENU hMenu = (ht == HTSYSMENU) ? get_win_sys_menu( hWnd ) : GetMenu( hWnd );
3137 UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
3138
3139 TRACE("wnd=%x ht=0x%04x (%ld,%ld)\n", hWnd, ht, pt.x, pt.y);
3140
3141 if (IsMenu(hMenu))
3142 {
3143 /* map point to parent client coordinates */
3144 HWND parent = GetAncestor( hWnd, GA_PARENT );
3145 if (parent != GetDesktopWindow()) ScreenToClient( parent, &pt );
3146
3147 MENU_InitTracking( hWnd, hMenu, FALSE, wFlags );
3148 MENU_TrackMenu( hMenu, wFlags, pt.x, pt.y, hWnd, NULL );
3149 MENU_ExitTracking(hWnd);
3150 }
3151}
3152
3153
3154/***********************************************************************
3155 * MENU_TrackKbdMenuBar
3156 *
3157 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3158 */
3159void MENU_TrackKbdMenuBar( HWND hwnd, UINT wParam, INT vkey)
3160{
3161 UINT uItem = NO_SELECTED_ITEM;
3162 HMENU hTrackMenu;
3163 UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON;
3164
3165 /* find window that has a menu */
3166
3167 while (GetWindowLongA( hwnd, GWL_STYLE ) & WS_CHILD)
3168 if (!(hwnd = GetParent( hwnd ))) return;
3169
3170 /* check if we have to track a system menu */
3171
3172 hTrackMenu = GetMenu( hwnd );
3173 if (!hTrackMenu || IsIconic(hwnd) || vkey == VK_SPACE )
3174 {
3175 if (!(GetWindowLongA( hwnd, GWL_STYLE ) & WS_SYSMENU)) return;
3176#ifdef __WIN32OS2__
3177 if ((GetWindowLongA( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)) return;
3178#endif
3179 hTrackMenu = get_win_sys_menu( hwnd );
3180 uItem = 0;
3181 wParam |= HTSYSMENU; /* prevent item lookup */
3182 }
3183
3184 if (!IsMenu( hTrackMenu )) return;
3185
3186 MENU_InitTracking( hwnd, hTrackMenu, FALSE, wFlags );
3187
3188 if( vkey && vkey != VK_SPACE )
3189 {
3190 uItem = MENU_FindItemByKey( hwnd, hTrackMenu, vkey, (wParam & HTSYSMENU) );
3191 if( uItem >= (UINT)(-2) )
3192 {
3193#ifndef __WIN32OS2__
3194 //Don't beep when unable to find menu item when alt key pressed
3195 if( uItem == (UINT)(-1) ) MessageBeep(0);
3196#endif
3197 hTrackMenu = 0;
3198 }
3199 }
3200
3201 if( hTrackMenu )
3202 {
3203 MENU_SelectItem( hwnd, hTrackMenu, uItem, TRUE, 0 );
3204
3205 if( uItem == NO_SELECTED_ITEM )
3206 MENU_MoveSelection( hwnd, hTrackMenu, ITEM_NEXT );
3207 else if( vkey )
3208 PostMessageA( hwnd, WM_KEYDOWN, VK_DOWN, 0L );
3209
3210 MENU_TrackMenu( hTrackMenu, wFlags, 0, 0, hwnd, NULL );
3211 }
3212 MENU_ExitTracking( hwnd );
3213}
3214
3215
3216/**********************************************************************
3217 * TrackPopupMenu (USER32.@)
3218 *
3219 * Like the win32 API, the function return the command ID only if the
3220 * flag TPM_RETURNCMD is on.
3221 *
3222 */
3223BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
3224 INT nReserved, HWND hWnd, const RECT *lpRect )
3225{
3226 BOOL ret = FALSE;
3227
3228 MENU_InitTracking(hWnd, hMenu, TRUE, wFlags);
3229
3230 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3231 if (!(wFlags & TPM_NONOTIFY))
3232 SendMessageA( hWnd, WM_INITMENUPOPUP, hMenu, 0);
3233
3234 if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
3235 ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect );
3236 MENU_ExitTracking(hWnd);
3237
3238 if( (!(wFlags & TPM_RETURNCMD)) && (ret != FALSE) )
3239 ret = 1;
3240
3241 return ret;
3242}
3243
3244/**********************************************************************
3245 * TrackPopupMenuEx (USER32.@)
3246 */
3247BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
3248 HWND hWnd, LPTPMPARAMS lpTpm )
3249{
3250 FIXME("not fully implemented\n" );
3251 return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
3252 lpTpm ? &lpTpm->rcExclude : NULL );
3253}
3254
3255/***********************************************************************
3256 * PopupMenuWndProc
3257 *
3258 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3259 */
3260static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
3261{
3262 TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
3263 hwnd, message, wParam, lParam);
3264
3265 switch(message)
3266 {
3267 case WM_CREATE:
3268 {
3269 CREATESTRUCTW *cs = (CREATESTRUCTW*)lParam;
3270 SetWindowLongW( hwnd, 0, (LONG)cs->lpCreateParams );
3271 return 0;
3272 }
3273
3274 case WM_MOUSEACTIVATE: /* We don't want to be activated */
3275 return MA_NOACTIVATE;
3276
3277 case WM_PAINT:
3278 {
3279 PAINTSTRUCT ps;
3280 BeginPaint( hwnd, &ps );
3281 MENU_DrawPopupMenu( hwnd, ps.hdc,
3282 (HMENU)GetWindowLongA( hwnd, 0 ) );
3283 EndPaint( hwnd, &ps );
3284 return 0;
3285 }
3286 case WM_ERASEBKGND:
3287 return 1;
3288
3289 case WM_DESTROY:
3290 /* zero out global pointer in case resident popup window was destroyed. */
3291 if (hwnd == top_popup) top_popup = 0;
3292 break;
3293
3294 case WM_SHOWWINDOW:
3295
3296 if( wParam )
3297 {
3298 if (!GetWindowLongW( hwnd, 0 )) ERR("no menu to display\n");
3299 }
3300 else
3301 SetWindowLongW( hwnd, 0, 0 );
3302 break;
3303
3304 case MM_SETMENUHANDLE:
3305 SetWindowLongW( hwnd, 0, wParam );
3306 break;
3307
3308 case MM_GETMENUHANDLE:
3309 return GetWindowLongW( hwnd, 0 );
3310
3311 default:
3312 return DefWindowProcW( hwnd, message, wParam, lParam );
3313 }
3314 return 0;
3315}
3316
3317
3318/***********************************************************************
3319 * MENU_GetMenuBarHeight
3320 *
3321 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3322 */
3323UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
3324 INT orgX, INT orgY )
3325{
3326 HDC hdc;
3327 RECT rectBar;
3328 LPPOPUPMENU lppop;
3329
3330 TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3331 hwnd, menubarWidth, orgX, orgY );
3332
3333 if (!(lppop = MENU_GetMenu( GetMenu(hwnd) ))) return 0;
3334
3335 hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
3336 SelectObject( hdc, hMenuFont);
3337 SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU));
3338 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
3339 ReleaseDC( hwnd, hdc );
3340 return lppop->Height;
3341}
3342
3343
3344/*******************************************************************
3345 * ChangeMenuA (USER32.@)
3346 */
3347BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
3348 UINT id, UINT flags )
3349{
3350 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3351 hMenu, pos, (DWORD)data, id, flags );
3352 if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
3353 id, data );
3354 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3355 if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
3356 id, data );
3357 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3358 flags & MF_BYPOSITION ? pos : id,
3359 flags & ~MF_REMOVE );
3360 /* Default: MF_INSERT */
3361 return InsertMenuA( hMenu, pos, flags, id, data );
3362}
3363
3364
3365/*******************************************************************
3366 * ChangeMenuW (USER32.@)
3367 */
3368BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
3369 UINT id, UINT flags )
3370{
3371 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3372 hMenu, pos, (DWORD)data, id, flags );
3373 if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
3374 id, data );
3375 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3376 if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
3377 id, data );
3378 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3379 flags & MF_BYPOSITION ? pos : id,
3380 flags & ~MF_REMOVE );
3381 /* Default: MF_INSERT */
3382 return InsertMenuW( hMenu, pos, flags, id, data );
3383}
3384
3385
3386/*******************************************************************
3387 * CheckMenuItem (USER32.@)
3388 */
3389DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
3390{
3391 MENUITEM *item;
3392 DWORD ret;
3393
3394 TRACE("menu=%04x id=%04x flags=%04x\n", hMenu, id, flags );
3395 if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
3396 ret = item->fState & MF_CHECKED;
3397 if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
3398 else item->fState &= ~MF_CHECKED;
3399 return ret;
3400}
3401
3402
3403/**********************************************************************
3404 * EnableMenuItem (USER32.@)
3405 */
3406UINT WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
3407{
3408 UINT oldflags;
3409 MENUITEM *item;
3410 POPUPMENU *menu;
3411
3412 TRACE("(%04x, %04X, %04X) !\n",
3413 hMenu, wItemID, wFlags);
3414
3415 /* Get the Popupmenu to access the owner menu */
3416 if (!(menu = MENU_GetMenu(hMenu)))
3417 return (UINT)-1;
3418
3419 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
3420 return (UINT)-1;
3421
3422 oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
3423 item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
3424
3425 /* In win95 if the close item in the system menu change update the close button */
3426 if (TWEAK_WineLook == WIN95_LOOK)
3427 if((item->wID == SC_CLOSE) && (oldflags != wFlags))
3428 {
3429 if (menu->hSysMenuOwner != 0)
3430 {
3431 POPUPMENU* parentMenu;
3432
3433 /* Get the parent menu to access*/
3434 if (!(parentMenu = MENU_GetMenu(menu->hSysMenuOwner)))
3435 return (UINT)-1;
3436
3437 /* Refresh the frame to reflect the change*/
3438 SetWindowPos(parentMenu->hWnd, 0, 0, 0, 0, 0,
3439 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
3440 }
3441 }
3442
3443 return oldflags;
3444}
3445
3446
3447/*******************************************************************
3448 * GetMenuStringA (USER32.@)
3449 */
3450INT 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 */
3456) {
3457 MENUITEM *item;
3458
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);
3464 str[0] = '\0';
3465 if (!WideCharToMultiByte( CP_ACP, 0, item->text, -1, str, nMaxSiz, NULL, NULL ))
3466 str[nMaxSiz-1] = 0;
3467 TRACE("returning '%s'\n", str );
3468 return strlen(str);
3469}
3470
3471
3472/*******************************************************************
3473 * GetMenuStringW (USER32.@)
3474 */
3475INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
3476 LPWSTR str, INT nMaxSiz, UINT wFlags )
3477{
3478 MENUITEM *item;
3479
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);
3485 str[0] = '\0';
3486 lstrcpynW( str, item->text, nMaxSiz );
3487 return strlenW(str);
3488}
3489
3490
3491/**********************************************************************
3492 * HiliteMenuItem (USER32.@)
3493 */
3494BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
3495 UINT wHilite )
3496{
3497 LPPOPUPMENU menu;
3498 TRACE("(%04x, %04x, %04x, %04x);\n",
3499 hWnd, hMenu, wItemID, wHilite);
3500 if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
3501 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3502 if (menu->FocusedItem == wItemID) return TRUE;
3503 MENU_HideSubPopups( hWnd, hMenu, FALSE );
3504 MENU_SelectItem( hWnd, hMenu, wItemID, TRUE, 0 );
3505 return TRUE;
3506}
3507
3508
3509/**********************************************************************
3510 * GetMenuState (USER32.@)
3511 */
3512UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
3513{
3514 MENUITEM *item;
3515 TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
3516 hMenu, wItemID, wFlags);
3517 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
3518 debug_print_menuitem (" item: ", item, "");
3519 if (item->fType & MF_POPUP)
3520 {
3521 POPUPMENU *menu = MENU_GetMenu( item->hSubMenu );
3522 if (!menu) return -1;
3523 else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
3524 }
3525 else
3526 {
3527 /* We used to (from way back then) mask the result to 0xff. */
3528 /* I don't know why and it seems wrong as the documented */
3529 /* return flag MF_SEPARATOR is outside that mask. */
3530 return (item->fType | item->fState);
3531 }
3532}
3533
3534
3535/**********************************************************************
3536 * GetMenuItemCount (USER32.@)
3537 */
3538INT WINAPI GetMenuItemCount( HMENU hMenu )
3539{
3540 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3541 if (!menu) return -1;
3542 TRACE("(%04x) returning %d\n",
3543 hMenu, menu->nItems );
3544 return menu->nItems;
3545}
3546
3547/**********************************************************************
3548 * GetMenuItemID (USER.264)
3549 */
3550UINT16 WINAPI GetMenuItemID16( HMENU16 hMenu, INT16 nPos )
3551{
3552 return (UINT16) GetMenuItemID (hMenu, nPos);
3553}
3554
3555/**********************************************************************
3556 * GetMenuItemID (USER32.@)
3557 */
3558UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
3559{
3560 MENUITEM * lpmi;
3561
3562 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return -1;
3563 if (lpmi->fType & MF_POPUP) return -1;
3564 return lpmi->wID;
3565
3566}
3567
3568
3569/*******************************************************************
3570 * InsertMenuW (USER32.@)
3571 */
3572BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
3573 UINT id, LPCWSTR str )
3574{
3575 MENUITEM *item;
3576
3577 if (IS_STRING_ITEM(flags) && str)
3578 TRACE("hMenu %04x, pos %d, flags %08x, "
3579 "id %04x, str %s\n",
3580 hMenu, pos, flags, id, debugstr_w(str) );
3581 else TRACE("hMenu %04x, pos %d, flags %08x, "
3582 "id %04x, str %08lx (not a string)\n",
3583 hMenu, pos, flags, id, (DWORD)str );
3584
3585 if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
3586
3587 if (!(MENU_SetItemData( item, flags, id, str )))
3588 {
3589 RemoveMenu( hMenu, pos, flags );
3590 return FALSE;
3591 }
3592
3593 if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
3594 (MENU_GetMenu((HMENU16)id))->wFlags |= MF_POPUP;
3595
3596 item->hCheckBit = item->hUnCheckBit = 0;
3597 return TRUE;
3598}
3599
3600
3601/*******************************************************************
3602 * InsertMenuA (USER32.@)
3603 */
3604BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
3605 UINT id, LPCSTR str )
3606{
3607 BOOL ret = FALSE;
3608
3609 if (IS_STRING_ITEM(flags) && str)
3610 {
3611 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3612 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3613 if (newstr)
3614 {
3615 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3616 ret = InsertMenuW( hMenu, pos, flags, id, newstr );
3617 HeapFree( GetProcessHeap(), 0, newstr );
3618 }
3619 return ret;
3620 }
3621 else return InsertMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3622}
3623
3624
3625/*******************************************************************
3626 * AppendMenuA (USER32.@)
3627 */
3628BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
3629 UINT id, LPCSTR data )
3630{
3631 return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
3632}
3633
3634
3635/*******************************************************************
3636 * AppendMenuW (USER32.@)
3637 */
3638BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
3639 UINT id, LPCWSTR data )
3640{
3641 return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
3642}
3643
3644
3645/**********************************************************************
3646 * RemoveMenu (USER32.@)
3647 */
3648BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3649{
3650 LPPOPUPMENU menu;
3651 MENUITEM *item;
3652
3653 TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
3654 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3655 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3656
3657 /* Remove item */
3658
3659 MENU_FreeItemData( item );
3660
3661 if (--menu->nItems == 0)
3662 {
3663 HeapFree( GetProcessHeap(), 0, menu->items );
3664 menu->items = NULL;
3665 }
3666 else
3667 {
3668 while(nPos < menu->nItems)
3669 {
3670 *item = *(item+1);
3671 item++;
3672 nPos++;
3673 }
3674 menu->items = HeapReAlloc( GetProcessHeap(), 0, menu->items,
3675 menu->nItems * sizeof(MENUITEM) );
3676 }
3677 return TRUE;
3678}
3679
3680
3681/**********************************************************************
3682 * DeleteMenu (USER32.@)
3683 */
3684BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3685{
3686 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
3687 if (!item) return FALSE;
3688 if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
3689 /* nPos is now the position of the item */
3690 RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
3691 return TRUE;
3692}
3693
3694
3695/*******************************************************************
3696 * ModifyMenuW (USER32.@)
3697 */
3698BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
3699 UINT id, LPCWSTR str )
3700{
3701 MENUITEM *item;
3702
3703 if (IS_STRING_ITEM(flags))
3704 {
3705 TRACE("%04x %d %04x %04x %s\n",
3706 hMenu, pos, flags, id, debugstr_w(str) );
3707 if (!str) return FALSE;
3708 }
3709 else
3710 {
3711 TRACE("%04x %d %04x %04x %08lx\n",
3712 hMenu, pos, flags, id, (DWORD)str );
3713 }
3714
3715 if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
3716 return MENU_SetItemData( item, flags, id, str );
3717}
3718
3719
3720/*******************************************************************
3721 * ModifyMenuA (USER32.@)
3722 */
3723BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
3724 UINT id, LPCSTR str )
3725{
3726 BOOL ret = FALSE;
3727
3728 if (IS_STRING_ITEM(flags) && str)
3729 {
3730 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3731 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3732 if (newstr)
3733 {
3734 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3735 ret = ModifyMenuW( hMenu, pos, flags, id, newstr );
3736 HeapFree( GetProcessHeap(), 0, newstr );
3737 }
3738 return ret;
3739 }
3740 else return ModifyMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3741}
3742
3743
3744/**********************************************************************
3745 * CreatePopupMenu (USER32.@)
3746 */
3747HMENU WINAPI CreatePopupMenu(void)
3748{
3749 HMENU hmenu;
3750 POPUPMENU *menu;
3751
3752 if (!(hmenu = CreateMenu())) return 0;
3753 menu = MENU_GetMenu( hmenu );
3754 menu->wFlags |= MF_POPUP;
3755 menu->bTimeToHide = FALSE;
3756 return hmenu;
3757}
3758
3759
3760/**********************************************************************
3761 * GetMenuCheckMarkDimensions (USER.417)
3762 * GetMenuCheckMarkDimensions (USER32.@)
3763 */
3764DWORD WINAPI GetMenuCheckMarkDimensions(void)
3765{
3766 return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK) );
3767}
3768
3769
3770/**********************************************************************
3771 * SetMenuItemBitmaps (USER32.@)
3772 */
3773BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
3774 HBITMAP hNewUnCheck, HBITMAP hNewCheck)
3775{
3776 MENUITEM *item;
3777 TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3778 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
3779 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3780
3781 if (!hNewCheck && !hNewUnCheck)
3782 {
3783 item->fState &= ~MF_USECHECKBITMAPS;
3784 }
3785 else /* Install new bitmaps */
3786 {
3787 item->hCheckBit = hNewCheck;
3788 item->hUnCheckBit = hNewUnCheck;
3789 item->fState |= MF_USECHECKBITMAPS;
3790 }
3791 return TRUE;
3792}
3793
3794
3795/**********************************************************************
3796 * CreateMenu (USER32.@)
3797 */
3798HMENU WINAPI CreateMenu(void)
3799{
3800 HMENU hMenu;
3801 LPPOPUPMENU menu;
3802
3803#ifdef __WIN32OS2__
3804 if (!(menu = (LPPOPUPMENU)HeapAlloc(GetProcessHeap(),0,sizeof(POPUPMENU)))) return 0;
3805 if(ObjAllocateHandle(&hMenu, (DWORD)menu, HNDL_MENU) == FALSE) return 0;
3806#else
3807 if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
3808 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3809#endif
3810 ZeroMemory(menu, sizeof(POPUPMENU));
3811 menu->wMagic = MENU_MAGIC;
3812 menu->FocusedItem = NO_SELECTED_ITEM;
3813 menu->bTimeToHide = FALSE;
3814
3815 TRACE("return %04x\n", hMenu );
3816
3817 return hMenu;
3818}
3819
3820
3821/**********************************************************************
3822 * DestroyMenu (USER32.@)
3823 */
3824BOOL WINAPI DestroyMenu( HMENU hMenu )
3825{
3826 TRACE("(%04x)\n", hMenu);
3827
3828 /* Silently ignore attempts to destroy default system popup */
3829
3830 if (hMenu && hMenu != MENU_DefSysPopup)
3831 {
3832 LPPOPUPMENU lppop = MENU_GetMenu(hMenu);
3833
3834 if (!lppop) return FALSE;
3835
3836 lppop->wMagic = 0; /* Mark it as destroyed */
3837
3838 if ((lppop->wFlags & MF_POPUP) && lppop->hWnd)
3839 {
3840 DestroyWindow( lppop->hWnd );
3841 lppop->hWnd = 0;
3842 }
3843
3844 if (lppop->items) /* recursively destroy submenus */
3845 {
3846 int i;
3847 MENUITEM *item = lppop->items;
3848 for (i = lppop->nItems; i > 0; i--, item++)
3849 {
3850 if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
3851 MENU_FreeItemData( item );
3852 }
3853 HeapFree( GetProcessHeap(), 0, lppop->items );
3854 }
3855#ifdef __WIN32OS2__
3856 HeapFree(GetProcessHeap(),0,(LPVOID)lppop);
3857 ObjDeleteHandle(hMenu, HNDL_MENU);
3858#else
3859 USER_HEAP_FREE( hMenu );
3860#endif
3861 }
3862 return (hMenu != MENU_DefSysPopup);
3863}
3864
3865
3866/**********************************************************************
3867 * GetSystemMenu (USER32.@)
3868 */
3869HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
3870{
3871#ifdef __WIN32OS2__
3872 HMENU retvalue = 0;
3873
3874 if(IsWindow(hWnd))
3875 {
3876 HMENU hSysMenu = getSysMenu(hWnd);
3877 if(hSysMenu)
3878 {
3879 if( bRevert )
3880 {
3881 DestroyMenu(hSysMenu);
3882 hSysMenu = 0;
3883 setSysMenu(hWnd,hSysMenu);
3884 }
3885 else
3886 {
3887 POPUPMENU *menu = MENU_GetMenu(hSysMenu);
3888 if(menu)
3889 {
3890 if( menu->nItems > 0 && menu->items[0].hSubMenu == MENU_DefSysPopup )
3891 menu->items[0].hSubMenu = MENU_CopySysPopup();
3892 }
3893 else
3894 {
3895 //WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
3896 // wndPtr->hSysMenu, hWnd);
3897 hSysMenu = 0;
3898 setSysMenu(hWnd,hSysMenu);
3899 }
3900 }
3901 }
3902
3903 if(!hSysMenu && (GetWindowLongA(hWnd,GWL_STYLE) & WS_SYSMENU) )
3904 {
3905 hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
3906 setSysMenu(hWnd,hSysMenu);
3907 }
3908
3909 if( hSysMenu )
3910 {
3911 POPUPMENU *menu;
3912 retvalue = GetSubMenu(hSysMenu, 0);
3913
3914 /* Store the dummy sysmenu handle to facilitate the refresh */
3915 /* of the close button if the SC_CLOSE item change */
3916 menu = MENU_GetMenu(retvalue);
3917 if (menu)
3918 menu->hSysMenuOwner = hSysMenu;
3919 }
3920 }
3921 return bRevert ? 0 : retvalue;
3922#else
3923 WND *wndPtr = WIN_FindWndPtr( hWnd );
3924 HMENU retvalue = 0;
3925
3926 if (wndPtr)
3927 {
3928 if( wndPtr->hSysMenu )
3929 {
3930 if( bRevert )
3931 {
3932 DestroyMenu(wndPtr->hSysMenu);
3933 wndPtr->hSysMenu = 0;
3934 }
3935 else
3936 {
3937 POPUPMENU *menu = MENU_GetMenu( wndPtr->hSysMenu );
3938 if( menu )
3939 {
3940 if( menu->nItems > 0 && menu->items[0].hSubMenu == MENU_DefSysPopup )
3941 menu->items[0].hSubMenu = MENU_CopySysPopup();
3942 }
3943 else
3944 {
3945 WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
3946 wndPtr->hSysMenu, hWnd);
3947 wndPtr->hSysMenu = 0;
3948 }
3949 }
3950 }
3951
3952 if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
3953 wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
3954
3955 if( wndPtr->hSysMenu )
3956 {
3957 POPUPMENU *menu;
3958 retvalue = GetSubMenu(wndPtr->hSysMenu, 0);
3959
3960 /* Store the dummy sysmenu handle to facilitate the refresh */
3961 /* of the close button if the SC_CLOSE item change */
3962 menu = MENU_GetMenu(retvalue);
3963 if ( menu )
3964 menu->hSysMenuOwner = wndPtr->hSysMenu;
3965 }
3966 WIN_ReleaseWndPtr(wndPtr);
3967 }
3968 return bRevert ? 0 : retvalue;
3969#endif
3970}
3971
3972
3973/*******************************************************************
3974 * SetSystemMenu (USER32.@)
3975 */
3976BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
3977{
3978#ifdef __WIN32OS2__
3979 HMENU hSysMenu;
3980
3981 if(!IsWindow(hwnd)) return FALSE;
3982
3983 hSysMenu = getSysMenu(hwnd);
3984 if(hSysMenu) DestroyMenu(hSysMenu);
3985
3986 setSysMenu(hwnd, MENU_GetSysMenu( hwnd, hMenu ));
3987 return TRUE;
3988#else
3989 WND *wndPtr = WIN_FindWndPtr(hwnd);
3990
3991 if (wndPtr)
3992 {
3993 if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
3994 wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
3995 WIN_ReleaseWndPtr(wndPtr);
3996 return TRUE;
3997 }
3998 return FALSE;
3999#endif
4000}
4001
4002
4003/**********************************************************************
4004 * GetMenu (USER32.@)
4005 */
4006HMENU WINAPI GetMenu( HWND hWnd )
4007{
4008 HMENU retvalue = (HMENU)GetWindowLongA( hWnd, GWL_ID );
4009#ifdef __WIN32OS2__
4010 if(MENU_GetMenu(retvalue) != NULL) {
4011 return retvalue;
4012 }
4013 dprintf(("WARNING: Invalid menu %x", retvalue));
4014 return 0;
4015#else
4016 TRACE("for %04x returning %04x\n", hWnd, retvalue);
4017 return retvalue;
4018#endif
4019}
4020
4021
4022/**********************************************************************
4023 * SetMenu (USER32.@)
4024 */
4025BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
4026{
4027 TRACE("(%04x, %04x);\n", hWnd, hMenu);
4028
4029 if (hMenu && !IsMenu(hMenu))
4030 {
4031 WARN("hMenu %x is not a menu handle\n", hMenu);
4032 return FALSE;
4033 }
4034 if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
4035
4036 hWnd = WIN_GetFullHandle( hWnd );
4037 if (GetCapture() == hWnd) ReleaseCapture();
4038
4039 if (hMenu != 0)
4040 {
4041 LPPOPUPMENU lpmenu;
4042
4043 if (!(lpmenu = MENU_GetMenu(hMenu))) return FALSE;
4044
4045 lpmenu->hWnd = hWnd;
4046 lpmenu->Height = 0; /* Make sure we recalculate the size */
4047 }
4048 SetWindowLongA( hWnd, GWL_ID, hMenu );
4049
4050 if (IsWindowVisible(hWnd))
4051 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4052 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4053 return TRUE;
4054}
4055
4056
4057
4058/**********************************************************************
4059 * GetSubMenu (USER32.@)
4060 */
4061HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
4062{
4063 MENUITEM * lpmi;
4064
4065#ifdef __WIN32OS2__
4066 if (!(lpmi = MENU_FindItem(&hMenu,(UINT*)&nPos,MF_BYPOSITION))) {
4067 SetLastError(ERROR_INVALID_HANDLE);
4068 return 0;
4069 }
4070#else
4071 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
4072#endif
4073 if (!(lpmi->fType & MF_POPUP)) return 0;
4074 return lpmi->hSubMenu;
4075}
4076
4077
4078/**********************************************************************
4079 * DrawMenuBar (USER32.@)
4080 */
4081BOOL WINAPI DrawMenuBar( HWND hWnd )
4082{
4083 LPPOPUPMENU lppop;
4084 HMENU hMenu = GetMenu(hWnd);
4085
4086 if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
4087 if (!hMenu || !(lppop = MENU_GetMenu( hMenu ))) return FALSE;
4088
4089 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
4090 lppop->hwndOwner = hWnd;
4091 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4092 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4093 return TRUE;
4094}
4095
4096/***********************************************************************
4097 * DrawMenuBarTemp (USER32.@)
4098 *
4099 * UNDOCUMENTED !!
4100 *
4101 * called by W98SE desk.cpl Control Panel Applet
4102 *
4103 * Not 100% sure about the param names, but close.
4104 */
4105DWORD WINAPI DrawMenuBarTemp(HWND someHWND, HDC someHDC, LPRECT someRECT, HMENU someHMENU, HFONT someFONT)
4106{
4107 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, 0x%08x): stub\n", someHWND, someHDC, someRECT, someHMENU, someFONT);
4108 return 0;
4109}
4110
4111/***********************************************************************
4112 * EndMenu (USER.187)
4113 * EndMenu (USER32.@)
4114 */
4115void WINAPI EndMenu(void)
4116{
4117 /* if we are in the menu code, and it is active */
4118 if (!fEndMenu && top_popup)
4119 {
4120 /* terminate the menu handling code */
4121 fEndMenu = TRUE;
4122
4123 /* needs to be posted to wakeup the internal menu handler */
4124 /* which will now terminate the menu, in the event that */
4125 /* the main window was minimized, or lost focus, so we */
4126 /* don't end up with an orphaned menu */
4127 PostMessageA( top_popup, WM_CANCELMODE, 0, 0);
4128 }
4129}
4130
4131
4132/***********************************************************************
4133 * LookupMenuHandle (USER.217)
4134 */
4135HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
4136{
4137 HMENU hmenu32 = hmenu;
4138 UINT id32 = id;
4139 if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
4140 else return hmenu32;
4141}
4142
4143
4144#ifndef __WIN32OS2__
4145/**********************************************************************
4146 * LoadMenu (USER.150)
4147 */
4148HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, LPCSTR name )
4149{
4150 HRSRC16 hRsrc;
4151 HGLOBAL16 handle;
4152 HMENU16 hMenu;
4153
4154 TRACE("(%04x,%s)\n", instance, debugres_a(name) );
4155
4156 if (HIWORD(name))
4157 {
4158 if (name[0] == '#') name = (LPCSTR)atoi( name + 1 );
4159 }
4160
4161 if (!name) return 0;
4162
4163 /* check for Win32 module */
4164 if (HIWORD(instance)) return LoadMenuA( instance, name );
4165 instance = GetExePtr( instance );
4166
4167 if (!(hRsrc = FindResource16( instance, name, RT_MENUA ))) return 0;
4168 if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
4169 hMenu = LoadMenuIndirect16(LockResource16(handle));
4170 FreeResource16( handle );
4171 return hMenu;
4172}
4173#endif
4174
4175/*****************************************************************
4176 * LoadMenuA (USER32.@)
4177 */
4178HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
4179{
4180 HRSRC hrsrc = FindResourceA( instance, name, RT_MENUA );
4181 if (!hrsrc) return 0;
4182 return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
4183}
4184
4185
4186/*****************************************************************
4187 * LoadMenuW (USER32.@)
4188 */
4189HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
4190{
4191 HRSRC hrsrc = FindResourceW( instance, name, RT_MENUW );
4192 if (!hrsrc) return 0;
4193 return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
4194}
4195
4196
4197/**********************************************************************
4198 * LoadMenuIndirect (USER.220)
4199 */
4200HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
4201{
4202 HMENU16 hMenu;
4203 WORD version, offset;
4204 LPCSTR p = (LPCSTR)template;
4205
4206 TRACE("(%p)\n", template );
4207 version = GET_WORD(p);
4208 p += sizeof(WORD);
4209 if (version)
4210 {
4211 WARN("version must be 0 for Win16\n" );
4212 return 0;
4213 }
4214 offset = GET_WORD(p);
4215 p += sizeof(WORD) + offset;
4216 if (!(hMenu = CreateMenu())) return 0;
4217 if (!MENU_ParseResource( p, hMenu, FALSE ))
4218 {
4219 DestroyMenu( hMenu );
4220 return 0;
4221 }
4222 return hMenu;
4223}
4224
4225
4226/**********************************************************************
4227 * LoadMenuIndirectA (USER32.@)
4228 */
4229HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
4230{
4231 HMENU16 hMenu;
4232 WORD version, offset;
4233 LPCSTR p = (LPCSTR)template;
4234
4235 TRACE("%p\n", template );
4236 version = GET_WORD(p);
4237 p += sizeof(WORD);
4238 switch (version)
4239 {
4240 case 0:
4241 offset = GET_WORD(p);
4242 p += sizeof(WORD) + offset;
4243 if (!(hMenu = CreateMenu())) return 0;
4244 if (!MENU_ParseResource( p, hMenu, TRUE ))
4245 {
4246 DestroyMenu( hMenu );
4247 return 0;
4248 }
4249 return hMenu;
4250 case 1:
4251 offset = GET_WORD(p);
4252 p += sizeof(WORD) + offset;
4253 if (!(hMenu = CreateMenu())) return 0;
4254 if (!MENUEX_ParseResource( p, hMenu))
4255 {
4256 DestroyMenu( hMenu );
4257 return 0;
4258 }
4259 return hMenu;
4260 default:
4261 ERR("version %d not supported.\n", version);
4262 return 0;
4263 }
4264}
4265
4266
4267/**********************************************************************
4268 * LoadMenuIndirectW (USER32.@)
4269 */
4270HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
4271{
4272 /* FIXME: is there anything different between A and W? */
4273 return LoadMenuIndirectA( template );
4274}
4275
4276
4277/**********************************************************************
4278 * IsMenu (USER32.@)
4279 */
4280BOOL WINAPI IsMenu(HMENU hmenu)
4281{
4282 LPPOPUPMENU menu = MENU_GetMenu(hmenu);
4283 return menu != NULL;
4284}
4285
4286/**********************************************************************
4287 * GetMenuItemInfo_common
4288 */
4289
4290static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
4291 LPMENUITEMINFOW lpmii, BOOL unicode)
4292{
4293 MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
4294
4295 debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
4296
4297 if (!menu)
4298 return FALSE;
4299
4300 if (lpmii->fMask & MIIM_TYPE) {
4301 lpmii->fType = menu->fType;
4302 switch (MENU_ITEM_TYPE(menu->fType)) {
4303 case MF_STRING:
4304 break; /* will be done below */
4305 case MF_OWNERDRAW:
4306 case MF_BITMAP:
4307 lpmii->dwTypeData = menu->text;
4308 /* fall through */
4309 default:
4310 lpmii->cch = 0;
4311 }
4312 }
4313
4314 /* copy the text string */
4315 if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING)) &&
4316 (MENU_ITEM_TYPE(menu->fType) == MF_STRING) && menu->text)
4317 {
4318 int len;
4319 if (unicode)
4320 {
4321 len = strlenW(menu->text);
4322 if(lpmii->dwTypeData && lpmii->cch)
4323 lstrcpynW(lpmii->dwTypeData, menu->text, lpmii->cch);
4324 }
4325 else
4326 {
4327 len = WideCharToMultiByte( CP_ACP, 0, menu->text, -1, NULL, 0, NULL, NULL );
4328 if(lpmii->dwTypeData && lpmii->cch)
4329 if (!WideCharToMultiByte( CP_ACP, 0, menu->text, -1,
4330 (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
4331 ((LPSTR)lpmii->dwTypeData)[lpmii->cch-1] = 0;
4332 }
4333 /* if we've copied a substring we return its length */
4334 if(lpmii->dwTypeData && lpmii->cch)
4335 {
4336 if (lpmii->cch <= len) lpmii->cch--;
4337 }
4338 else /* return length of string */
4339 lpmii->cch = len;
4340 }
4341
4342 if (lpmii->fMask & MIIM_FTYPE)
4343 lpmii->fType = menu->fType;
4344
4345 if (lpmii->fMask & MIIM_BITMAP)
4346 lpmii->hbmpItem = menu->hbmpItem;
4347
4348 if (lpmii->fMask & MIIM_STATE)
4349 lpmii->fState = menu->fState;
4350
4351 if (lpmii->fMask & MIIM_ID)
4352 lpmii->wID = menu->wID;
4353
4354 if (lpmii->fMask & MIIM_SUBMENU)
4355 lpmii->hSubMenu = menu->hSubMenu;
4356
4357 if (lpmii->fMask & MIIM_CHECKMARKS) {
4358 lpmii->hbmpChecked = menu->hCheckBit;
4359 lpmii->hbmpUnchecked = menu->hUnCheckBit;
4360 }
4361 if (lpmii->fMask & MIIM_DATA)
4362 lpmii->dwItemData = menu->dwItemData;
4363
4364 return TRUE;
4365}
4366
4367/**********************************************************************
4368 * GetMenuItemInfoA (USER32.@)
4369 */
4370BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
4371 LPMENUITEMINFOA lpmii)
4372{
4373 return GetMenuItemInfo_common (hmenu, item, bypos,
4374 (LPMENUITEMINFOW)lpmii, FALSE);
4375}
4376
4377/**********************************************************************
4378 * GetMenuItemInfoW (USER32.@)
4379 */
4380BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
4381 LPMENUITEMINFOW lpmii)
4382{
4383 return GetMenuItemInfo_common (hmenu, item, bypos,
4384 lpmii, TRUE);
4385}
4386
4387
4388/* set a menu item text from a ASCII or Unicode string */
4389inline static void set_menu_item_text( MENUITEM *menu, LPCWSTR text, BOOL unicode )
4390{
4391 if (!text)
4392 {
4393 menu->text = NULL;
4394 menu->fType |= MF_SEPARATOR;
4395 }
4396 else if (unicode)
4397 {
4398 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, (strlenW(text)+1) * sizeof(WCHAR) )))
4399 strcpyW( menu->text, text );
4400 }
4401 else
4402 {
4403 LPCSTR str = (LPCSTR)text;
4404 int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
4405 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
4406 MultiByteToWideChar( CP_ACP, 0, str, -1, menu->text, len );
4407 }
4408}
4409
4410
4411/**********************************************************************
4412 * SetMenuItemInfo_common
4413 */
4414
4415static BOOL SetMenuItemInfo_common(MENUITEM * menu,
4416 const MENUITEMINFOW *lpmii,
4417 BOOL unicode)
4418{
4419 if (!menu) return FALSE;
4420
4421 debug_print_menuitem("MENU_SetItemInfo_common from: ", menu, "");
4422
4423 if (lpmii->fMask & MIIM_TYPE ) {
4424 /* Get rid of old string. */
4425 if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4426 HeapFree(GetProcessHeap(), 0, menu->text);
4427 menu->text = NULL;
4428 }
4429
4430 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4431 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4432 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4433
4434 menu->text = lpmii->dwTypeData;
4435
4436 if (IS_STRING_ITEM(menu->fType))
4437 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4438 }
4439
4440 if (lpmii->fMask & MIIM_FTYPE ) {
4441 /* free the string when the type is changing */
4442 if ( (!IS_STRING_ITEM(lpmii->fType)) && IS_STRING_ITEM(menu->fType) && menu->text) {
4443 HeapFree(GetProcessHeap(), 0, menu->text);
4444 menu->text = NULL;
4445 }
4446 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4447 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4448 if ( IS_STRING_ITEM(menu->fType) && !menu->text )
4449 menu->fType |= MF_SEPARATOR;
4450 }
4451
4452 if (lpmii->fMask & MIIM_STRING ) {
4453 /* free the string when used */
4454 if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4455 HeapFree(GetProcessHeap(), 0, menu->text);
4456 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4457 }
4458 }
4459
4460 if (lpmii->fMask & MIIM_STATE)
4461 {
4462 /* FIXME: MFS_DEFAULT do we have to reset the other menu items? */
4463 menu->fState = lpmii->fState;
4464 }
4465
4466 if (lpmii->fMask & MIIM_ID)
4467 menu->wID = lpmii->wID;
4468
4469 if (lpmii->fMask & MIIM_SUBMENU) {
4470 menu->hSubMenu = lpmii->hSubMenu;
4471 if (menu->hSubMenu) {
4472 POPUPMENU *subMenu = MENU_GetMenu((UINT16)menu->hSubMenu);
4473 if (subMenu) {
4474 subMenu->wFlags |= MF_POPUP;
4475 menu->fType |= MF_POPUP;
4476 }
4477 else
4478 /* FIXME: Return an error ? */
4479 menu->fType &= ~MF_POPUP;
4480 }
4481 else
4482 menu->fType &= ~MF_POPUP;
4483 }
4484
4485 if (lpmii->fMask & MIIM_CHECKMARKS)
4486 {
4487 if (lpmii->fType & MFT_RADIOCHECK)
4488 menu->fType |= MFT_RADIOCHECK;
4489
4490 menu->hCheckBit = lpmii->hbmpChecked;
4491 menu->hUnCheckBit = lpmii->hbmpUnchecked;
4492 }
4493 if (lpmii->fMask & MIIM_DATA)
4494 menu->dwItemData = lpmii->dwItemData;
4495
4496 debug_print_menuitem("SetMenuItemInfo_common to : ", menu, "");
4497 return TRUE;
4498}
4499
4500/**********************************************************************
4501 * SetMenuItemInfoA (USER32.@)
4502 */
4503BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
4504 const MENUITEMINFOA *lpmii)
4505{
4506 if ((lpmii->fType & (MF_HILITE|MF_POPUP)) || (lpmii->fState)) {
4507 /* QuickTime does pass invalid data into SetMenuItemInfo.
4508 * do some of the checks Windows does.
4509 */
4510 WARN("Bad masks for type (0x%08x) or state (0x%08x)\n",
4511 lpmii->fType,lpmii->fState );
4512 return FALSE;
4513 }
4514
4515 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4516 (const MENUITEMINFOW *)lpmii, FALSE);
4517}
4518
4519/**********************************************************************
4520 * SetMenuItemInfoW (USER32.@)
4521 */
4522BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
4523 const MENUITEMINFOW *lpmii)
4524{
4525 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4526 lpmii, TRUE);
4527}
4528
4529/**********************************************************************
4530 * SetMenuDefaultItem (USER32.@)
4531 *
4532 */
4533BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
4534{
4535 UINT i;
4536 POPUPMENU *menu;
4537 MENUITEM *item;
4538
4539 TRACE("(0x%x,%d,%d)\n", hmenu, uItem, bypos);
4540
4541 if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
4542
4543 /* reset all default-item flags */
4544 item = menu->items;
4545 for (i = 0; i < menu->nItems; i++, item++)
4546 {
4547 item->fState &= ~MFS_DEFAULT;
4548 }
4549
4550 /* no default item */
4551 if ( -1 == uItem)
4552 {
4553 return TRUE;
4554 }
4555
4556 item = menu->items;
4557 if ( bypos )
4558 {
4559 if ( uItem >= menu->nItems ) return FALSE;
4560 item[uItem].fState |= MFS_DEFAULT;
4561 return TRUE;
4562 }
4563 else
4564 {
4565 for (i = 0; i < menu->nItems; i++, item++)
4566 {
4567 if (item->wID == uItem)
4568 {
4569 item->fState |= MFS_DEFAULT;
4570 return TRUE;
4571 }
4572 }
4573
4574 }
4575 return FALSE;
4576}
4577
4578/**********************************************************************
4579 * GetMenuDefaultItem (USER32.@)
4580 */
4581UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
4582{
4583 POPUPMENU *menu;
4584 MENUITEM * item;
4585 UINT i = 0;
4586
4587 TRACE("(0x%x,%d,%d)\n", hmenu, bypos, flags);
4588
4589 if (!(menu = MENU_GetMenu(hmenu))) return -1;
4590
4591 /* find default item */
4592 item = menu->items;
4593
4594 /* empty menu */
4595 if (! item) return -1;
4596
4597 while ( !( item->fState & MFS_DEFAULT ) )
4598 {
4599 i++; item++;
4600 if (i >= menu->nItems ) return -1;
4601 }
4602
4603 /* default: don't return disabled items */
4604 if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
4605
4606 /* search rekursiv when needed */
4607 if ( (item->fType & MF_POPUP) && (flags & GMDI_GOINTOPOPUPS) )
4608 {
4609 UINT ret;
4610 ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
4611 if ( -1 != ret ) return ret;
4612
4613 /* when item not found in submenu, return the popup item */
4614 }
4615 return ( bypos ) ? i : item->wID;
4616
4617}
4618
4619
4620/**********************************************************************
4621 * InsertMenuItemA (USER32.@)
4622 */
4623BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4624 const MENUITEMINFOA *lpmii)
4625{
4626 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4627 return SetMenuItemInfo_common(item, (const MENUITEMINFOW *)lpmii, FALSE);
4628}
4629
4630
4631/**********************************************************************
4632 * InsertMenuItemW (USER32.@)
4633 */
4634BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4635 const MENUITEMINFOW *lpmii)
4636{
4637 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4638 return SetMenuItemInfo_common(item, lpmii, TRUE);
4639}
4640
4641/**********************************************************************
4642 * CheckMenuRadioItem (USER32.@)
4643 */
4644
4645BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4646 UINT first, UINT last, UINT check,
4647 UINT bypos)
4648{
4649 MENUITEM *mifirst, *milast, *micheck;
4650 HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
4651
4652 TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4653 hMenu, first, last, check, bypos);
4654
4655 mifirst = MENU_FindItem (&mfirst, &first, bypos);
4656 milast = MENU_FindItem (&mlast, &last, bypos);
4657 micheck = MENU_FindItem (&mcheck, &check, bypos);
4658
4659 if (mifirst == NULL || milast == NULL || micheck == NULL ||
4660 mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4661 micheck > milast || micheck < mifirst)
4662 return FALSE;
4663
4664 while (mifirst <= milast)
4665 {
4666 if (mifirst == micheck)
4667 {
4668 mifirst->fType |= MFT_RADIOCHECK;
4669 mifirst->fState |= MFS_CHECKED;
4670 } else {
4671 mifirst->fType &= ~MFT_RADIOCHECK;
4672 mifirst->fState &= ~MFS_CHECKED;
4673 }
4674 mifirst++;
4675 }
4676
4677 return TRUE;
4678}
4679
4680/**********************************************************************
4681 * GetMenuItemRect (USER32.@)
4682 *
4683 * ATTENTION: Here, the returned values in rect are the screen
4684 * coordinates of the item just like if the menu was
4685 * always on the upper left side of the application.
4686 *
4687 */
4688BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4689 LPRECT rect)
4690{
4691 POPUPMENU *itemMenu;
4692 MENUITEM *item;
4693 HWND referenceHwnd;
4694
4695 TRACE("(0x%x,0x%x,%d,%p)\n", hwnd, hMenu, uItem, rect);
4696
4697 item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
4698 referenceHwnd = hwnd;
4699
4700 if(!hwnd)
4701 {
4702 itemMenu = MENU_GetMenu(hMenu);
4703 if (itemMenu == NULL)
4704 return FALSE;
4705
4706 if(itemMenu->hWnd == 0)
4707 return FALSE;
4708 referenceHwnd = itemMenu->hWnd;
4709 }
4710
4711 if ((rect == NULL) || (item == NULL))
4712 return FALSE;
4713
4714 *rect = item->rect;
4715
4716 MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
4717
4718 return TRUE;
4719}
4720
4721
4722/**********************************************************************
4723 * SetMenuInfo (USER32.@)
4724 *
4725 * FIXME
4726 * MIM_APPLYTOSUBMENUS
4727 * actually use the items to draw the menu
4728 */
4729BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
4730{
4731 POPUPMENU *menu;
4732
4733 TRACE("(0x%04x %p)\n", hMenu, lpmi);
4734
4735 if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu = MENU_GetMenu(hMenu)))
4736 {
4737
4738 if (lpmi->fMask & MIM_BACKGROUND)
4739 menu->hbrBack = lpmi->hbrBack;
4740
4741 if (lpmi->fMask & MIM_HELPID)
4742 menu->dwContextHelpID = lpmi->dwContextHelpID;
4743
4744 if (lpmi->fMask & MIM_MAXHEIGHT)
4745 menu->cyMax = lpmi->cyMax;
4746
4747 if (lpmi->fMask & MIM_MENUDATA)
4748 menu->dwMenuData = lpmi->dwMenuData;
4749
4750 if (lpmi->fMask & MIM_STYLE)
4751 menu->dwStyle = lpmi->dwStyle;
4752
4753 return TRUE;
4754 }
4755 return FALSE;
4756}
4757
4758/**********************************************************************
4759 * GetMenuInfo (USER32.@)
4760 *
4761 * NOTES
4762 * win98/NT5.0
4763 *
4764 */
4765BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
4766{ POPUPMENU *menu;
4767
4768 TRACE("(0x%04x %p)\n", hMenu, lpmi);
4769
4770 if (lpmi && (menu = MENU_GetMenu(hMenu)))
4771 {
4772
4773 if (lpmi->fMask & MIM_BACKGROUND)
4774 lpmi->hbrBack = menu->hbrBack;
4775
4776 if (lpmi->fMask & MIM_HELPID)
4777 lpmi->dwContextHelpID = menu->dwContextHelpID;
4778
4779 if (lpmi->fMask & MIM_MAXHEIGHT)
4780 lpmi->cyMax = menu->cyMax;
4781
4782 if (lpmi->fMask & MIM_MENUDATA)
4783 lpmi->dwMenuData = menu->dwMenuData;
4784
4785 if (lpmi->fMask & MIM_STYLE)
4786 lpmi->dwStyle = menu->dwStyle;
4787
4788 return TRUE;
4789 }
4790 return FALSE;
4791}
4792
4793/**********************************************************************
4794 * SetMenuContextHelpId (USER32.@)
4795 */
4796BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
4797{
4798 LPPOPUPMENU menu;
4799
4800 TRACE("(0x%04x 0x%08lx)\n", hMenu, dwContextHelpID);
4801
4802 if ((menu = MENU_GetMenu(hMenu)))
4803 {
4804 menu->dwContextHelpID = dwContextHelpID;
4805 return TRUE;
4806 }
4807 return FALSE;
4808}
4809
4810/**********************************************************************
4811 * GetMenuContextHelpId (USER32.@)
4812 */
4813DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
4814{
4815 LPPOPUPMENU menu;
4816
4817 TRACE("(0x%04x)\n", hMenu);
4818
4819 if ((menu = MENU_GetMenu(hMenu)))
4820 {
4821 return menu->dwContextHelpID;
4822 }
4823 return 0;
4824}
4825
4826/**********************************************************************
4827 * MenuItemFromPoint (USER32.@)
4828 */
4829UINT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
4830{
4831 POPUPMENU *menu = MENU_GetMenu(hMenu);
4832 UINT pos;
4833 MENUITEM *item;
4834
4835 /*FIXME: Do we have to handle hWnd here? */
4836 item = MENU_FindItemByCoords(menu, ptScreen, &pos);
4837
4838 return pos;
4839}
4840
4841#ifdef __WIN32OS2__
4842//******************************************************************************
4843//******************************************************************************
4844void WIN32API DisableOdinSysMenuItems()
4845{
4846 fDisableOdinSysMenuItems = TRUE;
4847}
4848//******************************************************************************
4849//******************************************************************************
4850#else
4851//winaccel.cpp
4852/**********************************************************************
4853 * translate_accelerator
4854 */
4855static BOOL translate_accelerator( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
4856 BYTE fVirt, WORD key, WORD cmd )
4857{
4858 UINT mesg = 0;
4859
4860 if (wParam != key) return FALSE;
4861
4862 if (message == WM_CHAR)
4863 {
4864 if ( !(fVirt & FALT) && !(fVirt & FVIRTKEY) )
4865 {
4866 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", wParam & 0xff);
4867 goto found;
4868 }
4869 }
4870 else
4871 {
4872 if(fVirt & FVIRTKEY)
4873 {
4874 INT mask = 0;
4875 TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
4876 wParam, 0xff & HIWORD(lParam));
4877 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
4878 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
4879 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
4880 if(mask == (fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
4881 TRACE_(accel)(", but incorrect SHIFT/CTRL/ALT-state\n");
4882 }
4883 else
4884 {
4885 if (!(lParam & 0x01000000)) /* no special_key */
4886 {
4887 if ((fVirt & FALT) && (lParam & 0x20000000))
4888 { /* ^^ ALT pressed */
4889 TRACE_(accel)("found accel for Alt-%c\n", wParam & 0xff);
4890 goto found;
4891 }
4892 }
4893 }
4894 }
4895 return FALSE;
4896
4897 found:
4898 if (message == WM_KEYUP || message == WM_SYSKEYUP)
4899 mesg = 1;
4900 else if (GetCapture())
4901 mesg = 2;
4902 else if (!IsWindowEnabled(hWnd))
4903 mesg = 3;
4904 else
4905 {
4906 HMENU hMenu, hSubMenu, hSysMenu;
4907 UINT uSysStat = (UINT)-1, uStat = (UINT)-1, nPos;
4908
4909 hMenu = (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) ? 0 : GetMenu(hWnd);
4910 hSysMenu = get_win_sys_menu( hWnd );
4911
4912 /* find menu item and ask application to initialize it */
4913 /* 1. in the system menu */
4914 hSubMenu = hSysMenu;
4915 nPos = cmd;
4916 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4917 {
4918 SendMessageA(hWnd, WM_INITMENU, (WPARAM)hSysMenu, 0L);
4919 if(hSubMenu != hSysMenu)
4920 {
4921 nPos = MENU_FindSubMenu(&hSysMenu, hSubMenu);
4922 TRACE_(accel)("hSysMenu = %04x, hSubMenu = %04x, nPos = %d\n", hSysMenu, hSubMenu, nPos);
4923 SendMessageA(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, TRUE));
4924 }
4925 uSysStat = GetMenuState(GetSubMenu(hSysMenu, 0), cmd, MF_BYCOMMAND);
4926 }
4927 else /* 2. in the window's menu */
4928 {
4929 hSubMenu = hMenu;
4930 nPos = cmd;
4931 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4932 {
4933 SendMessageA(hWnd, WM_INITMENU, (WPARAM)hMenu, 0L);
4934 if(hSubMenu != hMenu)
4935 {
4936 nPos = MENU_FindSubMenu(&hMenu, hSubMenu);
4937 TRACE_(accel)("hMenu = %04x, hSubMenu = %04x, nPos = %d\n", hMenu, hSubMenu, nPos);
4938 SendMessageA(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, FALSE));
4939 }
4940 uStat = GetMenuState(hMenu, cmd, MF_BYCOMMAND);
4941 }
4942 }
4943
4944 if (uSysStat != (UINT)-1)
4945 {
4946 if (uSysStat & (MF_DISABLED|MF_GRAYED))
4947 mesg=4;
4948 else
4949 mesg=WM_SYSCOMMAND;
4950 }
4951 else
4952 {
4953 if (uStat != (UINT)-1)
4954 {
4955 if (IsIconic(hWnd))
4956 mesg=5;
4957 else
4958 {
4959 if (uStat & (MF_DISABLED|MF_GRAYED))
4960 mesg=6;
4961 else
4962 mesg=WM_COMMAND;
4963 }
4964 }
4965 else
4966 mesg=WM_COMMAND;
4967 }
4968 }
4969
4970 if( mesg==WM_COMMAND )
4971 {
4972 TRACE_(accel)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd);
4973 SendMessageA(hWnd, mesg, 0x10000 | cmd, 0L);
4974 }
4975 else if( mesg==WM_SYSCOMMAND )
4976 {
4977 TRACE_(accel)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd);
4978 SendMessageA(hWnd, mesg, cmd, 0x00010000L);
4979 }
4980 else
4981 {
4982 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
4983 * #0: unknown (please report!)
4984 * #1: for WM_KEYUP,WM_SYSKEYUP
4985 * #2: mouse is captured
4986 * #3: window is disabled
4987 * #4: it's a disabled system menu option
4988 * #5: it's a menu option, but window is iconic
4989 * #6: it's a menu option, but disabled
4990 */
4991 TRACE_(accel)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
4992 if(mesg==0)
4993 ERR_(accel)(" unknown reason - please report!");
4994 }
4995 return TRUE;
4996}
4997
4998/**********************************************************************
4999 * TranslateAccelerator (USER32.@)
5000 * TranslateAcceleratorA (USER32.@)
5001 * TranslateAcceleratorW (USER32.@)
5002 */
5003INT WINAPI TranslateAccelerator( HWND hWnd, HACCEL hAccel, LPMSG msg )
5004{
5005 /* YES, Accel16! */
5006 LPACCEL16 lpAccelTbl;
5007 int i;
5008
5009 if (msg == NULL)
5010 {
5011 WARN_(accel)("msg null; should hang here to be win compatible\n");
5012 return 0;
5013 }
5014 if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(HACCEL_16(hAccel))))
5015 {
5016 WARN_(accel)("invalid accel handle=%x\n", hAccel);
5017 return 0;
5018 }
5019 if ((msg->message != WM_KEYDOWN &&
5020 msg->message != WM_KEYUP &&
5021 msg->message != WM_SYSKEYDOWN &&
5022 msg->message != WM_SYSKEYUP &&
5023 msg->message != WM_CHAR)) return 0;
5024
5025 TRACE_(accel)("TranslateAccelerators hAccel=%04x, hWnd=%04x,"
5026 "msg->hwnd=%04x, msg->message=%04x, wParam=%08x, lParam=%lx\n",
5027 hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
5028
5029 i = 0;
5030 do
5031 {
5032 if (translate_accelerator( hWnd, msg->message, msg->wParam, msg->lParam,
5033 lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
5034 return 1;
5035 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
5036 WARN_(accel)("couldn't translate accelerator key\n");
5037 return 0;
5038}
5039#endif
Note: See TracBrowser for help on using the repository browser.