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

Last change on this file since 9607 was 9607, checked in by sandervl, 23 years ago

fix for alt key & menu activation; fixed color of highlighted menubar item

File size: 141.5 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 FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1251 }
1252 }
1253 else
1254 FillRect( hdc, &rect, GetSysColorBrush(COLOR_MENU) );
1255 }
1256
1257 SetBkMode( hdc, TRANSPARENT );
1258
1259 if (!(lpitem->fType & MF_OWNERDRAW))
1260 {
1261 /* vertical separator */
1262 if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
1263 {
1264 if (TWEAK_WineLook > WIN31_LOOK)
1265 {
1266 RECT rc = rect;
1267 rc.top = 3;
1268 rc.bottom = height - 3;
1269 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
1270 }
1271 else
1272 {
1273 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1274 MoveToEx( hdc, rect.left, 0, NULL );
1275 LineTo( hdc, rect.left, height );
1276 }
1277 }
1278
1279 /* horizontal separator */
1280 if (lpitem->fType & MF_SEPARATOR)
1281 {
1282 if (TWEAK_WineLook > WIN31_LOOK)
1283 {
1284 RECT rc = rect;
1285 rc.left++;
1286 rc.right--;
1287 rc.top += SEPARATOR_HEIGHT / 2;
1288 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
1289 }
1290 else
1291 {
1292 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1293 MoveToEx( hdc, rect.left, rect.top + SEPARATOR_HEIGHT/2, NULL );
1294 LineTo( hdc, rect.right, rect.top + SEPARATOR_HEIGHT/2 );
1295 }
1296 return;
1297 }
1298 }
1299
1300 /* Setup colors */
1301
1302 if (lpitem->fState & MF_HILITE)
1303 {
1304#ifdef __WIN32OS2__
1305 if(!fOS2Look)
1306#else
1307 if(TWEAK_WineLook == WIN98_LOOK)
1308#endif
1309 {
1310 if(menuBar) {
1311 SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT));
1312 SetBkColor(hdc, GetSysColor(COLOR_MENU));
1313 } else {
1314 if(lpitem->fState & MF_GRAYED)
1315 SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
1316 else
1317 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1318 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1319 }
1320 }
1321 else /* Not Win98 Look */
1322 {
1323 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1324 if(!IS_BITMAP_ITEM(lpitem->fType))
1325 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1326 }
1327 }
1328 else
1329 {
1330 if (lpitem->fState & MF_GRAYED)
1331 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1332 else
1333 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
1334 SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
1335 }
1336
1337 /* helper lines for debugging */
1338/* FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1339 SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
1340 MoveToEx( hdc, rect.left, (rect.top + rect.bottom)/2, NULL );
1341 LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
1342*/
1343
1344 if (!menuBar)
1345 {
1346 INT y = rect.top + rect.bottom;
1347 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
1348 UINT check_bitmap_height = GetSystemMetrics( SM_CYMENUCHECK );
1349
1350 if (!(lpitem->fType & MF_OWNERDRAW))
1351 {
1352 /* Draw the check mark
1353 *
1354 * FIXME:
1355 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1356 */
1357 HBITMAP bm = (lpitem->fState & MF_CHECKED) ? lpitem->hCheckBit : lpitem->hUnCheckBit;
1358 if (bm) /* we have a custom bitmap */
1359 {
1360 HDC hdcMem = CreateCompatibleDC( hdc );
1361 SelectObject( hdcMem, bm );
1362 BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
1363 check_bitmap_width, check_bitmap_height,
1364 hdcMem, 0, 0, SRCCOPY );
1365 DeleteDC( hdcMem );
1366 }
1367 else if (lpitem->fState & MF_CHECKED) /* standard bitmaps */
1368 {
1369 RECT r;
1370 HBITMAP bm = CreateBitmap( check_bitmap_width, check_bitmap_height, 1, 1, NULL );
1371 HDC hdcMem = CreateCompatibleDC( hdc );
1372 SelectObject( hdcMem, bm );
1373 SetRect( &r, 0, 0, check_bitmap_width, check_bitmap_height );
1374 DrawFrameControl( hdcMem, &r, DFC_MENU,
1375 (lpitem->fType & MFT_RADIOCHECK) ?
1376 DFCS_MENUBULLET : DFCS_MENUCHECK );
1377 BitBlt( hdc, rect.left, (y - r.bottom) / 2, r.right, r.bottom,
1378 hdcMem, 0, 0, SRCCOPY );
1379 DeleteDC( hdcMem );
1380 DeleteObject( bm );
1381 }
1382 }
1383
1384 /* Draw the popup-menu arrow */
1385 if (lpitem->fType & MF_POPUP)
1386 {
1387 HDC hdcMem = CreateCompatibleDC( hdc );
1388 HBITMAP hOrigBitmap;
1389
1390 hOrigBitmap = SelectObject( hdcMem, hStdMnArrow );
1391 BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
1392 (y - arrow_bitmap_height) / 2,
1393 arrow_bitmap_width, arrow_bitmap_height,
1394 hdcMem, 0, 0, SRCCOPY );
1395 SelectObject( hdcMem, hOrigBitmap );
1396 DeleteDC( hdcMem );
1397 }
1398
1399 rect.left += check_bitmap_width;
1400 rect.right -= arrow_bitmap_width;
1401 }
1402
1403 /* Done for owner-drawn */
1404 if (lpitem->fType & MF_OWNERDRAW)
1405 return;
1406
1407 /* Draw the item text or bitmap */
1408 if (IS_BITMAP_ITEM(lpitem->fType))
1409 {
1410 MENU_DrawBitmapItem( hdc, lpitem, &rect, menuBar );
1411 return;
1412
1413 }
1414 /* No bitmap - process text if present */
1415 else if (IS_STRING_ITEM(lpitem->fType))
1416 {
1417 register int i;
1418 HFONT hfontOld = 0;
1419
1420 UINT uFormat = (menuBar) ?
1421 DT_CENTER | DT_VCENTER | DT_SINGLELINE :
1422 DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1423
1424 if ( lpitem->fState & MFS_DEFAULT )
1425 {
1426 hfontOld = SelectObject( hdc, hMenuFontBold);
1427 }
1428
1429 if (menuBar)
1430 {
1431 rect.left += MENU_BAR_ITEMS_SPACE / 2;
1432 rect.right -= MENU_BAR_ITEMS_SPACE / 2;
1433 }
1434
1435 for (i = 0; lpitem->text[i]; i++)
1436 if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
1437 break;
1438
1439 if( (TWEAK_WineLook != WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
1440 {
1441 if (!(lpitem->fState & MF_HILITE) )
1442 {
1443 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1444 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1445 DrawTextW( hdc, lpitem->text, i, &rect, uFormat );
1446 --rect.left; --rect.top; --rect.right; --rect.bottom;
1447 }
1448 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1449 }
1450
1451 DrawTextW( hdc, lpitem->text, i, &rect, uFormat);
1452
1453 /* paint the shortcut text */
1454 if (!menuBar && lpitem->text[i]) /* There's a tab or flush-right char */
1455 {
1456 if (lpitem->text[i] == '\t')
1457 {
1458 rect.left = lpitem->xTab;
1459 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1460 }
1461 else
1462 {
1463 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
1464 }
1465
1466 if( !(TWEAK_WineLook == WIN31_LOOK) && (lpitem->fState & MF_GRAYED))
1467 {
1468 if (!(lpitem->fState & MF_HILITE) )
1469 {
1470 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1471 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1472 DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1473 --rect.left; --rect.top; --rect.right; --rect.bottom;
1474 }
1475 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1476 }
1477 DrawTextW( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
1478 }
1479
1480 if (hfontOld)
1481 SelectObject (hdc, hfontOld);
1482 }
1483}
1484
1485
1486/***********************************************************************
1487 * MENU_DrawPopupMenu
1488 *
1489 * Paint a popup menu.
1490 */
1491static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
1492{
1493 HBRUSH hPrevBrush = 0;
1494 RECT rect;
1495
1496 TRACE("wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd, hdc, hmenu);
1497
1498 GetClientRect( hwnd, &rect );
1499
1500 if(TWEAK_WineLook == WIN31_LOOK)
1501 {
1502 rect.bottom -= POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
1503 rect.right -= POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER);
1504 }
1505
1506 if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) ))
1507 && (SelectObject( hdc, hMenuFont)))
1508 {
1509 HPEN hPrevPen;
1510
1511 Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
1512
1513 hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
1514 if( hPrevPen )
1515 {
1516 INT ropPrev, i;
1517 POPUPMENU *menu;
1518
1519 /* draw 3-d shade */
1520 if(TWEAK_WineLook == WIN31_LOOK) {
1521 SelectObject( hdc, hShadeBrush );
1522 SetBkMode( hdc, TRANSPARENT );
1523 ropPrev = SetROP2( hdc, R2_MASKPEN );
1524
1525 i = rect.right; /* why SetBrushOrg() doesn't? */
1526 PatBlt( hdc, i & 0xfffffffe,
1527 rect.top + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER),
1528 i%2 + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
1529 rect.bottom - rect.top, 0x00a000c9 );
1530 i = rect.bottom;
1531 PatBlt( hdc, rect.left + POPUP_XSHADE*GetSystemMetrics(SM_CXBORDER),
1532 i & 0xfffffffe,rect.right - rect.left,
1533 i%2 + POPUP_YSHADE*GetSystemMetrics(SM_CYBORDER), 0x00a000c9 );
1534 SelectObject( hdc, hPrevPen );
1535 SelectObject( hdc, hPrevBrush );
1536 SetROP2( hdc, ropPrev );
1537 }
1538 else
1539 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
1540
1541 /* draw menu items */
1542
1543 menu = MENU_GetMenu( hmenu );
1544 if (menu && menu->nItems)
1545 {
1546 MENUITEM *item;
1547 UINT u;
1548
1549 for (u = menu->nItems, item = menu->items; u > 0; u--, item++)
1550 MENU_DrawMenuItem( hwnd, hmenu, menu->hwndOwner, hdc, item,
1551 menu->Height, FALSE, ODA_DRAWENTIRE );
1552
1553 }
1554 } else
1555 {
1556 SelectObject( hdc, hPrevBrush );
1557 }
1558 }
1559}
1560
1561/***********************************************************************
1562 * MENU_DrawMenuBar
1563 *
1564 * Paint a menu bar. Returns the height of the menu bar.
1565 * called from [windows/nonclient.c]
1566 */
1567UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
1568 BOOL suppress_draw)
1569{
1570 LPPOPUPMENU lppop;
1571 UINT i,retvalue;
1572 HFONT hfontOld = 0;
1573 HMENU hMenu = GetMenu(hwnd);
1574
1575 lppop = MENU_GetMenu( hMenu );
1576 if (lppop == NULL || lprect == NULL)
1577 {
1578 retvalue = GetSystemMetrics(SM_CYMENU);
1579 goto END;
1580 }
1581
1582 TRACE("(%04x, %p, %p)\n", hDC, lprect, lppop);
1583
1584 hfontOld = SelectObject( hDC, hMenuFont);
1585
1586 if (lppop->Height == 0)
1587 MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
1588
1589 lprect->bottom = lprect->top + lppop->Height;
1590
1591 if (suppress_draw)
1592 {
1593 retvalue = lppop->Height;
1594 goto END;
1595 }
1596
1597 FillRect(hDC, lprect, GetSysColorBrush(COLOR_MENU) );
1598
1599 if (TWEAK_WineLook == WIN31_LOOK)
1600 {
1601 SelectObject( hDC, GetSysColorPen(COLOR_WINDOWFRAME) );
1602 MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
1603 LineTo( hDC, lprect->right, lprect->bottom );
1604 }
1605 else
1606 {
1607 SelectObject( hDC, GetSysColorPen(COLOR_3DFACE));
1608 MoveToEx( hDC, lprect->left, lprect->bottom, NULL );
1609 LineTo( hDC, lprect->right, lprect->bottom );
1610 }
1611
1612 if (lppop->nItems == 0)
1613 {
1614 retvalue = GetSystemMetrics(SM_CYMENU);
1615 goto END;
1616 }
1617
1618 for (i = 0; i < lppop->nItems; i++)
1619 {
1620 MENU_DrawMenuItem( hwnd, hMenu, hwnd,
1621 hDC, &lppop->items[i], lppop->Height, TRUE, ODA_DRAWENTIRE );
1622 }
1623 retvalue = lppop->Height;
1624
1625END:
1626 if (hfontOld) SelectObject (hDC, hfontOld);
1627 return retvalue;
1628}
1629
1630
1631/***********************************************************************
1632 * MENU_ShowPopup
1633 *
1634 * Display a popup menu.
1635 */
1636static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id,
1637 INT x, INT y, INT xanchor, INT yanchor )
1638{
1639 POPUPMENU *menu;
1640 UINT width, height;
1641
1642 TRACE("owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1643 hwndOwner, hmenu, id, x, y, xanchor, yanchor);
1644
1645 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
1646 if (menu->FocusedItem != NO_SELECTED_ITEM)
1647 {
1648 menu->items[menu->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1649 menu->FocusedItem = NO_SELECTED_ITEM;
1650 }
1651
1652 /* store the owner for DrawItem */
1653 menu->hwndOwner = hwndOwner;
1654
1655
1656 MENU_PopupMenuCalcSize( menu, hwndOwner );
1657
1658 /* adjust popup menu pos so that it fits within the desktop */
1659
1660 width = menu->Width + GetSystemMetrics(SM_CXBORDER);
1661 height = menu->Height + GetSystemMetrics(SM_CYBORDER);
1662
1663 if( x + width > GetSystemMetrics(SM_CXSCREEN ))
1664 {
1665 if( xanchor )
1666 x -= width - xanchor;
1667 if( x + width > GetSystemMetrics(SM_CXSCREEN))
1668 x = GetSystemMetrics(SM_CXSCREEN) - width;
1669 }
1670 if( x < 0 ) x = 0;
1671
1672 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1673 {
1674 if( yanchor )
1675 y -= height + yanchor;
1676 if( y + height > GetSystemMetrics(SM_CYSCREEN ))
1677 y = GetSystemMetrics(SM_CYSCREEN) - height;
1678 }
1679 if( y < 0 ) y = 0;
1680
1681 if( TWEAK_WineLook == WIN31_LOOK )
1682 {
1683 width += POPUP_XSHADE * GetSystemMetrics(SM_CXBORDER); /* add space for shading */
1684 height += POPUP_YSHADE * GetSystemMetrics(SM_CYBORDER);
1685 }
1686
1687 /* NOTE: In Windows, top menu popup is not owned. */
1688 menu->hWnd = CreateWindowA( POPUPMENU_CLASS_ATOM, NULL,
1689 WS_POPUP, x, y, width, height,
1690 hwndOwner, 0, GetWindowLongA(hwndOwner,GWL_HINSTANCE),
1691 (LPVOID)hmenu );
1692 if( !menu->hWnd ) return FALSE;
1693 if (!top_popup) top_popup = menu->hWnd;
1694
1695 /* Display the window */
1696
1697 SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
1698 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
1699 UpdateWindow( menu->hWnd );
1700 return TRUE;
1701}
1702
1703
1704/***********************************************************************
1705 * MENU_SelectItem
1706 */
1707static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex,
1708 BOOL sendMenuSelect, HMENU topmenu )
1709{
1710 LPPOPUPMENU lppop;
1711 HDC hdc;
1712
1713 TRACE("owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
1714
1715 lppop = MENU_GetMenu( hmenu );
1716 if ((!lppop) || (!lppop->nItems) || (!lppop->hWnd)) return;
1717
1718 if (lppop->FocusedItem == wIndex) return;
1719 if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
1720 else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
1721
1722 SelectObject( hdc, hMenuFont);
1723
1724 /* Clear previous highlighted item */
1725 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1726 {
1727 lppop->items[lppop->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
1728 MENU_DrawMenuItem(lppop->hWnd, hmenu, hwndOwner, hdc,&lppop->items[lppop->FocusedItem],
1729 lppop->Height, !(lppop->wFlags & MF_POPUP),
1730 ODA_SELECT );
1731 }
1732
1733 /* Highlight new item (if any) */
1734 lppop->FocusedItem = wIndex;
1735 if (lppop->FocusedItem != NO_SELECTED_ITEM)
1736 {
1737 if(!(lppop->items[wIndex].fType & MF_SEPARATOR)) {
1738 lppop->items[wIndex].fState |= MF_HILITE;
1739 MENU_DrawMenuItem( lppop->hWnd, hmenu, hwndOwner, hdc,
1740 &lppop->items[wIndex], lppop->Height,
1741 !(lppop->wFlags & MF_POPUP), ODA_SELECT );
1742 }
1743 if (sendMenuSelect)
1744 {
1745 MENUITEM *ip = &lppop->items[lppop->FocusedItem];
1746 SendMessageA( hwndOwner, WM_MENUSELECT,
1747 MAKELONG(ip->fType & MF_POPUP ? wIndex: ip->wID,
1748 ip->fType | ip->fState | MF_MOUSESELECT |
1749 (lppop->wFlags & MF_SYSMENU)), hmenu);
1750 }
1751 }
1752 else if (sendMenuSelect) {
1753 if(topmenu){
1754 int pos;
1755 if((pos=MENU_FindSubMenu(&topmenu, hmenu))!=NO_SELECTED_ITEM){
1756 POPUPMENU *ptm = MENU_GetMenu( topmenu );
1757 MENUITEM *ip = &ptm->items[pos];
1758 SendMessageA( hwndOwner, WM_MENUSELECT, MAKELONG(pos,
1759 ip->fType | ip->fState | MF_MOUSESELECT |
1760 (ptm->wFlags & MF_SYSMENU)), topmenu);
1761 }
1762 }
1763 }
1764 ReleaseDC( lppop->hWnd, hdc );
1765}
1766
1767
1768/***********************************************************************
1769 * MENU_MoveSelection
1770 *
1771 * Moves currently selected item according to the offset parameter.
1772 * If there is no selection then it should select the last item if
1773 * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
1774 */
1775static void MENU_MoveSelection( HWND hwndOwner, HMENU hmenu, INT offset )
1776{
1777 INT i;
1778 POPUPMENU *menu;
1779
1780 TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner, hmenu, offset);
1781
1782 menu = MENU_GetMenu( hmenu );
1783 if ((!menu) || (!menu->items)) return;
1784
1785 if ( menu->FocusedItem != NO_SELECTED_ITEM )
1786 {
1787 if( menu->nItems == 1 ) return; else
1788 for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems
1789 ; i += offset)
1790 if (!(menu->items[i].fType & MF_SEPARATOR))
1791 {
1792 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1793 return;
1794 }
1795 }
1796
1797 for ( i = (offset > 0) ? 0 : menu->nItems - 1;
1798 i >= 0 && i < menu->nItems ; i += offset)
1799 if (!(menu->items[i].fType & MF_SEPARATOR))
1800 {
1801 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
1802 return;
1803 }
1804}
1805
1806
1807/**********************************************************************
1808 * MENU_SetItemData
1809 *
1810 * Set an item flags, id and text ptr. Called by InsertMenu() and
1811 * ModifyMenu().
1812 */
1813static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT id,
1814 LPCWSTR str )
1815{
1816 LPWSTR prevText = IS_STRING_ITEM(item->fType) ? item->text : NULL;
1817
1818 debug_print_menuitem("MENU_SetItemData from: ", item, "");
1819 TRACE("flags=%x str=%p\n", flags, str);
1820
1821 if (IS_STRING_ITEM(flags))
1822 {
1823 if (!str)
1824 {
1825 flags |= MF_SEPARATOR;
1826 item->text = NULL;
1827 }
1828 else
1829 {
1830 LPWSTR text;
1831 /* Item beginning with a backspace is a help item */
1832 if (*str == '\b')
1833 {
1834 flags |= MF_HELP;
1835 str++;
1836 }
1837 if (!(text = HeapAlloc( GetProcessHeap(), 0, (strlenW(str)+1) * sizeof(WCHAR) )))
1838 return FALSE;
1839 strcpyW( text, str );
1840 item->text = text;
1841 }
1842 }
1843 else if (IS_BITMAP_ITEM(flags))
1844 item->text = (LPWSTR)(HBITMAP)LOWORD(str);
1845 else item->text = NULL;
1846
1847 if (flags & MF_OWNERDRAW)
1848 item->dwItemData = (DWORD)str;
1849 else
1850 item->dwItemData = 0;
1851
1852 if ((item->fType & MF_POPUP) && (flags & MF_POPUP) && (item->hSubMenu != id) )
1853 DestroyMenu( item->hSubMenu ); /* ModifyMenu() spec */
1854
1855 if (flags & MF_POPUP)
1856 {
1857 POPUPMENU *menu = MENU_GetMenu((UINT16)id);
1858 if (menu) menu->wFlags |= MF_POPUP;
1859 else
1860 {
1861 item->wID = 0;
1862 item->hSubMenu = 0;
1863 item->fType = 0;
1864 item->fState = 0;
1865 return FALSE;
1866 }
1867 }
1868
1869 item->wID = id;
1870 if (flags & MF_POPUP)
1871 item->hSubMenu = id;
1872
1873 if ((item->fType & MF_POPUP) && !(flags & MF_POPUP) )
1874 flags |= MF_POPUP; /* keep popup */
1875
1876 item->fType = flags & TYPE_MASK;
1877 item->fState = (flags & STATE_MASK) &
1878 ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
1879
1880
1881 /* Don't call SetRectEmpty here! */
1882
1883
1884 if (prevText) HeapFree( GetProcessHeap(), 0, prevText );
1885
1886 debug_print_menuitem("MENU_SetItemData to : ", item, "");
1887 return TRUE;
1888}
1889
1890
1891/**********************************************************************
1892 * MENU_InsertItem
1893 *
1894 * Insert a new item into a menu.
1895 */
1896static MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
1897{
1898 MENUITEM *newItems;
1899 POPUPMENU *menu;
1900
1901 if (!(menu = MENU_GetMenu(hMenu)))
1902 return NULL;
1903
1904 /* Find where to insert new item */
1905
1906 if (flags & MF_BYPOSITION) {
1907 if (pos > menu->nItems)
1908 pos = menu->nItems;
1909 } else {
1910 if (!MENU_FindItem( &hMenu, &pos, flags ))
1911 pos = menu->nItems;
1912 else {
1913 if (!(menu = MENU_GetMenu( hMenu )))
1914 return NULL;
1915 }
1916 }
1917
1918 /* Create new items array */
1919
1920 newItems = HeapAlloc( GetProcessHeap(), 0, sizeof(MENUITEM) * (menu->nItems+1) );
1921 if (!newItems)
1922 {
1923 WARN("allocation failed\n" );
1924 return NULL;
1925 }
1926 if (menu->nItems > 0)
1927 {
1928 /* Copy the old array into the new one */
1929 if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
1930 if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
1931 (menu->nItems-pos)*sizeof(MENUITEM) );
1932 HeapFree( GetProcessHeap(), 0, menu->items );
1933 }
1934 menu->items = newItems;
1935 menu->nItems++;
1936 memset( &newItems[pos], 0, sizeof(*newItems) );
1937 menu->Height = 0; /* force size recalculate */
1938 return &newItems[pos];
1939}
1940
1941
1942/**********************************************************************
1943 * MENU_ParseResource
1944 *
1945 * Parse a standard menu resource and add items to the menu.
1946 * Return a pointer to the end of the resource.
1947 */
1948static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
1949{
1950 WORD flags, id = 0;
1951 LPCSTR str;
1952
1953 do
1954 {
1955 flags = GET_WORD(res);
1956 res += sizeof(WORD);
1957 if (!(flags & MF_POPUP))
1958 {
1959 id = GET_WORD(res);
1960 res += sizeof(WORD);
1961 }
1962 str = res;
1963 if (!unicode) res += strlen(str) + 1;
1964 else res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
1965 if (flags & MF_POPUP)
1966 {
1967 HMENU hSubMenu = CreatePopupMenu();
1968 if (!hSubMenu) return NULL;
1969 if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
1970 return NULL;
1971 if (!unicode) AppendMenuA( hMenu, flags, (UINT)hSubMenu, str );
1972 else AppendMenuW( hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str );
1973 }
1974 else /* Not a popup */
1975 {
1976 if (!unicode) AppendMenuA( hMenu, flags, id, *str ? str : NULL );
1977 else AppendMenuW( hMenu, flags, id,
1978 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
1979 }
1980 } while (!(flags & MF_END));
1981 return res;
1982}
1983
1984
1985/**********************************************************************
1986 * MENUEX_ParseResource
1987 *
1988 * Parse an extended menu resource and add items to the menu.
1989 * Return a pointer to the end of the resource.
1990 */
1991static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
1992{
1993 WORD resinfo;
1994 do {
1995 MENUITEMINFOW mii;
1996
1997 mii.cbSize = sizeof(mii);
1998 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
1999 mii.fType = GET_DWORD(res);
2000 res += sizeof(DWORD);
2001 mii.fState = GET_DWORD(res);
2002 res += sizeof(DWORD);
2003 mii.wID = GET_DWORD(res);
2004 res += sizeof(DWORD);
2005 resinfo = GET_WORD(res); /* FIXME: for 16-bit apps this is a byte. */
2006 res += sizeof(WORD);
2007 /* Align the text on a word boundary. */
2008 res += (~((int)res - 1)) & 1;
2009 mii.dwTypeData = (LPWSTR) res;
2010 res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
2011 /* Align the following fields on a dword boundary. */
2012 res += (~((int)res - 1)) & 3;
2013
2014 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
2015 mii.fType, mii.fState, mii.wID, resinfo, debugstr_w(mii.dwTypeData));
2016
2017 if (resinfo & 1) { /* Pop-up? */
2018 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2019 res += sizeof(DWORD);
2020 mii.hSubMenu = CreatePopupMenu();
2021 if (!mii.hSubMenu)
2022 return NULL;
2023 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
2024 DestroyMenu(mii.hSubMenu);
2025 return NULL;
2026 }
2027 mii.fMask |= MIIM_SUBMENU;
2028 mii.fType |= MF_POPUP;
2029 }
2030 else if(!*mii.dwTypeData && !(mii.fType & MF_SEPARATOR))
2031 {
2032 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
2033 mii.wID, mii.fType);
2034 mii.fType |= MF_SEPARATOR;
2035 }
2036 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
2037 } while (!(resinfo & MF_END));
2038 return res;
2039}
2040
2041
2042/***********************************************************************
2043 * MENU_GetSubPopup
2044 *
2045 * Return the handle of the selected sub-popup menu (if any).
2046 */
2047static HMENU MENU_GetSubPopup( HMENU hmenu )
2048{
2049 POPUPMENU *menu;
2050 MENUITEM *item;
2051
2052 menu = MENU_GetMenu( hmenu );
2053
2054 if ((!menu) || (menu->FocusedItem == NO_SELECTED_ITEM)) return 0;
2055
2056 item = &menu->items[menu->FocusedItem];
2057 if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
2058 return item->hSubMenu;
2059 return 0;
2060}
2061
2062
2063/***********************************************************************
2064 * MENU_HideSubPopups
2065 *
2066 * Hide the sub-popup menus of this menu.
2067 */
2068static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
2069 BOOL sendMenuSelect )
2070{
2071 POPUPMENU *menu = MENU_GetMenu( hmenu );
2072
2073 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, sendMenuSelect);
2074
2075 if (menu && top_popup)
2076 {
2077 HMENU hsubmenu;
2078 POPUPMENU *submenu;
2079 MENUITEM *item;
2080
2081 if (menu->FocusedItem != NO_SELECTED_ITEM)
2082 {
2083 item = &menu->items[menu->FocusedItem];
2084 if (!(item->fType & MF_POPUP) ||
2085 !(item->fState & MF_MOUSESELECT)) return;
2086 item->fState &= ~MF_MOUSESELECT;
2087 hsubmenu = item->hSubMenu;
2088 } else return;
2089
2090 submenu = MENU_GetMenu( hsubmenu );
2091 MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
2092 MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect, 0 );
2093 DestroyWindow( submenu->hWnd );
2094 submenu->hWnd = 0;
2095 }
2096}
2097
2098
2099/***********************************************************************
2100 * MENU_ShowSubPopup
2101 *
2102 * Display the sub-menu of the selected item of this menu.
2103 * Return the handle of the submenu, or hmenu if no submenu to display.
2104 */
2105static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu,
2106 BOOL selectFirst, UINT wFlags )
2107{
2108 RECT rect;
2109 POPUPMENU *menu;
2110 MENUITEM *item;
2111 HDC hdc;
2112
2113 TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, selectFirst);
2114
2115 if (!(menu = MENU_GetMenu( hmenu ))) return hmenu;
2116
2117 if (menu->FocusedItem == NO_SELECTED_ITEM) return hmenu;
2118
2119 item = &menu->items[menu->FocusedItem];
2120 if (!(item->fType & MF_POPUP) || (item->fState & (MF_GRAYED | MF_DISABLED)))
2121 return hmenu;
2122
2123 /* message must be sent before using item,
2124 because nearly everything may be changed by the application ! */
2125
2126 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2127 if (!(wFlags & TPM_NONOTIFY))
2128 SendMessageA( hwndOwner, WM_INITMENUPOPUP, item->hSubMenu,
2129 MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));
2130
2131 item = &menu->items[menu->FocusedItem];
2132 rect = item->rect;
2133
2134 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2135 if (!(item->fState & MF_HILITE))
2136 {
2137 if (menu->wFlags & MF_POPUP) hdc = GetDC( menu->hWnd );
2138 else hdc = GetDCEx( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
2139
2140 SelectObject( hdc, hMenuFont);
2141
2142 item->fState |= MF_HILITE;
2143 MENU_DrawMenuItem( menu->hWnd, hmenu, hwndOwner, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP), ODA_DRAWENTIRE );
2144 ReleaseDC( menu->hWnd, hdc );
2145 }
2146 if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right)
2147 item->rect = rect;
2148
2149 item->fState |= MF_MOUSESELECT;
2150
2151 if (IS_SYSTEM_MENU(menu))
2152 {
2153 MENU_InitSysMenuPopup(item->hSubMenu,
2154 GetWindowLongA( menu->hWnd, GWL_STYLE ),
2155 GetClassLongA( menu->hWnd, GCL_STYLE));
2156
2157 NC_GetSysPopupPos( menu->hWnd, &rect );
2158 rect.top = rect.bottom;
2159 rect.right = GetSystemMetrics(SM_CXSIZE);
2160 rect.bottom = GetSystemMetrics(SM_CYSIZE);
2161 }
2162 else
2163 {
2164 GetWindowRect( menu->hWnd, &rect );
2165 if (menu->wFlags & MF_POPUP)
2166 {
2167 rect.left += item->rect.right - GetSystemMetrics(SM_CXBORDER);
2168 rect.top += item->rect.top;
2169 rect.right = item->rect.left - item->rect.right + GetSystemMetrics(SM_CXBORDER);
2170 rect.bottom = item->rect.top - item->rect.bottom;
2171 }
2172 else
2173 {
2174 rect.left += item->rect.left;
2175 rect.top += item->rect.bottom;
2176 rect.right = item->rect.right - item->rect.left;
2177 rect.bottom = item->rect.bottom - item->rect.top;
2178 }
2179 }
2180
2181 MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem,
2182 rect.left, rect.top, rect.right, rect.bottom );
2183 if (selectFirst)
2184 MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT );
2185 return item->hSubMenu;
2186}
2187
2188
2189
2190/**********************************************************************
2191 * MENU_IsMenuActive
2192 */
2193BOOL MENU_IsMenuActive(void)
2194{
2195 return (top_popup != 0);
2196}
2197
2198/***********************************************************************
2199 * MENU_PtMenu
2200 *
2201 * Walks menu chain trying to find a menu pt maps to.
2202 */
2203static HMENU MENU_PtMenu( HMENU hMenu, POINT pt )
2204{
2205 POPUPMENU *menu = MENU_GetMenu( hMenu );
2206 UINT item = menu->FocusedItem;
2207 HMENU ret;
2208
2209 /* try subpopup first (if any) */
2210 ret = (item != NO_SELECTED_ITEM &&
2211 (menu->items[item].fType & MF_POPUP) &&
2212 (menu->items[item].fState & MF_MOUSESELECT))
2213 ? MENU_PtMenu(menu->items[item].hSubMenu, pt) : 0;
2214
2215 if (!ret) /* check the current window (avoiding WM_HITTEST) */
2216 {
2217 INT ht = NC_HandleNCHitTest( menu->hWnd, pt );
2218 if( menu->wFlags & MF_POPUP )
2219 {
2220 if (ht != HTNOWHERE && ht != HTERROR) ret = hMenu;
2221 }
2222 else if (ht == HTSYSMENU)
2223 ret = get_win_sys_menu( menu->hWnd );
2224 else if (ht == HTMENU)
2225 ret = GetMenu( menu->hWnd );
2226 }
2227 return ret;
2228}
2229
2230/***********************************************************************
2231 * MENU_ExecFocusedItem
2232 *
2233 * Execute a menu item (for instance when user pressed Enter).
2234 * Return the wID of the executed item. Otherwise, -1 indicating
2235 * that no menu item was executed;
2236 * Have to receive the flags for the TrackPopupMenu options to avoid
2237 * sending unwanted message.
2238 *
2239 */
2240static INT MENU_ExecFocusedItem( MTRACKER* pmt, HMENU hMenu, UINT wFlags )
2241{
2242 MENUITEM *item;
2243 POPUPMENU *menu = MENU_GetMenu( hMenu );
2244
2245 TRACE("%p hmenu=0x%04x\n", pmt, hMenu);
2246
2247 if (!menu || !menu->nItems ||
2248 (menu->FocusedItem == NO_SELECTED_ITEM)) return -1;
2249
2250 item = &menu->items[menu->FocusedItem];
2251
2252 TRACE("%08x %08x %08x\n",
2253 hMenu, item->wID, item->hSubMenu);
2254
2255 if (!(item->fType & MF_POPUP))
2256 {
2257 if (!(item->fState & (MF_GRAYED | MF_DISABLED)) && !(item->fType & MF_SEPARATOR))
2258 {
2259 /* If TPM_RETURNCMD is set you return the id, but
2260 do not send a message to the owner */
2261 if(!(wFlags & TPM_RETURNCMD))
2262 {
2263 if( menu->wFlags & MF_SYSMENU )
2264 PostMessageA( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
2265 MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
2266 else
2267 PostMessageA( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 );
2268 }
2269 return item->wID;
2270 }
2271 }
2272 else
2273 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hMenu, TRUE, wFlags);
2274
2275 return -1;
2276}
2277
2278/***********************************************************************
2279 * MENU_SwitchTracking
2280 *
2281 * Helper function for menu navigation routines.
2282 */
2283static void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id )
2284{
2285 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2286 POPUPMENU *topmenu = MENU_GetMenu( pmt->hTopMenu );
2287
2288 TRACE("%p hmenu=0x%04x 0x%04x\n", pmt, hPtMenu, id);
2289
2290 if( pmt->hTopMenu != hPtMenu &&
2291 !((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
2292 {
2293 /* both are top level menus (system and menu-bar) */
2294 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2295 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
2296 pmt->hTopMenu = hPtMenu;
2297 }
2298 else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
2299 MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE, 0 );
2300}
2301
2302
2303/***********************************************************************
2304 * MENU_ButtonDown
2305 *
2306 * Return TRUE if we can go on with menu tracking.
2307 */
2308static BOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2309{
2310 TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2311
2312 if (hPtMenu)
2313 {
2314 UINT id = 0;
2315 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2316 MENUITEM *item;
2317
2318 if( IS_SYSTEM_MENU(ptmenu) )
2319 item = ptmenu->items;
2320 else
2321 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2322
2323 if( item )
2324 {
2325 if( ptmenu->FocusedItem != id )
2326 MENU_SwitchTracking( pmt, hPtMenu, id );
2327
2328 /* If the popup menu is not already "popped" */
2329 if(!(item->fState & MF_MOUSESELECT ))
2330 {
2331 pmt->hCurrentMenu = MENU_ShowSubPopup( pmt->hOwnerWnd, hPtMenu, FALSE, wFlags );
2332
2333 /* In win31, a newly popped menu always remains opened for the next buttonup */
2334#ifdef __WIN32OS2__
2335 if(fOS2Look)
2336 ptmenu->bTimeToHide = FALSE;
2337#endif
2338 if(TWEAK_WineLook == WIN31_LOOK)
2339 ptmenu->bTimeToHide = FALSE;
2340 }
2341
2342 return TRUE;
2343 }
2344 /* Else the click was on the menu bar, finish the tracking */
2345 }
2346 return FALSE;
2347}
2348
2349/***********************************************************************
2350 * MENU_ButtonUp
2351 *
2352 * Return the value of MENU_ExecFocusedItem if
2353 * the selected item was not a popup. Else open the popup.
2354 * A -1 return value indicates that we go on with menu tracking.
2355 *
2356 */
2357static INT MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags)
2358{
2359 TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
2360
2361 if (hPtMenu)
2362 {
2363 UINT id = 0;
2364 POPUPMENU *ptmenu = MENU_GetMenu( hPtMenu );
2365 MENUITEM *item;
2366
2367 if( IS_SYSTEM_MENU(ptmenu) )
2368 item = ptmenu->items;
2369 else
2370 item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2371
2372 if( item && (ptmenu->FocusedItem == id ))
2373 {
2374 if( !(item->fType & MF_POPUP) )
2375 return MENU_ExecFocusedItem( pmt, hPtMenu, wFlags);
2376
2377 /* If we are dealing with the top-level menu */
2378 /* and this is a click on an already "popped" item: */
2379 /* Stop the menu tracking and close the opened submenus */
2380 if((pmt->hTopMenu == hPtMenu) && (ptmenu->bTimeToHide == TRUE))
2381 return 0;
2382 }
2383 ptmenu->bTimeToHide = TRUE;
2384 }
2385 return -1;
2386}
2387
2388
2389/***********************************************************************
2390 * MENU_MouseMove
2391 *
2392 * Return TRUE if we can go on with menu tracking.
2393 */
2394static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
2395{
2396 UINT id = NO_SELECTED_ITEM;
2397 POPUPMENU *ptmenu = NULL;
2398
2399 if( hPtMenu )
2400 {
2401 ptmenu = MENU_GetMenu( hPtMenu );
2402 if( IS_SYSTEM_MENU(ptmenu) )
2403 id = 0;
2404 else
2405 MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
2406 }
2407
2408 if( id == NO_SELECTED_ITEM )
2409 {
2410 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2411 NO_SELECTED_ITEM, TRUE, pmt->hTopMenu);
2412
2413 }
2414 else if( ptmenu->FocusedItem != id )
2415 {
2416 MENU_SwitchTracking( pmt, hPtMenu, id );
2417 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hPtMenu, FALSE, wFlags);
2418 }
2419 return TRUE;
2420}
2421
2422
2423/***********************************************************************
2424 * MENU_DoNextMenu
2425 *
2426 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2427 */
2428static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
2429{
2430 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2431
2432 if( (vk == VK_LEFT && menu->FocusedItem == 0 ) ||
2433 (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
2434 {
2435 MDINEXTMENU next_menu;
2436 HMENU hNewMenu;
2437 HWND hNewWnd;
2438 UINT id = 0;
2439
2440 next_menu.hmenuIn = (IS_SYSTEM_MENU(menu)) ? GetSubMenu(pmt->hTopMenu,0) : pmt->hTopMenu;
2441 next_menu.hmenuNext = 0;
2442 next_menu.hwndNext = 0;
2443 SendMessageW( pmt->hOwnerWnd, WM_NEXTMENU, vk, (LPARAM)&next_menu );
2444
2445 TRACE("%04x [%04x] -> %04x [%04x]\n",
2446 pmt->hCurrentMenu, pmt->hOwnerWnd, next_menu.hmenuNext, next_menu.hwndNext );
2447
2448 if (!next_menu.hmenuNext || !next_menu.hwndNext)
2449 {
2450 DWORD style = GetWindowLongA( pmt->hOwnerWnd, GWL_STYLE );
2451 hNewWnd = pmt->hOwnerWnd;
2452 if( IS_SYSTEM_MENU(menu) )
2453 {
2454 /* switch to the menu bar */
2455
2456 if(style & WS_CHILD || !(hNewMenu = GetMenu(hNewWnd))) return FALSE;
2457
2458 if( vk == VK_LEFT )
2459 {
2460 menu = MENU_GetMenu( hNewMenu );
2461 id = menu->nItems - 1;
2462 }
2463 }
2464 else if (style & WS_SYSMENU )
2465 {
2466 /* switch to the system menu */
2467 hNewMenu = get_win_sys_menu( hNewWnd );
2468 }
2469 else return FALSE;
2470 }
2471 else /* application returned a new menu to switch to */
2472 {
2473 hNewMenu = next_menu.hmenuNext;
2474 hNewWnd = WIN_GetFullHandle( next_menu.hwndNext );
2475
2476 if( IsMenu(hNewMenu) && IsWindow(hNewWnd) )
2477 {
2478 DWORD style = GetWindowLongA( hNewWnd, GWL_STYLE );
2479
2480 if (style & WS_SYSMENU &&
2481 GetSubMenu(get_win_sys_menu(hNewWnd), 0) == hNewMenu )
2482 {
2483 /* get the real system menu */
2484 hNewMenu = get_win_sys_menu(hNewWnd);
2485 }
2486 else if (style & WS_CHILD || GetMenu(hNewWnd) != hNewMenu )
2487 {
2488 /* FIXME: Not sure what to do here;
2489 * perhaps try to track hNewMenu as a popup? */
2490
2491 TRACE(" -- got confused.\n");
2492 return FALSE;
2493 }
2494 }
2495 else return FALSE;
2496 }
2497
2498 if( hNewMenu != pmt->hTopMenu )
2499 {
2500 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM,
2501 FALSE, 0 );
2502 if( pmt->hCurrentMenu != pmt->hTopMenu )
2503 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2504 }
2505
2506 if( hNewWnd != pmt->hOwnerWnd )
2507 {
2508 ReleaseCapture();
2509 pmt->hOwnerWnd = hNewWnd;
2510#ifdef __WIN32OS2__
2511 SetCapture(pmt->hOwnerWnd); //SvL: Don't know if this is good enough
2512#else
2513 EVENT_Capture( pmt->hOwnerWnd, HTMENU );
2514#endif
2515 }
2516
2517 pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
2518 MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE, 0 );
2519
2520 return TRUE;
2521 }
2522 return FALSE;
2523}
2524
2525/***********************************************************************
2526 * MENU_SuspendPopup
2527 *
2528 * The idea is not to show the popup if the next input message is
2529 * going to hide it anyway.
2530 */
2531static BOOL MENU_SuspendPopup( MTRACKER* pmt, UINT16 uMsg )
2532{
2533 MSG msg;
2534
2535 msg.hwnd = pmt->hOwnerWnd;
2536
2537 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2538 pmt->trackFlags |= TF_SKIPREMOVE;
2539
2540 switch( uMsg )
2541 {
2542 case WM_KEYDOWN:
2543 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2544 if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
2545 {
2546 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
2547 PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
2548 if( msg.message == WM_KEYDOWN &&
2549 (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
2550 {
2551 pmt->trackFlags |= TF_SUSPENDPOPUP;
2552 return TRUE;
2553 }
2554 }
2555 break;
2556 }
2557
2558 /* failures go through this */
2559 pmt->trackFlags &= ~TF_SUSPENDPOPUP;
2560 return FALSE;
2561}
2562
2563/***********************************************************************
2564 * MENU_KeyEscape
2565 *
2566 * Handle a VK_ESCAPE key event in a menu.
2567 */
2568static BOOL MENU_KeyEscape(MTRACKER* pmt, UINT wFlags)
2569{
2570 BOOL bEndMenu = TRUE;
2571
2572 if (pmt->hCurrentMenu != pmt->hTopMenu)
2573 {
2574 POPUPMENU *menu = MENU_GetMenu(pmt->hCurrentMenu);
2575
2576 if (menu->wFlags & MF_POPUP)
2577 {
2578 HMENU hmenutmp, hmenuprev;
2579
2580 hmenuprev = hmenutmp = pmt->hTopMenu;
2581
2582 /* close topmost popup */
2583 while (hmenutmp != pmt->hCurrentMenu)
2584 {
2585 hmenuprev = hmenutmp;
2586 hmenutmp = MENU_GetSubPopup( hmenuprev );
2587 }
2588
2589 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2590 pmt->hCurrentMenu = hmenuprev;
2591 bEndMenu = FALSE;
2592 }
2593 }
2594
2595 return bEndMenu;
2596}
2597
2598/***********************************************************************
2599 * MENU_KeyLeft
2600 *
2601 * Handle a VK_LEFT key event in a menu.
2602 */
2603static void MENU_KeyLeft( MTRACKER* pmt, UINT wFlags )
2604{
2605 POPUPMENU *menu;
2606 HMENU hmenutmp, hmenuprev;
2607 UINT prevcol;
2608
2609 hmenuprev = hmenutmp = pmt->hTopMenu;
2610 menu = MENU_GetMenu( hmenutmp );
2611
2612 /* Try to move 1 column left (if possible) */
2613 if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) !=
2614 NO_SELECTED_ITEM ) {
2615
2616 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2617 prevcol, TRUE, 0 );
2618 return;
2619 }
2620
2621 /* close topmost popup */
2622 while (hmenutmp != pmt->hCurrentMenu)
2623 {
2624 hmenuprev = hmenutmp;
2625 hmenutmp = MENU_GetSubPopup( hmenuprev );
2626 }
2627
2628 MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
2629 pmt->hCurrentMenu = hmenuprev;
2630
2631 if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
2632 {
2633 /* move menu bar selection if no more popups are left */
2634
2635 if( !MENU_DoNextMenu( pmt, VK_LEFT) )
2636 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
2637
2638 if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2639 {
2640 /* A sublevel menu was displayed - display the next one
2641 * unless there is another displacement coming up */
2642
2643 if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
2644 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2645 pmt->hTopMenu, TRUE, wFlags);
2646 }
2647 }
2648}
2649
2650
2651/***********************************************************************
2652 * MENU_KeyRight
2653 *
2654 * Handle a VK_RIGHT key event in a menu.
2655 */
2656static void MENU_KeyRight( MTRACKER* pmt, UINT wFlags )
2657{
2658 HMENU hmenutmp;
2659 POPUPMENU *menu = MENU_GetMenu( pmt->hTopMenu );
2660 UINT nextcol;
2661
2662 TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
2663 pmt->hCurrentMenu,
2664 debugstr_w((MENU_GetMenu(pmt->hCurrentMenu))->
2665 items[0].text),
2666 pmt->hTopMenu, debugstr_w(menu->items[0].text) );
2667
2668 if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
2669 {
2670 /* If already displaying a popup, try to display sub-popup */
2671
2672 hmenutmp = pmt->hCurrentMenu;
2673 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hmenutmp, TRUE, wFlags);
2674
2675 /* if subpopup was displayed then we are done */
2676 if (hmenutmp != pmt->hCurrentMenu) return;
2677 }
2678
2679 /* Check to see if there's another column */
2680 if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) !=
2681 NO_SELECTED_ITEM ) {
2682 TRACE("Going to %d.\n", nextcol );
2683 MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
2684 nextcol, TRUE, 0 );
2685 return;
2686 }
2687
2688 if (!(menu->wFlags & MF_POPUP)) /* menu bar tracking */
2689 {
2690 if( pmt->hCurrentMenu != pmt->hTopMenu )
2691 {
2692 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
2693 hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
2694 } else hmenutmp = 0;
2695
2696 /* try to move to the next item */
2697 if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
2698 MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );
2699
2700 if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
2701 if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
2702 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
2703 pmt->hTopMenu, TRUE, wFlags);
2704 }
2705}
2706
2707/***********************************************************************
2708 * MENU_TrackMenu
2709 *
2710 * Menu tracking code.
2711 */
2712static INT MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y,
2713 HWND hwnd, const RECT *lprect )
2714{
2715 MSG msg;
2716 POPUPMENU *menu;
2717 BOOL fRemove;
2718 INT executedMenuId = -1;
2719 MTRACKER mt;
2720 BOOL enterIdleSent = FALSE;
2721#ifdef __WIN32OS2__
2722 BOOL bSysMenu = FALSE;
2723#endif
2724
2725 mt.trackFlags = 0;
2726 mt.hCurrentMenu = hmenu;
2727 mt.hTopMenu = hmenu;
2728 mt.hOwnerWnd = WIN_GetFullHandle( hwnd );
2729 mt.pt.x = x;
2730 mt.pt.y = y;
2731
2732 TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
2733 hmenu, wFlags, x, y, hwnd, (lprect) ? lprect->left : 0, (lprect) ? lprect->top : 0,
2734 (lprect) ? lprect->right : 0, (lprect) ? lprect->bottom : 0);
2735
2736 fEndMenu = FALSE;
2737 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
2738
2739 if (wFlags & TPM_BUTTONDOWN)
2740 {
2741 /* Get the result in order to start the tracking or not */
2742 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2743 fEndMenu = !fRemove;
2744 }
2745
2746#ifdef __WIN32OS2__
2747 bSysMenu = IS_SYSTEM_MENU(menu);
2748
2749 //SvL: Set keyboard & mouse event capture
2750 SetCapture(mt.hOwnerWnd);
2751 //SetCapture breaks system menu (double click), must generate double
2752 //clicks manually
2753 OSLibSetMenuDoubleClick(TRUE);
2754#else
2755 EVENT_Capture( mt.hOwnerWnd, HTMENU );
2756#endif
2757 while (!fEndMenu)
2758 {
2759 menu = MENU_GetMenu( mt.hCurrentMenu );
2760 if (!menu) /* sometimes happens if I do a window manager close */
2761 break;
2762
2763 /* we have to keep the message in the queue until it's
2764 * clear that menu loop is not over yet. */
2765
2766 for (;;)
2767 {
2768 if (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
2769 {
2770#ifdef __WIN32OS2__
2771 //We need to get & remove the message immediately, otherwise
2772 //we'll run into an Odin msg handling limitation (see oslibmsg.cpp todo's)
2773 GetMessageA(&msg, 0, 0, 0);
2774#endif
2775 if (!CallMsgFilterA( &msg, MSGF_MENU )) break;
2776 /* remove the message from the queue */
2777#ifndef __WIN32OS2__
2778 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2779#endif
2780 }
2781 else
2782 {
2783 if (!enterIdleSent)
2784 {
2785 HWND win = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
2786 enterIdleSent = TRUE;
2787 SendMessageW( mt.hOwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM)win );
2788 }
2789 WaitMessage();
2790 }
2791 }
2792
2793 /* check if EndMenu() tried to cancel us, by posting this message */
2794 if(msg.message == WM_CANCELMODE)
2795 {
2796 /* we are now out of the loop */
2797 fEndMenu = TRUE;
2798
2799#ifdef __WIN32OS2__
2800 /* remove the message from the queue */
2801 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
2802#endif
2803 /* break out of internal loop, ala ESCAPE */
2804 break;
2805 }
2806
2807 TranslateMessage( &msg );
2808 mt.pt = msg.pt;
2809
2810 if ( (msg.hwnd==menu->hWnd) || (msg.message!=WM_TIMER) )
2811 enterIdleSent=FALSE;
2812
2813 fRemove = FALSE;
2814 if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
2815 {
2816 /*
2817 * use the mouse coordinates in lParam instead of those in the MSG
2818 * struct to properly handle synthetic messages. lParam coords are
2819 * relative to client area, so they must be converted; since they can
2820 * be negative, we must use SLOWORD/SHIWORD instead of LOWORD/HIWORD.
2821 */
2822 mt.pt.x = SLOWORD(msg.lParam);
2823 mt.pt.y = SHIWORD(msg.lParam);
2824#ifdef __WIN32OS2__
2825 //This MUST be here (in Rewind, but not in Wine)
2826#endif
2827 ClientToScreen(msg.hwnd,&mt.pt);
2828
2829 /* Find a menu for this mouse event */
2830 hmenu = MENU_PtMenu( mt.hTopMenu, mt.pt );
2831
2832 switch(msg.message)
2833 {
2834 /* no WM_NC... messages in captured state */
2835
2836 case WM_RBUTTONDBLCLK:
2837 case WM_RBUTTONDOWN:
2838#ifdef __WIN32OS2__
2839 if (!(wFlags & TPM_RIGHTBUTTON)) {
2840 MENUITEM *item;
2841 UINT id = 0;
2842
2843 if( IS_SYSTEM_MENU(menu) )
2844 item = menu->items;
2845 else
2846 item = MENU_FindItemByCoords( menu, mt.pt, &id );
2847 //@@PF If our pointer is over the menu - do nothing
2848 if (item) break;
2849 //@@PF Time to close menu - win2k&98 checked
2850 fEndMenu = 1;
2851 break;
2852 }
2853 goto buttondown;
2854#else
2855 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2856#endif
2857 /* fall through */
2858 case WM_LBUTTONDBLCLK:
2859#ifdef __WIN32OS2__
2860 if (bSysMenu && (hmenu == mt.hTopMenu))
2861 {
2862 //double click on system menu -> close application
2863 if (!(GetClassLongA(hwnd, GCL_STYLE) & CS_NOCLOSE)) {
2864 PostMessageA(hwnd, WM_SYSCOMMAND, SC_CLOSE, msg.lParam);
2865 fEndMenu = TRUE;
2866 break;
2867 }
2868 }
2869 if(IsIconic(hwnd)) {
2870 //double click on minimized icon -> restore parent window
2871 PostMessageA(hwnd, WM_SYSCOMMAND,SC_RESTORE, msg.lParam);
2872 fEndMenu = TRUE;
2873 break;
2874 }
2875 //fall through
2876buttondown:
2877
2878#endif
2879 case WM_LBUTTONDOWN:
2880 /* If the message belongs to the menu, removes it from the queue */
2881 /* Else, end menu tracking */
2882 fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
2883 fEndMenu = !fRemove;
2884 break;
2885
2886 case WM_RBUTTONUP:
2887 if (!(wFlags & TPM_RIGHTBUTTON)) break;
2888 /* fall through */
2889 case WM_LBUTTONUP:
2890 /* Check if a menu was selected by the mouse */
2891 if (hmenu)
2892 {
2893 executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);
2894
2895 /* End the loop if executedMenuId is an item ID */
2896 /* or if the job was done (executedMenuId = 0). */
2897 fEndMenu = fRemove = (executedMenuId != -1);
2898 }
2899 /* No menu was selected by the mouse */
2900 /* if the function was called by TrackPopupMenu, continue
2901 with the menu tracking. If not, stop it */
2902 else
2903 fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
2904
2905 break;
2906
2907 case WM_MOUSEMOVE:
2908 /* In win95 winelook, the selected menu item must be changed every time the
2909 mouse moves. In Win31 winelook, the mouse button has to be held down */
2910
2911#ifdef __WIN32OS2__
2912 if ( !fOS2Look ||
2913#else
2914 if ( (TWEAK_WineLook > WIN31_LOOK) ||
2915#endif
2916 ( (msg.wParam & MK_LBUTTON) ||
2917 ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON))) )
2918
2919 fEndMenu |= !MENU_MouseMove( &mt, hmenu, wFlags );
2920
2921 } /* switch(msg.message) - mouse */
2922 }
2923 else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
2924 {
2925 fRemove = TRUE; /* Keyboard messages are always removed */
2926 switch(msg.message)
2927 {
2928 case WM_KEYDOWN:
2929 switch(msg.wParam)
2930 {
2931 case VK_HOME:
2932 case VK_END:
2933 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu,
2934 NO_SELECTED_ITEM, FALSE, 0 );
2935 /* fall through */
2936 case VK_UP:
2937 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu,
2938 (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
2939 break;
2940
2941 case VK_DOWN: /* If on menu bar, pull-down the menu */
2942
2943 menu = MENU_GetMenu( mt.hCurrentMenu );
2944 if (!(menu->wFlags & MF_POPUP))
2945 mt.hCurrentMenu = MENU_ShowSubPopup(mt.hOwnerWnd, mt.hTopMenu, TRUE, wFlags);
2946 else /* otherwise try to move selection */
2947 MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT );
2948 break;
2949
2950 case VK_LEFT:
2951 MENU_KeyLeft( &mt, wFlags );
2952 break;
2953
2954 case VK_RIGHT:
2955 MENU_KeyRight( &mt, wFlags );
2956 break;
2957
2958 case VK_ESCAPE:
2959 fEndMenu = MENU_KeyEscape(&mt, wFlags);
2960 break;
2961
2962 case VK_F1:
2963 {
2964 HELPINFO hi;
2965 hi.cbSize = sizeof(HELPINFO);
2966 hi.iContextType = HELPINFO_MENUITEM;
2967 if (menu->FocusedItem == NO_SELECTED_ITEM)
2968 hi.iCtrlId = 0;
2969 else
2970 hi.iCtrlId = menu->items[menu->FocusedItem].wID;
2971 hi.hItemHandle = hmenu;
2972 hi.dwContextId = menu->dwContextHelpID;
2973 hi.MousePos = msg.pt;
2974 SendMessageA(hwnd, WM_HELP, 0, (LPARAM)&hi);
2975 break;
2976 }
2977
2978 default:
2979 break;
2980 }
2981 break; /* WM_KEYDOWN */
2982
2983 case WM_SYSKEYDOWN:
2984 switch(msg.wParam)
2985 {
2986 case VK_MENU:
2987 fEndMenu = TRUE;
2988 break;
2989
2990 }
2991 break; /* WM_SYSKEYDOWN */
2992
2993 case WM_CHAR:
2994 {
2995 UINT pos;
2996
2997 if (msg.wParam == '\r' || msg.wParam == ' ')
2998 {
2999 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
3000 fEndMenu = (executedMenuId != -1);
3001
3002 break;
3003 }
3004
3005 /* Hack to avoid control chars. */
3006 /* We will find a better way real soon... */
3007 if ((msg.wParam <= 32) || (msg.wParam >= 127)) break;
3008
3009 pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu,
3010 LOWORD(msg.wParam), FALSE );
3011 if (pos == (UINT)-2) fEndMenu = TRUE;
3012 else if (pos == (UINT)-1) MessageBeep(0);
3013 else
3014 {
3015 MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos,
3016 TRUE, 0 );
3017 executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
3018 fEndMenu = (executedMenuId != -1);
3019 }
3020 }
3021 break;
3022 } /* switch(msg.message) - kbd */
3023 }
3024 else
3025 {
3026 DispatchMessageA( &msg );
3027 }
3028
3029 if (!fEndMenu) fRemove = TRUE;
3030
3031 /* finally remove message from the queue */
3032
3033 if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
3034#ifdef __WIN32OS2__
3035 ;
3036#else
3037 PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
3038#endif
3039 else mt.trackFlags &= ~TF_SKIPREMOVE;
3040 }
3041
3042#ifdef __WIN32OS2__
3043 OSLibSetMenuDoubleClick(FALSE);
3044#endif
3045 ReleaseCapture();
3046
3047 /* If dropdown is still painted and the close box is clicked on
3048 then the menu will be destroyed as part of the DispatchMessage above.
3049 This will then invalidate the menu handle in mt.hTopMenu. We should
3050 check for this first. */
3051 if( IsMenu( mt.hTopMenu ) )
3052 {
3053 menu = MENU_GetMenu( mt.hTopMenu );
3054
3055 if( IsWindow( mt.hOwnerWnd ) )
3056 {
3057 MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
3058
3059 if (menu && menu->wFlags & MF_POPUP)
3060 {
3061 DestroyWindow( menu->hWnd );
3062 menu->hWnd = 0;
3063 }
3064 MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
3065 SendMessageA( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0xffff), 0 );
3066 }
3067
3068 /* Reset the variable for hiding menu */
3069 if( menu ) menu->bTimeToHide = FALSE;
3070 }
3071
3072 /* The return value is only used by TrackPopupMenu */
3073 return ((executedMenuId != -1) ? executedMenuId : 0);
3074}
3075
3076/***********************************************************************
3077 * MENU_InitTracking
3078 */
3079static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
3080{
3081 TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd, hMenu);
3082
3083 HideCaret(0);
3084
3085 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
3086 if (!(wFlags & TPM_NONOTIFY))
3087 SendMessageA( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
3088
3089 SendMessageA( hWnd, WM_SETCURSOR, (WPARAM)hWnd, HTCAPTION );
3090
3091 if (!(wFlags & TPM_NONOTIFY))
3092 {
3093 POPUPMENU *menu;
3094 SendMessageA( hWnd, WM_INITMENU, hMenu, 0 );
3095 if ((menu = MENU_GetMenu( hMenu )) && (!menu->Height))
3096 { /* app changed/recreated menu bar entries in WM_INITMENU
3097 Recalculate menu sizes else clicks will not work */
3098 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3099 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
3100
3101 }
3102 }
3103 return TRUE;
3104}
3105/***********************************************************************
3106 * MENU_ExitTracking
3107 */
3108static BOOL MENU_ExitTracking(HWND hWnd)
3109{
3110 TRACE("hwnd=0x%04x\n", hWnd);
3111
3112 SendMessageA( hWnd, WM_EXITMENULOOP, 0, 0 );
3113 ShowCaret(0);
3114 return TRUE;
3115}
3116
3117/***********************************************************************
3118 * MENU_TrackMouseMenuBar
3119 *
3120 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
3121 */
3122void MENU_TrackMouseMenuBar( HWND hWnd, INT ht, POINT pt )
3123{
3124 HMENU hMenu = (ht == HTSYSMENU) ? get_win_sys_menu( hWnd ) : GetMenu( hWnd );
3125 UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
3126
3127 TRACE("wnd=%x ht=0x%04x (%ld,%ld)\n", hWnd, ht, pt.x, pt.y);
3128
3129 if (IsMenu(hMenu))
3130 {
3131 /* map point to parent client coordinates */
3132 HWND parent = GetAncestor( hWnd, GA_PARENT );
3133 if (parent != GetDesktopWindow()) ScreenToClient( parent, &pt );
3134
3135 MENU_InitTracking( hWnd, hMenu, FALSE, wFlags );
3136 MENU_TrackMenu( hMenu, wFlags, pt.x, pt.y, hWnd, NULL );
3137 MENU_ExitTracking(hWnd);
3138 }
3139}
3140
3141
3142/***********************************************************************
3143 * MENU_TrackKbdMenuBar
3144 *
3145 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
3146 */
3147void MENU_TrackKbdMenuBar( HWND hwnd, UINT wParam, INT vkey)
3148{
3149 UINT uItem = NO_SELECTED_ITEM;
3150 HMENU hTrackMenu;
3151 UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON;
3152
3153 /* find window that has a menu */
3154
3155 while (GetWindowLongA( hwnd, GWL_STYLE ) & WS_CHILD)
3156 if (!(hwnd = GetParent( hwnd ))) return;
3157
3158 /* check if we have to track a system menu */
3159
3160 hTrackMenu = GetMenu( hwnd );
3161 if (!hTrackMenu || IsIconic(hwnd) || vkey == VK_SPACE )
3162 {
3163 if (!(GetWindowLongA( hwnd, GWL_STYLE ) & WS_SYSMENU)) return;
3164 hTrackMenu = get_win_sys_menu( hwnd );
3165 uItem = 0;
3166 wParam |= HTSYSMENU; /* prevent item lookup */
3167 }
3168
3169 if (!IsMenu( hTrackMenu )) return;
3170
3171 MENU_InitTracking( hwnd, hTrackMenu, FALSE, wFlags );
3172
3173 if( vkey && vkey != VK_SPACE )
3174 {
3175 uItem = MENU_FindItemByKey( hwnd, hTrackMenu, vkey, (wParam & HTSYSMENU) );
3176 if( uItem >= (UINT)(-2) )
3177 {
3178#ifndef __WIN32OS2__
3179 //Don't beep when unable to find menu item when alt key pressed
3180 if( uItem == (UINT)(-1) ) MessageBeep(0);
3181#endif
3182 hTrackMenu = 0;
3183 }
3184 }
3185
3186 if( hTrackMenu )
3187 {
3188 MENU_SelectItem( hwnd, hTrackMenu, uItem, TRUE, 0 );
3189
3190 if( uItem == NO_SELECTED_ITEM )
3191 MENU_MoveSelection( hwnd, hTrackMenu, ITEM_NEXT );
3192 else if( vkey )
3193 PostMessageA( hwnd, WM_KEYDOWN, VK_DOWN, 0L );
3194
3195 MENU_TrackMenu( hTrackMenu, wFlags, 0, 0, hwnd, NULL );
3196 }
3197 MENU_ExitTracking( hwnd );
3198}
3199
3200
3201/**********************************************************************
3202 * TrackPopupMenu (USER32.@)
3203 *
3204 * Like the win32 API, the function return the command ID only if the
3205 * flag TPM_RETURNCMD is on.
3206 *
3207 */
3208BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
3209 INT nReserved, HWND hWnd, const RECT *lpRect )
3210{
3211 BOOL ret = FALSE;
3212
3213 MENU_InitTracking(hWnd, hMenu, TRUE, wFlags);
3214
3215 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3216 if (!(wFlags & TPM_NONOTIFY))
3217 SendMessageA( hWnd, WM_INITMENUPOPUP, hMenu, 0);
3218
3219 if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
3220 ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, lpRect );
3221 MENU_ExitTracking(hWnd);
3222
3223 if( (!(wFlags & TPM_RETURNCMD)) && (ret != FALSE) )
3224 ret = 1;
3225
3226 return ret;
3227}
3228
3229/**********************************************************************
3230 * TrackPopupMenuEx (USER32.@)
3231 */
3232BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
3233 HWND hWnd, LPTPMPARAMS lpTpm )
3234{
3235 FIXME("not fully implemented\n" );
3236 return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
3237 lpTpm ? &lpTpm->rcExclude : NULL );
3238}
3239
3240/***********************************************************************
3241 * PopupMenuWndProc
3242 *
3243 * NOTE: Windows has totally different (and undocumented) popup wndproc.
3244 */
3245static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
3246{
3247 TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
3248 hwnd, message, wParam, lParam);
3249
3250 switch(message)
3251 {
3252 case WM_CREATE:
3253 {
3254 CREATESTRUCTW *cs = (CREATESTRUCTW*)lParam;
3255 SetWindowLongW( hwnd, 0, (LONG)cs->lpCreateParams );
3256 return 0;
3257 }
3258
3259 case WM_MOUSEACTIVATE: /* We don't want to be activated */
3260 return MA_NOACTIVATE;
3261
3262 case WM_PAINT:
3263 {
3264 PAINTSTRUCT ps;
3265 BeginPaint( hwnd, &ps );
3266 MENU_DrawPopupMenu( hwnd, ps.hdc,
3267 (HMENU)GetWindowLongA( hwnd, 0 ) );
3268 EndPaint( hwnd, &ps );
3269 return 0;
3270 }
3271 case WM_ERASEBKGND:
3272 return 1;
3273
3274 case WM_DESTROY:
3275 /* zero out global pointer in case resident popup window was destroyed. */
3276 if (hwnd == top_popup) top_popup = 0;
3277 break;
3278
3279 case WM_SHOWWINDOW:
3280
3281 if( wParam )
3282 {
3283 if (!GetWindowLongW( hwnd, 0 )) ERR("no menu to display\n");
3284 }
3285 else
3286 SetWindowLongW( hwnd, 0, 0 );
3287 break;
3288
3289 case MM_SETMENUHANDLE:
3290 SetWindowLongW( hwnd, 0, wParam );
3291 break;
3292
3293 case MM_GETMENUHANDLE:
3294 return GetWindowLongW( hwnd, 0 );
3295
3296 default:
3297 return DefWindowProcW( hwnd, message, wParam, lParam );
3298 }
3299 return 0;
3300}
3301
3302
3303/***********************************************************************
3304 * MENU_GetMenuBarHeight
3305 *
3306 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
3307 */
3308UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
3309 INT orgX, INT orgY )
3310{
3311 HDC hdc;
3312 RECT rectBar;
3313 LPPOPUPMENU lppop;
3314
3315 TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
3316 hwnd, menubarWidth, orgX, orgY );
3317
3318 if (!(lppop = MENU_GetMenu( GetMenu(hwnd) ))) return 0;
3319
3320 hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
3321 SelectObject( hdc, hMenuFont);
3322 SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU));
3323 MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
3324 ReleaseDC( hwnd, hdc );
3325 return lppop->Height;
3326}
3327
3328
3329/*******************************************************************
3330 * ChangeMenuA (USER32.@)
3331 */
3332BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
3333 UINT id, UINT flags )
3334{
3335 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3336 hMenu, pos, (DWORD)data, id, flags );
3337 if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
3338 id, data );
3339 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3340 if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
3341 id, data );
3342 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3343 flags & MF_BYPOSITION ? pos : id,
3344 flags & ~MF_REMOVE );
3345 /* Default: MF_INSERT */
3346 return InsertMenuA( hMenu, pos, flags, id, data );
3347}
3348
3349
3350/*******************************************************************
3351 * ChangeMenuW (USER32.@)
3352 */
3353BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
3354 UINT id, UINT flags )
3355{
3356 TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
3357 hMenu, pos, (DWORD)data, id, flags );
3358 if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
3359 id, data );
3360 if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
3361 if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
3362 id, data );
3363 if (flags & MF_REMOVE) return RemoveMenu( hMenu,
3364 flags & MF_BYPOSITION ? pos : id,
3365 flags & ~MF_REMOVE );
3366 /* Default: MF_INSERT */
3367 return InsertMenuW( hMenu, pos, flags, id, data );
3368}
3369
3370
3371/*******************************************************************
3372 * CheckMenuItem (USER32.@)
3373 */
3374DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
3375{
3376 MENUITEM *item;
3377 DWORD ret;
3378
3379 TRACE("menu=%04x id=%04x flags=%04x\n", hMenu, id, flags );
3380 if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
3381 ret = item->fState & MF_CHECKED;
3382 if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
3383 else item->fState &= ~MF_CHECKED;
3384 return ret;
3385}
3386
3387
3388/**********************************************************************
3389 * EnableMenuItem (USER32.@)
3390 */
3391UINT WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
3392{
3393 UINT oldflags;
3394 MENUITEM *item;
3395 POPUPMENU *menu;
3396
3397 TRACE("(%04x, %04X, %04X) !\n",
3398 hMenu, wItemID, wFlags);
3399
3400 /* Get the Popupmenu to access the owner menu */
3401 if (!(menu = MENU_GetMenu(hMenu)))
3402 return (UINT)-1;
3403
3404 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
3405 return (UINT)-1;
3406
3407 oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
3408 item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
3409
3410 /* In win95 if the close item in the system menu change update the close button */
3411 if (TWEAK_WineLook == WIN95_LOOK)
3412 if((item->wID == SC_CLOSE) && (oldflags != wFlags))
3413 {
3414 if (menu->hSysMenuOwner != 0)
3415 {
3416 POPUPMENU* parentMenu;
3417
3418 /* Get the parent menu to access*/
3419 if (!(parentMenu = MENU_GetMenu(menu->hSysMenuOwner)))
3420 return (UINT)-1;
3421
3422 /* Refresh the frame to reflect the change*/
3423 SetWindowPos(parentMenu->hWnd, 0, 0, 0, 0, 0,
3424 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
3425 }
3426 }
3427
3428 return oldflags;
3429}
3430
3431
3432/*******************************************************************
3433 * GetMenuStringA (USER32.@)
3434 */
3435INT WINAPI GetMenuStringA(
3436 HMENU hMenu, /* [in] menuhandle */
3437 UINT wItemID, /* [in] menu item (dep. on wFlags) */
3438 LPSTR str, /* [out] outbuffer. If NULL, func returns entry length*/
3439 INT nMaxSiz, /* [in] length of buffer. if 0, func returns entry len*/
3440 UINT wFlags /* [in] MF_ flags */
3441) {
3442 MENUITEM *item;
3443
3444 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3445 hMenu, wItemID, str, nMaxSiz, wFlags );
3446 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3447 if (!IS_STRING_ITEM(item->fType)) return 0;
3448 if (!str || !nMaxSiz) return strlenW(item->text);
3449 str[0] = '\0';
3450 if (!WideCharToMultiByte( CP_ACP, 0, item->text, -1, str, nMaxSiz, NULL, NULL ))
3451 str[nMaxSiz-1] = 0;
3452 TRACE("returning '%s'\n", str );
3453 return strlen(str);
3454}
3455
3456
3457/*******************************************************************
3458 * GetMenuStringW (USER32.@)
3459 */
3460INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
3461 LPWSTR str, INT nMaxSiz, UINT wFlags )
3462{
3463 MENUITEM *item;
3464
3465 TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
3466 hMenu, wItemID, str, nMaxSiz, wFlags );
3467 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
3468 if (!IS_STRING_ITEM(item->fType)) return 0;
3469 if (!str || !nMaxSiz) return strlenW(item->text);
3470 str[0] = '\0';
3471 lstrcpynW( str, item->text, nMaxSiz );
3472 return strlenW(str);
3473}
3474
3475
3476/**********************************************************************
3477 * HiliteMenuItem (USER32.@)
3478 */
3479BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
3480 UINT wHilite )
3481{
3482 LPPOPUPMENU menu;
3483 TRACE("(%04x, %04x, %04x, %04x);\n",
3484 hWnd, hMenu, wItemID, wHilite);
3485 if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
3486 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3487 if (menu->FocusedItem == wItemID) return TRUE;
3488 MENU_HideSubPopups( hWnd, hMenu, FALSE );
3489 MENU_SelectItem( hWnd, hMenu, wItemID, TRUE, 0 );
3490 return TRUE;
3491}
3492
3493
3494/**********************************************************************
3495 * GetMenuState (USER32.@)
3496 */
3497UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
3498{
3499 MENUITEM *item;
3500 TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
3501 hMenu, wItemID, wFlags);
3502 if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
3503 debug_print_menuitem (" item: ", item, "");
3504 if (item->fType & MF_POPUP)
3505 {
3506 POPUPMENU *menu = MENU_GetMenu( item->hSubMenu );
3507 if (!menu) return -1;
3508 else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
3509 }
3510 else
3511 {
3512 /* We used to (from way back then) mask the result to 0xff. */
3513 /* I don't know why and it seems wrong as the documented */
3514 /* return flag MF_SEPARATOR is outside that mask. */
3515 return (item->fType | item->fState);
3516 }
3517}
3518
3519
3520/**********************************************************************
3521 * GetMenuItemCount (USER32.@)
3522 */
3523INT WINAPI GetMenuItemCount( HMENU hMenu )
3524{
3525 LPPOPUPMENU menu = MENU_GetMenu(hMenu);
3526 if (!menu) return -1;
3527 TRACE("(%04x) returning %d\n",
3528 hMenu, menu->nItems );
3529 return menu->nItems;
3530}
3531
3532/**********************************************************************
3533 * GetMenuItemID (USER.264)
3534 */
3535UINT16 WINAPI GetMenuItemID16( HMENU16 hMenu, INT16 nPos )
3536{
3537 return (UINT16) GetMenuItemID (hMenu, nPos);
3538}
3539
3540/**********************************************************************
3541 * GetMenuItemID (USER32.@)
3542 */
3543UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
3544{
3545 MENUITEM * lpmi;
3546
3547 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return -1;
3548 if (lpmi->fType & MF_POPUP) return -1;
3549 return lpmi->wID;
3550
3551}
3552
3553
3554/*******************************************************************
3555 * InsertMenuW (USER32.@)
3556 */
3557BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
3558 UINT id, LPCWSTR str )
3559{
3560 MENUITEM *item;
3561
3562 if (IS_STRING_ITEM(flags) && str)
3563 TRACE("hMenu %04x, pos %d, flags %08x, "
3564 "id %04x, str %s\n",
3565 hMenu, pos, flags, id, debugstr_w(str) );
3566 else TRACE("hMenu %04x, pos %d, flags %08x, "
3567 "id %04x, str %08lx (not a string)\n",
3568 hMenu, pos, flags, id, (DWORD)str );
3569
3570 if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
3571
3572 if (!(MENU_SetItemData( item, flags, id, str )))
3573 {
3574 RemoveMenu( hMenu, pos, flags );
3575 return FALSE;
3576 }
3577
3578 if (flags & MF_POPUP) /* Set the MF_POPUP flag on the popup-menu */
3579 (MENU_GetMenu((HMENU16)id))->wFlags |= MF_POPUP;
3580
3581 item->hCheckBit = item->hUnCheckBit = 0;
3582 return TRUE;
3583}
3584
3585
3586/*******************************************************************
3587 * InsertMenuA (USER32.@)
3588 */
3589BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
3590 UINT id, LPCSTR str )
3591{
3592 BOOL ret = FALSE;
3593
3594 if (IS_STRING_ITEM(flags) && str)
3595 {
3596 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3597 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3598 if (newstr)
3599 {
3600 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3601 ret = InsertMenuW( hMenu, pos, flags, id, newstr );
3602 HeapFree( GetProcessHeap(), 0, newstr );
3603 }
3604 return ret;
3605 }
3606 else return InsertMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3607}
3608
3609
3610/*******************************************************************
3611 * AppendMenuA (USER32.@)
3612 */
3613BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
3614 UINT id, LPCSTR data )
3615{
3616 return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
3617}
3618
3619
3620/*******************************************************************
3621 * AppendMenuW (USER32.@)
3622 */
3623BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
3624 UINT id, LPCWSTR data )
3625{
3626 return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
3627}
3628
3629
3630/**********************************************************************
3631 * RemoveMenu (USER32.@)
3632 */
3633BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3634{
3635 LPPOPUPMENU menu;
3636 MENUITEM *item;
3637
3638 TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
3639 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3640 if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
3641
3642 /* Remove item */
3643
3644 MENU_FreeItemData( item );
3645
3646 if (--menu->nItems == 0)
3647 {
3648 HeapFree( GetProcessHeap(), 0, menu->items );
3649 menu->items = NULL;
3650 }
3651 else
3652 {
3653 while(nPos < menu->nItems)
3654 {
3655 *item = *(item+1);
3656 item++;
3657 nPos++;
3658 }
3659 menu->items = HeapReAlloc( GetProcessHeap(), 0, menu->items,
3660 menu->nItems * sizeof(MENUITEM) );
3661 }
3662 return TRUE;
3663}
3664
3665
3666/**********************************************************************
3667 * DeleteMenu (USER32.@)
3668 */
3669BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
3670{
3671 MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
3672 if (!item) return FALSE;
3673 if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
3674 /* nPos is now the position of the item */
3675 RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
3676 return TRUE;
3677}
3678
3679
3680/*******************************************************************
3681 * ModifyMenuW (USER32.@)
3682 */
3683BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
3684 UINT id, LPCWSTR str )
3685{
3686 MENUITEM *item;
3687
3688 if (IS_STRING_ITEM(flags))
3689 {
3690 TRACE("%04x %d %04x %04x %s\n",
3691 hMenu, pos, flags, id, debugstr_w(str) );
3692 if (!str) return FALSE;
3693 }
3694 else
3695 {
3696 TRACE("%04x %d %04x %04x %08lx\n",
3697 hMenu, pos, flags, id, (DWORD)str );
3698 }
3699
3700 if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
3701 return MENU_SetItemData( item, flags, id, str );
3702}
3703
3704
3705/*******************************************************************
3706 * ModifyMenuA (USER32.@)
3707 */
3708BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
3709 UINT id, LPCSTR str )
3710{
3711 BOOL ret = FALSE;
3712
3713 if (IS_STRING_ITEM(flags) && str)
3714 {
3715 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
3716 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3717 if (newstr)
3718 {
3719 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
3720 ret = ModifyMenuW( hMenu, pos, flags, id, newstr );
3721 HeapFree( GetProcessHeap(), 0, newstr );
3722 }
3723 return ret;
3724 }
3725 else return ModifyMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
3726}
3727
3728
3729/**********************************************************************
3730 * CreatePopupMenu (USER32.@)
3731 */
3732HMENU WINAPI CreatePopupMenu(void)
3733{
3734 HMENU hmenu;
3735 POPUPMENU *menu;
3736
3737 if (!(hmenu = CreateMenu())) return 0;
3738 menu = MENU_GetMenu( hmenu );
3739 menu->wFlags |= MF_POPUP;
3740 menu->bTimeToHide = FALSE;
3741 return hmenu;
3742}
3743
3744
3745/**********************************************************************
3746 * GetMenuCheckMarkDimensions (USER.417)
3747 * GetMenuCheckMarkDimensions (USER32.@)
3748 */
3749DWORD WINAPI GetMenuCheckMarkDimensions(void)
3750{
3751 return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK) );
3752}
3753
3754
3755/**********************************************************************
3756 * SetMenuItemBitmaps (USER32.@)
3757 */
3758BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags,
3759 HBITMAP hNewUnCheck, HBITMAP hNewCheck)
3760{
3761 MENUITEM *item;
3762 TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
3763 hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
3764 if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
3765
3766 if (!hNewCheck && !hNewUnCheck)
3767 {
3768 item->fState &= ~MF_USECHECKBITMAPS;
3769 }
3770 else /* Install new bitmaps */
3771 {
3772 item->hCheckBit = hNewCheck;
3773 item->hUnCheckBit = hNewUnCheck;
3774 item->fState |= MF_USECHECKBITMAPS;
3775 }
3776 return TRUE;
3777}
3778
3779
3780/**********************************************************************
3781 * CreateMenu (USER32.@)
3782 */
3783HMENU WINAPI CreateMenu(void)
3784{
3785 HMENU hMenu;
3786 LPPOPUPMENU menu;
3787
3788#ifdef __WIN32OS2__
3789 if (!(menu = (LPPOPUPMENU)HeapAlloc(GetProcessHeap(),0,sizeof(POPUPMENU)))) return 0;
3790 if(ObjAllocateHandle(&hMenu, (DWORD)menu, HNDL_MENU) == FALSE) return 0;
3791#else
3792 if (!(hMenu = USER_HEAP_ALLOC( sizeof(POPUPMENU) ))) return 0;
3793 menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
3794#endif
3795 ZeroMemory(menu, sizeof(POPUPMENU));
3796 menu->wMagic = MENU_MAGIC;
3797 menu->FocusedItem = NO_SELECTED_ITEM;
3798 menu->bTimeToHide = FALSE;
3799
3800 TRACE("return %04x\n", hMenu );
3801
3802 return hMenu;
3803}
3804
3805
3806/**********************************************************************
3807 * DestroyMenu (USER32.@)
3808 */
3809BOOL WINAPI DestroyMenu( HMENU hMenu )
3810{
3811 TRACE("(%04x)\n", hMenu);
3812
3813 /* Silently ignore attempts to destroy default system popup */
3814
3815 if (hMenu && hMenu != MENU_DefSysPopup)
3816 {
3817 LPPOPUPMENU lppop = MENU_GetMenu(hMenu);
3818
3819 if (!lppop) return FALSE;
3820
3821 lppop->wMagic = 0; /* Mark it as destroyed */
3822
3823 if ((lppop->wFlags & MF_POPUP) && lppop->hWnd)
3824 {
3825 DestroyWindow( lppop->hWnd );
3826 lppop->hWnd = 0;
3827 }
3828
3829 if (lppop->items) /* recursively destroy submenus */
3830 {
3831 int i;
3832 MENUITEM *item = lppop->items;
3833 for (i = lppop->nItems; i > 0; i--, item++)
3834 {
3835 if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
3836 MENU_FreeItemData( item );
3837 }
3838 HeapFree( GetProcessHeap(), 0, lppop->items );
3839 }
3840#ifdef __WIN32OS2__
3841 HeapFree(GetProcessHeap(),0,(LPVOID)lppop);
3842 ObjDeleteHandle(hMenu, HNDL_MENU);
3843#else
3844 USER_HEAP_FREE( hMenu );
3845#endif
3846 }
3847 return (hMenu != MENU_DefSysPopup);
3848}
3849
3850
3851/**********************************************************************
3852 * GetSystemMenu (USER32.@)
3853 */
3854HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
3855{
3856#ifdef __WIN32OS2__
3857 HMENU retvalue = 0;
3858
3859 if(IsWindow(hWnd))
3860 {
3861 HMENU hSysMenu = getSysMenu(hWnd);
3862 if(hSysMenu)
3863 {
3864 if( bRevert )
3865 {
3866 DestroyMenu(hSysMenu);
3867 hSysMenu = 0;
3868 setSysMenu(hWnd,hSysMenu);
3869 }
3870 else
3871 {
3872 POPUPMENU *menu = MENU_GetMenu(hSysMenu);
3873 if(menu)
3874 {
3875 if( menu->nItems > 0 && menu->items[0].hSubMenu == MENU_DefSysPopup )
3876 menu->items[0].hSubMenu = MENU_CopySysPopup();
3877 }
3878 else
3879 {
3880 //WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
3881 // wndPtr->hSysMenu, hWnd);
3882 hSysMenu = 0;
3883 setSysMenu(hWnd,hSysMenu);
3884 }
3885 }
3886 }
3887
3888 if(!hSysMenu && (GetWindowLongA(hWnd,GWL_STYLE) & WS_SYSMENU) )
3889 {
3890 hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
3891 setSysMenu(hWnd,hSysMenu);
3892 }
3893
3894 if( hSysMenu )
3895 {
3896 POPUPMENU *menu;
3897 retvalue = GetSubMenu(hSysMenu, 0);
3898
3899 /* Store the dummy sysmenu handle to facilitate the refresh */
3900 /* of the close button if the SC_CLOSE item change */
3901 menu = MENU_GetMenu(retvalue);
3902 if (menu)
3903 menu->hSysMenuOwner = hSysMenu;
3904 }
3905 }
3906 return bRevert ? 0 : retvalue;
3907#else
3908 WND *wndPtr = WIN_FindWndPtr( hWnd );
3909 HMENU retvalue = 0;
3910
3911 if (wndPtr)
3912 {
3913 if( wndPtr->hSysMenu )
3914 {
3915 if( bRevert )
3916 {
3917 DestroyMenu(wndPtr->hSysMenu);
3918 wndPtr->hSysMenu = 0;
3919 }
3920 else
3921 {
3922 POPUPMENU *menu = MENU_GetMenu( wndPtr->hSysMenu );
3923 if( menu )
3924 {
3925 if( menu->nItems > 0 && menu->items[0].hSubMenu == MENU_DefSysPopup )
3926 menu->items[0].hSubMenu = MENU_CopySysPopup();
3927 }
3928 else
3929 {
3930 WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
3931 wndPtr->hSysMenu, hWnd);
3932 wndPtr->hSysMenu = 0;
3933 }
3934 }
3935 }
3936
3937 if(!wndPtr->hSysMenu && (wndPtr->dwStyle & WS_SYSMENU) )
3938 wndPtr->hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
3939
3940 if( wndPtr->hSysMenu )
3941 {
3942 POPUPMENU *menu;
3943 retvalue = GetSubMenu(wndPtr->hSysMenu, 0);
3944
3945 /* Store the dummy sysmenu handle to facilitate the refresh */
3946 /* of the close button if the SC_CLOSE item change */
3947 menu = MENU_GetMenu(retvalue);
3948 if ( menu )
3949 menu->hSysMenuOwner = wndPtr->hSysMenu;
3950 }
3951 WIN_ReleaseWndPtr(wndPtr);
3952 }
3953 return bRevert ? 0 : retvalue;
3954#endif
3955}
3956
3957
3958/*******************************************************************
3959 * SetSystemMenu (USER32.@)
3960 */
3961BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
3962{
3963#ifdef __WIN32OS2__
3964 HMENU hSysMenu;
3965
3966 if(!IsWindow(hwnd)) return FALSE;
3967
3968 hSysMenu = getSysMenu(hwnd);
3969 if(hSysMenu) DestroyMenu(hSysMenu);
3970
3971 setSysMenu(hwnd, MENU_GetSysMenu( hwnd, hMenu ));
3972 return TRUE;
3973#else
3974 WND *wndPtr = WIN_FindWndPtr(hwnd);
3975
3976 if (wndPtr)
3977 {
3978 if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
3979 wndPtr->hSysMenu = MENU_GetSysMenu( hwnd, hMenu );
3980 WIN_ReleaseWndPtr(wndPtr);
3981 return TRUE;
3982 }
3983 return FALSE;
3984#endif
3985}
3986
3987
3988/**********************************************************************
3989 * GetMenu (USER32.@)
3990 */
3991HMENU WINAPI GetMenu( HWND hWnd )
3992{
3993 HMENU retvalue = (HMENU)GetWindowLongA( hWnd, GWL_ID );
3994#ifdef __WIN32OS2__
3995 if(MENU_GetMenu(retvalue) != NULL) {
3996 return retvalue;
3997 }
3998 dprintf(("WARNING: Invalid menu %x", retvalue));
3999 return 0;
4000#else
4001 TRACE("for %04x returning %04x\n", hWnd, retvalue);
4002 return retvalue;
4003#endif
4004}
4005
4006
4007/**********************************************************************
4008 * SetMenu (USER32.@)
4009 */
4010BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
4011{
4012 TRACE("(%04x, %04x);\n", hWnd, hMenu);
4013
4014 if (hMenu && !IsMenu(hMenu))
4015 {
4016 WARN("hMenu %x is not a menu handle\n", hMenu);
4017 return FALSE;
4018 }
4019 if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
4020
4021 hWnd = WIN_GetFullHandle( hWnd );
4022 if (GetCapture() == hWnd) ReleaseCapture();
4023
4024 if (hMenu != 0)
4025 {
4026 LPPOPUPMENU lpmenu;
4027
4028 if (!(lpmenu = MENU_GetMenu(hMenu))) return FALSE;
4029
4030 lpmenu->hWnd = hWnd;
4031 lpmenu->Height = 0; /* Make sure we recalculate the size */
4032 }
4033 SetWindowLongA( hWnd, GWL_ID, hMenu );
4034
4035 if (IsWindowVisible(hWnd))
4036 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4037 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4038 return TRUE;
4039}
4040
4041
4042
4043/**********************************************************************
4044 * GetSubMenu (USER32.@)
4045 */
4046HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
4047{
4048 MENUITEM * lpmi;
4049
4050#ifdef __WIN32OS2__
4051 if (!(lpmi = MENU_FindItem(&hMenu,(UINT*)&nPos,MF_BYPOSITION))) {
4052 SetLastError(ERROR_INVALID_HANDLE);
4053 return 0;
4054 }
4055#else
4056 if (!(lpmi = MENU_FindItem(&hMenu,&nPos,MF_BYPOSITION))) return 0;
4057#endif
4058 if (!(lpmi->fType & MF_POPUP)) return 0;
4059 return lpmi->hSubMenu;
4060}
4061
4062
4063/**********************************************************************
4064 * DrawMenuBar (USER32.@)
4065 */
4066BOOL WINAPI DrawMenuBar( HWND hWnd )
4067{
4068 LPPOPUPMENU lppop;
4069 HMENU hMenu = GetMenu(hWnd);
4070
4071 if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
4072 if (!hMenu || !(lppop = MENU_GetMenu( hMenu ))) return FALSE;
4073
4074 lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
4075 lppop->hwndOwner = hWnd;
4076 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4077 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4078 return TRUE;
4079}
4080
4081/***********************************************************************
4082 * DrawMenuBarTemp (USER32.@)
4083 *
4084 * UNDOCUMENTED !!
4085 *
4086 * called by W98SE desk.cpl Control Panel Applet
4087 *
4088 * Not 100% sure about the param names, but close.
4089 */
4090DWORD WINAPI DrawMenuBarTemp(HWND someHWND, HDC someHDC, LPRECT someRECT, HMENU someHMENU, HFONT someFONT)
4091{
4092 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, 0x%08x): stub\n", someHWND, someHDC, someRECT, someHMENU, someFONT);
4093 return 0;
4094}
4095
4096/***********************************************************************
4097 * EndMenu (USER.187)
4098 * EndMenu (USER32.@)
4099 */
4100void WINAPI EndMenu(void)
4101{
4102 /* if we are in the menu code, and it is active */
4103 if (!fEndMenu && top_popup)
4104 {
4105 /* terminate the menu handling code */
4106 fEndMenu = TRUE;
4107
4108 /* needs to be posted to wakeup the internal menu handler */
4109 /* which will now terminate the menu, in the event that */
4110 /* the main window was minimized, or lost focus, so we */
4111 /* don't end up with an orphaned menu */
4112 PostMessageA( top_popup, WM_CANCELMODE, 0, 0);
4113 }
4114}
4115
4116
4117/***********************************************************************
4118 * LookupMenuHandle (USER.217)
4119 */
4120HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
4121{
4122 HMENU hmenu32 = hmenu;
4123 UINT id32 = id;
4124 if (!MENU_FindItem( &hmenu32, &id32, MF_BYCOMMAND )) return 0;
4125 else return hmenu32;
4126}
4127
4128
4129#ifndef __WIN32OS2__
4130/**********************************************************************
4131 * LoadMenu (USER.150)
4132 */
4133HMENU16 WINAPI LoadMenu16( HINSTANCE16 instance, LPCSTR name )
4134{
4135 HRSRC16 hRsrc;
4136 HGLOBAL16 handle;
4137 HMENU16 hMenu;
4138
4139 TRACE("(%04x,%s)\n", instance, debugres_a(name) );
4140
4141 if (HIWORD(name))
4142 {
4143 if (name[0] == '#') name = (LPCSTR)atoi( name + 1 );
4144 }
4145
4146 if (!name) return 0;
4147
4148 /* check for Win32 module */
4149 if (HIWORD(instance)) return LoadMenuA( instance, name );
4150 instance = GetExePtr( instance );
4151
4152 if (!(hRsrc = FindResource16( instance, name, RT_MENUA ))) return 0;
4153 if (!(handle = LoadResource16( instance, hRsrc ))) return 0;
4154 hMenu = LoadMenuIndirect16(LockResource16(handle));
4155 FreeResource16( handle );
4156 return hMenu;
4157}
4158#endif
4159
4160/*****************************************************************
4161 * LoadMenuA (USER32.@)
4162 */
4163HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
4164{
4165 HRSRC hrsrc = FindResourceA( instance, name, RT_MENUA );
4166 if (!hrsrc) return 0;
4167 return LoadMenuIndirectA( (LPCVOID)LoadResource( instance, hrsrc ));
4168}
4169
4170
4171/*****************************************************************
4172 * LoadMenuW (USER32.@)
4173 */
4174HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
4175{
4176 HRSRC hrsrc = FindResourceW( instance, name, RT_MENUW );
4177 if (!hrsrc) return 0;
4178 return LoadMenuIndirectW( (LPCVOID)LoadResource( instance, hrsrc ));
4179}
4180
4181
4182/**********************************************************************
4183 * LoadMenuIndirect (USER.220)
4184 */
4185HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
4186{
4187 HMENU16 hMenu;
4188 WORD version, offset;
4189 LPCSTR p = (LPCSTR)template;
4190
4191 TRACE("(%p)\n", template );
4192 version = GET_WORD(p);
4193 p += sizeof(WORD);
4194 if (version)
4195 {
4196 WARN("version must be 0 for Win16\n" );
4197 return 0;
4198 }
4199 offset = GET_WORD(p);
4200 p += sizeof(WORD) + offset;
4201 if (!(hMenu = CreateMenu())) return 0;
4202 if (!MENU_ParseResource( p, hMenu, FALSE ))
4203 {
4204 DestroyMenu( hMenu );
4205 return 0;
4206 }
4207 return hMenu;
4208}
4209
4210
4211/**********************************************************************
4212 * LoadMenuIndirectA (USER32.@)
4213 */
4214HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
4215{
4216 HMENU16 hMenu;
4217 WORD version, offset;
4218 LPCSTR p = (LPCSTR)template;
4219
4220 TRACE("%p\n", template );
4221 version = GET_WORD(p);
4222 p += sizeof(WORD);
4223 switch (version)
4224 {
4225 case 0:
4226 offset = GET_WORD(p);
4227 p += sizeof(WORD) + offset;
4228 if (!(hMenu = CreateMenu())) return 0;
4229 if (!MENU_ParseResource( p, hMenu, TRUE ))
4230 {
4231 DestroyMenu( hMenu );
4232 return 0;
4233 }
4234 return hMenu;
4235 case 1:
4236 offset = GET_WORD(p);
4237 p += sizeof(WORD) + offset;
4238 if (!(hMenu = CreateMenu())) return 0;
4239 if (!MENUEX_ParseResource( p, hMenu))
4240 {
4241 DestroyMenu( hMenu );
4242 return 0;
4243 }
4244 return hMenu;
4245 default:
4246 ERR("version %d not supported.\n", version);
4247 return 0;
4248 }
4249}
4250
4251
4252/**********************************************************************
4253 * LoadMenuIndirectW (USER32.@)
4254 */
4255HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
4256{
4257 /* FIXME: is there anything different between A and W? */
4258 return LoadMenuIndirectA( template );
4259}
4260
4261
4262/**********************************************************************
4263 * IsMenu (USER32.@)
4264 */
4265BOOL WINAPI IsMenu(HMENU hmenu)
4266{
4267 LPPOPUPMENU menu = MENU_GetMenu(hmenu);
4268 return menu != NULL;
4269}
4270
4271/**********************************************************************
4272 * GetMenuItemInfo_common
4273 */
4274
4275static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
4276 LPMENUITEMINFOW lpmii, BOOL unicode)
4277{
4278 MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
4279
4280 debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
4281
4282 if (!menu)
4283 return FALSE;
4284
4285 if (lpmii->fMask & MIIM_TYPE) {
4286 lpmii->fType = menu->fType;
4287 switch (MENU_ITEM_TYPE(menu->fType)) {
4288 case MF_STRING:
4289 break; /* will be done below */
4290 case MF_OWNERDRAW:
4291 case MF_BITMAP:
4292 lpmii->dwTypeData = menu->text;
4293 /* fall through */
4294 default:
4295 lpmii->cch = 0;
4296 }
4297 }
4298
4299 /* copy the text string */
4300 if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING)) &&
4301 (MENU_ITEM_TYPE(menu->fType) == MF_STRING) && menu->text)
4302 {
4303 int len;
4304 if (unicode)
4305 {
4306 len = strlenW(menu->text);
4307 if(lpmii->dwTypeData && lpmii->cch)
4308 lstrcpynW(lpmii->dwTypeData, menu->text, lpmii->cch);
4309 }
4310 else
4311 {
4312 len = WideCharToMultiByte( CP_ACP, 0, menu->text, -1, NULL, 0, NULL, NULL );
4313 if(lpmii->dwTypeData && lpmii->cch)
4314 if (!WideCharToMultiByte( CP_ACP, 0, menu->text, -1,
4315 (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
4316 ((LPSTR)lpmii->dwTypeData)[lpmii->cch-1] = 0;
4317 }
4318 /* if we've copied a substring we return its length */
4319 if(lpmii->dwTypeData && lpmii->cch)
4320 {
4321 if (lpmii->cch <= len) lpmii->cch--;
4322 }
4323 else /* return length of string */
4324 lpmii->cch = len;
4325 }
4326
4327 if (lpmii->fMask & MIIM_FTYPE)
4328 lpmii->fType = menu->fType;
4329
4330 if (lpmii->fMask & MIIM_BITMAP)
4331 lpmii->hbmpItem = menu->hbmpItem;
4332
4333 if (lpmii->fMask & MIIM_STATE)
4334 lpmii->fState = menu->fState;
4335
4336 if (lpmii->fMask & MIIM_ID)
4337 lpmii->wID = menu->wID;
4338
4339 if (lpmii->fMask & MIIM_SUBMENU)
4340 lpmii->hSubMenu = menu->hSubMenu;
4341
4342 if (lpmii->fMask & MIIM_CHECKMARKS) {
4343 lpmii->hbmpChecked = menu->hCheckBit;
4344 lpmii->hbmpUnchecked = menu->hUnCheckBit;
4345 }
4346 if (lpmii->fMask & MIIM_DATA)
4347 lpmii->dwItemData = menu->dwItemData;
4348
4349 return TRUE;
4350}
4351
4352/**********************************************************************
4353 * GetMenuItemInfoA (USER32.@)
4354 */
4355BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
4356 LPMENUITEMINFOA lpmii)
4357{
4358 return GetMenuItemInfo_common (hmenu, item, bypos,
4359 (LPMENUITEMINFOW)lpmii, FALSE);
4360}
4361
4362/**********************************************************************
4363 * GetMenuItemInfoW (USER32.@)
4364 */
4365BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
4366 LPMENUITEMINFOW lpmii)
4367{
4368 return GetMenuItemInfo_common (hmenu, item, bypos,
4369 lpmii, TRUE);
4370}
4371
4372
4373/* set a menu item text from a ASCII or Unicode string */
4374inline static void set_menu_item_text( MENUITEM *menu, LPCWSTR text, BOOL unicode )
4375{
4376 if (!text)
4377 {
4378 menu->text = NULL;
4379 menu->fType |= MF_SEPARATOR;
4380 }
4381 else if (unicode)
4382 {
4383 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, (strlenW(text)+1) * sizeof(WCHAR) )))
4384 strcpyW( menu->text, text );
4385 }
4386 else
4387 {
4388 LPCSTR str = (LPCSTR)text;
4389 int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
4390 if ((menu->text = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
4391 MultiByteToWideChar( CP_ACP, 0, str, -1, menu->text, len );
4392 }
4393}
4394
4395
4396/**********************************************************************
4397 * SetMenuItemInfo_common
4398 */
4399
4400static BOOL SetMenuItemInfo_common(MENUITEM * menu,
4401 const MENUITEMINFOW *lpmii,
4402 BOOL unicode)
4403{
4404 if (!menu) return FALSE;
4405
4406 debug_print_menuitem("MENU_SetItemInfo_common from: ", menu, "");
4407
4408 if (lpmii->fMask & MIIM_TYPE ) {
4409 /* Get rid of old string. */
4410 if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4411 HeapFree(GetProcessHeap(), 0, menu->text);
4412 menu->text = NULL;
4413 }
4414
4415 /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
4416 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4417 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4418
4419 menu->text = lpmii->dwTypeData;
4420
4421 if (IS_STRING_ITEM(menu->fType))
4422 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4423 }
4424
4425 if (lpmii->fMask & MIIM_FTYPE ) {
4426 /* free the string when the type is changing */
4427 if ( (!IS_STRING_ITEM(lpmii->fType)) && IS_STRING_ITEM(menu->fType) && menu->text) {
4428 HeapFree(GetProcessHeap(), 0, menu->text);
4429 menu->text = NULL;
4430 }
4431 menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
4432 menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
4433 if ( IS_STRING_ITEM(menu->fType) && !menu->text )
4434 menu->fType |= MF_SEPARATOR;
4435 }
4436
4437 if (lpmii->fMask & MIIM_STRING ) {
4438 /* free the string when used */
4439 if ( IS_STRING_ITEM(menu->fType) && menu->text) {
4440 HeapFree(GetProcessHeap(), 0, menu->text);
4441 set_menu_item_text( menu, lpmii->dwTypeData, unicode );
4442 }
4443 }
4444
4445 if (lpmii->fMask & MIIM_STATE)
4446 {
4447 /* FIXME: MFS_DEFAULT do we have to reset the other menu items? */
4448 menu->fState = lpmii->fState;
4449 }
4450
4451 if (lpmii->fMask & MIIM_ID)
4452 menu->wID = lpmii->wID;
4453
4454 if (lpmii->fMask & MIIM_SUBMENU) {
4455 menu->hSubMenu = lpmii->hSubMenu;
4456 if (menu->hSubMenu) {
4457 POPUPMENU *subMenu = MENU_GetMenu((UINT16)menu->hSubMenu);
4458 if (subMenu) {
4459 subMenu->wFlags |= MF_POPUP;
4460 menu->fType |= MF_POPUP;
4461 }
4462 else
4463 /* FIXME: Return an error ? */
4464 menu->fType &= ~MF_POPUP;
4465 }
4466 else
4467 menu->fType &= ~MF_POPUP;
4468 }
4469
4470 if (lpmii->fMask & MIIM_CHECKMARKS)
4471 {
4472 if (lpmii->fType & MFT_RADIOCHECK)
4473 menu->fType |= MFT_RADIOCHECK;
4474
4475 menu->hCheckBit = lpmii->hbmpChecked;
4476 menu->hUnCheckBit = lpmii->hbmpUnchecked;
4477 }
4478 if (lpmii->fMask & MIIM_DATA)
4479 menu->dwItemData = lpmii->dwItemData;
4480
4481 debug_print_menuitem("SetMenuItemInfo_common to : ", menu, "");
4482 return TRUE;
4483}
4484
4485/**********************************************************************
4486 * SetMenuItemInfoA (USER32.@)
4487 */
4488BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
4489 const MENUITEMINFOA *lpmii)
4490{
4491 if ((lpmii->fType & (MF_HILITE|MF_POPUP)) || (lpmii->fState)) {
4492 /* QuickTime does pass invalid data into SetMenuItemInfo.
4493 * do some of the checks Windows does.
4494 */
4495 WARN("Bad masks for type (0x%08x) or state (0x%08x)\n",
4496 lpmii->fType,lpmii->fState );
4497 return FALSE;
4498 }
4499
4500 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4501 (const MENUITEMINFOW *)lpmii, FALSE);
4502}
4503
4504/**********************************************************************
4505 * SetMenuItemInfoW (USER32.@)
4506 */
4507BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
4508 const MENUITEMINFOW *lpmii)
4509{
4510 return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
4511 lpmii, TRUE);
4512}
4513
4514/**********************************************************************
4515 * SetMenuDefaultItem (USER32.@)
4516 *
4517 */
4518BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
4519{
4520 UINT i;
4521 POPUPMENU *menu;
4522 MENUITEM *item;
4523
4524 TRACE("(0x%x,%d,%d)\n", hmenu, uItem, bypos);
4525
4526 if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
4527
4528 /* reset all default-item flags */
4529 item = menu->items;
4530 for (i = 0; i < menu->nItems; i++, item++)
4531 {
4532 item->fState &= ~MFS_DEFAULT;
4533 }
4534
4535 /* no default item */
4536 if ( -1 == uItem)
4537 {
4538 return TRUE;
4539 }
4540
4541 item = menu->items;
4542 if ( bypos )
4543 {
4544 if ( uItem >= menu->nItems ) return FALSE;
4545 item[uItem].fState |= MFS_DEFAULT;
4546 return TRUE;
4547 }
4548 else
4549 {
4550 for (i = 0; i < menu->nItems; i++, item++)
4551 {
4552 if (item->wID == uItem)
4553 {
4554 item->fState |= MFS_DEFAULT;
4555 return TRUE;
4556 }
4557 }
4558
4559 }
4560 return FALSE;
4561}
4562
4563/**********************************************************************
4564 * GetMenuDefaultItem (USER32.@)
4565 */
4566UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
4567{
4568 POPUPMENU *menu;
4569 MENUITEM * item;
4570 UINT i = 0;
4571
4572 TRACE("(0x%x,%d,%d)\n", hmenu, bypos, flags);
4573
4574 if (!(menu = MENU_GetMenu(hmenu))) return -1;
4575
4576 /* find default item */
4577 item = menu->items;
4578
4579 /* empty menu */
4580 if (! item) return -1;
4581
4582 while ( !( item->fState & MFS_DEFAULT ) )
4583 {
4584 i++; item++;
4585 if (i >= menu->nItems ) return -1;
4586 }
4587
4588 /* default: don't return disabled items */
4589 if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
4590
4591 /* search rekursiv when needed */
4592 if ( (item->fType & MF_POPUP) && (flags & GMDI_GOINTOPOPUPS) )
4593 {
4594 UINT ret;
4595 ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
4596 if ( -1 != ret ) return ret;
4597
4598 /* when item not found in submenu, return the popup item */
4599 }
4600 return ( bypos ) ? i : item->wID;
4601
4602}
4603
4604
4605/**********************************************************************
4606 * InsertMenuItemA (USER32.@)
4607 */
4608BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
4609 const MENUITEMINFOA *lpmii)
4610{
4611 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4612 return SetMenuItemInfo_common(item, (const MENUITEMINFOW *)lpmii, FALSE);
4613}
4614
4615
4616/**********************************************************************
4617 * InsertMenuItemW (USER32.@)
4618 */
4619BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
4620 const MENUITEMINFOW *lpmii)
4621{
4622 MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
4623 return SetMenuItemInfo_common(item, lpmii, TRUE);
4624}
4625
4626/**********************************************************************
4627 * CheckMenuRadioItem (USER32.@)
4628 */
4629
4630BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
4631 UINT first, UINT last, UINT check,
4632 UINT bypos)
4633{
4634 MENUITEM *mifirst, *milast, *micheck;
4635 HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
4636
4637 TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
4638 hMenu, first, last, check, bypos);
4639
4640 mifirst = MENU_FindItem (&mfirst, &first, bypos);
4641 milast = MENU_FindItem (&mlast, &last, bypos);
4642 micheck = MENU_FindItem (&mcheck, &check, bypos);
4643
4644 if (mifirst == NULL || milast == NULL || micheck == NULL ||
4645 mifirst > milast || mfirst != mlast || mfirst != mcheck ||
4646 micheck > milast || micheck < mifirst)
4647 return FALSE;
4648
4649 while (mifirst <= milast)
4650 {
4651 if (mifirst == micheck)
4652 {
4653 mifirst->fType |= MFT_RADIOCHECK;
4654 mifirst->fState |= MFS_CHECKED;
4655 } else {
4656 mifirst->fType &= ~MFT_RADIOCHECK;
4657 mifirst->fState &= ~MFS_CHECKED;
4658 }
4659 mifirst++;
4660 }
4661
4662 return TRUE;
4663}
4664
4665/**********************************************************************
4666 * GetMenuItemRect (USER32.@)
4667 *
4668 * ATTENTION: Here, the returned values in rect are the screen
4669 * coordinates of the item just like if the menu was
4670 * always on the upper left side of the application.
4671 *
4672 */
4673BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
4674 LPRECT rect)
4675{
4676 POPUPMENU *itemMenu;
4677 MENUITEM *item;
4678 HWND referenceHwnd;
4679
4680 TRACE("(0x%x,0x%x,%d,%p)\n", hwnd, hMenu, uItem, rect);
4681
4682 item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
4683 referenceHwnd = hwnd;
4684
4685 if(!hwnd)
4686 {
4687 itemMenu = MENU_GetMenu(hMenu);
4688 if (itemMenu == NULL)
4689 return FALSE;
4690
4691 if(itemMenu->hWnd == 0)
4692 return FALSE;
4693 referenceHwnd = itemMenu->hWnd;
4694 }
4695
4696 if ((rect == NULL) || (item == NULL))
4697 return FALSE;
4698
4699 *rect = item->rect;
4700
4701 MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
4702
4703 return TRUE;
4704}
4705
4706
4707/**********************************************************************
4708 * SetMenuInfo (USER32.@)
4709 *
4710 * FIXME
4711 * MIM_APPLYTOSUBMENUS
4712 * actually use the items to draw the menu
4713 */
4714BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
4715{
4716 POPUPMENU *menu;
4717
4718 TRACE("(0x%04x %p)\n", hMenu, lpmi);
4719
4720 if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu = MENU_GetMenu(hMenu)))
4721 {
4722
4723 if (lpmi->fMask & MIM_BACKGROUND)
4724 menu->hbrBack = lpmi->hbrBack;
4725
4726 if (lpmi->fMask & MIM_HELPID)
4727 menu->dwContextHelpID = lpmi->dwContextHelpID;
4728
4729 if (lpmi->fMask & MIM_MAXHEIGHT)
4730 menu->cyMax = lpmi->cyMax;
4731
4732 if (lpmi->fMask & MIM_MENUDATA)
4733 menu->dwMenuData = lpmi->dwMenuData;
4734
4735 if (lpmi->fMask & MIM_STYLE)
4736 menu->dwStyle = lpmi->dwStyle;
4737
4738 return TRUE;
4739 }
4740 return FALSE;
4741}
4742
4743/**********************************************************************
4744 * GetMenuInfo (USER32.@)
4745 *
4746 * NOTES
4747 * win98/NT5.0
4748 *
4749 */
4750BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
4751{ POPUPMENU *menu;
4752
4753 TRACE("(0x%04x %p)\n", hMenu, lpmi);
4754
4755 if (lpmi && (menu = MENU_GetMenu(hMenu)))
4756 {
4757
4758 if (lpmi->fMask & MIM_BACKGROUND)
4759 lpmi->hbrBack = menu->hbrBack;
4760
4761 if (lpmi->fMask & MIM_HELPID)
4762 lpmi->dwContextHelpID = menu->dwContextHelpID;
4763
4764 if (lpmi->fMask & MIM_MAXHEIGHT)
4765 lpmi->cyMax = menu->cyMax;
4766
4767 if (lpmi->fMask & MIM_MENUDATA)
4768 lpmi->dwMenuData = menu->dwMenuData;
4769
4770 if (lpmi->fMask & MIM_STYLE)
4771 lpmi->dwStyle = menu->dwStyle;
4772
4773 return TRUE;
4774 }
4775 return FALSE;
4776}
4777
4778/**********************************************************************
4779 * SetMenuContextHelpId (USER32.@)
4780 */
4781BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
4782{
4783 LPPOPUPMENU menu;
4784
4785 TRACE("(0x%04x 0x%08lx)\n", hMenu, dwContextHelpID);
4786
4787 if ((menu = MENU_GetMenu(hMenu)))
4788 {
4789 menu->dwContextHelpID = dwContextHelpID;
4790 return TRUE;
4791 }
4792 return FALSE;
4793}
4794
4795/**********************************************************************
4796 * GetMenuContextHelpId (USER32.@)
4797 */
4798DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
4799{
4800 LPPOPUPMENU menu;
4801
4802 TRACE("(0x%04x)\n", hMenu);
4803
4804 if ((menu = MENU_GetMenu(hMenu)))
4805 {
4806 return menu->dwContextHelpID;
4807 }
4808 return 0;
4809}
4810
4811/**********************************************************************
4812 * MenuItemFromPoint (USER32.@)
4813 */
4814UINT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
4815{
4816 POPUPMENU *menu = MENU_GetMenu(hMenu);
4817 UINT pos;
4818 MENUITEM *item;
4819
4820 /*FIXME: Do we have to handle hWnd here? */
4821 item = MENU_FindItemByCoords(menu, ptScreen, &pos);
4822
4823 return pos;
4824}
4825
4826#ifdef __WIN32OS2__
4827//******************************************************************************
4828//******************************************************************************
4829void WIN32API DisableOdinSysMenuItems()
4830{
4831 fDisableOdinSysMenuItems = TRUE;
4832}
4833//******************************************************************************
4834//******************************************************************************
4835#else
4836//winaccel.cpp
4837/**********************************************************************
4838 * translate_accelerator
4839 */
4840static BOOL translate_accelerator( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
4841 BYTE fVirt, WORD key, WORD cmd )
4842{
4843 UINT mesg = 0;
4844
4845 if (wParam != key) return FALSE;
4846
4847 if (message == WM_CHAR)
4848 {
4849 if ( !(fVirt & FALT) && !(fVirt & FVIRTKEY) )
4850 {
4851 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", wParam & 0xff);
4852 goto found;
4853 }
4854 }
4855 else
4856 {
4857 if(fVirt & FVIRTKEY)
4858 {
4859 INT mask = 0;
4860 TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
4861 wParam, 0xff & HIWORD(lParam));
4862 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
4863 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
4864 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
4865 if(mask == (fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
4866 TRACE_(accel)(", but incorrect SHIFT/CTRL/ALT-state\n");
4867 }
4868 else
4869 {
4870 if (!(lParam & 0x01000000)) /* no special_key */
4871 {
4872 if ((fVirt & FALT) && (lParam & 0x20000000))
4873 { /* ^^ ALT pressed */
4874 TRACE_(accel)("found accel for Alt-%c\n", wParam & 0xff);
4875 goto found;
4876 }
4877 }
4878 }
4879 }
4880 return FALSE;
4881
4882 found:
4883 if (message == WM_KEYUP || message == WM_SYSKEYUP)
4884 mesg = 1;
4885 else if (GetCapture())
4886 mesg = 2;
4887 else if (!IsWindowEnabled(hWnd))
4888 mesg = 3;
4889 else
4890 {
4891 HMENU hMenu, hSubMenu, hSysMenu;
4892 UINT uSysStat = (UINT)-1, uStat = (UINT)-1, nPos;
4893
4894 hMenu = (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) ? 0 : GetMenu(hWnd);
4895 hSysMenu = get_win_sys_menu( hWnd );
4896
4897 /* find menu item and ask application to initialize it */
4898 /* 1. in the system menu */
4899 hSubMenu = hSysMenu;
4900 nPos = cmd;
4901 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4902 {
4903 SendMessageA(hWnd, WM_INITMENU, (WPARAM)hSysMenu, 0L);
4904 if(hSubMenu != hSysMenu)
4905 {
4906 nPos = MENU_FindSubMenu(&hSysMenu, hSubMenu);
4907 TRACE_(accel)("hSysMenu = %04x, hSubMenu = %04x, nPos = %d\n", hSysMenu, hSubMenu, nPos);
4908 SendMessageA(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, TRUE));
4909 }
4910 uSysStat = GetMenuState(GetSubMenu(hSysMenu, 0), cmd, MF_BYCOMMAND);
4911 }
4912 else /* 2. in the window's menu */
4913 {
4914 hSubMenu = hMenu;
4915 nPos = cmd;
4916 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
4917 {
4918 SendMessageA(hWnd, WM_INITMENU, (WPARAM)hMenu, 0L);
4919 if(hSubMenu != hMenu)
4920 {
4921 nPos = MENU_FindSubMenu(&hMenu, hSubMenu);
4922 TRACE_(accel)("hMenu = %04x, hSubMenu = %04x, nPos = %d\n", hMenu, hSubMenu, nPos);
4923 SendMessageA(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, FALSE));
4924 }
4925 uStat = GetMenuState(hMenu, cmd, MF_BYCOMMAND);
4926 }
4927 }
4928
4929 if (uSysStat != (UINT)-1)
4930 {
4931 if (uSysStat & (MF_DISABLED|MF_GRAYED))
4932 mesg=4;
4933 else
4934 mesg=WM_SYSCOMMAND;
4935 }
4936 else
4937 {
4938 if (uStat != (UINT)-1)
4939 {
4940 if (IsIconic(hWnd))
4941 mesg=5;
4942 else
4943 {
4944 if (uStat & (MF_DISABLED|MF_GRAYED))
4945 mesg=6;
4946 else
4947 mesg=WM_COMMAND;
4948 }
4949 }
4950 else
4951 mesg=WM_COMMAND;
4952 }
4953 }
4954
4955 if( mesg==WM_COMMAND )
4956 {
4957 TRACE_(accel)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd);
4958 SendMessageA(hWnd, mesg, 0x10000 | cmd, 0L);
4959 }
4960 else if( mesg==WM_SYSCOMMAND )
4961 {
4962 TRACE_(accel)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd);
4963 SendMessageA(hWnd, mesg, cmd, 0x00010000L);
4964 }
4965 else
4966 {
4967 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
4968 * #0: unknown (please report!)
4969 * #1: for WM_KEYUP,WM_SYSKEYUP
4970 * #2: mouse is captured
4971 * #3: window is disabled
4972 * #4: it's a disabled system menu option
4973 * #5: it's a menu option, but window is iconic
4974 * #6: it's a menu option, but disabled
4975 */
4976 TRACE_(accel)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
4977 if(mesg==0)
4978 ERR_(accel)(" unknown reason - please report!");
4979 }
4980 return TRUE;
4981}
4982
4983/**********************************************************************
4984 * TranslateAccelerator (USER32.@)
4985 * TranslateAcceleratorA (USER32.@)
4986 * TranslateAcceleratorW (USER32.@)
4987 */
4988INT WINAPI TranslateAccelerator( HWND hWnd, HACCEL hAccel, LPMSG msg )
4989{
4990 /* YES, Accel16! */
4991 LPACCEL16 lpAccelTbl;
4992 int i;
4993
4994 if (msg == NULL)
4995 {
4996 WARN_(accel)("msg null; should hang here to be win compatible\n");
4997 return 0;
4998 }
4999 if (!hAccel || !(lpAccelTbl = (LPACCEL16) LockResource16(HACCEL_16(hAccel))))
5000 {
5001 WARN_(accel)("invalid accel handle=%x\n", hAccel);
5002 return 0;
5003 }
5004 if ((msg->message != WM_KEYDOWN &&
5005 msg->message != WM_KEYUP &&
5006 msg->message != WM_SYSKEYDOWN &&
5007 msg->message != WM_SYSKEYUP &&
5008 msg->message != WM_CHAR)) return 0;
5009
5010 TRACE_(accel)("TranslateAccelerators hAccel=%04x, hWnd=%04x,"
5011 "msg->hwnd=%04x, msg->message=%04x, wParam=%08x, lParam=%lx\n",
5012 hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam);
5013
5014 i = 0;
5015 do
5016 {
5017 if (translate_accelerator( hWnd, msg->message, msg->wParam, msg->lParam,
5018 lpAccelTbl[i].fVirt, lpAccelTbl[i].key, lpAccelTbl[i].cmd))
5019 return 1;
5020 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
5021 WARN_(accel)("couldn't translate accelerator key\n");
5022 return 0;
5023}
5024#endif
Note: See TracBrowser for help on using the repository browser.