Create a new window for the top popup menu on every new menu tracking,

so that the window belongs to the right thread.
This commit is contained in:
Alexandre Julliard 2001-05-11 20:05:42 +00:00
parent ee285b7ac8
commit e60ccd11d3
4 changed files with 56 additions and 236 deletions

View File

@ -25,13 +25,11 @@
#include "wine/unicode.h" #include "wine/unicode.h"
#include "wine/port.h" #include "wine/port.h"
#include "win.h" #include "win.h"
#include "task.h"
#include "heap.h" #include "heap.h"
#include "controls.h" #include "controls.h"
#include "nonclient.h" #include "nonclient.h"
#include "user.h" #include "user.h"
#include "message.h" #include "message.h"
#include "queue.h"
#include "debugtools.h" #include "debugtools.h"
@ -65,10 +63,9 @@ typedef struct {
typedef struct { typedef struct {
WORD wFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */ WORD wFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */
WORD wMagic; /* Magic number */ WORD wMagic; /* Magic number */
HQUEUE16 hTaskQ; /* Task queue for this menu */
WORD Width; /* Width of the whole menu */ WORD Width; /* Width of the whole menu */
WORD Height; /* Height of the whole menu */ WORD Height; /* Height of the whole menu */
WORD nItems; /* Number of items in the menu */ UINT nItems; /* Number of items in the menu */
HWND hWnd; /* Window containing the menu */ HWND hWnd; /* Window containing the menu */
MENUITEM *items; /* Array of menu items */ MENUITEM *items; /* Array of menu items */
UINT FocusedItem; /* Currently focused item */ UINT FocusedItem; /* Currently focused item */
@ -99,7 +96,6 @@ typedef struct
} MTRACKER; } MTRACKER;
#define MENU_MAGIC 0x554d /* 'MU' */ #define MENU_MAGIC 0x554d /* 'MU' */
#define IS_A_MENU(pmenu) ((pmenu) && (pmenu)->wMagic == MENU_MAGIC)
#define ITEM_PREV -1 #define ITEM_PREV -1
#define ITEM_NEXT 1 #define ITEM_NEXT 1
@ -167,9 +163,7 @@ static HMENU MENU_DefSysPopup = 0; /* Default system menu popup */
/* Use global popup window because there's no way 2 menus can /* Use global popup window because there's no way 2 menus can
* be tracked at the same time. */ * be tracked at the same time. */
static HWND top_popup;
static WND* pTopPopupWnd = 0;
static UINT uSubPWndLevel = 0;
/* Flag set by EndMenu() to force an exit from menu tracking */ /* Flag set by EndMenu() to force an exit from menu tracking */
static BOOL fEndMenu = FALSE; static BOOL fEndMenu = FALSE;
@ -294,9 +288,8 @@ static void do_debug_print_menuitem(const char *prefix, MENUITEM * mp,
*/ */
POPUPMENU *MENU_GetMenu(HMENU hMenu) POPUPMENU *MENU_GetMenu(HMENU hMenu)
{ {
POPUPMENU *menu; POPUPMENU *menu = USER_HEAP_LIN_ADDR(hMenu);
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu); if (!menu || menu->wMagic != MENU_MAGIC)
if (!IS_A_MENU(menu))
{ {
WARN("invalid menu handle=%x, ptr=%p, magic=%x\n", hMenu, menu, menu? menu->wMagic:0); WARN("invalid menu handle=%x, ptr=%p, magic=%x\n", hMenu, menu, menu? menu->wMagic:0);
menu = NULL; menu = NULL;
@ -314,51 +307,18 @@ static HMENU MENU_CopySysPopup(void)
HMENU hMenu = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU"); HMENU hMenu = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU");
if( hMenu ) { if( hMenu ) {
POPUPMENU* menu = (POPUPMENU *) USER_HEAP_LIN_ADDR(hMenu); POPUPMENU* menu = MENU_GetMenu(hMenu);
menu->wFlags |= MF_SYSMENU | MF_POPUP; menu->wFlags |= MF_SYSMENU | MF_POPUP;
SetMenuDefaultItem(hMenu, SC_CLOSE, FALSE); SetMenuDefaultItem(hMenu, SC_CLOSE, FALSE);
} }
else { else
hMenu = 0;
ERR("Unable to load default system menu\n" ); ERR("Unable to load default system menu\n" );
}
TRACE("returning %x.\n", hMenu ); TRACE("returning %x.\n", hMenu );
return hMenu; return hMenu;
} }
/***********************************************************************
* MENU_GetTopPopupWnd()
*
* Return the locked pointer pTopPopupWnd.
*/
static WND *MENU_GetTopPopupWnd()
{
return WIN_LockWndPtr(pTopPopupWnd);
}
/***********************************************************************
* MENU_ReleaseTopPopupWnd()
*
* Release the locked pointer pTopPopupWnd.
*/
static void MENU_ReleaseTopPopupWnd()
{
WIN_ReleaseWndPtr(pTopPopupWnd);
}
/***********************************************************************
* MENU_DestroyTopPopupWnd()
*
* Destroy the locked pointer pTopPopupWnd.
*/
static void MENU_DestroyTopPopupWnd()
{
WND *tmpWnd = pTopPopupWnd;
pTopPopupWnd = NULL;
WIN_ReleaseWndPtr(tmpWnd);
}
/********************************************************************** /**********************************************************************
* MENU_GetSysMenu * MENU_GetSysMenu
@ -375,7 +335,7 @@ HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu )
if ((hMenu = CreateMenu())) if ((hMenu = CreateMenu()))
{ {
POPUPMENU *menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hMenu); POPUPMENU *menu = MENU_GetMenu(hMenu);
menu->wFlags = MF_SYSMENU; menu->wFlags = MF_SYSMENU;
menu->hWnd = hWnd; menu->hWnd = hWnd;
@ -389,8 +349,7 @@ HMENU MENU_GetSysMenu( HWND hWnd, HMENU hPopupMenu )
menu->items[0].fType = MF_SYSMENU | MF_POPUP; menu->items[0].fType = MF_SYSMENU | MF_POPUP;
menu->items[0].fState = 0; menu->items[0].fState = 0;
menu = (POPUPMENU*) USER_HEAP_LIN_ADDR(hPopupMenu); if ((menu = MENU_GetMenu(hPopupMenu))) menu->wFlags |= MF_SYSMENU;
menu->wFlags |= MF_SYSMENU;
TRACE("GetSysMenu hMenu=%04x (%04x)\n", hMenu, hPopupMenu ); TRACE("GetSysMenu hMenu=%04x (%04x)\n", hMenu, hPopupMenu );
return hMenu; return hMenu;
@ -500,12 +459,13 @@ static void MENU_InitSysMenuPopup( HMENU hmenu, DWORD style, DWORD clsStyle )
static UINT MENU_GetStartOfNextColumn( static UINT MENU_GetStartOfNextColumn(
HMENU hMenu ) HMENU hMenu )
{ {
POPUPMENU *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu); POPUPMENU *menu = MENU_GetMenu(hMenu);
UINT i = menu->FocusedItem + 1; UINT i;
if(!menu) if(!menu)
return NO_SELECTED_ITEM; return NO_SELECTED_ITEM;
i = menu->FocusedItem + 1;
if( i == NO_SELECTED_ITEM ) if( i == NO_SELECTED_ITEM )
return i; return i;
@ -528,7 +488,7 @@ static UINT MENU_GetStartOfNextColumn(
static UINT MENU_GetStartOfPrevColumn( static UINT MENU_GetStartOfPrevColumn(
HMENU hMenu ) HMENU hMenu )
{ {
POPUPMENU const *menu = (POPUPMENU *)USER_HEAP_LIN_ADDR(hMenu); POPUPMENU *menu = MENU_GetMenu(hMenu);
UINT i; UINT i;
if( !menu ) if( !menu )
@ -1559,63 +1519,6 @@ END:
return retvalue; return retvalue;
} }
/***********************************************************************
* MENU_PatchResidentPopup
*/
BOOL MENU_PatchResidentPopup( HQUEUE16 checkQueue, WND* checkWnd )
{
WND *pTPWnd = MENU_GetTopPopupWnd();
if( pTPWnd )
{
HTASK16 hTask = 0;
TRACE("patching resident popup: %04x %04x [%04x %04x]\n",
checkQueue, checkWnd ? checkWnd->hwndSelf : 0, pTPWnd->hmemTaskQ,
pTPWnd->owner ? pTPWnd->owner->hwndSelf : 0);
switch( checkQueue )
{
case 0: /* checkWnd is the new popup owner */
if( checkWnd )
{
pTPWnd->owner = checkWnd;
if( pTPWnd->hmemTaskQ != checkWnd->hmemTaskQ )
hTask = QUEUE_GetQueueTask( checkWnd->hmemTaskQ );
}
break;
case 0xFFFF: /* checkWnd is destroyed */
if( pTPWnd->owner == checkWnd )
pTPWnd->owner = NULL;
MENU_ReleaseTopPopupWnd();
return TRUE;
default: /* checkQueue is exiting */
if( pTPWnd->hmemTaskQ == checkQueue )
{
hTask = QUEUE_GetQueueTask( pTPWnd->hmemTaskQ );
hTask = TASK_GetNextTask( hTask );
}
break;
}
if( hTask )
{
TDB* task = TASK_GetPtr( hTask );
if( task )
{
pTPWnd->hInstance = task->hInstance;
pTPWnd->hmemTaskQ = task->hQueue;
MENU_ReleaseTopPopupWnd();
return TRUE;
}
else WARN("failed to patch resident popup.\n");
}
}
MENU_ReleaseTopPopupWnd();
return FALSE;
}
/*********************************************************************** /***********************************************************************
* MENU_ShowPopup * MENU_ShowPopup
@ -1677,27 +1580,6 @@ static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id,
} }
/* NOTE: In Windows, top menu popup is not owned. */ /* NOTE: In Windows, top menu popup is not owned. */
if (!pTopPopupWnd) /* create top level popup menu window */
{
assert( uSubPWndLevel == 0 );
pTopPopupWnd = WIN_FindWndPtr(CreateWindowA( POPUPMENU_CLASS_ATOM, NULL,
WS_POPUP, x, y, width, height,
hwndOwner, 0, wndOwner->hInstance,
(LPVOID)hmenu ));
if (!pTopPopupWnd)
{
WIN_ReleaseWndPtr(wndOwner);
return FALSE;
}
menu->hWnd = pTopPopupWnd->hwndSelf;
MENU_ReleaseTopPopupWnd();
}
else
if( uSubPWndLevel )
{
/* create a new window for the submenu */
menu->hWnd = CreateWindowA( POPUPMENU_CLASS_ATOM, NULL, menu->hWnd = CreateWindowA( POPUPMENU_CLASS_ATOM, NULL,
WS_POPUP, x, y, width, height, WS_POPUP, x, y, width, height,
hwndOwner, 0, wndOwner->hInstance, hwndOwner, 0, wndOwner->hInstance,
@ -1707,23 +1589,7 @@ static BOOL MENU_ShowPopup( HWND hwndOwner, HMENU hmenu, UINT id,
WIN_ReleaseWndPtr(wndOwner); WIN_ReleaseWndPtr(wndOwner);
return FALSE; return FALSE;
} }
} if (!top_popup) top_popup = menu->hWnd;
else /* top level popup menu window already exists */
{
WND *pTPWnd = MENU_GetTopPopupWnd();
menu->hWnd = pTPWnd->hwndSelf;
MENU_PatchResidentPopup( 0, wndOwner );
SendMessageA( pTPWnd->hwndSelf, MM_SETMENUHANDLE, (WPARAM16)hmenu, 0L);
/* adjust its size */
SetWindowPos( menu->hWnd, 0, x, y, width, height,
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW);
MENU_ReleaseTopPopupWnd();
}
uSubPWndLevel++; /* menu level counter */
/* Display the window */ /* Display the window */
@ -1789,7 +1655,7 @@ static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, UINT wIndex,
if(topmenu){ if(topmenu){
int pos; int pos;
if((pos=MENU_FindSubMenu(&topmenu, hmenu))!=NO_SELECTED_ITEM){ if((pos=MENU_FindSubMenu(&topmenu, hmenu))!=NO_SELECTED_ITEM){
POPUPMENU *ptm = (POPUPMENU *) USER_HEAP_LIN_ADDR( topmenu ); POPUPMENU *ptm = MENU_GetMenu( topmenu );
MENUITEM *ip = &ptm->items[pos]; MENUITEM *ip = &ptm->items[pos];
SendMessageA( hwndOwner, WM_MENUSELECT, MAKELONG(pos, SendMessageA( hwndOwner, WM_MENUSELECT, MAKELONG(pos,
ip->fType | ip->fState | MF_MOUSESELECT | ip->fType | ip->fState | MF_MOUSESELECT |
@ -2102,7 +1968,7 @@ static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, sendMenuSelect); TRACE("owner=0x%04x hmenu=0x%04x 0x%04x\n", hwndOwner, hmenu, sendMenuSelect);
if (menu && uSubPWndLevel) if (menu && top_popup)
{ {
HMENU hsubmenu; HMENU hsubmenu;
POPUPMENU *submenu; POPUPMENU *submenu;
@ -2120,19 +1986,9 @@ static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu,
submenu = MENU_GetMenu( hsubmenu ); submenu = MENU_GetMenu( hsubmenu );
MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE ); MENU_HideSubPopups( hwndOwner, hsubmenu, FALSE );
MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect, 0 ); MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM, sendMenuSelect, 0 );
if (submenu->hWnd == MENU_GetTopPopupWnd()->hwndSelf )
{
ShowWindow( submenu->hWnd, SW_HIDE );
uSubPWndLevel = 0;
}
else
{
DestroyWindow( submenu->hWnd ); DestroyWindow( submenu->hWnd );
submenu->hWnd = 0; submenu->hWnd = 0;
} }
MENU_ReleaseTopPopupWnd();
}
} }
@ -2240,7 +2096,7 @@ static HMENU MENU_ShowSubPopup( HWND hwndOwner, HMENU hmenu,
*/ */
BOOL MENU_IsMenuActive(void) BOOL MENU_IsMenuActive(void)
{ {
return pTopPopupWnd && (pTopPopupWnd->dwStyle & WS_VISIBLE); return (top_popup != 0);
} }
/*********************************************************************** /***********************************************************************
@ -2986,8 +2842,8 @@ static INT MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y,
if (menu && menu->wFlags & MF_POPUP) if (menu && menu->wFlags & MF_POPUP)
{ {
ShowWindow( menu->hWnd, SW_HIDE ); DestroyWindow( menu->hWnd );
uSubPWndLevel = 0; menu->hWnd = 0;
} }
MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE, 0 ); MENU_SelectItem( mt.hOwnerWnd, mt.hTopMenu, NO_SELECTED_ITEM, FALSE, 0 );
SendMessageA( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0xffff), 0 ); SendMessageA( mt.hOwnerWnd, WM_MENUSELECT, MAKELONG(0,0xffff), 0 );
@ -3216,23 +3072,8 @@ static LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam,
return 1; return 1;
case WM_DESTROY: case WM_DESTROY:
/* zero out global pointer in case resident popup window was destroyed. */
/* zero out global pointer in case resident popup window if (hwnd == top_popup) top_popup = 0;
* was somehow destroyed. */
if(MENU_GetTopPopupWnd() )
{
if( hwnd == pTopPopupWnd->hwndSelf )
{
ERR("resident popup destroyed!\n");
MENU_DestroyTopPopupWnd();
uSubPWndLevel = 0;
}
else
uSubPWndLevel--;
MENU_ReleaseTopPopupWnd();
}
break; break;
case WM_SHOWWINDOW: case WM_SHOWWINDOW:
@ -3790,8 +3631,8 @@ BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
if (IS_STRING_ITEM(flags)) if (IS_STRING_ITEM(flags))
{ {
TRACE("%04x %d %04x %04x '%s'\n", TRACE("%04x %d %04x %04x %s\n",
hMenu, pos, flags, id, str ? debugstr_w(str) : "#NULL#" ); hMenu, pos, flags, id, debugstr_w(str) );
if (!str) return FALSE; if (!str) return FALSE;
} }
else else
@ -3842,7 +3683,7 @@ HMENU WINAPI CreatePopupMenu(void)
POPUPMENU *menu; POPUPMENU *menu;
if (!(hmenu = CreateMenu())) return 0; if (!(hmenu = CreateMenu())) return 0;
menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ); menu = MENU_GetMenu( hmenu );
menu->wFlags |= MF_POPUP; menu->wFlags |= MF_POPUP;
menu->bTimeToHide = FALSE; menu->bTimeToHide = FALSE;
return hmenu; return hmenu;
@ -3943,19 +3784,13 @@ BOOL WINAPI DestroyMenu( HMENU hMenu )
if (hMenu && hMenu != MENU_DefSysPopup) if (hMenu && hMenu != MENU_DefSysPopup)
{ {
LPPOPUPMENU lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu); LPPOPUPMENU lppop = MENU_GetMenu(hMenu);
WND *pTPWnd = MENU_GetTopPopupWnd();
if( pTPWnd && (hMenu == *(HMENU*)pTPWnd->wExtra) ) if (!lppop) return FALSE;
*(UINT*)pTPWnd->wExtra = 0;
if (!IS_A_MENU(lppop)) lppop = NULL;
if ( lppop )
{
lppop->wMagic = 0; /* Mark it as destroyed */ lppop->wMagic = 0; /* Mark it as destroyed */
if ((lppop->wFlags & MF_POPUP) && lppop->hWnd && if ((lppop->wFlags & MF_POPUP) && lppop->hWnd)
(!pTPWnd || (lppop->hWnd != pTPWnd->hwndSelf)))
DestroyWindow( lppop->hWnd ); DestroyWindow( lppop->hWnd );
if (lppop->items) /* recursively destroy submenus */ if (lppop->items) /* recursively destroy submenus */
@ -3970,13 +3805,6 @@ BOOL WINAPI DestroyMenu( HMENU hMenu )
HeapFree( GetProcessHeap(), 0, lppop->items ); HeapFree( GetProcessHeap(), 0, lppop->items );
} }
USER_HEAP_FREE( hMenu ); USER_HEAP_FREE( hMenu );
MENU_ReleaseTopPopupWnd();
}
else
{
MENU_ReleaseTopPopupWnd();
return FALSE;
}
} }
return (hMenu != MENU_DefSysPopup); return (hMenu != MENU_DefSysPopup);
} }
@ -4224,7 +4052,7 @@ DWORD WINAPI DrawMenuBarTemp(DWORD p1, DWORD p2)
void WINAPI EndMenu(void) void WINAPI EndMenu(void)
{ {
/* if we are in the menu code, and it is active */ /* if we are in the menu code, and it is active */
if (fEndMenu == FALSE && MENU_IsMenuActive()) if (!fEndMenu && top_popup)
{ {
/* terminate the menu handling code */ /* terminate the menu handling code */
fEndMenu = TRUE; fEndMenu = TRUE;
@ -4233,7 +4061,7 @@ void WINAPI EndMenu(void)
/* which will now terminate the menu, in the event that */ /* which will now terminate the menu, in the event that */
/* the main window was minimized, or lost focus, so we */ /* the main window was minimized, or lost focus, so we */
/* don't end up with an orphaned menu */ /* don't end up with an orphaned menu */
PostMessageA( pTopPopupWnd->hwndSelf, WM_CANCELMODE, 0, 0); PostMessageA( top_popup, WM_CANCELMODE, 0, 0);
} }
} }
@ -4387,8 +4215,7 @@ HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
*/ */
BOOL16 WINAPI IsMenu16( HMENU16 hmenu ) BOOL16 WINAPI IsMenu16( HMENU16 hmenu )
{ {
LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hmenu); return IsMenu( hmenu );
return IS_A_MENU(menu);
} }
@ -4397,8 +4224,8 @@ BOOL16 WINAPI IsMenu16( HMENU16 hmenu )
*/ */
BOOL WINAPI IsMenu(HMENU hmenu) BOOL WINAPI IsMenu(HMENU hmenu)
{ {
LPPOPUPMENU menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hmenu); LPPOPUPMENU menu = MENU_GetMenu(hmenu);
return IS_A_MENU(menu); return menu != NULL;
} }
/********************************************************************** /**********************************************************************

View File

@ -44,7 +44,6 @@ extern BOOL MENU_IsMenuActive(void);
extern HMENU MENU_GetSysMenu(HWND hWndOwner, HMENU hSysPopup); extern HMENU MENU_GetSysMenu(HWND hWndOwner, HMENU hSysPopup);
extern UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth, extern UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth,
INT orgX, INT orgY ); INT orgX, INT orgY );
extern BOOL MENU_PatchResidentPopup( HQUEUE16, struct tagWND* );
extern void MENU_TrackMouseMenuBar( struct tagWND *wnd, INT ht, POINT pt ); extern void MENU_TrackMouseMenuBar( struct tagWND *wnd, INT ht, POINT pt );
extern void MENU_TrackKbdMenuBar( struct tagWND *wnd, UINT wParam, INT vkey ); extern void MENU_TrackKbdMenuBar( struct tagWND *wnd, UINT wParam, INT vkey );
extern UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, extern UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect,

View File

@ -117,9 +117,6 @@ static void USER_QueueCleanup( HQUEUE16 hQueue )
desktop->hmemTaskQ = GetTaskQueue16( nextTask ); desktop->hmemTaskQ = GetTaskQueue16( nextTask );
} }
/* Patch resident popup menu window */
MENU_PatchResidentPopup( hQueue, NULL );
TIMER_RemoveQueueTimers( hQueue ); TIMER_RemoveQueueTimers( hQueue );
HOOK_FreeQueueHooks( hQueue ); HOOK_FreeQueueHooks( hQueue );

View File

@ -1379,9 +1379,6 @@ BOOL WINAPI DestroyWindow( HWND hwnd )
if( !(wndPtr->dwStyle & WS_CHILD) ) if( !(wndPtr->dwStyle & WS_CHILD) )
{ {
/* make sure top menu popup doesn't get destroyed */
MENU_PatchResidentPopup( (HQUEUE16)0xFFFF, wndPtr );
for (;;) for (;;)
{ {
WND *siblingPtr = WIN_LockWndPtr(wndPtr->parent->child); /* First sibling */ WND *siblingPtr = WIN_LockWndPtr(wndPtr->parent->child); /* First sibling */