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

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

Merged Rewind menu control

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