mirror of
https://github.com/Open-Shell/Open-Shell-Menu.git
synced 2026-04-12 01:47:24 +10:00
In several cases we don't want menu(s) to close when an action on menu was done. For example on drag-n-drop or menu item deletion (where confirmation dialog is shown). In such situations `s_bPreventClosing` was set to true (and then back to false when closing was allowed again). Though original code honored this variable only in certain situations and typically (at least on Win10) menus were hidden/closed despite of it. This patch changes the behavior and menus(s) are not closed when `s_bPreventClosing` is set to true. Basically now menu(s) stay visible until there is an action that changes active window. Following functionality was also removed because it is not needed now: * CMenuContainer::HideTemp * COwnerWindow::OnClear WM_CLEAR was sent to the window only by already removed `HideTemp`
3205 lines
95 KiB
C++
3205 lines
95 KiB
C++
// ## MenuContainer.h
|
|
// Classic Shell (c) 2009-2017, Ivo Beltchev
|
|
// Open-Shell (c) 2017-2018, The Open-Shell Team
|
|
// Confidential information of Ivo Beltchev. Not for disclosure or distribution without prior written consent from the author
|
|
|
|
// MenuCommands.cpp - handles the commands and actions of CMenuContainer
|
|
|
|
#include "stdafx.h"
|
|
#include "MenuContainer.h"
|
|
#include "StartMenuDLL.h"
|
|
#include "Settings.h"
|
|
#include "SettingsUI.h"
|
|
#include "SettingsUIHelper.h"
|
|
#include "Translations.h"
|
|
#include "LogManager.h"
|
|
#include "FNVHash.h"
|
|
#include "ResourceHelper.h"
|
|
#include "MetroLinkManager.h"
|
|
#include "ProgramsTree.h"
|
|
#include "resource.h"
|
|
#include <WtsApi32.h>
|
|
#include <PowrProf.h>
|
|
#include <propvarutil.h>
|
|
#include <algorithm>
|
|
#include <propkey.h>
|
|
|
|
static CString g_RenameText;
|
|
static POINT g_RenamePos;
|
|
|
|
// Dialog proc for the Rename dialog box
|
|
static INT_PTR CALLBACK RenameDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
if (uMsg==WM_INITDIALOG)
|
|
{
|
|
// translate text
|
|
SetWindowText(hwndDlg,FindTranslation(L"Menu.RenameTitle",L"Rename"));
|
|
SetDlgItemText(hwndDlg,IDC_LABEL,FindTranslation(L"Menu.RenamePrompt",L"&New name:"));
|
|
SetDlgItemText(hwndDlg,IDOK,FindTranslation(L"Menu.RenameOK",L"OK"));
|
|
SetDlgItemText(hwndDlg,IDCANCEL,FindTranslation(L"Menu.RenameCancel",L"Cancel"));
|
|
SetDlgItemText(hwndDlg,IDC_EDITNAME,g_RenameText);
|
|
// position near the item
|
|
SetWindowPos(hwndDlg,NULL,g_RenamePos.x,g_RenamePos.y,0,0,SWP_NOZORDER|SWP_NOSIZE);
|
|
SendMessage(hwndDlg,DM_REPOSITION,0,0);
|
|
return TRUE;
|
|
}
|
|
if (uMsg==WM_COMMAND && wParam==IDOK)
|
|
{
|
|
wchar_t buf[1024];
|
|
GetDlgItemText(hwndDlg,IDC_EDITNAME,buf,_countof(buf));
|
|
g_RenameText=buf;
|
|
|
|
EndDialog(hwndDlg,1);
|
|
return TRUE;
|
|
}
|
|
if (uMsg==WM_COMMAND && wParam==IDCANCEL)
|
|
{
|
|
EndDialog(hwndDlg,0);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static void SetShutdownPrivileges( void )
|
|
{
|
|
HANDLE hToken;
|
|
if (OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken))
|
|
{
|
|
TOKEN_PRIVILEGES tp={1};
|
|
if (LookupPrivilegeValue(NULL,L"SeShutdownPrivilege",&tp.Privileges[0].Luid))
|
|
tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
|
|
AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL);
|
|
CloseHandle(hToken);
|
|
}
|
|
}
|
|
|
|
static void DoSearchSubst( wchar_t *buf, int size, const wchar_t *search )
|
|
{
|
|
wchar_t search2[256];
|
|
char utf8[1024];
|
|
WcsToMbs(utf8,_countof(utf8),search,CP_UTF8);
|
|
int len=0;
|
|
for (const char *c=utf8;*c;c++)
|
|
{
|
|
if ((*c>='a' && *c<='z') || (*c>='A' && *c<='Z') || (*c>='0' && *c<='9'))
|
|
{
|
|
search2[len++]=*c;
|
|
}
|
|
else if (len<_countof(search2)-4)
|
|
{
|
|
len+=Sprintf(search2+len,_countof(search2)-len,L"%%%02X",(unsigned char)*c);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
search2[len]=0;
|
|
DWORD_PTR args[100]={(DWORD_PTR)search,(DWORD_PTR)search2};
|
|
wchar_t *pBuf=buf;
|
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_ARGUMENT_ARRAY|FORMAT_MESSAGE_FROM_STRING,buf,0,0,(LPWSTR)&pBuf,0,(va_list*)args);
|
|
Strcpy(buf,size,pBuf);
|
|
LocalFree(pBuf);
|
|
}
|
|
|
|
static DWORD CALLBACK ExecuteCommandThread( void *param )
|
|
{
|
|
CoInitialize(NULL);
|
|
const wchar_t *command=(wchar_t*)param;
|
|
wchar_t exe[_MAX_PATH];
|
|
const wchar_t *args=NULL;
|
|
CComString strExe, strArgs;
|
|
if (SUCCEEDED(SHEvaluateSystemCommandTemplate(command,&strExe,NULL,&strArgs)))
|
|
{
|
|
args=strArgs;
|
|
Strcpy(exe,_countof(exe),strExe);
|
|
}
|
|
else
|
|
{
|
|
args=SeparateArguments(command,exe);
|
|
}
|
|
SHELLEXECUTEINFO execute={sizeof(execute),SEE_MASK_FLAG_LOG_USAGE};
|
|
execute.lpFile=exe;
|
|
execute.lpParameters=args;
|
|
execute.nShow=SW_SHOWNORMAL;
|
|
ShellExecuteEx(&execute);
|
|
free(param);
|
|
CoUninitialize();
|
|
return 0;
|
|
}
|
|
|
|
void CMenuContainer::ExecuteCommand( const wchar_t *command, bool bElevated, bool bEnvSubst )
|
|
{
|
|
wchar_t text[1024];
|
|
if (bEnvSubst)
|
|
{
|
|
Strcpy(text,_countof(text),command);
|
|
DoEnvironmentSubst(text,_countof(text));
|
|
command=text;
|
|
}
|
|
if (bElevated)
|
|
{
|
|
wchar_t cmdLine[1024];
|
|
Sprintf(cmdLine,_countof(cmdLine),L"-runas %s",command);
|
|
|
|
wchar_t exe[_MAX_PATH];
|
|
GetModuleFileName(_AtlBaseModule.GetModuleInstance(),exe,_countof(exe));
|
|
PathRemoveFileSpec(exe);
|
|
PathAppend(exe,L"StartMenu.exe");
|
|
|
|
RECT rc;
|
|
if (m_bDestroyed)
|
|
::GetWindowRect(g_TaskBar,&rc);
|
|
else
|
|
GetWindowRect(&rc);
|
|
::SetForegroundWindow(g_OwnerWindow);
|
|
::SetWindowPos(g_OwnerWindow,HWND_TOPMOST,rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,0);
|
|
ShellExecute(g_OwnerWindow,L"runas",exe,cmdLine,NULL,SW_SHOWNORMAL);
|
|
}
|
|
else
|
|
{
|
|
CreateThread(NULL,0,ExecuteCommandThread,_wcsdup(command),0,NULL);
|
|
}
|
|
}
|
|
|
|
// Dialog proc for the Log Off dialog box
|
|
static INT_PTR CALLBACK LogOffDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
if (uMsg==WM_INITDIALOG)
|
|
{
|
|
// translate text
|
|
SendDlgItemMessage(hwndDlg,IDC_STATICICON1,STM_SETICON,lParam,0);
|
|
SetWindowText(hwndDlg,FindTranslation(L"Menu.LogoffTitle",L"Log Off Windows"));
|
|
SetDlgItemText(hwndDlg,IDC_PROMPT,FindTranslation(L"Menu.LogoffPrompt",L"Are you sure you want to log off?"));
|
|
SetDlgItemText(hwndDlg,IDOK,FindTranslation(L"Menu.LogoffYes",L"&Log Off"));
|
|
SetDlgItemText(hwndDlg,IDCANCEL,FindTranslation(L"Menu.LogoffNo",L"&No"));
|
|
return TRUE;
|
|
}
|
|
if (uMsg==WM_COMMAND && wParam==IDOK)
|
|
{
|
|
EndDialog(hwndDlg,1);
|
|
return TRUE;
|
|
}
|
|
if (uMsg==WM_COMMAND && wParam==IDCANCEL)
|
|
{
|
|
EndDialog(hwndDlg,0);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
struct ShortcutParams
|
|
{
|
|
ShortcutParams( void ) { memset(this,0,sizeof(*this)); }
|
|
wchar_t target[_MAX_PATH+1];
|
|
wchar_t temp[_MAX_PATH];
|
|
wchar_t fname[_MAX_PATH+1];
|
|
};
|
|
|
|
static DWORD WINAPI NewShortcutThread( void *param )
|
|
{
|
|
ShortcutParams *pParams=(ShortcutParams*)param;
|
|
HANDLE hFile=CreateFile(pParams->fname,0,FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
|
|
if (hFile!=INVALID_HANDLE_VALUE)
|
|
{
|
|
// run the shortcut wizard
|
|
wchar_t cmdLine[1024];
|
|
Sprintf(cmdLine,_countof(cmdLine),L"rundll32.exe appwiz.cpl,NewLinkHere %s",pParams->fname);
|
|
|
|
STARTUPINFO startupInfo={sizeof(startupInfo)};
|
|
PROCESS_INFORMATION processInfo;
|
|
memset(&processInfo,0,sizeof(processInfo));
|
|
wchar_t exe[_MAX_PATH]=L"%windir%\\system32\\rundll32.exe";
|
|
DoEnvironmentSubst(exe,_countof(exe));
|
|
if (CreateProcess(exe,cmdLine,NULL,NULL,FALSE,0,NULL,pParams->temp,&startupInfo,&processInfo))
|
|
{
|
|
CloseHandle(processInfo.hThread);
|
|
WaitForSingleObject(processInfo.hProcess,INFINITE);
|
|
CloseHandle(processInfo.hProcess);
|
|
|
|
// see what the file was renamed to
|
|
struct {
|
|
DWORD FileNameLength;
|
|
wchar_t FileName[_MAX_PATH];
|
|
} nameInfo={0};
|
|
BOOL bInfo=GetFileInformationByHandleEx(hFile,FileNameInfo,&nameInfo,sizeof(nameInfo));
|
|
CloseHandle(hFile);
|
|
if (bInfo)
|
|
{
|
|
// move to the final target folder
|
|
int len=Sprintf(pParams->fname,_countof(pParams->fname)-1,L"%s\\%s",pParams->temp,PathFindFileName(nameInfo.FileName));
|
|
pParams->fname[len+1]=0;
|
|
SHFILEOPSTRUCT shfop={g_OwnerWindow,FO_MOVE,pParams->fname,pParams->target};
|
|
SHFileOperation(&shfop);
|
|
}
|
|
}
|
|
else
|
|
CloseHandle(hFile);
|
|
DeleteFile(pParams->fname);
|
|
}
|
|
delete pParams;
|
|
return 0;
|
|
}
|
|
|
|
static DWORD WINAPI SleepThread( void *param )
|
|
{
|
|
SetSuspendState((intptr_t)param != 0,FALSE,FALSE);
|
|
return 0;
|
|
}
|
|
|
|
void CMenuContainer::CloseSubMenus( int flags, CMenuContainer *pAfter )
|
|
{
|
|
if (s_MenuMode==MODE_JUMPLIST && !(flags&CLOSE_KEEP_MODE))
|
|
{
|
|
if (pAfter && !pAfter->m_bSubMenu)
|
|
{
|
|
pAfter->SetMenuMode(MODE_NORMAL);
|
|
}
|
|
}
|
|
for (int i=(int)s_Menus.size()-((flags&CLOSE_SKIP_LAST)?2:1);i>=0 && s_Menus[i]!=pAfter;i--)
|
|
if (!s_Menus[i]->m_bDestroyed)
|
|
{
|
|
if ((flags&CLOSE_SKIP_SEARCH) && (s_Menus[i]->m_Options&CONTAINER_SEARCH))
|
|
continue;
|
|
if ((flags&CLOSE_ONLY_SEARCH) && !(s_Menus[i]->m_Options&CONTAINER_SEARCH))
|
|
continue;
|
|
if (flags&CLOSE_POST)
|
|
{
|
|
s_Menus[i]->ShowWindow(SW_HIDE);
|
|
s_Menus[i]->PostMessage(WM_CLOSE);
|
|
s_Menus[i]->m_bClosing=true;
|
|
}
|
|
else
|
|
s_Menus[i]->DestroyWindow();
|
|
}
|
|
}
|
|
|
|
void CMenuContainer::OpenSubMenu( int index, TActivateType type, bool bShift )
|
|
{
|
|
const MenuItem &item=m_Items[index];
|
|
if (m_bTwoColumns && s_bWin7Style)
|
|
{
|
|
if (item.bHasJumpList)
|
|
{
|
|
SetActiveWindow();
|
|
CloseSubMenus(CLOSE_KEEP_MODE,this);
|
|
OpenJumpList(index,type==ACTIVATE_OPEN_KBD);
|
|
return;
|
|
}
|
|
if (item.id==MENU_SEARCH_BOX)
|
|
{
|
|
SetActiveWindow();
|
|
CloseSubMenus(CLOSE_KEEP_MODE,this);
|
|
OpenSearchList();
|
|
return;
|
|
}
|
|
if (item.id==MENU_PROGRAMS && GetSettingInt(L"ProgramsStyle")==PROGRAMS_INLINE)
|
|
{
|
|
SetActiveWindow();
|
|
CloseSubMenus(CLOSE_KEEP_MODE,this);
|
|
SetMenuMode(s_MenuMode==MODE_PROGRAMS?MODE_NORMAL:MODE_PROGRAMS);
|
|
if (s_MenuMode==MODE_NORMAL)
|
|
SetHotItem(m_ProgramButtonIndex);
|
|
return;
|
|
}
|
|
}
|
|
// open a submenu - create a new menu object
|
|
const StdMenuItem *pSubMenu=item.pStdItem?item.pStdItem->submenu:NULL;
|
|
bool bOpenUp=false;
|
|
|
|
int options=(type==ACTIVATE_OPEN_SEARCH)?CONTAINER_DRAG|CONTAINER_SEARCH:CONTAINER_DRAG|CONTAINER_DROP;
|
|
if (item.id==MENU_CONTROLPANEL)
|
|
options|=CONTAINER_CONTROLPANEL;
|
|
if (item.id==MENU_DOCUMENTS)
|
|
options|=CONTAINER_DOCUMENTS;
|
|
if (item.id==MENU_APPS)
|
|
options|=CONTAINER_APPS;
|
|
if (item.bPrograms)
|
|
options|=CONTAINER_PROGRAMS;
|
|
if (item.bLink || (m_Options&CONTAINER_LINK))
|
|
options|=CONTAINER_LINK;
|
|
if ((m_Options&CONTAINER_TRACK) || item.id==MENU_PROGRAMS || item.id==MENU_APPS)
|
|
options|=CONTAINER_TRACK;
|
|
|
|
if (item.id==MENU_PROGRAMS && GetSettingInt(L"PinnedPrograms")==PINNED_PROGRAMS_PINNED)
|
|
options|=CONTAINER_ALLPROGRAMS;
|
|
|
|
if (item.id==MENU_RECENT_PROGRAMS)
|
|
options|=CONTAINER_RECENT;
|
|
|
|
if (m_Options&CONTAINER_OPENUP_REC)
|
|
{
|
|
options|=CONTAINER_OPENUP_REC;
|
|
bOpenUp=true;
|
|
}
|
|
if (m_Options&CONTAINER_SORTZA_REC)
|
|
options|=CONTAINER_SORTZA|CONTAINER_SORTZA_REC;
|
|
|
|
if (item.pStdItem)
|
|
{
|
|
if (item.pStdItem->settings&StdMenuItem::MENU_OPENUP)
|
|
bOpenUp=true;
|
|
if (item.pStdItem->settings&StdMenuItem::MENU_OPENUP_REC)
|
|
options|=CONTAINER_OPENUP_REC;
|
|
if (item.pStdItem->settings&StdMenuItem::MENU_SORTZA)
|
|
options|=CONTAINER_SORTZA;
|
|
if (item.pStdItem->settings&StdMenuItem::MENU_SORTZA_REC)
|
|
options|=CONTAINER_SORTZA_REC;
|
|
if (item.pStdItem->settings&StdMenuItem::MENU_SORTONCE)
|
|
options|=CONTAINER_SORTONCE;
|
|
if (item.pStdItem->settings&StdMenuItem::MENU_ITEMS_FIRST)
|
|
options|=CONTAINER_ITEMS_FIRST;
|
|
if (item.pStdItem->settings&StdMenuItem::MENU_TRACK)
|
|
options|=CONTAINER_TRACK;
|
|
if (item.pStdItem->settings&StdMenuItem::MENU_NOTRACK)
|
|
options&=~CONTAINER_TRACK;
|
|
if (item.pStdItem->settings&StdMenuItem::MENU_MULTICOLUMN)
|
|
options|=CONTAINER_MULTICOL_REC;
|
|
if (item.pStdItem->settings&StdMenuItem::MENU_NOEXTENSIONS)
|
|
options|=CONTAINER_NOEXTENSIONS;
|
|
if (item.pStdItem->settings&StdMenuItem::MENU_SINGLE_EXPAND)
|
|
options|=CONTAINER_NOSUBFOLDERS;
|
|
}
|
|
|
|
if (item.id==MENU_NETWORK)
|
|
options|=CONTAINER_NOPATH;
|
|
|
|
if (item.bHasJumpList)
|
|
options=CONTAINER_JUMPLIST|CONTAINER_DRAG|CONTAINER_DROP;
|
|
else if (item.id==MENU_COMPUTER && !s_bWin7Style)
|
|
{
|
|
if (GetSettingInt(L"Computer")==3)
|
|
options|=CONTAINER_NOSUBFOLDERS;
|
|
}
|
|
else if (item.pItem1 && item.pItemInfo)
|
|
{
|
|
CString PATH;
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
if (item.bLink)
|
|
PATH=item.pItemInfo->GetTargetPATH();
|
|
if (PATH.IsEmpty())
|
|
PATH=item.pItemInfo->PATH;
|
|
}
|
|
if (!PATH.IsEmpty())
|
|
{
|
|
for (int i=0;g_SpecialFolders[i].folder;i++)
|
|
{
|
|
if (PATH==g_SpecialFolders[i].PATH)
|
|
{
|
|
if (g_SpecialFolders[i].settings&SpecialFolder::FOLDER_NOSUBFOLDERS)
|
|
options|=CONTAINER_NOSUBFOLDERS;
|
|
if (g_SpecialFolders[i].settings&SpecialFolder::FOLDER_NONEWFOLDER)
|
|
options|=CONTAINER_NONEWFOLDER;
|
|
if (g_SpecialFolders[i].settings&SpecialFolder::FOLDER_NOPATH)
|
|
options|=CONTAINER_NOPATH;
|
|
if (g_SpecialFolders[i].settings&SpecialFolder::FOLDER_NODROP)
|
|
options&=~CONTAINER_DROP;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_Options&CONTAINER_NOEXTENSIONS)
|
|
options|=CONTAINER_NOEXTENSIONS;
|
|
|
|
if (item.id==MENU_PROGRAMS || item.id==MENU_APPS || (m_Options&CONTAINER_MULTICOL_REC))
|
|
options|=CONTAINER_MULTICOL_REC;
|
|
if ((options&CONTAINER_MULTICOL_REC) && !bShift)
|
|
options|=CONTAINER_MULTICOLUMN;
|
|
if (options&CONTAINER_SEARCH)
|
|
options&=~(CONTAINER_MULTICOL_REC|CONTAINER_MULTICOLUMN);
|
|
|
|
CMenuContainer *pMenu=new CSubMenuContainer(this,index,options,pSubMenu,item.pItem1,item.pItem2);
|
|
if (type==ACTIVATE_OPEN_SEARCH)
|
|
{
|
|
pMenu->InitSearchItems();
|
|
}
|
|
else
|
|
{
|
|
s_JumpAppInfo=item.bHasJumpList?item.pItemInfo:NULL;
|
|
pMenu->InitItems();
|
|
}
|
|
|
|
RECT itemRect;
|
|
GetItemRect(index,itemRect);
|
|
MapWindowPoints(NULL,&itemRect);
|
|
RECT border={-s_Skin.Submenu_padding.left+s_Skin.Submenu_offset,-s_Skin.Submenu_padding.top,s_Skin.Submenu_padding.right-s_Skin.Submenu_offset,s_Skin.Submenu_padding.bottom};
|
|
if (s_bRTL)
|
|
{
|
|
// swap and change signs
|
|
int q=border.left; border.left=-border.right; border.right=-q;
|
|
}
|
|
AdjustWindowRect(&border,s_SubmenuStyle,FALSE);
|
|
|
|
if (m_bSubMenu)
|
|
pMenu->m_MaxWidth=s_MenuLimits.right-s_MenuLimits.left;
|
|
else if (s_bExpandRight)
|
|
pMenu->m_MaxWidth=s_MenuLimits.right-itemRect.right-border.left;
|
|
else
|
|
pMenu->m_MaxWidth=itemRect.left+border.right-s_MenuLimits.left;
|
|
|
|
DWORD animFlags=AW_TOPMOST;
|
|
{
|
|
bool bDef;
|
|
int anim=GetSettingInt(L"SubMenuAnimation",bDef);
|
|
if (bDef)
|
|
{
|
|
DWORD fade;
|
|
SystemParametersInfo(SPI_GETMENUFADE,NULL,&fade,0);
|
|
anim=fade?1:2;
|
|
}
|
|
if (anim==3) animFlags|=((rand()<RAND_MAX/2)?AW_BLEND:AW_SLIDE);
|
|
else if (anim==1) animFlags|=AW_BLEND;
|
|
else if (anim==2) animFlags|=AW_SLIDE;
|
|
}
|
|
if (type!=ACTIVATE_OPEN_SEARCH)
|
|
animFlags|=AW_ACTIVATE;
|
|
|
|
BOOL animate;
|
|
if ((animFlags&(AW_BLEND|AW_SLIDE))==0 || (m_Submenu>=0 && !GetSettingBool(L"SubMenuAnimationAlways")))
|
|
animate=FALSE;
|
|
else
|
|
SystemParametersInfo(SPI_GETMENUANIMATION,NULL,&animate,0);
|
|
|
|
// destroy old submenus
|
|
SetActiveWindow();
|
|
CloseSubMenus(CLOSE_SKIP_LAST,this);
|
|
|
|
// open submenu
|
|
HWND parent=GetParent();
|
|
pMenu->Create(parent,NULL,s_SubmenuStyle,WS_EX_TOOLWINDOW|WS_EX_TOPMOST|(s_bRTL?WS_EX_LAYOUTRTL:0));
|
|
|
|
if (GetSettingBool(L"MenuShadow") && s_Skin.Submenu_shadow==MenuSkin::SHADOW_ON)
|
|
SetClassLongPtr(pMenu->m_hWnd,GCL_STYLE,GetClassLongPtr(pMenu->m_hWnd,GCL_STYLE)|CS_DROPSHADOW);
|
|
else
|
|
SetClassLongPtr(pMenu->m_hWnd,GCL_STYLE,GetClassLongPtr(pMenu->m_hWnd,GCL_STYLE)&~CS_DROPSHADOW);
|
|
|
|
if (!parent && s_TaskBar)
|
|
{
|
|
// place sub-menus in front of the taskbar
|
|
if (type==ACTIVATE_OPEN_SEARCH)
|
|
pMenu->SetWindowPos(s_TaskBar,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
|
|
else
|
|
pMenu->SetWindowPos(s_TaskBar,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
|
|
}
|
|
RECT rc2;
|
|
pMenu->GetWindowRect(&rc2);
|
|
|
|
// position new menu
|
|
int w=rc2.right-rc2.left;
|
|
int h=rc2.bottom-rc2.top;
|
|
|
|
if (s_bExpandRight)
|
|
{
|
|
if (itemRect.right+border.left+w<=s_MenuLimits.right)
|
|
{
|
|
// right
|
|
rc2.left=itemRect.right+border.left;
|
|
rc2.right=rc2.left+w;
|
|
animFlags|=AW_HOR_POSITIVE;
|
|
pMenu->m_Options|=CONTAINER_LEFT;
|
|
}
|
|
else if (itemRect.left+border.right-w>=s_MenuLimits.left)
|
|
{
|
|
// left
|
|
rc2.right=itemRect.left+border.right;
|
|
rc2.left=rc2.right-w;
|
|
animFlags|=AW_HOR_NEGATIVE;
|
|
}
|
|
else
|
|
{
|
|
// right again
|
|
rc2.right=s_MenuLimits.right;
|
|
rc2.left=rc2.right-w;
|
|
if (!s_bRTL)
|
|
{
|
|
int minx=m_bSubMenu?s_MenuLimits.left:(itemRect.right+border.left);
|
|
if (rc2.left<minx)
|
|
{
|
|
rc2.left=minx;
|
|
rc2.right=minx+w;
|
|
}
|
|
}
|
|
animFlags|=AW_HOR_POSITIVE;
|
|
pMenu->m_Options|=CONTAINER_LEFT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (itemRect.left+border.right-w>=s_MenuLimits.left)
|
|
{
|
|
// left
|
|
rc2.right=itemRect.left+border.right;
|
|
rc2.left=rc2.right-w;
|
|
animFlags|=AW_HOR_NEGATIVE;
|
|
}
|
|
else if (itemRect.right+border.left+w<=s_MenuLimits.right)
|
|
{
|
|
// right
|
|
rc2.left=itemRect.right+border.left;
|
|
rc2.right=rc2.left+w;
|
|
animFlags|=AW_HOR_POSITIVE;
|
|
pMenu->m_Options|=CONTAINER_LEFT;
|
|
}
|
|
else
|
|
{
|
|
// left again
|
|
rc2.left=s_MenuLimits.left;
|
|
rc2.right=rc2.left+w;
|
|
if (s_bRTL)
|
|
{
|
|
int maxx=m_bSubMenu?s_MenuLimits.right:(itemRect.left+border.right);
|
|
if (rc2.right>maxx)
|
|
{
|
|
rc2.left=maxx-w;
|
|
rc2.right=maxx;
|
|
}
|
|
}
|
|
animFlags|=AW_HOR_NEGATIVE;
|
|
}
|
|
}
|
|
|
|
if (s_bRTL)
|
|
animFlags^=(AW_HOR_POSITIVE|AW_HOR_NEGATIVE); // RTL flips the animation
|
|
|
|
if (bOpenUp)
|
|
{
|
|
if (itemRect.bottom+border.bottom-h>=s_MenuLimits.top)
|
|
{
|
|
// up
|
|
rc2.bottom=itemRect.bottom+border.bottom;
|
|
rc2.top=rc2.bottom-h;
|
|
}
|
|
else if (itemRect.top+border.top+h<=s_MenuLimits.bottom)
|
|
{
|
|
// down
|
|
rc2.top=itemRect.top+border.top;
|
|
rc2.bottom=rc2.top+h;
|
|
pMenu->m_Options|=CONTAINER_TOP;
|
|
}
|
|
else
|
|
{
|
|
// up again
|
|
rc2.top=s_MenuLimits.top-pMenu->m_ExtraBorder;
|
|
rc2.bottom=rc2.top+h;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (itemRect.top+border.top+h<=s_MenuLimits.bottom)
|
|
{
|
|
// down
|
|
rc2.top=itemRect.top+border.top;
|
|
rc2.bottom=rc2.top+h;
|
|
pMenu->m_Options|=CONTAINER_TOP;
|
|
}
|
|
else if (itemRect.bottom+border.bottom-h>=s_MenuLimits.top)
|
|
{
|
|
// up
|
|
rc2.bottom=itemRect.bottom+border.bottom;
|
|
rc2.top=rc2.bottom-h;
|
|
}
|
|
else
|
|
{
|
|
// down again
|
|
rc2.bottom=s_MenuLimits.bottom+pMenu->m_ExtraBorder;
|
|
rc2.top=rc2.bottom-h;
|
|
pMenu->m_Options|=CONTAINER_TOP;
|
|
}
|
|
}
|
|
|
|
SetSubmenu(index);
|
|
m_SubShowTime=0;
|
|
InvalidateItem(index);
|
|
if (type!=ACTIVATE_OPEN_SEARCH)
|
|
SetHotItem(index);
|
|
UpdateWindow();
|
|
|
|
if (type!=ACTIVATE_OPEN_SEARCH)
|
|
{
|
|
pMenu->SetFocus();
|
|
|
|
int hotItem=-1;
|
|
if (type==ACTIVATE_OPEN_KBD)
|
|
{
|
|
bool bLast=item.id==MENU_SHUTDOWN_BUTTON && GetSettingBool(L"SelectLastShutdown");
|
|
for (int i=0;i<(int)pMenu->m_Items.size();i++)
|
|
if (pMenu->CanSelectItem(i))
|
|
{
|
|
hotItem=i;
|
|
if (!bLast)
|
|
break;
|
|
}
|
|
}
|
|
pMenu->SetHotItem(hotItem);
|
|
}
|
|
|
|
int speed=0;
|
|
if (animate)
|
|
{
|
|
speed=GetSettingInt(L"SubMenuAnimationSpeed");
|
|
if (speed<=0) speed=MENU_ANIM_SPEED_SUBMENU;
|
|
else if (speed>=10000) speed=10000;
|
|
}
|
|
pMenu->AnimateMenu(animFlags,speed,rc2);
|
|
|
|
if (s_Tooltip.m_hWnd)
|
|
s_Tooltip.SetWindowPos(HWND_TOP,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
|
|
}
|
|
|
|
class ExitGuard
|
|
{
|
|
public:
|
|
ExitGuard( void ) { m_bArmed=true; }
|
|
~ExitGuard( void ) { Assert(!m_bArmed); }
|
|
void Disarm( void ) { m_bArmed=false; }
|
|
private:
|
|
bool m_bArmed;
|
|
};
|
|
|
|
#ifndef EWX_HYBRID_SHUTDOWN
|
|
#define EWX_HYBRID_SHUTDOWN 0x00400000
|
|
#endif
|
|
#define EWX_INSTALL_UPDATES 0x00100000 // undocumented switch to install updates on shutdown
|
|
|
|
static bool ExecuteSysCommand( TMenuID menuCommand )
|
|
{
|
|
CComPtr<IShellDispatch2> pShellDisp;
|
|
HRESULT hr;
|
|
switch (menuCommand)
|
|
{
|
|
case MENU_TASKBAR: // show taskbar properties
|
|
hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr=pShellDisp->TrayProperties();
|
|
if (FAILED(hr))
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to TrayProperties, 0x08%x",hr);
|
|
}
|
|
else
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr);
|
|
return true;
|
|
|
|
case MENU_FEATURES:
|
|
hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr=pShellDisp->ControlPanelItem(CComBSTR(L"appwiz.cpl"));
|
|
if (FAILED(hr))
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to ControlPanelItem(appwiz.cpl), 0x08%x",hr);
|
|
}
|
|
else
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr);
|
|
return true;
|
|
|
|
case MENU_SECURITY:
|
|
{
|
|
CComPtr<IShellDispatch4> pShellDisp4;
|
|
hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch4,(void**)&pShellDisp4);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr=pShellDisp4->WindowsSecurity();
|
|
if (FAILED(hr))
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to WindowsSecurity, 0x08%x",hr);
|
|
}
|
|
else
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr);
|
|
}
|
|
return true;
|
|
|
|
case MENU_SEARCH_FILES: // show the search UI
|
|
hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr=pShellDisp->FindFiles();
|
|
if (FAILED(hr))
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to FindFiles, 0x08%x",hr);
|
|
}
|
|
else
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr);
|
|
return true;
|
|
|
|
case MENU_SEARCH_PRINTER: // search for network printers
|
|
hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr=pShellDisp->FindPrinter(CComBSTR(L""),CComBSTR(L""),CComBSTR(L""));
|
|
if (FAILED(hr))
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to FindPrinter, 0x08%x",hr);
|
|
}
|
|
else
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr);
|
|
return true;
|
|
|
|
case MENU_SEARCH_COMPUTERS: // search for computers
|
|
hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr=pShellDisp->FindComputer();
|
|
if (FAILED(hr))
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to FindComputer, 0x08%x",hr);
|
|
}
|
|
else
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr);
|
|
return true;
|
|
|
|
case MENU_SEARCH_PEOPLE: // search for people using Windows Mail
|
|
{
|
|
SHELLEXECUTEINFO execute={sizeof(execute),SEE_MASK_DOENVSUBST,NULL,L"open"};
|
|
execute.lpFile=L"%ProgramFiles%\\Windows Mail\\wab.exe";
|
|
execute.lpParameters=L"/find";
|
|
execute.lpDirectory=L"%ProgramFiles%\\Windows Mail";
|
|
execute.nShow=SW_SHOWNORMAL;
|
|
ShellExecuteEx(&execute);
|
|
}
|
|
return true;
|
|
|
|
case MENU_HELP: // show Windows help
|
|
hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr=pShellDisp->Help();
|
|
if (FAILED(hr))
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to Help, 0x08%x",hr);
|
|
}
|
|
else
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr);
|
|
return true;
|
|
|
|
case MENU_RUN: // show the Run box
|
|
if (GetWinVersion()>=WIN_VER_WIN10)
|
|
{
|
|
ShellExecute(NULL,NULL,L"shell:::{2559a1f3-21d7-11d4-bdaf-00c04f60b9f0}",NULL,NULL,SW_SHOWNORMAL);
|
|
}
|
|
else
|
|
{
|
|
hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr=pShellDisp->FileRun();
|
|
if (FAILED(hr))
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to FileRun, 0x08%x",hr);
|
|
}
|
|
else
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr);
|
|
}
|
|
return true;
|
|
|
|
case MENU_LOGOFF: // log off
|
|
ExitWindowsEx(EWX_LOGOFF,0);
|
|
return true;
|
|
|
|
case MENU_LOGOFF_CONFIRM:
|
|
{
|
|
HMODULE hShell32=GetModuleHandle(L"Shell32.dll");
|
|
HICON icon=LoadIcon(hShell32,MAKEINTRESOURCE(45));
|
|
INT_PTR res=DialogBoxParam(g_Instance,MAKEINTRESOURCE(IsLanguageRTL()?IDD_LOGOFFR:IDD_LOGOFF),NULL,LogOffDlgProc,(LPARAM)icon);
|
|
DestroyIcon(icon);
|
|
if (res)
|
|
ExitWindowsEx(EWX_LOGOFF,0);
|
|
}
|
|
return true;
|
|
|
|
case MENU_RESTART: // restart
|
|
case MENU_RESTART_NOUPDATE:
|
|
SetShutdownPrivileges();
|
|
ExitWindowsEx(EWX_REBOOT,SHTDN_REASON_FLAG_PLANNED);
|
|
return true;
|
|
|
|
case MENU_RESTART_ADVANCED: // advanced restart
|
|
if (GetWinVersion()>=WIN_VER_WIN8)
|
|
{
|
|
STARTUPINFO startupInfo={sizeof(startupInfo)};
|
|
PROCESS_INFORMATION processInfo;
|
|
memset(&processInfo,0,sizeof(processInfo));
|
|
wchar_t exe[_MAX_PATH]=L"%windir%\\system32\\shutdown.exe";
|
|
DoEnvironmentSubst(exe,_countof(exe));
|
|
if (CreateProcess(exe,(LPWSTR)L"shutdown.exe /r /o /t 0",NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&startupInfo,&processInfo))
|
|
{
|
|
CloseHandle(processInfo.hThread);
|
|
CloseHandle(processInfo.hProcess);
|
|
}
|
|
}
|
|
else
|
|
ExitWindowsEx(EWX_REBOOT,SHTDN_REASON_FLAG_PLANNED);
|
|
return true;
|
|
|
|
case MENU_RESTART_UPDATE: // update and restart
|
|
{
|
|
UINT flags=EWX_REBOOT;
|
|
if (GetWinVersion()>=WIN_VER_WIN8)
|
|
flags|=EWX_INSTALL_UPDATES;
|
|
SetShutdownPrivileges();
|
|
ExitWindowsEx(flags,SHTDN_REASON_FLAG_PLANNED);
|
|
}
|
|
return true;
|
|
|
|
case MENU_SWITCHUSER: // switch_user
|
|
if (GetWinVersion()>=WIN_VER_WIN10)
|
|
{
|
|
// on Windows 10 this value must be set to 1. For some reason non-admin code has permissions to do so
|
|
CRegKey regSwitch;
|
|
if (regSwitch.Create(HKEY_LOCAL_MACHINE,L"Software\\Microsoft\\Windows\\CurrentVersion\\Authentication\\LogonUI\\UserSwitch",NULL,0,KEY_SET_VALUE)==ERROR_SUCCESS)
|
|
regSwitch.SetDWORDValue(L"Enabled",1);
|
|
}
|
|
WTSDisconnectSession(WTS_CURRENT_SERVER_HANDLE,WTS_CURRENT_SESSION,FALSE); // same as "disconnect"
|
|
return true;
|
|
|
|
case MENU_LOCK: // lock
|
|
LockWorkStation();
|
|
return true;
|
|
|
|
case MENU_SHUTDOWN: // shutdown
|
|
case MENU_SHUTDOWN_NOUPDATE:
|
|
SetShutdownPrivileges();
|
|
ExitWindowsEx(EWX_SHUTDOWN,SHTDN_REASON_FLAG_PLANNED);
|
|
return true;
|
|
|
|
case MENU_SHUTDOWN_UPDATE: // update and shutdown
|
|
SetShutdownPrivileges();
|
|
ExitWindowsEx(EWX_SHUTDOWN|EWX_INSTALL_UPDATES,SHTDN_REASON_FLAG_PLANNED);
|
|
return true;
|
|
|
|
case MENU_SHUTDOWN_HYBRID: // hybrid shutdown
|
|
SetShutdownPrivileges();
|
|
{
|
|
UINT flags=EWX_SHUTDOWN;
|
|
if (GetWinVersion()>=WIN_VER_WIN8)
|
|
{
|
|
CRegKey regPower;
|
|
if (regPower.Open(HKEY_LOCAL_MACHINE,L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Power",KEY_READ)==ERROR_SUCCESS)
|
|
{
|
|
DWORD val;
|
|
if (regPower.QueryDWORDValue(L"HiberbootEnabled",val)==ERROR_SUCCESS && val==1)
|
|
flags|=EWX_HYBRID_SHUTDOWN;
|
|
}
|
|
}
|
|
ExitWindowsEx(flags,SHTDN_REASON_FLAG_PLANNED);
|
|
}
|
|
return true;
|
|
|
|
case MENU_SLEEP:
|
|
if (GetSystemMetrics(SM_REMOTESESSION))
|
|
{
|
|
WTSDisconnectSession(WTS_CURRENT_SERVER_HANDLE,WTS_CURRENT_SESSION,FALSE);
|
|
Sleep(250);
|
|
}
|
|
CreateThread(NULL,0,SleepThread,(void*)FALSE,0,NULL);
|
|
return true;
|
|
|
|
case MENU_HIBERNATE:
|
|
if (GetSystemMetrics(SM_REMOTESESSION))
|
|
{
|
|
WTSDisconnectSession(WTS_CURRENT_SERVER_HANDLE,WTS_CURRENT_SESSION,FALSE);
|
|
Sleep(250);
|
|
}
|
|
CreateThread(NULL,0,SleepThread,(void*)TRUE,0,NULL);
|
|
return true;
|
|
|
|
case MENU_DISCONNECT: // disconnect the current Terminal Services session (remote desktop)
|
|
WTSDisconnectSession(WTS_CURRENT_SERVER_HANDLE,WTS_CURRENT_SESSION,FALSE);
|
|
return true;
|
|
|
|
case MENU_UNDOCK: // undock the PC
|
|
hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr=pShellDisp->EjectPC();
|
|
if (FAILED(hr))
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to EjectPC, 0x08%x",hr);
|
|
}
|
|
else
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr);
|
|
return true;
|
|
|
|
case MENU_MONITOROFF:
|
|
::SendMessage(g_TaskBar,WM_SYSCOMMAND,SC_MONITORPOWER,2);
|
|
return true;
|
|
|
|
case MENU_SHUTDOWN_BOX: // shutdown - ask to shutdown, log off, sleep, etc
|
|
hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr=pShellDisp->ShutdownWindows();
|
|
if (FAILED(hr))
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to ShutdownWindows, 0x08%x",hr);
|
|
}
|
|
else
|
|
LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr);
|
|
return true;
|
|
|
|
case MENU_PCSETTINGS:
|
|
if (GetWinVersion()>=WIN_VER_WIN8)
|
|
{
|
|
ShellExecute(NULL,NULL,L"shell:appsfolder\\windows.immersivecontrolpanel_cw5n1h2txyewy!microsoft.windows.immersivecontrolpanel",NULL,NULL,SW_SHOWNORMAL);
|
|
}
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
STARTMENUAPI bool DllExecuteNamedCommand( const wchar_t *command )
|
|
{
|
|
static struct NamedCommand
|
|
{
|
|
const wchar_t *name;
|
|
TMenuID command;
|
|
} s_NamedCommands[]=
|
|
{
|
|
{L"help",MENU_HELP},
|
|
{L"run",MENU_RUN},
|
|
{L"logoff",MENU_LOGOFF},
|
|
{L"undock",MENU_UNDOCK},
|
|
{L"monitor_off",MENU_MONITOROFF},
|
|
{L"disconnect",MENU_DISCONNECT},
|
|
{L"shutdown_box",MENU_SHUTDOWN_BOX},
|
|
{L"windows_security",MENU_SECURITY},
|
|
{L"taskbar_settings",MENU_TASKBAR},
|
|
{L"search_files",MENU_SEARCH_FILES},
|
|
{L"search_printer",MENU_SEARCH_PRINTER},
|
|
{L"search_computers",MENU_SEARCH_COMPUTERS},
|
|
{L"search_people",MENU_SEARCH_PEOPLE},
|
|
{L"sleep",MENU_SLEEP},
|
|
{L"hibernate",MENU_HIBERNATE},
|
|
{L"restart",MENU_RESTART},
|
|
{L"shutdown",MENU_SHUTDOWN},
|
|
{L"switch_user",MENU_SWITCHUSER},
|
|
{L"lock",MENU_LOCK},
|
|
{L"programs_features",MENU_FEATURES},
|
|
|
|
{L"confirm_logoff",MENU_LOGOFF_CONFIRM},
|
|
{L"advanced_boot",MENU_RESTART_ADVANCED},
|
|
{L"update_restart",MENU_RESTART_UPDATE},
|
|
{L"update_shutdown",MENU_SHUTDOWN_UPDATE},
|
|
{L"hybrid_shutdown",MENU_SHUTDOWN_HYBRID},
|
|
};
|
|
|
|
TMenuID menuCommand=MENU_NO;
|
|
for (int i=0;i<_countof(s_NamedCommands);i++)
|
|
{
|
|
if (wcscmp(command,s_NamedCommands[i].name)==0)
|
|
{
|
|
menuCommand=s_NamedCommands[i].command;
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (menuCommand)
|
|
{
|
|
case MENU_NO:
|
|
return false;
|
|
|
|
case MENU_HELP:
|
|
if (SHRestricted(REST_NOSMHELP)) return false;
|
|
break;
|
|
|
|
case MENU_RUN:
|
|
if (SHRestricted(REST_NORUN)) return false;
|
|
break;
|
|
|
|
case MENU_LOGOFF:
|
|
case MENU_LOGOFF_CONFIRM:
|
|
if (SHRestricted(REST_STARTMENULOGOFF)==1) return false;
|
|
break;
|
|
|
|
case MENU_DISCONNECT:
|
|
if (SHRestricted(REST_NODISCONNECT)) return false;
|
|
break;
|
|
|
|
case MENU_UNDOCK:
|
|
if (SHRestricted(REST_NOSMEJECTPC)) return false;
|
|
break;
|
|
|
|
case MENU_SEARCH_COMPUTERS:
|
|
if (SHRestricted(REST_HASFINDCOMPUTERS)) return false;
|
|
break;
|
|
|
|
case MENU_SWITCHUSER:
|
|
{
|
|
CComPtr<IShellDispatch2> pShellDisp;
|
|
if (SUCCEEDED(CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp)))
|
|
{
|
|
long val;
|
|
if (SUCCEEDED(pShellDisp->IsRestricted(CComBSTR(L"System"),CComBSTR(L"HideFastUserSwitching"),&val)) && val)
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MENU_TASKBAR:
|
|
if (SHRestricted(REST_NOSETTASKBAR)) return false;
|
|
break;
|
|
|
|
case MENU_FEATURES:
|
|
if (SHRestricted(REST_NOSETFOLDERS) || SHRestricted(REST_NOCONTROLPANEL)) return false;
|
|
break;
|
|
|
|
case MENU_RESTART:
|
|
case MENU_SHUTDOWN:
|
|
case MENU_RESTART_ADVANCED:
|
|
case MENU_RESTART_UPDATE:
|
|
case MENU_SHUTDOWN_UPDATE:
|
|
case MENU_SHUTDOWN_HYBRID:
|
|
if (SHRestricted(REST_NOCLOSE)) return false;
|
|
break;
|
|
}
|
|
|
|
ExecuteSysCommand(menuCommand);
|
|
return true;
|
|
}
|
|
|
|
static HRESULT CreatePinLink( PCIDLIST_ABSOLUTE sourcePidl, const wchar_t *name, const wchar_t *iconPath, int iconIndex )
|
|
{
|
|
wchar_t path[_MAX_PATH];
|
|
Sprintf(path,_countof(path),L"%s\\%s.lnk",CMenuContainer::s_PinFolder,name);
|
|
wchar_t finalPath[_MAX_PATH];
|
|
PathYetAnotherMakeUniqueName(finalPath,path,NULL,PathFindFileName(path));
|
|
|
|
HRESULT hr;
|
|
{
|
|
CComPtr<IShellLink> pLink;
|
|
hr=pLink.CoCreateInstance(CLSID_ShellLink);
|
|
if (FAILED(hr)) return hr;
|
|
|
|
hr=pLink->SetIDList(sourcePidl);
|
|
if (FAILED(hr)) return hr;
|
|
|
|
if (iconPath)
|
|
{
|
|
hr=pLink->SetIconLocation(iconPath,iconIndex);
|
|
if (FAILED(hr)) return hr;
|
|
}
|
|
|
|
CComQIPtr<IPersistFile> pFile(pLink);
|
|
if (!pFile) return E_FAIL;
|
|
hr=pFile->Save(finalPath,TRUE);
|
|
}
|
|
{
|
|
// reopen the link and set the "no new" property. without reopening the original properties are lost
|
|
CComPtr<IShellLink> pLink;
|
|
hr=pLink.CoCreateInstance(CLSID_ShellLink);
|
|
CComQIPtr<IPersistFile> pFile(pLink);
|
|
hr=pFile->Load(finalPath,STGM_READWRITE);
|
|
CComQIPtr<IPropertyStore> pStore(pLink);
|
|
if (pStore)
|
|
{
|
|
PROPVARIANT val;
|
|
InitPropVariantFromBoolean(TRUE,&val);
|
|
pStore->SetValue(PKEY_AppUserModel_ExcludeFromShowInNewInstall,val);
|
|
PropVariantClear(&val);
|
|
pStore->Commit();
|
|
}
|
|
hr=pFile->Save(finalPath,TRUE);
|
|
}
|
|
HANDLE h=CreateFile(finalPath,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
|
|
if (h!=INVALID_HANDLE_VALUE)
|
|
{
|
|
FILETIME curTime;
|
|
GetSystemTimeAsFileTime(&curTime);
|
|
SetFileTime(h,&curTime,&curTime,&curTime);
|
|
CloseHandle(h);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
// This function "activates" an item. The item can be activated in multiple ways:
|
|
// ACTIVATE_SELECT - select the item, make sure it is visible
|
|
// ACTIVATE_OPEN - if the item is a submenu, it is opened. otherwise the item is just selected (but all submenus are closed first)
|
|
// ACTIVATE_OPEN_KBD - same as above, but when done with a keyboard
|
|
// ACTIVATE_OPEN_SEARCH - opens the search results submenu
|
|
// ACTIVATE_EXECUTE - executes the item. it can be a shell item or a command item
|
|
// ACTIVATE_MENU - shows the context menu for the item
|
|
// ACTIVATE_RENAME - renames the item
|
|
// ACTIVATE_DELETE - deletes the item
|
|
// ACTIVATE_PROPERTIES - shows the properties of the item
|
|
void CMenuContainer::ActivateItem( int index, TActivateType type, const POINT *pPt, ActivateData *pData )
|
|
{
|
|
LOG_MENU(LOG_EXECUTE,L"Activate Item, ptr=%p, index=%d, type=%d",this,index,type);
|
|
if (index<0)
|
|
{
|
|
if (type==ACTIVATE_SELECT)
|
|
{
|
|
if (!(m_Options&CONTAINER_SEARCH))
|
|
SetFocus();
|
|
SetHotItem(-1);
|
|
return;
|
|
}
|
|
else if (type==ACTIVATE_MENU)
|
|
{
|
|
index=0;
|
|
type=ACTIVATE_MENU_BACKGROUND;
|
|
}
|
|
else
|
|
return;
|
|
}
|
|
|
|
// make a const copy of the item and use it instead. the m_Items array can be reallocated at any time
|
|
const MenuItem item=m_Items[index];
|
|
CAbsolutePidl pItemPidl1, pItemPidl2;
|
|
pItemPidl1.Clone(item.pItem1);
|
|
pItemPidl2.Clone(item.pItem2);
|
|
((MenuItem&)item).pItem1=NULL; // hack to ensure the pidls are not used anywhere here
|
|
((MenuItem&)item).pItem2=NULL;
|
|
|
|
if (type==ACTIVATE_SELECT)
|
|
{
|
|
// set the hot item
|
|
if (item.id==MENU_SEARCH_BOX)
|
|
{
|
|
m_SearchBox.SetFocus();
|
|
SetHotItem(-1);
|
|
}
|
|
else
|
|
{
|
|
if (item.id==MENU_PROGRAMS_TREE && m_pProgramsTree && m_pProgramsTree->m_hWnd)
|
|
m_pProgramsTree->SetFocus();
|
|
else if (!(m_Options&CONTAINER_SEARCH) && (m_bSubMenu || s_MenuMode!=MODE_SEARCH))
|
|
SetFocus();
|
|
SetHotItem(index,false,true);
|
|
}
|
|
if (m_ScrollHeight>0 && index<m_ScrollCount)
|
|
{
|
|
// scroll the pager to make this item visible
|
|
RECT rc=item.itemRect;
|
|
OffsetRect(&rc,0,-m_rContent.top);
|
|
int pos=m_ScrollOffset;
|
|
int total=m_Items[m_ScrollCount-1].itemRect.bottom-m_rContent.top-m_ScrollHeight;
|
|
if (pos>rc.top-m_ScrollButtonSize)
|
|
pos=rc.top-m_ScrollButtonSize;
|
|
else if (pos<rc.bottom+m_ScrollButtonSize-m_ScrollHeight)
|
|
pos=rc.bottom+m_ScrollButtonSize-m_ScrollHeight;
|
|
if (pos<0) pos=0;
|
|
if (pos>total) pos=total;
|
|
if (m_ScrollOffset!=pos)
|
|
{
|
|
m_ScrollOffset=pos;
|
|
UpdateScroll();
|
|
Invalidate();
|
|
}
|
|
}
|
|
if (m_SearchScrollCount>m_SearchScrollHeight && index>=m_OriginalCount)
|
|
{
|
|
// scroll the search results to make this item visible
|
|
int idx=index-m_OriginalCount;
|
|
int pos=m_SearchScrollPos;
|
|
if (pos>idx) pos=idx;
|
|
if (pos+m_SearchScrollHeight<idx+1)
|
|
pos=idx-m_SearchScrollHeight+1;
|
|
if (m_SearchScrollPos!=pos)
|
|
{
|
|
m_SearchScrollPos=m_Scrollbar.SetScrollPos(SB_CTL,pos);
|
|
InvalidateRect(&m_rContent);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
bool bShift=(!pData || !pData->bNoModifiers) && GetKeyState(VK_SHIFT)<0;
|
|
bool bCtrl=(!pData || !pData->bNoModifiers) && GetKeyState(VK_CONTROL)<0;
|
|
|
|
if (type==ACTIVATE_OPEN || type==ACTIVATE_OPEN_KBD || type==ACTIVATE_OPEN_SEARCH)
|
|
{
|
|
if (item.id==MENU_SEARCH_BOX && type!=ACTIVATE_OPEN_SEARCH)
|
|
return;
|
|
s_HotPos=GetMessagePos();
|
|
if (!item.bFolder && item.id!=MENU_SEARCH_BOX)
|
|
{
|
|
SetActiveWindow();
|
|
// destroy old submenus
|
|
CloseSubMenus(0,this);
|
|
|
|
// just select the item
|
|
ActivateItem(index,ACTIVATE_SELECT,NULL);
|
|
return;
|
|
}
|
|
|
|
OpenSubMenu(index,type,bShift);
|
|
return;
|
|
}
|
|
|
|
bool bKeepOpen=(type==ACTIVATE_EXECUTE) && bShift && !bCtrl && (!item.bMetroLink || GetWinVersion()>=WIN_VER_WIN10);
|
|
bool bTrackRecent=false;
|
|
if (s_RecentPrograms!=RECENT_PROGRAMS_NONE)
|
|
{
|
|
if (item.id==MENU_RECENT)
|
|
bTrackRecent=true;
|
|
else if (!m_bSubMenu || (m_Options&CONTAINER_TRACK))
|
|
bTrackRecent=item.id==MENU_NO && (!item.bFolder || item.bHasJumpList) && !item.pStdItem && (item.categoryHash&15)<=CSearchManager::CATEGORY_SETTING;
|
|
}
|
|
|
|
CString searchText;
|
|
for (CMenuContainer *pSearchMenu=this;pSearchMenu;pSearchMenu=pSearchMenu->m_pParent)
|
|
if (pSearchMenu->m_SearchBox.m_hWnd)
|
|
{
|
|
pSearchMenu->m_SearchBox.GetWindowText(searchText);
|
|
break;
|
|
}
|
|
|
|
if (type==ACTIVATE_EXECUTE)
|
|
{
|
|
if (item.id==MENU_EMPTY || item.id==MENU_EMPTY_TOP) return;
|
|
if (item.bFolder && pItemPidl1 && !item.bSplit && !GetSettingBool(L"EnableExplorer"))
|
|
return;
|
|
if (item.id==MENU_SEARCH_BOX)
|
|
{
|
|
// the search button was pressed
|
|
m_SearchBox.SetFocus();
|
|
CloseSubMenus(CLOSE_POST,this);
|
|
m_SearchBox.SetWindowText(L"");
|
|
return;
|
|
}
|
|
if (item.id==MENU_SEARCH_CATEGORY)
|
|
{
|
|
if (bCtrl || (pData && pData->bArrow))
|
|
{
|
|
for (std::list<CSearchManager::SearchCategory>::const_iterator it=s_SearchResults.indexed.begin();it!=s_SearchResults.indexed.end();++it)
|
|
{
|
|
if (item.categoryHash==it->categoryHash)
|
|
{
|
|
if (bKeepOpen)
|
|
LockSetForegroundWindow(LSFW_LOCK);
|
|
else
|
|
{
|
|
LockSetForegroundWindow(LSFW_UNLOCK);
|
|
FadeOutItem(index);
|
|
CloseSubMenus(CLOSE_POST,NULL);
|
|
}
|
|
PlayMenuSound(SOUND_COMMAND);
|
|
g_SearchManager.LaunchExternalSearch(it->search,it->categoryHash,searchText);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_SearchCategoryHash=(m_SearchCategoryHash==item.categoryHash)?CSearchManager::CATEGORY_INVALID:item.categoryHash;
|
|
RefreshSearch();
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (item.jumpIndex>=0)
|
|
{
|
|
if (item.id==MENU_NO)
|
|
{
|
|
if (bKeepOpen)
|
|
LockSetForegroundWindow(LSFW_LOCK);
|
|
else
|
|
{
|
|
LockSetForegroundWindow(LSFW_UNLOCK);
|
|
FadeOutItem(index);
|
|
CloseSubMenus(CLOSE_POST,NULL);
|
|
}
|
|
PlayMenuSound(SOUND_COMMAND);
|
|
ExecuteJumpItem(s_JumpAppInfo,s_JumpList.groups[LOWORD(item.jumpIndex)].items[HIWORD(item.jumpIndex)],g_OwnerWindow);
|
|
}
|
|
return;
|
|
}
|
|
if (g_LogCategories&LOG_ITEMS)
|
|
{
|
|
LOG_MENU(LOG_EXECUTE,L"item.bLink: %d",item.bLink?1:0);
|
|
LOG_MENU(LOG_EXECUTE,L"item.bMetroLink: %d",item.bMetroLink?1:0);
|
|
LOG_MENU(LOG_EXECUTE,L"item.bMetroApp: %d",item.bMetroApp?1:0);
|
|
if (!item.pItemInfo)
|
|
{
|
|
LOG_MENU(LOG_EXECUTE,L"No pItemInfo");
|
|
}
|
|
else
|
|
{
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
LOG_MENU(LOG_EXECUTE,L"bLink: %d",item.pItemInfo->IsLink()?1:0);
|
|
LOG_MENU(LOG_EXECUTE,L"bMetroLink: %d",item.pItemInfo->IsMetroLink()?1:0);
|
|
LOG_MENU(LOG_EXECUTE,L"bMetroApp: %d",item.pItemInfo->IsMetroApp()?1:0);
|
|
LOG_MENU(LOG_EXECUTE,L"bProtectedLink: %d",item.pItemInfo->IsProtectedLink()?1:0);
|
|
LOG_MENU(LOG_EXECUTE,L"bNoPin: %d",item.pItemInfo->IsNoPin()?1:0);
|
|
LOG_MENU(LOG_EXECUTE,L"bNoNew: %d",item.pItemInfo->IsNoNew()?1:0);
|
|
LOG_MENU(LOG_EXECUTE,L"path: %s",item.pItemInfo->GetPath());
|
|
LOG_MENU(LOG_EXECUTE,L"PATH: %s",item.pItemInfo->PATH);
|
|
LOG_MENU(LOG_EXECUTE,L"targetPATH: %s",item.pItemInfo->GetTargetPATH());
|
|
LOG_MENU(LOG_EXECUTE,L"appid: %s",item.pItemInfo->GetAppid());
|
|
LOG_MENU(LOG_EXECUTE,L"metroName: %s",item.pItemInfo->GetMetroName());
|
|
LOG_MENU(LOG_EXECUTE,L"iconPath: %s",item.pItemInfo->GetIconPath());
|
|
}
|
|
if (item.pItemInfo->smallIcon)
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ICONS);
|
|
LOG_MENU(LOG_EXECUTE,L"smallIcon: %s",item.pItemInfo->smallIcon->GetPath());
|
|
}
|
|
if (item.pItemInfo->largeIcon)
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ICONS);
|
|
LOG_MENU(LOG_EXECUTE,L"largeIcon: %s",item.pItemInfo->largeIcon->GetPath());
|
|
}
|
|
}
|
|
}
|
|
if (item.bMetroLink)
|
|
{
|
|
LockSetForegroundWindow(LSFW_UNLOCK);
|
|
FadeOutItem(index);
|
|
PlayMenuSound(SOUND_COMMAND);
|
|
ExecuteMetroLink(item.pItemInfo);
|
|
if (bTrackRecent)
|
|
{
|
|
CString path;
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
path=item.pItemInfo->GetPath();
|
|
}
|
|
AddMRUShortcut(path);
|
|
}
|
|
g_ItemManager.RemoveNewItem(pItemPidl1,NULL,false);
|
|
if (!(m_Options&CONTAINER_LINK))
|
|
g_SearchManager.AddItemRank(item.nameHash);
|
|
// close all menus when launching Metro apps
|
|
CloseSubMenus(CLOSE_POST,NULL);
|
|
return;
|
|
}
|
|
if (!pItemPidl1)
|
|
{
|
|
if (item.id<MENU_PROGRAMS) return; // non-executable item
|
|
if (item.bFolder && item.pStdItem && item.pStdItem->submenu && !item.pStdItem->command && item.id!=MENU_SHUTDOWN_BUTTON)
|
|
return; // non-executable item
|
|
}
|
|
|
|
// when executing an item close the whole menu
|
|
if (!bKeepOpen)
|
|
{
|
|
if (g_TopWin7Menu && s_bAllPrograms)
|
|
{
|
|
// send, don't post. the top menu must be closed immediately. otherwise its closing may interfere with launching the command
|
|
::SendMessage(g_TopWin7Menu,WM_CLOSE,0,0);
|
|
}
|
|
else
|
|
{
|
|
s_bPreventClosing=true; // hack: prevents any other closing behavior to occur while the item is being executed
|
|
CloseSubMenus(CLOSE_POST,NULL);
|
|
s_bPreventClosing=false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (type==ACTIVATE_MENU || type==ACTIVATE_MENU_BACKGROUND)
|
|
{
|
|
// when showing the context menu close all submenus
|
|
if (!(m_Options&CONTAINER_SEARCH))
|
|
SetActiveWindow();
|
|
if (s_MenuMode==MODE_NORMAL)
|
|
CloseSubMenus(0,this);
|
|
if (m_bTwoColumns && s_MenuMode==MODE_JUMPLIST && index<m_OriginalCount)
|
|
{
|
|
CloseSubMenus(0,this);
|
|
SetMenuMode(MODE_NORMAL);
|
|
}
|
|
}
|
|
|
|
if (type!=ACTIVATE_MENU_BACKGROUND)
|
|
SetHotItem(index);
|
|
|
|
bool bCommand=(item.pStdItem && item.pStdItem->command && *item.pStdItem->command) || item.id==MENU_SEARCH_EXECUTE || item.bStartScreen || !pItemPidl1; // this is a special executable command
|
|
|
|
if (type==ACTIVATE_EXECUTE && bCommand)
|
|
{
|
|
if (item.bStartScreen)
|
|
{
|
|
g_WSMHMonitor=MonitorFromWindow(m_hWnd,MONITOR_DEFAULTTONULL);
|
|
::PostMessage(g_ProgWin,WM_SYSCOMMAND,SC_TASKLIST,'WSMH');
|
|
return;
|
|
}
|
|
|
|
if (bKeepOpen)
|
|
LockSetForegroundWindow(LSFW_LOCK);
|
|
else
|
|
{
|
|
LockSetForegroundWindow(LSFW_UNLOCK);
|
|
if (item.id!=MENU_SLEEP && item.id!=MENU_HIBERNATE)
|
|
FadeOutItem(index);
|
|
// flush all messages to close the menus
|
|
// m_hWnd is not valid after this point
|
|
MSG msg;
|
|
while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
PlayMenuSound(SOUND_COMMAND);
|
|
|
|
// special handling for command items
|
|
TMenuID menuCommand=(item.id==MENU_SHUTDOWN_BUTTON)?s_ShutdownCommand:item.id;
|
|
|
|
// translate command
|
|
switch (menuCommand)
|
|
{
|
|
case MENU_SEARCH_FILES:
|
|
if (!GetSettingString(L"SearchFilesCommand").IsEmpty())
|
|
menuCommand=MENU_SEARCH_FILES_CUSTOM;
|
|
break;
|
|
case MENU_LOGOFF: // log off
|
|
if (GetSettingBool(L"ConfirmLogOff"))
|
|
menuCommand=MENU_LOGOFF_CONFIRM;
|
|
break;
|
|
case MENU_RESTART:
|
|
if (GetWinVersion()>=WIN_VER_WIN8 && bShift)
|
|
menuCommand=MENU_RESTART_ADVANCED;
|
|
else if (s_bHasUpdates && GetWinVersion()>=WIN_VER_WIN8)
|
|
menuCommand=MENU_RESTART_UPDATE;
|
|
else
|
|
menuCommand=MENU_RESTART_NOUPDATE;
|
|
break;
|
|
case MENU_SHUTDOWN:
|
|
if (s_bHasUpdates)
|
|
menuCommand=MENU_SHUTDOWN_UPDATE;
|
|
else if (GetWinVersion()>=WIN_VER_WIN8 && !bShift && GetSettingBool(L"HybridShutdown"))
|
|
menuCommand=MENU_SHUTDOWN_HYBRID;
|
|
else
|
|
menuCommand=MENU_SHUTDOWN_NOUPDATE;
|
|
break;
|
|
}
|
|
|
|
switch (menuCommand)
|
|
{
|
|
case MENU_CLASSIC_SETTINGS: // show our settings
|
|
#ifdef PREVENT_CLOSING
|
|
EditSettings(true,0);
|
|
#else
|
|
EditSettings(false,0);
|
|
#endif
|
|
break;
|
|
case MENU_MORE_RESULTS:
|
|
g_SearchManager.LaunchExternalSearch(NULL,CSearchManager::CATEGORY_INVALID,searchText);
|
|
break;
|
|
case MENU_SEARCH_INTERNET:
|
|
g_SearchManager.LaunchInternetSearch(searchText);
|
|
break;
|
|
case MENU_SEARCH_EXECUTE:
|
|
ExecuteCommand(item.name,bShift && bCtrl,true);
|
|
break;
|
|
case MENU_SEARCH_FILES_CUSTOM:
|
|
ExecuteCommand(GetSettingString(L"SearchFilesCommand"),bShift && bCtrl,true);
|
|
break;
|
|
|
|
default:
|
|
if (!ExecuteSysCommand(menuCommand) && item.pStdItem && item.pStdItem->command && *item.pStdItem->command)
|
|
{
|
|
wchar_t buf[1024];
|
|
Strcpy(buf,_countof(buf),item.pStdItem->command);
|
|
DoEnvironmentSubst(buf,_countof(buf));
|
|
if (!searchText.IsEmpty() && (wcswcs(buf,L"%1") || wcswcs(buf,L"%2")))
|
|
DoSearchSubst(buf,_countof(buf),searchText);
|
|
ExecuteCommand(buf,bShift && bCtrl,false);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
bool bHasMenu=false;
|
|
if (pItemPidl1)
|
|
bHasMenu=true;
|
|
else if (type==ACTIVATE_MENU && (item.id==MENU_EMPTY || item.id==MENU_EMPTY_TOP || item.id==MENU_SEARCH_CATEGORY))
|
|
bHasMenu=true;
|
|
else if (type==ACTIVATE_MENU && item.id==MENU_APPS && (g_ItemManager.HasNewApps(true) || (pData && pData->bProgramsTree)))
|
|
bHasMenu=true;
|
|
if (!bHasMenu)
|
|
return;
|
|
|
|
bool bUninstallPolicy=GetUninstallPolicy();
|
|
|
|
bool _bProtectedLink=false;
|
|
bool _bMetroApp=false;
|
|
bool _bExplicitAppId=false;
|
|
bool _bIsLink=false;
|
|
CString _path;
|
|
CItemManager::TLocation _location=CItemManager::LOCATION_UNKNOWN;
|
|
CString _appId;
|
|
if (item.pItemInfo && item.id!=MENU_APPS)
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
_bProtectedLink=item.pItemInfo->IsProtectedLink();
|
|
_bMetroApp=item.pItemInfo->IsMetroApp();
|
|
_path=item.pItemInfo->GetPath();
|
|
_location=item.pItemInfo->GetLocation();
|
|
_appId=item.pItemInfo->GetAppid();
|
|
_bIsLink=item.pItemInfo->IsLink();
|
|
_bExplicitAppId=item.pItemInfo->IsExplicitAppId();
|
|
}
|
|
|
|
// create a context menu for the selected item. the context menu can be shown (ACTIVATE_MENU) or its default
|
|
// item can be executed automatically (ACTIVATE_EXECUTE)
|
|
CComPtr<IContextMenu> pMenu;
|
|
HMENU menu=CreatePopupMenu();
|
|
CComPtr<IContextMenu> pSecondaryMenu;
|
|
int secondaryCmd=CMD_LAST;
|
|
|
|
CComPtr<IShellItem> pItem;
|
|
int insertBefore=-1, insertSecondary=-1;
|
|
if (item.id==MENU_APPS)
|
|
{
|
|
insertBefore=0;
|
|
if (g_ItemManager.HasNewApps(true))
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_MARKOLD,FindTranslation(L"Menu.RemoveHighlight",L"Remove highlight"));
|
|
else if (!pData || !pData->bProgramsTree)
|
|
return;
|
|
}
|
|
else if (item.id==MENU_EMPTY || item.id==MENU_EMPTY_TOP || item.id==MENU_SEARCH_CATEGORY || type==ACTIVATE_MENU_BACKGROUND)
|
|
{
|
|
insertBefore=0;
|
|
}
|
|
else
|
|
{
|
|
bool bQueryMenu=true;
|
|
if (item.jumpIndex>=0)
|
|
{
|
|
const CJumpItem &jumpItem=s_JumpList.groups[LOWORD(item.jumpIndex)].items[HIWORD(item.jumpIndex)];
|
|
// only items or links with no arguments can have a context menu
|
|
bQueryMenu=((type==ACTIVATE_MENU || type==ACTIVATE_PROPERTIES) && (jumpItem.type==CJumpItem::TYPE_ITEM || (jumpItem.type==CJumpItem::TYPE_LINK && !jumpItem.bHasArguments)) && !_path.IsEmpty());
|
|
}
|
|
if (bQueryMenu)
|
|
{
|
|
SHCreateItemFromIDList(pItemPidl1,IID_IShellItem,(void**)&pItem);
|
|
CComQIPtr<IShellItem2> pItem2(pItem);
|
|
if (pItem2 &&
|
|
((item.categoryHash&CSearchManager::CATEGORY_MASK)!=CSearchManager::CATEGORY_ITEM ||
|
|
(GetSettingInt(L"CompatibilityFixes")&COMPATIBILITY_UPDATE_ITEMS))) // don't update search items because we don't have the right bind context for them
|
|
pItem2->Update(NULL);
|
|
if (!pItem || FAILED(pItem->BindToHandler(NULL,BHID_SFUIObject,IID_IContextMenu,(void**)&pMenu)))
|
|
{
|
|
DestroyMenu(menu);
|
|
return;
|
|
}
|
|
|
|
UINT flags=CMF_DEFAULTONLY;
|
|
if (type==ACTIVATE_MENU)
|
|
{
|
|
flags=CMF_NORMAL|CMF_CANRENAME;
|
|
if (bShift) flags|=CMF_EXTENDEDVERBS;
|
|
}
|
|
if (type==ACTIVATE_DELETE || type==ACTIVATE_PROPERTIES)
|
|
flags=CMF_NORMAL;
|
|
if (type==ACTIVATE_RENAME)
|
|
flags=CMF_NORMAL|CMF_CANRENAME;
|
|
if (type==ACTIVATE_EXECUTE && bShift && bCtrl)
|
|
flags|=CMF_EXTENDEDVERBS;
|
|
HRESULT hr=pMenu->QueryContextMenu(menu,0,CMD_LAST,CMD_MAX,flags);
|
|
if (FAILED(hr))
|
|
{
|
|
DestroyMenu(menu);
|
|
return;
|
|
}
|
|
secondaryCmd=CMD_LAST+LOWORD(hr)+10;
|
|
}
|
|
|
|
if (item.bFolder && pItemPidl2)
|
|
{
|
|
// context menu for a double folder - remove most commands, add Open All Users
|
|
int n=GetMenuItemCount(menu);
|
|
for (int i=0;i<n;i++)
|
|
{
|
|
int id=GetMenuItemID(menu,i);
|
|
char command[256];
|
|
if (id<CMD_LAST || id>CMD_MAX || FAILED(pMenu->GetCommandString(id-CMD_LAST,GCS_VERBA,NULL,command,_countof(command))))
|
|
command[0]=0;
|
|
if (_stricmp(command,"open")==0)
|
|
{
|
|
if (GetSettingBool(L"EnableExplorer"))
|
|
{
|
|
if (!s_bNoCommonFolders)
|
|
InsertMenu(menu,i+1,MF_BYPOSITION|MF_STRING,CMD_OPEN_ALL,FindTranslation(L"Menu.OpenAll",L"O&pen All Users"));
|
|
InsertMenu(menu,i+2,MF_BYPOSITION|MF_SEPARATOR,0,0);
|
|
i+=2;
|
|
n+=2;
|
|
continue;
|
|
}
|
|
}
|
|
else if (_stricmp(command,"rename")==0 || _stricmp(command,"delete")==0)
|
|
{
|
|
if (item.id!=MENU_PROGRAMS) continue;
|
|
}
|
|
else if (_stricmp(command,"properties")==0)
|
|
{
|
|
insertBefore=i;
|
|
continue;
|
|
}
|
|
DeleteMenu(menu,i,MF_BYPOSITION);
|
|
i--;
|
|
n--;
|
|
}
|
|
}
|
|
else if (type==ACTIVATE_MENU && item.id==MENU_RECENT)
|
|
{
|
|
// context menu for a recent item - leave just open and runas
|
|
bool bHasUninstall=false;
|
|
int n=GetMenuItemCount(menu);
|
|
for (int i=0;i<n;i++)
|
|
{
|
|
int id=GetMenuItemID(menu,i);
|
|
char command[256];
|
|
if (id<CMD_LAST || id>CMD_MAX || FAILED(pMenu->GetCommandString(id-CMD_LAST,GCS_VERBA,NULL,command,_countof(command))))
|
|
command[0]=0;
|
|
if (_stricmp(command,"properties")==0)
|
|
{
|
|
insertBefore=i;
|
|
continue;
|
|
}
|
|
if (item.bMetroLink)
|
|
{
|
|
if (_stricmp(command,"pin_classic")==0 || _stricmp(command,"properties")==0)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if (bShift)
|
|
{
|
|
if (_stricmp(command,"delete")!=0 && _stricmp(command,"rename")!=0)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if (_stricmp(command,"open")==0 || _stricmp(command,"opencontaining")==0 || _stricmp(command,"runas")==0 || _stricmp(command,"runasuser")==0
|
|
|| _stricmp(command,"taskbarpin")==0 || _stricmp(command,"taskbarunpin")==0 || _stricmp(command,"pin_classic")==0 || _stricmp(command,"properties")==0)
|
|
continue;
|
|
if (_stricmp(command,"uninstall")==0)
|
|
{
|
|
bHasUninstall=true;
|
|
if (item.bMetroApp && bUninstallPolicy && !IsProtectedApp(_appId))
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
DeleteMenu(menu,i,MF_BYPOSITION);
|
|
i--;
|
|
n--;
|
|
}
|
|
if (insertBefore==-1)
|
|
insertBefore=n;
|
|
|
|
if (item.bMetroLink)
|
|
{
|
|
InsertMenu(menu,0,MF_BYPOSITION|MF_STRING,CMD_OPEN,FindTranslation(L"Menu.Open",L"&Open"));
|
|
SetMenuDefaultItem(menu,0,TRUE);
|
|
insertBefore++;
|
|
if (GetWinVersion()<WIN_VER_WIN10 && bUninstallPolicy && !bHasUninstall && !IsProtectedApp(_appId))
|
|
{
|
|
InsertMenu(menu,insertBefore,MF_BYPOSITION|MF_STRING,CMD_UNINSTALL,FindTranslation(L"Menu.Uninstall",L"&Uninstall"));
|
|
insertBefore++;
|
|
}
|
|
insertSecondary=1;
|
|
n++;
|
|
}
|
|
if (item.bMetroApp && IsWin10RS1() && !bHasUninstall && CanUninstallMetroApp(_appId))
|
|
{
|
|
InsertMenu(menu,insertBefore,MF_BYPOSITION|MF_STRING,CMD_UNINSTALL,FindTranslation(L"Menu.Uninstall",L"&Uninstall"));
|
|
insertBefore++;
|
|
}
|
|
|
|
if (n>0)
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_SEPARATOR,0,0);
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_DELETEMRU,FindTranslation(L"Menu.RemoveList",L"Remove &from this list"));
|
|
if (s_RecentPrograms==RECENT_PROGRAMS_RECENT)
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_DELETEALL,FindTranslation(L"Menu.RemoveAll",L"C&lear recent items list"));
|
|
if (pItemPidl1 && GetSettingBool(L"EnableExplorer"))
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_EXPLORE,FindTranslation(L"Menu.Explore",L"&Explore"));
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_SEPARATOR,0,0);
|
|
}
|
|
else if (type==ACTIVATE_MENU && item.bMetroLink && (_bProtectedLink || (m_Options&(CONTAINER_APPS|CONTAINER_SEARCH))))
|
|
{
|
|
// context menu for a Metro link - just open, properties and Explore
|
|
int n=GetMenuItemCount(menu);
|
|
for (int i=0;i<n;i++)
|
|
{
|
|
int id=GetMenuItemID(menu,i);
|
|
char command[256];
|
|
if (id<CMD_LAST || id>CMD_MAX || FAILED(pMenu->GetCommandString(id-CMD_LAST,GCS_VERBA,NULL,command,_countof(command))))
|
|
command[0]=0;
|
|
if (_stricmp(command,"properties")==0 || _stricmp(command,"pin_classic")==0)
|
|
{
|
|
insertBefore=i;
|
|
continue;
|
|
}
|
|
DeleteMenu(menu,i,MF_BYPOSITION);
|
|
i--;
|
|
n--;
|
|
}
|
|
InsertMenu(menu,0,MF_BYPOSITION|MF_STRING,CMD_OPEN,FindTranslation(L"Menu.Open",L"&Open"));
|
|
SetMenuDefaultItem(menu,0,TRUE);
|
|
insertBefore++;
|
|
if (GetWinVersion()<WIN_VER_WIN10 && bUninstallPolicy && !IsProtectedApp(_appId))
|
|
{
|
|
InsertMenu(menu,insertBefore,MF_BYPOSITION|MF_STRING,CMD_UNINSTALL,FindTranslation(L"Menu.Uninstall",L"&Uninstall"));
|
|
insertBefore++;
|
|
}
|
|
insertSecondary=1;
|
|
if (GetSettingBool(L"EnableExplorer"))
|
|
{
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_SEPARATOR,0,0);
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_EXPLORE,FindTranslation(L"Menu.Explore",L"&Explore"));
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_SEPARATOR,0,0);
|
|
}
|
|
}
|
|
else if (type==ACTIVATE_MENU && ((m_Options&CONTAINER_SEARCH) || (s_MenuMode==MODE_SEARCH && index>m_OriginalCount)))
|
|
{
|
|
// context menu for a search item - remove delete, rename and link
|
|
int n=GetMenuItemCount(menu);
|
|
for (int i=0;i<n;i++)
|
|
{
|
|
int id=GetMenuItemID(menu,i);
|
|
char command[256];
|
|
if (id<CMD_LAST || id>CMD_MAX || FAILED(pMenu->GetCommandString(id-CMD_LAST,GCS_VERBA,NULL,command,_countof(command))))
|
|
command[0]=0;
|
|
if (_stricmp(command,"properties")==0)
|
|
{
|
|
insertBefore=i;
|
|
continue;
|
|
}
|
|
if (_stricmp(command,"delete")!=0 && _stricmp(command,"rename")!=0)
|
|
continue;
|
|
DeleteMenu(menu,i,MF_BYPOSITION);
|
|
i--;
|
|
n--;
|
|
}
|
|
bool last=insertBefore==-1;
|
|
if (last)
|
|
insertBefore=n;
|
|
|
|
CSearchManager::TItemCategory cat=(CSearchManager::TItemCategory)(item.categoryHash&CSearchManager::CATEGORY_MASK);
|
|
if (pItemPidl1 && (cat<=CSearchManager::CATEGORY_FILE || cat==CSearchManager::CATEGORY_AUTOCOMPLETE))
|
|
{
|
|
bool bExplore=GetSettingBool(L"EnableExplorer");
|
|
bool bPin=!s_PinFolder.IsEmpty() && (cat==CSearchManager::CATEGORY_SETTING || cat==CSearchManager::CATEGORY_METROSETTING);
|
|
if (bExplore || bPin)
|
|
{
|
|
if (n>0)
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_SEPARATOR,0,0);
|
|
if (bPin)
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_PINSETTING,FindTranslation(L"Menu.PinStartCs",L"Pin to Start menu (Open-Shell)"));
|
|
if (bExplore)
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_EXPLORE,FindTranslation(L"Menu.Explore",L"&Explore"));
|
|
if (!last)
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_SEPARATOR,0,0);
|
|
}
|
|
}
|
|
}
|
|
else if (item.jumpIndex>=0)
|
|
{
|
|
// context menu for a jumplist item - just properties
|
|
int n=GetMenuItemCount(menu);
|
|
for (int i=0;i<n;i++)
|
|
{
|
|
int id=GetMenuItemID(menu,i);
|
|
char command[256];
|
|
if (id<CMD_LAST || id>CMD_MAX || FAILED(pMenu->GetCommandString(id-CMD_LAST,GCS_VERBA,NULL,command,_countof(command))))
|
|
command[0]=0;
|
|
if (_stricmp(command,"properties")==0)
|
|
continue;
|
|
DeleteMenu(menu,i,MF_BYPOSITION);
|
|
i--;
|
|
n--;
|
|
}
|
|
insertBefore=0;
|
|
const CJumpGroup &group=s_JumpList.groups[LOWORD(item.jumpIndex)];
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_OPEN,FindTranslation(L"Menu.Open",L"&Open"));
|
|
SetMenuDefaultItem(menu,0,TRUE);
|
|
if (group.type!=CJumpGroup::TYPE_TASKS)
|
|
{
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_SEPARATOR,0,0);
|
|
if (group.type==CJumpGroup::TYPE_PINNED)
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_PIN,FindTranslation(L"JumpList.Unpin",L"&Unpin from this list"));
|
|
else
|
|
{
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_PIN,FindTranslation(L"JumpList.Pin",L"P&in to this list"));
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_DELETEMRU,FindTranslation(L"JumpList.Remove",L"Remove &from this list"));
|
|
}
|
|
if (n>0)
|
|
{
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_SEPARATOR,0,0);
|
|
if (GetSettingBool(L"EnableExplorer"))
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_EXPLORE,FindTranslation(L"Menu.Explore",L"&Explore"));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool bHasUninstall=false;
|
|
int n=GetMenuItemCount(menu);
|
|
for (int i=0;i<n;i++)
|
|
{
|
|
int id=GetMenuItemID(menu,i);
|
|
char command[256];
|
|
if (id<CMD_LAST || id>CMD_MAX || FAILED(pMenu->GetCommandString(id-CMD_LAST,GCS_VERBA,NULL,command,_countof(command))))
|
|
command[0]=0;
|
|
if (_stricmp(command,"properties")==0)
|
|
{
|
|
insertBefore=i;
|
|
continue;
|
|
}
|
|
bool bDelete=false;
|
|
if (item.pStdItem && (_stricmp(command,"rename")==0 || _stricmp(command,"delete")==0))
|
|
bDelete=true;
|
|
else if (item.bMetroLink && _stricmp(command,"rename")==0)
|
|
bDelete=true;
|
|
else if (_stricmp(command,"uninstall")==0)
|
|
{
|
|
bHasUninstall=true;
|
|
if ((!item.bMetroApp && !item.bMetroLink) || !bUninstallPolicy || IsProtectedApp(_appId))
|
|
bDelete=true;
|
|
}
|
|
else if (item.bStartScreen)
|
|
{
|
|
if (_stricmp(command,"rename")==0 || _stricmp(command,"delete")==0)
|
|
EnableMenuItem(menu,i,MF_GRAYED|MF_BYPOSITION);
|
|
else if (_stricmp(command,"pin_classic")==0 && IsSettingLocked(L"StartScreenShortcut"))
|
|
EnableMenuItem(menu,i,MF_GRAYED|MF_BYPOSITION);
|
|
else if (_stricmp(command,"open")==0 || _stricmp(command,"opencontaining")==0 || _stricmp(command,"runas")==0)
|
|
bDelete=true;
|
|
}
|
|
if (bDelete)
|
|
{
|
|
DeleteMenu(menu,i,MF_BYPOSITION);
|
|
i--;
|
|
n--;
|
|
}
|
|
}
|
|
if (insertBefore==-1)
|
|
insertBefore=n;
|
|
if (item.bMetroLink)
|
|
{
|
|
InsertMenu(menu,0,MF_BYPOSITION|MF_STRING,CMD_OPEN,FindTranslation(L"Menu.Open",L"&Open"));
|
|
SetMenuDefaultItem(menu,0,TRUE);
|
|
insertBefore++;
|
|
if (GetWinVersion()<WIN_VER_WIN10 && !bHasUninstall && bUninstallPolicy && !IsProtectedApp(_appId))
|
|
{
|
|
InsertMenu(menu,insertBefore,MF_BYPOSITION|MF_STRING,CMD_UNINSTALL,FindTranslation(L"Menu.Uninstall",L"&Uninstall"));
|
|
insertBefore++;
|
|
}
|
|
insertSecondary=1;
|
|
}
|
|
else if (item.bMetroApp && !bHasUninstall && bUninstallPolicy && IsWin10RS1() && CanUninstallMetroApp(_appId))
|
|
{
|
|
InsertMenu(menu,insertBefore,MF_BYPOSITION|MF_STRING,CMD_UNINSTALL,FindTranslation(L"Menu.Uninstall",L"&Uninstall"));
|
|
insertBefore++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (item.bMetroLink && type==ACTIVATE_MENU && insertSecondary>=0)
|
|
{
|
|
pSecondaryMenu=GetMetroPinMenu(_appId);
|
|
if (pSecondaryMenu)
|
|
{
|
|
pSecondaryMenu->QueryContextMenu(menu,insertSecondary,secondaryCmd,CMD_MAX,CMF_NORMAL);
|
|
}
|
|
}
|
|
|
|
s_HotPos=GetMessagePos();
|
|
int res=0;
|
|
if (type==ACTIVATE_EXECUTE)
|
|
{
|
|
// just pick the default item
|
|
res=GetMenuDefaultItem(menu,FALSE,0);
|
|
if (bShift && bCtrl)
|
|
{
|
|
// find the runas verb if available
|
|
res=-1;
|
|
char command[256];
|
|
int n=GetMenuItemCount(menu);
|
|
for (int i=0;i<n;i++)
|
|
{
|
|
int id=GetMenuItemID(menu,i);
|
|
if (id>=CMD_LAST && id<=CMD_MAX && SUCCEEDED(pMenu->GetCommandString(id-CMD_LAST,GCS_VERBA,NULL,command,_countof(command))))
|
|
{
|
|
if (_stricmp(command,"runas")==0)
|
|
{
|
|
res=id;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (res==-1)
|
|
{
|
|
CComString pName;
|
|
if (SUCCEEDED(pItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,&pName)))
|
|
{
|
|
ExecuteCommand(pName,true,false);
|
|
DestroyMenu(menu);
|
|
s_HotPos=GetMessagePos();
|
|
return;
|
|
}
|
|
res=0;
|
|
}
|
|
}
|
|
if (res<0) res=0;
|
|
}
|
|
else if (type==ACTIVATE_RENAME || type==ACTIVATE_DELETE || type==ACTIVATE_PROPERTIES)
|
|
{
|
|
if ((type==ACTIVATE_RENAME || type==ACTIVATE_DELETE) && item.bStartScreen)
|
|
res=0;
|
|
else if (type==ACTIVATE_DELETE && item.id==MENU_RECENT)
|
|
res=CMD_DELETEMRU;
|
|
else if ((type==ACTIVATE_RENAME || type==ACTIVATE_DELETE) && item.bMetroLink && (_bProtectedLink || (m_Options&(CONTAINER_APPS|CONTAINER_SEARCH))))
|
|
res=0;
|
|
else
|
|
{
|
|
const char *name;
|
|
switch (type)
|
|
{
|
|
case ACTIVATE_RENAME: name="rename"; break;
|
|
case ACTIVATE_DELETE: name="delete"; break;
|
|
case ACTIVATE_PROPERTIES: name="properties"; break;
|
|
}
|
|
char command[256];
|
|
int n=GetMenuItemCount(menu);
|
|
for (int i=0;i<n;i++)
|
|
{
|
|
int id=GetMenuItemID(menu,i);
|
|
if (id>=CMD_LAST && id<=CMD_MAX && SUCCEEDED(pMenu->GetCommandString(id-CMD_LAST,GCS_VERBA,NULL,command,_countof(command))))
|
|
{
|
|
if (_stricmp(command,name)==0)
|
|
{
|
|
res=id;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (res<0) res=0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!GetSettingBool(L"EnableExplorer"))
|
|
{
|
|
// disable the Open verb
|
|
char command[256];
|
|
int n=GetMenuItemCount(menu);
|
|
for (int i=0;i<n;i++)
|
|
{
|
|
int id=GetMenuItemID(menu,i);
|
|
if (id>=CMD_LAST && id<=CMD_MAX && SUCCEEDED(pMenu->GetCommandString(id-CMD_LAST,GCS_VERBA,NULL,command,_countof(command))))
|
|
{
|
|
if ((item.bFolder && !item.bSplit && pItemPidl1 && _stricmp(command,"open")==0) || _stricmp(command,"opencontaining")==0)
|
|
{
|
|
EnableMenuItem(menu,i,MF_BYPOSITION|MF_GRAYED);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// show the context menu
|
|
m_pMenu2=pMenu;
|
|
m_pMenu3=pMenu;
|
|
HBITMAP shellBmp=NULL;
|
|
HBITMAP newFolderBmp=NULL;
|
|
HBITMAP newShortcutBmp=NULL;
|
|
if ((item.id==MENU_NO || item.id==MENU_EMPTY || type==ACTIVATE_MENU_BACKGROUND || (item.id==MENU_APPS && pData && pData->bProgramsTree)) && item.jumpIndex<0 && index<m_OriginalCount && (m_Options&CONTAINER_DROP)) // clicked on a movable item or the background
|
|
{
|
|
HMENU menu2=menu;
|
|
int subMenuIdx=-1;
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_SEPARATOR,0,0);
|
|
if (GetMenuItemCount(menu)>0)
|
|
{
|
|
if (GetSettingBool(L"CascadingMenu"))
|
|
{
|
|
menu2=CreatePopupMenu();
|
|
subMenuIdx=insertBefore;
|
|
insertBefore=0;
|
|
}
|
|
}
|
|
bool bSort=false, bAutoSort=false, bNew=false, bMarkOld=false;
|
|
if (pData && pData->bProgramsTree)
|
|
{
|
|
bNew=!(item.pItemInfo && _location==CItemManager::LOCATION_METRO) && !pData->bApps && GetSettingBool(L"ShowNewFolder");
|
|
bSort=true;
|
|
bAutoSort=pData->bAutoSort;
|
|
}
|
|
else
|
|
{
|
|
int n=0;
|
|
for (std::vector<MenuItem>::const_iterator it=m_Items.begin();it!=m_Items.end();++it)
|
|
if (it->id==MENU_NO)
|
|
n++;
|
|
if (n>1)
|
|
bSort=true; // more than 1 movable items
|
|
wchar_t path[_MAX_PATH];
|
|
if (!(m_Options&CONTAINER_APPS) && !(item.pItemInfo && _location==CItemManager::LOCATION_METRO) && !(m_Options&CONTAINER_NONEWFOLDER) && GetSettingBool(L"ShowNewFolder") && SHGetPathFromIDList(m_Path1[item.priority==2?1:0],path))
|
|
bNew=true;
|
|
bAutoSort=(m_Options&CONTAINER_AUTOSORT)!=0;
|
|
}
|
|
bMarkOld=item.bNew && pItemPidl1;
|
|
|
|
if (bSort)
|
|
InsertMenu(menu2,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_SORT,FindTranslation(L"Menu.SortByName",L"Sort &by Name"));
|
|
|
|
if (m_FolderHash[0])
|
|
InsertMenu(menu2,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_AUTOSORT,FindTranslation(L"Menu.AutoArrange",L"&Auto Arrange"));
|
|
if (bAutoSort)
|
|
{
|
|
EnableMenuItem(menu2,CMD_SORT,MF_BYCOMMAND|MF_GRAYED);
|
|
CheckMenuItem(menu2,CMD_AUTOSORT,MF_BYCOMMAND|MF_CHECKED);
|
|
}
|
|
if (bNew)
|
|
{
|
|
InsertMenu(menu2,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_NEWFOLDER,FindTranslation(L"Menu.NewFolder",L"New Folder"));
|
|
InsertMenu(menu2,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_NEWSHORTCUT,FindTranslation(L"Menu.NewShortcut",L"New Shortcut"));
|
|
}
|
|
if (bMarkOld)
|
|
InsertMenu(menu2,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_MARKOLD,FindTranslation(L"Menu.RemoveHighlight",L"Remove highlight"));
|
|
if (menu!=menu2 && GetMenuItemCount(menu2)==0)
|
|
{
|
|
DestroyMenu(menu2);
|
|
menu2=menu;
|
|
}
|
|
else
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_SEPARATOR,0,0);
|
|
|
|
if (bNew || menu!=menu2)
|
|
{
|
|
int size=GetSystemMetrics(SM_CXSMICON);
|
|
if (bNew)
|
|
{
|
|
HMODULE hShell32=GetModuleHandle(L"shell32.dll");
|
|
HICON hIcon=(HICON)LoadImage(hShell32,MAKEINTRESOURCE(319),IMAGE_ICON,size,size,LR_DEFAULTCOLOR);
|
|
if (hIcon)
|
|
{
|
|
newFolderBmp=BitmapFromIcon(hIcon,size,NULL,true);
|
|
MENUITEMINFO mii={sizeof(mii)};
|
|
mii.fMask=MIIM_BITMAP;
|
|
mii.hbmpItem=newFolderBmp;
|
|
SetMenuItemInfo(menu2,CMD_NEWFOLDER,FALSE,&mii);
|
|
}
|
|
hIcon=(HICON)LoadImage(hShell32,MAKEINTRESOURCE(16769),IMAGE_ICON,size,size,LR_DEFAULTCOLOR);
|
|
if (hIcon)
|
|
{
|
|
newShortcutBmp=BitmapFromIcon(hIcon,size,NULL,true);
|
|
MENUITEMINFO mii={sizeof(mii)};
|
|
mii.fMask=MIIM_BITMAP;
|
|
mii.hbmpItem=newShortcutBmp;
|
|
SetMenuItemInfo(menu2,CMD_NEWSHORTCUT,FALSE,&mii);
|
|
}
|
|
}
|
|
if (menu!=menu2)
|
|
{
|
|
InsertMenu(menu,subMenuIdx,MF_BYPOSITION|MF_POPUP,(UINT_PTR)menu2,FindTranslation(L"Menu.Organize",L"Organize Start menu"));
|
|
HICON hIcon=(HICON)LoadImage(g_Instance,MAKEINTRESOURCE(IDI_APPICON),IMAGE_ICON,size,size,LR_DEFAULTCOLOR);
|
|
if (hIcon)
|
|
{
|
|
shellBmp=BitmapFromIcon(hIcon,size,NULL,true);
|
|
MENUITEMINFO mii={sizeof(mii)};
|
|
mii.fMask=MIIM_BITMAP;
|
|
mii.hbmpItem=shellBmp;
|
|
SetMenuItemInfo(menu,subMenuIdx,TRUE,&mii);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (item.id==MENU_SEARCH_CATEGORY)
|
|
{
|
|
InsertMenu(menu,0,MF_BYPOSITION|MF_STRING,CMD_TOGGLE,item.categoryHash==m_SearchCategoryHash?FindTranslation(L"Menu.Collapse",L"Coll&apse"):FindTranslation(L"Menu.Expand",L"Exp&and"));
|
|
if (item.categoryHash>=CSearchManager::CATEGORY_FILE)
|
|
{
|
|
wchar_t text[256];
|
|
Sprintf(text,_countof(text),L"%s\t(Ctrl+Enter)",FindTranslation(L"Menu.MoreResults",L"See more results"));
|
|
InsertMenu(menu,1,MF_BYPOSITION|MF_STRING,CMD_EXPLORE,text);
|
|
}
|
|
SetMenuDefaultItem(menu,(pData && pData->bArrow)?1:0,TRUE);
|
|
}
|
|
|
|
if (item.id==MENU_PROGRAMS)
|
|
{
|
|
bool bNew;
|
|
if (s_bWin7Style && GetWinVersion()>=WIN_VER_WIN8 && GetSettingBool(L"AllProgramsMetro"))
|
|
bNew=g_ItemManager.HasNewPrograms(true) || g_ItemManager.HasNewApps(true);
|
|
else
|
|
bNew=g_ItemManager.HasNewPrograms(true);
|
|
if (bNew)
|
|
InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_MARKOLD,FindTranslation(L"Menu.RemoveHighlight",L"Remove highlight"));
|
|
}
|
|
if (pData && pData->bProgramsTree && item.bFolder && type==ACTIVATE_MENU)
|
|
{
|
|
InsertMenu(menu,0,MF_BYPOSITION|MF_STRING,CMD_TOGGLE,pData->bExpanded?FindTranslation(L"Menu.Collapse",L"Coll&apse"):FindTranslation(L"Menu.Expand",L"Exp&and"));
|
|
SetMenuDefaultItem(menu,0,TRUE);
|
|
InsertMenu(menu,1,MF_BYPOSITION|MF_SEPARATOR,0,0);
|
|
}
|
|
|
|
// remove multiple separators
|
|
{
|
|
bool bSeparator=true;
|
|
int n=GetMenuItemCount(menu);
|
|
for (int i=0;i<n;i++)
|
|
{
|
|
MENUITEMINFO info={sizeof(info),MIIM_FTYPE};
|
|
if (GetMenuItemInfo(menu,i,TRUE,&info))
|
|
{
|
|
if (info.fType==MFT_SEPARATOR && bSeparator)
|
|
{
|
|
DeleteMenu(menu,i,MF_BYPOSITION);
|
|
i--;
|
|
n--;
|
|
}
|
|
bSeparator=(info.fType==MFT_SEPARATOR);
|
|
}
|
|
}
|
|
if (n>0 && bSeparator)
|
|
DeleteMenu(menu,n-1,MF_BYPOSITION);
|
|
}
|
|
|
|
TPMPARAMS params={sizeof(params)}, *pParams=NULL;
|
|
POINT pt2;
|
|
if (pPt)
|
|
pt2=*pPt;
|
|
else
|
|
{
|
|
GetItemRect(index,params.rcExclude);
|
|
MapWindowPoints(NULL,¶ms.rcExclude);
|
|
pt2.x=params.rcExclude.left;
|
|
pt2.y=params.rcExclude.top;
|
|
pParams=¶ms;
|
|
}
|
|
SetContextItem(index);
|
|
InvalidateItem(index);
|
|
KillTimer(TIMER_HOVER);
|
|
res=0;
|
|
if (GetMenuItemCount(menu)>0)
|
|
{
|
|
LOG_MENU(LOG_EXECUTE,L"Open context menu, ptr=%p",this);
|
|
res=TrackPopupMenuEx(menu,TPM_RIGHTBUTTON|TPM_RETURNCMD|TPM_VERTICAL|(IsLanguageRTL()?TPM_LAYOUTRTL:0),pt2.x,pt2.y,m_hWnd,pParams);
|
|
LOG_MENU(LOG_EXECUTE,L"Select context menu, ptr=%p, index=%d",this,res);
|
|
}
|
|
SetContextItem(-1);
|
|
if (m_HotItem<0 && !m_bDestroyed) SetHotItem(index);
|
|
if (m_pMenu2) m_pMenu2.Release();
|
|
if (m_pMenu3) m_pMenu3.Release();
|
|
if (newFolderBmp) DeleteObject(newFolderBmp);
|
|
if (newShortcutBmp) DeleteObject(newShortcutBmp);
|
|
if (shellBmp) DeleteObject(shellBmp);
|
|
}
|
|
|
|
ExitGuard guard; // no returns are allowed until the end cleanup
|
|
if (pData) pData->command=res;
|
|
|
|
|
|
if (type==ACTIVATE_EXECUTE)
|
|
{
|
|
if (bKeepOpen)
|
|
LockSetForegroundWindow(LSFW_LOCK);
|
|
else
|
|
{
|
|
LockSetForegroundWindow(LSFW_UNLOCK);
|
|
FadeOutItem(index);
|
|
}
|
|
PlayMenuSound(SOUND_COMMAND);
|
|
}
|
|
|
|
if (res==CMD_PINSETTING)
|
|
{
|
|
CSearchManager::TItemCategory cat=(CSearchManager::TItemCategory)(item.categoryHash&CSearchManager::CATEGORY_MASK);
|
|
if (cat==CSearchManager::CATEGORY_SETTING)
|
|
CreatePinLink(pItemPidl1,item.name,NULL,0);
|
|
else if (cat==CSearchManager::CATEGORY_METROSETTING)
|
|
CreatePinLink(pItemPidl1,item.name,L"%windir%\\ImmersiveControlPanel\\systemsettings.exe",0);
|
|
m_bRefreshItems=true;
|
|
}
|
|
|
|
// handle our standard commands
|
|
if (item.jumpIndex>=0 && res!=CMD_EXPLORE && res<CMD_LAST && item.id!=MENU_EMPTY)
|
|
{
|
|
const CJumpGroup &group=s_JumpList.groups[LOWORD(item.jumpIndex)];
|
|
const CJumpItem &jumpItem=group.items[HIWORD(item.jumpIndex)];
|
|
if (res==CMD_OPEN)
|
|
{
|
|
ExecuteJumpItem(s_JumpAppInfo,jumpItem,g_OwnerWindow);
|
|
}
|
|
else if (res==CMD_PIN)
|
|
{
|
|
PinJumpItem(s_JumpAppInfo,s_JumpList,LOWORD(item.jumpIndex),HIWORD(item.jumpIndex),group.type!=CJumpGroup::TYPE_PINNED,-1);
|
|
PostRefreshMessage();
|
|
}
|
|
else if (res==CMD_DELETEMRU)
|
|
{
|
|
RemoveJumpItem(s_JumpAppInfo,s_JumpList,LOWORD(item.jumpIndex),HIWORD(item.jumpIndex));
|
|
PostRefreshMessage();
|
|
}
|
|
res=0;
|
|
}
|
|
if (res==CMD_OPEN && item.bMetroLink)
|
|
{
|
|
ExecuteMetroLink(item.pItemInfo);
|
|
if (bTrackRecent)
|
|
AddMRUShortcut(_path);
|
|
g_ItemManager.RemoveNewItem(pItemPidl1,NULL,false);
|
|
if (!(m_Options&CONTAINER_LINK))
|
|
g_SearchManager.AddItemRank(item.nameHash);
|
|
|
|
// close all menus when launching Metro apps
|
|
CloseSubMenus(CLOSE_POST,NULL);
|
|
res=0;
|
|
}
|
|
if (res==CMD_OPEN_ALL)
|
|
{
|
|
SHELLEXECUTEINFO execute={sizeof(execute),SEE_MASK_IDLIST|SEE_MASK_INVOKEIDLIST};
|
|
execute.lpVerb=L"open";
|
|
execute.lpIDList=pItemPidl2;
|
|
execute.nShow=SW_SHOWNORMAL;
|
|
ShellExecuteEx(&execute);
|
|
res=0;
|
|
}
|
|
|
|
if (res==CMD_SORT)
|
|
{
|
|
if (pData && pData->bProgramsTree && m_pProgramsTree)
|
|
{
|
|
m_pProgramsTree->OrderElements(pData->hTreeItem,TreeView_GetParent(m_pProgramsTree->m_hWnd,pData->hTreeItem),std::vector<unsigned int>(),false,true);
|
|
}
|
|
else
|
|
{
|
|
std::vector<SortMenuItem> items;
|
|
for (int i=0;i<m_OriginalCount;i++)
|
|
{
|
|
if (m_Items[i].id==MENU_NO)
|
|
{
|
|
SortMenuItem item(m_Items[i]);
|
|
items.push_back(item);
|
|
}
|
|
}
|
|
std::sort(items.begin(),items.end());
|
|
if (m_Options&CONTAINER_SORTZA)
|
|
std::reverse(items.begin(),items.end());
|
|
SaveItemOrder(items);
|
|
PostRefreshMessage();
|
|
}
|
|
res=0;
|
|
}
|
|
if (res==CMD_MARKOLD)
|
|
{
|
|
if (item.id==MENU_APPS)
|
|
g_ItemManager.RemoveNewItems(false,true);
|
|
else if (item.id==MENU_PROGRAMS)
|
|
{
|
|
g_ItemManager.RemoveNewItems(true,s_bWin7Style && GetWinVersion()>=WIN_VER_WIN8 && GetSettingBool(L"AllProgramsMetro"));
|
|
if (m_pProgramsTree)
|
|
m_pProgramsTree->ClearAllNew();
|
|
}
|
|
else
|
|
g_ItemManager.RemoveNewItem(pItemPidl1,pItemPidl2,item.bFolder);
|
|
PostRefreshMessage();
|
|
}
|
|
if (res==CMD_AUTOSORT)
|
|
{
|
|
if (pData && pData->bProgramsTree)
|
|
{
|
|
m_pProgramsTree->OrderElements(pData->hTreeItem,TreeView_GetParent(m_pProgramsTree->m_hWnd,pData->hTreeItem),std::vector<unsigned int>(),!pData->bAutoSort,true);
|
|
}
|
|
else
|
|
{
|
|
if (m_FolderHash[0])
|
|
{
|
|
CRegKey regOrder;
|
|
if (regOrder.Open(HKEY_CURRENT_USER,L"Software\\OpenShell\\StartMenu\\Order")!=ERROR_SUCCESS)
|
|
regOrder.Create(HKEY_CURRENT_USER,L"Software\\OpenShell\\StartMenu\\Order");
|
|
wchar_t name[100];
|
|
Sprintf(name,_countof(name),L"%08X",m_FolderHash[0]);
|
|
if (m_Options&CONTAINER_AUTOSORT)
|
|
regOrder.SetBinaryValue(name,NULL,0);
|
|
else
|
|
{
|
|
DWORD cAuto='AUTO';
|
|
regOrder.SetBinaryValue(name,&cAuto,4);
|
|
}
|
|
if (m_FolderHash[1])
|
|
{
|
|
Sprintf(name,_countof(name),L"%08X",m_FolderHash[1]);
|
|
if (m_Options&CONTAINER_AUTOSORT)
|
|
regOrder.SetBinaryValue(name,NULL,0);
|
|
else
|
|
{
|
|
DWORD cAuto='AUTO';
|
|
regOrder.SetBinaryValue(name,&cAuto,4);
|
|
}
|
|
}
|
|
}
|
|
PostRefreshMessage();
|
|
}
|
|
res=0;
|
|
}
|
|
|
|
if (res==CMD_NEWFOLDER)
|
|
{
|
|
g_RenameText=item.name;
|
|
if (pPt)
|
|
g_RenamePos=*pPt;
|
|
else
|
|
{
|
|
g_RenamePos.x=item.itemRect.left;
|
|
g_RenamePos.y=item.itemRect.top;
|
|
ClientToScreen(&g_RenamePos);
|
|
}
|
|
bool bAllPrograms=s_bAllPrograms;
|
|
for (std::vector<CMenuContainer*>::iterator it=s_Menus.begin();it!=s_Menus.end();++it)
|
|
(*it)->EnableWindow(FALSE); // disable all menus
|
|
if (bAllPrograms) ::EnableWindow(g_TopWin7Menu,FALSE);
|
|
|
|
CComPtr<IShellFolder> pFolder; // have to use IShellFolder for renaming because it's the only one that supports changing the display name
|
|
if (pItemPidl1)
|
|
{
|
|
PCUITEMID_CHILD pidl;
|
|
SHBindToParent(pItemPidl1,IID_IShellFolder,(void**)&pFolder,&pidl);
|
|
}
|
|
else if (pData && pData->bProgramsTree)
|
|
{
|
|
CComPtr<IShellFolder> pDesktop;
|
|
if (SUCCEEDED(SHGetDesktopFolder(&pDesktop)))
|
|
pDesktop->BindToObject(pData->parent,NULL,IID_IShellFolder,(void**)&pFolder);
|
|
}
|
|
else
|
|
{
|
|
CComPtr<IShellFolder> pDesktop;
|
|
if (SUCCEEDED(SHGetDesktopFolder(&pDesktop)))
|
|
pDesktop->BindToObject(m_Path1[0],NULL,IID_IShellFolder,(void**)&pFolder);
|
|
}
|
|
|
|
if (pFolder)
|
|
{
|
|
CComPtr<IContextMenu> pMenu2;
|
|
HMENU menu2=CreatePopupMenu();
|
|
|
|
std::vector<unsigned int> items;
|
|
{
|
|
CComPtr<IEnumIDList> pEnum;
|
|
if (pFolder->EnumObjects(NULL,SHCONTF_FOLDERS,&pEnum)!=S_OK) pEnum=NULL;
|
|
|
|
PITEMID_CHILD child;
|
|
while (pEnum && pEnum->Next(1,&child,NULL)==S_OK)
|
|
{
|
|
STRRET str;
|
|
if (SUCCEEDED(pFolder->GetDisplayNameOf(child,SHGDN_INFOLDER|SHGDN_FORPARSING,&str)))
|
|
{
|
|
CComString pName;
|
|
StrRetToStr(&str,child,&pName);
|
|
items.push_back(CalcFNVHash(pName));
|
|
}
|
|
ILFree(child);
|
|
}
|
|
}
|
|
|
|
s_bPreventClosing=true;
|
|
if (SUCCEEDED(pFolder->CreateViewObject(g_OwnerWindow,IID_IContextMenu,(void**)&pMenu2)))
|
|
{
|
|
if (SUCCEEDED(pMenu2->QueryContextMenu(menu2,0,1,32767,CMF_NORMAL)))
|
|
{
|
|
CMINVOKECOMMANDINFOEX info={sizeof(info),CMIC_MASK_UNICODE};
|
|
info.lpVerb="NewFolder";
|
|
info.lpVerbW=L"NewFolder";
|
|
info.nShow=SW_SHOWNORMAL;
|
|
info.fMask|=CMIC_MASK_NOASYNC;
|
|
info.hwnd=g_OwnerWindow;
|
|
pMenu2->InvokeCommand((CMINVOKECOMMANDINFO*)&info);
|
|
}
|
|
}
|
|
DestroyMenu(menu2);
|
|
s_bPreventClosing=false;
|
|
|
|
PITEMID_CHILD newPidl=NULL;
|
|
unsigned int newHash=0;
|
|
{
|
|
CComPtr<IEnumIDList> pEnum;
|
|
if (pFolder->EnumObjects(NULL,SHCONTF_FOLDERS,&pEnum)!=S_OK) pEnum=NULL;
|
|
|
|
PITEMID_CHILD child;
|
|
while (pEnum && pEnum->Next(1,&child,NULL)==S_OK)
|
|
{
|
|
STRRET str;
|
|
if (SUCCEEDED(pFolder->GetDisplayNameOf(child,SHGDN_INFOLDER|SHGDN_FORPARSING,&str)))
|
|
{
|
|
CComString pName;
|
|
StrRetToStr(&str,child,&pName);
|
|
unsigned int hash=CalcFNVHash(pName);
|
|
if (std::find(items.begin(),items.end(),hash)==items.end())
|
|
{
|
|
if (SUCCEEDED(pFolder->GetDisplayNameOf(child,SHGDN_INFOLDER|SHGDN_FOREDITING,&str)))
|
|
{
|
|
CComString pName2;
|
|
StrRetToStr(&str,child,&pName2);
|
|
g_RenameText=pName2;
|
|
}
|
|
else
|
|
g_RenameText=pName;
|
|
pName.MakeUpper();
|
|
newHash=CalcFNVHash(pName,item.priority==2?CalcFNVHash(L"\\"):FNV_HASH0);
|
|
newPidl=child;
|
|
break;
|
|
}
|
|
}
|
|
ILFree(child);
|
|
}
|
|
}
|
|
|
|
if (!pData || !pData->bProgramsTree)
|
|
{
|
|
PostRefreshMessage();
|
|
if (!m_bDestroyed)
|
|
PostMessage(MCM_SETCONTEXTITEM,newHash);
|
|
}
|
|
// show the Rename dialog box
|
|
s_bPreventClosing=true;
|
|
if (newPidl && DialogBox(g_Instance,MAKEINTRESOURCE(s_bRTL?IDD_RENAMER:IDD_RENAME),g_OwnerWindow,RenameDlgProc))
|
|
{
|
|
PITEMID_CHILD newPidl2=NULL;
|
|
if (SUCCEEDED(pFolder->SetNameOf(g_OwnerWindow,newPidl,g_RenameText,SHGDN_INFOLDER,&newPidl2)))
|
|
{
|
|
ILFree(newPidl);
|
|
newPidl=newPidl2;
|
|
if (!pData || !pData->bProgramsTree)
|
|
{
|
|
PostRefreshMessage();
|
|
StringUpper(g_RenameText);
|
|
newHash=CalcFNVHash(g_RenameText,item.priority==2?CalcFNVHash(L"\\"):FNV_HASH0);
|
|
if (!m_bDestroyed)
|
|
PostMessage(MCM_SETCONTEXTITEM,newHash);
|
|
}
|
|
}
|
|
}
|
|
if (newPidl && pData && pData->bProgramsTree)
|
|
{
|
|
CComPtr<IShellItem> pNewItem;
|
|
if (SUCCEEDED(SHCreateItemWithParent(NULL,pFolder,newPidl,IID_IShellItem,(void**)&pNewItem)))
|
|
{
|
|
CAbsolutePidl newAbsPidl;
|
|
if (SUCCEEDED(SHGetIDListFromObject(pNewItem,&newAbsPidl)))
|
|
pData->pNewItemInfo=g_ItemManager.GetItemInfo(pNewItem,newAbsPidl,0);
|
|
}
|
|
}
|
|
if (newPidl) ILFree(newPidl);
|
|
for (std::vector<CMenuContainer*>::iterator it=s_Menus.begin();it!=s_Menus.end();++it)
|
|
if (!(*it)->m_bDestroyed)
|
|
(*it)->EnableWindow(TRUE); // enable all menus
|
|
if (bAllPrograms) ::EnableWindow(g_TopWin7Menu,TRUE);
|
|
if (!m_bDestroyed)
|
|
{
|
|
SetForegroundWindow(m_hWnd);
|
|
SetActiveWindow();
|
|
if (pData && pData->bProgramsTree)
|
|
m_pProgramsTree->SetFocus();
|
|
else
|
|
SetFocus();
|
|
Invalidate();
|
|
if (m_HotItem<0) SetHotItem(index);
|
|
}
|
|
s_bPreventClosing=false;
|
|
}
|
|
SetContextItem(-1);
|
|
res=0;
|
|
}
|
|
|
|
if (res==CMD_NEWSHORTCUT)
|
|
{
|
|
wchar_t target[_MAX_PATH+1];
|
|
if (pData && pData->bProgramsTree)
|
|
SHGetPathFromIDList(pData->parent,target);
|
|
else
|
|
SHGetPathFromIDList(m_Path1[0],target);
|
|
target[Strlen(target)+1]=0;
|
|
wchar_t fname[_MAX_PATH+1];
|
|
|
|
// first try in the original folder
|
|
PathMakeUniqueName(fname,_countof(fname)-1,L"scut.lnk",L"New Shortcut.lnk",target);
|
|
HANDLE hFile=CreateFile(fname,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
|
|
if (hFile!=INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(hFile);
|
|
|
|
// just run the shortcut wizard
|
|
wchar_t cmdLine[1024];
|
|
Sprintf(cmdLine,_countof(cmdLine),L"rundll32.exe appwiz.cpl,NewLinkHere %s",fname);
|
|
|
|
STARTUPINFO startupInfo={sizeof(startupInfo)};
|
|
PROCESS_INFORMATION processInfo;
|
|
memset(&processInfo,0,sizeof(processInfo));
|
|
wchar_t exe[_MAX_PATH]=L"%windir%\\system32\\rundll32.exe";
|
|
DoEnvironmentSubst(exe,_countof(exe));
|
|
if (CreateProcess(exe,cmdLine,NULL,NULL,FALSE,0,NULL,target,&startupInfo,&processInfo))
|
|
{
|
|
CloseHandle(processInfo.hThread);
|
|
CloseHandle(processInfo.hProcess);
|
|
}
|
|
}
|
|
else if (GetLastError()==ERROR_ACCESS_DENIED)
|
|
{
|
|
// there was a problem, most likely UAC didn't let us create a folder
|
|
|
|
// create a temp folder just for us
|
|
wchar_t temp[_MAX_PATH];
|
|
GetTempPath(_countof(temp),temp);
|
|
Strcat(temp,_countof(temp),L"OpenShell");
|
|
CreateDirectory(temp,NULL);
|
|
|
|
// make a unique link file and keep a handle to the file
|
|
PathMakeUniqueName(fname,_countof(fname)-1,L"scut.lnk",L"New Shortcut.lnk",temp);
|
|
|
|
HANDLE hFile=CreateFile(fname,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
|
|
if (hFile!=INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(hFile);
|
|
// wait for the wizard to finish in a separate thread and close the menu
|
|
// otherwise it appears behind the menu
|
|
ShortcutParams *pParams=new ShortcutParams;
|
|
memcpy(pParams->target,target,sizeof(target));
|
|
memcpy(pParams->temp,temp,sizeof(temp));
|
|
memcpy(pParams->fname,fname,sizeof(fname));
|
|
CreateThread(NULL,0,NewShortcutThread,pParams,0,NULL);
|
|
}
|
|
}
|
|
res=0;
|
|
}
|
|
|
|
if (res==CMD_DELETEMRU && item.id==MENU_RECENT && s_RecentPrograms!=RECENT_PROGRAMS_NONE)
|
|
{
|
|
if (s_RecentPrograms==RECENT_PROGRAMS_RECENT)
|
|
{
|
|
CComString pName;
|
|
if (_bMetroApp)
|
|
DeleteMRUAppId(_appId);
|
|
else if (SUCCEEDED(pItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,&pName)))
|
|
DeleteMRUShortcut(pName);
|
|
}
|
|
else if (s_RecentPrograms==RECENT_PROGRAMS_FREQUENT)
|
|
{
|
|
RemoveMFUShortcut(item.mfuHash,_bMetroApp);
|
|
}
|
|
PostRefreshMessage();
|
|
res=0;
|
|
}
|
|
if (res==CMD_DELETEALL && item.id==MENU_RECENT && s_RecentPrograms==RECENT_PROGRAMS_RECENT)
|
|
{
|
|
DeleteMRUShortcut(NULL);
|
|
PostRefreshMessage();
|
|
res=0;
|
|
}
|
|
|
|
if (res==CMD_EXPLORE)
|
|
{
|
|
if (item.id==MENU_SEARCH_CATEGORY)
|
|
{
|
|
for (std::list<CSearchManager::SearchCategory>::const_iterator it=s_SearchResults.indexed.begin();it!=s_SearchResults.indexed.end();++it)
|
|
{
|
|
if (item.categoryHash==it->categoryHash)
|
|
{
|
|
FadeOutItem(index);
|
|
PlayMenuSound(SOUND_COMMAND);
|
|
g_SearchManager.LaunchExternalSearch(it->search,it->categoryHash,searchText);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SHOpenFolderAndSelectItems(pItemPidl1,0,NULL,0);
|
|
}
|
|
res=0;
|
|
}
|
|
|
|
if (res==CMD_UNINSTALL)
|
|
{
|
|
UninstallMetroApp(g_OwnerWindow,item.name,_appId);
|
|
res=0;
|
|
}
|
|
|
|
if (item.id==MENU_SEARCH_CATEGORY && res==CMD_TOGGLE)
|
|
{
|
|
m_SearchCategoryHash=(m_SearchCategoryHash==item.categoryHash)?CSearchManager::CATEGORY_INVALID:item.categoryHash;
|
|
RefreshSearch();
|
|
res=0;
|
|
}
|
|
|
|
// handle the shell commands
|
|
if (res>=CMD_LAST)
|
|
{
|
|
// handle special verbs
|
|
char command[256];
|
|
if (FAILED(pMenu->GetCommandString(res-CMD_LAST,GCS_VERBA,NULL,command,_countof(command))))
|
|
command[0]=0;
|
|
if (_stricmp(command,"rename")==0)
|
|
{
|
|
// show the Rename dialog box
|
|
CComPtr<IShellFolder> pFolder; // have to use IShellFolder for renaming because it's the only one that supports changing the display name
|
|
PCUITEMID_CHILD pidl;
|
|
s_bPreventClosing=true;
|
|
STRRET str;
|
|
if (SUCCEEDED(SHBindToParent(pItemPidl1,IID_IShellFolder,(void**)&pFolder,&pidl)) && SUCCEEDED(pFolder->GetDisplayNameOf(pidl,SHGDN_FOREDITING,&str)))
|
|
{
|
|
CComString pName;
|
|
StrRetToStr(&str,pidl,&pName);
|
|
g_RenameText=pName;
|
|
}
|
|
else
|
|
g_RenameText=item.name;
|
|
if (pPt)
|
|
g_RenamePos=*pPt;
|
|
else
|
|
{
|
|
g_RenamePos.x=item.itemRect.left;
|
|
g_RenamePos.y=item.itemRect.top;
|
|
ClientToScreen(&g_RenamePos);
|
|
}
|
|
for (std::vector<CMenuContainer*>::iterator it=s_Menus.begin();it!=s_Menus.end();++it)
|
|
(*it)->EnableWindow(FALSE); // disable all menus
|
|
bool bAllPrograms=s_bAllPrograms;
|
|
if (bAllPrograms) ::EnableWindow(g_TopWin7Menu,FALSE);
|
|
|
|
SetContextItem(index);
|
|
InvalidateItem(index);
|
|
bool bRenamed=DialogBox(g_Instance,MAKEINTRESOURCE(s_bRTL?IDD_RENAMER:IDD_RENAME),g_OwnerWindow,RenameDlgProc)!=0;
|
|
SetContextItem(-1);
|
|
if (m_HotItem<0) SetHotItem(index);
|
|
|
|
if (bRenamed)
|
|
{
|
|
if (GetWinVersion()>=WIN_VER_WIN8)
|
|
{
|
|
SetForegroundWindow(m_hWnd);
|
|
SetActiveWindow();
|
|
if (pData && pData->bProgramsTree)
|
|
m_pProgramsTree->SetFocus();
|
|
else
|
|
SetFocus();
|
|
}
|
|
// perform the rename operation
|
|
PITEMID_CHILD newPidl;
|
|
if (SUCCEEDED(pFolder->SetNameOf(g_OwnerWindow,pidl,g_RenameText,SHGDN_INFOLDER,&newPidl)))
|
|
{
|
|
STRRET str;
|
|
if (SUCCEEDED(pFolder->GetDisplayNameOf(newPidl,SHGDN_INFOLDER|SHGDN_FORPARSING,&str)))
|
|
{
|
|
CComString pName;
|
|
StrRetToStr(&str,newPidl,&pName);
|
|
pName.MakeUpper();
|
|
m_Items[index].name=g_RenameText;
|
|
m_Items[index].nameHash=CalcFNVHash(pName);
|
|
|
|
if (!(m_Options&CONTAINER_AUTOSORT) && (!pData || !pData->bProgramsTree))
|
|
{
|
|
std::vector<SortMenuItem> items;
|
|
for (int i=0;i<m_OriginalCount;i++)
|
|
{
|
|
if (m_Items[i].id==MENU_NO)
|
|
{
|
|
SortMenuItem item(m_Items[i]);
|
|
items.push_back(item);
|
|
}
|
|
}
|
|
SaveItemOrder(items);
|
|
}
|
|
|
|
// win7: if this is a pinned link with implicit app id, make it explicit - otherwise the app resolver will generate a new one
|
|
if (!m_bSubMenu && item.id==MENU_NO && GetWinVersion()<=WIN_VER_WIN7 && !_appId.IsEmpty() && _bIsLink && !_bExplicitAppId && SUCCEEDED(pFolder->GetDisplayNameOf(newPidl,SHGDN_FORPARSING,&str)))
|
|
{
|
|
CComString pPath;
|
|
StrRetToStr(&str,newPidl,&pPath);
|
|
CComPtr<IShellLink> pLink;
|
|
pLink.CoCreateInstance(CLSID_ShellLink);
|
|
CComQIPtr<IPersistFile> pFile(pLink);
|
|
if (pFile && SUCCEEDED(pFile->Load(pPath,STGM_READWRITE)))
|
|
{
|
|
CComQIPtr<IPropertyStore> pStore(pLink);
|
|
if (pStore)
|
|
{
|
|
PROPVARIANT val;
|
|
InitPropVariantFromString(_appId,&val);
|
|
if (SUCCEEDED(pStore->SetValue(PKEY_AppUserModel_ID,val)) && SUCCEEDED(pStore->Commit()))
|
|
pFile->Save(pPath,TRUE);
|
|
PropVariantClear(&val);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pData)
|
|
{
|
|
CComPtr<IShellItem> pNewItem;
|
|
if (SUCCEEDED(SHCreateItemWithParent(NULL,pFolder,newPidl,IID_IShellItem,(void**)&pNewItem)))
|
|
{
|
|
CAbsolutePidl newAbsPidl;
|
|
if (SUCCEEDED(SHGetIDListFromObject(pNewItem,&newAbsPidl)))
|
|
pData->pNewItemInfo=g_ItemManager.GetItemInfo(pNewItem,newAbsPidl,0);
|
|
}
|
|
}
|
|
}
|
|
ILFree(newPidl);
|
|
}
|
|
if (!pData || !pData->bProgramsTree)
|
|
PostRefreshMessage();
|
|
}
|
|
for (std::vector<CMenuContainer*>::iterator it=s_Menus.begin();it!=s_Menus.end();++it)
|
|
if (!(*it)->m_bDestroyed)
|
|
(*it)->EnableWindow(TRUE); // enable all menus
|
|
if (bAllPrograms) ::EnableWindow(g_TopWin7Menu,TRUE);
|
|
if (!m_bDestroyed)
|
|
{
|
|
SetForegroundWindow(m_hWnd);
|
|
SetActiveWindow();
|
|
if (pData && pData->bProgramsTree)
|
|
m_pProgramsTree->SetFocus();
|
|
else
|
|
SetFocus();
|
|
}
|
|
s_bPreventClosing=false;
|
|
s_HotPos=GetMessagePos();
|
|
res=CMD_RENAME;
|
|
}
|
|
else if (_stricmp(command,"uninstall")==0 && _bMetroApp && !_appId.IsEmpty())
|
|
{
|
|
UninstallMetroApp(g_OwnerWindow,item.name,_appId);
|
|
}
|
|
else
|
|
{
|
|
bool bRefreshMain=_stricmp(command,"pin_classic")==0;
|
|
bool bRefresh=(_stricmp(command,"delete")==0 || _stricmp(command,"link")==0);
|
|
|
|
if (item.bStartScreen && _stricmp(command,"pin_classic")==0)
|
|
{
|
|
{
|
|
CSettingsLockWrite lock;
|
|
CSetting *pSetting=FindSetting(L"StartScreenShortcut");
|
|
if (!pSetting->IsLocked())
|
|
{
|
|
pSetting->value=CComVariant(0);
|
|
pSetting->flags&=~CSetting::FLAG_DEFAULT;
|
|
}
|
|
}
|
|
SaveSettings();
|
|
}
|
|
|
|
IContextMenu *pInvokeMenu=pMenu;
|
|
int verbOffset=CMD_LAST;
|
|
if (pSecondaryMenu && res>=secondaryCmd)
|
|
{
|
|
pInvokeMenu=pSecondaryMenu;
|
|
verbOffset=secondaryCmd;
|
|
}
|
|
CMINVOKECOMMANDINFOEX info={sizeof(info),CMIC_MASK_UNICODE|CMIC_MASK_FLAG_LOG_USAGE};
|
|
info.lpVerb=MAKEINTRESOURCEA(res-verbOffset);
|
|
info.lpVerbW=MAKEINTRESOURCEW(res-verbOffset);
|
|
info.nShow=SW_SHOWNORMAL;
|
|
wchar_t dir[_MAX_PATH];
|
|
if (SHGetPathFromIDList(pItemPidl1,dir))
|
|
{
|
|
PathRemoveFileSpec(dir);
|
|
if (GetFileAttributes(dir)!=INVALID_FILE_ATTRIBUTES)
|
|
info.lpDirectoryW=dir;
|
|
}
|
|
if (pPt)
|
|
{
|
|
info.fMask|=CMIC_MASK_PTINVOKE;
|
|
info.ptInvoke=*pPt;
|
|
}
|
|
if (type==ACTIVATE_MENU)
|
|
{
|
|
if (bCtrl) info.fMask|=CMIC_MASK_CONTROL_DOWN;
|
|
if (bShift) info.fMask|=CMIC_MASK_SHIFT_DOWN;
|
|
}
|
|
|
|
if (bRefresh || bRefreshMain)
|
|
info.fMask|=CMIC_MASK_NOASYNC; // wait for delete/link commands to finish so we can refresh the menu
|
|
|
|
s_bPreventClosing=true;
|
|
for (std::vector<CMenuContainer*>::iterator it=s_Menus.begin();it!=s_Menus.end();++it)
|
|
(*it)->EnableWindow(FALSE); // disable all menus
|
|
bool bAllPrograms=s_bAllPrograms;
|
|
if (bAllPrograms) ::EnableWindow(g_TopWin7Menu,FALSE);
|
|
info.hwnd=g_OwnerWindow;
|
|
|
|
RECT rc;
|
|
GetWindowRect(&rc);
|
|
::SetForegroundWindow(g_OwnerWindow);
|
|
::SetWindowPos(g_OwnerWindow,HWND_TOPMOST,rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,0);
|
|
LOG_MENU(LOG_EXECUTE,L"Invoke command, ptr=%p, command='%S'",this,command);
|
|
HRESULT hr=pInvokeMenu->InvokeCommand((LPCMINVOKECOMMANDINFO)&info);
|
|
LOG_MENU(LOG_EXECUTE,L"Invoke command, ptr=%p, res=%d",this,hr);
|
|
if (type==ACTIVATE_EXECUTE && SUCCEEDED(hr))
|
|
{
|
|
if (bTrackRecent)
|
|
{
|
|
if (_bMetroApp)
|
|
AddMRUAppId(_appId);
|
|
else if (_path.IsEmpty())
|
|
{
|
|
CComString pName;
|
|
if (SUCCEEDED(pItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,&pName)))
|
|
AddMRUShortcut(pName);
|
|
}
|
|
else
|
|
AddMRUShortcut(_path);
|
|
}
|
|
g_ItemManager.RemoveNewItem(pItemPidl1,NULL,false);
|
|
if (!(m_Options&CONTAINER_LINK))
|
|
{
|
|
// update item ranks
|
|
CComString pName;
|
|
if (_bMetroApp)
|
|
{
|
|
CString APPID=_appId;
|
|
APPID.MakeUpper();
|
|
g_SearchManager.AddItemRank(CalcFNVHash(APPID));
|
|
}
|
|
else if (SUCCEEDED(pItem->GetDisplayName(SIGDN_PARENTRELATIVEPARSING,&pName))) // can't use item.name because the extension may be removed
|
|
{
|
|
pName.MakeUpper();
|
|
g_SearchManager.AddItemRank(CalcFNVHash(pName));
|
|
}
|
|
}
|
|
}
|
|
for (std::vector<CMenuContainer*>::iterator it=s_Menus.begin();it!=s_Menus.end();++it)
|
|
if (!(*it)->m_bDestroyed)
|
|
(*it)->EnableWindow(TRUE); // enable all menus
|
|
if (bAllPrograms) ::EnableWindow(g_TopWin7Menu,TRUE);
|
|
if (bRefreshMain && m_bSubMenu)
|
|
{
|
|
CMenuContainer *pMain=s_Menus[0];
|
|
if (!pMain->m_bSubMenu && !pMain->m_bDestroyed)
|
|
{
|
|
SetForegroundWindow(pMain->m_hWnd);
|
|
pMain->SetActiveWindow();
|
|
pMain->SetFocus();
|
|
CloseSubMenus(CLOSE_POST,pMain);
|
|
pMain->PostRefreshMessage();
|
|
}
|
|
}
|
|
else if ((bRefresh || bKeepOpen || bRefreshMain) && !m_bDestroyed)
|
|
{
|
|
SetForegroundWindow(m_hWnd);
|
|
SetActiveWindow();
|
|
if (m_Options&CONTAINER_SEARCH)
|
|
{
|
|
m_pParent->m_SearchBox.SetFocus();
|
|
SetWindowPos(HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
|
|
}
|
|
else if (pData && pData->bProgramsTree)
|
|
m_pProgramsTree->SetFocus();
|
|
else
|
|
SetFocus();
|
|
}
|
|
s_bPreventClosing=false;
|
|
|
|
if (!bKeepOpen && !bRefresh && !bRefreshMain)
|
|
{
|
|
HWND active=GetActiveWindow();
|
|
if (active!=m_hWnd && active!=g_OwnerWindow)
|
|
{
|
|
// if after all the window is not active, then another application was launched - close all menus
|
|
CloseSubMenus(CLOSE_POST,NULL);
|
|
if (g_TopWin7Menu && s_bAllPrograms) ::PostMessage(g_TopWin7Menu,WM_CLOSE,0,0);
|
|
}
|
|
}
|
|
if (_stricmp(command,"delete")==0)
|
|
res=CMD_DELETE;
|
|
|
|
if ((bRefresh && (!pData || !pData->bProgramsTree)) || (bRefreshMain && !m_bSubMenu))
|
|
{
|
|
if (bRefreshMain && !m_bSubMenu && (s_MenuMode==MODE_SEARCH || s_MenuMode==MODE_JUMPLIST))
|
|
m_bRefreshItems=true;
|
|
else
|
|
PostRefreshMessage(); // refresh the menu after an item was deleted or created
|
|
}
|
|
}
|
|
}
|
|
DestroyMenu(menu);
|
|
s_HotPos=GetMessagePos();
|
|
if (pData && res) pData->command=res;
|
|
LOG_MENU(LOG_EXECUTE,L"Exit activate, ptr=%p",this);
|
|
guard.Disarm();
|
|
}
|
|
|
|
void CMenuContainer::ActivateTreeItem( const void *treeItem, RECT &itemRect, TActivateType type, const POINT *pPt, ActivateData *pData )
|
|
{
|
|
AddRef(); // prevent the menu from being deleted while processing the operation
|
|
Assert(pData && pData->bProgramsTree);
|
|
const CProgramsTree::CTreeItem *pTreeItem=(CProgramsTree::CTreeItem*)treeItem;
|
|
MenuItem &item=m_Items[m_ProgramTreeIndex];
|
|
item.id=MENU_NO;
|
|
if (pTreeItem->bApps)
|
|
item.id=MENU_APPS;
|
|
else if (pTreeItem->bEmpty)
|
|
item.id=MENU_EMPTY;
|
|
item.name=pTreeItem->name;
|
|
item.pItemInfo=pTreeItem->pItemInfo1;
|
|
RECT rc=item.itemRect;
|
|
item.itemRect=itemRect;
|
|
item.pItem1=pTreeItem->pItemInfo1?(PIDLIST_ABSOLUTE)pTreeItem->pItemInfo1->GetPidl():NULL;
|
|
item.pItem2=pTreeItem->pItemInfo2?(PIDLIST_ABSOLUTE)pTreeItem->pItemInfo2->GetPidl():NULL;
|
|
item.bFolder=pTreeItem->bFolder;
|
|
item.bMetroLink=false;
|
|
item.bMetroApp=false;
|
|
item.bNew=pTreeItem->bNew;
|
|
if (pTreeItem->pItemInfo1)
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
item.bMetroLink=pTreeItem->pItemInfo1->IsMetroLink();
|
|
item.bMetroApp=pTreeItem->pItemInfo1->IsMetroApp();
|
|
}
|
|
pData->bApps=pTreeItem->bApps;
|
|
ActivateItem(m_ProgramTreeIndex,type,pPt,pData);
|
|
item.id=MENU_PROGRAMS_TREE;
|
|
item.itemRect=rc;
|
|
item.name.Empty();
|
|
item.pItemInfo=NULL;
|
|
item.pItem1=NULL;
|
|
item.pItem2=NULL;
|
|
Release();
|
|
}
|
|
|
|
void CMenuContainer::DragTreeItem( const void *treeItem, bool bApp )
|
|
{
|
|
const CProgramsTree::CTreeItem *pTreeItem=(CProgramsTree::CTreeItem*)treeItem;
|
|
MenuItem &item=m_Items[m_ProgramTreeIndex];
|
|
item.id=MENU_NO;
|
|
item.name=pTreeItem->name;
|
|
item.pItemInfo=pTreeItem->pItemInfo1;
|
|
item.pItem2=pTreeItem->pItemInfo2?(PIDLIST_ABSOLUTE)pTreeItem->pItemInfo2->GetPidl():NULL;
|
|
item.bFolder=pTreeItem->bFolder;
|
|
item.bMetroLink=false;
|
|
item.bMetroApp=false;
|
|
if(item.pItemInfo)
|
|
{
|
|
item.pItem1=pTreeItem->pItemInfo1->GetPidl();
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
item.bMetroLink=item.pItemInfo->IsMetroLink();
|
|
item.bMetroApp=item.pItemInfo->IsMetroApp();
|
|
}
|
|
DragOut(m_ProgramTreeIndex,bApp);
|
|
item.id=MENU_PROGRAMS_TREE;
|
|
item.name.Empty();
|
|
item.pItemInfo=NULL;
|
|
item.pItem1=NULL;
|
|
item.pItem2=NULL;
|
|
}
|
|
|
|
void CMenuContainer::RunUserCommand( bool bPicture )
|
|
{
|
|
CString command=GetSettingString(bPicture?L"UserPictureCommand":L"UserNameCommand");
|
|
if (!command.IsEmpty())
|
|
ExecuteCommand(command,false,true);
|
|
}
|
|
|
|
static DWORD WINAPI FaderThreadProc( void *param )
|
|
{
|
|
((CMenuFader*)param)->Create();
|
|
MSG msg;
|
|
while (GetMessage(&msg,NULL,0,0))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void CMenuContainer::FadeOutItem( int index )
|
|
{
|
|
int speed=GetSettingInt(L"MenuFadeSpeed");
|
|
if (speed<=0) return;
|
|
|
|
RECT rc;
|
|
|
|
HBITMAP bmp=NULL;
|
|
HRGN region=NULL;
|
|
if (index==m_ProgramTreeIndex)
|
|
{
|
|
HWND tree=m_pProgramsTree->m_hWnd;
|
|
HTREEITEM hItem=TreeView_GetSelection(tree);
|
|
TreeView_GetItemRect(tree,hItem,&rc,FALSE);
|
|
|
|
BITMAPINFO dib={sizeof(dib)};
|
|
dib.bmiHeader.biWidth=rc.right-rc.left;
|
|
dib.bmiHeader.biHeight=rc.top-rc.bottom;
|
|
dib.bmiHeader.biPlanes=1;
|
|
dib.bmiHeader.biBitCount=32;
|
|
dib.bmiHeader.biCompression=BI_RGB;
|
|
|
|
HDC hdc=CreateCompatibleDC(NULL);
|
|
if (s_bRTL) SetLayout(hdc,LAYOUT_RTL);
|
|
unsigned int *bits;
|
|
bmp=CreateDIBSection(hdc,&dib,DIB_RGB_COLORS,(void**)&bits,NULL,0);
|
|
HGDIOBJ bmp0=SelectObject(hdc,bmp);
|
|
SetViewportOrgEx(hdc,-rc.left,-rc.top,NULL);
|
|
m_pProgramsTree->SendMessage(WM_PRINTCLIENT,(WPARAM)hdc,PRF_CLIENT);
|
|
SelectObject(hdc,bmp0);
|
|
DeleteDC(hdc);
|
|
m_pProgramsTree->MapWindowPoints(NULL,&rc);
|
|
}
|
|
else
|
|
{
|
|
GetItemRect(index,rc);
|
|
BITMAPINFO dib={sizeof(dib)};
|
|
dib.bmiHeader.biWidth=rc.right-rc.left;
|
|
dib.bmiHeader.biHeight=rc.top-rc.bottom;
|
|
dib.bmiHeader.biPlanes=1;
|
|
dib.bmiHeader.biBitCount=32;
|
|
dib.bmiHeader.biCompression=BI_RGB;
|
|
|
|
HDC hdc=CreateCompatibleDC(NULL);
|
|
if (s_bRTL) SetLayout(hdc,LAYOUT_RTL);
|
|
unsigned int *bits;
|
|
bmp=CreateDIBSection(hdc,&dib,DIB_RGB_COLORS,(void**)&bits,NULL,0);
|
|
HGDIOBJ bmp0=SelectObject(hdc,bmp);
|
|
SetViewportOrgEx(hdc,-rc.left,-rc.top,NULL);
|
|
|
|
// create a region from the opaque pixels of the selection bitmap
|
|
MenuSkin::TItemDrawType drawType=m_Items[index].drawType;
|
|
if (drawType==MenuSkin::COLUMN1_NEW)
|
|
drawType=MenuSkin::COLUMN1_ITEM;
|
|
else if (drawType==MenuSkin::COLUMN2_NEW)
|
|
drawType=MenuSkin::COLUMN2_ITEM;
|
|
else if (drawType==MenuSkin::SUBMENU_NEW)
|
|
drawType=MenuSkin::SUBMENU_ITEM;
|
|
const MenuSkin::ItemDrawSettings &settings=s_Skin.ItemSettings[drawType];
|
|
if (settings.bmpSelection.GetBitmap() && settings.bmpSelection.bIs32)
|
|
{
|
|
HDC hdc2=CreateCompatibleDC(hdc);
|
|
SetLayout(hdc2,0);
|
|
HGDIOBJ bmp02=SelectObject(hdc2,settings.bmpSelection.GetBitmap());
|
|
FillRect(hdc,&rc,(HBRUSH)GetStockObject(WHITE_BRUSH));
|
|
RECT rSrc={0,0,settings.selSlicesX[0]+settings.selSlicesX[1]+settings.selSlicesX[2],settings.selSlicesY[0]+settings.selSlicesY[1]+settings.selSlicesY[2]};
|
|
RECT rMargins={settings.selSlicesX[0],settings.selSlicesY[0],settings.selSlicesX[2],settings.selSlicesY[2]};
|
|
if (m_Items[index].id==MENU_SHUTDOWN_BUTTON)
|
|
{
|
|
rSrc.right+=settings.selSlicesX[3]+settings.selSlicesX[4]+settings.selSlicesX[5];
|
|
rMargins.right=settings.selSlicesX[5];
|
|
}
|
|
int w=dib.bmiHeader.biWidth;
|
|
int h=-dib.bmiHeader.biHeight;
|
|
if (rMargins.left>w) rMargins.left=w;
|
|
if (rMargins.right>w) rMargins.right=w;
|
|
if (rMargins.top>h) rMargins.top=h;
|
|
if (rMargins.bottom>h) rMargins.bottom=h;
|
|
MarginsBlit(hdc2,hdc,rSrc,rc,rMargins,false);
|
|
SelectObject(hdc2,bmp02);
|
|
DeleteDC(hdc2);
|
|
SelectObject(hdc,bmp0);
|
|
|
|
for (int y=0;y<h;y++)
|
|
{
|
|
int minx=-1, maxx=-1;
|
|
int yw=y*w;
|
|
for (int x=0;x<w;x++)
|
|
{
|
|
if ((bits[yw+x]>>24)>=32)
|
|
{
|
|
if (minx==-1) minx=x; // first non-transparent pixel
|
|
if (maxx<x) maxx=x; // last non-transparent pixel
|
|
}
|
|
}
|
|
if (minx>=0)
|
|
{
|
|
maxx++;
|
|
HRGN r=CreateRectRgn(minx,y,maxx,y+1);
|
|
AddTrackedObject(r);
|
|
if (!region)
|
|
region=r;
|
|
else
|
|
{
|
|
CombineRgn(region,region,r,RGN_OR);
|
|
DeleteObject(r);
|
|
}
|
|
}
|
|
}
|
|
|
|
SelectObject(hdc,bmp);
|
|
}
|
|
|
|
DrawBackground(hdc,rc);
|
|
|
|
SelectObject(hdc,bmp0);
|
|
DeleteDC(hdc);
|
|
MapWindowPoints(NULL,&rc);
|
|
}
|
|
|
|
if (bmp)
|
|
{
|
|
CMenuFader *pFader=new CMenuFader(bmp,region,speed,rc);
|
|
CreateThread(NULL,0,FaderThreadProc,pFader,0,NULL);
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
CMenuFader::CMenuFader( HBITMAP bmp, HRGN region, int duration, RECT &rect )
|
|
{
|
|
m_Bitmap=bmp;
|
|
m_Region=region;
|
|
m_Duration=duration;
|
|
m_Rect=rect;
|
|
s_Faders.push_back(this);
|
|
}
|
|
|
|
CMenuFader::~CMenuFader( void )
|
|
{
|
|
if (m_Bitmap) DeleteObject(m_Bitmap);
|
|
if (m_Region) DeleteObject(m_Region);
|
|
s_Faders.erase(std::find(s_Faders.begin(),s_Faders.end(),this));
|
|
}
|
|
|
|
void CMenuFader::Create( void )
|
|
{
|
|
bool bRtl=false;
|
|
if (m_Rect.left>m_Rect.right)
|
|
{
|
|
bRtl=true;
|
|
int q=m_Rect.left; m_Rect.left=m_Rect.right; m_Rect.right=q;
|
|
}
|
|
CWindowImpl<CMenuFader>::Create(NULL,&m_Rect,NULL,WS_POPUP,WS_EX_TOOLWINDOW|WS_EX_TOPMOST|WS_EX_LAYERED|(bRtl?WS_EX_LAYOUTRTL:0));
|
|
ShowWindow(SW_SHOWNOACTIVATE);
|
|
if (m_Region)
|
|
{
|
|
SetWindowRgn(m_Region);
|
|
m_Region=NULL;
|
|
}
|
|
SetTimer(1,20);
|
|
m_Time0=0;
|
|
m_LastTime=0;
|
|
PostMessage(WM_TIMER,0,0);
|
|
SetLayeredWindowAttributes(m_hWnd,0,255,LWA_ALPHA);
|
|
}
|
|
|
|
LRESULT CMenuFader::OnEraseBkgnd( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
RECT rc;
|
|
GetClientRect(&rc);
|
|
HDC hdc=(HDC)wParam;
|
|
|
|
// draw the background
|
|
HDC hdc2=CreateCompatibleDC(hdc);
|
|
HGDIOBJ bmp0=SelectObject(hdc2,m_Bitmap);
|
|
BitBlt(hdc,0,0,rc.right,rc.bottom,hdc2,0,0,SRCCOPY);
|
|
SelectObject(hdc2,bmp0);
|
|
DeleteDC(hdc2);
|
|
return 1;
|
|
}
|
|
|
|
LRESULT CMenuFader::OnTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (m_Time0==0)
|
|
m_Time0=GetMessageTime();
|
|
int t=GetMessageTime()-m_Time0;
|
|
const int MAX_DELTA=80; // allow at most 80ms between redraws. if more, slow down time
|
|
if (t>MAX_DELTA+m_LastTime)
|
|
{
|
|
m_Time0+=t-MAX_DELTA-m_LastTime;
|
|
t=MAX_DELTA+m_LastTime;
|
|
}
|
|
m_LastTime=t;
|
|
if (t<m_Duration)
|
|
{
|
|
SetLayeredWindowAttributes(m_hWnd,0,(m_Duration-t)*255/m_Duration,LWA_ALPHA);
|
|
RedrawWindow();
|
|
}
|
|
else
|
|
{
|
|
KillTimer(1);
|
|
PostMessage(WM_CLOSE);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void CMenuFader::ClearAll( void )
|
|
{
|
|
while (!s_Faders.empty())
|
|
s_Faders[0]->SendMessage(WM_CLOSE);
|
|
}
|