[Win32k]
[reactos.git] / reactos / win32ss / user / user32 / windows / menu.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS user32.dll
4 * FILE: user32/windows/menu.c
5 * PURPOSE: Menus
6 *
7 * PROGRAMMERS: Casper S. Hornstrup
8 * James Tabor
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <user32.h>
14 #include <wine/debug.h>
15
16 LRESULT DefWndNCPaint(HWND hWnd, HRGN hRgn, BOOL Active);
17 BOOL WINAPI GdiValidateHandle(HGDIOBJ hobj);
18 LRESULT DefWndNCHitTest(HWND hWnd, POINT Point);
19 void FASTCALL NcGetSysPopupPos(HWND Wnd, RECT *Rect);
20
21 WINE_DEFAULT_DEBUG_CHANNEL(menu);
22
23 /* internal popup menu window messages */
24
25 #define MM_SETMENUHANDLE (WM_USER + 0)
26 #define MM_GETMENUHANDLE (WM_USER + 1)
27
28 /* internal flags for menu tracking */
29
30 #define TF_ENDMENU 0x10000
31 #define TF_SUSPENDPOPUP 0x20000
32 #define TF_SKIPREMOVE 0x40000
33
34 #define ITEM_PREV -1
35 #define ITEM_NEXT 1
36
37 /* Internal MenuTrackMenu() flags */
38 #define TPM_INTERNAL 0xF0000000
39 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
40 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
41
42 /* Space between 2 columns */
43 #define MENU_COL_SPACE 4
44
45 /* top and bottom margins for popup menus */
46 #define MENU_TOP_MARGIN 3
47 #define MENU_BOTTOM_MARGIN 2
48
49 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
50
51 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
52
53 #define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP)
54
55 #define MENUITEMINFO_TYPE_MASK \
56 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
57 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
58 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
59
60 #define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
61
62 #define STATE_MASK (~TYPE_MASK)
63
64 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
65
66 #define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
67
68 /* macro to test that flags do not indicate bitmap, ownerdraw or separator */
69 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
70 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
71
72 #define IS_SYSTEM_MENU(MenuInfo) \
73 (0 == ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSDESKMN))
74
75 #define IS_SYSTEM_POPUP(MenuInfo) \
76 (0 != ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSDESKMN))
77
78 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
79
80 /* Use global popup window because there's no way 2 menus can
81 * be tracked at the same time. */
82 static HWND top_popup;
83 static HMENU top_popup_hmenu;
84
85 /* Flag set by EndMenu() to force an exit from menu tracking */
86 static BOOL fEndMenu = FALSE;
87
88 #define MENU_ITEM_HBMP_SPACE (5)
89 #define MENU_BAR_ITEMS_SPACE (12)
90 #define SEPARATOR_HEIGHT (5)
91 #define MENU_TAB_SPACE (8)
92
93 typedef struct
94 {
95 UINT TrackFlags;
96 HMENU CurrentMenu; /* current submenu (can be equal to hTopMenu)*/
97 HMENU TopMenu; /* initial menu */
98 HWND OwnerWnd; /* where notifications are sent */
99 POINT Pt;
100 } MTRACKER;
101
102
103 /*********************************************************************
104 * PopupMenu class descriptor
105 */
106 const struct builtin_class_descr POPUPMENU_builtin_class =
107 {
108 WC_MENU, /* name */
109 CS_SAVEBITS | CS_DBLCLKS, /* style */
110 (WNDPROC) NULL, /* FIXME - procA */
111 (WNDPROC) PopupMenuWndProcW, /* FIXME - procW */
112 sizeof(MENUINFO *), /* extra */
113 (LPCWSTR) IDC_ARROW, /* cursor */
114 (HBRUSH)(COLOR_MENU + 1) /* brush */
115 };
116
117 #ifndef GET_WORD
118 #define GET_WORD(ptr) (*(WORD *)(ptr))
119 #endif
120 #ifndef GET_DWORD
121 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
122 #endif
123
124 HFONT hMenuFont = NULL;
125 HFONT hMenuFontBold = NULL;
126
127 /* Dimension of the menu bitmaps */
128 static HBITMAP BmpSysMenu = NULL;
129
130 static SIZE MenuCharSize;
131
132
133 /***********************************************************************
134 * MENU_GetMenu
135 *
136 * Validate the given menu handle and returns the menu structure pointer.
137 */
138 FORCEINLINE PMENU MENU_GetMenu(HMENU hMenu)
139 {
140 return ValidateHandleNoErr(hMenu, TYPE_MENU);
141 }
142
143 /***********************************************************************
144 * get_win_sys_menu
145 *
146 * Get the system menu of a window
147 */
148 static HMENU get_win_sys_menu( HWND hwnd )
149 {
150 HMENU ret = 0;
151 WND *win = ValidateHwnd( hwnd );
152 if (win)
153 {
154 ret = win->SystemMenu;
155 }
156 return ret;
157 }
158
159 /***********************************************************************
160 * MENU_FindItem
161 *
162 * Find a menu item. Return a pointer on the item, and modifies *hmenu
163 * in case the item was in a sub-menu.
164 */
165 ITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
166 {
167 MENU *menu;
168 ITEM *fallback = NULL;
169 UINT fallback_pos = 0;
170 UINT i;
171 PITEM pItem;
172
173 if ((*hmenu == (HMENU)0xffff) || (!(menu = MENU_GetMenu(*hmenu)))) return NULL;
174 if (wFlags & MF_BYPOSITION)
175 {
176 if (*nPos >= menu->cItems) return NULL;
177 pItem = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
178 if (pItem) pItem = &pItem[*nPos];
179 return pItem;
180 }
181 else
182 {
183 PITEM item = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
184 for (i = 0; item, i < menu->cItems; i++, item++)
185 {
186 if (item->spSubMenu)
187 {
188 PMENU pSubMenu = DesktopPtrToUser(item->spSubMenu);
189 HMENU hsubmenu = UserHMGetHandle(pSubMenu);
190 ITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
191 if (subitem)
192 {
193 *hmenu = hsubmenu;
194 return subitem;
195 }
196 else if (item->wID == *nPos)
197 {
198 /* fallback to this item if nothing else found */
199 fallback_pos = i;
200 fallback = item;
201 }
202 }
203 else if (item->wID == *nPos)
204 {
205 *nPos = i;
206 return item;
207 }
208 }
209 }
210
211 if (fallback)
212 *nPos = fallback_pos;
213
214 return fallback;
215 }
216
217 #define MAX_GOINTOSUBMENU (0x10)
218 UINT FASTCALL
219 IntGetMenuDefaultItem(PMENU Menu, BOOL fByPos, UINT gmdiFlags, DWORD *gismc)
220 {
221 UINT i = 0;
222 PITEM Item = Menu->rgItems ? DesktopPtrToUser(Menu->rgItems) : NULL;
223
224 /* empty menu */
225 if (!Item) return -1;
226
227 while ( !( Item->fState & MFS_DEFAULT ) )
228 {
229 i++; Item++;
230 if (i >= Menu->cItems ) return -1;
231 }
232
233 /* default: don't return disabled items */
234 if ( (!(GMDI_USEDISABLED & gmdiFlags)) && (Item->fState & MFS_DISABLED )) return -1;
235
236 /* search rekursiv when needed */
237 if ( (Item->fType & MF_POPUP) && (gmdiFlags & GMDI_GOINTOPOPUPS) && Item->spSubMenu)
238 {
239 UINT ret;
240 (*gismc)++;
241 ret = IntGetMenuDefaultItem( DesktopPtrToUser(Item->spSubMenu), fByPos, gmdiFlags, gismc );
242 (*gismc)--;
243 if ( -1 != ret ) return ret;
244
245 /* when item not found in submenu, return the popup item */
246 }
247 return ( fByPos ) ? i : Item->wID;
248 }
249
250 static BOOL GetMenuItemInfo_common ( HMENU hmenu,
251 UINT item,
252 BOOL bypos,
253 LPMENUITEMINFOW lpmii,
254 BOOL unicode)
255 {
256 ITEM *pItem = MENU_FindItem (&hmenu, &item, bypos ? MF_BYPOSITION : 0);
257
258 //debug_print_menuitem("GetMenuItemInfo_common: ", pItem, "");
259
260 if (!pItem)
261 {
262 SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
263 return FALSE;
264 }
265
266 if( lpmii->fMask & MIIM_TYPE)
267 {
268 if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP))
269 {
270 ERR("invalid combination of fMask bits used\n");
271 /* this does not happen on Win9x/ME */
272 SetLastError( ERROR_INVALID_PARAMETER);
273 return FALSE;
274 }
275 lpmii->fType = pItem->fType & MENUITEMINFO_TYPE_MASK;
276 if( pItem->hbmp) lpmii->fType |= MFT_BITMAP;
277 lpmii->hbmpItem = pItem->hbmp; /* not on Win9x/ME */
278 if( lpmii->fType & MFT_BITMAP)
279 {
280 lpmii->dwTypeData = (LPWSTR) pItem->hbmp;
281 lpmii->cch = 0;
282 }
283 else if( lpmii->fType & (MFT_OWNERDRAW | MFT_SEPARATOR))
284 {
285 /* this does not happen on Win9x/ME */
286 lpmii->dwTypeData = 0;
287 lpmii->cch = 0;
288 }
289 }
290
291 /* copy the text string */
292 if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING)))
293 {
294 if( !pItem->Xlpstr )
295 { // Very strange this fixes a wine test with a crash.
296 if(lpmii->dwTypeData && lpmii->cch && !(GdiValidateHandle((HGDIOBJ)lpmii->dwTypeData)) )
297 {
298 lpmii->cch = 0;
299 if( unicode)
300 *((WCHAR *)lpmii->dwTypeData) = 0;
301 else
302 *((CHAR *)lpmii->dwTypeData) = 0;
303 }
304 }
305 else
306 {
307 int len;
308 LPWSTR text = DesktopPtrToUser(pItem->Xlpstr);
309 if (unicode)
310 {
311 len = strlenW(text);
312 if(lpmii->dwTypeData && lpmii->cch)
313 lstrcpynW(lpmii->dwTypeData, text, lpmii->cch);
314 }
315 else
316 {
317 len = WideCharToMultiByte( CP_ACP, 0, text, -1, NULL, 0, NULL, NULL ) - 1;
318 if(lpmii->dwTypeData && lpmii->cch)
319 if (!WideCharToMultiByte( CP_ACP, 0, text, -1,
320 (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
321 ((LPSTR)lpmii->dwTypeData)[lpmii->cch - 1] = 0;
322 }
323 /* if we've copied a substring we return its length */
324 if(lpmii->dwTypeData && lpmii->cch)
325 if (lpmii->cch <= len + 1)
326 lpmii->cch--;
327 else
328 lpmii->cch = len;
329 else
330 {
331 /* return length of string */
332 /* not on Win9x/ME if fType & MFT_BITMAP */
333 lpmii->cch = len;
334 }
335 }
336 }
337
338 if (lpmii->fMask & MIIM_FTYPE)
339 lpmii->fType = pItem->fType & MENUITEMINFO_TYPE_MASK;
340
341 if (lpmii->fMask & MIIM_BITMAP)
342 lpmii->hbmpItem = pItem->hbmp;
343
344 if (lpmii->fMask & MIIM_STATE)
345 lpmii->fState = pItem->fState & MENUITEMINFO_STATE_MASK;
346
347 if (lpmii->fMask & MIIM_ID)
348 lpmii->wID = pItem->wID;
349
350 if (lpmii->fMask & MIIM_SUBMENU && pItem->spSubMenu )
351 {
352 PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
353 HMENU hSubMenu = UserHMGetHandle(pSubMenu);
354 lpmii->hSubMenu = hSubMenu;
355 }
356 else
357 {
358 /* hSubMenu is always cleared
359 * (not on Win9x/ME ) */
360 lpmii->hSubMenu = 0;
361 }
362
363 if (lpmii->fMask & MIIM_CHECKMARKS)
364 {
365 lpmii->hbmpChecked = pItem->hbmpChecked;
366 lpmii->hbmpUnchecked = pItem->hbmpUnchecked;
367 }
368 if (lpmii->fMask & MIIM_DATA)
369 lpmii->dwItemData = pItem->dwItemData;
370
371 return TRUE;
372 }
373
374 /***********************************************************************
375 * MenuGetRosMenuInfo
376 *
377 * Get full information about menu
378 */
379 static BOOL FASTCALL
380 MenuGetRosMenuInfo(PROSMENUINFO MenuInfo, HMENU Menu)
381 {
382 PMENU pMenu;
383 if (!(pMenu = ValidateHandleNoErr(Menu, TYPE_MENU))) return FALSE;
384
385 MenuInfo->hbrBack = pMenu->hbrBack;
386 MenuInfo->dwContextHelpID = pMenu->dwContextHelpId;
387 MenuInfo->cyMax = pMenu->cyMax;
388 MenuInfo->dwMenuData = pMenu->dwMenuData;
389 MenuInfo->dwStyle = pMenu->fFlags & MNS_STYLE_MASK;
390
391 MenuInfo->cItems = pMenu->cItems;
392
393 MenuInfo->iItem = pMenu->iItem;
394 MenuInfo->cxMenu = pMenu->cxMenu;
395 MenuInfo->cyMenu = pMenu->cyMenu;
396 MenuInfo->spwndNotify = pMenu->spwndNotify;
397 MenuInfo->cxTextAlign = pMenu->cxTextAlign;
398 MenuInfo->iTop = pMenu->iMaxTop;
399 MenuInfo->iMaxTop = pMenu->iMaxTop;
400 MenuInfo->dwArrowsOn = pMenu->dwArrowsOn;
401
402 MenuInfo->fFlags = pMenu->fFlags;
403 MenuInfo->Self = pMenu->head.h;
404 MenuInfo->TimeToHide = pMenu->TimeToHide;
405 MenuInfo->Wnd = pMenu->hWnd;
406 return TRUE;
407 }
408
409 /***********************************************************************
410 * MenuSetRosMenuInfo
411 *
412 * Set full information about menu
413 */
414 static BOOL FASTCALL
415 MenuSetRosMenuInfo(PROSMENUINFO MenuInfo)
416 {
417 MenuInfo->cbSize = sizeof(ROSMENUINFO);
418 MenuInfo->fMask = MIM_BACKGROUND | MIM_HELPID | MIM_MAXHEIGHT | MIM_MENUDATA | MIM_STYLE;
419
420 return NtUserThunkedMenuInfo(MenuInfo->Self, (LPCMENUINFO)MenuInfo);
421 }
422
423 /***********************************************************************
424 * MenuInitRosMenuItemInfo
425 *
426 * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
427 */
428 static VOID FASTCALL
429 MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo)
430 {
431 ZeroMemory(ItemInfo, sizeof(ROSMENUITEMINFO));
432 ItemInfo->cbSize = sizeof(ROSMENUITEMINFO);
433 }
434
435 /***********************************************************************
436 * MenuGetRosMenuItemInfo
437 *
438 * Get full information about a menu item
439 */
440 static BOOL FASTCALL
441 MenuGetRosMenuItemInfo(HMENU Menu, UINT Index, PROSMENUITEMINFO ItemInfo)
442 {
443 PITEM pItem;
444 UINT Save_Mask = ItemInfo->fMask; /* Save the org mask bits. */
445
446 if (ItemInfo->dwTypeData != NULL)
447 {
448 HeapFree(GetProcessHeap(), 0, ItemInfo->dwTypeData);
449 }
450
451 ItemInfo->dwTypeData = NULL;
452
453 if (!(pItem = MENU_FindItem(&Menu, &Index, MF_BYPOSITION)))
454 {
455 ItemInfo->fType = 0;
456 return FALSE;
457 }
458
459 ItemInfo->fType = pItem->fType;
460 ItemInfo->hbmpItem = pItem->hbmp;
461 ItemInfo->hbmpChecked = pItem->hbmpChecked;
462 ItemInfo->hbmpUnchecked = pItem->hbmpUnchecked;
463 ItemInfo->dwItemData = pItem->dwItemData;
464 ItemInfo->wID = pItem->wID;
465 ItemInfo->fState = pItem->fState;
466
467 if (pItem->spSubMenu)
468 {
469 PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
470 HMENU hSubMenu = UserHMGetHandle(pSubMenu);
471 ItemInfo->hSubMenu = hSubMenu;
472 }
473 else
474 ItemInfo->hSubMenu = NULL;
475
476 if (MENU_ITEM_TYPE(ItemInfo->fType) == MF_STRING)
477 {
478 LPWSTR lpstr = pItem->lpstr.Buffer ? DesktopPtrToUser(pItem->lpstr.Buffer) : NULL;
479 if (lpstr)
480 {
481 ItemInfo->cch = pItem->lpstr.Length / sizeof(WCHAR);
482 ItemInfo->cch++;
483 ItemInfo->dwTypeData = HeapAlloc(GetProcessHeap(), 0, ItemInfo->cch * sizeof(WCHAR));
484 if (ItemInfo->dwTypeData == NULL)
485 {
486 return FALSE;
487 }
488 RtlCopyMemory(ItemInfo->dwTypeData, lpstr, min(ItemInfo->cch * sizeof(WCHAR), pItem->lpstr.MaximumLength));
489 }
490 else
491 {
492 ItemInfo->cch = 0;
493 }
494 }
495
496 ItemInfo->Rect.left = pItem->xItem;
497 ItemInfo->Rect.top = pItem->yItem;
498 ItemInfo->Rect.right = pItem->cxItem; // Do this for now......
499 ItemInfo->Rect.bottom = pItem->cyItem;
500 ItemInfo->dxTab = pItem->dxTab;
501 ItemInfo->lpstr = pItem->lpstr.Buffer ? DesktopPtrToUser(pItem->lpstr.Buffer) : NULL;
502 ItemInfo->maxBmpSize.cx = pItem->cxBmp;
503 ItemInfo->maxBmpSize.cy = pItem->cyBmp;
504
505 ItemInfo->fMask = Save_Mask;
506 return TRUE;
507 }
508
509 /***********************************************************************
510 * MenuSetRosMenuItemInfo
511 *
512 * Set selected information about a menu item, need to set the mask bits.
513 */
514 static BOOL FASTCALL
515 MenuSetRosMenuItemInfo(HMENU Menu, UINT Index, PROSMENUITEMINFO ItemInfo)
516 {
517 BOOL Ret;
518
519 if (MENU_ITEM_TYPE(ItemInfo->fType) == MF_STRING &&
520 ItemInfo->dwTypeData != NULL)
521 {
522 ItemInfo->cch = strlenW(ItemInfo->dwTypeData);
523 }
524 if (ItemInfo->hSubMenu)
525 {
526 if (!IsMenu(ItemInfo->hSubMenu)) ItemInfo->hSubMenu = NULL;
527 }
528 Ret = NtUserThunkedMenuItemInfo(Menu, Index, TRUE, FALSE, (LPMENUITEMINFOW)ItemInfo, NULL);
529 return Ret;
530 }
531
532 /***********************************************************************
533 * MenuCleanupRosMenuItemInfo
534 *
535 * Cleanup after use of MenuGet/SetRosMenuItemInfo
536 */
537 static VOID FASTCALL
538 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo)
539 {
540 if (ItemInfo->dwTypeData != NULL)
541 {
542 HeapFree(GetProcessHeap(), 0, ItemInfo->dwTypeData);
543 ItemInfo->dwTypeData = NULL;
544 }
545 }
546
547 /***********************************************************************
548 * MenuInitSysMenuPopup
549 *
550 * Grey the appropriate items in System menu.
551 */
552 void FASTCALL MenuInitSysMenuPopup(HMENU hmenu, DWORD style, DWORD clsStyle, LONG HitTest )
553 {
554 BOOL gray;
555 UINT DefItem;
556 #if 0
557 MENUITEMINFOW mii;
558 #endif
559
560 gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
561 EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
562 gray = ((style & WS_MAXIMIZE) != 0);
563 EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
564 gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
565 EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
566 gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
567 EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
568 gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
569 EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
570 gray = (clsStyle & CS_NOCLOSE) != 0;
571
572 /* The menu item must keep its state if it's disabled */
573 if(gray)
574 EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED);
575
576 /* Set default menu item */
577 if(style & WS_MINIMIZE) DefItem = SC_RESTORE;
578 else if(HitTest == HTCAPTION) DefItem = ((style & (WS_MAXIMIZE | WS_MINIMIZE)) ? SC_RESTORE : SC_MAXIMIZE);
579 else DefItem = SC_CLOSE;
580 #if 0
581 mii.cbSize = sizeof(MENUITEMINFOW);
582 mii.fMask |= MIIM_STATE;
583 if((DefItem != SC_CLOSE) && GetMenuItemInfoW(hmenu, DefItem, FALSE, &mii) &&
584 (mii.fState & (MFS_GRAYED | MFS_DISABLED))) DefItem = SC_CLOSE;
585 #endif
586 SetMenuDefaultItem(hmenu, DefItem, MF_BYCOMMAND);
587 }
588
589 /******************************************************************************
590 *
591 * UINT MenuGetStartOfNextColumn(
592 * PROSMENUINFO MenuInfo)
593 *
594 *****************************************************************************/
595
596 static UINT MENU_GetStartOfNextColumn(
597 HMENU hMenu )
598 {
599 MENU *menu = MENU_GetMenu(hMenu);
600 PITEM pItem;
601 UINT i;
602
603 if(!menu)
604 return NO_SELECTED_ITEM;
605
606 i = menu->iItem + 1;
607 if( i == NO_SELECTED_ITEM )
608 return i;
609
610 pItem = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
611 if (!pItem) return NO_SELECTED_ITEM;
612 for( ; i < menu->cItems; ++i ) {
613 if (pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK))
614 return i;
615 }
616
617 return NO_SELECTED_ITEM;
618 }
619
620 /******************************************************************************
621 *
622 * UINT MenuGetStartOfPrevColumn(
623 * PROSMENUINFO MenuInfo)
624 *
625 *****************************************************************************/
626 static UINT MENU_GetStartOfPrevColumn(
627 HMENU hMenu )
628 {
629 MENU *menu = MENU_GetMenu(hMenu);
630 UINT i;
631 PITEM pItem;
632
633 if( !menu )
634 return NO_SELECTED_ITEM;
635
636 if( menu->iItem == 0 || menu->iItem == NO_SELECTED_ITEM )
637 return NO_SELECTED_ITEM;
638
639 pItem = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
640 if (!pItem) return NO_SELECTED_ITEM;
641
642 /* Find the start of the column */
643
644 for(i = menu->iItem; i != 0 &&
645 !(pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK));
646 --i); /* empty */
647
648 if(i == 0)
649 return NO_SELECTED_ITEM;
650
651 for(--i; i != 0; --i) {
652 if (pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK))
653 break;
654 }
655
656 TRACE("ret %d.\n", i );
657
658 return i;
659 }
660
661 /***********************************************************************
662 * MenuLoadBitmaps
663 *
664 * Load the arrow bitmap. We can't do this from MenuInit since user32
665 * can also be used (and thus initialized) from text-mode.
666 */
667 static void FASTCALL
668 MenuLoadBitmaps(VOID)
669 {
670 /* Load system buttons bitmaps */
671 if (NULL == BmpSysMenu)
672 {
673 BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
674 }
675 }
676 /////////// Make gpsi OBMI via callback //////////////
677 /***********************************************************************
678 * get_arrow_bitmap
679 */
680 HBITMAP get_arrow_bitmap(void)
681 {
682 static HBITMAP arrow_bitmap;
683
684 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW));
685 return arrow_bitmap;
686 }
687
688 /***********************************************************************
689 * get_down_arrow_bitmap DFCS_MENUARROWDOWN
690 */
691 HBITMAP get_down_arrow_bitmap(void)
692 {
693 static HBITMAP arrow_bitmap;
694
695 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROW));
696 return arrow_bitmap;
697 }
698
699 /***********************************************************************
700 * get_down_arrow_inactive_bitmap DFCS_MENUARROWDOWN | DFCS_INACTIVE
701 */
702 HBITMAP get_down_arrow_inactive_bitmap(void)
703 {
704 static HBITMAP arrow_bitmap;
705
706 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROWI));
707 return arrow_bitmap;
708 }
709
710 /***********************************************************************
711 * get_up_arrow_bitmap DFCS_MENUARROWUP
712 */
713 HBITMAP get_up_arrow_bitmap(void)
714 {
715 static HBITMAP arrow_bitmap;
716
717 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROW));
718 return arrow_bitmap;
719 }
720
721 /***********************************************************************
722 * get_up_arrow_inactive_bitmap DFCS_MENUARROWUP | DFCS_INACTIVE
723 */
724 static HBITMAP get_up_arrow_inactive_bitmap(void)
725 {
726 static HBITMAP arrow_bitmap;
727
728 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROWI));
729 return arrow_bitmap;
730 }
731 ////////////////
732 /***********************************************************************
733 * MenuFindSubMenu
734 *
735 * Find a Sub menu. Return the position of the submenu, and modifies
736 * *hmenu in case it is found in another sub-menu.
737 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
738 */
739 static UINT FASTCALL MenuFindSubMenu(HMENU *hmenu, HMENU hSubTarget )
740 {
741 PMENU menu, pSubMenu;
742 HMENU hSubMenu;
743 UINT i;
744 PITEM item;
745
746 if (((*hmenu)==(HMENU)0xffff) ||(!(menu = MENU_GetMenu(*hmenu))))
747 return NO_SELECTED_ITEM;
748
749 item = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
750 for (i = 0; i < menu->cItems; i++, item++)
751 {
752 if (!item->spSubMenu)
753 continue;
754 else
755 {
756 pSubMenu = DesktopPtrToUser(item->spSubMenu);
757 hSubMenu = UserHMGetHandle(pSubMenu);
758 if (hSubMenu == hSubTarget)
759 {
760 return i;
761 }
762 else
763 {
764 HMENU hsubmenu = hSubMenu;
765 UINT pos = MenuFindSubMenu( &hsubmenu, hSubTarget );
766 if (pos != NO_SELECTED_ITEM)
767 {
768 *hmenu = hsubmenu;
769 return pos;
770 }
771 }
772 }
773 }
774 return NO_SELECTED_ITEM;
775 }
776
777 /***********************************************************************
778 * MENU_AdjustMenuItemRect
779 *
780 * Adjust menu item rectangle according to scrolling state.
781 */
782 static void
783 MENU_AdjustMenuItemRect(PROSMENUINFO menu, LPRECT rect)
784 {
785 if (menu->dwArrowsOn)
786 {
787 UINT arrow_bitmap_height;
788 BITMAP bmp;
789
790 GetObjectW(get_up_arrow_bitmap(), sizeof(bmp), &bmp);
791 arrow_bitmap_height = bmp.bmHeight;
792 rect->top += arrow_bitmap_height - menu->iTop;
793 rect->bottom += arrow_bitmap_height - menu->iTop;
794 }
795 }
796
797 /***********************************************************************
798 * MenuDrawPopupGlyph
799 *
800 * Draws popup magic glyphs (can be found in system menu).
801 */
802 static void FASTCALL
803 MenuDrawPopupGlyph(HDC dc, LPRECT r, INT_PTR popupMagic, BOOL inactive, BOOL hilite)
804 {
805 LOGFONTW lf;
806 HFONT hFont, hOldFont;
807 COLORREF clrsave;
808 INT bkmode;
809 TCHAR symbol;
810 switch (popupMagic)
811 {
812 case (INT_PTR) HBMMENU_POPUP_RESTORE:
813 symbol = '2';
814 break;
815 case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
816 symbol = '0';
817 break;
818 case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
819 symbol = '1';
820 break;
821 case (INT_PTR) HBMMENU_POPUP_CLOSE:
822 symbol = 'r';
823 break;
824 default:
825 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic);
826 return;
827 }
828 ZeroMemory(&lf, sizeof(LOGFONTW));
829 InflateRect(r, -2, -2);
830 lf.lfHeight = r->bottom - r->top;
831 lf.lfWidth = 0;
832 lf.lfWeight = FW_NORMAL;
833 lf.lfCharSet = DEFAULT_CHARSET;
834 lstrcpy(lf.lfFaceName, TEXT("Marlett"));
835 hFont = CreateFontIndirect(&lf);
836 /* save font and text color */
837 hOldFont = SelectObject(dc, hFont);
838 clrsave = GetTextColor(dc);
839 bkmode = GetBkMode(dc);
840 /* set color and drawing mode */
841 SetBkMode(dc, TRANSPARENT);
842 if (inactive)
843 {
844 /* draw shadow */
845 if (!hilite)
846 {
847 SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
848 TextOut(dc, r->left + 1, r->top + 1, &symbol, 1);
849 }
850 }
851 SetTextColor(dc, GetSysColor(inactive ? COLOR_GRAYTEXT : (hilite ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT)));
852 /* draw selected symbol */
853 TextOut(dc, r->left, r->top, &symbol, 1);
854 /* restore previous settings */
855 SetTextColor(dc, clrsave);
856 SelectObject(dc, hOldFont);
857 SetBkMode(dc, bkmode);
858 DeleteObject(hFont);
859 }
860
861 /***********************************************************************
862 * MenuFindItemByKey
863 *
864 * Find the menu item selected by a key press.
865 * Return item id, -1 if none, -2 if we should close the menu.
866 */
867 static UINT FASTCALL MENU_FindItemByKey(HWND WndOwner, HMENU hmenu,
868 WCHAR Key, BOOL ForceMenuChar)
869 {
870 LRESULT MenuChar;
871 WORD Flags = 0;
872
873 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)Key, Key, hmenu );
874
875 if (!IsMenu( hmenu )) hmenu = GetSubMenu( get_win_sys_menu(WndOwner), 0);
876 if (hmenu)
877 {
878 MENU *menu = MENU_GetMenu( hmenu );
879 ITEM *item = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
880
881 if ( !ForceMenuChar )
882 {
883 UINT i;
884 BOOL cjk = GetSystemMetrics( SM_DBCSENABLED );
885
886 for (i = 0; i < menu->cItems; i++, item++)
887 {
888 LPWSTR text = item->Xlpstr ? DesktopPtrToUser(item->Xlpstr) : NULL;
889 if( text)
890 {
891 const WCHAR *p = text - 2;
892 do
893 {
894 const WCHAR *q = p + 2;
895 p = strchrW (q, '&');
896 if (!p && cjk) p = strchrW (q, '\036'); /* Japanese Win16 */
897 }
898 while (p != NULL && p [1] == '&');
899 if (p && (toupperW(p[1]) == toupperW(Key))) return i;
900 }
901 }
902 }
903
904 Flags |= menu->fFlags & MNF_POPUP ? MF_POPUP : 0;
905 Flags |= menu->fFlags & MNF_SYSDESKMN ? MF_SYSMENU : 0;
906
907 MenuChar = SendMessageW( WndOwner, WM_MENUCHAR,
908 MAKEWPARAM(Key, Flags), (LPARAM) hmenu);
909 if (HIWORD(MenuChar) == MNC_EXECUTE) return LOWORD(MenuChar);
910 if (HIWORD(MenuChar) == MNC_CLOSE) return (UINT)(-2);
911 }
912 return (UINT)(-1);
913 }
914
915 /***********************************************************************
916 * MenuGetBitmapItemSize
917 *
918 * Get the size of a bitmap item.
919 */
920 static void FASTCALL MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem, SIZE *size, HWND WndOwner)
921 {
922 BITMAP bm;
923 HBITMAP bmp = lpitem->hbmpItem;
924
925 size->cx = size->cy = 0;
926
927 /* check if there is a magic menu item associated with this item */
928 if (IS_MAGIC_BITMAP(bmp))
929 {
930 switch((INT_PTR) bmp)
931 {
932 case (INT_PTR)HBMMENU_CALLBACK:
933 {
934 MEASUREITEMSTRUCT measItem;
935 measItem.CtlType = ODT_MENU;
936 measItem.CtlID = 0;
937 measItem.itemID = lpitem->wID;
938 measItem.itemWidth = lpitem->Rect.right - lpitem->Rect.left;
939 measItem.itemHeight = lpitem->Rect.bottom - lpitem->Rect.top;
940 measItem.itemData = lpitem->dwItemData;
941 SendMessageW( WndOwner, WM_MEASUREITEM, lpitem->wID, (LPARAM)&measItem);
942 size->cx = measItem.itemWidth;
943 size->cy = measItem.itemHeight;
944 return;
945 }
946 break;
947
948 case (INT_PTR) HBMMENU_SYSTEM:
949 if (0 != lpitem->dwItemData)
950 {
951 bmp = (HBITMAP) lpitem->dwItemData;
952 break;
953 }
954 /* fall through */
955 case (INT_PTR) HBMMENU_MBAR_RESTORE:
956 case (INT_PTR) HBMMENU_MBAR_MINIMIZE:
957 case (INT_PTR) HBMMENU_MBAR_CLOSE:
958 case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D:
959 case (INT_PTR) HBMMENU_MBAR_CLOSE_D:
960 case (INT_PTR) HBMMENU_POPUP_CLOSE:
961 case (INT_PTR) HBMMENU_POPUP_RESTORE:
962 case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
963 case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
964 /* FIXME: Why we need to subtract these magic values? */
965 /* to make them smaller than the menu bar? */
966 size->cx = GetSystemMetrics(SM_CXSIZE) - 2;
967 size->cy = GetSystemMetrics(SM_CYSIZE) - 4;
968 return;
969 }
970 }
971
972 if (GetObjectW(bmp, sizeof(BITMAP), &bm))
973 {
974 size->cx = bm.bmWidth;
975 size->cy = bm.bmHeight;
976 }
977 }
978
979 /***********************************************************************
980 * MenuDrawBitmapItem
981 *
982 * Draw a bitmap item.
983 */
984 static void FASTCALL MenuDrawBitmapItem(HDC hdc, PROSMENUITEMINFO lpitem, const RECT *rect,
985 PROSMENUINFO MenuInfo, HWND WndOwner, UINT odaction, BOOL MenuBar)
986 {
987 BITMAP bm;
988 DWORD rop;
989 HDC hdcMem;
990 HBITMAP bmp;
991 int w = rect->right - rect->left;
992 int h = rect->bottom - rect->top;
993 int bmp_xoffset = 0;
994 int left, top;
995 HBITMAP hbmToDraw = lpitem->hbmpItem;
996 bmp = hbmToDraw;
997
998 /* Check if there is a magic menu item associated with this item */
999 if (IS_MAGIC_BITMAP(hbmToDraw))
1000 {
1001 UINT flags = 0;
1002 RECT r;
1003
1004 r = *rect;
1005 switch ((INT_PTR)hbmToDraw)
1006 {
1007 case (INT_PTR)HBMMENU_SYSTEM:
1008 if (lpitem->dwTypeData)
1009 {
1010 bmp = (HBITMAP)lpitem->dwTypeData;
1011 if (!GetObjectW( bmp, sizeof(bm), &bm )) return;
1012 }
1013 else
1014 {
1015 if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
1016 bmp = BmpSysMenu;
1017 if (! GetObjectW(bmp, sizeof(bm), &bm)) return;
1018 /* only use right half of the bitmap */
1019 bmp_xoffset = bm.bmWidth / 2;
1020 bm.bmWidth -= bmp_xoffset;
1021 }
1022 goto got_bitmap;
1023 case (INT_PTR)HBMMENU_MBAR_RESTORE:
1024 flags = DFCS_CAPTIONRESTORE;
1025 break;
1026 case (INT_PTR)HBMMENU_MBAR_MINIMIZE:
1027 r.right += 1;
1028 flags = DFCS_CAPTIONMIN;
1029 break;
1030 case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D:
1031 r.right += 1;
1032 flags = DFCS_CAPTIONMIN | DFCS_INACTIVE;
1033 break;
1034 case (INT_PTR)HBMMENU_MBAR_CLOSE:
1035 flags = DFCS_CAPTIONCLOSE;
1036 break;
1037 case (INT_PTR)HBMMENU_MBAR_CLOSE_D:
1038 flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE;
1039 break;
1040 case (INT_PTR)HBMMENU_CALLBACK:
1041 {
1042 DRAWITEMSTRUCT drawItem;
1043 POINT origorg;
1044 drawItem.CtlType = ODT_MENU;
1045 drawItem.CtlID = 0;
1046 drawItem.itemID = lpitem->wID;
1047 drawItem.itemAction = odaction;
1048 drawItem.itemState = (lpitem->fState & MF_CHECKED)?ODS_CHECKED:0;
1049 drawItem.itemState |= (lpitem->fState & MF_DEFAULT)?ODS_DEFAULT:0;
1050 drawItem.itemState |= (lpitem->fState & MF_DISABLED)?ODS_DISABLED:0;
1051 drawItem.itemState |= (lpitem->fState & MF_GRAYED)?ODS_GRAYED|ODS_DISABLED:0;
1052 drawItem.itemState |= (lpitem->fState & MF_HILITE)?ODS_SELECTED:0;
1053 //drawItem.itemState |= (!(MenuInfo->fFlags & MNF_UNDERLINE))?ODS_NOACCEL:0;
1054 //drawItem.itemState |= (MenuInfo->fFlags & MNF_INACTIVE)?ODS_INACTIVE:0;
1055 drawItem.hwndItem = (HWND)MenuInfo->Self;
1056 drawItem.hDC = hdc;
1057 drawItem.rcItem = *rect;
1058 drawItem.itemData = lpitem->dwItemData;
1059 /* some applications make this assumption on the DC's origin */
1060 SetViewportOrgEx( hdc, lpitem->Rect.left, lpitem->Rect.top, &origorg);
1061 OffsetRect( &drawItem.rcItem, - lpitem->Rect.left, - lpitem->Rect.top);
1062 SendMessageW( WndOwner, WM_DRAWITEM, 0, (LPARAM)&drawItem);
1063 SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
1064 return;
1065 }
1066 break;
1067
1068 case (INT_PTR) HBMMENU_POPUP_CLOSE:
1069 case (INT_PTR) HBMMENU_POPUP_RESTORE:
1070 case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
1071 case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
1072 MenuDrawPopupGlyph(hdc, &r, (INT_PTR)hbmToDraw, lpitem->fState & MF_GRAYED, lpitem->fState & MF_HILITE);
1073 return;
1074 }
1075 InflateRect(&r, -1, -1);
1076 if (0 != (lpitem->fState & MF_HILITE))
1077 {
1078 flags |= DFCS_PUSHED;
1079 }
1080 DrawFrameControl(hdc, &r, DFC_CAPTION, flags);
1081 return;
1082 }
1083
1084 if (!bmp || !GetObjectW( bmp, sizeof(bm), &bm )) return;
1085
1086 got_bitmap:
1087 hdcMem = CreateCompatibleDC( hdc );
1088 SelectObject( hdcMem, bmp );
1089
1090 /* handle fontsize > bitmap_height */
1091 top = (h>bm.bmHeight) ? rect->top+(h-bm.bmHeight)/2 : rect->top;
1092 left=rect->left;
1093 rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_BITMAP(hbmToDraw)) ? NOTSRCCOPY : SRCCOPY;
1094 if ((lpitem->fState & MF_HILITE) && lpitem->hbmpItem)
1095 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1096 BitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop );
1097 DeleteDC( hdcMem );
1098 }
1099
1100 /***********************************************************************
1101 * MenuCalcItemSize
1102 *
1103 * Calculate the size of the menu item and store it in lpitem->rect.
1104 */
1105 static void FASTCALL MenuCalcItemSize( HDC hdc, PROSMENUITEMINFO lpitem, PROSMENUINFO MenuInfo, HWND hwndOwner,
1106 INT orgX, INT orgY, BOOL menuBar, BOOL textandbmp)
1107 {
1108 WCHAR *p;
1109 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
1110 UINT arrow_bitmap_width;
1111 BITMAP bm;
1112 INT itemheight = 0;
1113
1114 TRACE("dc=%x owner=%x (%d,%d)\n", hdc, hwndOwner, orgX, orgY);
1115
1116 GetObjectW( get_arrow_bitmap(), sizeof(bm), &bm );
1117 arrow_bitmap_width = bm.bmWidth;
1118
1119 MenuCharSize.cx = GdiGetCharDimensions( hdc, NULL, &MenuCharSize.cy );
1120
1121 SetRect( &lpitem->Rect, orgX, orgY, orgX, orgY );
1122
1123 if (lpitem->fType & MF_OWNERDRAW)
1124 {
1125 MEASUREITEMSTRUCT mis;
1126 mis.CtlType = ODT_MENU;
1127 mis.CtlID = 0;
1128 mis.itemID = lpitem->wID;
1129 mis.itemData = lpitem->dwItemData;
1130 mis.itemHeight = HIWORD( GetDialogBaseUnits());
1131 mis.itemWidth = 0;
1132 SendMessageW( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
1133 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1134 * width of a menufont character to the width of an owner-drawn menu.
1135 */
1136 lpitem->Rect.right += mis.itemWidth + 2 * MenuCharSize.cx;
1137 if (menuBar) {
1138 /* under at least win95 you seem to be given a standard
1139 height for the menu and the height value is ignored */
1140 lpitem->Rect.bottom += GetSystemMetrics(SM_CYMENUSIZE);
1141 } else
1142 lpitem->Rect.bottom += mis.itemHeight;
1143 // Or this,
1144 //Item->cxBmp = mis.itemWidth;
1145 //Item->cyBmp = mis.itemHeight;
1146 TRACE("id=%04lx size=%dx%d\n",
1147 lpitem->wID, lpitem->Rect.right-lpitem->Rect.left,
1148 lpitem->Rect.bottom-lpitem->Rect.top);
1149 return;
1150 }
1151
1152 if (lpitem->fType & MF_SEPARATOR)
1153 {
1154 lpitem->Rect.bottom += GetSystemMetrics( SM_CYMENUSIZE)/2;//SEPARATOR_HEIGHT;
1155 if( !menuBar)
1156 lpitem->Rect.right += arrow_bitmap_width/*check_bitmap_width*/ + MenuCharSize.cx;
1157 return;
1158 }
1159
1160 lpitem->dxTab = 0;
1161
1162 if (lpitem->hbmpItem)
1163 {
1164 SIZE size;
1165
1166 if (!menuBar) {
1167 MenuGetBitmapItemSize(lpitem, &size, hwndOwner );
1168 /* Keep the size of the bitmap in callback mode to be able
1169 * to draw it correctly */
1170 lpitem->maxBmpSize = size;
1171 MenuInfo->cxTextAlign = max(MenuInfo->cxTextAlign, size.cx);
1172 MenuSetRosMenuInfo(MenuInfo);
1173 lpitem->Rect.right += size.cx + 2;
1174 itemheight = size.cy + 2;
1175
1176 if( !(MenuInfo->dwStyle & MNS_NOCHECK))
1177 lpitem->Rect.right += 2 * check_bitmap_width;
1178 lpitem->Rect.right += 4 + MenuCharSize.cx;
1179 lpitem->dxTab = lpitem->Rect.right;
1180 lpitem->Rect.right += arrow_bitmap_width;//check_bitmap_width;
1181 } else /* hbmpItem & MenuBar */ {
1182 MenuGetBitmapItemSize(lpitem, &size, hwndOwner );
1183 lpitem->Rect.right += size.cx;
1184 if( lpitem->lpstr) lpitem->Rect.right += 2;
1185 itemheight = size.cy;
1186
1187 /* Special case: Minimize button doesn't have a space behind it. */
1188 if (lpitem->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE ||
1189 lpitem->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE_D)
1190 lpitem->Rect.right -= 1;
1191 }
1192 }
1193 else if (!menuBar) {
1194 if( !(MenuInfo->dwStyle & MNS_NOCHECK))
1195 lpitem->Rect.right += check_bitmap_width;
1196 lpitem->Rect.right += 4 + MenuCharSize.cx;
1197 lpitem->dxTab = lpitem->Rect.right;
1198 lpitem->Rect.right += check_bitmap_width;
1199 }
1200
1201 /* it must be a text item - unless it's the system menu */
1202 if (!(lpitem->fType & MF_SYSMENU) && lpitem->lpstr) {
1203 HFONT hfontOld = NULL;
1204 RECT rc = lpitem->Rect;
1205 LONG txtheight, txtwidth;
1206
1207 if ( lpitem->fState & MFS_DEFAULT ) {
1208 hfontOld = SelectObject( hdc, hMenuFontBold );
1209 }
1210 if (menuBar) {
1211 txtheight = DrawTextW( hdc, lpitem->lpstr, -1, &rc,
1212 DT_SINGLELINE|DT_CALCRECT);
1213 lpitem->Rect.right += rc.right - rc.left;
1214 itemheight = max( max( itemheight, txtheight),
1215 GetSystemMetrics( SM_CYMENU) - 1);
1216 lpitem->Rect.right += 2 * MenuCharSize.cx;
1217 } else {
1218 if ((p = strchrW( lpitem->lpstr, '\t' )) != NULL) {
1219 RECT tmprc = rc;
1220 LONG tmpheight;
1221 int n = (int)( p - lpitem->lpstr);
1222 /* Item contains a tab (only meaningful in popup menus) */
1223 /* get text size before the tab */
1224 txtheight = DrawTextW( hdc, lpitem->lpstr, n, &rc,
1225 DT_SINGLELINE|DT_CALCRECT);
1226 txtwidth = rc.right - rc.left;
1227 p += 1; /* advance past the Tab */
1228 /* get text size after the tab */
1229 tmpheight = DrawTextW( hdc, p, -1, &tmprc,
1230 DT_SINGLELINE|DT_CALCRECT);
1231 lpitem->dxTab += txtwidth;
1232 txtheight = max( txtheight, tmpheight);
1233 txtwidth += MenuCharSize.cx + /* space for the tab */
1234 tmprc.right - tmprc.left; /* space for the short cut */
1235 } else {
1236 txtheight = DrawTextW( hdc, lpitem->lpstr, -1, &rc,
1237 DT_SINGLELINE|DT_CALCRECT);
1238 txtwidth = rc.right - rc.left;
1239 lpitem->dxTab += txtwidth;
1240 }
1241 lpitem->Rect.right += 2 + txtwidth;
1242 itemheight = max( itemheight,
1243 max( txtheight + 2, MenuCharSize.cy + 4));
1244 }
1245 if (hfontOld) SelectObject (hdc, hfontOld);
1246 } else if( menuBar) {
1247 itemheight = max( itemheight, GetSystemMetrics(SM_CYMENU)-1);
1248 }
1249 lpitem->Rect.bottom += itemheight;
1250 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem->Rect.left, lpitem->Rect.top, lpitem->Rect.right, lpitem->Rect.bottom);
1251 }
1252
1253 /***********************************************************************
1254 * MENU_GetMaxPopupHeight
1255 */
1256 static UINT
1257 MENU_GetMaxPopupHeight(PROSMENUINFO lppop)
1258 {
1259 if (lppop->cyMax)
1260 return lppop->cyMax;
1261 return GetSystemMetrics(SM_CYSCREEN) - GetSystemMetrics(SM_CYBORDER);
1262 }
1263
1264 /***********************************************************************
1265 * MenuPopupMenuCalcSize
1266 *
1267 * Calculate the size of a popup menu.
1268 */
1269 static void FASTCALL MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo, HWND WndOwner)
1270 {
1271 ROSMENUITEMINFO lpitem;
1272 HDC hdc;
1273 int start, i;
1274 int orgX, orgY, maxX, maxTab, maxTabWidth, maxHeight;
1275 BOOL textandbmp = FALSE;
1276
1277 MenuInfo->cxMenu = MenuInfo->cyMenu = 0;
1278 if (MenuInfo->cItems == 0)
1279 {
1280 MenuSetRosMenuInfo(MenuInfo);
1281 return;
1282 }
1283
1284 hdc = GetDC(NULL);
1285 SelectObject( hdc, hMenuFont );
1286
1287 start = 0;
1288 maxX = 2 + 1;
1289
1290 MenuInfo->cxTextAlign = 0;
1291
1292 MenuInitRosMenuItemInfo(&lpitem);
1293 //MenuGetRosMenuItemInfo(MenuInfo->Self, start, &lpitem);
1294 while (start < MenuInfo->cItems)
1295 {
1296 //lpitem = &lppop->items[start];
1297 orgX = maxX;
1298 //if( lpitem.fType & (MF_MENUBREAK | MF_MENUBARBREAK))
1299 // orgX += MENU_COL_SPACE;
1300 orgY = 2;//MENU_TOP_MARGIN;
1301
1302 maxTab = maxTabWidth = 0;
1303 /* Parse items until column break or end of menu */
1304 for (i = start; i < MenuInfo->cItems; i++)//, lpitem++)
1305 {
1306 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i, &lpitem))
1307 {
1308 MenuCleanupRosMenuItemInfo(&lpitem);
1309 MenuSetRosMenuInfo(MenuInfo);
1310 return;
1311 }
1312 if (i != start &&
1313 (lpitem.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
1314
1315
1316 MenuCalcItemSize(hdc, &lpitem, MenuInfo, WndOwner, orgX, orgY, FALSE, textandbmp);
1317 if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &lpitem))
1318 {
1319 MenuCleanupRosMenuItemInfo(&lpitem);
1320 MenuSetRosMenuInfo(MenuInfo);
1321 return;
1322 }
1323
1324 maxX = max(maxX, lpitem.Rect.right);
1325 orgY = lpitem.Rect.bottom;
1326 if (IS_STRING_ITEM(lpitem.fType) && lpitem.dxTab )
1327 {
1328 maxTab = max( maxTab, lpitem.dxTab );
1329 maxTabWidth = max(maxTabWidth, lpitem.Rect.right - lpitem.dxTab);
1330 }
1331 if( lpitem.lpstr && lpitem.hbmpItem) textandbmp = TRUE;
1332 }
1333
1334 /* Finish the column (set all items to the largest width found) */
1335 maxX = max( maxX, maxTab + maxTabWidth );
1336 while (start < i)
1337 {
1338 if (MenuGetRosMenuItemInfo(MenuInfo->Self, start, &lpitem))
1339 {
1340 lpitem.Rect.right = maxX;
1341 if (IS_STRING_ITEM(lpitem.fType) && lpitem.dxTab)
1342 {
1343 lpitem.dxTab = maxTab;
1344 }
1345 MenuSetRosMenuItemInfo(MenuInfo->Self, start, &lpitem);
1346 }
1347 start++;
1348 }
1349 MenuInfo->cyMenu = max(MenuInfo->cyMenu, orgY);
1350 }
1351
1352 MenuInfo->cxMenu = maxX;
1353 /* if none of the items have both text and bitmap then
1354 * the text and bitmaps are all aligned on the left. If there is at
1355 * least one item with both text and bitmap then bitmaps are
1356 * on the left and texts left aligned with the right hand side
1357 * of the bitmaps */
1358 if( !textandbmp) MenuInfo->cxTextAlign = 0;
1359
1360 /* space for 3d border */
1361 MenuInfo->cyMenu += MENU_BOTTOM_MARGIN;
1362 MenuInfo->cxMenu += 2;
1363
1364 /* Adjust popup height if it exceeds maximum */
1365 maxHeight = MENU_GetMaxPopupHeight(MenuInfo);
1366 MenuInfo->iMaxTop = MenuInfo->cyMenu - MENU_TOP_MARGIN;
1367 if (MenuInfo->cyMenu >= maxHeight)
1368 {
1369 MenuInfo->cyMenu = maxHeight;
1370 MenuInfo->dwArrowsOn = 1;
1371 }
1372 else
1373 {
1374 MenuInfo->dwArrowsOn = 0;
1375 }
1376
1377 MenuCleanupRosMenuItemInfo(&lpitem);
1378 MenuSetRosMenuInfo(MenuInfo);
1379 ReleaseDC( 0, hdc );
1380 }
1381
1382 /***********************************************************************
1383 * MenuMenuBarCalcSize
1384 *
1385 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1386 * height is off by 1 pixel which causes lengthy window relocations when
1387 * active document window is maximized/restored.
1388 *
1389 * Calculate the size of the menu bar.
1390 */
1391 static void FASTCALL MenuMenuBarCalcSize( HDC hdc, LPRECT lprect,
1392 PROSMENUINFO MenuInfo, HWND hwndOwner )
1393 {
1394 ROSMENUITEMINFO ItemInfo;
1395 int start, i, orgX, orgY, maxY, helpPos;
1396
1397 if ((lprect == NULL) || (MenuInfo == NULL)) return;
1398 if (MenuInfo->cItems == 0) return;
1399 TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect));
1400 MenuInfo->cxMenu = lprect->right - lprect->left;
1401 MenuInfo->cyMenu = 0;
1402 maxY = lprect->top + 1;
1403 start = 0;
1404 helpPos = -1;
1405
1406 MenuInfo->cxTextAlign = 0;
1407
1408 MenuInitRosMenuItemInfo(&ItemInfo);
1409 while (start < MenuInfo->cItems)
1410 {
1411 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo))
1412 {
1413 MenuCleanupRosMenuItemInfo(&ItemInfo);
1414 return;
1415 }
1416 orgX = lprect->left;
1417 orgY = maxY;
1418
1419 /* Parse items until line break or end of menu */
1420 for (i = start; i < MenuInfo->cItems; i++)
1421 {
1422 if ((helpPos == -1) && (ItemInfo.fType & MF_RIGHTJUSTIFY)) helpPos = i;
1423 if ((i != start) &&
1424 (ItemInfo.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
1425
1426 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX, orgY);
1427 MenuCalcItemSize(hdc, &ItemInfo, MenuInfo, hwndOwner, orgX, orgY, TRUE, FALSE);
1428 if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo))
1429 {
1430 MenuCleanupRosMenuItemInfo(&ItemInfo);
1431 return;
1432 }
1433
1434 if (ItemInfo.Rect.right > lprect->right)
1435 {
1436 if (i != start) break;
1437 else ItemInfo.Rect.right = lprect->right;
1438 }
1439 maxY = max( maxY, ItemInfo.Rect.bottom );
1440 orgX = ItemInfo.Rect.right;
1441 if (i + 1 < MenuInfo->cItems)
1442 {
1443 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i + 1, &ItemInfo))
1444 {
1445 MenuCleanupRosMenuItemInfo(&ItemInfo);
1446 return;
1447 }
1448 }
1449 }
1450
1451 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1452 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1453 #if 0
1454 /* Finish the line (set all items to the largest height found) */
1455 while (start < i)
1456 {
1457 if (MenuGetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo))
1458 {
1459 ItemInfo.Rect.bottom = maxY;
1460 MenuSetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo);
1461 }
1462 start++;
1463 }
1464 #else
1465 start = i; /* This works! */
1466 #endif
1467 }
1468
1469 lprect->bottom = maxY;
1470 MenuInfo->cyMenu = lprect->bottom - lprect->top;
1471 MenuSetRosMenuInfo(MenuInfo);
1472
1473 if (helpPos != -1)
1474 {
1475 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1476 /* the last item (if several lines, only move the last line) */
1477 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->cItems - 1, &ItemInfo))
1478 {
1479 MenuCleanupRosMenuItemInfo(&ItemInfo);
1480 return;
1481 }
1482 orgY = ItemInfo.Rect.top;
1483 orgX = lprect->right;
1484 for (i = MenuInfo->cItems - 1; helpPos <= i; i--)
1485 {
1486 if (i < helpPos) break; /* done */
1487 if (ItemInfo.Rect.top != orgY) break; /* Other line */
1488 if (orgX <= ItemInfo.Rect.right) break; /* Too far right already */
1489 ItemInfo.Rect.left += orgX - ItemInfo.Rect.right;
1490 ItemInfo.Rect.right = orgX;
1491 orgX = ItemInfo.Rect.left;
1492 MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo);
1493 if (helpPos + 1 <= i &&
1494 ! MenuGetRosMenuItemInfo(MenuInfo->Self, i - 1, &ItemInfo))
1495 {
1496 MenuCleanupRosMenuItemInfo(&ItemInfo);
1497 return;
1498 }
1499 }
1500 }
1501
1502 MenuCleanupRosMenuItemInfo(&ItemInfo);
1503 }
1504
1505 /***********************************************************************
1506 * MENU_DrawScrollArrows
1507 *
1508 * Draw scroll arrows.
1509 */
1510 static void
1511 MENU_DrawScrollArrows(PROSMENUINFO lppop, HDC hdc)
1512 {
1513 HDC hdcMem = CreateCompatibleDC(hdc);
1514 HBITMAP hOrigBitmap;
1515 UINT arrow_bitmap_width, arrow_bitmap_height;
1516 BITMAP bmp;
1517 RECT rect;
1518
1519 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp), &bmp);
1520 arrow_bitmap_width = bmp.bmWidth;
1521 arrow_bitmap_height = bmp.bmHeight;
1522
1523 if (lppop->iTop)
1524 hOrigBitmap = SelectObject(hdcMem, get_up_arrow_bitmap());
1525 else
1526 hOrigBitmap = SelectObject(hdcMem, get_up_arrow_inactive_bitmap());
1527 rect.left = 0;
1528 rect.top = 0;
1529 rect.right = lppop->cxMenu;
1530 rect.bottom = arrow_bitmap_height;
1531 FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENU));
1532 BitBlt(hdc, (lppop->cxMenu - arrow_bitmap_width) / 2, 0,
1533 arrow_bitmap_width, arrow_bitmap_height, hdcMem, 0, 0, SRCCOPY);
1534 rect.top = lppop->cyMenu - arrow_bitmap_height;
1535 rect.bottom = lppop->cyMenu;
1536 FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENU));
1537 if (lppop->iTop < lppop->iMaxTop - (MENU_GetMaxPopupHeight(lppop) - 2 * arrow_bitmap_height))
1538 SelectObject(hdcMem, get_down_arrow_bitmap());
1539 else
1540 SelectObject(hdcMem, get_down_arrow_inactive_bitmap());
1541 BitBlt(hdc, (lppop->cxMenu - arrow_bitmap_width) / 2,
1542 lppop->cyMenu - arrow_bitmap_height,
1543 arrow_bitmap_width, arrow_bitmap_height, hdcMem, 0, 0, SRCCOPY);
1544 SelectObject(hdcMem, hOrigBitmap);
1545 DeleteDC(hdcMem);
1546 }
1547
1548 /***********************************************************************
1549 * draw_popup_arrow
1550 *
1551 * Draws the popup-menu arrow.
1552 */
1553 static void draw_popup_arrow( HDC hdc, RECT rect, UINT arrow_bitmap_width,
1554 UINT arrow_bitmap_height)
1555 {
1556 HDC hdcMem = CreateCompatibleDC( hdc );
1557 HBITMAP hOrigBitmap;
1558
1559 hOrigBitmap = SelectObject( hdcMem, get_arrow_bitmap() );
1560 BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
1561 (rect.top + rect.bottom - arrow_bitmap_height) / 2,
1562 arrow_bitmap_width, arrow_bitmap_height,
1563 hdcMem, 0, 0, SRCCOPY );
1564 SelectObject( hdcMem, hOrigBitmap );
1565 DeleteDC( hdcMem );
1566 }
1567
1568 /***********************************************************************
1569 * MenuDrawMenuItem
1570 *
1571 * Draw a single menu item.
1572 */
1573 static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC hdc,
1574 PROSMENUITEMINFO lpitem, UINT Height, BOOL menuBar, UINT odaction)
1575 {
1576 RECT rect;
1577 PWCHAR Text;
1578 BOOL flat_menu = FALSE;
1579 int bkgnd;
1580 UINT arrow_bitmap_width = 0, arrow_bitmap_height = 0;
1581 PWND Wnd = ValidateHwndNoErr(hWnd);
1582
1583 if (!Wnd)
1584 return;
1585
1586 if (!menuBar) {
1587 BITMAP bmp;
1588 GetObjectW( get_arrow_bitmap(), sizeof(bmp), &bmp );
1589 arrow_bitmap_width = bmp.bmWidth;
1590 arrow_bitmap_height = bmp.bmHeight;
1591 }
1592
1593 if (lpitem->fType & MF_SYSMENU)
1594 {
1595 if ( (Wnd->style & WS_MINIMIZE))
1596 {
1597 UserGetInsideRectNC(Wnd, &rect);
1598 UserDrawSysMenuButton(hWnd, hdc, &rect, lpitem->fState & (MF_HILITE | MF_MOUSESELECT));
1599 }
1600 return;
1601 }
1602
1603 SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
1604 bkgnd = (menuBar && flat_menu) ? COLOR_MENUBAR : COLOR_MENU;
1605
1606 /* Setup colors */
1607
1608 if (lpitem->fState & MF_HILITE)
1609 {
1610 if(menuBar && !flat_menu) {
1611 SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT));
1612 SetBkColor(hdc, GetSysColor(COLOR_MENU));
1613 } else {
1614 if (lpitem->fState & MF_GRAYED)
1615 SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
1616 else
1617 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1618 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1619 }
1620 }
1621 else
1622 {
1623 if (lpitem->fState & MF_GRAYED)
1624 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1625 else
1626 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
1627 SetBkColor( hdc, GetSysColor( bkgnd ) );
1628 }
1629
1630 TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->Rect));
1631 rect = lpitem->Rect;
1632 MENU_AdjustMenuItemRect(MenuInfo, &rect);
1633
1634 if (lpitem->fType & MF_OWNERDRAW)
1635 {
1636 /*
1637 ** Experimentation under Windows reveals that an owner-drawn
1638 ** menu is given the rectangle which includes the space it requested
1639 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1640 ** and a popup-menu arrow. This is the value of lpitem->rect.
1641 ** Windows will leave all drawing to the application except for
1642 ** the popup-menu arrow. Windows always draws that itself, after
1643 ** the menu owner has finished drawing.
1644 */
1645 DRAWITEMSTRUCT dis;
1646
1647 dis.CtlType = ODT_MENU;
1648 dis.CtlID = 0;
1649 dis.itemID = lpitem->wID;
1650 dis.itemData = (DWORD)lpitem->dwItemData;
1651 dis.itemState = 0;
1652 if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
1653 if (lpitem->fState & MF_DEFAULT) dis.itemState |= ODS_DEFAULT;
1654 if (lpitem->fState & MF_DISABLED) dis.itemState |= ODS_DISABLED;
1655 if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED | ODS_DISABLED;
1656 if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED;
1657 //if (!(MenuInfo->fFlags & MNF_UNDERLINE)) dis.itemState |= ODS_NOACCEL;
1658 //if (MenuInfo->fFlags & MNF_INACTIVE) dis.itemState |= ODS_INACTIVE;
1659 dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1660 dis.hwndItem = (HWND) MenuInfo->Self;
1661 dis.hDC = hdc;
1662 dis.rcItem = rect;
1663 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1664 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd,
1665 dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
1666 dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
1667 dis.rcItem.bottom);
1668 SendMessageW(WndOwner, WM_DRAWITEM, 0, (LPARAM) &dis);
1669 /* Draw the popup-menu arrow */
1670 if (lpitem->hSubMenu)
1671 {
1672 /* RECT rectTemp;
1673 CopyRect(&rectTemp, &rect);
1674 rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK);
1675 DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW);
1676 */
1677 draw_popup_arrow( hdc, rect, arrow_bitmap_width, arrow_bitmap_height);
1678 }
1679 return;
1680 }
1681
1682 if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
1683
1684 if (lpitem->fState & MF_HILITE)
1685 {
1686 if (flat_menu)
1687 {
1688 InflateRect (&rect, -1, -1);
1689 FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENUHILIGHT));
1690 InflateRect (&rect, 1, 1);
1691 FrameRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1692 }
1693 else
1694 {
1695 if(menuBar)
1696 DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
1697 else
1698 FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1699 }
1700 }
1701 else
1702 FillRect( hdc, &rect, GetSysColorBrush(bkgnd) );
1703
1704 SetBkMode( hdc, TRANSPARENT );
1705
1706 /* vertical separator */
1707 if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
1708 {
1709 HPEN oldPen;
1710 RECT rc = rect;
1711
1712 rc.left -= 3;//MENU_COL_SPACE / 2 + 1;
1713 rc.top = 3;
1714 rc.bottom = Height - 3;
1715 if (flat_menu)
1716 {
1717 oldPen = SelectObject( hdc, GetStockObject(DC_PEN) );
1718 SetDCPenColor(hdc, GetSysColor(COLOR_BTNSHADOW));
1719 MoveToEx( hdc, rc.left, rc.top, NULL );
1720 LineTo( hdc, rc.left, rc.bottom );
1721 SelectObject( hdc, oldPen );
1722 }
1723 else
1724 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
1725 }
1726
1727 /* horizontal separator */
1728 if (lpitem->fType & MF_SEPARATOR)
1729 {
1730 HPEN oldPen;
1731 RECT rc = rect;
1732
1733 rc.left++;
1734 rc.right--;
1735 rc.top += SEPARATOR_HEIGHT / 2;
1736 if (flat_menu)
1737 {
1738 oldPen = SelectObject( hdc, GetStockObject(DC_PEN) );
1739 SetDCPenColor( hdc, GetSysColor(COLOR_BTNSHADOW));
1740 MoveToEx( hdc, rc.left, rc.top, NULL );
1741 LineTo( hdc, rc.right, rc.top );
1742 SelectObject( hdc, oldPen );
1743 }
1744 else
1745 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
1746 return;
1747 }
1748
1749 #if 0
1750 /* helper lines for debugging */
1751 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
1752 FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1753 SelectObject(hdc, GetStockObject(DC_PEN));
1754 SetDCPenColor(hdc, GetSysColor(COLOR_WINDOWFRAME));
1755 MoveToEx(hdc, rect.left, (rect.top + rect.bottom) / 2, NULL);
1756 LineTo(hdc, rect.right, (rect.top + rect.bottom) / 2);
1757 #endif
1758
1759 if (!menuBar)
1760 {
1761 HBITMAP bm;
1762 INT y = rect.top + rect.bottom;
1763 RECT rc = rect;
1764 BOOL checked = FALSE;
1765 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
1766 UINT check_bitmap_height = GetSystemMetrics( SM_CYMENUCHECK );
1767 /* Draw the check mark
1768 *
1769 * FIXME:
1770 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1771 */
1772 if( !(MenuInfo->dwStyle & MNS_NOCHECK)) {
1773 bm = (lpitem->fState & MF_CHECKED) ? lpitem->hbmpChecked :
1774 lpitem->hbmpUnchecked;
1775 if (bm) /* we have a custom bitmap */
1776 {
1777 HDC hdcMem = CreateCompatibleDC( hdc );
1778
1779 SelectObject( hdcMem, bm );
1780 BitBlt( hdc, rc.left, (y - check_bitmap_height) / 2,
1781 check_bitmap_width, check_bitmap_height,
1782 hdcMem, 0, 0, SRCCOPY );
1783 DeleteDC( hdcMem );
1784 checked = TRUE;
1785 }
1786 else if (lpitem->fState & MF_CHECKED) /* standard bitmaps */
1787 {
1788 RECT r;
1789 //HBITMAP bm = CreateBitmap( check_bitmap_width, check_bitmap_height, 1, 1, NULL );
1790 //HDC hdcMem = CreateCompatibleDC( hdc );
1791 //SelectObject( hdcMem, bm );
1792 //SetRect( &r, 0, 0, check_bitmap_width, check_bitmap_height);
1793 CopyRect(&r, &rect);
1794 r.right = r.left + GetSystemMetrics(SM_CXMENUCHECK);
1795 DrawFrameControl( hdc, &r, DFC_MENU,
1796 (lpitem->fType & MFT_RADIOCHECK) ?
1797 DFCS_MENUBULLET : DFCS_MENUCHECK);
1798 //BitBlt( hdc, rc.left, (y - r.bottom) / 2, r.right, r.bottom, hdcMem, 0, 0, SRCCOPY );
1799 //DeleteDC( hdcMem );
1800 //DeleteObject( bm );
1801 checked = TRUE;
1802 }
1803 }
1804 if ( lpitem->hbmpItem )//&& !( checked && (MenuInfo->dwStyle & MNS_CHECKORBMP)))
1805 {
1806 RECT bmpRect;
1807 CopyRect(&bmpRect, &rect);
1808 if (!(MenuInfo->dwStyle & MNS_CHECKORBMP) && !(MenuInfo->dwStyle & MNS_NOCHECK))
1809 bmpRect.left += check_bitmap_width + 2;
1810 if (!(checked && (MenuInfo->dwStyle & MNS_CHECKORBMP)))
1811 {
1812 //POINT origorg;
1813 bmpRect.right = bmpRect.left + lpitem->maxBmpSize.cx;
1814 /* some applications make this assumption on the DC's origin */
1815 //SetViewportOrgEx( hdc, rect.left, rect.top, &origorg);
1816 MenuDrawBitmapItem(hdc, lpitem, &bmpRect, MenuInfo, WndOwner, odaction, menuBar);
1817 //SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
1818 }
1819 }
1820 /* Draw the popup-menu arrow */
1821 if (lpitem->hSubMenu)
1822 {
1823 /* RECT rectTemp;
1824 CopyRect(&rectTemp, &rect);
1825 rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK);
1826 DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW);
1827 */
1828 draw_popup_arrow( hdc, rect, arrow_bitmap_width, arrow_bitmap_height);
1829 }
1830 rect.left += 4;
1831 if( !(MenuInfo->dwStyle & MNS_NOCHECK))
1832 rect.left += check_bitmap_width;
1833 rect.right -= arrow_bitmap_width;//check_bitmap_width;
1834 }
1835 else if( lpitem->hbmpItem)
1836 { /* Draw the bitmap */
1837 //POINT origorg;
1838
1839 //SetViewportOrgEx( hdc, rect.left, rect.top, &origorg);
1840 MenuDrawBitmapItem(hdc, lpitem, &rect, MenuInfo, WndOwner, odaction, menuBar);
1841 //SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
1842 }
1843
1844 /* process text if present */
1845 if (lpitem->lpstr)
1846 {
1847 register int i = 0;
1848 HFONT hfontOld = 0;
1849 UINT uFormat = menuBar ?
1850 DT_CENTER | DT_VCENTER | DT_SINGLELINE :
1851 DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1852
1853 if((MenuInfo->dwStyle & MNS_CHECKORBMP))
1854 rect.left += max(0, (int)(MenuInfo->cxTextAlign - GetSystemMetrics(SM_CXMENUCHECK)));
1855 else
1856 rect.left += MenuInfo->cxTextAlign;
1857
1858 if ( lpitem->fState & MFS_DEFAULT )
1859 {
1860 hfontOld = SelectObject(hdc, hMenuFontBold);
1861 }
1862
1863 if (menuBar) {
1864 rect.left += MENU_BAR_ITEMS_SPACE / 2;
1865 rect.right -= MENU_BAR_ITEMS_SPACE / 2;
1866 }
1867
1868 Text = lpitem->lpstr;
1869 if(Text)
1870 {
1871 for (i = 0; L'\0' != Text[i]; i++)
1872 if (Text[i] == L'\t' || Text[i] == L'\b')
1873 break;
1874 }
1875
1876 if(lpitem->fState & MF_GRAYED)
1877 {
1878 if (!(lpitem->fState & MF_HILITE) )
1879 {
1880 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1881 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1882 DrawTextW( hdc, Text, i, &rect, uFormat );
1883 --rect.left; --rect.top; --rect.right; --rect.bottom;
1884 }
1885 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1886 }
1887
1888 DrawTextW( hdc, Text, i, &rect, uFormat);
1889
1890 /* paint the shortcut text */
1891 if (!menuBar && L'\0' != Text[i]) /* There's a tab or flush-right char */
1892 {
1893 if (L'\t' == Text[i])
1894 {
1895 rect.left = lpitem->dxTab;
1896 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1897 }
1898 else
1899 {
1900 rect.right = lpitem->dxTab;
1901 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
1902 }
1903
1904 if (lpitem->fState & MF_GRAYED)
1905 {
1906 if (!(lpitem->fState & MF_HILITE) )
1907 {
1908 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1909 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1910 DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat);
1911 --rect.left; --rect.top; --rect.right; --rect.bottom;
1912 }
1913 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1914 }
1915 DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat );
1916 }
1917
1918 if (hfontOld)
1919 SelectObject (hdc, hfontOld);
1920 }
1921 }
1922
1923 /***********************************************************************
1924 * MenuDrawPopupMenu
1925 *
1926 * Paint a popup menu.
1927 */
1928 static void FASTCALL MenuDrawPopupMenu(HWND hwnd, HDC hdc, HMENU hmenu )
1929 {
1930 HBRUSH hPrevBrush = 0;
1931 RECT rect;
1932
1933 TRACE("wnd=%p dc=%p menu=%p\n", hwnd, hdc, hmenu);
1934
1935 GetClientRect( hwnd, &rect );
1936
1937 if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) ))
1938 && (SelectObject( hdc, hMenuFont)))
1939 {
1940 HPEN hPrevPen;
1941
1942 Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
1943
1944 hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
1945 if ( hPrevPen )
1946 {
1947 BOOL flat_menu = FALSE;
1948 ROSMENUINFO MenuInfo;
1949 ROSMENUITEMINFO ItemInfo;
1950
1951 SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
1952 if (flat_menu)
1953 FrameRect(hdc, &rect, GetSysColorBrush(COLOR_BTNSHADOW));
1954 else
1955 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
1956
1957 //TRACE("hmenu %p Style %08x\n", hmenu, menu->dwStyle);
1958 /* draw menu items */
1959 if (MenuGetRosMenuInfo(&MenuInfo, hmenu) && MenuInfo.cItems)
1960 {
1961 UINT u;
1962 MenuInitRosMenuItemInfo(&ItemInfo);
1963
1964 for (u = 0; u < MenuInfo.cItems; u++)
1965 {
1966 if (MenuGetRosMenuItemInfo(MenuInfo.Self, u, &ItemInfo))
1967 {
1968 HWND WndOwner = MenuInfo.spwndNotify ? MenuInfo.spwndNotify->head.h : NULL;
1969 MenuDrawMenuItem(hwnd, &MenuInfo, WndOwner, hdc, &ItemInfo,
1970 MenuInfo.cyMenu, FALSE, ODA_DRAWENTIRE);
1971 }
1972 }
1973 /* draw scroll arrows */
1974 if (MenuInfo.dwArrowsOn)
1975 MENU_DrawScrollArrows(&MenuInfo, hdc);
1976
1977 MenuSetRosMenuInfo(&MenuInfo);
1978 MenuCleanupRosMenuItemInfo(&ItemInfo);
1979 }
1980 } else
1981 {
1982 SelectObject( hdc, hPrevBrush );
1983 }
1984 }
1985 }
1986
1987 /***********************************************************************
1988 * MenuDrawMenuBar
1989 *
1990 * Paint a menu bar. Returns the height of the menu bar.
1991 * called from [windows/nonclient.c]
1992 */
1993 UINT MenuDrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
1994 BOOL suppress_draw)
1995 {
1996 ROSMENUINFO lppop;
1997 HFONT hfontOld = 0;
1998 HMENU hMenu = GetMenu(hwnd);
1999
2000 if (! MenuGetRosMenuInfo(&lppop, hMenu) || lprect == NULL)
2001 {
2002 return GetSystemMetrics(SM_CYMENU);
2003 }
2004
2005 if (suppress_draw)
2006 {
2007 hfontOld = SelectObject(hDC, hMenuFont);
2008
2009 MenuMenuBarCalcSize(hDC, lprect, &lppop, hwnd);
2010
2011 lprect->bottom = lprect->top + lppop.cyMenu;
2012
2013 if (hfontOld) SelectObject( hDC, hfontOld);
2014 return lppop.cyMenu;
2015 }
2016 else
2017 return DrawMenuBarTemp(hwnd, hDC, lprect, hMenu, NULL);
2018 }
2019
2020 /***********************************************************************
2021 * MENU_InitPopup
2022 *
2023 * Popup menu initialization before WM_ENTERMENULOOP.
2024 */
2025 static BOOL MENU_InitPopup( HWND hwndOwner, HMENU hmenu, UINT flags )
2026 {
2027 MENU *menu;
2028 DWORD ex_style = 0;
2029 ROSMENUINFO MenuInfo;
2030
2031 TRACE("owner=%p hmenu=%p\n", hwndOwner, hmenu);
2032
2033 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
2034
2035 /* store the owner for DrawItem */
2036 if (!IsWindow( hwndOwner ))
2037 {
2038 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2039 return FALSE;
2040 }
2041 MenuGetRosMenuInfo(&MenuInfo, menu->head.h);
2042 //menu->hwndOwner = hwndOwner;
2043 MenuInfo.spwndNotify = ValidateHwndNoErr( hwndOwner );
2044
2045 if (flags & TPM_LAYOUTRTL)
2046 ex_style = WS_EX_LAYOUTRTL;
2047
2048 /* NOTE: In Windows, top menu popup is not owned. */
2049 //menu->hWnd = CreateWindowExW( ex_style, WC_MENU, NULL,
2050 MenuInfo.Wnd = CreateWindowExW( ex_style, WC_MENU, NULL,
2051 WS_POPUP, 0, 0, 0, 0,
2052 hwndOwner, 0, (HINSTANCE)GetWindowLongPtrW(hwndOwner, GWLP_HINSTANCE),
2053 (LPVOID)hmenu );
2054 MenuSetRosMenuInfo(&MenuInfo);
2055 if( !menu->hWnd ) return FALSE;
2056 return TRUE;
2057 }
2058
2059 /***********************************************************************
2060 * MenuShowPopup
2061 *
2062 * Display a popup menu.
2063 */
2064 static BOOL FASTCALL MenuShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, UINT flags,
2065 INT x, INT y, INT xanchor, INT yanchor )
2066 {
2067 ROSMENUINFO MenuInfo;
2068 ROSMENUITEMINFO ItemInfo;
2069 UINT width, height;
2070 POINT pt;
2071 HMONITOR monitor;
2072 MONITORINFO info;
2073
2074 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
2075 hwndOwner, hmenu, id, x, y, xanchor, yanchor);
2076
2077 if (! MenuGetRosMenuInfo(&MenuInfo, hmenu)) return FALSE;
2078 if (MenuInfo.iItem != NO_SELECTED_ITEM)
2079 {
2080 MenuInitRosMenuItemInfo(&ItemInfo);
2081 if (MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.iItem, &ItemInfo))
2082 {
2083 ItemInfo.fMask |= MIIM_STATE;
2084 ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT);
2085 MenuSetRosMenuItemInfo(MenuInfo.Self, MenuInfo.iItem, &ItemInfo);
2086 }
2087 MenuCleanupRosMenuItemInfo(&ItemInfo);
2088 MenuInfo.iItem = NO_SELECTED_ITEM;
2089 }
2090
2091 //menu->dwArrowsOn = 0;
2092 MenuInfo.dwArrowsOn = 0;
2093 MenuSetRosMenuInfo(&MenuInfo);
2094 MenuPopupMenuCalcSize(&MenuInfo, hwndOwner);
2095
2096 /* adjust popup menu pos so that it fits within the desktop */
2097
2098 width = MenuInfo.cxMenu + GetSystemMetrics(SM_CXBORDER);
2099 height = MenuInfo.cyMenu + GetSystemMetrics(SM_CYBORDER);
2100
2101 /* FIXME: should use item rect */
2102 pt.x = x;
2103 pt.y = y;
2104 monitor = MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST );
2105 info.cbSize = sizeof(info);
2106 GetMonitorInfoW( monitor, &info );
2107
2108 if (flags & TPM_LAYOUTRTL)
2109 flags ^= TPM_RIGHTALIGN;
2110
2111 if( flags & TPM_RIGHTALIGN ) x -= width;
2112 if( flags & TPM_CENTERALIGN ) x -= width / 2;
2113
2114 if( flags & TPM_BOTTOMALIGN ) y -= height;
2115 if( flags & TPM_VCENTERALIGN ) y -= height / 2;
2116
2117 if( x + width > info.rcMonitor.right)
2118 {
2119 if( xanchor && x >= width - xanchor )
2120 x -= width - xanchor;
2121
2122 if( x + width > info.rcMonitor.right)
2123 x = info.rcMonitor.right - width;
2124 }
2125 if( x < info.rcMonitor.left ) x = info.rcMonitor.left;
2126
2127 if( y + height > info.rcMonitor.bottom)
2128 {
2129 if( yanchor && y >= height + yanchor )
2130 y -= height + yanchor;
2131
2132 if( y + height > info.rcMonitor.bottom)
2133 y = info.rcMonitor.bottom - height;
2134 }
2135 if( y < info.rcMonitor.top ) y = info.rcMonitor.top;
2136
2137 if (!top_popup) {
2138 top_popup = MenuInfo.Wnd;
2139 top_popup_hmenu = hmenu;
2140 }
2141 /* Display the window */
2142
2143 SetWindowPos( MenuInfo.Wnd, HWND_TOPMOST, x, y, width, height,
2144 SWP_SHOWWINDOW | SWP_NOACTIVATE);
2145 UpdateWindow( MenuInfo.Wnd );
2146
2147 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART, MenuInfo.Wnd, OBJID_CLIENT, CHILDID_SELF, 0);
2148
2149 return TRUE;
2150 }
2151
2152 /***********************************************************************
2153 * MENU_EnsureMenuItemVisible
2154 */
2155 void
2156 MENU_EnsureMenuItemVisible(PROSMENUINFO lppop, PROSMENUITEMINFO item, HDC hdc)
2157 {
2158 if (lppop->dwArrowsOn)
2159 {
2160 //ITEM *item = &lppop->items[wIndex];
2161 UINT nMaxHeight = MENU_GetMaxPopupHeight(lppop);
2162 UINT nOldPos = lppop->iTop;
2163 RECT rc;
2164 UINT arrow_bitmap_height;
2165 BITMAP bmp;
2166
2167 GetClientRect(lppop->Wnd, &rc);
2168
2169 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp), &bmp);
2170 arrow_bitmap_height = bmp.bmHeight;
2171
2172 rc.top += arrow_bitmap_height;
2173 rc.bottom -= arrow_bitmap_height + MENU_BOTTOM_MARGIN;
2174
2175 nMaxHeight -= GetSystemMetrics(SM_CYBORDER) + 2 * arrow_bitmap_height;
2176 if (item->Rect.bottom > lppop->iTop + nMaxHeight)
2177 {
2178 lppop->iTop = item->Rect.bottom - nMaxHeight;
2179 ScrollWindow(lppop->Wnd, 0, nOldPos - lppop->iTop, &rc, &rc);
2180 MENU_DrawScrollArrows(lppop, hdc);
2181 }
2182 else if (item->Rect.top - MENU_TOP_MARGIN < lppop->iTop)
2183 {
2184 lppop->iTop = item->Rect.top - MENU_TOP_MARGIN;
2185 ScrollWindow(lppop->Wnd, 0, nOldPos - lppop->iTop, &rc, &rc);
2186 MENU_DrawScrollArrows(lppop, hdc);
2187 }
2188 }
2189 }
2190
2191 /***********************************************************************
2192 * MenuSelectItem
2193 */
2194 static void FASTCALL MenuSelectItem(HWND hwndOwner, PROSMENUINFO hmenu, UINT wIndex,
2195 BOOL sendMenuSelect, HMENU topmenu)
2196 {
2197 ROSMENUITEMINFO ItemInfo;
2198 ROSMENUINFO TopMenuInfo;
2199 HDC hdc;
2200
2201 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
2202
2203 if (!hmenu || !hmenu->cItems || !hmenu->Wnd) return;
2204 if (hmenu->iItem == wIndex) return;
2205 if (hmenu->fFlags & MNF_POPUP) hdc = GetDC(hmenu->Wnd);
2206 else hdc = GetDCEx(hmenu->Wnd, 0, DCX_CACHE | DCX_WINDOW);
2207 if (!top_popup) {
2208 top_popup = hmenu->Wnd;
2209 top_popup_hmenu = hmenu->Self;
2210 }
2211
2212 SelectObject( hdc, hMenuFont );
2213
2214 MenuInitRosMenuItemInfo(&ItemInfo);
2215
2216 /* Clear previous highlighted item */
2217 if (hmenu->iItem != NO_SELECTED_ITEM)
2218 {
2219 if (MenuGetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo))
2220 {
2221 ItemInfo.fMask |= MIIM_STATE;
2222 ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT);
2223 MenuSetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo);
2224 }
2225 MenuDrawMenuItem(hmenu->Wnd, hmenu, hwndOwner, hdc, &ItemInfo,
2226 hmenu->cyMenu, !(hmenu->fFlags & MNF_POPUP),
2227 ODA_SELECT);
2228 }
2229
2230 /* Highlight new item (if any) */
2231 hmenu->iItem = wIndex;
2232 MenuSetRosMenuInfo(hmenu);
2233 if (hmenu->iItem != NO_SELECTED_ITEM)
2234 {
2235 if (MenuGetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo))
2236 {
2237 if (!(ItemInfo.fType & MF_SEPARATOR))
2238 {
2239 ItemInfo.fMask |= MIIM_STATE;
2240 ItemInfo.fState |= MF_HILITE;
2241 MenuSetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo);
2242 MENU_EnsureMenuItemVisible(hmenu, &ItemInfo, hdc);
2243 MenuDrawMenuItem(hmenu->Wnd, hmenu, hwndOwner, hdc,
2244 &ItemInfo, hmenu->cyMenu, !(hmenu->fFlags & MNF_POPUP), ODA_SELECT);
2245 }
2246 if (sendMenuSelect)
2247 {
2248 WPARAM wParam = MAKEWPARAM( ItemInfo.hSubMenu ? wIndex : ItemInfo.wID,
2249 ItemInfo.fType | ItemInfo.fState |
2250 (ItemInfo.hSubMenu ? MF_POPUP : 0) |
2251 (hmenu->fFlags & MNF_SYSDESKMN ? MF_SYSMENU : 0 ) );
2252
2253 SendMessageW(hwndOwner, WM_MENUSELECT, wParam, (LPARAM) hmenu->Self);
2254 }
2255 }
2256 }
2257 else if (sendMenuSelect)
2258 {
2259 if(topmenu)
2260 {
2261 int pos;
2262 pos = MenuFindSubMenu(&topmenu, hmenu->Self);
2263 if (pos != NO_SELECTED_ITEM)
2264 {
2265 if (MenuGetRosMenuInfo(&TopMenuInfo, topmenu)
2266 && MenuGetRosMenuItemInfo(topmenu, pos, &ItemInfo))
2267 {
2268 WPARAM wParam = MAKEWPARAM( Pos, ItemInfo.fType | ItemInfo.fState |
2269 (ItemInfo.hSubMenu ? MF_POPUP : 0) |
2270 (TopMenuInfo.fFlags & MNF_SYSDESKMN ? MF_SYSMENU : 0 ) );
2271
2272 SendMessageW(hwndOwner, WM_MENUSELECT, wParam, (LPARAM) topmenu);
2273 }
2274 }
2275 }
2276 }
2277 MenuCleanupRosMenuItemInfo(&ItemInfo);
2278 ReleaseDC(hmenu->Wnd, hdc);
2279 }
2280
2281 /***********************************************************************
2282 * MenuMoveSelection
2283 *
2284 * Moves currently selected item according to the Offset parameter.
2285 * If there is no selection then it should select the last item if
2286 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
2287 */
2288 static void FASTCALL
2289 MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset)
2290 {
2291 INT i;
2292 ROSMENUITEMINFO ItemInfo;
2293 INT OrigPos;
2294
2295 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner, MenuInfo, Offset);
2296
2297 /* Prevent looping */
2298 if (0 == MenuInfo->cItems || 0 == Offset)
2299 return;
2300 else if (Offset < -1)
2301 Offset = -1;
2302 else if (Offset > 1)
2303 Offset = 1;
2304
2305 MenuInitRosMenuItemInfo(&ItemInfo);
2306
2307 OrigPos = MenuInfo->iItem;
2308 if (OrigPos == NO_SELECTED_ITEM) /* NO_SELECTED_ITEM is not -1 ! */
2309 {
2310 OrigPos = 0;
2311 i = -1;
2312 }
2313 else
2314 {
2315 i = MenuInfo->iItem;
2316 }
2317
2318 do
2319 {
2320 /* Step */
2321 i += Offset;
2322 /* Clip and wrap around */
2323 if (i < 0)
2324 {
2325 i = MenuInfo->cItems - 1;
2326 }
2327 else if (i >= MenuInfo->cItems)
2328 {
2329 i = 0;
2330 }
2331 /* If this is a good candidate; */
2332 if (MenuGetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo) &&
2333 0 == (ItemInfo.fType & MF_SEPARATOR))
2334 {
2335 MenuSelectItem(WndOwner, MenuInfo, i, TRUE, NULL);
2336 MenuCleanupRosMenuItemInfo(&ItemInfo);
2337 return;
2338 }
2339 } while (i != OrigPos);
2340
2341 /* Not found */
2342 MenuCleanupRosMenuItemInfo(&ItemInfo);
2343 }
2344
2345 #if 0
2346 LRESULT WINAPI
2347 PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
2348 {
2349 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
2350 PWND pWnd;
2351 PPOPUPMENU pPopupMenu;
2352
2353 pWnd = ValidateHwndNoErr(Wnd);
2354 if (pWnd)
2355 {
2356 if (!pWnd->fnid)
2357 {
2358 if (Message != WM_NCCREATE)
2359 {
2360 return DefWindowProcW(Wnd, Message, wParam, lParam);
2361 }
2362 NtUserSetWindowFNID(Wnd, FNID_MENU);
2363 pPopupMenu = HeapAlloc( GetProcessHeap(), 0, sizeof(POPUPMENU) );
2364 pPopupMenu->spwndPopupMenu = pWnd;
2365 SetWindowLongPtrW(Wnd, 0, (LONG_PTR)pPopupMenu);
2366 }
2367 else
2368 {
2369 if (pWnd->fnid != FNID_MENU)
2370 {
2371 ERR("Wrong window class for Menu!\n");
2372 return 0;
2373 }
2374 pPopupMenu = ((PMENUWND)pWnd)->ppopupmenu;
2375 }
2376 }
2377 #endif
2378
2379 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
2380
2381 switch(Message)
2382 {
2383 case WM_CREATE:
2384 {
2385 CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
2386 pPopupMenu->spmenu = ValidateHandle(cs->lpCreateParams, TYPE_MENU);
2387 return 0;
2388 }
2389
2390 case WM_MOUSEACTIVATE: /* We don't want to be activated */
2391 return MA_NOACTIVATE;
2392
2393 case WM_PAINT:
2394 {
2395 PAINTSTRUCT ps;
2396 BeginPaint(Wnd, &ps);
2397 MenuDrawPopupMenu(Wnd, ps.hdc, pPopupMenu->spmenu->head.h);
2398 EndPaint(Wnd, &ps);
2399 return 0;
2400 }
2401
2402 case WM_PRINTCLIENT:
2403 {
2404 MenuDrawPopupMenu( Wnd, (HDC)wParam, pPopupMenu->spmenu->head.h);
2405 return 0;
2406 }
2407
2408 case WM_ERASEBKGND:
2409 return 1;
2410
2411 case WM_DESTROY:
2412 /* zero out global pointer in case resident popup window was destroyed. */
2413 if (Wnd == top_popup)
2414 {
2415 top_popup = NULL;
2416 top_popup_hmenu = NULL;
2417 }
2418 break;
2419
2420 case WM_NCDESTROY:
2421 {
2422 HeapFree( GetProcessHeap(), 0, pPopupMenu );
2423 SetWindowLongPtrW(Wnd, 0, 0);
2424 NtUserSetWindowFNID(Wnd, FNID_DESTROY);
2425 break;
2426 }
2427
2428 case WM_SHOWWINDOW:
2429 if (0 != wParam)
2430 {
2431 if (!pPopupMenu || !pPopupMenu->spmenu)
2432 {
2433 OutputDebugStringA("no menu to display\n");
2434 }
2435 }
2436 /*else
2437 {
2438 pPopupMenu->spmenu = NULL; ///// WTF?
2439 }*/
2440 break;
2441
2442 case MM_SETMENUHANDLE:
2443 {
2444 PMENU pmenu = ValidateHandle((HMENU)wParam, TYPE_MENU);
2445 if (!pmenu)
2446 {
2447 ERR("Bad Menu Handle\n");
2448 break;
2449 }
2450 pPopupMenu->spmenu = pmenu;
2451 break;
2452 }
2453
2454 case MM_GETMENUHANDLE:
2455 case MN_GETHMENU:
2456 return (LRESULT)(pPopupMenu ? (pPopupMenu->spmenu ? pPopupMenu->spmenu->head.h : NULL) : NULL);
2457
2458 default:
2459 return DefWindowProcW(Wnd, Message, wParam, lParam);
2460 }
2461
2462 return 0;
2463 }
2464 #endif
2465
2466 LRESULT WINAPI
2467 PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
2468 {
2469 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
2470 PWND pWnd;
2471
2472 pWnd = ValidateHwnd(Wnd);
2473 if (pWnd)
2474 {
2475 if (!pWnd->fnid)
2476 {
2477 if (Message != WM_NCCREATE)
2478 {
2479 return DefWindowProcW(Wnd, Message, wParam, lParam);
2480 }
2481 NtUserSetWindowFNID(Wnd, FNID_MENU);
2482 }
2483 else
2484 {
2485 if (pWnd->fnid != FNID_MENU)
2486 {
2487 ERR("Wrong window class for Menu!\n");
2488 return 0;
2489 }
2490 }
2491 }
2492 #endif
2493
2494 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
2495
2496 switch(Message)
2497 {
2498 case WM_CREATE:
2499 {
2500 CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
2501 SetWindowLongPtrW(Wnd, 0, (LONG_PTR)cs->lpCreateParams);
2502 return 0;
2503 }
2504
2505 case WM_MOUSEACTIVATE: /* We don't want to be activated */
2506 return MA_NOACTIVATE;
2507
2508 case WM_PAINT:
2509 {
2510 PAINTSTRUCT ps;
2511 BeginPaint(Wnd, &ps);
2512 MenuDrawPopupMenu(Wnd, ps.hdc, (HMENU)GetWindowLongPtrW(Wnd, 0));
2513 EndPaint(Wnd, &ps);
2514 return 0;
2515 }
2516
2517 case WM_PRINTCLIENT:
2518 {
2519 MenuDrawPopupMenu( Wnd, (HDC)wParam,
2520 (HMENU)GetWindowLongPtrW( Wnd, 0 ) );
2521 return 0;
2522 }
2523
2524 case WM_ERASEBKGND:
2525 return 1;
2526
2527 case WM_DESTROY:
2528 /* zero out global pointer in case resident popup window was destroyed. */
2529 if (Wnd == top_popup)
2530 {
2531 top_popup = NULL;
2532 top_popup_hmenu = NULL;
2533 }
2534 break;
2535
2536 #ifdef __REACTOS__
2537 case WM_NCDESTROY:
2538 NtUserSetWindowFNID(Wnd, FNID_DESTROY);
2539 break;
2540 #endif
2541
2542 case WM_SHOWWINDOW:
2543 if (0 != wParam)
2544 {
2545 if (0 == GetWindowLongPtrW(Wnd, 0))
2546 {
2547 OutputDebugStringA("no menu to display\n");
2548 }
2549 }
2550 else
2551 {
2552 SetWindowLongPtrW(Wnd, 0, 0);
2553 }
2554 break;
2555
2556 case MM_SETMENUHANDLE:
2557 SetWindowLongPtrW(Wnd, 0, wParam);
2558 break;
2559
2560 case MM_GETMENUHANDLE:
2561 case MN_GETHMENU:
2562 return GetWindowLongPtrW(Wnd, 0);
2563
2564 default:
2565 return DefWindowProcW(Wnd, Message, wParam, lParam);
2566 }
2567
2568 return 0;
2569 }
2570
2571 //
2572 // This breaks some test results. Should handle A2U if called!
2573 //
2574 LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
2575 {
2576 PWND pWnd;
2577
2578 pWnd = ValidateHwnd(Wnd);
2579 if (pWnd && !pWnd->fnid && Message != WM_NCCREATE)
2580 {
2581 return DefWindowProcA(Wnd, Message, wParam, lParam);
2582 }
2583 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
2584
2585 switch(Message)
2586 {
2587 case WM_NCCREATE:
2588 case WM_CREATE:
2589 case WM_MOUSEACTIVATE:
2590 case WM_PAINT:
2591 case WM_PRINTCLIENT:
2592 case WM_ERASEBKGND:
2593 case WM_DESTROY:
2594 case WM_NCDESTROY:
2595 case WM_SHOWWINDOW:
2596 case MM_SETMENUHANDLE:
2597 case MM_GETMENUHANDLE:
2598 case MN_GETHMENU:
2599 return PopupMenuWndProcW(Wnd, Message, wParam, lParam);
2600
2601 default:
2602 return DefWindowProcA(Wnd, Message, wParam, lParam);
2603 }
2604 return 0;
2605 }
2606
2607 /**********************************************************************
2608 * MENU_ParseResource
2609 *
2610 * Parse a standard menu resource and add items to the menu.
2611 * Return a pointer to the end of the resource.
2612 *
2613 * NOTE: flags is equivalent to the mtOption field
2614 */
2615 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu)
2616 {
2617 WORD flags, id = 0;
2618 HMENU hSubMenu;
2619 LPCWSTR str;
2620 BOOL end = FALSE;
2621
2622 do
2623 {
2624 flags = GET_WORD(res);
2625
2626 /* remove MF_END flag before passing it to AppendMenu()! */
2627 end = (flags & MF_END);
2628 if(end) flags ^= MF_END;
2629
2630 res += sizeof(WORD);
2631 if(!(flags & MF_POPUP))
2632 {
2633 id = GET_WORD(res);
2634 res += sizeof(WORD);
2635 }
2636 str = (LPCWSTR)res;
2637 res += (strlenW(str) + 1) * sizeof(WCHAR);
2638
2639 if (flags & MF_POPUP)
2640 {
2641 hSubMenu = CreatePopupMenu();
2642 if(!hSubMenu) return NULL;
2643 if(!(res = MENU_ParseResource(res, hSubMenu))) return NULL;
2644 AppendMenuW(hMenu, flags, (UINT_PTR)hSubMenu, (LPCWSTR)str);
2645 }
2646 else /* Not a popup */
2647 {
2648 AppendMenuW(hMenu, flags, id, *(LPCWSTR)str ? (LPCWSTR)str : NULL);
2649 }
2650 } while(!end);
2651 return res;
2652 }
2653
2654 /**********************************************************************
2655 * MENUEX_ParseResource
2656 *
2657 * Parse an extended menu resource and add items to the menu.
2658 * Return a pointer to the end of the resource.
2659 */
2660 static LPCSTR MENUEX_ParseResource(LPCSTR res, HMENU hMenu)
2661 {
2662 WORD resinfo;
2663 do
2664 {
2665 MENUITEMINFOW mii;
2666
2667 mii.cbSize = sizeof(mii);
2668 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
2669 mii.fType = GET_DWORD(res);
2670 res += sizeof(DWORD);
2671 mii.fState = GET_DWORD(res);
2672 res += sizeof(DWORD);
2673 mii.wID = GET_DWORD(res);
2674 res += sizeof(DWORD);
2675 resinfo = GET_WORD(res);
2676 res += sizeof(WORD);
2677 /* Align the text on a word boundary. */
2678 res += (~((UINT_PTR)res - 1)) & 1;
2679 mii.dwTypeData = (LPWSTR)res;
2680 mii.cch = strlenW(mii.dwTypeData);
2681 res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
2682 /* Align the following fields on a dword boundary. */
2683 res += (~((UINT_PTR)res - 1)) & 3;
2684
2685 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
2686 mii.fType, mii.fState, mii.wID, resinfo, mii.dwTypeData);
2687
2688 if (resinfo & 1) /* Pop-up? */
2689 {
2690 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2691 res += sizeof(DWORD);
2692 mii.hSubMenu = CreatePopupMenu();
2693 if (!mii.hSubMenu)
2694 {
2695 ERR("CreatePopupMenu failed\n");
2696 return NULL;
2697 }
2698
2699 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu)))
2700 {
2701 ERR("MENUEX_ParseResource failed\n");
2702 DestroyMenu(mii.hSubMenu);
2703 return NULL;
2704 }
2705 mii.fMask |= MIIM_SUBMENU;
2706 }
2707 else if (!mii.dwTypeData[0] && !(mii.fType & MF_SEPARATOR))
2708 {
2709 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
2710 mii.wID, mii.fType);
2711 mii.fType |= MF_SEPARATOR;
2712 }
2713 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
2714 } while (!(resinfo & MF_END));
2715 return res;
2716 }
2717
2718
2719 /***********************************************************************
2720 * DrawMenuBarTemp (USER32.@)
2721 *
2722 * UNDOCUMENTED !!
2723 *
2724 * called by W98SE desk.cpl Control Panel Applet
2725 *
2726 * Not 100% sure about the param names, but close.
2727 *
2728 * @implemented
2729 */
2730 DWORD WINAPI
2731 DrawMenuBarTemp(HWND Wnd, HDC DC, LPRECT Rect, HMENU Menu, HFONT Font)
2732 {
2733 ROSMENUINFO MenuInfo;
2734 ROSMENUITEMINFO ItemInfo;
2735 UINT i;
2736 HFONT FontOld = NULL;
2737 BOOL flat_menu = FALSE;
2738
2739 SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
2740
2741 if (NULL == Menu)
2742 {
2743 Menu = GetMenu(Wnd);
2744 }
2745
2746 if (NULL == Font)
2747 {
2748 Font = hMenuFont;
2749 }
2750
2751 if (NULL == Rect || ! MenuGetRosMenuInfo(&MenuInfo, Menu))
2752 {
2753 return GetSystemMetrics(SM_CYMENU);
2754 }
2755
2756 TRACE("(%x, %x, %p, %x, %x)\n", Wnd, DC, Rect, Menu, Font);
2757
2758 FontOld = SelectObject(DC, Font);
2759
2760 if (0 == MenuInfo.cyMenu)
2761 {
2762 MenuMenuBarCalcSize(DC, Rect, &MenuInfo, Wnd);
2763 }
2764
2765 Rect->bottom = Rect->top + MenuInfo.cyMenu;
2766
2767 FillRect(DC, Rect, GetSysColorBrush(flat_menu ? COLOR_MENUBAR : COLOR_MENU));
2768
2769 SelectObject(DC, GetStockObject(DC_PEN));
2770 SetDCPenColor(DC, GetSysColor(COLOR_3DFACE));
2771 MoveToEx(DC, Rect->left, Rect->bottom - 1, NULL);
2772 LineTo(DC, Rect->right, Rect->bottom - 1);
2773
2774 if (0 == MenuInfo.cItems)
2775 {
2776 SelectObject(DC, FontOld);
2777 return GetSystemMetrics(SM_CYMENU);
2778 }
2779
2780 MenuInitRosMenuItemInfo(&ItemInfo);
2781 for (i = 0; i < MenuInfo.cItems; i++)
2782 {
2783 if (MenuGetRosMenuItemInfo(MenuInfo.Self, i, &ItemInfo))
2784 {
2785 MenuDrawMenuItem(Wnd, &MenuInfo, Wnd, DC, &ItemInfo,
2786 MenuInfo.cyMenu, TRUE, ODA_DRAWENTIRE);
2787 }
2788 }
2789 MenuCleanupRosMenuItemInfo(&ItemInfo);
2790
2791 SelectObject(DC, FontOld);
2792
2793 return MenuInfo.cyMenu;
2794 }
2795
2796
2797 /***********************************************************************
2798 * MenuShowSubPopup
2799 *
2800 * Display the sub-menu of the selected item of this menu.
2801 * Return the handle of the submenu, or menu if no submenu to display.
2802 */
2803 static HMENU FASTCALL
2804 MenuShowSubPopup(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SelectFirst, UINT Flags)
2805 {
2806 RECT Rect;
2807 ROSMENUITEMINFO ItemInfo;
2808 ROSMENUINFO SubMenuInfo;
2809 HDC Dc;
2810 HMENU Ret;
2811
2812 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner, MenuInfo, SelectFirst);
2813
2814 if (MenuInfo->iItem == NO_SELECTED_ITEM) return MenuInfo->Self;
2815
2816 MenuInitRosMenuItemInfo(&ItemInfo);
2817 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo))
2818 {
2819 MenuCleanupRosMenuItemInfo(&ItemInfo);
2820 return MenuInfo->Self;
2821 }
2822
2823 //item = &menu->rgItems[menu->iItem];
2824 if (!(ItemInfo.hSubMenu) || (ItemInfo.fState & (MF_GRAYED | MF_DISABLED)))
2825 {
2826 MenuCleanupRosMenuItemInfo(&ItemInfo);
2827 return MenuInfo->Self;
2828 }
2829
2830 /* message must be sent before using item,
2831 because nearly everything may be changed by the application ! */
2832
2833 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2834 if (!(Flags & TPM_NONOTIFY))
2835 {
2836 SendMessageW(WndOwner, WM_INITMENUPOPUP, (WPARAM) ItemInfo.hSubMenu,
2837 MAKELPARAM(MenuInfo->iItem, IS_SYSTEM_MENU(MenuInfo)));
2838 }
2839
2840 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo))
2841 {
2842 MenuCleanupRosMenuItemInfo(&ItemInfo);
2843 return MenuInfo->Self;
2844 }
2845
2846 //item = &menu->rgItems[menu->iItem];
2847 Rect = ItemInfo.Rect;
2848
2849 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2850 if (!(ItemInfo.fState & MF_HILITE))
2851 {
2852 if (MenuInfo->fFlags & MNF_POPUP) Dc = GetDC(MenuInfo->Wnd);
2853 else Dc = GetDCEx(MenuInfo->Wnd, 0, DCX_CACHE | DCX_WINDOW);
2854
2855 SelectObject(Dc, hMenuFont);
2856 ItemInfo.fMask |= MIIM_STATE;
2857 ItemInfo.fState |= MF_HILITE;
2858 MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo);
2859 MenuDrawMenuItem(MenuInfo->Wnd, MenuInfo, WndOwner, Dc, &ItemInfo, MenuInfo->cyMenu,
2860 !(MenuInfo->fFlags & MNF_POPUP), ODA_DRAWENTIRE);
2861 ReleaseDC(MenuInfo->Wnd, Dc);
2862 }
2863
2864 if (!ItemInfo.Rect.top && !ItemInfo.Rect.left && !ItemInfo.Rect.bottom && !ItemInfo.Rect.right)
2865 ItemInfo.Rect = Rect;
2866
2867 ItemInfo.fMask |= MIIM_STATE;
2868 ItemInfo.fState |= MF_MOUSESELECT;
2869 MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo);
2870
2871 if (IS_SYSTEM_MENU(MenuInfo))
2872 {
2873 MenuInitSysMenuPopup(ItemInfo.hSubMenu,
2874 GetWindowLongPtrW(MenuInfo->Wnd, GWL_STYLE),
2875 GetClassLongPtrW(MenuInfo->Wnd, GCL_STYLE), HTSYSMENU);
2876
2877 NcGetSysPopupPos(MenuInfo->Wnd, &Rect);
2878 if (Flags & TPM_LAYOUTRTL) Rect.left = Rect.right;
2879 Rect.top = Rect.bottom;
2880 Rect.right = GetSystemMetrics(SM_CXSIZE);
2881 Rect.bottom = GetSystemMetrics(SM_CYSIZE);
2882 }
2883 else
2884 {
2885 GetWindowRect(MenuInfo->Wnd, &Rect);
2886 if (MenuInfo->fFlags & MNF_POPUP)
2887 {
2888 RECT rc = ItemInfo.Rect;
2889
2890 MENU_AdjustMenuItemRect(MenuInfo, &rc);
2891
2892 /* The first item in the popup menu has to be at the
2893 same y position as the focused menu item */
2894 if(Flags & TPM_LAYOUTRTL)
2895 Rect.left += GetSystemMetrics(SM_CXBORDER);
2896 else
2897 Rect.left += rc.right /*ItemInfo.Rect.right*/ - GetSystemMetrics(SM_CXBORDER);
2898 Rect.top += rc.top - MENU_TOP_MARGIN;//3;
2899 Rect.right = rc.left - rc.right + GetSystemMetrics(SM_CXBORDER);
2900 Rect.bottom = rc.top - rc.bottom - MENU_TOP_MARGIN - MENU_BOTTOM_MARGIN/*2*/
2901 - GetSystemMetrics(SM_CYBORDER);
2902 }
2903 else
2904 {
2905 if(Flags & TPM_LAYOUTRTL)
2906 Rect.left += Rect.right - ItemInfo.Rect.left;
2907 else
2908 Rect.left += ItemInfo.Rect.left;
2909 Rect.top += ItemInfo.Rect.bottom;
2910 Rect.right = ItemInfo.Rect.right - ItemInfo.Rect.left;
2911 Rect.bottom = ItemInfo.Rect.bottom - ItemInfo.Rect.top;
2912 }
2913 }
2914
2915 /* use default alignment for submenus */
2916 Flags &= ~(TPM_CENTERALIGN | TPM_RIGHTALIGN | TPM_VCENTERALIGN | TPM_BOTTOMALIGN);
2917
2918 MENU_InitPopup( WndOwner, ItemInfo.hSubMenu, Flags );
2919
2920 MenuShowPopup(WndOwner, ItemInfo.hSubMenu, MenuInfo->iItem, Flags,
2921 Rect.left, Rect.top, Rect.right, Rect.bottom );
2922 if (SelectFirst && MenuGetRosMenuInfo(&SubMenuInfo, ItemInfo.hSubMenu))
2923 {
2924 MenuMoveSelection(WndOwner, &SubMenuInfo, ITEM_NEXT);
2925 }
2926
2927 Ret = ItemInfo.hSubMenu;
2928 MenuCleanupRosMenuItemInfo(&ItemInfo);
2929
2930 return Ret;
2931 }
2932
2933 /**********************************************************************
2934 * MENU_EndMenu
2935 *
2936 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2937 *
2938 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2939 */
2940 void MENU_EndMenu( HWND hwnd )
2941 {
2942 MENU *menu;
2943 menu = top_popup_hmenu ? MENU_GetMenu( top_popup_hmenu ) : NULL;
2944 if (menu && ( hwnd == menu->hWnd || hwnd == (menu->spwndNotify ? menu->spwndNotify->head.h : NULL)) )
2945 EndMenu();
2946 }
2947
2948 /***********************************************************************
2949 * MenuHideSubPopups
2950 *
2951 * Hide the sub-popup menus of this menu.
2952 */
2953 static void FASTCALL
2954 MenuHideSubPopups(HWND WndOwner, PROSMENUINFO MenuInfo,
2955 BOOL SendMenuSelect, UINT wFlags)
2956 {
2957 ROSMENUINFO SubMenuInfo;
2958 ROSMENUITEMINFO ItemInfo;
2959
2960 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner, MenuInfo, SendMenuSelect);
2961
2962 if (MenuInfo && top_popup && NO_SELECTED_ITEM != MenuInfo->iItem)
2963 {
2964 //item = &menu->rgItems[menu->iItem];
2965 MenuInitRosMenuItemInfo(&ItemInfo);
2966 ItemInfo.fMask |= MIIM_FTYPE | MIIM_STATE;
2967 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo)
2968 || !(ItemInfo.hSubMenu)
2969 || !(ItemInfo.fState & MF_MOUSESELECT))
2970 {
2971 MenuCleanupRosMenuItemInfo(&ItemInfo);
2972 return;
2973 }
2974 ItemInfo.fState &= ~MF_MOUSESELECT;
2975 ItemInfo.fMask |= MIIM_STATE;
2976 MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo);
2977 if (MenuGetRosMenuInfo(&SubMenuInfo, ItemInfo.hSubMenu))
2978 {
2979 MenuHideSubPopups(WndOwner, &SubMenuInfo, FALSE, wFlags);
2980 MenuSelectItem(WndOwner, &SubMenuInfo, NO_SELECTED_ITEM, SendMenuSelect, NULL);
2981
2982 DestroyWindow(SubMenuInfo.Wnd);
2983 /* Native returns handle to destroyed window */
2984 if (!(wFlags & TPM_NONOTIFY))
2985 SendMessageW( WndOwner, WM_UNINITMENUPOPUP, (WPARAM)ItemInfo.hSubMenu,
2986 MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo)) );
2987 ////
2988 // Call WM_UNINITMENUPOPUP FIRST before destroy!!
2989 // Fixes todo_wine User32 test menu.c line 2233 GetMenuBarInfo callback....
2990 //
2991 SubMenuInfo.Wnd = NULL;
2992 MenuSetRosMenuInfo(&SubMenuInfo);
2993 ////
2994 }
2995 }
2996 }
2997
2998 /***********************************************************************
2999 * MenuSwitchTracking
3000 *
3001 * Helper function for menu navigation routines.
3002 */
3003 static void FASTCALL
3004 MenuSwitchTracking(MTRACKER* Mt, PROSMENUINFO PtMenuInfo, UINT Index, UINT wFlags)
3005 {
3006 ROSMENUINFO TopMenuInfo;
3007
3008 TRACE("%x menu=%x 0x%04x\n", Mt, PtMenuInfo->Self, Index);
3009
3010 if ( MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu) &&
3011 Mt->TopMenu != PtMenuInfo->Self &&
3012 !((PtMenuInfo->fFlags | TopMenuInfo.fFlags) & MNF_POPUP) )
3013 {
3014 /* both are top level menus (system and menu-bar) */
3015 MenuHideSubPopups(Mt->OwnerWnd, &TopMenuInfo, FALSE, wFlags);
3016 MenuSelectItem(Mt->OwnerWnd, &TopMenuInfo, NO_SELECTED_ITEM, FALSE, NULL);
3017 Mt->TopMenu = PtMenuInfo->Self;
3018 }
3019 else
3020 {
3021 MenuHideSubPopups(Mt->OwnerWnd, PtMenuInfo, FALSE, wFlags);
3022 }
3023
3024 MenuSelectItem(Mt->OwnerWnd, PtMenuInfo, Index, TRUE, NULL);
3025 }
3026
3027 /***********************************************************************
3028 * MenuExecFocusedItem
3029 *
3030 * Execute a menu item (for instance when user pressed Enter).
3031 * Return the wID of the executed item. Otherwise, -1 indicating
3032 * that no menu item was executed, -2 if a popup is shown;
3033 * Have to receive the flags for the TrackPopupMenu options to avoid
3034 * sending unwanted message.
3035 *
3036 */
3037 static INT FASTCALL
3038 MenuExecFocusedItem(MTRACKER *Mt, PROSMENUINFO MenuInfo, UINT Flags)
3039 {
3040 ROSMENUITEMINFO ItemInfo;
3041 UINT wID;
3042
3043 TRACE("%p menu=%p\n", Mt, MenuInfo);
3044
3045 if (0 == MenuInfo->cItems || NO_SELECTED_ITEM == MenuInfo->iItem)
3046 {
3047 return -1;
3048 }
3049
3050 MenuInitRosMenuItemInfo(&ItemInfo);
3051 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo))
3052 {
3053 MenuCleanupRosMenuItemInfo(&ItemInfo);
3054 return -1;
3055 }
3056
3057 TRACE("%p %08x %p\n", MenuInfo, ItemInfo.wID, ItemInfo.hSubMenu);
3058
3059 if (0 == (ItemInfo.hSubMenu))
3060<