Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

menu.cpp

Go to the documentation of this file.
00001 /* $Id: menu.cpp,v 1.44 2001/12/26 11:35:39 sandervl Exp $*/
00002 /*
00003  * Menu functions
00004  *
00005  * Copyright 1993 Martin Ayotte
00006  * Copyright 1994 Alexandre Julliard
00007  * Copyright 1997 Morten Welinder
00008  *
00009  * Copyright 1999 Christoph Bratschi
00010  *
00011  * Corel version: 200005313
00012  * (WINE version: 20000130)
00013  *
00014  * Status:  ???
00015  * Version: ???
00016  */
00017 
00018 /*
00019  * Note: the style MF_MOUSESELECT is used to mark popup items that
00020  * have been selected, i.e. their popup menu is currently displayed.
00021  * This is probably not the meaning this style has in MS-Windows.
00022  */
00023 
00024 #include <assert.h>
00025 #include <ctype.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include <os2win.h>
00029 #include <heapstring.h>
00030 #include "controls.h"
00031 #include "menu.h"
00032 
00033 #ifdef __WIN32OS2__
00034 #include <objhandle.h>
00035 #include "pmwindow.h"
00036 #include "win32wmisc.h"
00037 #include "oslibmsg.h"
00038 #include "oslibwin.h"
00039 #include "syscolor.h"
00040 
00041 #define DBG_LOCALLOG    DBG_menu
00042 #include "dbglocal.h"
00043 #endif
00044 
00045 //DEFAULT_DEBUG_CHANNEL(menu)
00046 //DECLARE_DEBUG_CHANNEL(winhelp)
00047 
00048 
00049 /* internal popup menu window messages */
00050 
00051 #define MM_SETMENUHANDLE        (WM_USER + 0)
00052 #define MM_GETMENUHANDLE        (WM_USER + 1)
00053 
00054 /* Menu item structure */
00055 typedef struct {
00056     /* ----------- MENUITEMINFO Stuff ----------- */
00057     UINT fType;                 /* Item type. */
00058     UINT fState;                /* Item state.  */
00059     UINT wID;                   /* Item id.  */
00060     HMENU hSubMenu;             /* Pop-up menu.  */
00061     HBITMAP hCheckBit;          /* Bitmap when checked.  */
00062     HBITMAP hUnCheckBit;        /* Bitmap when unchecked.  */
00063     LPSTR text;                 /* Item text or bitmap handle.  */
00064     DWORD dwItemData;           /* Application defined.  */
00065     DWORD dwTypeData;           /* depends on fMask */
00066     HBITMAP hbmpItem;           /* bitmap in win98 style menus */
00067     /* ----------- Wine stuff ----------- */
00068     RECT      rect;             /* Item area (relative to menu window) */
00069     UINT      xTab;             /* X position of text after Tab */
00070 } MENUITEM;
00071 
00072 /* Popup menu structure */
00073 typedef struct {
00074     WORD        wFlags;       /* Menu flags (MF_POPUP, MF_SYSMENU) */
00075     WORD        wMagic;       /* Magic number */
00076     HQUEUE      hTaskQ;       /* Task queue for this menu */
00077     WORD        Width;        /* Width of the whole menu */
00078     WORD        Height;       /* Height of the whole menu */
00079     WORD        nItems;       /* Number of items in the menu */
00080     HWND        hWnd;         /* Window containing the menu */
00081     MENUITEM    *items;       /* Array of menu items */
00082     UINT        FocusedItem;  /* Currently focused item */
00083     HWND        hwndOwner;    /* window receiving the messages for ownerdraw */
00084     BOOL        bTimeToHide;  /* Request hiding when receiving a second click in the top-level menu item */
00085     /* ------------ MENUINFO members ------ */
00086     DWORD       dwStyle;        /* Extended mennu style */
00087     UINT        cyMax;          /* max hight of the whole menu, 0 is screen hight */
00088     HBRUSH      hbrBack;        /* brush for menu background */
00089     DWORD       dwContextHelpID;
00090     DWORD       dwMenuData;     /* application defined value */
00091     HMENU       hSysMenuOwner;  /* Handle to the dummy sys menu holder */
00092 } POPUPMENU, *LPPOPUPMENU;
00093 
00094 /* internal flags for menu tracking */
00095 
00096 #define TF_ENDMENU              0x0001
00097 #define TF_SUSPENDPOPUP         0x0002
00098 #define TF_SKIPREMOVE           0x0004
00099 
00100 typedef struct
00101 {
00102     UINT        trackFlags;
00103     HMENU       hCurrentMenu; /* current submenu (can be equal to hTopMenu)*/
00104     HMENU       hTopMenu;     /* initial menu */
00105     HWND        hOwnerWnd;    /* where notifications are sent */
00106     POINT       pt;
00107 } MTRACKER;
00108 
00109 #define MENU_MAGIC   0x554d  /* 'MU' */
00110 
00111 #define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
00112 
00113 #define ITEM_PREV               -1
00114 #define ITEM_NEXT                1
00115 
00116   /* Internal MENU_TrackMenu() flags */
00117 #define TPM_INTERNAL            0xF0000000
00118 #define TPM_ENTERIDLEEX         0x80000000              /* set owner window for WM_ENTERIDLE */
00119 #define TPM_BUTTONDOWN          0x40000000              /* menu was clicked before tracking */
00120 #define TPM_POPUPMENU           0x20000000              /* menu is a popup menu */
00121 #define TPM_CAPTIONSYSMENU      0x10000000
00122 
00123   /* popup menu shade thickness */
00124 #define POPUP_XSHADE            4
00125 #define POPUP_YSHADE            4
00126 
00127   /* Space between 2 menu bar items */
00128 #define MENU_BAR_ITEMS_SPACE 12
00129 
00130   /* Minimum width of a tab character */
00131 #define MENU_TAB_SPACE 8
00132 
00133   /* Height of a separator item */
00134 #define SEPARATOR_HEIGHT 5
00135 
00136   /* (other menu->FocusedItem values give the position of the focused item) */
00137 #define NO_SELECTED_ITEM  0xffff
00138 
00139 #define MENU_ITEM_TYPE(flags) \
00140   ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
00141 
00142 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
00143 #define IS_SEPARATOR_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_SEPARATOR)
00144 #define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
00145 
00146 #define IS_SYSTEM_MENU(menu)  \
00147         (!((menu)->wFlags & MF_POPUP) && (menu)->wFlags & MF_SYSMENU)
00148 
00149 #define IS_SYSTEM_POPUP(menu) \
00150         ((menu)->wFlags & MF_POPUP && (menu)->wFlags & MF_SYSMENU)
00151 
00152 #define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
00153                    MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
00154                    MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
00155                    MF_POPUP | MF_SYSMENU | MF_HELP)
00156 #define STATE_MASK (~TYPE_MASK)
00157 
00158   /* Dimension of the menu bitmaps */
00159 static WORD check_bitmap_width = 0, check_bitmap_height = 0;
00160 static WORD arrow_bitmap_width = 0, arrow_bitmap_height = 0;
00161 
00162 static HBITMAP hStdRadioCheck = 0;
00163 static HBITMAP hStdCheck = 0;
00164 static HBITMAP hStdMnArrow = 0;
00165 
00166 /* Minimze/restore/close buttons to be inserted in menubar */
00167 static HBITMAP hBmpMinimize = 0;
00168 static HBITMAP hBmpMinimizeD = 0;
00169 static HBITMAP hBmpMaximize = 0;
00170 static HBITMAP hBmpMaximizeD = 0;
00171 static HBITMAP hBmpClose = 0;
00172 static HBITMAP hBmpCloseD = 0;
00173 
00174 
00175 static HBRUSH   hShadeBrush = 0;
00176 static HFONT    hMenuFont = 0;
00177 static HFONT    hMenuFontBold = 0;
00178 
00179 static HMENU MENU_DefSysPopup = 0;  /* Default system menu popup */
00180 
00181 /* Use global popup window because there's no way 2 menus can
00182  * be tracked at the same time.  */
00183 
00184 static HWND pTopPopupWnd   = 0;
00185 static UINT uSubPWndLevel = 0;
00186 
00187   /* Flag set by EndMenu() to force an exit from menu tracking */
00188 static BOOL fEndMenu = FALSE;
00189 
00190 /*
00191    The following variables and defines are used to keep track of which
00192    menu item the mouse is currently over. (Used to implement a pause before
00193    popup menus are displayed. )
00194 
00195    See: MENU_MouseMove()
00196         MENU_TrackMenu()
00197 */
00198 #define     SUBMENU_POPUP_TIMERID    100
00199 #define     POPUP_MENU_DELAY         500
00200 static UINT mouseOverMenuID          = -1;
00201 static BOOL isTimerSet               = FALSE;
00202 
00203 #ifdef __WIN32OS2__
00204 static BOOL fDisableOdinSysMenuItems = FALSE;
00205 #endif
00206 
00207 /***********************************************************************
00208  *           debug_print_menuitem
00209  *
00210  * Print a menuitem in readable form.
00211  */
00212 
00213 #define debug_print_menuitem(pre, mp, post) \
00214   if(!TRACE_ON(menu)) ; else do_debug_print_menuitem(pre, mp, post)
00215 
00216 #define MENUOUT(text) \
00217   DPRINTF("%s%s", (count++ ? "," : ""), (text))
00218 
00219 #define MENUFLAG(bit,text) \
00220   do { \
00221     if (flags & (bit)) { flags &= ~(bit); MENUOUT ((text)); } \
00222   } while (0)
00223 
00224 #if 0
00225 static void do_debug_print_menuitem(const char *prefix, MENUITEM * mp,
00226                                     const char *postfix)
00227 {
00228     TRACE("%s ", prefix);
00229     if (mp) {
00230         UINT flags = mp->fType;
00231         int typ = MENU_ITEM_TYPE(flags);
00232         DPRINTF( "{ ID=0x%x", mp->wID);
00233         if (flags & MF_POPUP)
00234             DPRINTF( ", Sub=0x%x", mp->hSubMenu);
00235         if (flags) {
00236             int count = 0;
00237             DPRINTF( ", Typ=");
00238             if (typ == MFT_STRING)
00239                 /* Nothing */ ;
00240             else if (typ == MFT_SEPARATOR)
00241                 MENUOUT("sep");
00242             else if (typ == MFT_OWNERDRAW)
00243                 MENUOUT("own");
00244             else if (typ == MFT_BITMAP)
00245                 MENUOUT("bit");
00246             else
00247                 MENUOUT("???");
00248             flags -= typ;
00249 
00250             MENUFLAG(MF_POPUP, "pop");
00251             MENUFLAG(MFT_MENUBARBREAK, "barbrk");
00252             MENUFLAG(MFT_MENUBREAK, "brk");
00253             MENUFLAG(MFT_RADIOCHECK, "radio");
00254             MENUFLAG(MFT_RIGHTORDER, "rorder");
00255             MENUFLAG(MF_SYSMENU, "sys");
00256             MENUFLAG(MFT_RIGHTJUSTIFY, "right");        /* same as MF_HELP */
00257 
00258             if (flags)
00259                 DPRINTF( "+0x%x", flags);
00260         }
00261         flags = mp->fState;
00262         if (flags) {
00263             int count = 0;
00264             DPRINTF( ", State=");
00265             MENUFLAG(MFS_GRAYED, "grey");
00266             MENUFLAG(MFS_DEFAULT, "default");
00267             MENUFLAG(MFS_DISABLED, "dis");
00268             MENUFLAG(MFS_CHECKED, "check");
00269             MENUFLAG(MFS_HILITE, "hi");
00270             MENUFLAG(MF_USECHECKBITMAPS, "usebit");
00271             MENUFLAG(MF_MOUSESELECT, "mouse");
00272             if (flags)
00273                 DPRINTF( "+0x%x", flags);
00274         }
00275         if (mp->hCheckBit)
00276             DPRINTF( ", Chk=0x%x", mp->hCheckBit);
00277         if (mp->hUnCheckBit)
00278             DPRINTF( ", Unc=0x%x", mp->hUnCheckBit);
00279 
00280         if (typ == MFT_STRING) {
00281             if (mp->text)
00282                 DPRINTF( ", Text=\"%s\"", mp->text);
00283             else
00284                 DPRINTF( ", Text=Null");
00285         } else if (mp->text == NULL)
00286             /* Nothing */ ;
00287         else
00288             DPRINTF( ", Text=%p", mp->text);
00289         if (mp->dwItemData)
00290             DPRINTF( ", ItemData=0x%08lx", mp->dwItemData);
00291         DPRINTF( " }");
00292     } else {
00293         DPRINTF( "NULL");
00294     }
00295 
00296     DPRINTF(" %s\n", postfix);
00297 }
00298 #endif
00299 
00300 #undef MENUOUT
00301 #undef MENUFLAG
00302 
00303 //#define USER_HEAP_ALLOC(size) HeapAlloc(GetProcessHeap(),0,size)
00304 //#define USER_HEAP_FREE(handle) HeapFree(GetProcessHeap(),0,(LPVOID)handle)
00305 
00306 
00307 /***********************************************************************
00308  *           MENU_GetMenu
00309  *
00310  * Validate the given menu handle and returns the menu structure pointer.
00311  */
00312 POPUPMENU *MENU_GetMenu(HMENU hMenu)
00313 {
00314 #ifdef __WIN32OS2__
00315     if(ObjGetHandleType(hMenu) == USEROBJ_MENU) {
00316         POPUPMENU *menu;
00317 
00318         menu = (POPUPMENU *)ObjGetHandleData(hMenu, USEROBJ_MENU);
00319         return menu;
00320     }
00321     return NULL;
00322 #else
00323     POPUPMENU *menu;
00324     menu = (POPUPMENU*)hMenu;
00325     if (!IS_A_MENU(menu))
00326     {
00327         //ERR("invalid menu handle=%x, ptr=%p, magic=%x\n", hMenu, menu, menu? menu->wMagic:0);
00328         menu = NULL;
00329     }
00330     return menu;
00331 #endif
00332 }
00333 
00334 /***********************************************************************
00335  *           MENU_CopySysPopup
00336  *
00337  * Return the default system menu.
00338  */
00339 static HMENU MENU_CopySysPopup(void)
00340 {
00341     HMENU hMenu = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
00342 
00343     if( hMenu ) {
00344 #ifdef __WIN32OS2__
00345         POPUPMENU* menu = MENU_GetMenu(hMenu);
00346 #else
00347         POPUPMENU* menu = (POPUPMENU*)hMenu;
00348 #endif
00349         menu->wFlags |= MF_SYSMENU | MF_POPUP;
00350         SetMenuDefaultItem(hMenu, SC_CLOSE, FALSE);
00351 #ifdef __WIN32OS2__
00352         if(fDisableOdinSysMenuItems) {
00353             RemoveMenu(hMenu, 9, MF_BYPOSITION);
00354             RemoveMenu(hMenu, 9, MF_BYPOSITION);
00355             RemoveMenu(hMenu, 9, MF_BYPOSITION);
00356             RemoveMenu(hMenu, 9, MF_BYPOSITION);
00357             RemoveMenu(hMenu, 9, MF_BYPOSITION);
00358         }
00359 #ifndef DEBUG
00360         else {
00361             RemoveMenu(hMenu, SC_PUTMARK, MF_BYCOMMAND);
00362             RemoveMenu(hMenu, SC_DEBUGINT3, MF_BYCOMMAND);
00363             RemoveMenu(hMenu, 11, MF_BYPOSITION);       //separator
00364         }
00365 #endif
00366 #endif
00367     }
00368     else {
00369         hMenu = 0;
00370         //ERR("Unable to load default system menu\n" );
00371     }
00372 
00373     //TRACE("returning %x.\n", hMenu );
00374 
00375     return hMenu;
00376 }
00377 
00378 /***********************************************************************
00379  *           MENU_GetTopPopupWnd()
00380  *
00381  * Return the locked pointer pTopPopupWnd.
00382  */
00383 static HWND MENU_GetTopPopupWnd()
00384 {
00385     return pTopPopupWnd;
00386 }
00387 /***********************************************************************
00388  *           MENU_ReleaseTopPopupWnd()
00389  *
00390  * Realease the locked pointer pTopPopupWnd.
00391  */
00392 static void MENU_ReleaseTopPopupWnd()
00393 {
00394 }
00395 /***********************************************************************
00396  *           MENU_DestroyTopPopupWnd()
00397  *
00398  * Destroy the locked pointer pTopPopupWnd.
00399  */
00400 static void MENU_DestroyTopPopupWnd()
00401 {
00402     pTopPopupWnd = NULL;
00403 }
00404 
00405 
00406 
00407 /**********************************************************************
00408  *           MENU_GetSysMenu
00409  *
00410  * Create a copy of the system menu. System menu in Windows is
00411  * a special menu-bar with the single entry - system menu popup.
00412  * This popup is presented to the outside world as a "system menu".
00413  * However, the real system menu handle is sometimes seen in the
00414  * WM_MENUSELECT paramemters (and Word 6 likes it this way).
00415  */
00416 HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu )
00417 {
00418     HMENU hMenu;
00419 
00420     hMenu = CreateMenu();
00421     if (hMenu)
00422     {
00423 #ifdef __WIN32OS2__
00424         POPUPMENU *menu = MENU_GetMenu(hMenu);
00425 #else
00426         POPUPMENU *menu = (POPUPMENU*)hMenu;
00427 #endif
00428         menu->wFlags = MF_SYSMENU;
00429         menu->hWnd = hWnd;
00430 
00431         if (hPopupMenu == (HMENU)(-1))
00432             hPopupMenu = MENU_CopySysPopup();
00433         else if( !hPopupMenu ) hPopupMenu = MENU_DefSysPopup;
00434 
00435         if (hPopupMenu)
00436         {
00437             InsertMenuA( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION, hPopupMenu, NULL );
00438 
00439             menu->items[0].fType = MF_SYSMENU | MF_POPUP;
00440             menu->items[0].fState = 0;
00441 #ifdef __WIN32OS2__
00442             menu = MENU_GetMenu(hPopupMenu);
00443 #else
00444             menu = (POPUPMENU*)hPopupMenu;
00445 #endif
00446             menu->wFlags |= MF_SYSMENU;
00447 
00448             //TRACE("GetSysMenu hMenu=%04x (%04x)\n", hMenu, hPopupMenu );
00449             return hMenu;
00450         }
00451         DestroyMenu( hMenu );
00452     }
00453     //ERR("failed to load system menu!\n");
00454     return 0;
00455 }
00456 
00457 
00458 /***********************************************************************
00459  *           MENU_Init
00460  *
00461  * Menus initialisation.
00462  */
00463 BOOL MENU_Init()
00464 {
00465     HBITMAP hBitmap;
00466     NONCLIENTMETRICSA ncm;
00467 
00468     static unsigned char shade_bits[16] = { 0x55, 0, 0xAA, 0,
00469                                             0x55, 0, 0xAA, 0,
00470                                             0x55, 0, 0xAA, 0,
00471                                             0x55, 0, 0xAA, 0 };
00472 
00473     /* Load menu bitmaps */
00474     hStdCheck = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CHECK));
00475     hStdRadioCheck = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_RADIOCHECK));
00476     hStdMnArrow = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW));
00477     /* Load system buttons bitmaps */
00478     hBmpMinimize = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCE));
00479     hBmpMinimizeD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_REDUCED));
00480     hBmpMaximize = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORE));
00481     hBmpMaximizeD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_RESTORED));
00482     hBmpClose = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSE));
00483     hBmpCloseD = LoadBitmapA(0,MAKEINTRESOURCEA(OBM_CLOSED));
00484 
00485     if (hStdCheck)
00486     {
00487         BITMAP bm;
00488         GetObjectA( hStdCheck, sizeof(bm), &bm );
00489         check_bitmap_width = bm.bmWidth;
00490         check_bitmap_height = bm.bmHeight;
00491     } else
00492          return FALSE;
00493 
00494     /* Assume that radio checks have the same size as regular check.  */
00495     if (!hStdRadioCheck)
00496          return FALSE;
00497 
00498     if (hStdMnArrow)
00499     {
00500         BITMAP bm;
00501         GetObjectA( hStdMnArrow, sizeof(bm), &bm );
00502         arrow_bitmap_width = bm.bmWidth;
00503         arrow_bitmap_height = bm.bmHeight;
00504     } else
00505         return FALSE;
00506 
00507     if (! (hBitmap = CreateBitmap( 8, 8, 1, 1, shade_bits)))
00508         return FALSE;
00509 
00510     if(!(hShadeBrush = CreatePatternBrush( hBitmap )))
00511         return FALSE;
00512 
00513     DeleteObject( hBitmap );
00514     if (!(MENU_DefSysPopup = MENU_CopySysPopup()))
00515         return FALSE;
00516 
00517     ncm.cbSize = sizeof (NONCLIENTMETRICSA);
00518     if (!(SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSA), &ncm, 0)))
00519         return FALSE;
00520 
00521     if (!(hMenuFont = CreateFontIndirectA( &ncm.lfMenuFont )))
00522         return FALSE;
00523 
00524     ncm.lfMenuFont.lfWeight += 300;
00525     if ( ncm.lfMenuFont.lfWeight > 1000)
00526         ncm.lfMenuFont.lfWeight = 1000;
00527 
00528     if (!(hMenuFontBold = CreateFontIndirectA( &ncm.lfMenuFont )))
00529         return FALSE;
00530 
00531     return TRUE;
00532 }
00533 
00534 /***********************************************************************
00535  *           MENU_InitSysMenuPopup
00536  *
00537  * Grey the appropriate items in System menu.
00538  */
00539 static void MENU_InitSysMenuPopup( HMENU hmenu, DWORD style, DWORD clsStyle )
00540 {
00541     BOOL gray;
00542 
00543     gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
00544     EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
00545     gray = ((style & WS_MAXIMIZE) != 0);
00546     EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
00547     gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
00548     EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
00549     gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
00550     EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
00551     gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
00552     EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
00553     gray = (clsStyle & CS_NOCLOSE) != 0;
00554 
00555     /* The menu item must keep its state if it's disabled */
00556     if(gray)
00557         EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED);
00558 }
00559 
00560 
00561 /******************************************************************************
00562  *
00563  *   UINT32  MENU_GetStartOfNextColumn(
00564  *     HMENU32  hMenu )
00565  *
00566  *****************************************************************************/
00567 
00568 static UINT  MENU_GetStartOfNextColumn(
00569     HMENU  hMenu )
00570 {
00571 #ifdef __WIN32OS2__
00572     POPUPMENU  *menu = MENU_GetMenu(hMenu);
00573 #else
00574     POPUPMENU  *menu = (POPUPMENU*)hMenu;
00575 #endif
00576     UINT  i = menu->FocusedItem + 1;
00577 
00578     if(!menu)
00579         return NO_SELECTED_ITEM;
00580 
00581     if( i == NO_SELECTED_ITEM )
00582         return i;
00583 
00584     for( ; i < menu->nItems; ++i ) {
00585         if (menu->items[i].fType & MF_MENUBARBREAK)
00586             return i;
00587     }
00588 
00589     return NO_SELECTED_ITEM;
00590 }
00591 
00592 
00593 /******************************************************************************
00594  *
00595  *   UINT32  MENU_GetStartOfPrevColumn(
00596  *     HMENU32  hMenu )
00597  *
00598  *****************************************************************************/
00599 
00600 static UINT  MENU_GetStartOfPrevColumn(
00601     HMENU  hMenu )
00602 {
00603 #ifdef __WIN32OS2__
00604     POPUPMENU const  *menu = MENU_GetMenu(hMenu);
00605 #else
00606     POPUPMENU const  *menu = (POPUPMENU*)hMenu;
00607 #endif
00608     UINT  i;
00609 
00610     if( !menu )
00611         return NO_SELECTED_ITEM;
00612 
00613     if( menu->FocusedItem == 0 || menu->FocusedItem == NO_SELECTED_ITEM )
00614         return NO_SELECTED_ITEM;
00615 
00616     /* Find the start of the column */
00617 
00618     for(i = menu->FocusedItem; i != 0 &&
00619          !(menu->items[i].fType & MF_MENUBARBREAK);
00620         --i); /* empty */
00621 
00622     if(i == 0)
00623         return NO_SELECTED_ITEM;
00624 
00625     for(--i; i != 0; --i) {
00626         if (menu->items[i].fType & MF_MENUBARBREAK)
00627             break;
00628     }
00629 
00630     //TRACE("ret %d.\n", i );
00631 
00632     return i;
00633 }
00634 
00635 
00636 
00637 /***********************************************************************
00638  *           MENU_FindItem
00639  *
00640  * Find a menu item. Return a pointer on the item, and modifies *hmenu
00641  * in case the item was in a sub-menu.
00642  */
00643 static MENUITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
00644 {
00645     POPUPMENU *menu;
00646     UINT i;
00647 
00648     if (((*hmenu)==0xffff) || (!(menu = MENU_GetMenu(*hmenu)))) return NULL;
00649     if (!menu) return NULL;
00650     if (wFlags & MF_BYPOSITION)
00651     {
00652         if (*nPos >= menu->nItems) return NULL;
00653         return &menu->items[*nPos];
00654     }
00655     else
00656     {
00657         MENUITEM *item = menu->items;
00658 
00659         for (i = 0; i < menu->nItems; i++, item++)
00660         {
00661             if (item->wID == *nPos)
00662             {
00663                 *nPos = i;
00664                 return item;
00665             }
00666             else if (item->fType & MF_POPUP)
00667             {
00668                 HMENU hsubmenu = item->hSubMenu;
00669                 MENUITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
00670 #ifdef __WIN32OS2__
00671                 if (subitem && subitem!=item)
00672 #else
00673                 if (subitem)
00674 #endif
00675                 {
00676                     *hmenu = hsubmenu;
00677                     return subitem;
00678                 }
00679             }
00680         }
00681     }
00682     return NULL;
00683 }
00684 
00685 /***********************************************************************
00686  *           MENU_FindSubMenu
00687  *
00688  * Find a Sub menu. Return the position of the submenu, and modifies
00689  * *hmenu in case it is found in another sub-menu.
00690  * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
00691  */
00692 UINT MENU_FindSubMenu( HMENU *hmenu, HMENU hSubTarget )
00693 {
00694     POPUPMENU *menu;
00695     UINT i;
00696     MENUITEM *item;
00697     if (((*hmenu)==0xffff) ||
00698             (!(menu = MENU_GetMenu(*hmenu))))
00699         return NO_SELECTED_ITEM;
00700     item = menu->items;
00701     for (i = 0; i < menu->nItems; i++, item++) {
00702         if(!(item->fType & MF_POPUP)) continue;
00703         if (item->hSubMenu == hSubTarget) {
00704             return i;
00705         }
00706         else  {
00707             HMENU hsubmenu = item->hSubMenu;
00708             UINT pos = MENU_FindSubMenu( &hsubmenu, hSubTarget );
00709             if (pos != NO_SELECTED_ITEM) {
00710                 *hmenu = hsubmenu;
00711                 return pos;
00712             }
00713         }
00714     }
00715     return NO_SELECTED_ITEM;
00716 }
00717 
00718 /***********************************************************************
00719  *           MENU_FreeItemData
00720  */
00721 static void MENU_FreeItemData( MENUITEM* item )
00722 {
00723     /* delete text */
00724     if (IS_STRING_ITEM(item->fType) && item->text)
00725         HeapFree(GetProcessHeap(), 0, item->text );
00726 }
00727 
00728 /***********************************************************************
00729  *           MENU_FindItemByCoords
00730  *
00731  * Find the item at the specified coordinates (screen coords). Does
00732  * not work for child windows and therefore should not be called for
00733  * an arbitrary system menu.
00734  */
00735 static MENUITEM *MENU_FindItemByCoords( POPUPMENU *menu,
00736                                         POINT pt, UINT *pos )
00737 {
00738     MENUITEM *item;
00739     UINT i;
00740     RECT wrect;
00741 
00742     if (!GetWindowRect(menu->hWnd,&wrect)) return NULL;
00743     pt.x -= wrect.left;pt.y -= wrect.top;
00744     item = menu->items;
00745     for (i = 0; i < menu->nItems; i++, item++)
00746     {
00747         if ((pt.x >= item->rect.left) && (pt.x < item->rect.right) &&
00748             (pt.y >= item->rect.top) && (pt.y < item->rect.bottom))
00749         {
00750             if (pos) *pos = i;
00751             return item;
00752         }
00753     }
00754     return NULL;
00755 }
00756 
00757 
00758 /***********************************************************************
00759  *           MENU_FindItemByKey
00760  *
00761  * Find the menu item selected by a key press.
00762  * Return item id, -1 if none, -2 if we should close the menu.
00763  */
00764 static UINT MENU_FindItemByKey( HWND hwndOwner, HMENU hmenu,
00765                                   UINT key, BOOL forceMenuChar )
00766 {
00767     //TRACE("\tlooking for '%c' in [%04x]\n", (char)key, (UINT16)hmenu );
00768 
00769     if (!IsMenu( hmenu ))
00770     {
00771         hmenu = GetSubMenu(getSysMenu(hwndOwner), 0);
00772     }
00773 
00774     if (hmenu)
00775     {
00776         POPUPMENU *menu = MENU_GetMenu(hmenu);
00777         MENUITEM *item = menu->items;
00778         LONG menuchar;
00779 
00780         if( !forceMenuChar )
00781         {
00782              UINT i;
00783 
00784              key = toupper(key);
00785              for (i = 0; i < menu->nItems; i++, item++)
00786              {
00787                 if (item->text && (IS_STRING_ITEM(item->fType)))
00788                 {
00789                     char *p = item->text - 2;
00790                     do
00791                     {
00792                         p = strchr (p + 2, '&');
00793                     }
00794                     while (p != NULL && p [1] == '&');
00795                     if (p && (toupper(p[1]) == key)) return i;
00796                 }
00797              }
00798         }
00799         menuchar = SendMessageA( hwndOwner, WM_MENUCHAR,
00800                                    MAKEWPARAM( key, menu->wFlags ), hmenu );
00801         if (HIWORD(menuchar) == 2) return LOWORD(menuchar);
00802         if (HIWORD(menuchar) == 1) return (UINT)(-2);
00803     }
00804     return (UINT)(-1);
00805 }
00806 /***********************************************************************
00807  *           MENU_LoadMagicItem
00808  *
00809  * Load the bitmap associated with the magic menu item and its style
00810  */
00811 
00812 static HBITMAP MENU_LoadMagicItem(UINT id, BOOL hilite, DWORD dwItemData)
00813 {
00814     /*
00815      * Magic menu item id's section
00816      * These magic id's are used by windows to insert "standard" mdi
00817      * buttons (minimize,restore,close) on menu. Under windows,
00818      * these magic id's make sure the right things appear when those
00819      * bitmap buttons are pressed/selected/released.
00820      */
00821 
00822     switch(id & 0xffff)
00823     {   case HBMMENU_SYSTEM:
00824             return (dwItemData) ?
00825                 (HBITMAP)dwItemData :
00826                 (hilite ? hBmpMinimizeD : hBmpMinimize);
00827         case HBMMENU_MBAR_RESTORE:
00828             return (hilite ? hBmpMaximizeD: hBmpMaximize);
00829         case HBMMENU_MBAR_MINIMIZE:
00830             return (hilite ? hBmpMinimizeD : hBmpMinimize);
00831         case HBMMENU_MBAR_CLOSE:
00832             return (hilite ? hBmpCloseD : hBmpClose);
00833         case HBMMENU_CALLBACK:
00834         case HBMMENU_MBAR_CLOSE_D:
00835         case HBMMENU_MBAR_MINIMIZE_D:
00836         case HBMMENU_POPUP_CLOSE:
00837         case HBMMENU_POPUP_RESTORE:
00838         case HBMMENU_POPUP_MAXIMIZE:
00839         case HBMMENU_POPUP_MINIMIZE:
00840         default:
00841             //FIXME("Magic 0x%08x not implemented\n", id);
00842             return 0;
00843     }
00844 
00845 }
00846 
00847 /***********************************************************************
00848  *           MENU_CalcItemSize
00849  *
00850  * Calculate the size of the menu item and store it in lpitem->rect.
00851  */
00852 static void MENU_CalcItemSize( HDC hdc, MENUITEM *lpitem, HWND hwndOwner,
00853                                INT orgX, INT orgY, BOOL menuBar )
00854 {
00855     char *p;
00856 
00857     //TRACE("dc=0x%04x owner=0x%04x (%d,%d)\n", hdc, hwndOwner, orgX, orgY);
00858     //debug_print_menuitem("MENU_CalcItemSize: menuitem:", lpitem,
00859     //                     (menuBar ? " (MenuBar)" : ""));
00860 
00861     SetRect( &lpitem->rect, orgX, orgY, orgX, orgY );
00862 
00863     if (lpitem->fType & MF_OWNERDRAW)
00864     {
00865         MEASUREITEMSTRUCT mis;
00866         mis.CtlType    = ODT_MENU;
00867         mis.CtlID      = 0;
00868         mis.itemID     = lpitem->wID;
00869         mis.itemData   = (DWORD)lpitem->dwItemData;
00870         mis.itemHeight = 0;
00871         mis.itemWidth  = 0;
00872         SendMessageA( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
00873         lpitem->rect.bottom += mis.itemHeight;
00874         lpitem->rect.right  += mis.itemWidth;
00875 
00876         //SvL: Add size of space between two menu items (fixes RealPlayer 7 menu)
00877         if(menuBar)
00878         {
00879              lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
00880         }
00881 
00882         //TRACE("id=%04x size=%dx%d\n",
00883         //             lpitem->wID, mis.itemWidth, mis.itemHeight);
00884         return;
00885     }
00886 
00887     if (lpitem->fType & MF_SEPARATOR)
00888     {
00889         lpitem->rect.bottom += SEPARATOR_HEIGHT;
00890         return;
00891     }
00892 
00893     if (!menuBar)
00894     {
00895         lpitem->rect.right += 2 * check_bitmap_width;
00896         if (lpitem->fType & MF_POPUP)
00897             lpitem->rect.right += arrow_bitmap_width;
00898     }
00899 
00900     if (IS_BITMAP_ITEM(lpitem->fType))
00901     {
00902         BITMAP bm;
00903         HBITMAP resBmp = 0;
00904 
00905         /* Check if there is a magic menu item associated with this item */
00906         if((LOWORD((int)lpitem->text))<12)
00907         {
00908             resBmp = MENU_LoadMagicItem((int)lpitem->text, (lpitem->fType & MF_HILITE),
00909                                         lpitem->dwItemData);
00910         }
00911         else
00912             resBmp = (HBITMAP)lpitem->text;
00913 
00914         if (GetObjectA(resBmp, sizeof(bm), &bm ))
00915         {
00916             lpitem->rect.right  += bm.bmWidth;
00917             lpitem->rect.bottom += bm.bmHeight;
00918 
00919         }
00920     }
00921 
00922 
00923     /* it must be a text item - unless it's the system menu */
00924     if (!(lpitem->fType & MF_SYSMENU) && IS_STRING_ITEM( lpitem->fType ))
00925     {   SIZE size;
00926 
00927         GetTextExtentPoint32A(hdc, lpitem->text,  strlen(lpitem->text), &size);
00928 
00929         lpitem->rect.right  += size.cx;
00930         lpitem->rect.bottom += MAX (size.cy, GetSystemMetrics(SM_CYMENU)-1);
00931         lpitem->xTab = 0;
00932 
00933         if (menuBar)
00934         {
00935              lpitem->rect.right += MENU_BAR_ITEMS_SPACE;
00936         }
00937         else if ((p = strchr( lpitem->text, '\t' )) != NULL)
00938         {
00939             /* Item contains a tab (only meaningful in popup menus) */
00940             GetTextExtentPoint32A(hdc, lpitem->text, (int)(p - lpitem->text) , &size);
00941             lpitem->xTab = check_bitmap_width + MENU_TAB_SPACE + size.cx;
00942             lpitem->rect.right += MENU_TAB_SPACE;
00943         }
00944         else
00945         {
00946             if (strchr( lpitem->text, '\b' ))
00947                 lpitem->rect.right += MENU_TAB_SPACE;
00948             lpitem->xTab = lpitem->rect.right - check_bitmap_width
00949                            - arrow_bitmap_width;
00950         }
00951     }
00952     //dprintf(("MENU_CalcItemSize %x (%d,%d)-(%d,%d)", lpitem->wID, lpitem->rect.left, lpitem->rect.top, lpitem->rect.right, lpitem->rect.bottom));
00953     //TRACE("(%d,%d)-(%d,%d)\n", lpitem->rect.left, lpitem->rect.top, lpitem->rect.right, lpitem->rect.bottom);
00954 }
00955 
00956 
00957 /***********************************************************************
00958  *           MENU_PopupMenuCalcSize
00959  *
00960  * Calculate the size of a popup menu.
00961  */
00962 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, HWND hwndOwner )
00963 {
00964     MENUITEM *lpitem;
00965     HDC hdc;
00966     int start, i;
00967     int orgX, orgY, maxX, maxTab, maxTabWidth;
00968 
00969     lppop->Width = lppop->Height = 0;
00970     if (lppop->nItems == 0) return;
00971 #ifdef __WIN32OS2__
00972     hdc = CreateCompatibleDC( 0 );
00973 #else
00974     hdc = GetDC( 0 );
00975 #endif
00976 
00977     SelectObject( hdc, hMenuFont);
00978 
00979     start = 0;
00980     maxX = 2 ;
00981 
00982     while (start < lppop->nItems)
00983     {
00984         lpitem = &lppop->items[start];
00985         orgX = maxX;
00986         orgY = 2;
00987 
00988         maxTab = maxTabWidth = 0;
00989 
00990           /* Parse items until column break or end of menu */
00991         for (i = start; i < lppop->nItems; i++, lpitem++)
00992         {
00993             if ((i != start) &&
00994                 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
00995 
00996             MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE );
00997 
00998             if (lpitem->fType & MF_MENUBARBREAK) orgX++;
00999             maxX = MAX( maxX, lpitem->rect.right );
01000             orgY = lpitem->rect.bottom;
01001             if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
01002             {
01003                 maxTab = MAX( maxTab, lpitem->xTab );
01004                 maxTabWidth = MAX(maxTabWidth,lpitem->rect.right-lpitem->xTab);
01005             }
01006         }
01007 
01008           /* Finish the column (set all items to the largest width found) */
01009         maxX = MAX( maxX, maxTab + maxTabWidth );
01010         for (lpitem = &lppop->items[start]; start < i; start++, lpitem++)
01011         {
01012             lpitem->rect.right = maxX;
01013             if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
01014                 lpitem->xTab = maxTab;
01015 
01016         }
01017         lppop->Height = MAX( lppop->Height, orgY );
01018     }
01019 
01020     lppop->Width  = maxX;
01021 
01022     /* space for 3d border */
01023     lppop->Height += 2;
01024     lppop->Width += 2;
01025 
01026 #ifdef __WIN32OS2__
01027     DeleteDC(hdc);
01028 #else
01029     ReleaseDC( 0, hdc );
01030 #endif
01031 }
01032 
01033 
01034 /***********************************************************************
01035  *           MENU_MenuBarCalcSize
01036  *
01037  * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
01038  * height is off by 1 pixel which causes lengthy window relocations when
01039  * active document window is maximized/restored.
01040  *
01041  * Calculate the size of the menu bar.
01042  */
01043 static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect,
01044                                   LPPOPUPMENU lppop, HWND hwndOwner )
01045 {
01046     MENUITEM *lpitem;
01047     int start, i, orgX, orgY, maxY, helpPos;
01048 
01049     if ((lprect == NULL) || (lppop == NULL)) return;
01050     if (lppop->nItems == 0) return;
01051     //TRACE("left=%d top=%d right=%d bottom=%d\n",
01052     //             lprect->left, lprect->top, lprect->right, lprect->bottom);
01053     lppop->Width  = lprect->right - lprect->left;
01054     lppop->Height = 0;
01055     maxY = lprect->top;
01056     start = 0;
01057     helpPos = -1;
01058     while (start < lppop->nItems)
01059     {
01060         lpitem = &lppop->items[start];
01061         orgX = lprect->left;
01062         orgY = maxY;
01063 
01064           /* Parse items until line break or end of menu */
01065         for (i = start; i < lppop->nItems; i++, lpitem++)
01066         {
01067             if ((helpPos == -1) && (lpitem->fType & MF_HELP)) helpPos = i;
01068             if ((i != start) &&
01069                 (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
01070 
01071             //TRACE("calling MENU_CalcItemSize org=(%d, %d)\n",
01072             //             orgX, orgY );
01073             //debug_print_menuitem ("  item: ", lpitem, "");
01074             MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, TRUE );
01075 
01076             if (lpitem->rect.right > lprect->right)
01077             {
01078                 if (i != start) break;
01079                 else lpitem->rect.right = lprect->right;
01080             }
01081             maxY = MAX( maxY, lpitem->rect.bottom );
01082             orgX = lpitem->rect.right;
01083         }
01084 
01085           /* Finish the line (set all items to the largest height found) */
01086         while (start < i) lppop->items[start++].rect.bottom = maxY;
01087     }
01088 
01089     lprect->bottom = maxY;
01090     lppop->Height = lprect->bottom - lprect->top;
01091 
01092     /* Flush right all magic items and items between the MF_HELP and */
01093     /* the last item (if several lines, only move the last line) */
01094     lpitem = &lppop->items[lppop->nItems-1];
01095     orgY = lpitem->rect.top;
01096     orgX = lprect->right;
01097     for (i = lppop->nItems - 1; i >= helpPos; i--, lpitem--)
01098     {
01099         if ( !IS_BITMAP_ITEM(lpitem->fType) && ((helpPos ==-1) ? TRUE : (helpPos>i) ))
01100             break;                              /* done */
01101         if (lpitem->rect.top != orgY) break;    /* Other line */
01102         if (lpitem->rect.right >= orgX) break;  /* Too far right already */
01103         lpitem->rect.left += orgX - lpitem->rect.right;
01104         lpitem->rect.right = orgX;
01105         orgX = lpitem->rect.left;
01106     }
01107 }
01108 
01109 /***********************************************************************
01110  *           MENU_DrawMenuItem
01111  *
01112  * Draw a single menu item.
01113  */
01114 static void MENU_DrawMenuItem( HWND hwnd, HMENU hmenu, HWND hwndOwner, HDC hdc, MENUITEM *lpitem,
01115                                UINT height, BOOL menuBar, UINT odaction )
01116 {
01117     RECT rect;
01118 
01119     //debug_print_menuitem("MENU_DrawMenuItem: ", lpitem, "");
01120 
01121     if (lpitem->fType & MF_SYSMENU) return;
01122 
01123     if (lpitem->fType & MF_OWNERDRAW)
01124     {
01125         DRAWITEMSTRUCT dis;
01126 
01127         dis.CtlType   = ODT_MENU;
01128         dis.CtlID     = 0;
01129         dis.itemID    = lpitem->wID;
01130         dis.itemData  = (DWORD)lpitem->dwItemData;
01131         dis.itemState = 0;
01132         if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
01133         if (lpitem->fState & MF_GRAYED)  dis.itemState |= ODS_GRAYED;
01134         if (lpitem->fState & MF_HILITE)  dis.itemState |= ODS_SELECTED;
01135         dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
01136         dis.hwndItem   = hmenu;
01137         dis.hDC        = hdc;
01138         dis.rcItem     = lpitem->rect;
01139         //TRACE("Ownerdraw: owner=%04x itemID=%d, itemState=%d, itemAction=%d, "
01140         //      "hwndItem=%04x, hdc=%04x, rcItem={%d,%d,%d,%d}\n", hwndOwner,
01141         //      dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
01142         //      dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
01143         //      dis.rcItem.bottom);
01144         SendMessageA( hwndOwner, WM_DRAWITEM, 0, (LPARAM)&dis );
01145         return;
01146     }
01147 
01148     //TRACE("rect={%d,%d,%d,%d}\n", lpitem->rect.left, lpitem->rect.top,
01149     //                                    lpitem->rect.right,lpitem->rect.bottom);
01150 
01151     if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
01152 
01153     rect = lpitem->rect;
01154 
01155     //CB: todo: does Win98 use DrawEdge for menubars?
01156 
01157     if ((lpitem->fState & MF_HILITE) && !(IS_BITMAP_ITEM(lpitem->fType)))
01158 #ifdef __WIN32OS2__
01159             if(fOS2Look) 
01160                  FillRect( hdc, &rect, GetOS2ColorBrush(PMSYSCLR_MENUHILITEBGND) );
01161             else FillRect( hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT) );
01162 #else
01163             FillRect( hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT) );
01164 #endif
01165     else {
01166         //SvL: TODO: Bug in GDI32; draws black rectangle instead of menu color
01167         ///          for everything except the 1st menu item
01168         RECT dummy = rect;
01169 
01170         FillRect( hdc, &dummy, GetSysColorBrush(COLOR_HIGHLIGHT) );
01171         FillRect( hdc, &rect, GetSysColorBrush(COLOR_MENU) ); //CB: back color switching bug?
01172     }
01173 
01174     SetBkMode( hdc, TRANSPARENT );
01175 
01176     /* vertical separator */
01177     if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
01178     {
01179             RECT rc = rect;
01180             rc.top = 3;
01181             rc.bottom = height - 3;
01182             DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
01183     }
01184 
01185     /* horizontal separator */
01186     if (lpitem->fType & MF_SEPARATOR)
01187     {
01188             RECT rc = rect;
01189             rc.left++;
01190             rc.right--;
01191             rc.top += SEPARATOR_HEIGHT / 2;
01192             DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
01193         return;
01194     }
01195 
01196       /* Setup colors */
01197 
01198     if ((lpitem->fState & MF_HILITE) && !(IS_BITMAP_ITEM(lpitem->fType)) )
01199     {
01200         if (lpitem->fState & MF_GRAYED)
01201             SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
01202 #if 1 //CB: WINE's Win98 menubar -> to check
01203 
01204         else
01205             SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
01206 #else
01207         else
01208         {
01209           if (menuBar)
01210             SetTextColor(hdc,GetSysColor(COLOR_MENUTEXT));
01211           else
01212             SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
01213         }
01214 #endif
01215         SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
01216     }
01217     else
01218     {
01219         if (lpitem->fState & MF_GRAYED)
01220             SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
01221         else
01222             SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
01223         SetBkColor( hdc, GetSysColor( COLOR_MENU ) );
01224     }
01225 
01226         /* helper lines for debugging */
01227 /*      FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
01228         SelectObject( hdc, GetSysColorPen(COLOR_WINDOWFRAME) );
01229         MoveTo( hdc, rect.left, (rect.top + rect.bottom)/2,NULL);
01230         LineTo( hdc, rect.right, (rect.top + rect.bottom)/2 );
01231 */
01232 
01233     if (!menuBar)
01234     {
01235         INT     y = rect.top + rect.bottom;
01236 
01237           /* Draw the check mark
01238            *
01239            * FIXME:
01240            * Custom checkmark bitmaps are monochrome but not always 1bpp.
01241            */
01242 
01243         if (lpitem->fState & MF_CHECKED)
01244         {
01245             HBITMAP bm = lpitem->hCheckBit ? lpitem->hCheckBit :
01246                         ((lpitem->fType & MFT_RADIOCHECK) ? hStdRadioCheck : hStdCheck);
01247             HDC hdcMem = CreateCompatibleDC( hdc );
01248 
01249             SelectObject( hdcMem, bm );
01250             BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
01251                       check_bitmap_width, check_bitmap_height,
01252                       hdcMem, 0, 0, (lpitem->fState & MF_HILITE) ? MERGEPAINT : SRCAND );
01253             DeleteDC( hdcMem );
01254         }
01255         else if (lpitem->hUnCheckBit)
01256         {
01257             HDC hdcMem = CreateCompatibleDC( hdc );
01258 
01259             SelectObject( hdcMem, lpitem->hUnCheckBit );
01260             BitBlt( hdc, rect.left, (y - check_bitmap_height) / 2,
01261                       check_bitmap_width, check_bitmap_height,
01262                       hdcMem, 0, 0, (lpitem->fState & MF_HILITE) ? MERGEPAINT : SRCAND );
01263             DeleteDC( hdcMem );
01264         }
01265 
01266           /* Draw the popup-menu arrow */
01267         if (lpitem->fType & MF_POPUP)
01268         {
01269             HDC hdcMem = CreateCompatibleDC( hdc );
01270 
01271             SelectObject( hdcMem, hStdMnArrow );
01272             BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
01273                       (y - arrow_bitmap_height) / 2,
01274                       arrow_bitmap_width, arrow_bitmap_height,
01275                       hdcMem, 0, 0, (lpitem->fState & MF_HILITE) ? MERGEPAINT : SRCAND );
01276             DeleteDC( hdcMem );
01277         }
01278 
01279         rect.left += check_bitmap_width;
01280         rect.right -= arrow_bitmap_width;
01281     }
01282 
01283     /* Draw the item text or bitmap */
01284     if (IS_BITMAP_ITEM(lpitem->fType))
01285     {   int top;
01286 
01287         HBITMAP resBmp = 0;
01288 
01289         HDC hdcMem = CreateCompatibleDC( hdc );
01290 
01291         /*
01292          * Check if there is a magic menu item associated with this item
01293          * and load the appropriate bitmap
01294          */
01295         if((LOWORD((int)lpitem->text)) < 12)
01296         {
01297             resBmp = MENU_LoadMagicItem((int)lpitem->text, (lpitem->fState & MF_HILITE),
01298                                         lpitem->dwItemData);
01299         }
01300         else
01301             resBmp = (HBITMAP)lpitem->text;
01302 
01303         if (resBmp)
01304         {
01305             BITMAP bm;
01306             GetObjectA( resBmp, sizeof(bm), &bm );
01307 
01308             SelectObject(hdcMem,resBmp );
01309 
01310             /* handle fontsize >  bitmap_height */
01311             top = ((rect.bottom-rect.top)>bm.bmHeight) ?
01312                 rect.top+(rect.bottom-rect.top-bm.bmHeight)/2 : rect.top;
01313 
01314             BitBlt( hdc, rect.left, top, rect.right - rect.left,
01315                   rect.bottom - rect.top, hdcMem, 0, 0, SRCCOPY );
01316         }
01317         DeleteDC( hdcMem );
01318 
01319         return;
01320 
01321     }
01322     /* No bitmap - process text if present */
01323     else if (IS_STRING_ITEM(lpitem->fType))
01324     {
01325         register int i;
01326         HFONT hfontOld = 0;
01327 
01328         UINT uFormat = (menuBar) ?
01329                         DT_CENTER | DT_VCENTER | DT_SINGLELINE :
01330                         DT_LEFT | DT_VCENTER | DT_SINGLELINE;
01331 
01332         if ( lpitem->fState & MFS_DEFAULT )
01333         {
01334              hfontOld = SelectObject( hdc, hMenuFontBold);
01335         }
01336 
01337         if (menuBar)
01338         {
01339             rect.left += MENU_BAR_ITEMS_SPACE / 2;
01340             rect.right -= MENU_BAR_ITEMS_SPACE / 2;
01341             i = strlen( lpitem->text );
01342         }
01343         else
01344         {
01345             for (i = 0; lpitem->text[i]; i++)
01346                 if ((lpitem->text[i] == '\t') || (lpitem->text[i] == '\b'))
01347                     break;
01348         }
01349 
01350         if(lpitem->fState & MF_GRAYED)
01351         {
01352             if (!(lpitem->fState & MF_HILITE) )
01353             {
01354                 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
01355                 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
01356                 DrawTextA( hdc, lpitem->text, i, &rect, uFormat );
01357                 --rect.left; --rect.top; --rect.right; --rect.bottom;
01358             }
01359             SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
01360         }
01361 
01362         DrawTextA( hdc, lpitem->text, i, &rect, uFormat);
01363 
01364         /* paint the shortcut text */
01365         if (lpitem->text[i])  /* There's a tab or flush-right char */
01366         {
01367             if (lpitem->text[i] == '\t')
01368             {
01369                 rect.left = lpitem->xTab;
01370                 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
01371             }
01372             else
01373             {
01374                 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
01375             }
01376 
01377             if(lpitem->fState & MF_GRAYED)
01378             {
01379                 if (!(lpitem->fState & MF_HILITE) )
01380                 {
01381                     ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
01382                     SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
01383                     DrawTextA( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
01384                     --rect.left; --rect.top; --rect.right; --rect.bottom;
01385                 }
01386                 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
01387             }
01388             DrawTextA( hdc, lpitem->text + i + 1, -1, &rect, uFormat );
01389         }
01390 
01391         if (hfontOld)
01392             SelectObject (hdc, hfontOld);
01393     }
01394 }
01395 
01396 
01397 /***********************************************************************
01398  *           MENU_DrawPopupMenu
01399  *
01400  * Paint a popup menu.
01401  */
01402 static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu )
01403 {
01404     HBRUSH hPrevBrush = 0;
01405     RECT rect;
01406 
01407     //TRACE("wnd=0x%04x dc=0x%04x menu=0x%04x\n", hwnd, hdc, hmenu);
01408 
01409     GetClientRect( hwnd, &rect );
01410 
01411     if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) ))
01412         && (SelectObject( hdc, hMenuFont)))
01413     {
01414         HPEN hPrevPen;
01415 
01416         Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
01417 
01418         hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
01419         if( hPrevPen )
01420         {
01421             INT ropPrev, i;
01422             POPUPMENU *menu;
01423 
01424             /* draw 3-d shade */
01425             DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
01426 
01427             /* draw menu items */
01428 
01429             menu = MENU_GetMenu(hmenu);
01430             if (menu && menu->nItems)
01431             {
01432                 MENUITEM *item;
01433                 UINT u;
01434 
01435                 for (u = menu->nItems, item = menu->items; u > 0; u--, item++)
01436                     MENU_DrawMenuItem( hwnd, hmenu, menu->hwndOwner, hdc, item,
01437                                        menu->Height, FALSE, ODA_DRAWENTIRE );
01438 
01439             }
01440         } else
01441         {
01442             SelectObject( hdc, hPrevBrush );
01443         }
01444     }
01445 }
01446 
01447 /***********************************************************************
01448  *           MENU_DrawMenuBar
01449  *
01450  * Paint a menu bar. Returns the height of the menu bar.
01451  * called from [windows/nonclient.c]
01452  */
01453 UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
01454                          BOOL suppress_draw)
01455 {
01456     LPPOPUPMENU lppop;
01457     UINT i,retvalue;
01458     HFONT hfontOld = 0;
01459 
01460     lppop = MENU_GetMenu(GetMenu(hwnd));
01461     if (lppop == NULL || lprect == NULL)
01462     {
01463         retvalue = GetSystemMetrics(SM_CYMENU);
01464         goto END;
01465     }
01466 
01467     //TRACE("(%04x, %p, %p)\n", hDC, lprect, lppop);
01468 
01469     hfontOld = SelectObject( hDC, hMenuFont);
01470 
01471     if (lppop->Height == 0)
01472         MENU_MenuBarCalcSize(hDC, lprect, lppop, hwnd);
01473 
01474     lprect->bottom = lprect->top + lppop->Height;
01475 
01476     if (suppress_draw)
01477     {
01478         retvalue = lppop->Height;
01479         goto END;
01480     }
01481 
01482     HDC memDC;
01483     HBITMAP memBmp,oldBmp;
01484     RECT r;
01485     HFONT oldMemFont;
01486 
01487     memDC = CreateCompatibleDC(hDC);
01488     r = *lprect;
01489     r.right -= r.left;
01490     r.bottom -= r.top;
01491     r.left = r.top = 0;
01492     memBmp = CreateCompatibleBitmap(hDC,r.right,r.bottom+1);
01493     oldBmp = SelectObject(memDC,memBmp);
01494     oldMemFont = SelectObject(memDC,hMenuFont);
01495 
01496     FillRect(memDC,&r,GetSysColorBrush(COLOR_MENU));
01497 
01498     SelectObject(memDC,GetSysColorPen(COLOR_3DFACE));
01499     MoveToEx(memDC,r.left,r.bottom,NULL);
01500     LineTo(memDC,r.right,r.bottom);
01501 
01502     if (lppop->nItems == 0)
01503     {
01504       retvalue = GetSystemMetrics(SM_CYMENU);
01505     } else
01506     {
01507       for (i = 0; i < lppop->nItems; i++)
01508       {
01509         OffsetRect(&lppop->items[i].rect,-lprect->left,-lprect->top);
01510         MENU_DrawMenuItem( hwnd,GetMenu(hwnd), GetWindow(hwnd,GW_OWNER),
01511                          memDC, &lppop->items[i], lppop->Height, TRUE, ODA_DRAWENTIRE );
01512         OffsetRect(&lppop->items[i].rect,lprect->left,lprect->top);
01513       }
01514       retvalue = lppop->Height;
01515     }
01516 
01517     BitBlt(hDC,lprect->left,lprect->top,lprect->right-lprect->left,lprect->bottom-lprect->top+1,memDC,0,0,SRCCOPY);
01518     SelectObject(memDC,oldBmp);
01519     if (oldMemFont) SelectObject(memDC,oldMemFont);
01520     DeleteObject(memBmp);
01521     DeleteDC(memDC);
01522 
01523 END:
01524     if (hfontOld)
01525         SelectObject (hDC, hfontOld);
01526 
01527     return retvalue;
01528 }
01529 
01530 /***********************************************************************
01531  *           MENU_PatchResidentPopup
01532  */
01533 BOOL MENU_PatchResidentPopup( HQUEUE checkQueue, HWND checkWnd )
01534 {
01535     HWND pTPWnd = MENU_GetTopPopupWnd();
01536 #if 0 //CB: todo
01537     if( pTPWnd )
01538     {
01539         HTASK hTask = 0;
01540 
01541         //TRACE("patching resident popup: %04x %04x [%04x %04x]\n",
01542         //        checkQueue, checkWnd ? checkWnd->hwndSelf : 0, pTPWnd->hmemTaskQ,
01543         //        pTPWnd->owner ? pTPWnd->owner->hwndSelf : 0);
01544 
01545         switch( checkQueue )
01546         {
01547             case 0: /* checkWnd is the new popup owner */
01548                  if( checkWnd )
01549                  {
01550                      pTPWnd->owner = checkWnd;
01551                      if( pTPWnd->hmemTaskQ != checkWnd->hmemTaskQ )
01552                          hTask = QUEUE_GetQueueTask( checkWnd->hmemTaskQ );
01553                  }
01554                  break;
01555 
01556             case 0xFFFF: /* checkWnd is destroyed */
01557                  if( pTPWnd->owner == checkWnd )
01558                      pTPWnd->owner = NULL;
01559                  MENU_ReleaseTopPopupWnd();
01560                  return TRUE;
01561 
01562             default: /* checkQueue is exiting */
01563                  if( pTPWnd->hmemTaskQ == checkQueue )
01564                  {
01565                      hTask = QUEUE_GetQueueTask( pTPWnd->hmemTaskQ );
01566                      hTask = TASK_GetNextTask( hTask );
01567                  }
01568                  break;
01569         }
01570 
01571         if( hTask )
01572         {
01573             TDB* task = (TDB*)GlobalLock( hTask );
01574             if( task )
01575             {
01576                 pTPWnd->hInstance = task->hInstance;
01577                 pTPWnd->hmemTaskQ = task->hQueue;
01578                 MENU_ReleaseTopPopupWnd();
01579                 return TRUE;
01580             }
01581             //else WARN("failed to patch resident popup.\n");
01582         }
01583     }
01584 #endif
01585     MENU_ReleaseTopPopupWnd();
01586     return FALSE;
01587 }
01588 
01589 /***********************************************************************
01590  *           MENU_ShowPopup
01591  *
01592  * Display a popup menu.
01593  */
01594 static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id,
01595                               INT x, INT y, INT xanchor, INT yanchor )
01596 {
01597     POPUPMENU   *menu;
01598 
01599     //TRACE("owner=0x%04x hmenu=0x%04x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
01600     //hwndOwner, hmenu, id, x, y, xanchor, yanchor);
01601 
01602     if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
01603     if (menu->FocusedItem != NO_SELECTED_ITEM)
01604     {
01605         menu->items[menu->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
01606         menu->FocusedItem = NO_SELECTED_ITEM;
01607     }
01608 
01609     /* store the owner for DrawItem*/
01610     menu->hwndOwner = hwndOwner;
01611 
01612     if(IsWindow(hwndOwner))
01613     {
01614         UINT    width, height;
01615 
01616         MENU_PopupMenuCalcSize( menu, hwndOwner );
01617 
01618         /* adjust popup menu pos so that it fits within the desktop */
01619 
01620         width = menu->Width + GetSystemMetrics(SM_CXBORDER);
01621         height = menu->Height + GetSystemMetrics(SM_CYBORDER);
01622 
01623         if( x + width > GetSystemMetrics(SM_CXSCREEN ))
01624         {
01625             if( xanchor )
01626                 x -= width - xanchor;
01627             if( x + width > GetSystemMetrics(SM_CXSCREEN))
01628                 x = GetSystemMetrics(SM_CXSCREEN) - width;
01629         }
01630         if( x < 0 ) x = 0;
01631 
01632         if( y + height > GetSystemMetrics(SM_CYSCREEN ))
01633         {
01634             if( yanchor )
01635                 y -= height + yanchor;
01636             if( y + height > GetSystemMetrics(SM_CYSCREEN ))
01637                 y = GetSystemMetrics(SM_CYSCREEN) - height;
01638         }
01639         if( y < 0 ) y = 0;
01640 
01641         /* NOTE: In Windows, top menu popup is not owned. */
01642         if (!pTopPopupWnd)      /* create top level popup menu window */
01643         {
01644             assert( uSubPWndLevel == 0 );
01645 
01646             pTopPopupWnd = CreateWindowA( POPUPMENUCLASSNAME, NULL,
01647                                           WS_POPUP, x, y, width, height,
01648                                           hwndOwner, 0, GetWindowLongA(hwndOwner,GWL_HINSTANCE),
01649                                           (LPVOID)hmenu );
01650             if (!pTopPopupWnd)
01651             {
01652                 DebugInt3();
01653                 return FALSE;
01654             }
01655             menu->hWnd = pTopPopupWnd;
01656             MENU_ReleaseTopPopupWnd();
01657         }
01658         else
01659             if( uSubPWndLevel )
01660             {
01661                 /* create a new window for the submenu */
01662 
01663                 menu->hWnd = CreateWindowA( POPUPMENUCLASSNAME, NULL,
01664                                           WS_POPUP, x, y, width, height,
01665                                           hwndOwner, 0, GetWindowLongA(hwndOwner,GWL_HINSTANCE),
01666                                           (LPVOID)hmenu );
01667                 if( !menu->hWnd )
01668                 {
01669                     DebugInt3();
01670                     return FALSE;
01671                 }
01672             }
01673             else /* top level popup menu window already exists */
01674             {
01675                 HWND pTPWnd = MENU_GetTopPopupWnd();
01676                 menu->hWnd = pTPWnd;
01677 
01678                 MENU_PatchResidentPopup( 0, hwndOwner );
01679                 SendMessageA( pTPWnd, MM_SETMENUHANDLE, (WPARAM)hmenu, 0L);
01680 
01681                 /* adjust its size */
01682 
01683                 SetWindowPos( menu->hWnd, 0, x, y, width, height,
01684                                 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW);
01685                 MENU_ReleaseTopPopupWnd();
01686             }
01687 
01688         uSubPWndLevel++;        /* menu level counter */
01689 
01690       /* Display the window */
01691 
01692         SetWindowPos( menu->hWnd, HWND_TOP, 0, 0, 0, 0,
01693                         SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
01694         EnableWindow(menu->hWnd,TRUE);
01695         UpdateWindow( menu->hWnd );
01696         return TRUE;
01697     }
01698     return FALSE;
01699 }
01700 
01701 
01702 /***********************************************************************
01703  *           MENU_SelectItem
01704  */
01705 static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex,
01706                              BOOL sendMenuSelect, HMENU topmenu )
01707 {
01708     LPPOPUPMENU lppop;
01709     HDC hdc;
01710 
01711     //TRACE("owner=0x%04x menu=0x%04x index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
01712 
01713     lppop = MENU_GetMenu(hmenu);
01714     if ((!lppop) || (!lppop->nItems)) return;
01715 
01716     if (lppop->FocusedItem == wIndex) return;
01717     if (lppop->wFlags & MF_POPUP) hdc = GetDC( lppop->hWnd );
01718     else hdc = GetDCEx( lppop->hWnd, 0, DCX_CACHE | DCX_WINDOW);
01719 
01720     SelectObject( hdc, hMenuFont);
01721 
01722       /* Clear previous highlighted item */
01723     if (lppop->FocusedItem != NO_SELECTED_ITEM)
01724     {
01725         lppop->items[lppop->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
01726         MENU_DrawMenuItem(lppop->hWnd, hmenu, hwndOwner, hdc,&lppop->items[lppop->FocusedItem],
01727                           lppop->Height, !(lppop->wFlags & MF_POPUP),
01728                           ODA_SELECT );
01729     }
01730 
01731       /* Highlight new item (if any) */
01732     lppop->FocusedItem = wIndex;
01733     if (lppop->FocusedItem != NO_SELECTED_ITEM)
01734     {
01735         if(!(lppop->items[wIndex].fType & MF_SEPARATOR)) {
01736             lppop->items[wIndex].fState |= MF_HILITE;
01737             MENU_DrawMenuItem( lppop->hWnd, hmenu, hwndOwner, hdc,
01738                     &lppop->items[wIndex], lppop->Height,
01739                     !(lppop->wFlags & MF_POPUP), ODA_SELECT );
01740         }
01741         if (sendMenuSelect)
01742         {
01743             MENUITEM *ip = &lppop->items[lppop->FocusedItem];
01744             SendMessageA( hwndOwner, WM_MENUSELECT,
01745                      MAKELONG(ip->fType & MF_POPUP ? wIndex: ip->wID,
01746                      ip->fType | ip->fState | MF_MOUSESELECT |
01747                      (lppop->wFlags & MF_SYSMENU)), hmenu);
01748         }
01749     }
01750     else if (sendMenuSelect) {
01751         if(topmenu){
01752             int pos;
01753             if((pos=MENU_FindSubMenu(&topmenu, hmenu))!=NO_SELECTED_ITEM){
01754 #ifdef __WIN32OS2__
01755                 POPUPMENU *ptm = MENU_GetMenu(topmenu);
01756 #else
01757                 POPUPMENU *ptm = (POPUPMENU*)topmenu;
01758 #endif
01759                 MENUITEM *ip = &ptm->items[pos];
01760                 SendMessageA( hwndOwner, WM_MENUSELECT, MAKELONG(pos,
01761                          ip->fType | ip->fState | MF_MOUSESELECT |
01762                          (ptm->wFlags & MF_SYSMENU)), topmenu);
01763             }
01764         }
01765     }
01766     ReleaseDC( lppop->hWnd, hdc );
01767 }
01768 
01769 
01770 /***********************************************************************
01771  *           MENU_MoveSelection
01772  *
01773  * Moves currently selected item according to the offset parameter.
01774  * If there is no selection then it should select the last item if
01775  * offset is ITEM_PREV or the first item if offset is ITEM_NEXT.
01776  */
01777 static void MENU_MoveSelection( HWND hwndOwner, HMENU hmenu, INT offset )
01778 {
01779     INT i;
01780     POPUPMENU *menu;
01781 
01782     //TRACE("hwnd=0x%04x hmenu=0x%04x off=0x%04x\n", hwndOwner, hmenu, offset);
01783 
01784     menu = MENU_GetMenu(hmenu);
01785     if ((!menu) || (!menu->items)) return;
01786 
01787     if ( menu->FocusedItem != NO_SELECTED_ITEM )
01788     {
01789         if( menu->nItems == 1 ) return; else
01790         for (i = menu->FocusedItem + offset ; i >= 0 && i < menu->nItems
01791                                             ; i += offset)
01792             if (!(menu->items[i].fType & MF_SEPARATOR))
01793             {
01794                 MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
01795                 return;
01796             }
01797     }
01798 
01799     for ( i = (offset > 0) ? 0 : menu->nItems - 1;
01800                   i >= 0 && i < menu->nItems ; i += offset)
01801         if (!(menu->items[i].fType & MF_SEPARATOR))
01802         {
01803             MENU_SelectItem( hwndOwner, hmenu, i, TRUE, 0 );
01804             return;
01805         }
01806 }
01807 
01808 
01809 /**********************************************************************
01810  *         MENU_SetItemData
01811  *
01812  * Set an item flags, id and text ptr. Called by InsertMenu() and
01813  * ModifyMenu().
01814  */
01815 static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT id,
01816                                 LPCSTR str )
01817 {
01818     LPSTR prevText = IS_STRING_ITEM(item->fType) ? item->text : NULL;
01819 
01820     //debug_print_menuitem("MENU_SetItemData from: ", item, "");
01821 
01822 
01823     if (IS_STRING_ITEM(flags))
01824     {
01825         if (!str || !*str)
01826         {
01827             flags |= MF_SEPARATOR;
01828             item->text = NULL;
01829         }
01830         else
01831         {
01832             LPSTR text;
01833             /* Item beginning with a backspace is a help item */
01834             if (*str == '\b')
01835             {
01836                 flags |= MF_HELP;
01837                 str++;
01838             }
01839             if (!(text = HEAP_strdupA(GetProcessHeap(), 0, str ))) return FALSE;
01840             item->text = text;
01841         }
01842     }
01843     else if (IS_BITMAP_ITEM(flags))
01844 #ifdef __WIN32OS2__
01845         //SvL: Our bitmap handles are 32 bits!
01846         item->text = (LPSTR)str;
01847 #else
01848         item->text = (LPSTR)(HBITMAP)LOWORD(str);
01849 #endif
01850     else item->text = NULL;
01851 
01852     if (flags & MF_OWNERDRAW)
01853         item->dwItemData = (DWORD)str;
01854     else
01855         item->dwItemData = 0;
01856 
01857     if ((item->fType & MF_POPUP) && (flags & MF_POPUP) && (item->hSubMenu != id) )
01858         DestroyMenu( item->hSubMenu );   /* ModifyMenu() spec */
01859 
01860     if (flags & MF_POPUP)
01861     {
01862         POPUPMENU *menu = MENU_GetMenu((UINT)id);
01863         if (IS_A_MENU(menu)) menu->wFlags |= MF_POPUP;
01864         else
01865         {
01866             item->wID = 0;
01867             item->hSubMenu = 0;
01868             item->fType = 0;
01869             item->fState = 0;
01870             return FALSE;
01871         }
01872     }
01873 
01874     item->wID = id;
01875     if (flags & MF_POPUP)
01876       item->hSubMenu = id;
01877 
01878     if ((item->fType & MF_POPUP) && !(flags & MF_POPUP) )
01879       flags |= MF_POPUP; /* keep popup */
01880 
01881     item->fType = flags & TYPE_MASK;
01882     item->fState = (flags & STATE_MASK) &
01883         ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
01884 
01885 
01886     /* Don't call SetRectEmpty here! */
01887 
01888 
01889     if (prevText) HeapFree(GetProcessHeap(), 0, prevText );
01890 
01891     //debug_print_menuitem("MENU_SetItemData to  : ", item, "");
01892     return TRUE;
01893 }
01894 
01895 
01896 /**********************************************************************
01897  *         MENU_InsertItem
01898  *
01899  * Insert a new item into a menu.
01900  */
01901 static MENUITEM *MENU_InsertItem( HMENU hMenu, UINT pos, UINT flags )
01902 {
01903     MENUITEM *newItems;
01904     POPUPMENU *menu;
01905 
01906     if (!(menu = MENU_GetMenu(hMenu)))
01907         return NULL;
01908 
01909     /* Find where to insert new item */
01910     if (flags & MF_BYPOSITION) {
01911         if (pos > menu->nItems)
01912             pos = menu->nItems;
01913     } else {
01914         if (!MENU_FindItem( &hMenu, &pos, flags ))
01915             pos = menu->nItems;
01916         else {
01917             if (!(menu = MENU_GetMenu( hMenu )))
01918                 return NULL;
01919         }
01920     }
01921     /* Create new items array */
01922 
01923     newItems = (MENUITEM*)HeapAlloc(GetProcessHeap(), 0, sizeof(MENUITEM) * (menu->nItems+1) );
01924     if (!newItems)
01925     {
01926         //WARN("allocation failed\n" );
01927         return NULL;
01928     }
01929     if (menu->nItems > 0)
01930     {
01931           /* Copy the old array into the new */
01932         if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) );
01933         if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos],
01934                                         (menu->nItems-pos)*sizeof(MENUITEM) );
01935         HeapFree(GetProcessHeap(), 0, menu->items );
01936     }
01937     menu->items = newItems;
01938     menu->nItems++;
01939     memset( &newItems[pos], 0, sizeof(*newItems) );
01940     menu->Height = 0; /* force size recalculate */
01941     return &newItems[pos];
01942 }
01943 
01944 
01945 /**********************************************************************
01946  *         MENU_ParseResource
01947  *
01948  * Parse a standard menu resource and add items to the menu.
01949  * Return a pointer to the end of the resource.
01950  */
01951 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
01952 {
01953     WORD flags, id = 0;
01954     LPCSTR str;
01955 
01956     do
01957     {
01958         flags = GET_WORD(res);
01959         res += sizeof(WORD);
01960         if (!(flags & MF_POPUP))
01961         {
01962             id = GET_WORD(res);
01963             res += sizeof(WORD);
01964         }
01965         //if (!IS_STRING_ITEM(flags))
01966         //    ERR("not a string item %04x\n", flags );
01967         str = res;
01968         if (!unicode) res += strlen(str) + 1;
01969         else res += (lstrlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
01970         if (flags & MF_POPUP)
01971         {
01972             HMENU hSubMenu = CreatePopupMenu();
01973             if (!hSubMenu) return NULL;
01974             if (!(res = MENU_ParseResource( res, hSubMenu, unicode )))
01975                 return NULL;
01976             if (!unicode) AppendMenuA( hMenu, flags, (UINT)hSubMenu, str );
01977             else AppendMenuW( hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str );
01978         }
01979         else  /* Not a popup */
01980         {
01981             if (!unicode) AppendMenuA( hMenu, flags, id, *str ? str : NULL );
01982             else AppendMenuW( hMenu, flags, id,
01983                                 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
01984         }
01985     } while (!(flags & MF_END));
01986     return res;
01987 }
01988 
01989 
01990 /**********************************************************************
01991  *         MENUEX_ParseResource
01992  *
01993  * Parse an extended menu resource and add items to the menu.
01994  * Return a pointer to the end of the resource.
01995  */
01996 static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
01997 {
01998     WORD resinfo;
01999     do {
02000         MENUITEMINFOW mii;
02001 
02002         mii.cbSize = sizeof(mii);
02003         mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
02004         mii.fType = GET_DWORD(res);
02005         res += sizeof(DWORD);
02006         mii.fState = GET_DWORD(res);
02007         res += sizeof(DWORD);
02008         mii.wID = GET_DWORD(res);
02009         res += sizeof(DWORD);
02010         resinfo = GET_WORD(res);
02011         res += sizeof(WORD);
02012         /* Align the text on a word boundary.  */
02013         res += (~((int)res - 1)) & 1;
02014         mii.dwTypeData = (LPWSTR) res;
02015         res += (1 + lstrlenW(mii.dwTypeData)) * sizeof(WCHAR);
02016         /* Align the following fields on a dword boundary.  */
02017         res += (~((int)res - 1)) & 3;
02018 
02019         /* FIXME: This is inefficient and cannot be optimised away by gcc.  */
02020         {
02021             LPSTR newstr = HEAP_strdupWtoA(GetProcessHeap(),
02022                                            0, mii.dwTypeData);
02023             //TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
02024             //             mii.fType, mii.fState, mii.wID, resinfo, newstr);
02025             HeapFree( GetProcessHeap(), 0, newstr );
02026         }
02027 
02028         if (resinfo & 1) {      /* Pop-up? */
02029             /* DWORD helpid = GET_DWORD(res); FIXME: use this.  */
02030             res += sizeof(DWORD);
02031             mii.hSubMenu = CreatePopupMenu();
02032             if (!mii.hSubMenu)
02033                 return NULL;
02034             if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
02035                 DestroyMenu(mii.hSubMenu);
02036                 return NULL;
02037         }
02038             mii.fMask |= MIIM_SUBMENU;
02039             mii.fType |= MF_POPUP;
02040         }
02041         InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
02042     } while (!(resinfo & MF_END));
02043     return res;
02044 }
02045 
02046 
02047 /***********************************************************************
02048  *           MENU_GetSubPopup
02049  *
02050  * Return the handle of the selected sub-popup menu (if any).
02051  */
02052 static HMENU MENU_GetSubPopup( HMENU hmenu )
02053 {
02054     POPUPMENU *menu;
02055     MENUITEM *item;
02056 
02057     menu = MENU_GetMenu(hmenu);
02058 
02059     if ((!menu) || (menu->FocusedItem == NO_SELECTED_ITEM)) return 0;
02060 
02061     item = &menu->items[menu->FocusedItem];
02062     if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
02063         return item->hSubMenu;
02064     return 0;
02065 }
02066 
02067 
02068 /***********************************************************************
02069  *           MENU_HideSubPopups
02070  *
02071  * Hide the sub-popup menus of this menu.
02072  */
02073 static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
02074                                 BOOL sendMenuSelect )
02075 {
02076     POPUPMENU *menu = MENU_GetMenu(hmenu);
02077 
02078     //TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, sendMenuSelect);
02079 
02080     if (menu && uSubPWndLevel)
02081     {
02082         HMENU hsubmenu;
02083         POPUPMENU *submenu;
02084         MENUITEM *item;
02085 
02086         if (menu->FocusedItem != NO_SELECTED_ITEM)
02087         {
02088             item = &menu->items[menu->FocusedItem];
02089             if (!(item->fType & MF_POPUP) ||
02090                 !(item->fState & MF_MOUSESELECT)) return;
02091             item->fState &= ~MF_MOUSESELECT;
02092             hsubmenu = item->hSubMenu;
02093         } else return;
02094 
02095         submenu = MENU_GetMenu(hsubmenu);
02096         MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
02097         MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect, 0 );
02098 
02099         if (submenu->hWnd == MENU_GetTopPopupWnd() )
02100         {
02101             DestroyWindow( submenu->hWnd );
02102             submenu->hWnd = 0;
02103 //            ShowWindow( submenu->hWnd, SW_HIDE );
02104             uSubPWndLevel = 0;
02105         }
02106         else
02107         {
02108             DestroyWindow( submenu->hWnd );
02109             submenu->hWnd = 0;
02110         }
02111         MENU_ReleaseTopPopupWnd();
02112     }
02113 }
02114 
02115 
02116 /***********************************************************************
02117  *           MENU_ShowSubPopup
02118  *
02119  * Display the sub-menu of the selected item of this menu.
02120  * Return the handle of the submenu, or hmenu if no submenu to display.
02121  */
02122 static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu,
02123                                   BOOL selectFirst, UINT wFlags,POINT *pt)
02124 {
02125     RECT rect;
02126     POPUPMENU *menu;
02127     MENUITEM *item;
02128     HDC hdc;
02129 
02130     //TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, selectFirst);
02131 
02132     if (!(menu = MENU_GetMenu(hmenu))) return hmenu;
02133 
02134     if (menu->FocusedItem == NO_SELECTED_ITEM)
02135     {
02136         return hmenu;
02137     }
02138 
02139     item = &menu->items[menu->FocusedItem];
02140     if (!(item->fType & MF_POPUP) ||
02141         (item->fState & (MF_GRAYED | MF_DISABLED)))
02142     {
02143         return hmenu;
02144     }
02145 
02146     /* message must be send before using item,
02147        because nearly everything may by changed by the application ! */
02148 
02149     /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
02150     if (!(wFlags & TPM_NONOTIFY))
02151        SendMessageA( hwndOwner, WM_INITMENUPOPUP, item->hSubMenu,
02152                    MAKELONG( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));
02153 
02154     item = &menu->items[menu->FocusedItem];
02155     rect = item->rect;
02156 
02157     /* correct item if modified as a reaction to WM_INITMENUPOPUP-message */
02158     if (!(item->fState & MF_HILITE))
02159     {
02160         if (menu->wFlags & MF_POPUP) hdc = GetDC( menu->hWnd );
02161         else hdc = GetDCEx( menu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
02162 
02163         SelectObject( hdc, hMenuFont);
02164 
02165         item->fState |= MF_HILITE;
02166         MENU_DrawMenuItem( menu->hWnd, hmenu, hwndOwner, hdc, item, menu->Height, !(menu->wFlags & MF_POPUP), ODA_DRAWENTIRE );
02167         ReleaseDC( menu->hWnd, hdc );
02168     }
02169     if (!item->rect.top && !item->rect.left && !item->rect.bottom && !item->rect.right)
02170       item->rect = rect;
02171 
02172     item->fState |= MF_MOUSESELECT;
02173 
02174     if (IS_SYSTEM_MENU(menu))
02175     {
02176         Win32BaseWindow *win32wnd = Win32BaseWindow::GetWindowFromHandle(menu->hWnd);
02177 
02178         MENU_InitSysMenuPopup(item->hSubMenu,GetWindowLongA(menu->hWnd,GWL_STYLE), GetClassLongA(menu->hWnd, GCL_STYLE));
02179 
02180         if ((wFlags & TPM_CAPTIONSYSMENU) && pt)
02181         {
02182           rect.top = pt->y;
02183           rect.left = pt->x;
02184           rect.bottom = rect.right = 0;
02185         } else
02186         {
02187           if (win32wnd) win32wnd->GetSysPopupPos(&rect);
02188           rect.top = rect.bottom;
02189           rect.right = GetSystemMetrics(SM_CXSIZE);
02190           rect.bottom = GetSystemMetrics(SM_CYSIZE);
02191         }
02192         if(win32wnd) RELEASE_WNDOBJ(win32wnd);
02193     }
02194     else
02195     {
02196         if (menu->wFlags & MF_POPUP)
02197         {
02198             RECT rectWindow;
02199 
02200             GetWindowRect(menu->hWnd,&rectWindow);
02201             rect.left = rectWindow.left + item->rect.right;
02202             rect.top = rectWindow.top + item->rect.top;
02203             rect.right = item->rect.left - item->rect.right;
02204             rect.bottom = item->rect.top - item->rect.bottom;
02205         }
02206         else
02207         {
02208             RECT rectWindow;
02209 
02210             GetWindowRect(menu->hWnd,&rectWindow);
02211             rect.left = rectWindow.left + item->rect.left;
02212             rect.top = rectWindow.top + item->rect.bottom;
02213             rect.right = item->rect.right - item->rect.left;
02214             rect.bottom = item->rect.bottom - item->rect.top;
02215         }
02216     }
02217 
02218     MENU_ShowPopup( hwndOwner, item->hSubMenu, menu->FocusedItem,
02219                     rect.left, rect.top, rect.right, rect.bottom );
02220     if (selectFirst)
02221         MENU_MoveSelection( hwndOwner, item->hSubMenu, ITEM_NEXT );
02222     return item->hSubMenu;
02223 }
02224 
02225 /***********************************************************************
02226  *           MENU_PtMenu
02227  *
02228  * Walks menu chain trying to find a menu pt maps to.
02229  */
02230 static HMENU MENU_PtMenu(HMENU hMenu,POINT pt,BOOL inMenuBar)
02231 {
02232    POPUPMENU *menu = MENU_GetMenu(hMenu);
02233    register UINT ht = menu->FocusedItem;
02234 
02235    /* try subpopup first (if any) */
02236     ht = (ht != NO_SELECTED_ITEM &&
02237           (menu->items[ht].fType & MF_POPUP) &&
02238           (menu->items[ht].fState & MF_MOUSESELECT))
02239         ? (UINT) MENU_PtMenu(menu->items[ht].hSubMenu,pt,inMenuBar) : 0;
02240 
02241    if( !ht )    /* check the current window (avoiding WM_HITTEST) */
02242    {
02243         Win32BaseWindow *win32wnd = Win32BaseWindow::GetWindowFromHandle(menu->hWnd);
02244         if(win32wnd==NULL) {
02245             //SvL: This happens in Moraff's YourJongg 2.0, return here
02246             //TODO: Check if this is supposed to happen at all...
02247             return (HMENU)0;
02248         }
02249 
02250         ht = win32wnd->HandleNCHitTest(pt);
02251         RELEASE_WNDOBJ(win32wnd);
02252         if( menu->wFlags & MF_POPUP )
02253             ht =  (ht != (UINT)HTNOWHERE &&
02254                    ht != (UINT)HTERROR) ? (UINT)hMenu : 0;
02255         else
02256         {
02257             ht = ((ht == HTSYSMENU) && !inMenuBar) ? (UINT)(getSysMenu(menu->hWnd))
02258                  : ((ht == HTMENU) && inMenuBar) ? (UINT)(GetMenu(menu->hWnd)) : 0;
02259         }
02260    }
02261    return (HMENU)ht;
02262 }
02263 
02264 /***********************************************************************
02265  *           MENU_ExecFocusedItem
02266  *
02267  * Execute a menu item (for instance when user pressed Enter).
02268  * Return the wID of the executed item. Otherwise, -1 indicating
02269  * that no menu item wase executed;
02270  * Have to receive the flags for the TrackPopupMenu options to avoid
02271  * sending unwanted message.
02272  *
02273  */
02274 static INT MENU_ExecFocusedItem( MTRACKER* pmt, HMENU hMenu, UINT wFlags )
02275 {
02276     MENUITEM *item;
02277     POPUPMENU *menu = MENU_GetMenu(hMenu);
02278 
02279     //TRACE("%p hmenu=0x%04x\n", pmt, hMenu);
02280 
02281     if (!menu || !menu->nItems ||
02282         (menu->FocusedItem == NO_SELECTED_ITEM)) return -1;
02283 
02284     item = &menu->items[menu->FocusedItem];
02285 
02286     //TRACE("%08x %08x %08x\n",
02287     //             hMenu, item->wID, item->hSubMenu);
02288 
02289     if (!(item->fType & MF_POPUP))
02290     {
02291         if (!(item->fState & (MF_GRAYED | MF_DISABLED)))
02292         {
02293             /* If TPM_RETURNCMD is set you return the id, but
02294                do not send a message to the owner */
02295             if(!(wFlags & TPM_RETURNCMD))
02296             {
02297                 if( menu->wFlags & MF_SYSMENU )
02298                     PostMessageA( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
02299                                   MAKELPARAM(pmt->pt.x, pmt->pt.y) );
02300                 else
02301                     PostMessageA( pmt->hOwnerWnd, WM_COMMAND, item->wID, 0 );
02302             }
02303             return item->wID;
02304         }
02305     }
02306     else
02307         pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hMenu, TRUE, wFlags,&pmt->pt);
02308 
02309     return -1;
02310 }
02311 
02312 /***********************************************************************
02313  *           MENU_SwitchTracking
02314  *
02315  * Helper function for menu navigation routines.
02316  */
02317 static void MENU_SwitchTracking( MTRACKER* pmt, HMENU hPtMenu, UINT id )
02318 {
02319     POPUPMENU *ptmenu = MENU_GetMenu(hPtMenu);
02320     POPUPMENU *topmenu = MENU_GetMenu(pmt->hTopMenu);
02321 
02322     //TRACE("%p hmenu=0x%04x 0x%04x\n", pmt, hPtMenu, id);
02323 
02324     if( pmt->hTopMenu != hPtMenu &&
02325         !((ptmenu->wFlags | topmenu->wFlags) & MF_POPUP) )
02326     {
02327         /* both are top level menus (system and menu-bar) */
02328         MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
02329         MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
02330         pmt->hTopMenu = hPtMenu;
02331     }
02332     else MENU_HideSubPopups( pmt->hOwnerWnd, hPtMenu, FALSE );
02333     MENU_SelectItem( pmt->hOwnerWnd, hPtMenu, id, TRUE, 0 );
02334 }
02335 
02336 
02337 /***********************************************************************
02338  *           MENU_ButtonDown
02339  *
02340  * Return TRUE if we can go on with menu tracking.
02341  */
02342 static BOOL MENU_ButtonDown( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
02343 {
02344     //TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
02345 
02346     if (hPtMenu)
02347     {
02348         UINT id = 0;
02349         POPUPMENU *ptmenu = MENU_GetMenu(hPtMenu);
02350         MENUITEM *item;
02351 
02352         if( IS_SYSTEM_MENU(ptmenu) )
02353             item = ptmenu->items;
02354         else
02355             item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
02356 
02357         if( item )
02358         {
02359             if( ptmenu->FocusedItem != id )
02360                 MENU_SwitchTracking( pmt, hPtMenu, id );
02361 
02362             /* If the popup menu is not already "popped" */
02363             if(!(item->fState & MF_MOUSESELECT ))
02364             {
02365                 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,hPtMenu,FALSE,wFlags,&pmt->pt);
02366 
02367 #ifdef __WIN32OS2__
02368                 if(fOS2Look)
02369                     ptmenu->bTimeToHide = FALSE;                    
02370 #else
02371                 /* In win31, a newly popped menu always remains opened for the next buttonup */
02372                 if(TWEAK_WineLook == WIN31_LOOK)
02373                     ptmenu->bTimeToHide = FALSE;                    
02374 #endif
02375             }
02376 
02377             return TRUE;
02378         }
02379         /* Else the click was on the menu bar, finish the tracking */
02380     }
02381     return FALSE;
02382 }
02383 
02384 /***********************************************************************
02385  *           MENU_ButtonUp
02386  *
02387  * Return the value of MENU_ExecFocusedItem if
02388  * the selected item was not a popup. Else open the popup.
02389  * A -1 return value indicates that we go on with menu tracking.
02390  *
02391  */
02392 static INT MENU_ButtonUp( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags)
02393 {
02394     //TRACE("%p hmenu=0x%04x\n", pmt, hPtMenu);
02395 
02396     if (hPtMenu)
02397     {
02398         UINT id = 0;
02399         POPUPMENU *ptmenu = MENU_GetMenu(hPtMenu);
02400         MENUITEM *item;
02401 
02402         if( IS_SYSTEM_MENU(ptmenu) )
02403             item = ptmenu->items;
02404         else
02405             item = MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
02406 
02407         if( item && (ptmenu->FocusedItem == id ))
02408         {
02409             if( !(item->fType & MF_POPUP) )
02410                 return MENU_ExecFocusedItem( pmt, hPtMenu, wFlags);
02411 
02412             /* If we are dealing with the top-level menu and that this */
02413             /* is a click on an already "poppped" item                 */
02414             /* Stop the menu tracking and close the opened submenus    */
02415             if((pmt->hTopMenu == hPtMenu) && (ptmenu->bTimeToHide == TRUE))
02416                 return 0;
02417         }
02418         ptmenu->bTimeToHide = TRUE;
02419     }
02420     return -1;
02421 }
02422 
02423 
02424 /***********************************************************************
02425  *           MENU_MouseMove
02426  *
02427  * Return TRUE if we can go on with menu tracking.
02428  */
02429 static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags )
02430 {
02431     UINT id = NO_SELECTED_ITEM;
02432     POPUPMENU *ptmenu = NULL;
02433 
02434     if( hPtMenu )
02435     {
02436         ptmenu = MENU_GetMenu(hPtMenu);
02437         if( IS_SYSTEM_MENU(ptmenu) )
02438             id = 0;
02439         else
02440             MENU_FindItemByCoords( ptmenu, pmt->pt, &id );
02441     }
02442 
02443     if( id == NO_SELECTED_ITEM )
02444     {
02445         MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
02446                          NO_SELECTED_ITEM, TRUE, pmt->hTopMenu);
02447 
02448     }
02449     else if( ptmenu->FocusedItem != id )
02450     {
02451        POPUPMENU *menu;
02452        MENUITEM *item;
02453 
02454             MENU_SwitchTracking( pmt, hPtMenu, id );
02455 
02456 
02457        /*
02458           Test to see if we are trying to popup a submenu or not.
02459           If we aren't, don't change the current menu pointer
02460           and return.
02461        */
02462        if (!(menu = (POPUPMENU *)MENU_GetMenu( hPtMenu )))
02463        {
02464           pmt->hCurrentMenu = hPtMenu;
02465           return TRUE;
02466        }
02467 
02468        if (!IsWindow( menu->hWnd ) ||
02469            (menu->FocusedItem == NO_SELECTED_ITEM))
02470        {
02471           pmt->hCurrentMenu = hPtMenu;
02472           return TRUE;
02473        }
02474 
02475        item = &menu->items[menu->FocusedItem];
02476        if (!(item->fType & MF_POPUP) ||
02477            (item->fState & (MF_GRAYED | MF_DISABLED)))
02478        {
02479           pmt->hCurrentMenu =  hPtMenu;
02480           return TRUE;
02481        }
02482 
02483        /* Check to see if we are trying to popup a toplevel menu or a
02484           submenu.  Only the submenu has a delay.
02485        */
02486        if (uSubPWndLevel)
02487        {
02488          /*
02489            If we made it here, we want to pop up a submenu.  Before we pop it up,
02490            we want a slight delay.  This is implemented by remembering the ID of the menu
02491            where the mouse is currently positioned, and setting up a timer.  When the
02492            timer fires (handled in MENU_TrackMenu() ), if the mouse is over the same
02493            submenu item, we popup it up.  Otherwise, we do nothing.
02494          */
02495          KillTimer (pmt->hOwnerWnd, SUBMENU_POPUP_TIMERID); /* Just in case another timer was set up and not fired yet... */
02496          if ( (SetTimer (pmt->hOwnerWnd, SUBMENU_POPUP_TIMERID, POPUP_MENU_DELAY, NULL)) != SUBMENU_POPUP_TIMERID)
02497          {
02498             /*
02499               For some reason the timer wasn't set up properly... Revert to old
02500               functionality.
02501             */
02502             pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,hPtMenu,FALSE,wFlags,&pmt->pt);
02503             return TRUE;
02504          }
02505        } else
02506        {
02507          /* We are trying to popup a top level menu... so no delay */
02508 
02509           pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hPtMenu, FALSE, wFlags,&pmt->pt);
02510           return TRUE;
02511        }
02512 
02513        mouseOverMenuID = id;
02514        isTimerSet = TRUE;
02515     }
02516     return TRUE;
02517 }
02518 
02519 
02520 /***********************************************************************
02521  *           MENU_DoNextMenu
02522  *
02523  * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
02524  */
02525 static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
02526 {
02527     POPUPMENU *menu = MENU_GetMenu(pmt->hTopMenu);
02528 
02529     if( (vk == VK_LEFT &&  menu->FocusedItem == 0 ) ||
02530         (vk == VK_RIGHT && menu->FocusedItem == menu->nItems - 1))
02531     {
02532         MDINEXTMENU next_menu;
02533         HMENU hNewMenu;
02534         HWND  hNewWnd;
02535         UINT  id = 0;
02536 
02537         next_menu.hmenuIn = (IS_SYSTEM_MENU(menu)) ? GetSubMenu(pmt->hTopMenu,0) : pmt->hTopMenu;
02538         next_menu.hmenuNext = 0;
02539         next_menu.hwndNext = 0;
02540 
02541         SendMessageW( pmt->hOwnerWnd, WM_NEXTMENU, vk, (LPARAM)&next_menu );
02542 
02543         dprintf(("%04x [%04x] -> %04x [%04x]\n",
02544               pmt->hCurrentMenu, pmt->hOwnerWnd, next_menu.hmenuNext, next_menu.hwndNext ));
02545 
02546         if (!next_menu.hmenuNext || !next_menu.hwndNext)
02547         {
02548             hNewWnd = pmt->hOwnerWnd;
02549             if( IS_SYSTEM_MENU(menu) )
02550             {
02551                 /* switch to the menu bar */
02552 
02553                 if( (GetWindowLongA(pmt->hOwnerWnd,GWL_STYLE) & WS_CHILD) || !GetMenu(pmt->hOwnerWnd) )
02554                 {
02555                     return FALSE;
02556                 }
02557 
02558                 hNewMenu = GetMenu(pmt->hOwnerWnd);
02559                 if( vk == VK_LEFT )
02560                 {
02561                     menu = MENU_GetMenu(hNewMenu);
02562                     id = menu->nItems - 1;
02563                 }
02564             }
02565             else if( GetWindowLongA(pmt->hOwnerWnd,GWL_STYLE) & WS_SYSMENU )
02566             {
02567                 /* switch to the system menu */
02568                 hNewMenu = getSysMenu(pmt->hOwnerWnd);
02569             }
02570             else
02571             {
02572                 return FALSE;
02573         }
02574         }
02575         else    /* application returned a new menu to switch to */
02576         {
02577             hNewMenu = next_menu.hmenuNext;
02578             hNewWnd = next_menu.hwndNext;
02579 
02580             if( IsMenu(hNewMenu) && IsWindow(hNewWnd) )
02581             {
02582                 if( (GetWindowLongA(hNewWnd,GWL_STYLE) & WS_SYSMENU) &&
02583                     GetSubMenu(getSysMenu(hNewWnd), 0) == hNewMenu )
02584                 {
02585                     /* get the real system menu */
02586                     hNewMenu =  getSysMenu(hNewWnd);
02587                 }
02588                 else if( (GetWindowLongA(hNewWnd,GWL_STYLE) & WS_CHILD) || (GetMenu(hNewWnd) != hNewMenu) )
02589                 {
02590                     /* FIXME: Not sure what to do here, perhaps,
02591                      * try to track hNewMenu as a popup? */
02592 
02593                     //TRACE(" -- got confused.\n");
02594                     return FALSE;
02595                 }
02596             }
02597             else return FALSE;
02598         }
02599 
02600         if( hNewMenu != pmt->hTopMenu )
02601         {
02602             MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, NO_SELECTED_ITEM,
02603                     FALSE, 0 );
02604             if( pmt->hCurrentMenu != pmt->hTopMenu )
02605                 MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
02606         }
02607 
02608         if( hNewWnd != pmt->hOwnerWnd )
02609         {
02610             ReleaseCapture();
02611             pmt->hOwnerWnd = hNewWnd;
02612             SetCapture(pmt->hOwnerWnd); //SvL: Don't know if this is good enough
02613             //EVENT_Capture( pmt->hOwnerWnd, HTMENU ); //CB: todo
02614         }
02615 
02616         pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */
02617         MENU_SelectItem( pmt->hOwnerWnd, pmt->hTopMenu, id, TRUE, 0 );
02618 
02619         return TRUE;
02620     }
02621     return FALSE;
02622 }
02623 
02624 /***********************************************************************
02625  *           MENU_SuspendPopup
02626  *
02627  * The idea is not to show the popup if the next input message is
02628  * going to hide it anyway.
02629  */
02630 static BOOL MENU_SuspendPopup( MTRACKER* pmt, UINT uMsg )
02631 {
02632     MSG msg;
02633 
02634     msg.hwnd = pmt->hOwnerWnd;
02635 
02636     PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
02637     pmt->trackFlags |= TF_SKIPREMOVE;
02638 
02639     switch( uMsg )
02640     {
02641         case WM_KEYDOWN:
02642              PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
02643              if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
02644              {
02645                  PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
02646                  PeekMessageA( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
02647                  if( msg.message == WM_KEYDOWN &&
02648                     (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
02649                  {
02650                      pmt->trackFlags |= TF_SUSPENDPOPUP;
02651                      return TRUE;
02652                  }
02653              }
02654              break;
02655     }
02656 
02657     /* failures go through this */
02658     pmt->trackFlags &= ~TF_SUSPENDPOPUP;
02659     return FALSE;
02660 }
02661 
02662 /***********************************************************************
02663  *           MENU_KeyLeft
02664  *
02665  * Handle a VK_LEFT key event in a menu.
02666  */
02667 static void MENU_KeyLeft( MTRACKER* pmt, UINT wFlags )
02668 {
02669     POPUPMENU *menu;
02670     HMENU hmenutmp, hmenuprev;
02671     UINT  prevcol;
02672 
02673     hmenuprev = hmenutmp = pmt->hTopMenu;
02674     menu = MENU_GetMenu(hmenutmp);
02675 
02676     /* Try to move 1 column left (if possible) */
02677     if( (prevcol = MENU_GetStartOfPrevColumn( pmt->hCurrentMenu )) !=
02678         NO_SELECTED_ITEM ) {
02679 
02680         MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
02681                          prevcol, TRUE, 0 );
02682         return;
02683     }
02684 
02685     /* close topmost popup */
02686     while (hmenutmp != pmt->hCurrentMenu)
02687     {
02688         hmenuprev = hmenutmp;
02689         hmenutmp = MENU_GetSubPopup( hmenuprev );
02690     }
02691 
02692     MENU_HideSubPopups( pmt->hOwnerWnd, hmenuprev, TRUE );
02693     pmt->hCurrentMenu = hmenuprev;
02694 
02695     if ( (hmenuprev == pmt->hTopMenu) && !(menu->wFlags & MF_POPUP) )
02696     {
02697         /* move menu bar selection if no more popups are left */
02698 
02699         if( !MENU_DoNextMenu( pmt, VK_LEFT) )
02700              MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_PREV );
02701 
02702         if ( hmenuprev != hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
02703         {
02704            /* A sublevel menu was displayed - display the next one
02705             * unless there is another displacement coming up */
02706 
02707             if( !MENU_SuspendPopup( pmt, WM_KEYDOWN ) )
02708                 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
02709                                                 pmt->hTopMenu, TRUE, wFlags,&pmt->pt);
02710         }
02711     }
02712 }
02713 
02714 
02715 /***********************************************************************
02716  *           MENU_KeyRight
02717  *
02718  * Handle a VK_RIGHT key event in a menu.
02719  */
02720 static void MENU_KeyRight( MTRACKER* pmt, UINT wFlags )
02721 {
02722     HMENU hmenutmp;
02723     POPUPMENU *menu = MENU_GetMenu(pmt->hTopMenu);
02724     UINT  nextcol;
02725 
02726     //TRACE("MENU_KeyRight called, cur %x (%s), top %x (%s).\n",
02727     //              pmt->hCurrentMenu,
02728     //              ((POPUPMENU *)USER_HEAP_LIN_ADDR(pmt->hCurrentMenu))->
02729     //                 items[0].text,
02730     //              pmt->hTopMenu, menu->items[0].text );
02731 
02732     if ( (menu->wFlags & MF_POPUP) || (pmt->hCurrentMenu != pmt->hTopMenu))
02733     {
02734         /* If already displaying a popup, try to display sub-popup */
02735 
02736         hmenutmp = pmt->hCurrentMenu;
02737         pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd, hmenutmp, TRUE, wFlags,&pmt->pt);
02738 
02739         /* if subpopup was displayed then we are done */
02740         if (hmenutmp != pmt->hCurrentMenu) return;
02741     }
02742 
02743     /* Check to see if there's another column */
02744     if( (nextcol = MENU_GetStartOfNextColumn( pmt->hCurrentMenu )) !=
02745         NO_SELECTED_ITEM ) {
02746         //TRACE("Going to %d.\n", nextcol );
02747         MENU_SelectItem( pmt->hOwnerWnd, pmt->hCurrentMenu,
02748                          nextcol, TRUE, 0 );
02749         return;
02750     }
02751 
02752     if (!(menu->wFlags & MF_POPUP))     /* menu bar tracking */
02753     {
02754         if( pmt->hCurrentMenu != pmt->hTopMenu )
02755         {
02756             MENU_HideSubPopups( pmt->hOwnerWnd, pmt->hTopMenu, FALSE );
02757             hmenutmp = pmt->hCurrentMenu = pmt->hTopMenu;
02758         } else hmenutmp = 0;
02759 
02760         /* try to move to the next item */
02761         if( !MENU_DoNextMenu( pmt, VK_RIGHT) )
02762              MENU_MoveSelection( pmt->hOwnerWnd, pmt->hTopMenu, ITEM_NEXT );
02763 
02764         if( hmenutmp || pmt->trackFlags & TF_SUSPENDPOPUP )
02765             if( !MENU_SuspendPopup(pmt, WM_KEYDOWN) )
02766                 pmt->hCurrentMenu = MENU_ShowSubPopup(pmt->hOwnerWnd,
02767                                                        pmt->hTopMenu, TRUE, wFlags,&pmt->pt);
02768     }
02769 }
02770 
02771 VOID MENU_DispatchMouseMsg(MSG *msg)
02772 {
02773   LONG hittest;
02774 
02775   hittest = SendMessageA(msg->hwnd,WM_NCHITTEST,0,MAKELONG(msg->pt.x,msg->pt.y));
02776   if (hittest != HTCLIENT)
02777     SendMessageA(msg->hwnd,msg->message+WM_NCMOUSEMOVE-WM_MOUSEMOVE,hittest,MAKELONG(msg->pt.x,msg->pt.y));
02778   else
02779     DispatchMessageA(msg);
02780 }
02781 
02782 /***********************************************************************
02783  *           MENU_TrackMenu
02784  *
02785  * Menu tracking code.
02786  */
02787 static INT MENU_TrackMenu(HMENU hmenu,UINT wFlags,INT x,INT y,HWND hwnd,BOOL inMenuBar,const RECT *lprect)
02788 {
02789     MSG msg;
02790     POPUPMENU *menu;
02791     BOOL fRemove;
02792     INT executedMenuId = -1;
02793     MTRACKER mt;
02794     BOOL enterIdleSent = FALSE;
02795     BOOL bSysMenu;
02796 
02797     mt.trackFlags = 0;
02798     mt.hCurrentMenu = hmenu;
02799     mt.hTopMenu = hmenu;
02800     mt.hOwnerWnd = hwnd;
02801     mt.pt.x = x;
02802     mt.pt.y = y;
02803 
02804     //TRACE("hmenu=0x%04x flags=0x%08x (%d,%d) hwnd=0x%04x (%d,%d)-(%d,%d)\n",
02805     //        hmenu, wFlags, x, y, hwnd, (lprect) ? lprect->left : 0, (lprect) ? lprect->top : 0,
02806     //        (lprect) ? lprect->right : 0,  (lprect) ? lprect->bottom : 0);
02807 
02808     fEndMenu = FALSE;
02809     if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
02810 
02811     bSysMenu = IS_SYSTEM_MENU(menu);
02812 
02813     if (wFlags & TPM_BUTTONDOWN)
02814     {
02815         /* Get the result in order to start the tracking or not */
02816         fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
02817         fEndMenu = !fRemove;
02818     }
02819 
02820 #ifdef __WIN32OS2__
02821     //SvL: Set keyboard & mouse event capture
02822     SetCapture(mt.hOwnerWnd);
02823     //SetCapture breaks system menu (double click), must generate double
02824     //clicks manually
02825     SetMenuDoubleClick(TRUE);
02826 #else
02827     EVENT_Capture( mt.hOwnerWnd, HTMENU );
02828 #endif
02829 
02830     while (!fEndMenu)
02831     {
02832         menu = MENU_GetMenu(mt.hCurrentMenu);
02833         msg.hwnd = (wFlags & TPM_ENTERIDLEEX && menu->wFlags & MF_POPUP) ? menu->hWnd : 0;
02834 
02835         /* we have to keep the message in the queue until it's
02836          * clear that menu loop is not over yet. */
02837 #ifdef __WIN32OS2__
02838         //SvL: Getting messages for only the menu delays background paints (i.e. VPBuddy logo)
02839         if (!GetMessageA(&msg,0,0,0)) break;
02840 #else
02841         if (!GetMessageA(&msg,msg.hwnd,0,0)) break;
02842 #endif
02843         TranslateMessage( &msg );
02844         mt.pt = msg.pt;
02845 
02846         if ( (msg.hwnd==menu->hWnd) || (msg.message!=WM_TIMER) )
02847           enterIdleSent=FALSE;
02848 
02849         fRemove = FALSE;
02850         if((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
02851         {
02852             /* Find a menu for this mouse event */
02853             POINT pt = msg.pt;
02854 
02855             hmenu = MENU_PtMenu(mt.hTopMenu,pt,inMenuBar);
02856 
02857             //CB: todo: solve conflicts with OS/2's single message queue architecture
02858 
02859             switch(msg.message)
02860             {
02861                 /* no WM_NC... messages in captured state */
02862 
02863                 case WM_RBUTTONDBLCLK:
02864                 case WM_RBUTTONDOWN:
02865                     if (!(wFlags & TPM_RIGHTBUTTON)) break;
02866                     goto buttondown;
02867                 case WM_LBUTTONDBLCLK:
02868                     if (bSysMenu && (hmenu == mt.hTopMenu))
02869                     {
02870 #ifdef __WIN32OS2__
02871                         //double click on system menu -> close application
02872                         PostMessageA(hwnd, WM_SYSCOMMAND,SC_CLOSE, msg.lParam);
02873 #endif
02874                         fEndMenu = TRUE;
02875                         break;
02876                     }
02877                     /* fall through */
02878                 case WM_LBUTTONDOWN:
02879                     /* If the message belongs to the menu, removes it from the queue */
02880                     /* Else, end menu tracking */
02881 
02882                  buttondown:
02883                     /* Forcing mouse popup NOW - Ensure timer doesn't popup menu also */
02884                     mouseOverMenuID = -1;
02885                     fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
02886                     fEndMenu = !fRemove;
02887                     break;
02888 
02889                 case WM_RBUTTONUP:
02890                     if (!(wFlags & TPM_RIGHTBUTTON)) break;
02891                     /* fall through */
02892                 case WM_LBUTTONUP:
02893                     /* Check if a menu was selected by the mouse */
02894                     if (hmenu)
02895                     {
02896                         /* Forcing mouse popup NOW - Ensure timer doesn't popup menu also */
02897                         mouseOverMenuID = -1;
02898                         executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);
02899 
02900                         /* End the loop if executedMenuId is an item ID */
02901                         /* or if the job was done (executedMenuId = 0). */
02902                         fEndMenu = fRemove = (executedMenuId != -1);
02903                     }
02904                     /* No menu was selected by the mouse */
02905                     /* if the function was called by TrackPopupMenu, continue
02906                        with the menu tracking. If not, stop it */
02907                     else
02908                         fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
02909 
02910                     break;
02911 
02912                 case WM_MOUSEMOVE:
02913                     /* In win95 winelook, the selected menu item must be changed every time the
02914                        mouse moves. In Win31 winelook, the mouse button has to be held down */
02915 #ifdef __WIN32OS2__
02916                     if ( !fOS2Look ||
02917                          ( (msg.wParam & MK_LBUTTON) ||
02918                            ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON))) )
02919                        fEndMenu |= !MENU_MouseMove( &mt, hmenu, wFlags );
02920 #else
02921                     if ( (TWEAK_WineLook > WIN31_LOOK) ||
02922                          ( (msg.wParam & MK_LBUTTON) ||
02923                            ((wFlags & TPM_RIGHTBUTTON) && (msg.wParam & MK_RBUTTON))) )
02924                        fEndMenu |= !MENU_MouseMove( &mt, hmenu, wFlags );
02925 #endif
02926 
02927             } /* switch(msg.message) - mouse */
02928         }
02929         else if (msg.message == WM_TIMER)
02930         {
02931            UINT id = -1;
02932            POPUPMENU *ptmenu = NULL;
02933 
02934            if (isTimerSet)
02935            {
02936               /*
02937                 If we get here, an attempt was made to pop up a submenu.
02938                 (See MENU_MouseMove() )
02939               */
02940 
02941               /* Get the ID of the menu item the mouse is over now. */
02942               if( hmenu )
02943               {
02944                  ptmenu = (POPUPMENU *)MENU_GetMenu( hmenu );
02945                  if( IS_SYSTEM_MENU(ptmenu) )
02946                    id = 0;
02947                  else
02948                    MENU_FindItemByCoords( ptmenu, mt.pt, &id );
02949 
02950                  /* If it is over the same item that set up the timer originally .... */
02951                  if (mouseOverMenuID != -1 && mouseOverMenuID == id)
02952                  {
02953                    /* .... Pop up the menu */
02954                    mt.hCurrentMenu = MENU_ShowSubPopup(mt.hOwnerWnd, hmenu, FALSE, wFlags,&mt.pt);
02955                   }
02956               }
02957 
02958               /* Reset the timer so it doesn't fire again. (So we are ready for the next
02959                  attempt to popup a submenu... ) */
02960               KillTimer(mt.hOwnerWnd,SUBMENU_POPUP_TIMERID);
02961               isTimerSet = FALSE;
02962            }
02963         }
02964         else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
02965         {
02966             fRemove = TRUE;  /* Keyboard messages are always removed */
02967             switch(msg.message)
02968             {
02969             case WM_KEYDOWN:
02970                 switch(msg.wParam)
02971                 {
02972                 case VK_HOME:
02973                 case VK_END:
02974                     MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu,
02975                                      NO_SELECTED_ITEM, FALSE, 0 );
02976                 /* fall through */
02977                 case VK_UP:
02978                     MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu,
02979                                        (msg.wParam == VK_HOME)? ITEM_NEXT : ITEM_PREV );
02980                     break;
02981 
02982                 case VK_DOWN: /* If on menu bar, pull-down the menu */
02983 
02984                     menu = MENU_GetMenu(mt.hCurrentMenu);
02985                     if (!(menu->wFlags & MF_POPUP))
02986                         mt.hCurrentMenu = MENU_ShowSubPopup(mt.hOwnerWnd, mt.hTopMenu, TRUE, wFlags,&mt.pt);
02987                     else      /* otherwise try to move selection */
02988                         MENU_MoveSelection( mt.hOwnerWnd, mt.hCurrentMenu, ITEM_NEXT );
02989                     break;
02990 
02991                 case VK_LEFT:
02992                     MENU_KeyLeft( &mt, wFlags );
02993                     break;
02994 
02995                 case VK_RIGHT:
02996                     MENU_KeyRight( &mt, wFlags );
02997                     break;
02998 
02999                 case VK_ESCAPE:
03000                     fEndMenu = TRUE;
03001                     break;
03002 
03003                 case VK_F1:
03004                     {
03005                         HELPINFO hi;
03006                         hi.cbSize = sizeof(HELPINFO);
03007                         hi.iContextType = HELPINFO_MENUITEM;
03008                         if (menu->FocusedItem == NO_SELECTED_ITEM)
03009                             hi.iCtrlId = 0;
03010                         else
03011                             hi.iCtrlId = menu->items[menu->FocusedItem].wID;
03012                         hi.hItemHandle = hmenu;
03013                         hi.dwContextId = menu->dwContextHelpID;
03014                         hi.MousePos = msg.pt;
03015                         //TRACE_(winhelp)("Sending HELPINFO_MENUITEM to 0x%08x\n", hwnd);
03016                         SendMessageA(hwnd, WM_HELP, 0, (LPARAM)&hi);
03017                         break;
03018                     }
03019 
03020                 default:
03021                     break;
03022                 }
03023                 break;  /* WM_KEYDOWN */
03024 
03025             case WM_SYSKEYDOWN:
03026                 switch(msg.wParam)
03027                 {
03028                 case VK_MENU:
03029                     fEndMenu = TRUE;
03030                     break;
03031 
03032                 }
03033                 break;  /* WM_SYSKEYDOWN */
03034 
03035             case WM_CHAR:
03036                 {
03037                     UINT        pos;
03038 
03039                     if (msg.wParam == '\r' || msg.wParam == ' ')
03040                     {
03041                         executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
03042                         fEndMenu = (executedMenuId != -1);
03043 
03044                         break;
03045                     }
03046 
03047                       /* Hack to avoid control chars. */
03048                       /* We will find a better way real soon... */
03049                     if ((msg.wParam <= 32) || (msg.wParam >= 127)) break;
03050 
03051                     pos = MENU_FindItemByKey( mt.hOwnerWnd, mt.hCurrentMenu,
03052                                               LOWORD(msg.wParam), FALSE );
03053                     if (pos == (UINT)-2) fEndMenu = TRUE;
03054                     else if (pos == (UINT)-1) MessageBeep(0);
03055                     else
03056                     {
03057                         MENU_SelectItem( mt.hOwnerWnd, mt.hCurrentMenu, pos,
03058                                 TRUE, 0 );
03059                         executedMenuId = MENU_ExecFocusedItem(&mt,mt.hCurrentMenu, wFlags);
03060                         fEndMenu = (executedMenuId != -1);
03061                     }
03062                 }
03063                 break;
03064             }  /* switch(msg.message) - kbd */
03065         }
03066         else if (msg.message == WM_SYSCOMMAND)
03067         {
03068             /* The user clicked on the system menu/button */
03069             fEndMenu = TRUE;
03070             break;
03071         }
03072         else
03073         {
03074             DispatchMessageA( &msg );
03075         }
03076 
03077         if (!fEndMenu) fRemove = TRUE;
03078 
03079         /* finally remove message from the queue */
03080 
03081         if (fRemove && !(mt.trackFlags & TF_SKIPREMOVE) )
03082             PeekMessageA( &msg, 0, msg.message, msg.message, PM_REMOVE );
03083         else mt.trackFlags &= ~TF_SKIPREMOVE;
03084     }
03085 #ifdef __WIN32OS2__
03086     SetMenuDoubleClick(FALSE);
03087     ReleaseCapture();
03088 #endif
03089 
03090     menu = MENU_GetMenu(mt.hTopMenu);
03091 
03092     if( IsWindow( mt.hOwnerWnd ) )
03093     {
03094         MENU_HideSubPopups( mt.hOwnerWnd, mt.hTopMenu, FALSE );
03095 
03096         MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
03097 #ifdef __WIN32OS2__
03098         if (menu && menu->wFlags & MF_POPUP)
03099         {
03100                 DestroyWindow( menu->hWnd );
03101                 menu->hWnd = 0;
03102 //            ShowWindow( menu->hWnd, SW_HIDE );
03103                 uSubPWndLevel = 0;
03104         }
03105 #endif
03106         SendMessageA( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0xffff), 0 );
03107     }
03108 
03109     /* Reset the variable for hiding menu */
03110     menu->bTimeToHide = FALSE;
03111 
03112     /* The return value is only used by TrackPopupMenu */
03113     return ((executedMenuId != -1) ? executedMenuId : 0);
03114 }
03115 
03116 /***********************************************************************
03117  *           MENU_InitTracking
03118  */
03119 static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
03120 {
03121     //TRACE("hwnd=0x%04x hmenu=0x%04x\n", hWnd, hMenu);
03122 
03123     HideCaret(0);
03124 
03125     /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
03126     if (!(wFlags & TPM_NONOTIFY))
03127        SendMessageA( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
03128 
03129     SendMessageA( hWnd, WM_SETCURSOR, hWnd, HTCAPTION );
03130 
03131     if (!(wFlags & TPM_NONOTIFY))
03132        SendMessageA( hWnd, WM_INITMENU, hMenu, 0 );
03133 
03134     return TRUE;
03135 }
03136 /***********************************************************************
03137  *           MENU_ExitTracking
03138  */
03139 static BOOL MENU_ExitTracking(HWND hWnd)
03140 {
03141     //TRACE("hwnd=0x%04x\n", hWnd);
03142 
03143     SendMessageA( hWnd, WM_EXITMENULOOP, 0, 0 );
03144     ShowCaret(0);
03145     return TRUE;
03146 }
03147 
03148 /***********************************************************************
03149  *           MENU_TrackMouseMenuBar
03150  *
03151  * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
03152  */
03153 void MENU_TrackMouseMenuBar( HWND hWnd, INT ht, POINT pt )
03154 {
03155     HMENU hMenu = (ht == 0) ? GetMenu(hWnd):getSysMenu(hWnd);
03156     UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
03157 
03158     //TRACE("pwnd=%p ht=0x%04x (%ld,%ld)\n", wndPtr, ht, pt.x, pt.y);
03159 
03160     if (IsMenu(hMenu))
03161     {
03162         if (ht == HTCAPTION) wFlags |= TPM_CAPTIONSYSMENU | TPM_RIGHTBUTTON;
03163         if (IsIconic(hWnd)) wFlags |= TPM_BOTTOMALIGN; //CB: todo: for minimized windows
03164 
03165         MENU_InitTracking( hWnd, hMenu, FALSE, wFlags );
03166         MENU_TrackMenu( hMenu, wFlags, pt.x, pt.y, hWnd,ht == 0, NULL );
03167         MENU_ExitTracking(hWnd);
03168     }
03169 }
03170 
03171 MENUITEM  *MENU_HighlightedItem=NULL;
03172 UINT       MENU_HighlightedItemID=NO_SELECTED_ITEM;
03173 POPUPMENU *MENU_HighlightedMenu=NULL;
03174 
03175 void MENU_TrackMouseMenuBar_MouseMove(HWND hwnd,POINT pt,BOOL OnMenu)
03176 {
03177     HMENU hMenu = GetMenu(hwnd);
03178     MENUITEM *item = NULL;
03179     RECT rect;
03180     HDC hdc;
03181     BOOL UnHighlight = (OnMenu==TRUE)?FALSE:TRUE;
03182     POPUPMENU *ptmenu = NULL;
03183     UINT id = NO_SELECTED_ITEM;
03184 
03185     if (OnMenu == TRUE && IsMenu(hMenu)) {
03186 
03187         ptmenu=(POPUPMENU *)MENU_GetMenu( hMenu );
03188 
03189         item=MENU_FindItemByCoords( ptmenu, pt, &id );
03190 
03191         if(!item) {
03192             /* No item selected, perhaps we are on the blank spot? */
03193             UnHighlight = TRUE;
03194             /* Paranoid setting */
03195             item=NULL;
03196         } else if(id == MENU_HighlightedItemID) {
03197             /* If it's already highlighted, don't do it again */
03198             return;
03199         } else if(item->fState & MF_MOUSESELECT) {
03200             /* If it's dropped, we let the DrawMenuItem draw the sunken border */
03201             return;
03202         } else if(item->fType & MF_BITMAP) {
03203             UnHighlight = TRUE;
03204             /* (Required) Paranoid setting */
03205             item=NULL;
03206         } else {
03207             hdc = GetDCEx( ptmenu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
03208             rect = item->rect;
03209             DrawEdge(hdc, &rect, BDR_RAISEDINNER, BF_RECT);
03210             ReleaseDC( ptmenu->hWnd, hdc );
03211 
03212             UnHighlight = TRUE;
03213         }
03214     }
03215 
03216     if(UnHighlight == TRUE) {
03217         if(MENU_HighlightedItem) {
03218             if(!(MENU_HighlightedItem->fState & MF_MOUSESELECT)) {
03219                 hdc = GetDCEx( MENU_HighlightedMenu->hWnd, 0, DCX_CACHE | DCX_WINDOW);
03220                 rect = MENU_HighlightedItem->rect;
03221 
03222                 FrameRect(hdc, &rect, GetSysColorBrush(COLOR_MENU));
03223                 ReleaseDC( MENU_HighlightedMenu->hWnd, hdc );
03224             }
03225         }
03226 
03227         /* Sets to NULL, NO_SELECTED_ITEM, NULL, unless it found a new
03228             item, then it will be filled in with the proper values */
03229         MENU_HighlightedItem = item;
03230         MENU_HighlightedItemID = id;
03231         MENU_HighlightedMenu= ptmenu;
03232     }
03233 }
03234 
03235 /***********************************************************************
03236  *           MENU_TrackKbdMenuBar
03237  *
03238  * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
03239  */
03240 void MENU_TrackKbdMenuBar( HWND hWnd, UINT wParam, INT vkey)
03241 {
03242    UINT uItem = NO_SELECTED_ITEM;
03243    HMENU hTrackMenu;
03244    UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON;
03245 
03246     /* find window that has a menu */
03247 
03248     while(GetWindowLongA(hWnd,GWL_STYLE) & WS_CHILD)
03249         if( !(hWnd = GetParent(hWnd)) ) return;
03250 
03251     /* check if we have to track a system menu */
03252 
03253     if( (GetWindowLongA(hWnd,GWL_STYLE) & (WS_CHILD | WS_MINIMIZE)) ||
03254         !GetMenu(hWnd) || vkey == VK_SPACE )
03255     {
03256         if( !(GetWindowLongA(hWnd,GWL_STYLE) & WS_SYSMENU) ) return;
03257         hTrackMenu = getSysMenu(hWnd);
03258         uItem = 0;
03259         wParam |= HTSYSMENU;    /* prevent item lookup */
03260     }
03261     else
03262         hTrackMenu = GetMenu(hWnd);
03263 
03264     if (IsMenu( hTrackMenu ))
03265     {
03266         MENU_InitTracking( hWnd, hTrackMenu, FALSE, wFlags );
03267 
03268         if( vkey && vkey != VK_SPACE )
03269         {
03270             uItem = MENU_FindItemByKey( hWnd, hTrackMenu,
03271                                         vkey, (wParam & HTSYSMENU) );
03272             if( uItem >= (UINT)(-2) )
03273             {
03274                 if( uItem == (UINT)(-1) ) MessageBeep(0);
03275                 hTrackMenu = 0;
03276             }
03277         }
03278 
03279         if( hTrackMenu )
03280         {
03281             MENU_SelectItem( hWnd, hTrackMenu, uItem, TRUE, 0 );
03282 
03283             if( uItem == NO_SELECTED_ITEM )
03284                 MENU_MoveSelection( hWnd, hTrackMenu, ITEM_NEXT );
03285             else if( vkey )
03286                 PostMessageA( hWnd, WM_KEYDOWN, VK_DOWN, 0L );
03287 
03288             MENU_TrackMenu( hTrackMenu, wFlags, 0, 0, hWnd,TRUE, NULL );
03289         }
03290 
03291         MENU_ExitTracking (hWnd);
03292     }
03293 }
03294 
03295 
03296 /**********************************************************************
03297  *           TrackPopupMenu   (USER32.549)
03298  *
03299  * Like the win32 API, the function return the command ID only if the
03300  * flag TPM_RETURNCMD is on.
03301  *
03302  */
03303 BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
03304                            INT nReserved, HWND hWnd, const RECT *lpRect )
03305 {
03306     BOOL ret = FALSE;
03307 
03308     if(lpRect) {
03309          dprintf(("USER32: TrackPopupMenu %x %x (%d,%d) %x %x (%d,%d)(%d,%d)", hMenu, wFlags, x, y, nReserved, hWnd, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom));
03310     }
03311     else dprintf(("USER32: TrackPopupMenu %x %x (%d,%d) %x %x lpRect=NULL", hMenu, wFlags, x, y, nReserved, hWnd));
03312 
03313     MENU_InitTracking(hWnd, hMenu, TRUE, wFlags);
03314 
03315     /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
03316     if (!(wFlags & TPM_NONOTIFY))
03317         SendMessageA( hWnd, WM_INITMENUPOPUP, hMenu, 0);
03318 
03319     if (MENU_ShowPopup( hWnd, hMenu, 0, x, y, 0, 0 ))
03320         ret = MENU_TrackMenu( hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd,FALSE, lpRect );
03321     MENU_ExitTracking(hWnd);
03322 
03323     if( (!(wFlags & TPM_RETURNCMD)) && (ret != FALSE) )
03324         ret = 1;
03325 
03326     return ret;
03327 }
03328 
03329 /**********************************************************************
03330  *           TrackPopupMenuEx   (USER32.550)
03331  */
03332 BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, INT x, INT y,
03333                                 HWND hWnd, LPTPMPARAMS lpTpm )
03334 {
03335     dprintf(("USER32: TrackPopupMenuEx"));
03336     //FIXME("not fully implemented\n" );
03337     return TrackPopupMenu( hMenu, wFlags, x, y, 0, hWnd,
03338                              lpTpm ? &lpTpm->rcExclude : NULL );
03339 }
03340 
03341 /***********************************************************************
03342  *           PopupMenuWndProc
03343  *
03344  * NOTE: Windows has totally different (and undocumented) popup wndproc.
03345  */
03346 LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam,
03347                                  LPARAM lParam )
03348 {
03349     LRESULT retvalue;
03350 
03351     //TRACE("hwnd=0x%04x msg=0x%04x wp=0x%04x lp=0x%08lx\n",
03352     //hwnd, message, wParam, lParam);
03353 
03354     switch(message)
03355     {
03356     case WM_CREATE:
03357         {
03358             CREATESTRUCTA *cs = (CREATESTRUCTA*)lParam;
03359             SetWindowLongA( hwnd, 0, (LONG)cs->lpCreateParams );
03360             retvalue = 0;
03361             goto END;
03362         }
03363 
03364     case WM_MOUSEACTIVATE:  /* We don't want to be activated */
03365         retvalue = MA_NOACTIVATE;
03366         goto END;
03367 
03368     case WM_PAINT:
03369         {
03370             PAINTSTRUCT ps;
03371             BeginPaint( hwnd, &ps );
03372             MENU_DrawPopupMenu( hwnd, ps.hdc,
03373                                 (HMENU)GetWindowLongA( hwnd, 0 ) );
03374             EndPaint( hwnd, &ps );
03375             retvalue = 0;
03376             goto END;
03377         }
03378     case WM_ERASEBKGND:
03379         retvalue = 1;
03380         goto END;
03381 
03382     case WM_DESTROY:
03383 
03384         /* zero out global pointer in case resident popup window
03385          * was somehow destroyed. */
03386 
03387         if(MENU_GetTopPopupWnd() )
03388         {
03389             if( hwnd == pTopPopupWnd )
03390             {
03391                 //ERR("resident popup destroyed!\n");
03392 
03393                 MENU_DestroyTopPopupWnd();
03394                 uSubPWndLevel = 0;
03395             }
03396             else
03397                 uSubPWndLevel--;
03398             MENU_ReleaseTopPopupWnd();
03399         }
03400         break;
03401 
03402     case WM_SHOWWINDOW:
03403 
03404         if( wParam )
03405         {
03406             //if( !(*(HMENU*)wndPtr->wExtra) )
03407             //    ERR("no menu to display\n");
03408         }
03409         else
03410             SetWindowLongA(hwnd,0,0);
03411         break;
03412 
03413     case MM_SETMENUHANDLE:
03414 
03415         SetWindowLongA(hwnd,0,wParam);
03416         break;
03417 
03418     case MM_GETMENUHANDLE:
03419 
03420         retvalue = GetWindowLongA(hwnd,0);
03421         goto END;
03422 
03423     default:
03424         retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
03425         goto END;
03426     }
03427     retvalue = 0;
03428 END:
03429     return retvalue;
03430 }
03431 
03432 
03433 /***********************************************************************
03434  *           MENU_GetMenuBarHeight
03435  *
03436  * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
03437  */
03438 UINT MENU_GetMenuBarHeight(HWND hwnd,UINT menubarWidth,INT orgX,INT orgY)
03439 {
03440     HDC hdc;
03441     RECT rectBar;
03442     LPPOPUPMENU lppop;
03443     UINT retvalue;
03444 
03445     //TRACE("HWND 0x%x, width %d, at (%d, %d).\n",
03446     //             hwnd, menubarWidth, orgX, orgY );
03447 
03448     if (!(lppop = MENU_GetMenu(GetMenu(hwnd))))
03449     {
03450         return 0;
03451     }
03452 
03453     hdc = GetDCEx( hwnd, 0, DCX_CACHE | DCX_WINDOW );
03454     SelectObject( hdc, hMenuFont);
03455     SetRect(&rectBar, orgX, orgY, orgX+menubarWidth, orgY+GetSystemMetrics(SM_CYMENU));
03456     MENU_MenuBarCalcSize( hdc, &rectBar, lppop, hwnd );
03457     ReleaseDC( hwnd, hdc );
03458     retvalue = lppop->Height;
03459     return retvalue;
03460 }
03461 
03462 
03463 /*******************************************************************
03464  *         ChangeMenu32A    (USER32.23)
03465  */
03466 BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
03467                              UINT id, UINT flags )
03468 {
03469     dprintf(("USER32: ChangeMenuA"));
03470 
03471     //TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
03472     //              hMenu, pos, (DWORD)data, id, flags );
03473     if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
03474                                                  id, data );
03475     if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
03476     if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
03477                                                 id, data );
03478     if (flags & MF_REMOVE) return RemoveMenu( hMenu,
03479                                               flags & MF_BYPOSITION ? pos : id,
03480                                               flags & ~MF_REMOVE );
03481     /* Default: MF_INSERT */
03482     return InsertMenuA( hMenu, pos, flags, id, data );
03483 }
03484 
03485 
03486 /*******************************************************************
03487  *         ChangeMenu32W    (USER32.24)
03488  */
03489 BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
03490                              UINT id, UINT flags )
03491 {
03492     dprintf(("USER32: ChangeMenuW"));
03493 
03494     //TRACE("menu=%08x pos=%d data=%08lx id=%08x flags=%08x\n",
03495     //              hMenu, pos, (DWORD)data, id, flags );
03496     if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
03497                                                  id, data );
03498     if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE);
03499     if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
03500                                                 id, data );
03501     if (flags & MF_REMOVE) return RemoveMenu( hMenu,
03502                                               flags & MF_BYPOSITION ? pos : id,
03503                                               flags & ~MF_REMOVE );
03504     /* Default: MF_INSERT */
03505     return InsertMenuW( hMenu, pos, flags, id, data );
03506 }
03507 
03508 
03509 /*******************************************************************
03510  *         CheckMenuItem    (USER32.46)
03511  */
03512 DWORD WINAPI CheckMenuItem( HMENU hMenu, UINT id, UINT flags )
03513 {
03514     MENUITEM *item;
03515     DWORD ret;
03516 
03517     dprintf(("USER32: CheckMenuItem %x %x %x", hMenu, id, flags));
03518 
03519     //TRACE("menu=%04x id=%04x flags=%04x\n", hMenu, id, flags );
03520     if (!(item = MENU_FindItem( &hMenu, &id, flags ))) return -1;
03521     ret = item->fState & MF_CHECKED;
03522     if (flags & MF_CHECKED) item->fState |= MF_CHECKED;
03523     else item->fState &= ~MF_CHECKED;
03524     return ret;
03525 }
03526 
03527 
03528 /**********************************************************************
03529  *         EnableMenuItem32    (USER32.170)
03530  */
03531 UINT WINAPI EnableMenuItem( HMENU hMenu, UINT wItemID, UINT wFlags )
03532 {
03533     UINT    oldflags;
03534     MENUITEM *item;
03535     POPUPMENU *menu;
03536 
03537     dprintf(("USER32: EnableMenuItem %x %x %x", hMenu, wItemID, wFlags));
03538 
03539     //TRACE("(%04x, %04X, %04X) !\n",
03540     //             hMenu, wItemID, wFlags);
03541 
03542     /* Get the Popupmenu to access the owner menu */
03543     if (!(menu = MENU_GetMenu(hMenu)))
03544         return (UINT)-1;
03545 
03546     if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags )))
03547         return (UINT)-1;
03548 
03549     oldflags = item->fState & (MF_GRAYED | MF_DISABLED);
03550     item->fState ^= (oldflags ^ wFlags) & (MF_GRAYED | MF_DISABLED);
03551 
03552     /* In win95 if the close item in the system menu change update the close button */
03553     if((item->wID == SC_CLOSE) && (oldflags != wFlags))
03554     {
03555         if (menu->hSysMenuOwner != 0)
03556         {
03557             POPUPMENU* parentMenu;
03558 
03559             /* Get the parent menu to access*/
03560             if (!(parentMenu = MENU_GetMenu(menu->hSysMenuOwner)))
03561                 return (UINT)-1;
03562 
03563             /* Refresh the frame to reflect the change*/
03564             SetWindowPos(parentMenu->hWnd, 0, 0, 0, 0, 0,
03565                          SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
03566         }
03567     }
03568 
03569     return oldflags;
03570 }
03571 
03572 
03573 /*******************************************************************
03574  *         GetMenuString32A    (USER32.268)
03575  */
03576 INT WINAPI GetMenuStringA(
03577         HMENU hMenu,    /* [in] menuhandle */
03578         UINT wItemID,   /* [in] menu item (dep. on wFlags) */
03579         LPSTR str,      /* [out] outbuffer. If NULL, func returns entry length*/
03580         INT nMaxSiz,    /* [in] length of buffer. if 0, func returns entry len*/
03581         UINT wFlags     /* [in] MF_ flags */
03582 ) {
03583     MENUITEM *item;
03584 
03585     dprintf(("USER32: GetMenuStringA %x %d %d %x", hMenu, wItemID, nMaxSiz, wFlags));
03586 
03587     //TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
03588     //             hMenu, wItemID, str, nMaxSiz, wFlags );
03589 
03590     item = MENU_FindItem( &hMenu, &wItemID, wFlags );
03591 
03592     if (!str || !nMaxSiz)
03593     {
03594     if (item && IS_STRING_ITEM(item->fType))
03595         return strlen(item->text);
03596     else
03597         return 0;
03598     }
03599 
03600     str[0] = '\0';
03601 
03602     if (item)
03603     {
03604     if (!IS_STRING_ITEM(item->fType)) return 0;
03605     lstrcpynA( str, item->text, nMaxSiz );
03606     }
03607 
03608     return strlen(str);
03609 }
03610 
03611 
03612 /*******************************************************************
03613  *         GetMenuString32W    (USER32.269)
03614  */
03615 INT WINAPI GetMenuStringW( HMENU hMenu, UINT wItemID,
03616                                LPWSTR str, INT nMaxSiz, UINT wFlags )
03617 {
03618     MENUITEM *item;
03619 
03620     dprintf(("USER32: GetMenuStringW %x %d %x %d %d", hMenu, wItemID, str, nMaxSiz, wFlags));
03621 
03622     //TRACE("menu=%04x item=%04x ptr=%p len=%d flags=%04x\n",
03623     //             hMenu, wItemID, str, nMaxSiz, wFlags );
03624 
03625     item = MENU_FindItem( &hMenu, &wItemID, wFlags );
03626 
03627     if (!str || !nMaxSiz)
03628     {
03629     if (item && IS_STRING_ITEM(item->fType))
03630         return strlen(item->text);
03631     else
03632         return 0;
03633     }
03634 
03635     str[0] = '\0';
03636 
03637     if (item)
03638     {
03639     if (!IS_STRING_ITEM(item->fType)) return 0;
03640     lstrcpynAtoW( str, item->text, nMaxSiz );
03641     }
03642 
03643     return lstrlenW(str);
03644 }
03645 
03646 
03647 /**********************************************************************
03648  *         HiliteMenuItem32    (USER32.318)
03649  */
03650 BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
03651                                 UINT wHilite )
03652 {
03653     LPPOPUPMENU menu;
03654 
03655     dprintf(("USER32: HiliteMenuItem"));
03656 
03657     //TRACE("(%04x, %04x, %04x, %04x);\n",
03658     //             hWnd, hMenu, wItemID, wHilite);
03659     if (!MENU_FindItem( &hMenu, &wItemID, wHilite )) return FALSE;
03660     if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
03661     if (menu->FocusedItem == wItemID) return TRUE;
03662     MENU_HideSubPopups( hWnd, hMenu, FALSE );
03663     MENU_SelectItem( hWnd, hMenu, wItemID, TRUE, 0 );
03664     return TRUE;
03665 }
03666 
03667 
03668 /**********************************************************************
03669  *         GetMenuState    (USER32.267)
03670  */
03671 UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags )
03672 {
03673     MENUITEM *item;
03674 
03675     dprintf(("USER32: GetMenuState %d %d",wItemID,wFlags));
03676 
03677     //TRACE("(menu=%04x, id=%04x, flags=%04x);\n",
03678     //             hMenu, wItemID, wFlags);
03679 
03680     if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return -1;
03681 
03682     //debug_print_menuitem ("  item: ", item, "");
03683     if (item->fType & MF_POPUP)
03684     {
03685         POPUPMENU *menu = MENU_GetMenu(item->hSubMenu);
03686         if (!menu) return -1;
03687         else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff);
03688     }
03689     else
03690     {
03691         /* We used to (from way back then) mask the result to 0xff.  */
03692         /* I don't know why and it seems wrong as the documented */
03693         /* return flag MF_SEPARATOR is outside that mask.  */
03694         return (item->fType | item->fState);
03695     }
03696 }
03697 
03698 
03699 /**********************************************************************
03700  *         GetMenuItemCount32    (USER32.262)
03701  */
03702 INT WINAPI GetMenuItemCount( HMENU hMenu )
03703 {
03704     LPPOPUPMENU menu = MENU_GetMenu(hMenu);
03705 
03706     dprintf(("USER32: GetMenuItemCount %x", hMenu));
03707 
03708     if (!IS_A_MENU(menu)) return -1;
03709     //TRACE("(%04x) returning %d\n",
03710     //              hMenu, menu->nItems );
03711     return menu->nItems;
03712 }
03713 
03714 /**********************************************************************
03715  *         GetMenuItemID32    (USER32.263)
03716  */
03717 UINT WINAPI GetMenuItemID( HMENU hMenu, INT nPos )
03718 {
03719     MENUITEM * lpmi;
03720 
03721     dprintf(("USER32: GetMenuItemID %x %d", hMenu, nPos));
03722 
03723     if (!(lpmi = MENU_FindItem(&hMenu,(UINT*)&nPos,MF_BYPOSITION))) return 0xFFFFFFFF;
03724     if (lpmi->fType & MF_POPUP) return 0xFFFFFFFF;
03725     return lpmi->wID;
03726 
03727 }
03728 
03729 /*******************************************************************
03730  *         InsertMenu32A    (USER32.322)
03731  */
03732 BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
03733                              UINT id, LPCSTR str )
03734 {
03735     MENUITEM *item;
03736 
03737     if (IS_STRING_ITEM(flags) && str)
03738         dprintf(("USER32: InsertMenuA %x %d %x %x %s", hMenu, pos, flags, id, str));
03739     //    TRACE("hMenu %04x, pos %d, flags %08x, "
03740     //                  "id %04x, str '%s'\n",
03741     //                  hMenu, pos, flags, id, str );
03742     else // TRACE("hMenu %04x, pos %d, flags %08x, "
03743         dprintf(("USER32: InsertMenuA %x %d %x %d %x", hMenu, pos, flags, id, str));
03744     //                   "id %04x, str %08lx (not a string)\n",
03745     //                   hMenu, pos, flags, id, (DWORD)str );
03746 
03747     if (!(item = MENU_InsertItem( hMenu, pos, flags ))) return FALSE;
03748 
03749     if (!(MENU_SetItemData( item, flags, id, str )))
03750     {
03751         RemoveMenu( hMenu, pos, flags );
03752         return FALSE;
03753     }
03754 
03755     if (flags & MF_POPUP)  /* Set the MF_POPUP flag on the popup-menu */
03756         (MENU_GetMenu((HMENU)id))->wFlags |= MF_POPUP;
03757 
03758     item->hCheckBit = item->hUnCheckBit = 0;
03759     return TRUE;
03760 }
03761 
03762 
03763 /*******************************************************************
03764  *         InsertMenu32W    (USER32.325)
03765  */
03766 BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
03767                              UINT id, LPCWSTR str )
03768 {
03769     BOOL ret;
03770 
03771     if (IS_STRING_ITEM(flags) && str)
03772     {
03773         LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
03774         ret = InsertMenuA( hMenu, pos, flags, id, newstr );
03775         HeapFree( GetProcessHeap(), 0, newstr );
03776         return ret;
03777     }
03778     else return InsertMenuA( hMenu, pos, flags, id, (LPCSTR)str );
03779 }
03780 
03781 
03782 /*******************************************************************
03783  *         AppendMenu32A    (USER32.5)
03784  */
03785 BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
03786                              UINT id, LPCSTR data )
03787 {
03788     dprintf(("USER32: AppendMenuA %x %x %x %x", hMenu, flags, id, data));
03789 
03790     return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
03791 }
03792 
03793 
03794 /*******************************************************************
03795  *         AppendMenu32W    (USER32.6)
03796  */
03797 BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
03798                              UINT id, LPCWSTR data )
03799 {
03800     dprintf(("USER32: AppendMenuW %x %x %x %x", hMenu, flags, id, data));
03801 
03802     return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
03803 }
03804 
03805 
03806 /**********************************************************************
03807  *         RemoveMenu    (USER32.441)
03808  */
03809 BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
03810 {
03811     LPPOPUPMENU menu;
03812     MENUITEM *item;
03813 
03814     dprintf(("USER32: RemoveMenu %x %d %x", hMenu, nPos, wFlags));
03815 
03816     //TRACE("(menu=%04x pos=%04x flags=%04x)\n",hMenu, nPos, wFlags);
03817     if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
03818     if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
03819 
03820       /* Remove item */
03821 
03822     MENU_FreeItemData( item );
03823 
03824     if (--menu->nItems == 0)
03825     {
03826         HeapFree(GetProcessHeap(), 0, menu->items );
03827         menu->items = NULL;
03828     }
03829     else
03830     {
03831         while(nPos < menu->nItems)
03832         {
03833             *item = *(item+1);
03834             item++;
03835             nPos++;
03836         }
03837         menu->items = (MENUITEM*)HeapReAlloc(GetProcessHeap(), 0, menu->items,
03838                                              menu->nItems * sizeof(MENUITEM) );
03839     }
03840     return TRUE;
03841 }
03842 
03843 
03844 /**********************************************************************
03845  *         DeleteMenu32    (USER32.129)
03846  */
03847 BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags )
03848 {
03849     MENUITEM *item = MENU_FindItem( &hMenu, &nPos, wFlags );
03850 
03851     dprintf(("USER32: DeleteMenu %x %d %x", hMenu, nPos, wFlags));
03852 
03853     if (!item) return FALSE;
03854     if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu );
03855       /* nPos is now the position of the item */
03856     RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION );
03857     return TRUE;
03858 }
03859 
03860 
03861 /*******************************************************************
03862  *         ModifyMenu32A    (USER32.397)
03863  */
03864 BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
03865                              UINT id, LPCSTR str )
03866 {
03867     MENUITEM *item;
03868 
03869 
03870     if (IS_STRING_ITEM(flags))
03871     {
03872         dprintf(("USER32: ModifyMenuA, %x %d %x %d %s", hMenu, pos, flags, id, str));
03873         //TRACE("%04x %d %04x %04x '%s'\n",
03874         //              hMenu, pos, flags, id, str ? str : "#NULL#" );
03875         if (!str) return FALSE;
03876     }
03877     else
03878     {
03879         dprintf(("USER32: ModifyMenuA, %x %d %x %d %x", hMenu, pos, flags, id, str));
03880         //TRACE("%04x %d %04x %04x %08lx\n",
03881         //              hMenu, pos, flags, id, (DWORD)str );
03882     }
03883 
03884     if (!(item = MENU_FindItem( &hMenu, &pos, flags ))) return FALSE;
03885     return MENU_SetItemData( item, flags, id, str );
03886 }
03887 
03888 
03889 /*******************************************************************
03890  *         ModifyMenu32W    (USER32.398)
03891  */
03892 BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
03893                              UINT id, LPCWSTR str )
03894 {
03895     BOOL ret;
03896 
03897     if (IS_STRING_ITEM(flags) && str)
03898     {
03899         LPSTR newstr = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
03900         ret = ModifyMenuA( hMenu, pos, flags, id, newstr );
03901         HeapFree( GetProcessHeap(), 0, newstr );
03902         return ret;
03903     }
03904     else return ModifyMenuA( hMenu, pos, flags, id, (LPCSTR)str );
03905 }
03906 
03907 
03908 /**********************************************************************
03909  *         CreatePopupMenu32    (USER32.82)
03910  */
03911 HMENU WINAPI CreatePopupMenu(void)
03912 {
03913     HMENU hmenu;
03914     POPUPMENU *menu;
03915 
03916     dprintf(("USER32: CreatePopupMenu"));
03917 
03918     if (!(hmenu = CreateMenu())) return 0;
03919     menu = MENU_GetMenu(hmenu);
03920     menu->wFlags |= MF_POPUP;
03921     menu->bTimeToHide = FALSE;
03922     return hmenu;
03923 }
03924 
03925 
03926 /**********************************************************************
03927  *         GetMenuCheckMarkDimensions    (USER.417) (USER32.258)
03928  */
03929 DWORD WINAPI GetMenuCheckMarkDimensions(void)
03930 {
03931     dprintf(("USER32: GetMenuCheckMarkDimensions"));
03932 
03933     return MAKELONG( check_bitmap_width, check_bitmap_height );
03934 }
03935 
03936 
03937 /**********************************************************************
03938  *         SetMenuItemBitmaps32    (USER32.490)
03939  */
03940 BOOL WINAPI SetMenuItemBitmaps(HMENU hMenu, UINT nPos, UINT wFlags,
03941                                HBITMAP hNewUnCheck, HBITMAP hNewCheck)
03942 {
03943     MENUITEM *item;
03944 
03945     dprintf(("USER32: SetMenuItemBitmaps %x %d %x %x %x", hMenu, nPos, wFlags, hNewCheck, hNewUnCheck));
03946 
03947     //TRACE("(%04x, %04x, %04x, %04x, %04x)\n",
03948     //             hMenu, nPos, wFlags, hNewCheck, hNewUnCheck);
03949     if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
03950 
03951     if (!hNewCheck && !hNewUnCheck)
03952     {
03953         item->fState &= ~MF_USECHECKBITMAPS;
03954     }
03955     else  /* Install new bitmaps */
03956     {
03957         item->hCheckBit = hNewCheck;
03958         item->hUnCheckBit = hNewUnCheck;
03959         item->fState |= MF_USECHECKBITMAPS;
03960     }
03961     return TRUE;
03962 }
03963 
03964 
03965 /**********************************************************************
03966  *         CreateMenu    (USER32.81)
03967  */
03968 HMENU WINAPI CreateMenu(void)
03969 {
03970     HMENU hMenu;
03971     LPPOPUPMENU menu;
03972 
03973     dprintf(("USER32: CreateMenu"));
03974 
03975 #ifdef __WIN32OS2__
03976     if (!(menu = (LPPOPUPMENU)HeapAlloc(GetProcessHeap(),0,sizeof(POPUPMENU)))) return 0;
03977     if(ObjAllocateHandle(&hMenu, (DWORD)menu, USEROBJ_MENU) == FALSE) return 0;
03978 #else
03979     if (!(hMenu = (HMENU)HeapAlloc(GetProcessHeap(),0,sizeof(POPUPMENU)))) return 0;
03980     menu = (LPPOPUPMENU)hMenu;
03981 #endif
03982 
03983     ZeroMemory(menu, sizeof(POPUPMENU));
03984     menu->wMagic = MENU_MAGIC;
03985     menu->FocusedItem = NO_SELECTED_ITEM;
03986     menu->bTimeToHide = FALSE;
03987 
03988     //TRACE("return %04x\n", hMenu );
03989 
03990     return hMenu;
03991 }
03992 
03993 
03994 /**********************************************************************
03995  *         DestroyMenu32    (USER32.134)
03996  */
03997 BOOL WINAPI DestroyMenu( HMENU hMenu )
03998 {
03999     //TRACE("(%04x)\n", hMenu);
04000 
04001     dprintf(("USER32: DestroyMenu %x", hMenu));
04002 
04003     /* Silently ignore attempts to destroy default system popup */
04004 
04005     if (hMenu && hMenu != MENU_DefSysPopup)
04006     {
04007         LPPOPUPMENU lppop = MENU_GetMenu(hMenu);
04008         HWND pTPWnd = MENU_GetTopPopupWnd();
04009 
04010         if( pTPWnd && (hMenu == GetWindowLongA(pTPWnd,0)) )
04011           SetWindowLongA(pTPWnd,0,0);
04012 
04013         if (IS_A_MENU(lppop))
04014         {
04015             lppop->wMagic = 0;  /* Mark it as destroyed */
04016 
04017             if ((lppop->wFlags & MF_POPUP) && lppop->hWnd &&
04018                 (!pTPWnd || (lppop->hWnd != pTPWnd)))
04019                 DestroyWindow( lppop->hWnd );
04020 
04021             if (lppop->items)   /* recursively destroy submenus */
04022             {
04023                 int i;
04024                 MENUITEM *item = lppop->items;
04025                 for (i = lppop->nItems; i > 0; i--, item++)
04026                 {
04027                     if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
04028                     MENU_FreeItemData( item );
04029                 }
04030                 HeapFree(GetProcessHeap(), 0, lppop->items );
04031             }
04032 #ifdef __WIN32OS2__
04033             HeapFree(GetProcessHeap(),0,(LPVOID)lppop);
04034             ObjFreeHandle(hMenu);
04035 #else
04036             HeapFree(GetProcessHeap(),0,(LPVOID)hMenu);
04037 #endif
04038             MENU_ReleaseTopPopupWnd();
04039         }
04040         else
04041         {
04042             MENU_ReleaseTopPopupWnd();
04043             return FALSE;
04044         }
04045     }
04046     return (hMenu != MENU_DefSysPopup);
04047 }
04048 
04049 /**********************************************************************
04050  *         GetSystemMenu32    (USER32.291)
04051  */
04052 HMENU WINAPI GetSystemMenu( HWND hWnd, BOOL bRevert )
04053 {
04054     HMENU retvalue = 0;
04055 
04056     dprintf(("USER32: GetSystemMenu %x %d", hWnd, bRevert));
04057 
04058     if (IsWindow(hWnd))
04059     {
04060         HMENU hSysMenu = getSysMenu(hWnd);
04061         if(hSysMenu)
04062         {
04063             if( bRevert )
04064             {
04065                 DestroyMenu(hSysMenu);
04066                 hSysMenu = 0;
04067                 setSysMenu(hWnd,hSysMenu);
04068             }
04069             else
04070             {
04071                 POPUPMENU *menu = MENU_GetMenu(hSysMenu);
04072                 if(menu)
04073                 {
04074                    if( menu->nItems > 0 && menu->items[0].hSubMenu == MENU_DefSysPopup )
04075                       menu->items[0].hSubMenu = MENU_CopySysPopup();
04076                 }
04077                 else
04078                 {
04079                    //WARN("Current sys-menu (%04x) of wnd %04x is broken\n",
04080                    //     wndPtr->hSysMenu, hWnd);
04081                    hSysMenu = 0;
04082                    setSysMenu(hWnd,hSysMenu);
04083                 }
04084             }
04085         }
04086 
04087         if(!hSysMenu && (GetWindowLongA(hWnd,GWL_STYLE) & WS_SYSMENU) )
04088         {
04089             hSysMenu = MENU_GetSysMenu( hWnd, (HMENU)(-1) );
04090             setSysMenu(hWnd,hSysMenu);
04091         }
04092 
04093         if( hSysMenu )
04094         {
04095             POPUPMENU *menu;
04096             retvalue = GetSubMenu(hSysMenu, 0);
04097 
04098             /* Store the dummy sysmenu handle to facilitate the refresh */
04099             /* of the close button if the SC_CLOSE item change */
04100             menu = MENU_GetMenu(retvalue);
04101             if (menu)
04102                menu->hSysMenuOwner = hSysMenu;
04103         }
04104     }
04105     return retvalue;
04106 }
04107 
04108 
04109 /*******************************************************************
04110  *         SetSystemMenu32    (USER32.508)
04111  */
04112 BOOL WINAPI SetSystemMenu( HWND hwnd, HMENU hMenu )
04113 {
04114     Win32BaseWindow *win32wnd = Win32BaseWindow::GetWindowFromHandle(hwnd);
04115 
04116     dprintf(("USER32: SetSystemMenu"));
04117 
04118     if (win32wnd)
04119     {
04120         if (win32wnd->GetSysMenu()) DestroyMenu(win32wnd->GetSysMenu());
04121         win32wnd->SetSysMenu(MENU_GetSysMenu( hwnd, hMenu ));
04122         RELEASE_WNDOBJ(win32wnd);
04123         return TRUE;
04124     }
04125     return FALSE;
04126 }
04127 
04128 /**********************************************************************
04129  *         GetMenu32    (USER32.257)
04130  */
04131 HMENU WINAPI GetMenu( HWND hWnd )
04132 {
04133     HMENU retvalue;
04134 
04135     dprintf(("USER32: GetMenu %x %x", hWnd, GetWindowLongA( hWnd, GWL_ID )));
04136 
04137     if (GetWindowLongA(hWnd,GWL_STYLE) & WS_CHILD) {
04138         dprintf(("WARNING: window is child; no menu"));
04139         return 0;
04140     }
04141     retvalue = (HMENU)GetWindowLongA( hWnd, GWL_ID );
04142 #ifdef __WIN32OS2__
04143     if(MENU_GetMenu(retvalue) != NULL) {
04144         return retvalue;
04145     }
04146     return 0;
04147 #else
04148     return retvalue;
04149 #endif
04150 }
04151 
04152 /**********************************************************************
04153  *         SetMenu32    (USER32.487)
04154  */
04155 BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
04156 {
04157     //TRACE("(%04x, %04x);\n", hWnd, hMenu);
04158 
04159     dprintf(("USER32: SetMenu %x %x", hWnd, hMenu));
04160 
04161     if (hMenu && !IsMenu(hMenu))
04162     {
04163         //WARN("hMenu is not a menu handle\n");
04164         return FALSE;
04165     }
04166 
04167 
04168     if (!(GetWindowLongA(hWnd,GWL_STYLE) & WS_CHILD))
04169     {
04170         if (GetCapture() == hWnd) ReleaseCapture();
04171 
04172         if (hMenu != 0)
04173         {
04174             LPPOPUPMENU lpmenu;
04175 
04176             if (!(lpmenu = MENU_GetMenu(hMenu)))
04177             {
04178                 return FALSE;
04179             }
04180             lpmenu->hWnd = hWnd;
04181             lpmenu->wFlags &= ~MF_POPUP;  /* Can't be a popup */
04182             lpmenu->Height = 0;  /* Make sure we recalculate the size */
04183         }
04184         SetWindowLongA( hWnd, GWL_ID, hMenu );
04185 
04186 #ifdef __WIN32OS2__
04187 //SvL: This fixes the menu in standard mine sweeper (window isn't visible
04188 //     when SetMenu is called)
04189 //        if (IsWindowVisible(hWnd))
04190 #endif
04191             SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
04192                         SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
04193         return TRUE;
04194     }
04195     return FALSE;
04196 }
04197 
04198 
04199 /**********************************************************************
04200  *         GetSubMenu32    (USER32.288)
04201  */
04202 HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
04203 {
04204     MENUITEM * lpmi;
04205 
04206     dprintf(("USER32: GetSubMenu %x %d", hMenu, nPos));
04207 
04208 #ifdef __WIN32OS2__
04209     if (!(lpmi = MENU_FindItem(&hMenu,(UINT*)&nPos,MF_BYPOSITION)))  {
04210         SetLastError(ERROR_INVALID_HANDLE);
04211         return 0;
04212     }
04213 #else
04214     if (!(lpmi = MENU_FindItem(&hMenu,(UINT*)&nPos,MF_BYPOSITION))) return 0;
04215 #endif
04216 
04217     if (!(lpmi->fType & MF_POPUP)) return 0;
04218     return lpmi->hSubMenu;
04219 }
04220 
04221 
04222 /**********************************************************************
04223  *         DrawMenuBar    (USER32.161)
04224  */
04225 BOOL WINAPI DrawMenuBar( HWND hWnd )
04226 {
04227     LPPOPUPMENU lppop;
04228 
04229     dprintf(("USER32: DrawMenuBar %x", hWnd));
04230 
04231     if (!(GetWindowLongA(hWnd,GWL_STYLE) & WS_CHILD) && GetMenu(hWnd))
04232     {
04233         lppop = MENU_GetMenu(GetMenu(hWnd));
04234         if (lppop == NULL)
04235         {
04236             return FALSE;
04237         }
04238 
04239         lppop->Height = 0; /* Make sure we call MENU_MenuBarCalcSize */
04240         lppop->hwndOwner = hWnd;
04241         SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
04242                         SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
04243         return TRUE;
04244     }
04245     return FALSE;
04246 }
04247 
04248 
04249 /***********************************************************************
04250  *           EndMenu   (USER.187) (USER32.175)
04251  */
04252 void WINAPI EndMenu(void)
04253 {
04254     dprintf(("USER32: EndMenu not implemented!"));
04255     /*
04256      * FIXME: NOT ENOUGH! This has to cancel menu tracking right away.
04257      */
04258 
04259     fEndMenu = TRUE;
04260 }
04261 
04262 
04263 /*****************************************************************
04264  *        LoadMenu32A   (USER32.370)
04265  */
04266 HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
04267 {
04268     HRSRC hrsrc = FindResourceA( instance, name, RT_MENUA );
04269 
04270     dprintf(("USER32: LoadMenuA %x %x", instance, name));
04271 
04272     if (!hrsrc) return 0;
04273     return LoadMenuIndirectA( (MENUITEMTEMPLATEHEADER*)LoadResource( instance, hrsrc ));
04274 }
04275 
04276 
04277 /*****************************************************************
04278  *        LoadMenu32W   (USER32.373)
04279  */
04280 HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
04281 {
04282     HRSRC hrsrc = FindResourceW( instance, name, RT_MENUW );
04283 
04284     dprintf(("USER32: LoadMenuW %x %x", instance, name));
04285 
04286     if (!hrsrc) return 0;
04287     return LoadMenuIndirectW( (MENUITEMTEMPLATEHEADER*)LoadResource( instance, hrsrc ));
04288 }
04289 
04290 
04291 /**********************************************************************
04292  *          LoadMenuIndirect32A    (USER32.371)
04293  */
04294 HMENU WINAPI LoadMenuIndirectA(CONST MENUITEMTEMPLATEHEADER *lpMenuTemplate)
04295 {
04296     HMENU hMenu;
04297     WORD version, offset;
04298     LPCSTR p = (LPCSTR)lpMenuTemplate;
04299 
04300     dprintf(("USER32: LoadMenuIndirectA"));
04301 
04302     //TRACE("%p\n", template );
04303     version = GET_WORD(p);
04304     p += sizeof(WORD);
04305     switch (version)
04306       {
04307       case 0:
04308         offset = GET_WORD(p);
04309         p += sizeof(WORD) + offset;
04310         if (!(hMenu = CreateMenu())) return 0;
04311         if (!MENU_ParseResource( p, hMenu, TRUE ))
04312           {
04313             DestroyMenu( hMenu );
04314             return 0;
04315           }
04316         return hMenu;
04317       case 1:
04318         offset = GET_WORD(p);
04319         p += sizeof(WORD) + offset;
04320         if (!(hMenu = CreateMenu())) return 0;
04321         if (!MENUEX_ParseResource( p, hMenu))
04322           {
04323             DestroyMenu( hMenu );
04324             return 0;
04325           }
04326         return hMenu;
04327       default:
04328         //ERR("version %d not supported.\n", version);
04329         return 0;
04330       }
04331 }
04332 
04333 
04334 /**********************************************************************
04335  *          LoadMenuIndirect32W    (USER32.372)
04336  */
04337 HMENU WINAPI LoadMenuIndirectW(CONST MENUITEMTEMPLATEHEADER *lpMenuTemplate )
04338 {
04339     dprintf(("USER32: LoadMenuIndirectW"));
04340 
04341     /* FIXME: is there anything different between A and W? */
04342     return LoadMenuIndirectA(lpMenuTemplate);
04343 }
04344 
04345 
04346 /**********************************************************************
04347  *              IsMenu32    (USER32.346)
04348  */
04349 BOOL WINAPI IsMenu(HMENU hmenu)
04350 {
04351     LPPOPUPMENU menu = MENU_GetMenu(hmenu);
04352 
04353     dprintf(("USER32: IsMenu %x", hmenu));
04354 
04355     return IS_A_MENU(menu);
04356 }
04357 
04358 /**********************************************************************
04359  *              GetMenuItemInfo32_common
04360  */
04361 
04362 static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
04363                                         LPMENUITEMINFOA lpmii, BOOL unicode)
04364 {
04365     MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
04366 
04367     //debug_print_menuitem("GetMenuItemInfo32_common: ", menu, "");
04368 
04369     if (!menu)
04370         return FALSE;
04371 
04372     if (lpmii->fMask & MIIM_TYPE) {
04373         lpmii->fType = menu->fType;
04374         switch (MENU_ITEM_TYPE(menu->fType)) {
04375                 case MF_STRING:
04376                     if (menu->text) {
04377                         if (unicode) {
04378                             if(lpmii->dwTypeData && lpmii->cch)
04379                                 lstrcpynAtoW((LPWSTR) lpmii->dwTypeData, menu->text, lpmii->cch);
04380                             lpmii->cch = lstrlenA(menu->text);
04381                         } else {
04382                             if(lpmii->dwTypeData && lpmii->cch)
04383                                 lstrcpynA(lpmii->dwTypeData, menu->text, lpmii->cch);
04384                             lpmii->cch = lstrlenA(menu->text);
04385                         }
04386                     }
04387                     break;
04388                 case MF_OWNERDRAW:
04389                 case MF_BITMAP:
04390                     lpmii->dwTypeData = menu->text;
04391                     /* fall through */
04392                 default:
04393                     lpmii->cch = 0;
04394         }
04395     }
04396 
04397     if (lpmii->fMask & MIIM_STRING) {
04398         if (unicode) {
04399             lstrcpynAtoW((LPWSTR) lpmii->dwTypeData, menu->text, lpmii->cch);
04400             lpmii->cch = lstrlenW((LPWSTR)menu->text);
04401         } else {
04402             lstrcpynA(lpmii->dwTypeData, menu->text, lpmii->cch);
04403             lpmii->cch = lstrlenA(menu->text);
04404         }
04405     }
04406 
04407     if (lpmii->fMask & MIIM_FTYPE)
04408         lpmii->fType = menu->fType;
04409 
04410     if (lpmii->fMask & MIIM_BITMAP)
04411         lpmii->hbmpItem = menu->hbmpItem;
04412 
04413     if (lpmii->fMask & MIIM_STATE)
04414         lpmii->fState = menu->fState;
04415 
04416     if (lpmii->fMask & MIIM_ID)
04417         lpmii->wID = menu->wID;
04418 
04419     if (lpmii->fMask & MIIM_SUBMENU)
04420         lpmii->hSubMenu = menu->hSubMenu;
04421 
04422     if (lpmii->fMask & MIIM_CHECKMARKS) {
04423         lpmii->hbmpChecked = menu->hCheckBit;
04424         lpmii->hbmpUnchecked = menu->hUnCheckBit;
04425     }
04426     if (lpmii->fMask & MIIM_DATA)
04427         lpmii->dwItemData = menu->dwItemData;
04428 
04429   return TRUE;
04430 }
04431 
04432 /**********************************************************************
04433  *              GetMenuItemInfoA    (USER32.264)
04434  */
04435 BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
04436                                   LPMENUITEMINFOA lpmii)
04437 {
04438     dprintf(("USER32: GetMenuItemInfoA %x %d %d %x", hmenu, item, bypos, lpmii));
04439 
04440     return GetMenuItemInfo_common (hmenu, item, bypos, lpmii, FALSE);
04441 }
04442 
04443 /**********************************************************************
04444  *              GetMenuItemInfoW    (USER32.265)
04445  */
04446 BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
04447                                   LPMENUITEMINFOW lpmii)
04448 {
04449     dprintf(("USER32: GetMenuItemInfoW %x %d %d %x", hmenu, item, bypos, lpmii));
04450 
04451     return GetMenuItemInfo_common (hmenu, item, bypos,
04452                                      (LPMENUITEMINFOA)lpmii, TRUE);
04453 }
04454 
04455 /**********************************************************************
04456  *              SetMenuItemInfo32_common
04457  */
04458 
04459 static BOOL SetMenuItemInfo_common(MENUITEM * menu,
04460                                        const MENUITEMINFOA *lpmii,
04461                                        BOOL unicode)
04462 {
04463     if (!menu) return FALSE;
04464 
04465     if (lpmii->fMask & MIIM_TYPE ) {
04466         /* Get rid of old string.  */
04467         if ( IS_STRING_ITEM(menu->fType) && menu->text) {
04468             HeapFree(GetProcessHeap(), 0, menu->text);
04469             menu->text = NULL;
04470         }
04471 
04472         /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
04473         menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
04474         menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
04475 
04476         menu->text = lpmii->dwTypeData;
04477 
04478         if (IS_STRING_ITEM(menu->fType) && menu->text) {
04479             if (unicode)
04480                 menu->text = HEAP_strdupWtoA(GetProcessHeap(), 0,  (LPWSTR) lpmii->dwTypeData);
04481             else
04482                 menu->text = HEAP_strdupA(GetProcessHeap(), 0, lpmii->dwTypeData);
04483         }
04484     }
04485 
04486     if (lpmii->fMask & MIIM_FTYPE ) {
04487         /* free the string when the type is changing */
04488         if ( (!IS_STRING_ITEM(lpmii->fType)) && IS_STRING_ITEM(menu->fType) && menu->text) {
04489             HeapFree(GetProcessHeap(), 0, menu->text);
04490             menu->text = NULL;
04491         }
04492         menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
04493         menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
04494     }
04495 
04496     if (lpmii->fMask & MIIM_STRING ) {
04497         /* free the string when used */
04498         if ( IS_STRING_ITEM(menu->fType) && menu->text) {
04499             HeapFree(GetProcessHeap(), 0, menu->text);
04500             if (unicode)
04501                 menu->text = HEAP_strdupWtoA(GetProcessHeap(), 0,  (LPWSTR) lpmii->dwTypeData);
04502             else
04503                 menu->text = HEAP_strdupA(GetProcessHeap(), 0, lpmii->dwTypeData);
04504         }
04505     }
04506 
04507     if (lpmii->fMask & MIIM_STATE)
04508     {
04509         /* fixme: MFS_DEFAULT do we have to reset the other menu items? */
04510         menu->fState = lpmii->fState;
04511     }
04512 
04513     if (lpmii->fMask & MIIM_ID)
04514         menu->wID = lpmii->wID;
04515 
04516     if (lpmii->fMask & MIIM_SUBMENU) {
04517         menu->hSubMenu = lpmii->hSubMenu;
04518         if (menu->hSubMenu) {
04519             POPUPMENU *subMenu = MENU_GetMenu((UINT)menu->hSubMenu);
04520             if (IS_A_MENU(subMenu)) {
04521                 subMenu->wFlags |= MF_POPUP;
04522                 menu->fType |= MF_POPUP;
04523             }
04524             else
04525                 /* FIXME: Return an error ? */
04526                 menu->fType &= ~MF_POPUP;
04527         }
04528         else
04529             menu->fType &= ~MF_POPUP;
04530     }
04531 
04532     if (lpmii->fMask & MIIM_CHECKMARKS)
04533     {
04534         menu->hCheckBit = lpmii->hbmpChecked;
04535         menu->hUnCheckBit = lpmii->hbmpUnchecked;
04536     }
04537     if (lpmii->fMask & MIIM_DATA)
04538         menu->dwItemData = lpmii->dwItemData;
04539 
04540     //debug_print_menuitem("SetMenuItemInfo32_common: ", menu, "");
04541     return TRUE;
04542 }
04543 
04544 /**********************************************************************
04545  *              SetMenuItemInfo32A    (USER32.491)
04546  */
04547 BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
04548                                  const MENUITEMINFOA *lpmii)
04549 {
04550     dprintf(("USER32: SetMenuItemInfoA %x %d %d %x", hmenu, item, bypos, lpmii));
04551 
04552     return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
04553                                     lpmii, FALSE);
04554 }
04555 
04556 /**********************************************************************
04557  *              SetMenuItemInfo32W    (USER32.492)
04558  */
04559 BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
04560                                  const MENUITEMINFOW *lpmii)
04561 {
04562     dprintf(("USER32: SetMenuItemInfoW"));
04563 
04564     return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
04565                                     (const MENUITEMINFOA*)lpmii, TRUE);
04566 }
04567 
04568 /**********************************************************************
04569  *              SetMenuDefaultItem    (USER32.489)
04570  *
04571  */
04572 BOOL WINAPI SetMenuDefaultItem(HMENU hmenu, UINT uItem, UINT bypos)
04573 {
04574         UINT i;
04575         POPUPMENU *menu;
04576         MENUITEM *item;
04577 
04578 
04579         dprintf(("USER32: SetMenuDefaultItem"));
04580         //TRACE("(0x%x,%d,%d)\n", hmenu, uItem, bypos);
04581 
04582         if (!(menu = MENU_GetMenu(hmenu))) return FALSE;
04583 
04584         /* reset all default-item flags */
04585         item = menu->items;
04586         for (i = 0; i < menu->nItems; i++, item++)
04587         {
04588             item->fState &= ~MFS_DEFAULT;
04589         }
04590 
04591         /* no default item */
04592         if ( -1 == uItem)
04593         {
04594             return TRUE;
04595         }
04596 
04597         item = menu->items;
04598         if ( bypos )
04599         {
04600             if ( uItem >= menu->nItems ) return FALSE;
04601             item[uItem].fState |= MFS_DEFAULT;
04602             return TRUE;
04603         }
04604         else
04605         {
04606             for (i = 0; i < menu->nItems; i++, item++)
04607             {
04608                 if (item->wID == uItem)
04609                 {
04610                      item->fState |= MFS_DEFAULT;
04611                      return TRUE;
04612                 }
04613             }
04614 
04615         }
04616         return FALSE;
04617 }
04618 
04619 /**********************************************************************
04620  *              GetMenuDefaultItem    (USER32.260)
04621  */
04622 UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags)
04623 {
04624         POPUPMENU *menu;
04625         MENUITEM * item;
04626         UINT i = 0;
04627 
04628         dprintf(("USER32: GetMenuDefaultItem"));
04629         //TRACE("(0x%x,%d,%d)\n", hmenu, bypos, flags);
04630 
04631         if (!(menu = MENU_GetMenu(hmenu))) return -1;
04632 
04633         /* find default item */
04634         item = menu->items;
04635 
04636         /* empty menu */
04637         if (! item) return -1;
04638 
04639         while ( !( item->fState & MFS_DEFAULT ) )
04640         {
04641             i++; item++;
04642             if  (i >= menu->nItems ) return -1;
04643         }
04644 
04645         /* default: don't return disabled items */
04646         if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
04647 
04648         /* search rekursiv when needed */
04649         if ( (item->fType & MF_POPUP) &&  (flags & GMDI_GOINTOPOPUPS) )
04650         {
04651             UINT ret;
04652             ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags );
04653             if ( -1 != ret ) return ret;
04654 
04655             /* when item not found in submenu, return the popup item */
04656         }
04657         return ( bypos ) ? i : item->wID;
04658 
04659 }
04660 
04661 /**********************************************************************
04662  *              InsertMenuItem32A    (USER32.323)
04663  */
04664 BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
04665                                 const MENUITEMINFOA *lpmii)
04666 {
04667     MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
04668 
04669     dprintf(("USER32: InsertMenuItemA %x %d %d %x", hMenu, uItem, bypos, lpmii->wID));
04670 
04671     return SetMenuItemInfo_common(item, lpmii, FALSE);
04672 }
04673 
04674 
04675 /**********************************************************************
04676  *              InsertMenuItem32W    (USER32.324)
04677  */
04678 BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
04679                                 const MENUITEMINFOW *lpmii)
04680 {
04681     MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
04682 
04683     dprintf(("USER32: InsertMenuItemW"));
04684 
04685     return SetMenuItemInfo_common(item, (const MENUITEMINFOA*)lpmii, TRUE);
04686 }
04687 
04688 /**********************************************************************
04689  *              CheckMenuRadioItem32    (USER32.47)
04690  */
04691 
04692 BOOL WINAPI CheckMenuRadioItem(HMENU hMenu,
04693                                    UINT first, UINT last, UINT check,
04694                                    UINT bypos)
04695 {
04696      MENUITEM *mifirst, *milast, *micheck;
04697      HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu;
04698 
04699      dprintf(("USER32: CheckMenuRadioItem"));
04700      //TRACE("ox%x: %d-%d, check %d, bypos=%d\n",
04701      //             hMenu, first, last, check, bypos);
04702 
04703      mifirst = MENU_FindItem (&mfirst, &first, bypos);
04704      milast = MENU_FindItem (&mlast, &last, bypos);
04705      micheck = MENU_FindItem (&mcheck, &check, bypos);
04706 
04707      if (mifirst == NULL || milast == NULL || micheck == NULL ||
04708          mifirst > milast || mfirst != mlast || mfirst != mcheck ||
04709          micheck > milast || micheck < mifirst)
04710           return FALSE;
04711 
04712      while (mifirst <= milast)
04713      {
04714           if (mifirst == micheck)
04715           {
04716                mifirst->fType |= MFT_RADIOCHECK;
04717                mifirst->fState |= MFS_CHECKED;
04718           } else {
04719                mifirst->fType &= ~MFT_RADIOCHECK;
04720                mifirst->fState &= ~MFS_CHECKED;
04721           }
04722           mifirst++;
04723      }
04724 
04725      return TRUE;
04726 }
04727 
04728 /**********************************************************************
04729  *              GetMenuItemRect32    (USER32.266)
04730  *
04731  *      ATTENTION: Here, the returned values in rect are the screen
04732  *                 coordinates of the item just like if the menu was
04733  *                 always on the upper left side of the application.
04734  *
04735  */
04736 BOOL WINAPI GetMenuItemRect (HWND hwnd, HMENU hMenu, UINT uItem,
04737                                  LPRECT rect)
04738 {
04739      POPUPMENU *itemMenu;
04740      MENUITEM *item;
04741      HWND referenceHwnd;
04742 
04743      //TRACE("(0x%x,0x%x,%d,%p)\n", hwnd, hMenu, uItem, rect);
04744 
04745      item = MENU_FindItem (&hMenu, &uItem, MF_BYPOSITION);
04746      referenceHwnd = hwnd;
04747 
04748      if(!hwnd)
04749      {
04750          itemMenu = MENU_GetMenu(hMenu);
04751          if (itemMenu == NULL) {
04752                 SetLastError(ERROR_INVALID_PARAMETER);
04753                 return FALSE;
04754          }
04755 
04756          if(itemMenu->hWnd == 0)
04757              return FALSE;
04758          referenceHwnd = itemMenu->hWnd;
04759      }
04760 
04761      if ((rect == NULL) || (item == NULL)) {
04762         SetLastError(ERROR_INVALID_PARAMETER);
04763         return FALSE;
04764      }
04765      *rect = item->rect;
04766 
04767      MapWindowPoints(referenceHwnd, 0, (LPPOINT)rect, 2);
04768      dprintf(("USER32: GetMenuItemRect %x %x %d (%d,%d)(%d,%d)", hwnd, hMenu, uItem, rect->left, rect->top, rect->right, rect->bottom));
04769 
04770      return TRUE;
04771 }
04772 
04773 /**********************************************************************
04774  *              SetMenuInfo
04775  *
04776  * FIXME
04777  *      MIM_APPLYTOSUBMENUS
04778  *      actually use the items to draw the menu
04779  */
04780 BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi)
04781 {
04782     POPUPMENU *menu;
04783 
04784     dprintf(("USER32: SetMenuInfo"));
04785     //TRACE("(0x%04x %p)\n", hMenu, lpmi);
04786 
04787     if (lpmi && (lpmi->cbSize==sizeof(MENUINFO)) && (menu=MENU_GetMenu(hMenu)))
04788     {
04789 
04790         if (lpmi->fMask & MIM_BACKGROUND)
04791             menu->hbrBack = lpmi->hbrBack;
04792 
04793         if (lpmi->fMask & MIM_HELPID)
04794             menu->dwContextHelpID = lpmi->dwContextHelpID;
04795 
04796         if (lpmi->fMask & MIM_MAXHEIGHT)
04797             menu->cyMax = lpmi->cyMax;
04798 
04799         if (lpmi->fMask & MIM_MENUDATA)
04800             menu->dwMenuData = lpmi->dwMenuData;
04801 
04802         if (lpmi->fMask & MIM_STYLE)
04803             menu->dwStyle = lpmi->dwStyle;
04804 
04805         return TRUE;
04806     }
04807     return FALSE;
04808 }
04809 
04810 /**********************************************************************
04811  *              GetMenuInfo
04812  *
04813  *  NOTES
04814  *      win98/NT5.0
04815  *
04816  */
04817 BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi)
04818 {   POPUPMENU *menu;
04819 
04820     dprintf(("USER32: GetMenuInfo"));
04821     //TRACE("(0x%04x %p)\n", hMenu, lpmi);
04822 
04823     if (lpmi && (menu = MENU_GetMenu(hMenu)))
04824     {
04825 
04826         if (lpmi->fMask & MIM_BACKGROUND)
04827             lpmi->hbrBack = menu->hbrBack;
04828 
04829         if (lpmi->fMask & MIM_HELPID)
04830             lpmi->dwContextHelpID = menu->dwContextHelpID;
04831 
04832         if (lpmi->fMask & MIM_MAXHEIGHT)
04833             lpmi->cyMax = menu->cyMax;
04834 
04835         if (lpmi->fMask & MIM_MENUDATA)
04836             lpmi->dwMenuData = menu->dwMenuData;
04837 
04838         if (lpmi->fMask & MIM_STYLE)
04839             lpmi->dwStyle = menu->dwStyle;
04840 
04841         return TRUE;
04842     }
04843     return FALSE;
04844 }
04845 
04846 /**********************************************************************
04847  *         SetMenuContextHelpId    (USER32.488)
04848  */
04849 BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID)
04850 {
04851     LPPOPUPMENU menu;
04852 
04853     dprintf(("USER32: SetMenuContextHelpId"));
04854     //TRACE("(0x%04x 0x%08lx)\n", hMenu, dwContextHelpID);
04855 
04856     menu = MENU_GetMenu(hMenu);
04857     if (menu)
04858     {
04859         menu->dwContextHelpID = dwContextHelpID;
04860         return TRUE;
04861     }
04862     return FALSE;
04863 }
04864 
04865 /**********************************************************************
04866  *         GetMenuContextHelpId    (USER32.488)
04867  */
04868 DWORD WINAPI GetMenuContextHelpId( HMENU hMenu )
04869 {
04870     LPPOPUPMENU menu;
04871 
04872     dprintf(("USER32: GetMenuContextHelpId"));
04873 
04874     menu = MENU_GetMenu(hMenu);
04875     if (menu)
04876     {
04877         return menu->dwContextHelpID;
04878     }
04879     return 0;
04880 }
04881 
04882 /**********************************************************************
04883  *         MenuItemFromPoint    (USER32.387)
04884  */
04885 UINT WINAPI MenuItemFromPoint(HWND hWnd, HMENU hMenu, POINT ptScreen)
04886 {
04887     dprintf(("USER32: MenuItemFromPoint not implemented!"));
04888 
04889     return 0;
04890 }
04891 
04892 /**********************************************************************
04893  *         IsMenuActive    (Internal)
04894  */
04895 BOOL IsMenuActive(void)
04896 {
04897     return pTopPopupWnd &&  (GetWindowLongA(pTopPopupWnd,GWL_STYLE) & WS_VISIBLE);
04898 }
04899 
04900 BOOL POPUPMENU_Register()
04901 {
04902     WNDCLASSA wndClass;
04903     BOOL rc;
04904 
04905 //SvL: Don't check this now
04906 //    if (GlobalFindAtomA(POPUPMENUCLASSNAME)) return FALSE;
04907 
04908     ZeroMemory(&wndClass,sizeof(WNDCLASSA));
04909     wndClass.style         = CS_GLOBALCLASS | CS_SAVEBITS;
04910     wndClass.lpfnWndProc   = (WNDPROC)PopupMenuWndProc;
04911     wndClass.cbClsExtra    = 0;
04912     wndClass.cbWndExtra    = sizeof(HMENU);
04913     wndClass.hCursor       = LoadCursorA(0,IDC_ARROWA);
04914     wndClass.hbrBackground = NULL_BRUSH;
04915     wndClass.lpszClassName = POPUPMENUCLASSNAME;
04916 
04917     rc = RegisterClassA(&wndClass);
04918     MENU_Init();
04919 
04920     return rc;
04921 }
04922 //******************************************************************************
04923 //******************************************************************************
04924 BOOL POPUPMENU_Unregister()
04925 {
04926     if (GlobalFindAtomA(POPUPMENUCLASSNAME))
04927         return UnregisterClassA(POPUPMENUCLASSNAME,(HINSTANCE)NULL);
04928     else return FALSE;
04929 }
04930 //******************************************************************************
04931 //******************************************************************************
04932 #ifdef __WIN32OS2__
04933 void DisableOdinSysMenuItems()
04934 {
04935     fDisableOdinSysMenuItems = TRUE;
04936 }
04937 //******************************************************************************
04938 //******************************************************************************
04939 #endif

Generated on Wed Jan 23 23:17:37 2002 for ODIN-user32 by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001