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

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

destroy menu window after it has been used (instead of just hiding it)

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