Sync with trunk r63502.
[reactos.git] / 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_SYSMENU))
74
75 #define IS_SYSTEM_POPUP(MenuInfo) \
76 (0 != ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSMENU))
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_SYSMENU ? 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 {
1261 //ERR("MGMaxPH cyMax %d\n",lppop->cyMax);
1262 return lppop->cyMax;
1263 }
1264 //ERR("MGMaxPH SyMax %d\n",GetSystemMetrics(SM_CYSCREEN) - GetSystemMetrics(SM_CYBORDER));
1265 return GetSystemMetrics(SM_CYSCREEN) - GetSystemMetrics(SM_CYBORDER);
1266 }
1267
1268 /***********************************************************************
1269 * MenuPopupMenuCalcSize
1270 *
1271 * Calculate the size of a popup menu.
1272 */
1273 static void FASTCALL MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo, HWND WndOwner)
1274 {
1275 ROSMENUITEMINFO lpitem;
1276 HDC hdc;
1277 int start, i;
1278 int orgX, orgY, maxX, maxTab, maxTabWidth, maxHeight;
1279 BOOL textandbmp = FALSE;
1280
1281 MenuInfo->cxMenu = MenuInfo->cyMenu = 0;
1282 if (MenuInfo->cItems == 0)
1283 {
1284 MenuSetRosMenuInfo(MenuInfo);
1285 return;
1286 }
1287
1288 hdc = GetDC(NULL);
1289 SelectObject( hdc, hMenuFont );
1290
1291 start = 0;
1292 maxX = 2 + 1;
1293
1294 MenuInfo->cxTextAlign = 0;
1295
1296 MenuInitRosMenuItemInfo(&lpitem);
1297 //MenuGetRosMenuItemInfo(MenuInfo->Self, start, &lpitem);
1298 while (start < MenuInfo->cItems)
1299 {
1300 //lpitem = &lppop->items[start];
1301 orgX = maxX;
1302 //if( lpitem.fType & (MF_MENUBREAK | MF_MENUBARBREAK))
1303 // orgX += MENU_COL_SPACE;
1304 orgY = 2;//MENU_TOP_MARGIN;
1305
1306 maxTab = maxTabWidth = 0;
1307 /* Parse items until column break or end of menu */
1308 for (i = start; i < MenuInfo->cItems; i++)//, lpitem++)
1309 {
1310 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i, &lpitem))
1311 {
1312 MenuCleanupRosMenuItemInfo(&lpitem);
1313 MenuSetRosMenuInfo(MenuInfo);
1314 return;
1315 }
1316 if (i != start &&
1317 (lpitem.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
1318
1319
1320 MenuCalcItemSize(hdc, &lpitem, MenuInfo, WndOwner, orgX, orgY, FALSE, textandbmp);
1321 if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &lpitem))
1322 {
1323 MenuCleanupRosMenuItemInfo(&lpitem);
1324 MenuSetRosMenuInfo(MenuInfo);
1325 return;
1326 }
1327
1328 maxX = max(maxX, lpitem.Rect.right);
1329 orgY = lpitem.Rect.bottom;
1330 if (IS_STRING_ITEM(lpitem.fType) && lpitem.dxTab )
1331 {
1332 maxTab = max( maxTab, lpitem.dxTab );
1333 maxTabWidth = max(maxTabWidth, lpitem.Rect.right - lpitem.dxTab);
1334 }
1335 if( lpitem.lpstr && lpitem.hbmpItem) textandbmp = TRUE;
1336 }
1337
1338 /* Finish the column (set all items to the largest width found) */
1339 maxX = max( maxX, maxTab + maxTabWidth );
1340 while (start < i)
1341 {
1342 if (MenuGetRosMenuItemInfo(MenuInfo->Self, start, &lpitem))
1343 {
1344 lpitem.Rect.right = maxX;
1345 if (IS_STRING_ITEM(lpitem.fType) && lpitem.dxTab)
1346 {
1347 lpitem.dxTab = maxTab;
1348 }
1349 MenuSetRosMenuItemInfo(MenuInfo->Self, start, &lpitem);
1350 }
1351 start++;
1352 }
1353 MenuInfo->cyMenu = max(MenuInfo->cyMenu, orgY);
1354 }
1355
1356 MenuInfo->cxMenu = maxX;
1357 /* if none of the items have both text and bitmap then
1358 * the text and bitmaps are all aligned on the left. If there is at
1359 * least one item with both text and bitmap then bitmaps are
1360 * on the left and texts left aligned with the right hand side
1361 * of the bitmaps */
1362 if( !textandbmp) MenuInfo->cxTextAlign = 0;
1363
1364 /* space for 3d border */
1365 MenuInfo->cyMenu += MENU_BOTTOM_MARGIN;
1366 MenuInfo->cxMenu += 2;
1367
1368 /* Adjust popup height if it exceeds maximum */
1369 maxHeight = MENU_GetMaxPopupHeight(MenuInfo);
1370 MenuInfo->iMaxTop = MenuInfo->cyMenu - MENU_TOP_MARGIN;
1371 if (MenuInfo->cyMenu >= maxHeight)
1372 {
1373 MenuInfo->cyMenu = maxHeight;
1374 MenuInfo->dwArrowsOn = 1;
1375 }
1376 else
1377 {
1378 MenuInfo->dwArrowsOn = 0;
1379 }
1380
1381 MenuCleanupRosMenuItemInfo(&lpitem);
1382 MenuSetRosMenuInfo(MenuInfo);
1383 ReleaseDC( 0, hdc );
1384 }
1385
1386 /***********************************************************************
1387 * MenuMenuBarCalcSize
1388 *
1389 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1390 * height is off by 1 pixel which causes lengthy window relocations when
1391 * active document window is maximized/restored.
1392 *
1393 * Calculate the size of the menu bar.
1394 */
1395 static void FASTCALL MenuMenuBarCalcSize( HDC hdc, LPRECT lprect,
1396 PROSMENUINFO MenuInfo, HWND hwndOwner )
1397 {
1398 ROSMENUITEMINFO ItemInfo;
1399 int start, i, orgX, orgY, maxY, helpPos;
1400
1401 if ((lprect == NULL) || (MenuInfo == NULL)) return;
1402 if (MenuInfo->cItems == 0) return;
1403 TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect));
1404 MenuInfo->cxMenu = lprect->right - lprect->left;
1405 MenuInfo->cyMenu = 0;
1406 maxY = lprect->top + 1;
1407 start = 0;
1408 helpPos = -1;
1409
1410 MenuInfo->cxTextAlign = 0;
1411
1412 MenuInitRosMenuItemInfo(&ItemInfo);
1413 while (start < MenuInfo->cItems)
1414 {
1415 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo))
1416 {
1417 MenuCleanupRosMenuItemInfo(&ItemInfo);
1418 return;
1419 }
1420 orgX = lprect->left;
1421 orgY = maxY;
1422
1423 /* Parse items until line break or end of menu */
1424 for (i = start; i < MenuInfo->cItems; i++)
1425 {
1426 if ((helpPos == -1) && (ItemInfo.fType & MF_RIGHTJUSTIFY)) helpPos = i;
1427 if ((i != start) &&
1428 (ItemInfo.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
1429
1430 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX, orgY);
1431 MenuCalcItemSize(hdc, &ItemInfo, MenuInfo, hwndOwner, orgX, orgY, TRUE, FALSE);
1432 if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo))
1433 {
1434 MenuCleanupRosMenuItemInfo(&ItemInfo);
1435 return;
1436 }
1437
1438 if (ItemInfo.Rect.right > lprect->right)
1439 {
1440 if (i != start) break;
1441 else ItemInfo.Rect.right = lprect->right;
1442 }
1443 maxY = max( maxY, ItemInfo.Rect.bottom );
1444 orgX = ItemInfo.Rect.right;
1445 if (i + 1 < MenuInfo->cItems)
1446 {
1447 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i + 1, &ItemInfo))
1448 {
1449 MenuCleanupRosMenuItemInfo(&ItemInfo);
1450 return;
1451 }
1452 }
1453 }
1454
1455 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1456 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1457 #if 0
1458 /* Finish the line (set all items to the largest height found) */
1459 while (start < i)
1460 {
1461 if (MenuGetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo))
1462 {
1463 ItemInfo.Rect.bottom = maxY;
1464 MenuSetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo);
1465 }
1466 start++;
1467 }
1468 #else
1469 start = i; /* This works! */
1470 #endif
1471 }
1472
1473 lprect->bottom = maxY;
1474 MenuInfo->cyMenu = lprect->bottom - lprect->top;
1475 MenuSetRosMenuInfo(MenuInfo);
1476
1477 if (helpPos != -1)
1478 {
1479 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1480 /* the last item (if several lines, only move the last line) */
1481 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->cItems - 1, &ItemInfo))
1482 {
1483 MenuCleanupRosMenuItemInfo(&ItemInfo);
1484 return;
1485 }
1486 orgY = ItemInfo.Rect.top;
1487 orgX = lprect->right;
1488 for (i = MenuInfo->cItems - 1; helpPos <= i; i--)
1489 {
1490 if (i < helpPos) break; /* done */
1491 if (ItemInfo.Rect.top != orgY) break; /* Other line */
1492 if (orgX <= ItemInfo.Rect.right) break; /* Too far right already */
1493 ItemInfo.Rect.left += orgX - ItemInfo.Rect.right;
1494 ItemInfo.Rect.right = orgX;
1495 orgX = ItemInfo.Rect.left;
1496 MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo);
1497 if (helpPos + 1 <= i &&
1498 ! MenuGetRosMenuItemInfo(MenuInfo->Self, i - 1, &ItemInfo))
1499 {
1500 MenuCleanupRosMenuItemInfo(&ItemInfo);
1501 return;
1502 }
1503 }
1504 }
1505
1506 MenuCleanupRosMenuItemInfo(&ItemInfo);
1507 }
1508
1509 /***********************************************************************
1510 * MENU_DrawScrollArrows
1511 *
1512 * Draw scroll arrows.
1513 */
1514 static void
1515 MENU_DrawScrollArrows(PROSMENUINFO lppop, HDC hdc)
1516 {
1517 HDC hdcMem = CreateCompatibleDC(hdc);
1518 HBITMAP hOrigBitmap;
1519 UINT arrow_bitmap_width, arrow_bitmap_height;
1520 BITMAP bmp;
1521 RECT rect;
1522
1523 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp), &bmp);
1524 arrow_bitmap_width = bmp.bmWidth;
1525 arrow_bitmap_height = bmp.bmHeight;
1526
1527 if (lppop->iTop)
1528 hOrigBitmap = SelectObject(hdcMem, get_up_arrow_bitmap());
1529 else
1530 hOrigBitmap = SelectObject(hdcMem, get_up_arrow_inactive_bitmap());
1531 rect.left = 0;
1532 rect.top = 0;
1533 rect.right = lppop->cxMenu;
1534 rect.bottom = arrow_bitmap_height;
1535 FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENU));
1536 BitBlt(hdc, (lppop->cxMenu - arrow_bitmap_width) / 2, 0,
1537 arrow_bitmap_width, arrow_bitmap_height, hdcMem, 0, 0, SRCCOPY);
1538 rect.top = lppop->cyMenu - arrow_bitmap_height;
1539 rect.bottom = lppop->cyMenu;
1540 FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENU));
1541 if (lppop->iTop < lppop->iMaxTop - (MENU_GetMaxPopupHeight(lppop) - 2 * arrow_bitmap_height))
1542 SelectObject(hdcMem, get_down_arrow_bitmap());
1543 else
1544 SelectObject(hdcMem, get_down_arrow_inactive_bitmap());
1545 BitBlt(hdc, (lppop->cxMenu - arrow_bitmap_width) / 2,
1546 lppop->cyMenu - arrow_bitmap_height,
1547 arrow_bitmap_width, arrow_bitmap_height, hdcMem, 0, 0, SRCCOPY);
1548 SelectObject(hdcMem, hOrigBitmap);
1549 DeleteDC(hdcMem);
1550 }
1551
1552 /***********************************************************************
1553 * draw_popup_arrow
1554 *
1555 * Draws the popup-menu arrow.
1556 */
1557 static void draw_popup_arrow( HDC hdc, RECT rect, UINT arrow_bitmap_width,
1558 UINT arrow_bitmap_height)
1559 {
1560 HDC hdcMem = CreateCompatibleDC( hdc );
1561 HBITMAP hOrigBitmap;
1562
1563 hOrigBitmap = SelectObject( hdcMem, get_arrow_bitmap() );
1564 BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
1565 (rect.top + rect.bottom - arrow_bitmap_height) / 2,
1566 arrow_bitmap_width, arrow_bitmap_height,
1567 hdcMem, 0, 0, SRCCOPY );
1568 SelectObject( hdcMem, hOrigBitmap );
1569 DeleteDC( hdcMem );
1570 }
1571
1572 /***********************************************************************
1573 * MenuDrawMenuItem
1574 *
1575 * Draw a single menu item.
1576 */
1577 static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC hdc,
1578 PROSMENUITEMINFO lpitem, UINT Height, BOOL menuBar, UINT odaction)
1579 {
1580 RECT rect;
1581 PWCHAR Text;
1582 BOOL flat_menu = FALSE;
1583 int bkgnd;
1584 UINT arrow_bitmap_width = 0, arrow_bitmap_height = 0;
1585 PWND Wnd = ValidateHwndNoErr(hWnd);
1586
1587 if (!Wnd)
1588 return;
1589
1590 if (!menuBar) {
1591 BITMAP bmp;
1592 GetObjectW( get_arrow_bitmap(), sizeof(bmp), &bmp );
1593 arrow_bitmap_width = bmp.bmWidth;
1594 arrow_bitmap_height = bmp.bmHeight;
1595 }
1596
1597 if (lpitem->fType & MF_SYSMENU)
1598 {
1599 if ( (Wnd->style & WS_MINIMIZE))
1600 {
1601 UserGetInsideRectNC(Wnd, &rect);
1602 UserDrawSysMenuButton(hWnd, hdc, &rect, lpitem->fState & (MF_HILITE | MF_MOUSESELECT));
1603 }
1604 return;
1605 }
1606
1607 SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
1608 bkgnd = (menuBar && flat_menu) ? COLOR_MENUBAR : COLOR_MENU;
1609
1610 /* Setup colors */
1611
1612 if (lpitem->fState & MF_HILITE)
1613 {
1614 if(menuBar && !flat_menu) {
1615 SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT));
1616 SetBkColor(hdc, GetSysColor(COLOR_MENU));
1617 } else {
1618 if (lpitem->fState & MF_GRAYED)
1619 SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
1620 else
1621 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1622 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1623 }
1624 }
1625 else
1626 {
1627 if (lpitem->fState & MF_GRAYED)
1628 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1629 else
1630 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
1631 SetBkColor( hdc, GetSysColor( bkgnd ) );
1632 }
1633
1634 TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->Rect));
1635 rect = lpitem->Rect;
1636 MENU_AdjustMenuItemRect(MenuInfo, &rect);
1637
1638 if (lpitem->fType & MF_OWNERDRAW)
1639 {
1640 /*
1641 ** Experimentation under Windows reveals that an owner-drawn
1642 ** menu is given the rectangle which includes the space it requested
1643 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1644 ** and a popup-menu arrow. This is the value of lpitem->rect.
1645 ** Windows will leave all drawing to the application except for
1646 ** the popup-menu arrow. Windows always draws that itself, after
1647 ** the menu owner has finished drawing.
1648 */
1649 DRAWITEMSTRUCT dis;
1650
1651 dis.CtlType = ODT_MENU;
1652 dis.CtlID = 0;
1653 dis.itemID = lpitem->wID;
1654 dis.itemData = (DWORD)lpitem->dwItemData;
1655 dis.itemState = 0;
1656 if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
1657 if (lpitem->fState & MF_DEFAULT) dis.itemState |= ODS_DEFAULT;
1658 if (lpitem->fState & MF_DISABLED) dis.itemState |= ODS_DISABLED;
1659 if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED | ODS_DISABLED;
1660 if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED;
1661 //if (!(MenuInfo->fFlags & MNF_UNDERLINE)) dis.itemState |= ODS_NOACCEL;
1662 //if (MenuInfo->fFlags & MNF_INACTIVE) dis.itemState |= ODS_INACTIVE;
1663 dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1664 dis.hwndItem = (HWND) MenuInfo->Self;
1665 dis.hDC = hdc;
1666 dis.rcItem = rect;
1667 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1668 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd,
1669 dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
1670 dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
1671 dis.rcItem.bottom);
1672 SendMessageW(WndOwner, WM_DRAWITEM, 0, (LPARAM) &dis);
1673 /* Draw the popup-menu arrow */
1674 if (lpitem->hSubMenu)
1675 {
1676 /* RECT rectTemp;
1677 CopyRect(&rectTemp, &rect);
1678 rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK);
1679 DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW);
1680 */
1681 draw_popup_arrow( hdc, rect, arrow_bitmap_width, arrow_bitmap_height);
1682 }
1683 return;
1684 }
1685
1686 if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
1687
1688 if (lpitem->fState & MF_HILITE)
1689 {
1690 if (flat_menu)
1691 {
1692 InflateRect (&rect, -1, -1);
1693 FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENUHILIGHT));
1694 InflateRect (&rect, 1, 1);
1695 FrameRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1696 }
1697 else
1698 {
1699 if(menuBar)
1700 DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
1701 else
1702 FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1703 }
1704 }
1705 else
1706 FillRect( hdc, &rect, GetSysColorBrush(bkgnd) );
1707
1708 SetBkMode( hdc, TRANSPARENT );
1709
1710 /* vertical separator */
1711 if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
1712 {
1713 HPEN oldPen;
1714 RECT rc = rect;
1715
1716 rc.left -= 3;//MENU_COL_SPACE / 2 + 1;
1717 rc.top = 3;
1718 rc.bottom = Height - 3;
1719 if (flat_menu)
1720 {
1721 oldPen = SelectObject( hdc, GetStockObject(DC_PEN) );
1722 SetDCPenColor(hdc, GetSysColor(COLOR_BTNSHADOW));
1723 MoveToEx( hdc, rc.left, rc.top, NULL );
1724 LineTo( hdc, rc.left, rc.bottom );
1725 SelectObject( hdc, oldPen );
1726 }
1727 else
1728 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
1729 }
1730
1731 /* horizontal separator */
1732 if (lpitem->fType & MF_SEPARATOR)
1733 {
1734 HPEN oldPen;
1735 RECT rc = rect;
1736
1737 rc.left++;
1738 rc.right--;
1739 rc.top += SEPARATOR_HEIGHT / 2;
1740 if (flat_menu)
1741 {
1742 oldPen = SelectObject( hdc, GetStockObject(DC_PEN) );
1743 SetDCPenColor( hdc, GetSysColor(COLOR_BTNSHADOW));
1744 MoveToEx( hdc, rc.left, rc.top, NULL );
1745 LineTo( hdc, rc.right, rc.top );
1746 SelectObject( hdc, oldPen );
1747 }
1748 else
1749 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
1750 return;
1751 }
1752
1753 #if 0
1754 /* helper lines for debugging */
1755 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
1756 FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1757 SelectObject(hdc, GetStockObject(DC_PEN));
1758 SetDCPenColor(hdc, GetSysColor(COLOR_WINDOWFRAME));
1759 MoveToEx(hdc, rect.left, (rect.top + rect.bottom) / 2, NULL);
1760 LineTo(hdc, rect.right, (rect.top + rect.bottom) / 2);
1761 #endif
1762
1763 if (!menuBar)
1764 {
1765 HBITMAP bm;
1766 INT y = rect.top + rect.bottom;
1767 RECT rc = rect;
1768 BOOL checked = FALSE;
1769 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
1770 UINT check_bitmap_height = GetSystemMetrics( SM_CYMENUCHECK );
1771 /* Draw the check mark
1772 *
1773 * FIXME:
1774 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1775 */
1776 if( !(MenuInfo->dwStyle & MNS_NOCHECK)) {
1777 bm = (lpitem->fState & MF_CHECKED) ? lpitem->hbmpChecked :
1778 lpitem->hbmpUnchecked;
1779 if (bm) /* we have a custom bitmap */
1780 {
1781 HDC hdcMem = CreateCompatibleDC( hdc );
1782
1783 SelectObject( hdcMem, bm );
1784 BitBlt( hdc, rc.left, (y - check_bitmap_height) / 2,
1785 check_bitmap_width, check_bitmap_height,
1786 hdcMem, 0, 0, SRCCOPY );
1787 DeleteDC( hdcMem );
1788 checked = TRUE;
1789 }
1790 else if (lpitem->fState & MF_CHECKED) /* standard bitmaps */
1791 {
1792 RECT r;
1793 //HBITMAP bm = CreateBitmap( check_bitmap_width, check_bitmap_height, 1, 1, NULL );
1794 //HDC hdcMem = CreateCompatibleDC( hdc );
1795 //SelectObject( hdcMem, bm );
1796 //SetRect( &r, 0, 0, check_bitmap_width, check_bitmap_height);
1797 CopyRect(&r, &rect);
1798 r.right = r.left + GetSystemMetrics(SM_CXMENUCHECK);
1799 DrawFrameControl( hdc, &r, DFC_MENU,
1800 (lpitem->fType & MFT_RADIOCHECK) ?
1801 DFCS_MENUBULLET : DFCS_MENUCHECK);
1802 //BitBlt( hdc, rc.left, (y - r.bottom) / 2, r.right, r.bottom, hdcMem, 0, 0, SRCCOPY );
1803 //DeleteDC( hdcMem );
1804 //DeleteObject( bm );
1805 checked = TRUE;
1806 }
1807 }
1808 if ( lpitem->hbmpItem )//&& !( checked && (MenuInfo->dwStyle & MNS_CHECKORBMP)))
1809 {
1810 RECT bmpRect;
1811 CopyRect(&bmpRect, &rect);
1812 if (!(MenuInfo->dwStyle & MNS_CHECKORBMP) && !(MenuInfo->dwStyle & MNS_NOCHECK))
1813 bmpRect.left += check_bitmap_width + 2;
1814 if (!(checked && (MenuInfo->dwStyle & MNS_CHECKORBMP)))
1815 {
1816 //POINT origorg;
1817 bmpRect.right = bmpRect.left + lpitem->maxBmpSize.cx;
1818 /* some applications make this assumption on the DC's origin */
1819 //SetViewportOrgEx( hdc, rect.left, rect.top, &origorg);
1820 MenuDrawBitmapItem(hdc, lpitem, &bmpRect, MenuInfo, WndOwner, odaction, menuBar);
1821 //SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
1822 }
1823 }
1824 /* Draw the popup-menu arrow */
1825 if (lpitem->hSubMenu)
1826 {
1827 /* RECT rectTemp;
1828 CopyRect(&rectTemp, &rect);
1829 rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK);
1830 DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW);
1831 */
1832 draw_popup_arrow( hdc, rect, arrow_bitmap_width, arrow_bitmap_height);
1833 }
1834 rect.left += 4;
1835 if( !(MenuInfo->dwStyle & MNS_NOCHECK))
1836 rect.left += check_bitmap_width;
1837 rect.right -= arrow_bitmap_width;//check_bitmap_width;
1838 }
1839 else if( lpitem->hbmpItem)
1840 { /* Draw the bitmap */
1841 //POINT origorg;
1842
1843 //SetViewportOrgEx( hdc, rect.left, rect.top, &origorg);
1844 MenuDrawBitmapItem(hdc, lpitem, &rect, MenuInfo, WndOwner, odaction, menuBar);
1845 //SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
1846 }
1847
1848 /* process text if present */
1849 if (lpitem->lpstr)
1850 {
1851 int i = 0;
1852 HFONT hfontOld = 0;
1853
1854 UINT uFormat = menuBar ?
1855 DT_CENTER | DT_VCENTER | DT_SINGLELINE :
1856 DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1857
1858 if ((MenuInfo->dwStyle & MNS_CHECKORBMP))
1859 rect.left += max(0, (int)(MenuInfo->cxTextAlign - GetSystemMetrics(SM_CXMENUCHECK)));
1860 else
1861 rect.left += MenuInfo->cxTextAlign;
1862
1863 if ( lpitem->fState & MFS_DEFAULT )
1864 {
1865 hfontOld = SelectObject(hdc, hMenuFontBold);
1866 }
1867
1868 if (menuBar) {
1869 if( lpitem->hbmpItem)
1870 rect.left += lpitem->maxBmpSize.cx;
1871 if( !(lpitem->hbmpItem == HBMMENU_CALLBACK))
1872 rect.left += MenuCharSize.cx;
1873 rect.right -= MenuCharSize.cx;
1874 //rect.left += MENU_BAR_ITEMS_SPACE / 2;
1875 //rect.right -= MENU_BAR_ITEMS_SPACE / 2;
1876 }
1877
1878 Text = lpitem->lpstr;
1879 if(Text)
1880 {
1881 for (i = 0; L'\0' != Text[i]; i++)
1882 if (Text[i] == L'\t' || Text[i] == L'\b')
1883 break;
1884 }
1885
1886 if(lpitem->fState & MF_GRAYED)
1887 {
1888 if (!(lpitem->fState & MF_HILITE) )
1889 {
1890 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1891 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1892 DrawTextW( hdc, Text, i, &rect, uFormat );
1893 --rect.left; --rect.top; --rect.right; --rect.bottom;
1894 }
1895 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1896 }
1897
1898 DrawTextW( hdc, Text, i, &rect, uFormat);
1899
1900 /* paint the shortcut text */
1901 if (!menuBar && L'\0' != Text[i]) /* There's a tab or flush-right char */
1902 {
1903 if (L'\t' == Text[i])
1904 {
1905 rect.left = lpitem->dxTab;
1906 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1907 }
1908 else
1909 {
1910 rect.right = lpitem->dxTab;
1911 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
1912 }
1913
1914 if (lpitem->fState & MF_GRAYED)
1915 {
1916 if (!(lpitem->fState & MF_HILITE) )
1917 {
1918 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1919 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1920 DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat);
1921 --rect.left; --rect.top; --rect.right; --rect.bottom;
1922 }
1923 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1924 }
1925 DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat );
1926 }
1927
1928 if (hfontOld)
1929 SelectObject (hdc, hfontOld);
1930 }
1931 }
1932
1933 /***********************************************************************
1934 * MenuDrawPopupMenu
1935 *
1936 * Paint a popup menu.
1937 */
1938 static void FASTCALL MenuDrawPopupMenu(HWND hwnd, HDC hdc, HMENU hmenu )
1939 {
1940 HBRUSH hPrevBrush = 0;
1941 RECT rect;
1942
1943 TRACE("wnd=%p dc=%p menu=%p\n", hwnd, hdc, hmenu);
1944
1945 GetClientRect( hwnd, &rect );
1946
1947 if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) ))
1948 && (SelectObject( hdc, hMenuFont)))
1949 {
1950 HPEN hPrevPen;
1951
1952 Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
1953
1954 hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
1955 if ( hPrevPen )
1956 {
1957 BOOL flat_menu = FALSE;
1958 ROSMENUINFO MenuInfo;
1959 ROSMENUITEMINFO ItemInfo;
1960
1961 SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
1962 if (flat_menu)
1963 FrameRect(hdc, &rect, GetSysColorBrush(COLOR_BTNSHADOW));
1964 else
1965 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
1966
1967 //TRACE("hmenu %p Style %08x\n", hmenu, menu->dwStyle);
1968 /* draw menu items */
1969 if (MenuGetRosMenuInfo(&MenuInfo, hmenu) && MenuInfo.cItems)
1970 {
1971 UINT u;
1972 MenuInitRosMenuItemInfo(&ItemInfo);
1973
1974 //for (u = MenuInfo.cItems; u > 0; u--, item++)
1975 for (u = 0; u < MenuInfo.cItems; u++)
1976 {
1977 if (MenuGetRosMenuItemInfo(MenuInfo.Self, u, &ItemInfo))
1978 {
1979 HWND WndOwner = MenuInfo.spwndNotify ? MenuInfo.spwndNotify->head.h : NULL;
1980 MenuDrawMenuItem(hwnd, &MenuInfo, WndOwner, hdc, &ItemInfo,
1981 MenuInfo.cyMenu, FALSE, ODA_DRAWENTIRE);
1982 }
1983 }
1984 /* draw scroll arrows */
1985 if (MenuInfo.dwArrowsOn)
1986 {
1987 MENU_DrawScrollArrows(&MenuInfo, hdc);
1988 }
1989
1990 MenuSetRosMenuInfo(&MenuInfo);
1991 MenuCleanupRosMenuItemInfo(&ItemInfo);
1992 }
1993 } else
1994 {
1995 SelectObject( hdc, hPrevBrush );
1996 }
1997 }
1998 }
1999
2000 /***********************************************************************
2001 * MenuDrawMenuBar
2002 *
2003 * Paint a menu bar. Returns the height of the menu bar.
2004 * called from [windows/nonclient.c]
2005 */
2006 UINT MenuDrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
2007 BOOL suppress_draw)
2008 {
2009 ROSMENUINFO lppop;
2010 HFONT hfontOld = 0;
2011 HMENU hMenu = GetMenu(hwnd);
2012
2013 if (! MenuGetRosMenuInfo(&lppop, hMenu) || lprect == NULL)
2014 {
2015 return GetSystemMetrics(SM_CYMENU);
2016 }
2017
2018 if (suppress_draw)
2019 {
2020 hfontOld = SelectObject(hDC, hMenuFont);
2021
2022 MenuMenuBarCalcSize(hDC, lprect, &lppop, hwnd);
2023
2024 lprect->bottom = lprect->top + lppop.cyMenu;
2025
2026 if (hfontOld) SelectObject( hDC, hfontOld);
2027 return lppop.cyMenu;
2028 }
2029 else
2030 return DrawMenuBarTemp(hwnd, hDC, lprect, hMenu, NULL);
2031 }
2032
2033 /***********************************************************************
2034 * MENU_InitPopup
2035 *
2036 * Popup menu initialization before WM_ENTERMENULOOP.
2037 */
2038 static BOOL MENU_InitPopup( HWND hwndOwner, HMENU hmenu, UINT flags )
2039 {
2040 MENU *menu;
2041 DWORD ex_style = WS_EX_TOOLWINDOW;
2042 ROSMENUINFO MenuInfo;
2043
2044 TRACE("owner=%p hmenu=%p\n", hwndOwner, hmenu);
2045
2046 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
2047
2048 /* store the owner for DrawItem */
2049 if (!IsWindow( hwndOwner ))
2050 {
2051 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2052 return FALSE;
2053 }
2054 MenuGetRosMenuInfo(&MenuInfo, menu->head.h);
2055 //menu->hwndOwner = hwndOwner;
2056 MenuInfo.spwndNotify = ValidateHwndNoErr( hwndOwner );
2057
2058 if (flags & TPM_LAYOUTRTL)
2059 ex_style = WS_EX_LAYOUTRTL;
2060
2061 /* NOTE: In Windows, top menu popup is not owned. */
2062 //menu->hWnd = CreateWindowExW( ex_style, WC_MENU, NULL,
2063 MenuInfo.Wnd = CreateWindowExW( ex_style, WC_MENU, NULL,
2064 WS_POPUP, 0, 0, 0, 0,
2065 hwndOwner, 0, (HINSTANCE)GetWindowLongPtrW(hwndOwner, GWLP_HINSTANCE),
2066 (LPVOID)hmenu );
2067 MenuSetRosMenuInfo(&MenuInfo);
2068 if( !menu->hWnd ) return FALSE;
2069 return TRUE;
2070 }
2071
2072 /***********************************************************************
2073 * MenuShowPopup
2074 *
2075 * Display a popup menu.
2076 */
2077 static BOOL FASTCALL MenuShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, UINT flags,
2078 INT x, INT y, INT xanchor, INT yanchor )
2079 {
2080 ROSMENUINFO MenuInfo;
2081 ROSMENUITEMINFO ItemInfo;
2082 UINT width, height;
2083 POINT pt;
2084 HMONITOR monitor;
2085 MONITORINFO info;
2086
2087 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
2088 hwndOwner, hmenu, id, x, y, xanchor, yanchor);
2089
2090 if (! MenuGetRosMenuInfo(&MenuInfo, hmenu)) return FALSE;
2091 if (MenuInfo.iItem != NO_SELECTED_ITEM)
2092 {
2093 MenuInitRosMenuItemInfo(&ItemInfo);
2094 if (MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.iItem, &ItemInfo))
2095 {
2096 ItemInfo.fMask |= MIIM_STATE;
2097 ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT);
2098 MenuSetRosMenuItemInfo(MenuInfo.Self, MenuInfo.iItem, &ItemInfo);
2099 }
2100 MenuCleanupRosMenuItemInfo(&ItemInfo);
2101 MenuInfo.iItem = NO_SELECTED_ITEM;
2102 }
2103
2104 //menu->dwArrowsOn = 0;
2105 MenuInfo.dwArrowsOn = 0;
2106 MenuSetRosMenuInfo(&MenuInfo);
2107 MenuPopupMenuCalcSize(&MenuInfo, hwndOwner);
2108
2109 /* adjust popup menu pos so that it fits within the desktop */
2110
2111 width = MenuInfo.cxMenu + GetSystemMetrics(SM_CXBORDER);
2112 height = MenuInfo.cyMenu + GetSystemMetrics(SM_CYBORDER);
2113
2114 /* FIXME: should use item rect */
2115 pt.x = x;
2116 pt.y = y;
2117 monitor = MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST );
2118 info.cbSize = sizeof(info);
2119 GetMonitorInfoW( monitor, &info );
2120
2121 if (flags & TPM_LAYOUTRTL)
2122 flags ^= TPM_RIGHTALIGN;
2123
2124 if( flags & TPM_RIGHTALIGN ) x -= width;
2125 if( flags & TPM_CENTERALIGN ) x -= width / 2;
2126
2127 if( flags & TPM_BOTTOMALIGN ) y -= height;
2128 if( flags & TPM_VCENTERALIGN ) y -= height / 2;
2129
2130 if( x + width > info.rcMonitor.right)
2131 {
2132 if( xanchor && x >= width - xanchor )
2133 x -= width - xanchor;
2134
2135 if( x + width > info.rcMonitor.right)
2136 x = info.rcMonitor.right - width;
2137 }
2138 if( x < info.rcMonitor.left ) x = info.rcMonitor.left;
2139
2140 if( y + height > info.rcMonitor.bottom)
2141 {
2142 if( yanchor && y >= height + yanchor )
2143 y -= height + yanchor;
2144
2145 if( y + height > info.rcMonitor.bottom)
2146 y = info.rcMonitor.bottom - height;
2147 }
2148 if( y < info.rcMonitor.top ) y = info.rcMonitor.top;
2149
2150 if (!top_popup) {
2151 top_popup = MenuInfo.Wnd;
2152 top_popup_hmenu = hmenu;
2153 }
2154 /* Display the window */
2155
2156 SetWindowPos( MenuInfo.Wnd, HWND_TOPMOST, x, y, width, height,
2157 SWP_SHOWWINDOW | SWP_NOACTIVATE);
2158 UpdateWindow( MenuInfo.Wnd );
2159
2160 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART, MenuInfo.Wnd, OBJID_CLIENT, CHILDID_SELF, 0);
2161
2162 return TRUE;
2163 }
2164
2165 /***********************************************************************
2166 * MENU_EnsureMenuItemVisible
2167 */
2168 void
2169 MENU_EnsureMenuItemVisible(PROSMENUINFO lppop, PROSMENUITEMINFO item, HDC hdc)
2170 {
2171 if (lppop->dwArrowsOn)
2172 {
2173 //ITEM *item = &lppop->items[wIndex];
2174 UINT nMaxHeight = MENU_GetMaxPopupHeight(lppop);
2175 UINT nOldPos = lppop->iTop;
2176 RECT rc;
2177 UINT arrow_bitmap_height;
2178 BITMAP bmp;
2179
2180 GetClientRect(lppop->Wnd, &rc);
2181
2182 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp), &bmp);
2183 arrow_bitmap_height = bmp.bmHeight;
2184
2185 rc.top += arrow_bitmap_height;
2186 rc.bottom -= arrow_bitmap_height + MENU_BOTTOM_MARGIN;
2187
2188 nMaxHeight -= GetSystemMetrics(SM_CYBORDER) + 2 * arrow_bitmap_height;
2189 if (item->Rect.bottom > lppop->iTop + nMaxHeight)
2190 {
2191 lppop->iTop = item->Rect.bottom - nMaxHeight;
2192 ScrollWindow(lppop->Wnd, 0, nOldPos - lppop->iTop, &rc, &rc);
2193 MENU_DrawScrollArrows(lppop, hdc);
2194 }
2195 else if (item->Rect.top - MENU_TOP_MARGIN < lppop->iTop)
2196 {
2197 lppop->iTop = item->Rect.top - MENU_TOP_MARGIN;
2198 ScrollWindow(lppop->Wnd, 0, nOldPos - lppop->iTop, &rc, &rc);
2199 MENU_DrawScrollArrows(lppop, hdc);
2200 }
2201 MenuSetRosMenuInfo(lppop);
2202 }
2203 }
2204
2205 /***********************************************************************
2206 * MenuSelectItem
2207 */
2208 static void FASTCALL MenuSelectItem(HWND hwndOwner, PROSMENUINFO hmenu, UINT wIndex,
2209 BOOL sendMenuSelect, HMENU topmenu)
2210 {
2211 ROSMENUITEMINFO ItemInfo;
2212 ROSMENUINFO TopMenuInfo;
2213 HDC hdc;
2214
2215 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
2216
2217 if (!hmenu || !hmenu->cItems || !hmenu->Wnd) return;
2218 if (hmenu->iItem == wIndex) return;
2219 if (hmenu->fFlags & MNF_POPUP) hdc = GetDC(hmenu->Wnd);
2220 else hdc = GetDCEx(hmenu->Wnd, 0, DCX_CACHE | DCX_WINDOW);
2221 if (!top_popup) {
2222 top_popup = hmenu->Wnd;
2223 top_popup_hmenu = hmenu->Self;
2224 }
2225
2226 SelectObject( hdc, hMenuFont );
2227
2228 MenuInitRosMenuItemInfo(&ItemInfo);
2229
2230 /* Clear previous highlighted item */
2231 if (hmenu->iItem != NO_SELECTED_ITEM)
2232 {
2233 if (MenuGetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo))
2234 {
2235 ItemInfo.fMask |= MIIM_STATE;
2236 ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT);
2237 MenuSetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo);
2238 }
2239 MenuDrawMenuItem(hmenu->Wnd, hmenu, hwndOwner, hdc, &ItemInfo,
2240 hmenu->cyMenu, !(hmenu->fFlags & MNF_POPUP),
2241 ODA_SELECT);
2242 }
2243
2244 /* Highlight new item (if any) */
2245 hmenu->iItem = wIndex;
2246 MenuSetRosMenuInfo(hmenu);
2247 if (hmenu->iItem != NO_SELECTED_ITEM)
2248 {
2249 if (MenuGetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo))
2250 {
2251 if (!(ItemInfo.fType & MF_SEPARATOR))
2252 {
2253 ItemInfo.fMask |= MIIM_STATE;
2254 ItemInfo.fState |= MF_HILITE;
2255 MenuSetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo);
2256 MENU_EnsureMenuItemVisible(hmenu, &ItemInfo, hdc);
2257 MenuDrawMenuItem(hmenu->Wnd, hmenu, hwndOwner, hdc,
2258 &ItemInfo, hmenu->cyMenu, !(hmenu->fFlags & MNF_POPUP), ODA_SELECT);
2259 }
2260 if (sendMenuSelect)
2261 {
2262 WPARAM wParam = MAKEWPARAM( ItemInfo.hSubMenu ? wIndex : ItemInfo.wID,
2263 ItemInfo.fType | ItemInfo.fState |
2264 (ItemInfo.hSubMenu ? MF_POPUP : 0) |
2265 (hmenu->fFlags & MNF_SYSMENU ? MF_SYSMENU : 0 ) );
2266
2267 SendMessageW(hwndOwner, WM_MENUSELECT, wParam, (LPARAM) hmenu->Self);
2268 }
2269 }
2270 }
2271 else if (sendMenuSelect)
2272 {
2273 if(topmenu)
2274 {
2275 int pos;
2276 pos = MenuFindSubMenu(&topmenu, hmenu->Self);
2277 if (pos != NO_SELECTED_ITEM)
2278 {
2279 if (MenuGetRosMenuInfo(&TopMenuInfo, topmenu)
2280 && MenuGetRosMenuItemInfo(topmenu, pos, &ItemInfo))
2281 {
2282 WPARAM wParam = MAKEWPARAM( Pos, ItemInfo.fType | ItemInfo.fState |
2283 (ItemInfo.hSubMenu ? MF_POPUP : 0) |
2284 (TopMenuInfo.fFlags & MNF_SYSMENU ? MF_SYSMENU : 0 ) );
2285
2286 SendMessageW(hwndOwner, WM_MENUSELECT, wParam, (LPARAM) topmenu);
2287 }
2288 }
2289 }
2290 }
2291 MenuCleanupRosMenuItemInfo(&ItemInfo);
2292 ReleaseDC(hmenu->Wnd, hdc);
2293 }
2294
2295 /***********************************************************************
2296 * MenuMoveSelection
2297 *
2298 * Moves currently selected item according to the Offset parameter.
2299 * If there is no selection then it should select the last item if
2300 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
2301 */
2302 static void FASTCALL
2303 MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset)
2304 {
2305 INT i;
2306 ROSMENUITEMINFO ItemInfo;
2307 INT OrigPos;
2308
2309 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner, MenuInfo, Offset);
2310
2311 /* Prevent looping */
2312 if (0 == MenuInfo->cItems || 0 == Offset)
2313 return;
2314 else if (Offset < -1)
2315 Offset = -1;
2316 else if (Offset > 1)
2317 Offset = 1;
2318
2319 MenuInitRosMenuItemInfo(&ItemInfo);
2320
2321 OrigPos = MenuInfo->iItem;
2322 if (OrigPos == NO_SELECTED_ITEM) /* NO_SELECTED_ITEM is not -1 ! */
2323 {
2324 OrigPos = 0;
2325 i = -1;
2326 }
2327 else
2328 {
2329 i = MenuInfo->iItem;
2330 }
2331
2332 do
2333 {
2334 /* Step */
2335 i += Offset;
2336 /* Clip and wrap around */
2337 if (i < 0)
2338 {
2339 i = MenuInfo->cItems - 1;
2340 }
2341 else if (i >= MenuInfo->cItems)
2342 {
2343 i = 0;
2344 }
2345 /* If this is a good candidate; */
2346 if (MenuGetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo) &&
2347 0 == (ItemInfo.fType & MF_SEPARATOR))
2348 {
2349 MenuSelectItem(WndOwner, MenuInfo, i, TRUE, NULL);
2350 MenuCleanupRosMenuItemInfo(&ItemInfo);
2351 return;
2352 }
2353 } while (i != OrigPos);
2354
2355 /* Not found */
2356 MenuCleanupRosMenuItemInfo(&ItemInfo);
2357 }
2358
2359 #if 0
2360 LRESULT WINAPI
2361 PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
2362 {
2363 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
2364 PWND pWnd;
2365 PPOPUPMENU pPopupMenu;
2366
2367 pWnd = ValidateHwndNoErr(Wnd);
2368 if (pWnd)
2369 {
2370 if (!pWnd->fnid)
2371 {
2372 if (Message != WM_NCCREATE)
2373 {
2374 return DefWindowProcW(Wnd, Message, wParam, lParam);
2375 }
2376 NtUserSetWindowFNID(Wnd, FNID_MENU);
2377 pPopupMenu = HeapAlloc( GetProcessHeap(), 0, sizeof(POPUPMENU) );
2378 pPopupMenu->spwndPopupMenu = pWnd;
2379 SetWindowLongPtrW(Wnd, 0, (LONG_PTR)pPopupMenu);
2380 }
2381 else
2382 {
2383 if (pWnd->fnid != FNID_MENU)
2384 {
2385 ERR("Wrong window class for Menu!\n");
2386 return 0;
2387 }
2388 pPopupMenu = ((PMENUWND)pWnd)->ppopupmenu;
2389 }
2390 }
2391 #endif
2392
2393 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
2394
2395 switch(Message)
2396 {
2397 case WM_CREATE:
2398 {
2399 CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
2400 pPopupMenu->spmenu = ValidateHandle(cs->lpCreateParams, TYPE_MENU);
2401 return 0;
2402 }
2403
2404 case WM_MOUSEACTIVATE: /* We don't want to be activated */
2405 return MA_NOACTIVATE;
2406
2407 case WM_PAINT:
2408 {
2409 PAINTSTRUCT ps;
2410 BeginPaint(Wnd, &ps);
2411 MenuDrawPopupMenu(Wnd, ps.hdc, pPopupMenu->spmenu->head.h);
2412 EndPaint(Wnd, &ps);
2413 return 0;
2414 }
2415
2416 case WM_PRINTCLIENT:
2417 {
2418 MenuDrawPopupMenu( Wnd, (HDC)wParam, pPopupMenu->spmenu->head.h);
2419 return 0;
2420 }
2421
2422 case WM_ERASEBKGND:
2423 return 1;
2424
2425 case WM_DESTROY:
2426 /* zero out global pointer in case resident popup window was destroyed. */
2427 if (Wnd == top_popup)
2428 {
2429 top_popup = NULL;
2430 top_popup_hmenu = NULL;
2431 }
2432 break;
2433
2434 case WM_NCDESTROY:
2435 {
2436 HeapFree( GetProcessHeap(), 0, pPopupMenu );
2437 SetWindowLongPtrW(Wnd, 0, 0);
2438 NtUserSetWindowFNID(Wnd, FNID_DESTROY);
2439 break;
2440 }
2441
2442 case WM_SHOWWINDOW:
2443 if (0 != wParam)
2444 {
2445 if (!pPopupMenu || !pPopupMenu->spmenu)
2446 {
2447 OutputDebugStringA("no menu to display\n");
2448 }
2449 }
2450 /*else
2451 {
2452 pPopupMenu->spmenu = NULL; ///// WTF?
2453 }*/
2454 break;
2455
2456 case MM_SETMENUHANDLE:
2457 {
2458 PMENU pmenu = ValidateHandle((HMENU)wParam, TYPE_MENU);
2459 if (!pmenu)
2460 {
2461 ERR("Bad Menu Handle\n");
2462 break;
2463 }
2464 pPopupMenu->spmenu = pmenu;
2465 break;
2466 }
2467
2468 case MM_GETMENUHANDLE:
2469 case MN_GETHMENU:
2470 return (LRESULT)(pPopupMenu ? (pPopupMenu->spmenu ? pPopupMenu->spmenu->head.h : NULL) : NULL);
2471
2472 default:
2473 return DefWindowProcW(Wnd, Message, wParam, lParam);
2474 }
2475
2476 return 0;
2477 }
2478 #endif
2479
2480 LRESULT WINAPI
2481 PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
2482 {
2483 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
2484 PWND pWnd;
2485
2486 pWnd = ValidateHwnd(Wnd);
2487 if (pWnd)
2488 {
2489 if (!pWnd->fnid)
2490 {
2491 if (Message != WM_NCCREATE)
2492 {
2493 return DefWindowProcW(Wnd, Message, wParam, lParam);
2494 }
2495 NtUserSetWindowFNID(Wnd, FNID_MENU);
2496 }
2497 else
2498 {
2499 if (pWnd->fnid != FNID_MENU)
2500 {
2501 ERR("Wrong window class for Menu!\n");
2502 return 0;
2503 }
2504 }
2505 }
2506 #endif
2507
2508 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
2509
2510 switch(Message)
2511 {
2512 case WM_CREATE:
2513 {
2514 CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
2515 SetWindowLongPtrW(Wnd, 0, (LONG_PTR)cs->lpCreateParams);
2516 return 0;
2517 }
2518
2519 case WM_MOUSEACTIVATE: /* We don't want to be activated */
2520 return MA_NOACTIVATE;
2521
2522 case WM_PAINT:
2523 {
2524 PAINTSTRUCT ps;
2525 BeginPaint(Wnd, &ps);
2526 MenuDrawPopupMenu(Wnd, ps.hdc, (HMENU)GetWindowLongPtrW(Wnd, 0));
2527 EndPaint(Wnd, &ps);
2528 return 0;
2529 }
2530
2531 case WM_PRINTCLIENT:
2532 {
2533 MenuDrawPopupMenu( Wnd, (HDC)wParam,
2534 (HMENU)GetWindowLongPtrW( Wnd, 0 ) );
2535 return 0;
2536 }
2537
2538 case WM_ERASEBKGND:
2539 return 1;
2540
2541 case WM_DESTROY:
2542 /* zero out global pointer in case resident popup window was destroyed. */
2543 if (Wnd == top_popup)
2544 {
2545 top_popup = NULL;
2546 top_popup_hmenu = NULL;
2547 }
2548 break;
2549
2550 #ifdef __REACTOS__
2551 case WM_NCDESTROY:
2552 NtUserSetWindowFNID(Wnd, FNID_DESTROY);
2553 break;
2554 #endif
2555
2556 case WM_SHOWWINDOW:
2557 if (0 != wParam)
2558 {
2559 if (0 == GetWindowLongPtrW(Wnd, 0))
2560 {
2561 OutputDebugStringA("no menu to display\n");
2562 }
2563 }
2564 else
2565 {
2566 SetWindowLongPtrW(Wnd, 0, 0);
2567 }
2568 break;
2569
2570 case MM_SETMENUHANDLE:
2571 SetWindowLongPtrW(Wnd, 0, wParam);
2572 break;
2573
2574 case MM_GETMENUHANDLE:
2575 case MN_GETHMENU:
2576 return GetWindowLongPtrW(Wnd, 0);
2577
2578 default:
2579 return DefWindowProcW(Wnd, Message, wParam, lParam);
2580 }
2581
2582 return 0;
2583 }
2584
2585 //
2586 // This breaks some test results. Should handle A2U if called!
2587 //
2588 LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
2589 {
2590 PWND pWnd;
2591
2592 pWnd = ValidateHwnd(Wnd);
2593 if (pWnd && !pWnd->fnid && Message != WM_NCCREATE)
2594 {
2595 return DefWindowProcA(Wnd, Message, wParam, lParam);
2596 }
2597 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
2598
2599 switch(Message)
2600 {
2601 case WM_NCCREATE:
2602 case WM_CREATE:
2603 case WM_MOUSEACTIVATE:
2604 case WM_PAINT:
2605 case WM_PRINTCLIENT:
2606 case WM_ERASEBKGND:
2607 case WM_DESTROY:
2608 case WM_NCDESTROY:
2609 case WM_SHOWWINDOW:
2610 case MM_SETMENUHANDLE:
2611 case MM_GETMENUHANDLE:
2612 case MN_GETHMENU:
2613 return PopupMenuWndProcW(Wnd, Message, wParam, lParam);
2614
2615 default:
2616 return DefWindowProcA(Wnd, Message, wParam, lParam);
2617 }
2618 return 0;
2619 }
2620
2621 /**********************************************************************
2622 * MENU_ParseResource
2623 *
2624 * Parse a standard menu resource and add items to the menu.
2625 * Return a pointer to the end of the resource.
2626 *
2627 * NOTE: flags is equivalent to the mtOption field
2628 */
2629 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu)
2630 {
2631 WORD flags, id = 0;
2632 HMENU hSubMenu;
2633 LPCWSTR str;
2634 BOOL end = FALSE;
2635
2636 do
2637 {
2638 flags = GET_WORD(res);
2639
2640 /* remove MF_END flag before passing it to AppendMenu()! */
2641 end = (flags & MF_END);
2642 if(end) flags ^= MF_END;
2643
2644 res += sizeof(WORD);
2645 if(!(flags & MF_POPUP))
2646 {
2647 id = GET_WORD(res);
2648 res += sizeof(WORD);
2649 }
2650 str = (LPCWSTR)res;
2651 res += (strlenW(str) + 1) * sizeof(WCHAR);
2652
2653 if (flags & MF_POPUP)
2654 {
2655 hSubMenu = CreatePopupMenu();
2656 if(!hSubMenu) return NULL;
2657 if(!(res = MENU_ParseResource(res, hSubMenu))) return NULL;
2658 AppendMenuW(hMenu, flags, (UINT_PTR)hSubMenu, (LPCWSTR)str);
2659 }
2660 else /* Not a popup */
2661 {
2662 AppendMenuW(hMenu, flags, id, *(LPCWSTR)str ? (LPCWSTR)str : NULL);
2663 }
2664 } while(!end);
2665 return res;
2666 }
2667
2668 /**********************************************************************
2669 * MENUEX_ParseResource
2670 *
2671 * Parse an extended menu resource and add items to the menu.
2672 * Return a pointer to the end of the resource.
2673 */
2674 static LPCSTR MENUEX_ParseResource(LPCSTR res, HMENU hMenu)
2675 {
2676 WORD resinfo;
2677 do
2678 {
2679 MENUITEMINFOW mii;
2680
2681 mii.cbSize = sizeof(mii);
2682 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
2683 mii.fType = GET_DWORD(res);
2684 res += sizeof(DWORD);
2685 mii.fState = GET_DWORD(res);
2686 res += sizeof(DWORD);
2687 mii.wID = GET_DWORD(res);
2688 res += sizeof(DWORD);
2689 resinfo = GET_WORD(res);
2690 res += sizeof(WORD);
2691 /* Align the text on a word boundary. */
2692 res += (~((UINT_PTR)res - 1)) & 1;
2693 mii.dwTypeData = (LPWSTR)res;
2694 mii.cch = strlenW(mii.dwTypeData);
2695 res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
2696 /* Align the following fields on a dword boundary. */
2697 res += (~((UINT_PTR)res - 1)) & 3;
2698
2699 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
2700 mii.fType, mii.fState, mii.wID, resinfo, mii.dwTypeData);
2701
2702 if (resinfo & 1) /* Pop-up? */
2703 {
2704 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2705 res += sizeof(DWORD);
2706 mii.hSubMenu = CreatePopupMenu();
2707 if (!mii.hSubMenu)
2708 {
2709 ERR("CreatePopupMenu failed\n");
2710 return NULL;
2711 }
2712
2713 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu)))
2714 {
2715 ERR("MENUEX_ParseResource failed\n");
2716 DestroyMenu(mii.hSubMenu);
2717 return NULL;
2718 }
2719 mii.fMask |= MIIM_SUBMENU;
2720 }
2721 else if (!mii.dwTypeData[0] && !(mii.fType & MF_SEPARATOR))
2722 {
2723 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
2724 mii.wID, mii.fType);
2725 mii.fType |= MF_SEPARATOR;
2726 }
2727 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
2728 } while (!(resinfo & MF_END));
2729 return res;
2730 }
2731
2732
2733 /***********************************************************************
2734 * DrawMenuBarTemp (USER32.@)
2735 *
2736 * UNDOCUMENTED !!
2737 *
2738 * called by W98SE desk.cpl Control Panel Applet
2739 *
2740 * Not 100% sure about the param names, but close.
2741 *
2742 * @implemented
2743 */
2744 DWORD WINAPI
2745 DrawMenuBarTemp(HWND Wnd, HDC DC, LPRECT Rect, HMENU Menu, HFONT Font)
2746 {
2747 ROSMENUINFO MenuInfo;
2748 ROSMENUITEMINFO ItemInfo;
2749 UINT i;
2750 HFONT FontOld = NULL;
2751 BOOL flat_menu = FALSE;
2752
2753 SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
2754
2755 if (NULL == Menu)
2756 {
2757 Menu = GetMenu(Wnd);
2758 }
2759
2760 if (NULL == Font)
2761 {
2762 Font = hMenuFont;
2763 }
2764
2765 if (NULL == Rect || ! MenuGetRosMenuInfo(&MenuInfo, Menu))
2766 {
2767 return GetSystemMetrics(SM_CYMENU);
2768 }
2769
2770 TRACE("(%x, %x, %p, %x, %x)\n", Wnd, DC, Rect, Menu, Font);
2771
2772 FontOld = SelectObject(DC, Font);
2773
2774 if (0 == MenuInfo.cyMenu)
2775 {
2776 MenuMenuBarCalcSize(DC, Rect, &MenuInfo, Wnd);
2777 }
2778
2779 Rect->bottom = Rect->top + MenuInfo.cyMenu;
2780
2781 FillRect(DC, Rect, GetSysColorBrush(flat_menu ? COLOR_MENUBAR : COLOR_MENU));
2782
2783 SelectObject(DC, GetStockObject(DC_PEN));
2784 SetDCPenColor(DC, GetSysColor(COLOR_3DFACE));
2785 MoveToEx(DC, Rect->left, Rect->bottom - 1, NULL);
2786 LineTo(DC, Rect->right, Rect->bottom - 1);
2787
2788 if (0 == MenuInfo.cItems)
2789 {
2790 SelectObject(DC, FontOld);
2791 return GetSystemMetrics(SM_CYMENU);
2792 }
2793
2794 MenuInitRosMenuItemInfo(&ItemInfo);
2795 for (i = 0; i < MenuInfo.cItems; i++)
2796 {
2797 if (MenuGetRosMenuItemInfo(MenuInfo.Self, i, &ItemInfo))
2798 {
2799 MenuDrawMenuItem(Wnd, &MenuInfo, Wnd, DC, &ItemInfo,
2800 MenuInfo.cyMenu, TRUE, ODA_DRAWENTIRE);
2801 }
2802 }
2803 MenuCleanupRosMenuItemInfo(&ItemInfo);
2804
2805 SelectObject(DC, FontOld);
2806
2807 return MenuInfo.cyMenu;
2808 }
2809
2810
2811 /***********************************************************************
2812 * MenuShowSubPopup
2813 *
2814 * Display the sub-menu of the selected item of this menu.
2815 * Return the handle of the submenu, or menu if no submenu to display.
2816 */
2817 static HMENU FASTCALL
2818 MenuShowSubPopup(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SelectFirst, UINT Flags)
2819 {
2820 RECT Rect;
2821 ROSMENUITEMINFO ItemInfo;
2822 ROSMENUINFO SubMenuInfo;
2823 HDC Dc;
2824 HMENU Ret;
2825
2826 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner, MenuInfo, SelectFirst);
2827
2828 if (MenuInfo->iItem == NO_SELECTED_ITEM) return MenuInfo->Self;
2829
2830 MenuInitRosMenuItemInfo(&ItemInfo);
2831 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo))
2832 {
2833 MenuCleanupRosMenuItemInfo(&ItemInfo);
2834 return MenuInfo->Self;
2835 }
2836
2837 //item = &menu->rgItems[menu->iItem];
2838 if (!(ItemInfo.hSubMenu) || (ItemInfo.fState & (MF_GRAYED | MF_DISABLED)))
2839 {
2840 MenuCleanupRosMenuItemInfo(&ItemInfo);
2841 return MenuInfo->Self;
2842 }
2843
2844 /* message must be sent before using item,
2845 because nearly everything may be changed by the application ! */
2846
2847 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2848 if (!(Flags & TPM_NONOTIFY))
2849 {
2850 SendMessageW(WndOwner, WM_INITMENUPOPUP, (WPARAM) ItemInfo.hSubMenu,
2851 MAKELPARAM(MenuInfo->iItem, IS_SYSTEM_MENU(MenuInfo)));
2852 }
2853
2854 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo))
2855 {
2856 MenuCleanupRosMenuItemInfo(&ItemInfo);
2857 return MenuInfo->Self;
2858 }
2859
2860 //item = &menu->rgItems[menu->iItem];
2861 Rect = ItemInfo.Rect;
2862
2863 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2864 if (!(ItemInfo.fState & MF_HILITE))
2865 {
2866 if (MenuInfo->fFlags & MNF_POPUP) Dc = GetDC(MenuInfo->Wnd);
2867 else Dc = GetDCEx(MenuInfo->Wnd, 0, DCX_CACHE | DCX_WINDOW);
2868
2869 SelectObject(Dc, hMenuFont);
2870 ItemInfo.fMask |= MIIM_STATE;
2871 ItemInfo.fState |= MF_HILITE;
2872 MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo);
2873 MenuDrawMenuItem(MenuInfo->Wnd, MenuInfo, WndOwner, Dc, &ItemInfo, MenuInfo->cyMenu,
2874 !(MenuInfo->fFlags & MNF_POPUP), ODA_DRAWENTIRE);
2875 ReleaseDC(MenuInfo->Wnd, Dc);
2876 }
2877
2878 if (!ItemInfo.Rect.top && !ItemInfo.Rect.left && !ItemInfo.Rect.bottom && !ItemInfo.Rect.right)
2879 ItemInfo.Rect = Rect;
2880
2881 ItemInfo.fMask |= MIIM_STATE;
2882 ItemInfo.fState |= MF_MOUSESELECT;
2883 MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo);
2884
2885 if (IS_SYSTEM_MENU(MenuInfo))
2886 {
2887 MenuInitSysMenuPopup(ItemInfo.hSubMenu,
2888 GetWindowLongPtrW(MenuInfo->Wnd, GWL_STYLE),
2889 GetClassLongPtrW(MenuInfo->Wnd, GCL_STYLE), HTSYSMENU);
2890
2891 NcGetSysPopupPos(MenuInfo->Wnd, &Rect);
2892 if (Flags & TPM_LAYOUTRTL) Rect.left = Rect.right;
2893 Rect.top = Rect.bottom;
2894 Rect.right = GetSystemMetrics(SM_CXSIZE);
2895 Rect.bottom = GetSystemMetrics(SM_CYSIZE);
2896 }
2897 else
2898 {
2899 GetWindowRect(MenuInfo->Wnd, &Rect);
2900 if (MenuInfo->fFlags & MNF_POPUP)
2901 {
2902 RECT rc = ItemInfo.Rect;
2903
2904 MENU_AdjustMenuItemRect(MenuInfo, &rc);
2905
2906 /* The first item in the popup menu has to be at the
2907 same y position as the focused menu item */
2908 if(Flags & TPM_LAYOUTRTL)
2909 Rect.left += GetSystemMetrics(SM_CXBORDER);
2910 else
2911 Rect.left += rc.right /*ItemInfo.Rect.right*/ - GetSystemMetrics(SM_CXBORDER);
2912 Rect.top += rc.top - MENU_TOP_MARGIN;//3;
2913 Rect.right = rc.left - rc.right + GetSystemMetrics(SM_CXBORDER);
2914 Rect.bottom = rc.top - rc.bottom - MENU_TOP_MARGIN - MENU_BOTTOM_MARGIN/*2*/
2915 - GetSystemMetrics(SM_CYBORDER);
2916 }
2917 else
2918 {
2919 if(Flags & TPM_LAYOUTRTL)
2920 Rect.left += Rect.right - ItemInfo.Rect.left;
2921 else
2922 Rect.left += ItemInfo.Rect.left;
2923 Rect.top += ItemInfo.Rect.bottom;
2924 Rect.right = ItemInfo.Rect.right - ItemInfo.Rect.left;
2925 Rect.bottom = ItemInfo.Rect.bottom - ItemInfo.Rect.top;
2926 }
2927 }
2928
2929 /* use default alignment for submenus */
2930 Flags &= ~(TPM_CENTERALIGN | TPM_RIGHTALIGN | TPM_VCENTERALIGN | TPM_BOTTOMALIGN);
2931
2932 MENU_InitPopup( WndOwner, ItemInfo.hSubMenu, Flags );
2933
2934 MenuShowPopup(WndOwner, ItemInfo.hSubMenu, MenuInfo->iItem, Flags,
2935 Rect.left, Rect.top, Rect.right, Rect.bottom );
2936 if (SelectFirst && MenuGetRosMenuInfo(&SubMenuInfo, ItemInfo.hSubMenu))
2937 {
2938 MenuMoveSelection(WndOwner, &SubMenuInfo, ITEM_NEXT);
2939 }
2940
2941 Ret = ItemInfo.hSubMenu;
2942 MenuCleanupRosMenuItemInfo(&ItemInfo);
2943
2944 return Ret;
2945 }
2946
2947 /**********************************************************************
2948 * MENU_EndMenu
2949 *
2950 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2951 *
2952 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2953 */
2954 void MENU_EndMenu( HWND hwnd )
2955 {
2956 MENU *menu;
2957 menu = top_popup_hmenu ? MENU_GetMenu( top_popup_hmenu ) : NULL;
2958 if (menu && ( hwnd == menu->hWnd || hwnd == (menu->spwndNotify ? menu->spwndNotify->head.h : NULL)) )
2959 EndMenu();
2960 }
2961
2962 /***********************************************************************
2963 * MenuHideSubPopups
2964 *
2965 * Hide the sub-popup menus of this menu.
2966 */
2967 static void FASTCALL
2968 MenuHideSubPopups(HWND WndOwner, PROSMENUINFO MenuInfo,
2969 BOOL SendMenuSelect, UINT wFlags)
2970 {
2971 ROSMENUINFO SubMenuInfo;
2972 ROSMENUITEMINFO ItemInfo;
2973
2974 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner, MenuInfo, SendMenuSelect);
2975
2976 if (MenuInfo && top_popup && NO_SELECTED_ITEM != MenuInfo->iItem)
2977 {
2978 //item = &menu->rgItems[menu->iItem];
2979 MenuInitRosMenuItemInfo(&ItemInfo);
2980 ItemInfo.fMask |= MIIM_FTYPE | MIIM_STATE;
2981 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo)
2982 || !(ItemInfo.hSubMenu)
2983 || !(ItemInfo.fState & MF_MOUSESELECT))
2984 {
2985 MenuCleanupRosMenuItemInfo(&ItemInfo);
2986 return;
2987 }
2988 ItemInfo.fState &= ~MF_MOUSESELECT;
2989 ItemInfo.fMask |= MIIM_STATE;
2990 MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo);
2991 if (MenuGetRosMenuInfo(&SubMenuInfo, ItemInfo.hSubMenu))
2992 {
2993 MenuHideSubPopups(WndOwner, &SubMenuInfo, FALSE, wFlags);
2994 MenuSelectItem(WndOwner, &SubMenuInfo, NO_SELECTED_ITEM, SendMenuSelect, NULL);
2995
2996 DestroyWindow(SubMenuInfo.Wnd);
2997 /* Native returns handle to destroyed window */
2998 if (!(wFlags & TPM_NONOTIFY))
2999 SendMessageW( WndOwner, WM_UNINITMENUPOPUP, (WPARAM)ItemInfo.hSubMenu,
3000 MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo)) );
3001 ////
3002 // Call WM_UNINITMENUPOPUP FIRST before destroy!!
3003 // Fixes todo_wine User32 test menu.c line 2233 GetMenuBarInfo callback....
3004 //
3005 SubMenuInfo.Wnd = NULL;
3006 MenuSetRosMenuInfo(&SubMenuInfo);
3007 ////
3008 }
3009 }
3010 }
3011
3012 /***********************************************************************
3013 * MenuSwitchTracking
3014 *
3015 * Helper function for menu navigation routines.
3016 */
3017 static void FASTCALL
3018 MenuSwitchTracking(MTRACKER* Mt, PROSMENUINFO PtMenuInfo, UINT Index, UINT wFlags)
3019 {
3020 ROSMENUINFO TopMenuInfo;
3021
3022 TRACE("%x menu=%x 0x%04x\n", Mt, PtMenuInfo->Self, Index);
3023
3024 if ( MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu) &&
3025 Mt->TopMenu != PtMenuInfo->Self &&
3026 !((PtMenuInfo->fFlags | TopMenuInfo.fFlags) & MNF_POPUP) )
3027 {
3028 /* both are top level menus (system and menu-bar) */
3029 MenuHideSubPopups(Mt->OwnerWnd, &TopMenuInfo, FALSE, wFlags);
3030 MenuSelectItem(Mt->OwnerWnd, &TopMenuInfo, NO_SELECTED_ITEM, FALSE, NULL);
3031 Mt->TopMenu = PtMenuInfo->Self;
3032 }
3033 else
3034 {
3035 MenuHideSubPopups(Mt->OwnerWnd, PtMenuInfo, FALSE, wFlags);
3036 }
3037
3038 MenuSelectItem(Mt->OwnerWnd, PtMenuInfo, Index, TRUE, NULL);
3039 }
3040
3041 /***********************************************************************
3042 * MenuExecFocusedItem
3043 *
3044 * Execute a menu item (for instance when user pressed Enter).
3045 * Return the wID of the executed item. Otherwise, -1 indicating
3046 * that no menu item was executed, -2 if a popup is shown;
3047 * Have to receive the flags for the TrackPopupMenu options to avoid
3048 * sending unwanted message.
3049 *
3050 */
3051 static INT FASTCALL
3052 MenuExecFocusedItem(MTRACKER *Mt, PROSMENUINFO MenuInfo, UINT Flags)
3053 {
3054 ROSMENUITEMINFO ItemInfo;
3055 UINT wID;
3056
3057 TRACE("%p menu=%p\n", Mt, MenuInfo);
3058
3059 if (0 == MenuInfo->cItems || NO_SELECTED_ITEM == MenuInfo->iItem)
3060 {
3061 return -1;
3062 }
3063
3064 MenuInitRosMenuItemInfo(&ItemInfo);
3065 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo))
3066 {
3067 MenuCleanupRosMenuItemInfo(&ItemInfo);
3068 return -1;
3069 }
3070
3071 TRACE("%p %08x %p\n", MenuInfo, ItemInfo.wID, ItemInfo.hSubMenu);
3072
3073 if (0 == (ItemInfo.hSubMenu))
3074 {
3075 if (0 == (ItemInfo.fState & (MF_GRAYED | MF_DISABLED))
3076 && 0 == (ItemInfo.fType & MF_SEPARATOR))
3077 {
3078 /* If TPM_RETURNCMD is set you return the id, but
3079 do not send a message to the owner */
3080 if (0 == (Flags & TPM_RETURNCMD))
3081 {
3082 if (0 != (MenuInfo->fFlags & MNF_SYSMENU))
3083 {
3084 PostMessageW(Mt->OwnerWnd, WM_SYSCOMMAND, ItemInfo.wID,
3085 MAKELPARAM((SHORT) Mt->Pt.x, (SHORT) Mt->Pt.y));
3086 }
3087 else
3088 {
3089 ROSMENUINFO topmenuI;
3090 BOOL ret = MenuGetRosMenuInfo(&topmenuI, Mt->TopMenu);
3091 DWORD dwStyle = MenuInfo->dwStyle | (ret ? topmenuI.dwStyle : 0);
3092
3093 if (dwStyle & MNS_NOTIFYBYPOS)
3094 PostMessageW(Mt->OwnerWnd, WM_MENUCOMMAND, MenuInfo->iItem, (LPARAM)MenuInfo->Self);
3095 else
3096 PostMessageW(Mt->OwnerWnd, WM_COMMAND, ItemInfo.wID, 0);
3097 }
3098 }
3099 wID = ItemInfo.wID;
3100 MenuCleanupRosMenuItemInfo(&ItemInfo);
3101 return wID;
3102 }
3103 }
3104 else
3105 {
3106 Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, MenuInfo, TRUE, Flags);
3107 return -2;
3108 }
3109
3110 return -1;
3111 }
3112
3113 /***********************************************************************
3114 * MenuButtonDown
3115 *
3116 * Return TRUE if we can go on with menu tracking.
3117 */
3118 static BOOL FASTCALL
3119 MENU_ButtonDown(MTRACKER* Mt, HMENU PtMenu, UINT Flags)
3120 {
3121 int Index;
3122 ROSMENUINFO MenuInfo;
3123 ROSMENUITEMINFO Item;
3124
3125 TRACE("%x PtMenu=%p\n", Mt, PtMenu);
3126
3127 if (NULL != PtMenu)
3128 {
3129 if (! MenuGetRosMenuInfo(&MenuInfo, PtMenu))
3130 {
3131 return FALSE;
3132 }
3133 if (IS_SYSTEM_MENU(&MenuInfo))
3134 {
3135 Index = 0;
3136