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

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

Use different color for highlighted menus (OS/2 L&F)

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