source: trunk/src/user32/new/menu.cpp@ 2396

Last change on this file since 2396 was 2396, checked in by cbratschi, 26 years ago

activated menu code

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