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

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

Menu control: do not paint default menu item strings in bold if in OS/2 GUI mode

File size: 141.8 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 hTrackMenu = get_win_sys_menu( hwnd );
3177 uItem = 0;
3178 wParam |= HTSYSMENU; /* prevent item lookup */
3179 }
3180
3181 if (!IsMenu( hTrackMenu )) return;
3182
3183 MENU_InitTracking( hwnd, hTrackMenu, FALSE, wFlags );
3184
3185 if( vkey && vkey != VK_SPACE )
3186 {
3187 uItem = MENU_FindItemByKey( hwnd, hTrackMenu, vkey, (wParam & HTSYSMENU) );
3188 if( uItem >= (UINT)(-2) )
3189 {
3190#ifndef __WIN32OS2__
3191 //Don't beep when unable to find menu item when alt key pressed
3192 if( uItem == (UINT)(-1) ) MessageBeep(0);
3193#endif
3194 hTrackMenu = 0;
3195 }
3196 }
3197
3198 if( hTrackMenu )
3199 {
3200 MENU_SelectItem( hwnd, hTrackMenu, uItem, TRUE, 0 );
3201
3202 if( uItem == NO_SELECTED_ITEM )
3203 MENU_MoveSelection( hwnd, hTrackMenu, ITEM_NEXT );
3204 else if( vkey )
3205 PostMessageA( hwnd, WM_KEYDOWN, VK_DOWN, 0L );
3206
3207 MENU_TrackMenu( hTrackMenu, wFlags, 0, 0, hwnd, NULL );
3208 }
3209 MENU_ExitTracking( hwnd );
3210}
3211
3212
3213/**********************************************************************
3214 * TrackPopupMenu (USER32.@)
3215 *
3216 * Like the win32 API, the function return the command ID only if the
3217 * flag TPM_RETURNCMD is on.
3218 *
3219 */
3220BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
3221 INT nReserved, HWND hWnd, const RECT *lpRect )
3222{
3223 BOOL ret = FALSE;
3224
3225 MENU_InitTracking(hWnd, hMenu, TRUE, wFlags);
3226
3227 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3228 if (!(wFlags & TPM_NONOTIFY))
3229 SendMessageA( hWnd, WM_INITMENUPOPUP, hMenu, 0);
3230
3231 if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
3232 ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect );
3233 MENU_ExitTracking(hWnd);
3234
3235 if( (!(wFlags & TPM_RETURNCMD)) && (ret != FALSE) )
3236 ret = 1;
3237
3238 return ret;
3239}
3240
3241/**********************************************************************
3242 * TrackPopupMenuEx (USER32.@)
3243 */
3244BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
3245 HWND hWnd, LPTPMPARAMS lpTpm )
3246{
3247 FIXME("not fully implemented\n" );
3248 return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
3249 lpTpm ? &lpTpm->rcExclude : NULL );
3250}
3251
3252/***********************************************************************
3253 * PopupMenuWndProc
3254 *
3255 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3256 */
3257static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
3258{
3259 TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
3260 hwnd, message, wParam, lParam);
3261
3262 switch(message)
3263 {
3264 case WM_CREATE:
3265 {
3266 CREATESTRUCTW *cs = (CREATESTRUCTW*)lParam;
3267 SetWindowLongW( hwnd, 0, (LONG)cs->lpCreateParams );
3268 return 0;
3269 }
3270
3271 case WM_MOUSEACTIVATE: /* We don't want to be activated */
3272 return MA_NOACTIVATE;
3273
3274 case WM_PAINT:
3275 {
3276 PAINTSTRUCT ps;
3277 BeginPaint( hwnd, &ps );
3278 MENU_DrawPopupMenu( hwnd, ps.hdc,
3279 (HMENU)GetWindowLongA( hwnd, 0 ) );
3280 EndPaint( hwnd, &ps );
3281 return 0;
3282 }
3283 case WM_ERASEBKGND:
3284 return 1;
3285
3286 case WM_DESTROY:
3287 /* zero out global pointer in case resident popup window was destroyed. */
3288 if (hwnd == top_popup) top_popup = 0;
3289 break;
3290
3291 case WM_SHOWWINDOW:
3292
3293 if( wParam )
3294 {
3295 if (!GetWindowLongW( hwnd, 0 )) ERR("no menu to display\n");
3296 }
3297 else
3298 SetWindowLongW( hwnd, 0, 0 );
3299 break;
3300
3301 case MM_SETMENUHANDLE:
3302 SetWindowLongW( hwnd, 0, wParam );
3303 break;
3304
3305 case MM_GETMENUHANDLE:
3306 return GetWindowLongW( hwnd, 0 );
3307
3308 default:
3309 return DefWindowProcW( hwnd, message, wParam, lParam );
3310 }
3311 return 0;
3312}
3313
3314
3315/***********************************************************************
3316 * MENU_GetMenuBarHeight
3317 *
3318 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3319 */
3320UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
3321 INT orgX, INT orgY )
3322{
3323 HDC hdc;
3324 RECT rectBar;
3325 LPPOPUPMENU lppop;
3326
3327 TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3328 hwnd, menubarWidth, orgX, orgY );
3329
3330 if (!(lppop = MENU_GetMenu( GetMenu(hwnd) ))) return 0;
3331
3332 hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
3333 SelectObject( hdc, hMenuFont);
3334 SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU));
3335 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
3336 ReleaseDC( hwnd, hdc );
3337 return lppop->Height;
3338}
3339
3340
3341/*******************************************************************
3342 * ChangeMenuA (USER32.@)
3343 */
3344BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
3345 UINT id, UINT flags )
3346{
3347 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3348 hMenu, pos, (DWORD)data, id, flags );
3349 if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
3350 id, data );
3351 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3352 if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
3353 id, data );
3354 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3355 flags & MF_BYPOSITION ? pos : id,
3356 flags & ~MF_REMOVE );
3357 /* Default: MF_INSERT */
3358 return InsertMenuA( hMenu, pos, flags, id, data );
3359}
3360
3361
3362/*******************************************************************
3363 * ChangeMenuW (USER32.@)
3364 */
3365BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
3366 UINT id, UINT flags )
3367{
3368 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3369 hMenu, pos, (DWORD)data, id, flags );
3370 if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
3371 id, data );
3372 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3373 if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
3374 id, data );
3375 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3376 flags & MF_BYPOSITION ? pos : id,
3377 flags & ~MF_REMOVE );
3378 /* Default: MF_INSERT */
3379 return InsertMenuW( hMenu, pos, flags, id, data );
3380}
3381
3382
3383/*******************************************************************
3384 * CheckMenuItem (USER32.@)
3385 */
3386DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
3387{
3388 MENUITEM *item;
3389 DWORD ret;
3390
3391 TRACE("menu=%04x id=%04x flags=%04x\n", hMenu, id, flags );
3392 if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
3393 ret = item->fState & MF_CHECKED;
3394 if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
3395 else item->fState &= ~MF_CHECKED;
3396 return ret;
3397}
3398
3399
3400/**********************************************************************
3401 * EnableMenuItem (USER32.@)
3402 */
3403UINT WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
3404{
3405 UINT oldflags;
3406 MENUITEM *item;
3407 POPUPMENU *menu;
3408
3409 TRACE("(%04x, %04X, %04X) !\n",
3410 hMenu, wItemID, wFlags);
3411
3412 /* Get the Popupmenu to access the owner menu */
3413 if (!(menu = MENU_GetMenu(hMenu)))
3414 return (UINT)-1;
3415
3416 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
3417 return (UINT)-1;
3418
3419 oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
3420 item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
3421
3422 /* In win95 if the close item in the system menu change update the close button */
3423 if (TWEAK_WineLook == WIN95_LOOK)
3424 if((item->wID == SC_CLOSE) && (oldflags != wFlags))
3425 {
3426 if (menu->hSysMenuOwner != 0)
3427 {
3428 POPUPMENU* parentMenu;
3429
3430 /* Get the parent menu to access*/
3431 if (!(parentMenu = MENU_GetMenu(menu->hSysMenuOwner)))
3432 return (UINT)-1;
3433
3434 /* Refresh the frame to reflect the change*/
3435 SetWindowPos(parentMenu->hWnd, 0, 0, 0, 0, 0,
3436 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
3437 }
3438 }
3439
3440 return oldflags;
3441}
3442
3443
3444/*******************************************************************
3445 * GetMenuStringA (USER32.@)
3446 */
3447INT WINAPI GetMenuStringA(
3448 HMENU hMenu, /* [in] menuhandle */
3449 UINT wItemID, /* [in] menu item (dep. on wFlags) */
3450 LPSTR str, /* [out] outbuffer. If NULL, func returns entry length*/
3451 INT nMaxSiz, /* [in] length of buffer. if 0, func returns entry len*/
3452 UINT wFlags /* [in] MF_ flags */
3453) {
3454 MENUITEM *item;
3455
3456 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3457 hMenu, wItemID, str, nMaxSiz, wFlags );
3458 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3459 if (!IS_STRING_ITEM(item->fType)) return 0;
3460 if (!str || !nMaxSiz) return strlenW(item->text);
3461 str[0] = '\0';
3462 if (!WideCharToMultiByte( CP_ACP, 0, item->text, -1, str, nMaxSiz, NULL, NULL ))
3463 str[nMaxSiz-1] = 0;
3464 TRACE("returning '%s'\n", str );
3465 return strlen(str);
3466}
3467
3468
3469/*******************************************************************
3470 * GetMenuStringW (USER32.@)
3471 */
3472INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
3473 LPWSTR str, INT nMaxSiz, UINT wFlags )
3474{
3475 MENUITEM *item;
3476
3477 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3478 hMenu, wItemID, str, nMaxSiz, wFlags );
3479 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3480 if (!IS_STRING_ITEM(item->fType)) return 0;
3481 if (!str || !nMaxSiz) return strlenW(item->text);
3482 str[0] = '\0';
3483 lstrcpynW( str, item->text, nMaxSiz );
3484 return strlenW(str);
3485}
3486
3487
3488/**********************************************************************
3489 * HiliteMenuItem (USER32.@)
3490 */
3491BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
3492 UINT wHilite )
3493{
3494 LPPOPUPMENU menu;
3495 TRACE("(%04x, %04x, %04x, %04x);\n",
3496 hWnd, hMenu, wItemID, wHilite);
3497 if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
3498 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3499 if (menu->FocusedItem == wItemID) return TRUE;
3500 MENU_HideSubPopups( hWnd, hMenu, FALSE );
3501 MENU_SelectItem( hWnd, hMenu, wItemID, TRUE, 0 );
3502 return TRUE;
3503}
3504
3505
3506/**********************************************************************
3507 * GetMenuState (USER32.@)
3508 */
3509UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
3510{
3511 MENUITEM *item;
3512 TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
3513 hMenu, wItemID, wFlags);
3514 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
3515 debug_print_menuitem (" item: ", item, "");
3516 if (item->fType & MF_POPUP)
3517 {
3518 POPUPMENU *menu = MENU_GetMenu( item->hSubMenu );
3519 if (!menu) return -1;
3520 else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
3521 }
3522 else
3523 {
3524 /* We used to (from way back then) mask the result to 0xff. */
3525 /* I don't know why and it seems wrong as the documented */
3526 /* return flag MF_SEPARATOR is outside that mask. */
3527 return (item->fType | item->fState);
3528 }
3529}
3530
3531
3532/**********************************************************************
3533 * GetMenuItemCount (USER32.@)
3534 */
3535INT WINAPI GetMenuItemCount( HMENU hMenu )
3536{
3537 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3538 if (!menu) return -1;
3539 TRACE("(%04x) returning %d\n",
3540 hMenu, menu->nItems );
3541 return menu->nItems;
3542}
3543
3544/**********************************************************************
3545 * GetMenuItemID (USER.264)
3546 */
3547UINT16 WINAPI GetMenuItemID16( HMENU16 hMenu, INT16 nPos )
3548{
3549 return (UINT16) GetMenuItemID (hMenu, nPos);
3550}
3551
3552/**********************************************************************
3553 * GetMenuItemID (USER32.@)
3554 */
3555UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
3556{
3557 MENUITEM * lpmi;
3558
3559 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return -1;
3560 if (lpmi->fType & MF_POPUP) return -1;
3561 return lpmi->wID;
3562
3563}
3564
3565
3566/*******************************************************************
3567 * InsertMenuW (USER32.@)
3568 */
3569BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
3570 UINT id, LPCWSTR str )
3571{
3572 MENUITEM *item;
3573
3574 if (IS_STRING_ITEM(flags) && str)
3575 TRACE("hMenu %04x, pos %d, flags %08x, "
3576 "id %04x, str %s\n",
3577 hMenu, pos, flags, id, debugstr_w(str) );
3578 else TRACE("hMenu %04x, pos %d, flags %08x, "
3579 "id %04x, str %08lx (not a string)\n",
3580 hMenu, pos, flags, id, (DWORD)str );
3581
3582 if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
3583
3584 if (!(MENU_SetItemData( item, flags, id, str )))
3585 {
3586 RemoveMenu( hMenu, pos, flags );
3587 return FALSE;
3588 }
3589
3590 if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
3591 (MENU_GetMenu((HMENU16)id))->wFlags |= MF_POPUP;
3592
3593 item->hCheckBit = item->hUnCheckBit = 0;
3594 return TRUE;
3595}
3596
3597
3598/*******************************************************************
3599 * InsertMenuA (USER32.@)
3600 */
3601BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
3602 UINT id, LPCSTR str )
3603{
3604 BOOL ret = FALSE;
3605
3606 if (IS_STRING_ITEM(flags) && str)
3607 {
3608 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3609 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3610 if (newstr)
3611 {
3612 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3613 ret = InsertMenuW( hMenu, pos, flags, id, newstr );
3614 HeapFree( GetProcessHeap(), 0, newstr );
3615 }
3616 return ret;
3617 }
3618 else return InsertMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3619}
3620
3621
3622/*******************************************************************
3623 * AppendMenuA (USER32.@)
3624 */
3625BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
3626 UINT id, LPCSTR data )
3627{
3628 return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
3629}
3630
3631
3632/*******************************************************************
3633 * AppendMenuW (USER32.@)
3634 */
3635BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
3636 UINT id, LPCWSTR data )
3637{
3638 return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
3639}
3640
3641
3642/**********************************************************************
3643 * RemoveMenu (USER32.@)
3644 */
3645BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3646{
3647 LPPOPUPMENU menu;
3648 MENUITEM *item;
3649
3650 TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
3651 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3652 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3653
3654 /* Remove item */
3655
3656 MENU_FreeItemData( item );
3657
3658 if (--menu->nItems == 0)
3659 {
3660 HeapFree( GetProcessHeap(), 0, menu->items );
3661 menu->items = NULL;
3662 }
3663 else
3664 {
3665 while(nPos < menu->nItems)
3666 {
3667 *item = *(item+1);
3668 item++;
3669 nPos++;
3670 }
3671 menu->items = HeapReAlloc( GetProcessHeap(), 0, menu->items,
3672 menu->nItems * sizeof(MENUITEM) );
3673 }
3674 return TRUE;
3675}
3676
3677
3678/**********************************************************************
3679 * DeleteMenu (USER32.@)
3680 */
3681BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3682{
3683 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
3684 if (!item) return FALSE;
3685 if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
3686 /* nPos is now the position of the item */
3687 RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
3688 return TRUE;
3689}
3690
3691
3692/*******************************************************************
3693 * ModifyMenuW (USER32.@)
3694 */
3695BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
3696 UINT id, LPCWSTR str )
3697{
3698 MENUITEM *item;
3699
3700 if (IS_STRING_ITEM(flags))
3701 {
3702 TRACE("%04x %d %04x %04x %s\n",
3703 hMenu, pos, flags, id, debugstr_w(str) );
3704 if (!str) return FALSE;
3705 }
3706 else
3707 {
3708 TRACE("%04x %d %04x %04x %08lx\n",
3709 hMenu, pos, flags, id, (DWORD)str );
3710 }
3711
3712 if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
3713 return MENU_SetItemData( item, flags, id, str );
3714}
3715
3716
3717/*******************************************************************
3718 * ModifyMenuA (USER32.@)
3719 */
3720BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
3721 UINT id, LPCSTR str )
3722{
3723 BOOL ret = FALSE;
3724
3725 if (IS_STRING_ITEM(flags) && str)
3726 {
3727 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3728 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3729 if (newstr)
3730 {
3731 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3732 ret = ModifyMenuW( hMenu, pos, flags, id, newstr );
3733 HeapFree( GetProcessHeap(), 0, newstr );
3734 }
3735 return ret;
3736 }
3737 else return ModifyMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3738}
3739
3740
3741/**********************************************************************
3742 * CreatePopupMenu (USER32.@)
3743 */
3744HMENU WINAPI CreatePopupMenu(void)
3745{
3746 HMENU hmenu;
3747 POPUPMENU *menu;
3748
3749 if (!(hmenu = CreateMenu())) return 0;
3750 menu = MENU_GetMenu( hmenu );
3751 menu->wFlags |= MF_POPUP;
3752 menu->bTimeToHide = FALSE;
3753 return hmenu;
3754}
3755
3756
3757/**********************************************************************
3758 * GetMenuCheckMarkDimensions (USER.417)
3759 * GetMenuCheckMarkDimensions (USER32.@)
3760 */
3761DWORD WINAPI GetMenuCheckMarkDimensions(void)
3762{
3763 return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK) );
3764}
3765
3766
3767/**********************************************************************
3768 * SetMenuItemBitmaps (USER32.@)
3769 */
3770BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
3771 HBITMAP hNewUnCheck, HBITMAP hNewCheck)
3772{
3773 MENUITEM *item;
3774 TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3775 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
3776 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3777
3778 if (!hNewCheck && !hNewUnCheck)
3779 {
3780 item->fState &= ~MF_USECHECKBITMAPS;
3781 }
3782 else /* Install new bitmaps */
3783 {
3784 item->hCheckBit = hNewCheck;
3785 item->hUnCheckBit = hNewUnCheck;
3786 item->fState |= MF_USECHECKBITMAPS;
3787 }
3788 return TRUE;
3789}
3790
3791
3792/**********************************************************************
3793 * CreateMenu (USER32.@)
3794 */
3795HMENU WINAPI CreateMenu(void)
3796{
3797 HMENU hMenu;
3798 LPPOPUPMENU menu;
3799
3800#ifdef __WIN32OS2__
3801 if (!(menu = (LPPOPUPMENU)HeapAlloc(GetProcessHeap(),0,sizeof(POPUPMENU)))) return 0;
3802 if(ObjAllocateHandle(&hMenu, (DWORD)menu, HNDL_MENU) == FALSE) return 0;
3803#else
3804 if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
3805 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3806#endif
3807 ZeroMemory(menu, sizeof(POPUPMENU));
3808 menu->wMagic = MENU_MAGIC;
3809 menu->FocusedItem = NO_SELECTED_ITEM;
3810 menu->bTimeToHide = FALSE;
3811
3812 TRACE("return %04x\n", hMenu );
3813
3814 return hMenu;
3815}
3816
3817
3818/**********************************************************************
3819 * DestroyMenu (USER32.@)
3820 */
3821BOOL WINAPI DestroyMenu( HMENU hMenu )
3822{
3823 TRACE("(%04x)\n", hMenu);
3824
3825 /* Silently ignore attempts to destroy default system popup */
3826
3827 if (hMenu && hMenu != MENU_DefSysPopup)
3828 {
3829 LPPOPUPMENU lppop = MENU_GetMenu(hMenu);
3830
3831 if (!lppop) return FALSE;
3832
3833 lppop->wMagic = 0; /* Mark it as destroyed */
3834
3835 if ((lppop->wFlags & MF_POPUP) && lppop->hWnd)
3836 {
3837 DestroyWindow( lppop->hWnd );
3838 lppop->hWnd = 0;
3839 }
3840
3841 if (lppop->items) /* recursively destroy submenus */
3842 {
3843 int i;
3844 MENUITEM *item = lppop->items;
3845 for (i = lppop->nItems; i > 0; i--, item++)
3846 {
3847 if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
3848 MENU_FreeItemData( item );
3849 }
3850 HeapFree( GetProcessHeap(), 0, lppop->items );
3851 }
3852#ifdef __WIN32OS2__
3853 HeapFree(GetProcessHeap(),0,(LPVOID)lppop);
3854 ObjDeleteHandle(hMenu, HNDL_MENU);
3855#else
3856 USER_HEAP_FREE( hMenu );
3857#endif
3858 }
3859 return (hMenu != MENU_DefSysPopup);
3860}
3861
3862
3863/**********************************************************************
3864 * GetSystemMenu (USER32.@)
3865 */
3866HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
3867{
3868#ifdef __WIN32OS2__
3869 HMENU retvalue = 0;
3870
3871 if(IsWindow(hWnd))
3872 {
3873 HMENU hSysMenu = getSysMenu(hWnd);
3874 if(hSysMenu)
3875 {
3876 if( bRevert )
3877 {
3878 DestroyMenu(hSysMenu);
3879 hSysMenu = 0;
3880 setSysMenu(hWnd,hSysMenu);
3881 }
3882 else
3883 {
3884 POPUPMENU *menu = MENU_GetMenu(hSysMenu);
3885 if(menu)
3886 {
3887 if( menu->nItems > 0 && menu->items[0].hSubMenu == MENU_DefSysPopup )
3888 menu->items[0].hSubMenu = MENU_CopySysPopup();
3889 }
3890 else
3891 {
3892 //WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
3893 // wndPtr->hSysMenu, hWnd);
3894 hSysMenu = 0;
3895 setSysMenu(hWnd,hSysMenu);
3896 }
3897 }
3898 }
3899
3900 if(!hSysMenu && (GetWindowLongA(hWnd,GWL_STYLE) & WS_SYSMENU) )
3901 {
3902 hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
3903 setSysMenu(hWnd,hSysMenu);
3904 }
3905
3906 if( hSysMenu )
3907 {
3908 POPUPMENU *menu;
3909 retvalue = GetSubMenu(hSysMenu, 0);
3910
3911 /* Store the dummy sysmenu handle to facilitate the refresh */
3912 /* of the close button if the SC_CLOSE item change */
3913 menu = MENU_GetMenu(retvalue);
3914 if (menu)
3915 menu->hSysMenuOwner = hSysMenu;
3916 }
3917 }
3918 return bRevert ? 0 : retvalue;
3919#else
3920 WND *wndPtr = WIN_FindWndPtr( hWnd );
3921 HMENU retvalue = 0;
3922
3923 if (wndPtr)
3924 {
3925 if( wndPtr->hSysMenu )
3926 {
3927 if( bRevert )
3928 {
3929 DestroyMenu(wndPtr->hSysMenu);
3930 wndPtr->hSysMenu = 0;
3931 }
3932 else
3933 {
3934 POPUPMENU *menu = MENU_GetMenu( wndPtr->hSysMenu );
3935 if( menu )
3936 {
3937 if( menu->nItems > 0 && menu->items[0].hSubMenu == MENU_DefSysPopup )
3938 menu->items[0].hSubMenu = MENU_CopySysPopup();
3939 }
3940 else
3941 {
3942 WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
3943 wndPtr->hSysMenu, hWnd);
3944 wndPtr->hSysMenu = 0;
3945 }
3946 }
3947 }
3948
3949 if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
3950 wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
3951
3952 if( wndPtr->hSysMenu )
3953 {
3954 POPUPMENU *menu;
3955 retvalue = GetSubMenu(wndPtr->hSysMenu, 0);
3956
3957 /* Store the dummy sysmenu handle to facilitate the refresh */
3958 /* of the close button if the SC_CLOSE item change */
3959 menu = MENU_GetMenu(retvalue);
3960 if ( menu )
3961 menu->hSysMenuOwner = wndPtr->hSysMenu;
3962 }
3963 WIN_ReleaseWndPtr(wndPtr);
3964 }
3965 return bRevert ? 0 : retvalue;
3966#endif
3967}
3968
3969
3970/*******************************************************************
3971 * SetSystemMenu (USER32.@)
3972 */
3973BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
3974{
3975#ifdef __WIN32OS2__
3976 HMENU hSysMenu;
3977
3978 if(!IsWindow(hwnd)) return FALSE;
3979
3980 hSysMenu = getSysMenu(hwnd);
3981 if(hSysMenu) DestroyMenu(hSysMenu);
3982
3983 setSysMenu(hwnd, MENU_GetSysMenu( hwnd, hMenu ));
3984 return TRUE;
3985#else
3986 WND *wndPtr = WIN_FindWndPtr(hwnd);
3987
3988 if (wndPtr)
3989 {
3990 if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
3991 wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
3992 WIN_ReleaseWndPtr(wndPtr);
3993 return TRUE;
3994 }
3995 return FALSE;
3996#endif
3997}
3998
3999
4000/**********************************************************************
4001 * GetMenu (USER32.@)
4002 */
4003HMENU WINAPI GetMenu( HWND hWnd )
4004{
4005 HMENU retvalue = (HMENU)GetWindowLongA( hWnd, GWL_ID );
4006#ifdef __WIN32OS2__
4007 if(MENU_GetMenu(retvalue) != NULL) {
4008 return retvalue;
4009 }
4010 dprintf(("WARNING: Invalid menu %x", retvalue));
4011 return 0;
4012#else
4013 TRACE("for %04x returning %04x\n", hWnd, retvalue);
4014 return retvalue;
4015#endif
4016}
4017
4018
4019/**********************************************************************
4020 * SetMenu (USER32.@)
4021 */
4022BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
4023{
4024 TRACE("(%04x, %04x);\n", hWnd, hMenu);
4025
4026 if (hMenu && !IsMenu(hMenu))
4027 {
4028 WARN("hMenu %x is not a menu handle\n", hMenu);
4029 return FALSE;
4030 }
4031 if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
4032
4033 hWnd = WIN_GetFullHandle( hWnd );
4034 if (GetCapture() == hWnd) ReleaseCapture();
4035
4036 if (hMenu != 0)
4037 {
4038 LPPOPUPMENU lpmenu;
4039
4040 if (!(lpmenu = MENU_GetMenu(hMenu))) return FALSE;
4041
4042 lpmenu->hWnd = hWnd;
4043 lpmenu->Height = 0; /* Make sure we recalculate the size */
4044 }
4045 SetWindowLongA( hWnd, GWL_ID, hMenu );
4046
4047 if (IsWindowVisible(hWnd))
4048 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4049 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4050 return TRUE;
4051}
4052
4053
4054
4055/**********************************************************************
4056 * GetSubMenu (USER32.@)
4057 */
4058HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
4059{
4060 MENUITEM * lpmi;
4061
4062#ifdef __WIN32OS2__
4063 if (!(lpmi = MENU_FindItem(&hMenu,(UINT*)&nPos,MF_BYPOSITION))) {
4064 SetLastError(ERROR_INVALID_HANDLE);
4065 return 0;
4066 }
4067#else
4068 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
4069#endif
4070 if (!(lpmi->fType & MF_POPUP)) return 0;
4071 return lpmi->hSubMenu;
4072}
4073
4074
4075/**********************************************************************
4076 * DrawMenuBar (USER32.@)
4077 */
4078BOOL WINAPI DrawMenuBar( HWND hWnd )
4079{
4080 LPPOPUPMENU lppop;
4081 HMENU hMenu = GetMenu(hWnd);
4082
4083 if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
4084 if (!hMenu || !(lppop = MENU_GetMenu( hMenu ))) return FALSE;
4085
4086 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
4087 lppop->hwndOwner = hWnd;
4088 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4089 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4090 return TRUE;
4091}
4092
4093/***********************************************************************
4094 * DrawMenuBarTemp (USER32.@)
4095 *
4096 * UNDOCUMENTED !!
4097 *
4098 * called by W98SE desk.cpl Control Panel Applet
4099 *
4100 * Not 100% sure about the param names, but close.
4101 */
4102DWORD WINAPI DrawMenuBarTemp(HWND someHWND, HDC someHDC, LPRECT someRECT, HMENU someHMENU, HFONT someFONT)
4103{
4104 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, 0x%08x): stub\n", someHWND, someHDC, someRECT, someHMENU, someFONT);
4105 return 0;
4106}
4107
4108/***********************************************************************
4109 * EndMenu (USER.187)
4110 * EndMenu (USER32.@)
4111 */
4112void WINAPI EndMenu(void)
4113{
4114 /* if we are in the menu code, and it is active */
4115 if (!fEndMenu && top_popup)
4116 {
4117 /* terminate the menu handling code */
4118 fEndMenu = TRUE;
4119
4120 /* needs to be posted to wakeup the internal menu handler */
4121 /* which will now terminate the menu, in the event that */
4122 /* the main window was minimized, or lost focus, so we */
4123 /* don't end up with an orphaned menu */
4124 PostMessageA( top_popup, WM_CANCELMODE, 0, 0);
4125 }
4126}
4127
4128
4129/***********************************************************************
4130 * LookupMenuHandle (USER.217)
4131 */
4132HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
4133{
4134 HMENU hmenu32 = hmenu;
4135 UINT id32 = id;
4136 if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
4137 else return hmenu32;
4138}
4139
4140
4141#ifndef __WIN32OS2__
4142/**********************************************************************
4143 * LoadMenu (USER.150)
4144 */
4145HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, LPCSTR name )
4146{
4147 HRSRC16 hRsrc;
4148 HGLOBAL16 handle;
4149 HMENU16 hMenu;
4150
4151 TRACE("(%04x,%s)\n", instance, debugres_a(name) );
4152
4153 if (HIWORD(name))
4154 {
4155 if (name[0] == '#') name = (LPCSTR)atoi( name + 1 );
4156 }
4157
4158 if (!name) return 0;
4159
4160 /* check for Win32 module */
4161 if (HIWORD(instance)) return LoadMenuA( instance, name );
4162 instance = GetExePtr( instance );
4163
4164 if (!(hRsrc = FindResource16( instance, name, RT_MENUA ))) return 0;
4165 if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
4166 hMenu = LoadMenuIndirect16(LockResource16(handle));
4167 FreeResource16( handle );
4168 return hMenu;
4169}
4170#endif
4171
4172/*****************************************************************
4173 * LoadMenuA (USER32.@)
4174 */
4175HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
4176{
4177 HRSRC hrsrc = FindResourceA( instance, name, RT_MENUA );
4178 if (!hrsrc) return 0;
4179 return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
4180}
4181
4182
4183/*****************************************************************
4184 * LoadMenuW (USER32.@)
4185 */
4186HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
4187{
4188 HRSRC hrsrc = FindResourceW( instance, name, RT_MENUW );
4189 if (!hrsrc) return 0;
4190 return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
4191}
4192
4193
4194/**********************************************************************
4195 * LoadMenuIndirect (USER.220)
4196 */
4197HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
4198{
4199 HMENU16 hMenu;
4200 WORD version, offset;
4201 LPCSTR p = (LPCSTR)template;
4202
4203 TRACE("(%p)\n", template );
4204 version = GET_WORD(p);
4205 p += sizeof(WORD);
4206 if (version)
4207 {
4208 WARN("version must be 0 for Win16\n" );
4209 return 0;
4210 }
4211 offset = GET_WORD(p);
4212 p += sizeof(WORD) + offset;
4213 if (!(hMenu = CreateMenu())) return 0;
4214 if (!MENU_ParseResource( p, hMenu, FALSE ))
4215 {
4216 DestroyMenu( hMenu );
4217 return 0;
4218 }
4219 return hMenu;
4220}
4221
4222
4223/**********************************************************************
4224 * LoadMenuIndirectA (USER32.@)
4225 */
4226HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
4227{
4228 HMENU16 hMenu;
4229 WORD version, offset;
4230 LPCSTR p = (LPCSTR)template;
4231
4232 TRACE("%p\n", template );
4233 version = GET_WORD(p);
4234 p += sizeof(WORD);
4235 switch (version)
4236 {
4237 case 0:
4238 offset = GET_WORD(p);
4239 p += sizeof(WORD) + offset;
4240 if (!(hMenu = CreateMenu())) return 0;
4241 if (!MENU_ParseResource( p, hMenu, TRUE ))
4242 {
4243 DestroyMenu( hMenu );
4244 return 0;
4245 }
4246 return hMenu;
4247 case 1:
4248 offset = GET_WORD(p);
4249 p += sizeof(WORD) + offset;
4250 if (!(hMenu = CreateMenu())) return 0;
4251 if (!MENUEX_ParseResource( p, hMenu))
4252 {
4253 DestroyMenu( hMenu );
4254 return 0;
4255 }
4256 return hMenu;
4257 default:
4258 ERR("version %d not supported.\n", version);
4259 return 0;
4260 }
4261}
4262
4263
4264/**********************************************************************
4265 * LoadMenuIndirectW (USER32.@)
4266 */
4267HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
4268{
4269 /* FIXME: is there anything different between A and W? */
4270 return LoadMenuIndirectA( template );
4271}
4272
4273
4274/**********************************************************************
4275 * IsMenu (USER32.@)
4276 */
4277BOOL WINAPI IsMenu(HMENU hmenu)
4278{
4279 LPPOPUPMENU menu = MENU_GetMenu(hmenu);
4280 return menu != NULL;
4281}
4282
4283/**********************************************************************
4284 * GetMenuItemInfo_common
4285 */
4286
4287static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
4288 LPMENUITEMINFOW lpmii, BOOL unicode)
4289{
4290 MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
4291
4292 debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
4293
4294 if (!menu)
4295 return FALSE;
4296
4297 if (lpmii->fMask & MIIM_TYPE) {
4298 lpmii->fType = menu->fType;
4299 switch (MENU_ITEM_TYPE(menu->fType)) {
4300 case MF_STRING:
4301 break; /* will be done below */
4302 case MF_OWNERDRAW:
4303 case MF_BITMAP:
4304 lpmii->dwTypeData = menu->text;
4305 /* fall through */
4306 default:
4307 lpmii->cch = 0;
4308 }
4309 }
4310
4311 /* copy the text string */
4312 if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING)) &&
4313 (MENU_ITEM_TYPE(menu->fType) == MF_STRING) && menu->text)
4314 {
4315 int len;
4316 if (unicode)
4317 {
4318 len = strlenW(menu->text);
4319 if(lpmii->dwTypeData && lpmii->cch)
4320 lstrcpynW(lpmii->dwTypeData, menu->text, lpmii->cch);
4321 }
4322 else
4323 {
4324 len = WideCharToMultiByte( CP_ACP, 0, menu->text, -1, NULL, 0, NULL, NULL );
4325 if(lpmii->dwTypeData && lpmii->cch)
4326 if (!WideCharToMultiByte( CP_ACP, 0, menu->text, -1,
4327 (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
4328 ((LPSTR)lpmii->dwTypeData)[lpmii->cch-1] = 0;
4329 }
4330 /* if we've copied a substring we return its length */
4331 if(lpmii->dwTypeData && lpmii->cch)
4332 {
4333 if (lpmii->cch <= len) lpmii->cch--;
4334 }
4335 else /* return length of string */
4336 lpmii->cch = len;
4337 }
4338
4339 if (lpmii->fMask & MIIM_FTYPE)
4340 lpmii->fType = menu->fType;
4341
4342 if (lpmii->fMask & MIIM_BITMAP)
4343 lpmii->hbmpItem = menu->hbmpItem;
4344
4345 if (lpmii->fMask & MIIM_STATE)
4346 lpmii->fState = menu->fState;
4347
4348 if (lpmii->fMask & MIIM_ID)
4349 lpmii->wID = menu->wID;
4350
4351 if (lpmii->fMask & MIIM_SUBMENU)
4352 lpmii->hSubMenu = menu->hSubMenu;
4353
4354 if (lpmii->fMask & MIIM_CHECKMARKS) {
4355 lpmii->hbmpChecked = menu->hCheckBit;
4356 lpmii->hbmpUnchecked = menu->hUnCheckBit;
4357 }
4358 if (lpmii->fMask & MIIM_DATA)
4359 lpmii->dwItemData = menu->dwItemData;
4360
4361 return TRUE;
4362}
4363
4364/**********************************************************************
4365 * GetMenuItemInfoA (USER32.@)
4366 */
4367BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
4368 LPMENUITEMINFOA lpmii)
4369{
4370 return GetMenuItemInfo_common (hmenu, item, bypos,
4371 (LPMENUITEMINFOW)lpmii, FALSE);
4372}
4373
4374/**********************************************************************
4375 * GetMenuItemInfoW (USER32.@)
4376 */
4377BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
4378 LPMENUITEMINFOW lpmii)
4379{
4380 return GetMenuItemInfo_common (hmenu, item, bypos,
4381 lpmii, TRUE);
4382}
4383
4384
4385/* set a menu item text from a ASCII or Unicode string */
4386inline static void set_menu_item_text( MENUITEM *menu, LPCWSTR text, BOOL unicode )
4387{
4388 if (!text)
4389 {
4390 menu->text = NULL;
4391 menu->fType |= MF_SEPARATOR;
4392 }
4393 else if (unicode)
4394 {
4395 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, (strlenW(text)+1) * sizeof(WCHAR) )))
4396 strcpyW( menu->text, text );
4397 }
4398 else
4399 {
4400 LPCSTR str = (LPCSTR)text;
4401 int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
4402 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
4403 MultiByteToWideChar( CP_ACP, 0, str, -1, menu->text, len );
4404 }
4405}
4406
4407
4408/**********************************************************************
4409 * SetMenuItemInfo_common
4410 */
4411
4412static BOOL SetMenuItemInfo_common(MENUITEM * menu,
4413 const MENUITEMINFOW *lpmii,
4414 BOOL unicode)
4415{
4416 if (!menu) return FALSE;
4417
4418 debug_print_menuitem("MENU_SetItemInfo_common from: ", menu, "");
4419
4420 if (lpmii->fMask & MIIM_TYPE ) {
4421 /* Get rid of old string. */
4422 if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4423 HeapFree(GetProcessHeap(), 0, menu->text);
4424 menu->text = NULL;
4425 }
4426
4427 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4428 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4429 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4430
4431 menu->text = lpmii->dwTypeData;
4432
4433 if (IS_STRING_ITEM(menu->fType))
4434 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4435 }
4436
4437 if (lpmii->fMask & MIIM_FTYPE ) {
4438 /* free the string when the type is changing */
4439 if ( (!IS_STRING_ITEM(lpmii->fType)) && IS_STRING_ITEM(menu->fType) && menu->text) {
4440 HeapFree(GetProcessHeap(), 0, menu->text);
4441 menu->text = NULL;
4442 }
4443 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4444 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4445 if ( IS_STRING_ITEM(menu->fType) && !menu->text )
4446 menu->fType |= MF_SEPARATOR;
4447 }
4448
4449 if (lpmii->fMask & MIIM_STRING ) {
4450 /* free the string when used */
4451 if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4452 HeapFree(GetProcessHeap(), 0, menu->text);
4453 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4454 }
4455 }
4456
4457 if (lpmii->fMask & MIIM_STATE)
4458 {
4459 /* FIXME: MFS_DEFAULT do we have to reset the other menu items? */
4460 menu->fState = lpmii->fState;
4461 }
4462
4463 if (lpmii->fMask & MIIM_ID)
4464 menu->wID = lpmii->wID;
4465
4466 if (lpmii->fMask & MIIM_SUBMENU) {
4467 menu->hSubMenu = lpmii->hSubMenu;
4468 if (menu->hSubMenu) {
4469 POPUPMENU *subMenu = MENU_GetMenu((UINT16)menu->hSubMenu);
4470 if (subMenu) {
4471 subMenu->wFlags |= MF_POPUP;
4472 menu->fType |= MF_POPUP;
4473 }
4474 else
4475 /* FIXME: Return an error ? */
4476 menu->fType &= ~MF_POPUP;
4477 }
4478 else
4479 menu->fType &= ~MF_POPUP;
4480 }
4481
4482 if (lpmii->fMask & MIIM_CHECKMARKS)
4483 {
4484 if (lpmii->fType & MFT_RADIOCHECK)
4485 menu->fType |= MFT_RADIOCHECK;
4486
4487 menu->hCheckBit = lpmii->hbmpChecked;
4488 menu->hUnCheckBit = lpmii->hbmpUnchecked;
4489 }
4490 if (lpmii->fMask & MIIM_DATA)
4491 menu->dwItemData = lpmii->dwItemData;
4492
4493 debug_print_menuitem("SetMenuItemInfo_common to : ", menu, "");
4494 return TRUE;
4495}
4496
4497/**********************************************************************
4498 * SetMenuItemInfoA (USER32.@)
4499 */
4500BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
4501 const MENUITEMINFOA *lpmii)
4502{
4503 if ((lpmii->fType & (MF_HILITE|MF_POPUP)) || (lpmii->fState)) {
4504 /* QuickTime does pass invalid data into SetMenuItemInfo.
4505 * do some of the checks Windows does.
4506 */
4507 WARN("Bad masks for type (0x%08x) or state (0x%08x)\n",
4508 lpmii->fType,lpmii->fState );
4509 return FALSE;
4510 }
4511
4512 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4513 (const MENUITEMINFOW *)lpmii, FALSE);
4514}
4515
4516/**********************************************************************
4517 * SetMenuItemInfoW (USER32.@)
4518 */
4519BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
4520 const MENUITEMINFOW *lpmii)
4521{
4522 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4523 lpmii, TRUE);
4524}
4525
4526/**********************************************************************
4527 * SetMenuDefaultItem (USER32.@)
4528 *
4529 */
4530BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
4531{
4532 UINT i;
4533 POPUPMENU *menu;
4534 MENUITEM *item;
4535
4536 TRACE("(0x%x,%d,%d)\n", hmenu, uItem, bypos);
4537
4538 if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
4539
4540 /* reset all default-item flags */
4541 item = menu->items;
4542 for (i = 0; i < menu->nItems; i++, item++)
4543 {
4544 item->fState &= ~MFS_DEFAULT;
4545 }
4546
4547 /* no default item */
4548 if ( -1 == uItem)
4549 {
4550 return TRUE;
4551 }
4552
4553 item = menu->items;
4554 if ( bypos )
4555 {
4556 if ( uItem >= menu->nItems ) return FALSE;
4557 item[uItem].fState |= MFS_DEFAULT;
4558 return TRUE;
4559 }
4560 else
4561 {
4562 for (i = 0; i < menu->nItems; i++, item++)
4563 {
4564 if (item->wID == uItem)
4565 {
4566 item->fState |= MFS_DEFAULT;
4567 return TRUE;
4568 }
4569 }
4570
4571 }
4572 return FALSE;
4573}
4574
4575/**********************************************************************
4576 * GetMenuDefaultItem (USER32.@)
4577 */
4578UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
4579{
4580 POPUPMENU *menu;
4581 MENUITEM * item;
4582 UINT i = 0;
4583
4584 TRACE("(0x%x,%d,%d)\n", hmenu, bypos, flags);
4585
4586 if (!(menu = MENU_GetMenu(hmenu))) return -1;
4587
4588 /* find default item */
4589 item = menu->items;
4590
4591 /* empty menu */
4592 if (! item) return -1;
4593
4594 while ( !( item->fState & MFS_DEFAULT ) )
4595 {
4596 i++; item++;
4597 if (i >= menu->nItems ) return -1;
4598 }
4599
4600 /* default: don't return disabled items */
4601 if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
4602
4603 /* search rekursiv when needed */
4604 if ( (item->fType & MF_POPUP) && (flags & GMDI_GOINTOPOPUPS) )
4605 {
4606 UINT ret;
4607 ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
4608 if ( -1 != ret ) return ret;
4609
4610 /* when item not found in submenu, return the popup item */
4611 }
4612 return ( bypos ) ? i : item->wID;
4613
4614}
4615
4616
4617/**********************************************************************
4618 * InsertMenuItemA (USER32.@)
4619 */
4620BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4621 const MENUITEMINFOA *lpmii)
4622{
4623 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4624 return SetMenuItemInfo_common(item, (const MENUITEMINFOW *)lpmii, FALSE);
4625}
4626
4627
4628/**********************************************************************
4629 * InsertMenuItemW (USER32.@)
4630 */
4631BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4632 const MENUITEMINFOW *lpmii)
4633{
4634 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4635 return SetMenuItemInfo_common(item, lpmii, TRUE);
4636}
4637
4638/**********************************************************************
4639 * CheckMenuRadioItem (USER32.@)
4640 */
4641
4642BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4643 UINT first, UINT last, UINT check,
4644 UINT bypos)
4645{
4646 MENUITEM *mifirst, *milast, *micheck;
4647 HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
4648
4649 TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4650 hMenu, first, last, check, bypos);
4651
4652 mifirst = MENU_FindItem (&mfirst, &first, bypos);
4653 milast = MENU_FindItem (&mlast, &last, bypos);
4654 micheck = MENU_FindItem (&mcheck, &check, bypos);
4655
4656 if (mifirst == NULL || milast == NULL || micheck == NULL ||
4657 mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4658 micheck > milast || micheck < mifirst)
4659 return FALSE;
4660
4661 while (mifirst <= milast)
4662 {
4663 if (mifirst == micheck)
4664 {
4665 mifirst->fType |= MFT_RADIOCHECK;
4666 mifirst->fState |= MFS_CHECKED;
4667 } else {
4668 mifirst->fType &= ~MFT_RADIOCHECK;
4669 mifirst->fState &= ~MFS_CHECKED;
4670 }
4671 mifirst++;
4672 }
4673
4674 return TRUE;
4675}
4676
4677/**********************************************************************
4678 * GetMenuItemRect (USER32.@)
4679 *
4680 * ATTENTION: Here, the returned values in rect are the screen
4681 * coordinates of the item just like if the menu was
4682 * always on the upper left side of the application.
4683 *
4684 */
4685BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4686 LPRECT rect)
4687{
4688 POPUPMENU *itemMenu;
4689 MENUITEM *item;
4690 HWND referenceHwnd;
4691
4692 TRACE("(0x%x,0x%x,%d,%p)\n", hwnd, hMenu, uItem, rect);
4693
4694 item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
4695 referenceHwnd = hwnd;
4696
4697 if(!hwnd)
4698 {
4699 itemMenu = MENU_GetMenu(hMenu);
4700 if (itemMenu == NULL)
4701 return FALSE;
4702
4703 if(itemMenu->hWnd == 0)
4704 return FALSE;
4705 referenceHwnd = itemMenu->hWnd;
4706 }
4707
4708 if ((rect == NULL) || (item == NULL))
4709 return FALSE;
4710
4711 *rect = item->rect;
4712
4713 MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
4714
4715 return TRUE;
4716}
4717
4718
4719/**********************************************************************
4720 * SetMenuInfo (USER32.@)
4721 *
4722 * FIXME
4723 * MIM_APPLYTOSUBMENUS
4724 * actually use the items to draw the menu
4725 */
4726BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
4727{
4728 POPUPMENU *menu;
4729
4730 TRACE("(0x%04x %p)\n", hMenu, lpmi);
4731
4732 if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu = MENU_GetMenu(hMenu)))
4733 {
4734
4735 if (lpmi->fMask & MIM_BACKGROUND)
4736 menu->hbrBack = lpmi->hbrBack;
4737
4738 if (lpmi->fMask & MIM_HELPID)
4739 menu->dwContextHelpID = lpmi->dwContextHelpID;
4740
4741 if (lpmi->fMask & MIM_MAXHEIGHT)
4742 menu->cyMax = lpmi->cyMax;
4743
4744 if (lpmi->fMask & MIM_MENUDATA)
4745 menu->dwMenuData = lpmi->dwMenuData;
4746
4747 if (lpmi->fMask & MIM_STYLE)
4748 menu->dwStyle = lpmi->dwStyle;
4749
4750 return TRUE;
4751 }
4752 return FALSE;
4753}
4754
4755/**********************************************************************
4756 * GetMenuInfo (USER32.@)
4757 *
4758 * NOTES
4759 * win98/NT5.0
4760 *
4761 */
4762BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
4763{ POPUPMENU *menu;
4764
4765 TRACE("(0x%04x %p)\n", hMenu, lpmi);
4766
4767 if (lpmi && (menu = MENU_GetMenu(hMenu)))
4768 {
4769
4770 if (lpmi->fMask & MIM_BACKGROUND)
4771 lpmi->hbrBack = menu->hbrBack;
4772
4773 if (lpmi->fMask & MIM_HELPID)
4774 lpmi->dwContextHelpID = menu->dwContextHelpID;
4775
4776 if (lpmi->fMask & MIM_MAXHEIGHT)
4777 lpmi->cyMax = menu->cyMax;
4778
4779 if (lpmi->fMask & MIM_MENUDATA)
4780 lpmi->dwMenuData = menu->dwMenuData;
4781
4782 if (lpmi->fMask & MIM_STYLE)
4783 lpmi->dwStyle = menu->dwStyle;
4784
4785 return TRUE;
4786 }
4787 return FALSE;
4788}
4789
4790/**********************************************************************
4791 * SetMenuContextHelpId (USER32.@)
4792 */
4793BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
4794{
4795 LPPOPUPMENU menu;
4796
4797 TRACE("(0x%04x 0x%08lx)\n", hMenu, dwContextHelpID);
4798
4799 if ((menu = MENU_GetMenu(hMenu)))
4800 {
4801 menu->dwContextHelpID = dwContextHelpID;
4802 return TRUE;
4803 }
4804 return FALSE;
4805}
4806
4807/**********************************************************************
4808 * GetMenuContextHelpId (USER32.@)
4809 */
4810DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
4811{
4812 LPPOPUPMENU menu;
4813
4814 TRACE("(0x%04x)\n", hMenu);
4815
4816 if ((menu = MENU_GetMenu(hMenu)))
4817 {
4818 return menu->dwContextHelpID;
4819 }
4820 return 0;
4821}
4822
4823/**********************************************************************
4824 * MenuItemFromPoint (USER32.@)
4825 */
4826UINT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
4827{
4828 POPUPMENU *menu = MENU_GetMenu(hMenu);
4829 UINT pos;
4830 MENUITEM *item;
4831
4832 /*FIXME: Do we have to handle hWnd here? */
4833 item = MENU_FindItemByCoords(menu, ptScreen, &pos);
4834
4835 return pos;
4836}
4837
4838#ifdef __WIN32OS2__
4839//******************************************************************************
4840//******************************************************************************
4841void WIN32API DisableOdinSysMenuItems()
4842{
4843 fDisableOdinSysMenuItems = TRUE;
4844}
4845//******************************************************************************
4846//******************************************************************************
4847#else
4848//winaccel.cpp
4849/**********************************************************************
4850 * translate_accelerator
4851 */
4852static BOOL translate_accelerator( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
4853 BYTE fVirt, WORD key, WORD cmd )
4854{
4855 UINT mesg = 0;
4856
4857 if (wParam != key) return FALSE;
4858
4859 if (message == WM_CHAR)
4860 {
4861 if ( !(fVirt & FALT) && !(fVirt & FVIRTKEY) )
4862 {
4863 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", wParam & 0xff);
4864 goto found;
4865 }
4866 }
4867 else
4868 {
4869 if(fVirt & FVIRTKEY)
4870 {
4871 INT mask = 0;
4872 TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
4873 wParam, 0xff & HIWORD(lParam));
4874 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
4875 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
4876 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
4877 if(mask == (fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
4878 TRACE_(accel)(", but incorrect SHIFT/CTRL/ALT-state\n");
4879 }
4880 else
4881 {
4882 if (!(lParam & 0x01000000)) /* no special_key */
4883 {
4884 if ((fVirt & FALT) && (lParam & 0x20000000))
4885 { /* ^^ ALT pressed */
4886 TRACE_(accel)("found accel for Alt-%c\n", wParam & 0xff);
4887 goto found;
4888 }
4889 }
4890 }
4891 }
4892 return FALSE;
4893
4894 found:
4895 if (message == WM_KEYUP || message == WM_SYSKEYUP)
4896 mesg = 1;
4897 else if (GetCapture())
4898 mesg = 2;
4899 else if (!IsWindowEnabled(hWnd))
4900 mesg = 3;
4901 else
4902 {
4903 HMENU hMenu, hSubMenu, hSysMenu;
4904 UINT uSysStat = (UINT)-1, uStat = (UINT)-1, nPos;
4905
4906 hMenu = (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) ? 0 : GetMenu(hWnd);
4907 hSysMenu = get_win_sys_menu( hWnd );
4908
4909 /* find menu item and ask application to initialize it */
4910 /* 1. in the system menu */
4911 hSubMenu = hSysMenu;
4912 nPos = cmd;
4913 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4914 {
4915 SendMessageA(hWnd, WM_INITMENU, (WPARAM)hSysMenu, 0L);
4916 if(hSubMenu != hSysMenu)
4917 {
4918 nPos = MENU_FindSubMenu(&hSysMenu, hSubMenu);
4919 TRACE_(accel)("hSysMenu = %04x, hSubMenu = %04x, nPos = %d\n", hSysMenu, hSubMenu, nPos);
4920 SendMessageA(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, TRUE));
4921 }
4922 uSysStat = GetMenuState(GetSubMenu(hSysMenu, 0), cmd, MF_BYCOMMAND);
4923 }
4924 else /* 2. in the window's menu */
4925 {
4926 hSubMenu = hMenu;
4927 nPos = cmd;
4928 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4929 {
4930 SendMessageA(hWnd, WM_INITMENU, (WPARAM)hMenu, 0L);
4931 if(hSubMenu != hMenu)
4932 {
4933 nPos = MENU_FindSubMenu(&hMenu, hSubMenu);
4934 TRACE_(accel)("hMenu = %04x, hSubMenu = %04x, nPos = %d\n", hMenu, hSubMenu, nPos);
4935 SendMessageA(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, FALSE));
4936 }
4937 uStat = GetMenuState(hMenu, cmd, MF_BYCOMMAND);
4938 }
4939 }
4940
4941 if (uSysStat != (UINT)-1)
4942 {
4943 if (uSysStat & (MF_DISABLED|MF_GRAYED))
4944 mesg=4;
4945 else
4946 mesg=WM_SYSCOMMAND;
4947 }
4948 else
4949 {
4950 if (uStat != (UINT)-1)
4951 {
4952 if (IsIconic(hWnd))
4953 mesg=5;
4954 else
4955 {
4956 if (uStat & (MF_DISABLED|MF_GRAYED))
4957 mesg=6;
4958 else
4959 mesg=WM_COMMAND;
4960 }
4961 }
4962 else
4963 mesg=WM_COMMAND;
4964 }
4965 }
4966
4967 if( mesg==WM_COMMAND )
4968 {
4969 TRACE_(accel)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd);
4970 SendMessageA(hWnd, mesg, 0x10000 | cmd, 0L);
4971 }
4972 else if( mesg==WM_SYSCOMMAND )
4973 {
4974 TRACE_(accel)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd);
4975 SendMessageA(hWnd, mesg, cmd, 0x00010000L);
4976 }
4977 else
4978 {
4979 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
4980 * #0: unknown (please report!)
4981 * #1: for WM_KEYUP,WM_SYSKEYUP
4982 * #2: mouse is captured
4983 * #3: window is disabled
4984 * #4: it's a disabled system menu option
4985 * #5: it's a menu option, but window is iconic
4986 * #6: it's a menu option, but disabled
4987 */
4988 TRACE_(accel)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
4989 if(mesg==0)
4990 ERR_(accel)(" unknown reason - please report!");
4991 }
4992 return TRUE;
4993}
4994
4995/**********************************************************************
4996 * TranslateAccelerator (USER32.@)
4997 * TranslateAcceleratorA (USER32.@)
4998 * TranslateAcceleratorW (USER32.@)
4999 */
5000INT WINAPI TranslateAccelerator( HWND hWnd, HACCEL hAccel, LPMSG msg )
5001{
5002 /* YES, Accel16! */
5003 LPACCEL16 lpAccelTbl;
5004 int i;
5005
5006 if (msg == NULL)
5007 {
5008 WARN_(accel)("msg null; should hang here to be win compatible\n");
5009 return 0;
5010 }
5011 if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(HACCEL_16(hAccel))))
5012 {
5013 WARN_(accel)("invalid accel handle=%x\n", hAccel);
5014 return 0;
5015 }
5016 if ((msg->message != WM_KEYDOWN &&
5017 msg->message != WM_KEYUP &&
5018 msg->message != WM_SYSKEYDOWN &&
5019 msg->message != WM_SYSKEYUP &&
5020 msg->message != WM_CHAR)) return 0;
5021
5022 TRACE_(accel)("TranslateAccelerators hAccel=%04x, hWnd=%04x,"
5023 "msg->hwnd=%04x, msg->message=%04x, wParam=%08x, lParam=%lx\n",
5024 hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
5025
5026 i = 0;
5027 do
5028 {
5029 if (translate_accelerator( hWnd, msg->message, msg->wParam, msg->lParam,
5030 lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
5031 return 1;
5032 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
5033 WARN_(accel)("couldn't translate accelerator key\n");
5034 return 0;
5035}
5036#endif
Note: See TracBrowser for help on using the repository browser.