source: trunk/src/user32/menu.cpp@ 7195

Last change on this file since 7195 was 7195, checked in by sandervl, 24 years ago

double click fix + double click on system menu now works

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