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

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

PF: Eat first WM_MOUSEMOVE while menu tracking like windows does; SvL: Use our fast critical sections instead of OS/2 mutex semaphores in the timer code

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