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

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

Always use windows system colors (even in OS/2 L&F mode)

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