mirror of
https://github.com/Open-Shell/Open-Shell-Menu.git
synced 2026-04-12 01:47:24 +10:00
(Modern) Settings are just more and more important in Windows 10. So it makes sense to show their search results first. Fixes #481.
9199 lines
267 KiB
C++
9199 lines
267 KiB
C++
// 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
|
|
|
|
// MenuContainer.cpp - contains the main logic of CMenuContainer
|
|
|
|
#include "stdafx.h"
|
|
#include "MenuContainer.h"
|
|
#include "Accessibility.h"
|
|
#include "StartMenuDLL.h"
|
|
#include "StartButton.h"
|
|
#include "Settings.h"
|
|
#include "Translations.h"
|
|
#include "CustomMenu.h"
|
|
#include "LogManager.h"
|
|
#include "FNVHash.h"
|
|
#include "ResourceHelper.h"
|
|
#include "SettingsUIHelper.h"
|
|
#include "DownloadHelper.h"
|
|
#include "SettingsUI.h"
|
|
#include "MetroLinkManager.h"
|
|
#include "ProgramsTree.h"
|
|
#include "dllmain.h"
|
|
#include "resource.h"
|
|
#include <uxtheme.h>
|
|
#include <vsstyle.h>
|
|
#include <vssym32.h>
|
|
#include <WtsApi32.h>
|
|
#include <Lm.h>
|
|
#include <Dsgetdc.h>
|
|
#include <PowrProf.h>
|
|
#include <dwmapi.h>
|
|
#include <propkey.h>
|
|
#define SECURITY_WIN32
|
|
#include <Security.h>
|
|
#include <algorithm>
|
|
#include <wuapi.h>
|
|
|
|
struct StdMenuOption
|
|
{
|
|
TMenuID id;
|
|
int options;
|
|
};
|
|
|
|
// Options for special menu items
|
|
enum
|
|
{
|
|
MENU_NONE = 0,
|
|
MENU_ENABLED = 1, // the item shows in the menu
|
|
MENU_EXPANDED = 2, // the item is expanded
|
|
};
|
|
|
|
static StdMenuOption g_StdOptions[]=
|
|
{
|
|
{MENU_COMPUTER,MENU_NONE}, // MENU_ENABLED|MENU_EXPANDED from settings
|
|
{MENU_FAVORITES,MENU_NONE}, // MENU_ENABLED|MENU_EXPANDED from settings, check policy
|
|
{MENU_DOCUMENTS,MENU_NONE}, // MENU_ENABLED|MENU_EXPANDED from settings, check policy
|
|
{MENU_HELP,MENU_ENABLED}, // check policy
|
|
{MENU_RUN,MENU_ENABLED}, // check policy
|
|
{MENU_LOGOFF,MENU_ENABLED}, // MENU_ENABLED from settings, check policy
|
|
{MENU_RESTART,MENU_ENABLED}, // MENU_ENABLED
|
|
{MENU_RESTART_NOUPDATE,MENU_ENABLED}, // only available when there are updates
|
|
{MENU_DISCONNECT,MENU_NONE}, // MENU_ENABLED if in a remote session, check policy
|
|
{MENU_SHUTDOWN_BOX,MENU_ENABLED}, // MENU_NONE if in a remote session, check policy
|
|
{MENU_SHUTDOWN_BUTTON,MENU_ENABLED|MENU_EXPANDED}, // MENU_ENABLED|MENU_EXPANDED from the settings
|
|
{MENU_SHUTDOWN,MENU_ENABLED}, // MENU_NONE if in a remote session, check policy
|
|
{MENU_SHUTDOWN_NOUPDATE,MENU_ENABLED}, // only available when there are updates
|
|
{MENU_UNDOCK,MENU_ENABLED}, // from settings, check policy
|
|
{MENU_CONTROLPANEL,MENU_ENABLED|MENU_EXPANDED}, // MENU_EXPANDED from settings, check policy
|
|
{MENU_NETWORK,MENU_ENABLED}, // MENU_EXPANDED from settings, check policy
|
|
{MENU_SECURITY,MENU_ENABLED}, // MENU_ENABLED if in a remote session
|
|
{MENU_PRINTERS,MENU_ENABLED}, // MENU_EXPANDED from settings, check policy
|
|
{MENU_TASKBAR,MENU_ENABLED}, // check policy
|
|
{MENU_FEATURES,MENU_ENABLED}, // no setting (prevents the Programs and Features from expanding), check policy (for control panel)
|
|
{MENU_CLASSIC_SETTINGS,MENU_ENABLED}, // MENU_ENABLED from ini file
|
|
{MENU_SEARCH,MENU_ENABLED}, // check policy
|
|
{MENU_SEARCH_BOX,MENU_NONE}, // check settings
|
|
{MENU_SEARCH_PRINTER,MENU_NONE}, // MENU_ENABLED if Active Directory is available
|
|
{MENU_SEARCH_COMPUTERS,MENU_NONE}, // MENU_ENABLED if Active Directory is available, check policy
|
|
{MENU_SEARCH_PEOPLE,MENU_NONE}, // MENU_ENABLED if %ProgramFiles%\Windows Mail\wab.exe exists
|
|
{MENU_USERFILES,MENU_ENABLED}, // check policy
|
|
{MENU_USERDOCUMENTS,MENU_ENABLED}, // check policy
|
|
{MENU_USERPICTURES,MENU_ENABLED}, // check policy
|
|
{MENU_SLEEP,MENU_ENABLED}, // check power caps
|
|
{MENU_HIBERNATE,MENU_ENABLED}, // check power caps
|
|
{MENU_LOCK,MENU_ENABLED}, // check power settings
|
|
{MENU_SWITCHUSER,MENU_ENABLED}, // check group policy
|
|
{MENU_APPS,MENU_ENABLED}, // enable on Win8+
|
|
{MENU_PCSETTINGS,MENU_ENABLED}, // enable on Win8+
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CUserWindow::Init( CMenuContainer *pOwner )
|
|
{
|
|
const MenuSkin &skin=CMenuContainer::s_Skin;
|
|
m_pOwner=pOwner;
|
|
m_Size=skin.User_bitmapSize;
|
|
BITMAPINFO bi={0};
|
|
bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
|
|
bi.bmiHeader.biWidth=m_Size.cx;
|
|
bi.bmiHeader.biHeight=m_Size.cy;
|
|
bi.bmiHeader.biPlanes=1;
|
|
bi.bmiHeader.biBitCount=32;
|
|
HDC hdc=CreateCompatibleDC(NULL);
|
|
m_Bitmap=CreateDIBSection(hdc,&bi,DIB_RGB_COLORS,(void**)&m_Bits,NULL,0);
|
|
DeleteDC(hdc);
|
|
memset(m_Bits,0,m_Size.cx*m_Size.cy*4);
|
|
m_Source.resize(m_Size.cx*m_Size.cy*2);
|
|
m_bUserBitmapMask=(skin.User_mask.bIsBitmap && skin.User_mask.bIs32 && skin.User_maskSize.cx==skin.User_image_size && skin.User_maskSize.cy==skin.User_image_size);
|
|
if (m_bUserBitmapMask)
|
|
m_UserBitmap=CMenuContainer::LoadUserImage(skin.User_image_size,skin.User_mask.GetBitmap());
|
|
else
|
|
m_UserBitmap=CMenuContainer::LoadUserImage(skin.User_image_size,NULL);
|
|
m_TimerBitmap=(HBITMAP)1;
|
|
SetImage(NULL,false);
|
|
}
|
|
|
|
void CUserWindow::StartImageTimer( HBITMAP bmp )
|
|
{
|
|
if (m_TimerBitmap==bmp) return;
|
|
m_TimerBitmap=bmp;
|
|
DWORD time;
|
|
SystemParametersInfo(SPI_GETMOUSEHOVERTIME,NULL,&time,0);
|
|
SetTimer(TIMER_SET,time);
|
|
}
|
|
|
|
void CUserWindow::SetImage( HBITMAP bmp, bool bAnimate )
|
|
{
|
|
m_bDefaultImage=!bmp;
|
|
EnableWindow(m_bDefaultImage);
|
|
int size=m_Size.cx*m_Size.cy;
|
|
memcpy(&m_Source[0],m_Bits,size*4);
|
|
|
|
HDC hdst=CreateCompatibleDC(NULL);
|
|
RECT rc={0,0,m_Size.cx,m_Size.cy};
|
|
HGDIOBJ bmp0=SelectObject(hdst,m_Bitmap);
|
|
FillRect(hdst,&rc,(HBRUSH)GetStockObject(BLACK_BRUSH));
|
|
HDC hsrc=CreateCompatibleDC(NULL);
|
|
HGDIOBJ bmp01=GetCurrentObject(hsrc,OBJ_BITMAP);
|
|
int iconSize=bmp?CItemManager::EXTRA_LARGE_ICON_SIZE:CMenuContainer::s_Skin.User_image_size;
|
|
if (bmp)
|
|
{
|
|
SelectObject(hsrc,bmp);
|
|
BitBlt(hdst,(m_Size.cx-iconSize)/2,(m_Size.cy-iconSize)/2,iconSize,iconSize,hsrc,0,0,SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
if (m_UserBitmap)
|
|
{
|
|
SelectObject(hsrc,m_UserBitmap);
|
|
BitBlt(hdst,CMenuContainer::s_Skin.User_image_offset.x,CMenuContainer::s_Skin.User_image_offset.y,iconSize,iconSize,hsrc,0,0,SRCCOPY);
|
|
}
|
|
if (CMenuContainer::s_Skin.User_bitmap.GetBitmap())
|
|
{
|
|
SelectObject(hsrc,CMenuContainer::s_Skin.User_bitmap.GetBitmap());
|
|
BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
|
|
AlphaBlend(hdst,0,0,m_Size.cx,m_Size.cy,hsrc,0,0,m_Size.cx,m_Size.cy,func);
|
|
}
|
|
}
|
|
SelectObject(hsrc,bmp01);
|
|
DeleteDC(hsrc);
|
|
SelectObject(hdst,bmp0);
|
|
DeleteDC(hdst);
|
|
|
|
memcpy(&m_Source[size],m_Bits,size*4);
|
|
if (!bmp && !m_bUserBitmapMask)
|
|
{
|
|
int dx=CMenuContainer::s_Skin.User_image_offset.x;
|
|
int dy=m_Size.cy-CMenuContainer::s_Skin.User_image_offset.y-1;
|
|
for (int y=0;y<iconSize;y++)
|
|
for (int x=0;x<iconSize;x++)
|
|
m_Source[size+(dy-y)*m_Size.cx+x+dx]|=0xFF000000;
|
|
}
|
|
if (bAnimate)
|
|
{
|
|
m_Timer=0;
|
|
SetTimer(TIMER_BLEND,15);
|
|
}
|
|
else
|
|
{
|
|
memcpy(m_Bits,&m_Source[size],size*4);
|
|
Update();
|
|
}
|
|
}
|
|
|
|
void CUserWindow::Update( int alpha )
|
|
{
|
|
BLENDFUNCTION func={AC_SRC_OVER,0,(BYTE)alpha,AC_SRC_ALPHA};
|
|
|
|
HDC hSrc=CreateCompatibleDC(NULL);
|
|
HGDIOBJ bmp0=SelectObject(hSrc,m_Bitmap);
|
|
POINT srcPos={0,0};
|
|
UpdateLayeredWindow(m_hWnd,NULL,NULL,&m_Size,hSrc,&srcPos,0,&func,ULW_ALPHA);
|
|
SelectObject(hSrc,bmp0);
|
|
DeleteDC(hSrc);
|
|
}
|
|
|
|
void CUserWindow::UpdatePartial( POINT pos, const RECT *pClipRect )
|
|
{
|
|
BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
|
|
|
|
SIZE size=m_Size;
|
|
POINT srcPos={0,0};
|
|
if (pClipRect)
|
|
{
|
|
if (pos.x<pClipRect->left)
|
|
{
|
|
int dx=pClipRect->left-pos.x;
|
|
pos.x+=dx;
|
|
size.cx-=dx;
|
|
srcPos.x+=dx;
|
|
}
|
|
if (pos.x+size.cx>pClipRect->right)
|
|
size.cx=pClipRect->right-pos.x;
|
|
|
|
if (pos.y<pClipRect->top)
|
|
{
|
|
int dy=pClipRect->top-pos.y;
|
|
pos.y+=dy;
|
|
size.cy-=dy;
|
|
srcPos.y+=dy;
|
|
}
|
|
if (pos.y+size.cy>pClipRect->bottom)
|
|
size.cy=pClipRect->bottom-pos.y;
|
|
}
|
|
if (size.cx<0) size.cx=0;
|
|
if (size.cy<0) size.cy=0;
|
|
|
|
HDC hSrc=CreateCompatibleDC(NULL);
|
|
HGDIOBJ bmp0=SelectObject(hSrc,m_Bitmap);
|
|
UpdateLayeredWindow(m_hWnd,NULL,&pos,&size,hSrc,&srcPos,0,&func,ULW_ALPHA);
|
|
SelectObject(hSrc,bmp0);
|
|
DeleteDC(hSrc);
|
|
}
|
|
|
|
LRESULT CUserWindow::OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (m_Bitmap) DeleteObject(m_Bitmap);
|
|
m_Bitmap=NULL;
|
|
if (m_UserBitmap) DeleteObject(m_UserBitmap);
|
|
m_UserBitmap=NULL;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CUserWindow::OnLButtonDown( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (m_bDefaultImage)
|
|
m_pOwner->RunUserCommand(true);
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CUserWindow::OnSetCursor( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (m_bDefaultImage)
|
|
SetCursor(LoadCursor(NULL,IDC_HAND));
|
|
else
|
|
bHandled=FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
LRESULT CUserWindow::OnTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
const int BLEND_STEP=5;
|
|
if (wParam==TIMER_BLEND)
|
|
{
|
|
m_Timer+=BLEND_STEP;
|
|
if (m_Timer>100) m_Timer=100;
|
|
|
|
// blend the two images
|
|
int n=m_Size.cx*m_Size.cy;
|
|
for (int i=0;i<n;i++)
|
|
{
|
|
unsigned int pixel1=m_Source[i];
|
|
unsigned int pixel2=m_Source[i+n];
|
|
int a1=(pixel1>>24);
|
|
int r1=(pixel1>>16)&255;
|
|
int g1=(pixel1>>8)&255;
|
|
int b1=(pixel1)&255;
|
|
int a2=(pixel2>>24);
|
|
int r2=(pixel2>>16)&255;
|
|
int g2=(pixel2>>8)&255;
|
|
int b2=(pixel2)&255;
|
|
int a=a1+(a2-a1)*m_Timer/100;
|
|
int r=r1+(r2-r1)*m_Timer/100;
|
|
int g=g1+(g2-g1)*m_Timer/100;
|
|
int b=b1+(b2-b1)*m_Timer/100;
|
|
m_Bits[i]=(a<<24)|(r<<16)|(g<<8)|b;
|
|
}
|
|
|
|
Update();
|
|
if (m_Timer==100)
|
|
KillTimer(TIMER_BLEND);
|
|
}
|
|
if (wParam==TIMER_SET)
|
|
{
|
|
SetImage(m_TimerBitmap,true);
|
|
m_TimerBitmap=(HBITMAP)1;
|
|
KillTimer(TIMER_SET);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
int CMenuContainer::s_MaxRecentDocuments=15;
|
|
int CMenuContainer::s_ScrollMenus=0;
|
|
bool CMenuContainer::s_bRTL=false;
|
|
bool CMenuContainer::s_bKeyboardCues=false;
|
|
bool CMenuContainer::s_bOverrideFirstDown=false;
|
|
bool CMenuContainer::s_bExpandRight=true;
|
|
TRecentPrograms CMenuContainer::s_RecentPrograms=RECENT_PROGRAMS_NONE;
|
|
bool CMenuContainer::s_bBehindTaskbar=true;
|
|
bool CMenuContainer::s_bShowTopEmpty=false;
|
|
bool CMenuContainer::s_bNoDragDrop=false;
|
|
bool CMenuContainer::s_bNoContextMenu=false;
|
|
bool CMenuContainer::s_bExpandLinks=false;
|
|
bool CMenuContainer::s_bLogicalSort=false;
|
|
bool CMenuContainer::s_bExtensionSort=false;
|
|
bool CMenuContainer::s_bAllPrograms=false;
|
|
bool CMenuContainer::s_bNoCommonFolders=false;
|
|
bool CMenuContainer::s_bNoRun=false;
|
|
bool CMenuContainer::s_bNoClose=false;
|
|
bool CMenuContainer::s_bHasTouch=false;
|
|
char CMenuContainer::s_bActiveDirectory=-1;
|
|
bool CMenuContainer::s_bPreventClosing=false;
|
|
bool CMenuContainer::s_bDragClosed=false;
|
|
bool CMenuContainer::s_bTempHidden=false;
|
|
bool CMenuContainer::s_bDisableHover=false;
|
|
bool CMenuContainer::s_bHasUpdates=false;
|
|
CMenuContainer *CMenuContainer::s_pDragSource=NULL;
|
|
bool CMenuContainer::s_bDragFromTree;
|
|
bool CMenuContainer::s_bDragMovable;
|
|
bool CMenuContainer::s_bRightDrag;
|
|
bool CMenuContainer::s_bLockWorkArea;
|
|
bool CMenuContainer::s_bPendingSearchEnter;
|
|
std::vector<CMenuContainer*> CMenuContainer::s_Menus;
|
|
volatile HWND CMenuContainer::s_FirstMenu, CMenuContainer::s_SearchMenu;
|
|
CSearchManager::SearchResults CMenuContainer::s_SearchResults;
|
|
std::map<unsigned int,int> CMenuContainer::s_MenuScrolls;
|
|
CString CMenuContainer::s_MRUShortcuts[MRU_PROGRAMS_COUNT];
|
|
bool CMenuContainer::s_bMRULoaded=false;
|
|
const CItemManager::ItemInfo *CMenuContainer::s_JumpAppInfo;
|
|
CJumpList CMenuContainer::s_JumpList;
|
|
int CMenuContainer::s_TaskBarId;
|
|
HWND CMenuContainer::s_TaskBar, CMenuContainer::s_StartButton;
|
|
UINT CMenuContainer::s_TaskBarEdge;
|
|
RECT CMenuContainer::s_StartRect;
|
|
HWND CMenuContainer::s_LastFGWindow;
|
|
HTHEME CMenuContainer::s_Theme;
|
|
HTHEME CMenuContainer::s_PagerTheme;
|
|
CWindow CMenuContainer::s_Tooltip;
|
|
CWindow CMenuContainer::s_TooltipBalloon;
|
|
int CMenuContainer::s_TipShowTime;
|
|
int CMenuContainer::s_TipHideTime;
|
|
int CMenuContainer::s_TipShowTimeFolder;
|
|
int CMenuContainer::s_TipHideTimeFolder;
|
|
DWORD CMenuContainer::s_HotPos;
|
|
int CMenuContainer::s_HotItem;
|
|
CMenuContainer *CMenuContainer::s_pHotMenu;
|
|
int CMenuContainer::s_TipItem;
|
|
CMenuContainer *CMenuContainer::s_pTipMenu;
|
|
RECT CMenuContainer::s_MenuLimits;
|
|
RECT CMenuContainer::s_MainMenuLimits;
|
|
DWORD CMenuContainer::s_TaskbarState;
|
|
DWORD CMenuContainer::s_HoverTime;
|
|
DWORD CMenuContainer::s_SplitHoverTime;
|
|
DWORD CMenuContainer::s_ProgramsHoverTime;
|
|
DWORD CMenuContainer::s_XMouse;
|
|
DWORD CMenuContainer::s_SubmenuStyle;
|
|
CLIPFORMAT CMenuContainer::s_ShellFormat;
|
|
CLIPFORMAT CMenuContainer::s_ShellUrlFormat;
|
|
CLIPFORMAT CMenuContainer::s_DescriptorFormat;
|
|
CLIPFORMAT CMenuContainer::s_ContentsFormat;
|
|
CLIPFORMAT CMenuContainer::s_MetroLinkFormat;
|
|
CLIPFORMAT CMenuContainer::s_PreferredEffectFormat;
|
|
CLIPFORMAT CMenuContainer::s_DropDescriptionFormat;
|
|
MenuSkin CMenuContainer::s_Skin;
|
|
CMenuContainer::StartMenuParams CMenuContainer::s_StartMenuParams;
|
|
UINT CMenuContainer::s_StartMenuMsg;
|
|
std::vector<CMenuFader*> CMenuFader::s_Faders;
|
|
bool CMenuContainer::s_bWin7Style;
|
|
CMenuContainer::TMenuMode CMenuContainer::s_MenuMode;
|
|
CMenuContainer::TMenuMode CMenuContainer::s_PreSearchMenuMode;
|
|
TMenuID CMenuContainer::s_ShutdownCommand;
|
|
int CMenuContainer::s_MenuHeight;
|
|
int CMenuContainer::s_MenuMaxHeight[2];
|
|
int CMenuContainer::s_MenuWidthNormal;
|
|
int CMenuContainer::s_MenuWidthJump;
|
|
int CMenuContainer::s_MenuWidthMax;
|
|
int CMenuContainer::s_BackgroundW1, CMenuContainer::s_BackgroundW2, CMenuContainer::s_BackgroundH1, CMenuContainer::s_BackgroundH2;
|
|
CMenuContainer::OldMenuState CMenuContainer::s_OldMenuState;
|
|
CUserWindow CMenuContainer::s_UserPicture;
|
|
RECT CMenuContainer::s_UserPictureRect;
|
|
int CMenuContainer::s_ProgramsScrollPos;
|
|
HBITMAP CMenuContainer::s_ArrowsBitmap;
|
|
unsigned int CMenuContainer::s_LastArrowColor;
|
|
char CMenuContainer::s_HasMoreResults;
|
|
int CMenuContainer::s_ProgramsWidth, CMenuContainer::s_JumplistWidth;
|
|
CComPtr<IFrameworkInputPane> CMenuContainer::s_pFrameworkInputPane;
|
|
CString CMenuContainer::s_PinFolder;
|
|
|
|
LRESULT CALLBACK CMenuContainer::SubclassSearchBox( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
|
|
{
|
|
CMenuContainer *pParent=(CMenuContainer*)uIdSubclass;
|
|
CWindow box(hWnd);
|
|
if (uMsg==WM_PAINT && !pParent->m_bNoSearchDraw)
|
|
{
|
|
// use buffered paint to allow the edit box to appear on a glass background
|
|
pParent->m_bNoSearchDraw=true;
|
|
|
|
PAINTSTRUCT ps;
|
|
HDC hdc=box.BeginPaint(&ps);
|
|
|
|
BP_PAINTPARAMS paintParams={sizeof(paintParams)};
|
|
HDC hdcPaint=NULL;
|
|
HPAINTBUFFER hBufferedPaint=BeginBufferedPaint(hdc,&ps.rcPaint,BPBF_TOPDOWNDIB,&paintParams,&hdcPaint);
|
|
if (hdcPaint)
|
|
{
|
|
SendMessage(hWnd,WM_PRINTCLIENT,(WPARAM)hdcPaint,PRF_CLIENT);
|
|
BufferedPaintSetAlpha(hBufferedPaint,&ps.rcPaint,255);
|
|
EndBufferedPaint(hBufferedPaint,TRUE);
|
|
}
|
|
box.EndPaint(&ps);
|
|
|
|
pParent->m_bSearchDrawn=true;
|
|
pParent->m_bNoSearchDraw=false;
|
|
return 0;
|
|
}
|
|
if (uMsg==WM_PRINTCLIENT)
|
|
{
|
|
LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
HDC hdc=(HDC)wParam;
|
|
if ((lParam&PRF_CLIENT) && ::GetWindowTextLength(hWnd)==0 && ((GetSettingInt(L"SearchBox")==SEARCHBOX_NORMAL && GetSettingBool(L"SearchSelect")) || GetFocus()!=hWnd) && pParent->m_SearchIndex>=0)
|
|
{
|
|
RECT rc;
|
|
::SendMessage(hWnd,EM_GETRECT,0,(LPARAM)&rc);
|
|
if (s_bRTL)
|
|
rc.right-=3;
|
|
else
|
|
rc.left+=3;
|
|
HGDIOBJ font0=SelectObject(hdc,s_Skin.Search_hint_font);
|
|
SetBkColor(hdc,GetSysColor(COLOR_WINDOW));
|
|
SetBkMode(hdc,TRANSPARENT);
|
|
SetTextColor(hdc,s_Skin.Search_text_colors[1]);
|
|
DrawText(hdc,pParent->m_Items[pParent->m_SearchIndex].name,-1,&rc,DT_SINGLELINE|DT_EDITCONTROL|(s_bRTL?DT_RIGHT:DT_LEFT));
|
|
SelectObject(hdc,font0);
|
|
}
|
|
return res;
|
|
}
|
|
if (uMsg==WM_KEYDOWN)
|
|
{
|
|
if (wParam==VK_TAB)
|
|
{
|
|
s_bPendingSearchEnter=false;
|
|
// forward Tabs to the parent
|
|
return pParent->SendMessage(uMsg,wParam,lParam);
|
|
}
|
|
if (wParam==VK_UP || wParam==VK_DOWN)
|
|
{
|
|
s_bPendingSearchEnter=false;
|
|
// forward up/down keys
|
|
CMenuContainer *pSearchMenu=s_Menus[s_Menus.size()-1];
|
|
if (pSearchMenu->m_Options&CONTAINER_SEARCH)
|
|
return pSearchMenu->SendMessage(uMsg,wParam,lParam); // forward to the search menu
|
|
else
|
|
return pParent->SendMessage(uMsg,wParam,lParam); // forward to the parent
|
|
}
|
|
if (wParam==VK_PRIOR || wParam==VK_NEXT)
|
|
{
|
|
s_bPendingSearchEnter=false;
|
|
// forward page keys
|
|
CMenuContainer *pSearchMenu=s_Menus[s_Menus.size()-1];
|
|
if (pSearchMenu->m_Options&CONTAINER_SEARCH)
|
|
return pSearchMenu->SendMessage(uMsg,wParam,lParam); // forward to the search menu
|
|
else
|
|
return pParent->SendMessage(uMsg,wParam,lParam); // forward to the parent
|
|
}
|
|
if (wParam==VK_LEFT || wParam==VK_RIGHT)
|
|
{
|
|
// forward left/right keys
|
|
if (::GetWindowTextLength(hWnd)==0)
|
|
return pParent->SendMessage(uMsg,wParam,lParam); // forward to the parent
|
|
}
|
|
if (wParam==VK_RETURN)
|
|
{
|
|
// forward Enter to the submenu, or execute the current string
|
|
CMenuContainer *pSearchMenu=s_Menus[s_Menus.size()-1];
|
|
bool bShift=GetKeyState(VK_SHIFT)<0;
|
|
bool bCtrl=GetKeyState(VK_CONTROL)<0;
|
|
if ((pSearchMenu->m_Options&CONTAINER_SEARCH) || (!pSearchMenu->m_bSubMenu && s_MenuMode==MODE_SEARCH))
|
|
{
|
|
if (pSearchMenu->m_HotItem>=0 && pSearchMenu->m_HotItem<(int)pSearchMenu->m_Items.size() &&
|
|
pSearchMenu->m_Items[pSearchMenu->m_HotItem].id!=MENU_EMPTY && pSearchMenu->m_Items[pSearchMenu->m_HotItem].id!=MENU_SEARCH_EMPTY)
|
|
{
|
|
pSearchMenu->SendMessage(WM_KEYDOWN,VK_RETURN);
|
|
}
|
|
else if (!s_bNoRun && (!s_SearchResults.bSearching || s_SearchResults.bResults))
|
|
{
|
|
CString command;
|
|
CWindow(hWnd).GetWindowText(command);
|
|
if (!command.IsEmpty())
|
|
pSearchMenu->ExecuteCommand(command,bShift && bCtrl,true);
|
|
}
|
|
else if (s_SearchResults.bSearching && !s_SearchResults.bResults)
|
|
{
|
|
s_bPendingSearchEnter=true;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
if (wParam==VK_ESCAPE)
|
|
{
|
|
s_bPendingSearchEnter=false;
|
|
// forward Esc to the parent or clear the string
|
|
if (box.GetWindowTextLength()==0)
|
|
pParent->PostMessage(WM_KEYDOWN,VK_ESCAPE);
|
|
else
|
|
box.SetWindowText(L"");
|
|
return 0;
|
|
}
|
|
if (wParam==VK_BACK && GetKeyState(VK_CONTROL)<0)
|
|
{
|
|
wchar_t text[1024];
|
|
::GetWindowText(hWnd,text,_countof(text));
|
|
int len=Strlen(text);
|
|
int pos=(int)::SendMessage(hWnd,EM_GETSEL,0,0);
|
|
if (LOWORD(pos)==HIWORD(pos))
|
|
{
|
|
pos=LOWORD(pos);
|
|
if (pos>len) pos=len;
|
|
int start=0;
|
|
for (int i=0;i<pos;i++)
|
|
{
|
|
if (i>0 && (text[i-1]==' ' || text[i-1]=='\\') && text[i]!=text[i-1])
|
|
start=i;
|
|
}
|
|
pos=MAKELONG(start,pos);
|
|
}
|
|
int start=LOWORD(pos);
|
|
int end=HIWORD(pos);
|
|
if (start>len) start=len;
|
|
if (end>len) end=len;
|
|
memmove(text+start,text+end,(len-end+1)*2);
|
|
::SetWindowText(hWnd,text);
|
|
::SendMessage(hWnd,EM_SETSEL,start,start);
|
|
return 0;
|
|
}
|
|
}
|
|
if (uMsg==WM_SYSCHAR)
|
|
{
|
|
CMenuContainer *pSearchMenu=s_Menus[s_Menus.size()-1];
|
|
if (pSearchMenu->m_Options&CONTAINER_SEARCH)
|
|
{
|
|
if (!pSearchMenu->SendMessage(WM_CHAR,wParam,lParam))
|
|
return 0;
|
|
}
|
|
pParent->SendMessage(WM_CHAR,wParam,lParam);
|
|
}
|
|
if (uMsg==WM_SYSKEYDOWN)
|
|
{
|
|
if (s_bWin7Style)
|
|
{
|
|
pParent->SendMessage(WM_SYSKEYDOWN,wParam,lParam);
|
|
if (wParam==VK_MENU)
|
|
pParent->ShowKeyboardCues();
|
|
}
|
|
else
|
|
{
|
|
CMenuContainer *pSearchMenu=s_Menus[s_Menus.size()-1];
|
|
if (pSearchMenu->m_Options&CONTAINER_SEARCH)
|
|
pSearchMenu->SendMessage(WM_SYSKEYDOWN,wParam,lParam);
|
|
}
|
|
}
|
|
if (uMsg==WM_CHAR && (wParam==VK_RETURN || wParam==10 || wParam==VK_ESCAPE || wParam==VK_TAB || wParam==127))
|
|
{
|
|
// prevent a beep when Enter, Esc or Tab is pressed
|
|
return 0;
|
|
}
|
|
if (uMsg==WM_MOUSEACTIVATE)
|
|
{
|
|
pParent->ActivateItem(pParent->m_SearchIndex,ACTIVATE_SELECT,NULL);
|
|
s_bDisableHover=!s_bWin7Style;
|
|
// close all sub-menus
|
|
CloseSubMenus(CLOSE_SKIP_SEARCH,pParent);
|
|
::SetFocus(hWnd);
|
|
if (s_bBehindTaskbar && s_TaskBar)
|
|
pParent->SetWindowPos(s_TaskBar,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
|
|
return MA_NOACTIVATE;
|
|
}
|
|
if (uMsg==WM_SETFOCUS)
|
|
{
|
|
pParent->SetSearchState(::GetWindowTextLength(hWnd)>0?SEARCH_TEXT:SEARCH_BLANK);
|
|
}
|
|
if (uMsg==WM_KILLFOCUS)
|
|
{
|
|
s_bPendingSearchEnter=false;
|
|
if (!s_bPreventClosing)
|
|
{
|
|
#ifndef PREVENT_CLOSING
|
|
box.SetWindowText(L"");
|
|
pParent->SetSearchState(SEARCH_NONE);
|
|
#endif
|
|
}
|
|
}
|
|
if (uMsg==WM_CONTEXTMENU && (lParam&0xFFFFFFFF)==0xFFFFFFFF)
|
|
{
|
|
if (s_bWin7Style)
|
|
return pParent->SendMessage(WM_CONTEXTMENU,wParam,lParam);
|
|
else
|
|
{
|
|
CMenuContainer *pSearchMenu=s_Menus[s_Menus.size()-1];
|
|
if (pSearchMenu->m_Options&CONTAINER_SEARCH)
|
|
return pSearchMenu->SendMessage(WM_CONTEXTMENU,wParam,lParam);
|
|
}
|
|
}
|
|
if (uMsg==WM_MOUSEWHEEL)
|
|
{
|
|
if (s_bWin7Style)
|
|
return pParent->SendMessage(WM_MOUSEWHEEL,wParam,lParam);
|
|
}
|
|
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
LRESULT CALLBACK CMenuContainer::SubclassScrollbar( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
|
|
{
|
|
CMenuContainer *pParent=(CMenuContainer*)uIdSubclass;
|
|
if (!pParent->m_ScrollTheme)
|
|
{
|
|
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
DWORD oldThread=g_CustomScrollbarThread;
|
|
g_CustomScrollbarThread=GetCurrentThreadId();
|
|
g_CustomScrollbarTheme=pParent->m_ScrollTheme;
|
|
LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
g_CustomScrollbarThread=oldThread;
|
|
if (!oldThread)
|
|
g_CustomScrollbarTheme=NULL;
|
|
return res;
|
|
}
|
|
|
|
int CMenuContainer::CompareMenuString( const wchar_t *str1, const wchar_t *str2 )
|
|
{
|
|
if (s_bExtensionSort)
|
|
{
|
|
const wchar_t *ext1=PathFindExtension(str1);
|
|
const wchar_t *ext2=PathFindExtension(str2);
|
|
int cmp=CompareString(LOCALE_USER_DEFAULT,LINGUISTIC_IGNORECASE,ext1,-1,ext2,-1)-CSTR_EQUAL;
|
|
if (cmp) return cmp;
|
|
}
|
|
if (s_bLogicalSort)
|
|
return StrCmpLogicalW(str1,str2);
|
|
else
|
|
return CompareString(LOCALE_USER_DEFAULT,LINGUISTIC_IGNORECASE,str1,-1,str2,-1)-CSTR_EQUAL;
|
|
}
|
|
|
|
CMenuContainer::CMenuContainer( CMenuContainer *pParent, int index, int options, const StdMenuItem *pStdItem, PIDLIST_ABSOLUTE path1, PIDLIST_ABSOLUTE path2 )
|
|
{
|
|
m_RefCount=1;
|
|
m_bSubMenu=(index>=0); // this may be true even if pParent is NULL (in case you want to show only sub-menus somewhere, use index=0 and pParent=NULL)
|
|
m_HoverItem=m_ContextItem=m_HotItem=m_InsertMark=-1;
|
|
m_DragHoverItem=m_DragIndex=-1;
|
|
m_ClickIndex=GetKeyState(VK_LBUTTON)<0?-2:-1;
|
|
m_bHoverArrow=m_bClickArrow=false;
|
|
m_pParent=pParent;
|
|
m_ParentIndex=pParent?index:-1;
|
|
m_Options=options;
|
|
m_pStdItem=pStdItem;
|
|
m_Bitmap=NULL;
|
|
m_BitmapOffset=0;
|
|
m_Region=NULL;
|
|
m_PaintOffset.x=m_PaintOffset.y=0;
|
|
m_Path1[0].Clone(path1);
|
|
if (!s_bNoCommonFolders)
|
|
m_Path2[0].Clone(path2);
|
|
|
|
if (options&CONTAINER_ALLPROGRAMS)
|
|
{
|
|
ShGetKnownFolderIDList(FOLDERID_Programs,&m_Path1[1]);
|
|
if (!s_bNoCommonFolders)
|
|
ShGetKnownFolderIDList(FOLDERID_CommonPrograms,&m_Path2[1]);
|
|
}
|
|
|
|
Assert(path1 || !path2);
|
|
|
|
m_FolderHash[0]=m_FolderHash[1]=0;
|
|
if (m_Options&CONTAINER_APPS)
|
|
m_FolderHash[0]=CalcFNVHash(L"apps");
|
|
|
|
InitializeSpecialFolders();
|
|
|
|
m_bDestroyed=false;
|
|
s_Menus.push_back(this);
|
|
m_Submenu=-1;
|
|
m_SubJumpItem=-1;
|
|
m_bTrackMouse=false;
|
|
m_RefreshPosted=0;
|
|
|
|
m_SubShowTime=0;
|
|
m_bInsertAfter=false;
|
|
m_bHotArrow=false;
|
|
|
|
m_DragHoverTime=0;
|
|
|
|
m_MaxWidth=0;
|
|
m_bTwoColumns=false;
|
|
memset(&m_rMenu,0,sizeof(m_rMenu));
|
|
memset(&m_rContent,0,sizeof(m_rContent));
|
|
memset(&m_rContent2,0,sizeof(m_rContent2));
|
|
memset(&m_rUser1,0,sizeof(m_rUser1));
|
|
memset(&m_rUser2,0,sizeof(m_rUser2));
|
|
memset(&m_rPadding,0,sizeof(m_rPadding));
|
|
|
|
m_ExtraTop=m_ExtraBottom=m_ExtraBorder=0;
|
|
m_MouseWheel=0;
|
|
m_ScrollCount=m_ScrollHeight=m_ScrollOffset=m_ScrollButtonSize=0;
|
|
m_bScrollUp=m_bScrollDown=m_bScrollUpHot=m_bScrollDownHot=false;
|
|
m_SearchIndex=-1;
|
|
m_SearchItemCount=0;
|
|
m_SearchProvidersCount=0;
|
|
m_bScrollTimerMouse=false;
|
|
m_bScrollTimerTouch=false;
|
|
m_bNoSearchDraw=false;
|
|
m_bSearchDrawn=false;
|
|
m_bInSearchUpdate=false;
|
|
m_bDisableProgHover=false;
|
|
m_bClosing=false;
|
|
m_bRefreshItems=false;
|
|
m_bWorkAreaPosted=false;
|
|
m_SearchIcons=NULL;
|
|
m_SearchState=SEARCH_NONE;
|
|
m_SearchCategoryHash=CSearchManager::CATEGORY_INVALID;
|
|
m_pProgramsTree=NULL;
|
|
m_ProgramButtonIndex=m_ProgramTreeIndex=-1;
|
|
m_OriginalCount=0;
|
|
m_OriginalScrollCount=-1;
|
|
m_SearchScrollCount=m_SearchScrollHeight=m_SearchScrollPos=0;
|
|
m_SearchHash=0;
|
|
m_pDropTargetInfo=NULL;
|
|
m_DropTargetIndex=-1;
|
|
m_PanPosY=m_Overpan=m_PointerId=0;
|
|
m_InputCookie=0;
|
|
m_ScrollTheme=NULL;
|
|
|
|
CoCreateInstance(CLSID_DragDropHelper,NULL,CLSCTX_INPROC_SERVER,IID_IDropTargetHelper,(void**)&m_pDropTargetHelper);
|
|
m_pDragSourceHelper=CComQIPtr<IDragSourceHelper2>(m_pDropTargetHelper);
|
|
LOG_MENU(LOG_OPEN,L"Open Menu, ptr=%p, index=%d, options=%08X",this,index,options);
|
|
}
|
|
|
|
CMenuContainer::~CMenuContainer( void )
|
|
{
|
|
ClearItems(m_Items.begin(),m_Items.end());
|
|
if (std::find(s_Menus.begin(),s_Menus.end(),m_pParent)!=s_Menus.end()) // check if the parent is still alive
|
|
{
|
|
if (m_pParent->m_Submenu==m_ParentIndex)
|
|
{
|
|
if (!m_pParent->m_bDestroyed)
|
|
{
|
|
m_pParent->InvalidateItem(m_ParentIndex);
|
|
if (m_pParent->m_HotItem<0 && !(m_Options&CONTAINER_SEARCH) && (!m_pParent->m_pProgramsTree || !m_pParent->m_pProgramsTree->m_hWnd || m_pParent->m_pProgramsTree->m_hWnd!=GetFocus()))
|
|
m_pParent->SetHotItem(m_ParentIndex);
|
|
}
|
|
m_pParent->SetSubmenu(-1);
|
|
}
|
|
}
|
|
if (m_Bitmap) DeleteObject(m_Bitmap);
|
|
if (m_Region) DeleteObject(m_Region);
|
|
|
|
// must be here and not in OnDestroy because during drag/drop a menu can close while still processing messages
|
|
s_Menus.erase(std::find(s_Menus.begin(),s_Menus.end(),this));
|
|
if (m_SearchIcons)
|
|
DeleteObject(m_SearchIcons);
|
|
if (m_pProgramsTree) m_pProgramsTree->Release();
|
|
}
|
|
|
|
void CMenuContainer::AddFirstFolder( IShellItem *pFolder, std::vector<MenuItem> &items, int options )
|
|
{
|
|
CAbsolutePidl ignore;
|
|
if (!m_pParent || (m_Options&CONTAINER_ALLPROGRAMS))
|
|
{
|
|
// remove the Programs subfolder from the main menu. it will be added separately
|
|
ShGetKnownFolderIDList(FOLDERID_Programs,&ignore);
|
|
}
|
|
|
|
CShellItemEnumerator enumerator(pFolder);
|
|
if (!enumerator.IsValid()) return;
|
|
|
|
CComPtr<IShellItem> pChild;
|
|
CAbsolutePidl childPidl;
|
|
int refreshFlags=CItemManager::INFO_SMALL_ICON;
|
|
if (!m_bSubMenu)
|
|
{
|
|
if (s_Skin.Main_icon_size==MenuSkin::ICON_SIZE_LARGE)
|
|
refreshFlags=CItemManager::INFO_LARGE_ICON;
|
|
else if (s_Skin.Main_icon_size==MenuSkin::ICON_SIZE_NONE)
|
|
refreshFlags=0;
|
|
}
|
|
if (options&CONTAINER_PROGRAMS)
|
|
refreshFlags|=CItemManager::INFO_LINK|CItemManager::INFO_METRO;
|
|
if (options&CONTAINER_NOPATH)
|
|
refreshFlags|=CItemManager::INFO_NO_PATH;
|
|
while (enumerator.GetNext(pChild,childPidl))
|
|
{
|
|
SFGAOF flags=0;
|
|
HRESULT hrFlags=pChild->GetAttributes(SFGAO_FOLDER|SFGAO_STREAM|SFGAO_LINK|SFGAO_HIDDEN,&flags);
|
|
if (FAILED(hrFlags)) // check if the item is a folder, archive or a link
|
|
flags=0;
|
|
if (flags&SFGAO_HIDDEN)
|
|
continue;
|
|
CComString pName;
|
|
if (SUCCEEDED(pChild->GetDisplayName(SIGDN_PARENTRELATIVEPARSING,&pName)))
|
|
{
|
|
LOG_MENU(LOG_OPEN,L"%s, 0x%08X, 0x%08X",(const wchar_t*)pName,flags,hrFlags);
|
|
MenuItem item(MENU_NO);
|
|
if (ignore && ILIsEqual(childPidl,ignore))
|
|
continue;
|
|
item.pItemInfo=g_ItemManager.GetItemInfo(pChild,childPidl,refreshFlags);
|
|
bool bLibrary=_wcsicmp(PathFindExtension(pName),L".library-ms")==0;
|
|
bool bStartScreen=(
|
|
#ifndef STARTSCREEN_WIN7
|
|
GetWinVersion()>=WIN_VER_WIN8 &&
|
|
#endif
|
|
wcscmp(pName,STARTSCREEN_COMMAND)==0);
|
|
const wchar_t *pStr=pName;
|
|
if (!(pStr[0]&0xFF00) && isalpha(pStr[0]) && pStr[1]==':' && Strlen(pStr)<=3)
|
|
item.drive=(char)toupper(pStr[0]);
|
|
if (bStartScreen)
|
|
{
|
|
if (GetWinVersion()>=WIN_VER_WIN10)
|
|
item.name=FindTranslation(L"Menu.StartMenu",L"Start Menu");
|
|
else
|
|
item.name=FindTranslation(L"Menu.StartScreen",L"Start Screen");
|
|
pName.MakeUpper();
|
|
item.nameHash=CalcFNVHash(pName);
|
|
}
|
|
else
|
|
{
|
|
CComString pName2;
|
|
if (SUCCEEDED(pChild->GetDisplayName(SIGDN_NORMALDISPLAY,&pName2)))
|
|
{
|
|
if ((options&CONTAINER_CONTROLPANEL) && (_wcsnicmp(pName2,L"::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0",42)==0 || Strlen(pName2)==0))
|
|
continue; // if the display name starts with the control panel GUID, something's wrong (like the Intel crap)
|
|
pName.MakeUpper();
|
|
item.nameHash=CalcFNVHash(pName);
|
|
pName.Clear();
|
|
item.SetName(pName2,(options&CONTAINER_NOEXTENSIONS)!=0);
|
|
}
|
|
else
|
|
{
|
|
if (options&CONTAINER_CONTROLPANEL)
|
|
continue; // control panel items should have a normal name
|
|
item.SetName(pName,(options&CONTAINER_NOEXTENSIONS)!=0);
|
|
pName.MakeUpper();
|
|
item.nameHash=CalcFNVHash(pName);
|
|
}
|
|
|
|
if (bLibrary) flags&=~SFGAO_STREAM;
|
|
item.bLink=(flags&SFGAO_LINK)!=0;
|
|
item.bFolder=(!(options&CONTAINER_CONTROLPANEL) && !(options&CONTAINER_NOSUBFOLDERS) && (flags&SFGAO_FOLDER) && (!(flags&(SFGAO_STREAM|SFGAO_LINK)) || (s_bExpandLinks && item.bLink)));
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
if (item.pItemInfo->IsMetroLink())
|
|
{
|
|
if ((m_bSubMenu && GetSettingBool(L"HideProgramsMetro")) || _wcsicmp(item.pItemInfo->GetAppid(),DESKTOP_APP_ID)==0)
|
|
continue;
|
|
item.bLink=item.bMetroLink=true;
|
|
if (!item.pItemInfo->GetMetroName().IsEmpty())
|
|
item.name=item.pItemInfo->GetMetroName();
|
|
}
|
|
item.bMetroApp=item.pItemInfo->IsMetroApp();
|
|
}
|
|
}
|
|
item.pItem1=childPidl.Detach();
|
|
item.bStartScreen=bStartScreen;
|
|
item.bPrograms=(options&CONTAINER_PROGRAMS)!=0;
|
|
items.push_back(item);
|
|
#ifdef REPEAT_ITEMS
|
|
for (int i=0;i<REPEAT_ITEMS;i++)
|
|
{
|
|
item.pItem1=ILCloneFull(item.pItem1);
|
|
items.push_back(item);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
void CMenuContainer::AddSecondFolder( IShellItem *pFolder, std::vector<MenuItem> &items, int options )
|
|
{
|
|
CAbsolutePidl ignore;
|
|
if (!m_pParent || (m_Options&CONTAINER_ALLPROGRAMS))
|
|
{
|
|
// remove the Programs subfolder from the main menu. it will be added separately
|
|
ShGetKnownFolderIDList(FOLDERID_CommonPrograms,&ignore);
|
|
}
|
|
|
|
CShellItemEnumerator enumerator(pFolder);
|
|
if (!enumerator.IsValid()) return;
|
|
|
|
CComPtr<IShellItem> pChild;
|
|
CAbsolutePidl childPidl;
|
|
int refreshFlags=CItemManager::INFO_SMALL_ICON;
|
|
if (!m_bSubMenu)
|
|
{
|
|
if (s_Skin.Main_icon_size==MenuSkin::ICON_SIZE_LARGE)
|
|
refreshFlags=CItemManager::INFO_LARGE_ICON;
|
|
else if (s_Skin.Main_icon_size==MenuSkin::ICON_SIZE_NONE)
|
|
refreshFlags=0;
|
|
}
|
|
if (options&CONTAINER_PROGRAMS)
|
|
refreshFlags|=CItemManager::INFO_LINK|CItemManager::INFO_METRO;
|
|
while (enumerator.GetNext(pChild,childPidl))
|
|
{
|
|
SFGAOF flags=0;
|
|
HRESULT hrFlags=pChild->GetAttributes(SFGAO_FOLDER|SFGAO_STREAM|SFGAO_LINK|SFGAO_HIDDEN,&flags);
|
|
if (FAILED(hrFlags)) // check if the item is a folder, archive or a link
|
|
flags=0;
|
|
if (flags&SFGAO_HIDDEN)
|
|
continue;
|
|
CComString pName;
|
|
if (SUCCEEDED(pChild->GetDisplayName(SIGDN_PARENTRELATIVEPARSING,&pName)))
|
|
{
|
|
LOG_MENU(LOG_OPEN,L"%s, 0x%08X, 0x%08X",(const wchar_t*)pName,flags,hrFlags);
|
|
bool bLibrary=_wcsicmp(PathFindExtension(pName),L".library-ms")==0;
|
|
bool bStartScreen=(
|
|
#ifndef STARTSCREEN_WIN7
|
|
GetWinVersion()>=WIN_VER_WIN8 &&
|
|
#endif
|
|
wcscmp(pName,STARTSCREEN_COMMAND)==0);
|
|
MenuItem item(MENU_NO);
|
|
if (bStartScreen)
|
|
{
|
|
if (GetWinVersion()>=WIN_VER_WIN10)
|
|
item.name=FindTranslation(L"Menu.StartMenu",L"Start Menu");
|
|
else
|
|
item.name=FindTranslation(L"Menu.StartScreen",L"Start Screen");
|
|
pName.MakeUpper();
|
|
item.nameHash=CalcFNVHash(pName);
|
|
}
|
|
else
|
|
{
|
|
CComString pName2;
|
|
if (SUCCEEDED(pChild->GetDisplayName(SIGDN_NORMALDISPLAY,&pName2)))
|
|
{
|
|
pName.MakeUpper();
|
|
item.nameHash=CalcFNVHash(pName);
|
|
pName.Clear();
|
|
item.SetName(pName2,(options&CONTAINER_NOEXTENSIONS)!=0);
|
|
}
|
|
else
|
|
{
|
|
item.SetName(pName,(options&CONTAINER_NOEXTENSIONS)!=0);
|
|
pName.MakeUpper();
|
|
item.nameHash=CalcFNVHash(pName);
|
|
}
|
|
}
|
|
pName.Clear();
|
|
|
|
if (ignore && ILIsEqual(childPidl,ignore))
|
|
continue;
|
|
|
|
// look for another item with the same name
|
|
bool bFound=false;
|
|
for (std::vector<MenuItem>::iterator it=items.begin();it!=items.end();++it)
|
|
{
|
|
if (item.nameHash==it->nameHash)
|
|
{
|
|
it->pItem2=childPidl.Detach();
|
|
bFound=true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
// new item
|
|
if (!bStartScreen)
|
|
{
|
|
item.pItemInfo=g_ItemManager.GetItemInfo(pChild,childPidl,refreshFlags);
|
|
|
|
if (bLibrary) flags&=~SFGAO_STREAM;
|
|
item.bLink=(flags&SFGAO_LINK)!=0;
|
|
item.bFolder=(!(options&CONTAINER_CONTROLPANEL) && !(options&CONTAINER_NOSUBFOLDERS) && (flags&SFGAO_FOLDER) && (!(flags&(SFGAO_STREAM|SFGAO_LINK)) || (s_bExpandLinks && item.bLink)));
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
if (item.pItemInfo->IsMetroLink())
|
|
{
|
|
if ((m_bSubMenu && GetSettingBool(L"HideProgramsMetro")) || _wcsicmp(item.pItemInfo->GetAppid(),DESKTOP_APP_ID)==0)
|
|
continue;
|
|
item.bLink=item.bMetroLink=true;
|
|
if (!item.pItemInfo->GetMetroName().IsEmpty())
|
|
item.name=item.pItemInfo->GetMetroName();
|
|
item.bMetroApp=item.pItemInfo->IsMetroApp();
|
|
}
|
|
}
|
|
}
|
|
item.pItem1=childPidl.Detach();
|
|
item.bStartScreen=bStartScreen;
|
|
item.bPrograms=(options&CONTAINER_PROGRAMS)!=0;
|
|
items.push_back(item);
|
|
#ifdef REPEAT_ITEMS
|
|
for (int i=0;i<REPEAT_ITEMS;i++)
|
|
{
|
|
item.pItem1=ILCloneFull(item.pItem1);
|
|
items.push_back(item);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int GetStdOptions( TMenuID id )
|
|
{
|
|
for (int i=0;i<_countof(g_StdOptions);i++)
|
|
if (g_StdOptions[i].id==id)
|
|
{
|
|
return g_StdOptions[i].options;
|
|
break;
|
|
}
|
|
return MENU_ENABLED|MENU_EXPANDED;
|
|
}
|
|
|
|
static const CItemManager::ItemInfo *GetInternetIcon( bool bDoc )
|
|
{
|
|
wchar_t path[_MAX_PATH];
|
|
DWORD size=_countof(path);
|
|
if (SUCCEEDED(AssocQueryString(0,bDoc?ASSOCSTR_DEFAULTICON:ASSOCSTR_EXECUTABLE,L"http",L"open",path,&size)))
|
|
{
|
|
if (bDoc)
|
|
return g_ItemManager.GetCustomIcon(path,CItemManager::ICON_SIZE_TYPE_SMALL);
|
|
CAbsolutePidl pidl;
|
|
pidl.Attach(ILCreateFromPath(path));
|
|
CComPtr<IShellItem> pItem;
|
|
if (pidl && SUCCEEDED(SHCreateItemFromIDList(pidl,IID_IShellItem,(void**)&pItem)))
|
|
return g_ItemManager.GetItemInfo(pItem,pidl,CItemManager::INFO_SMALL_ICON);
|
|
}
|
|
return g_ItemManager.GetCustomIcon(L"shell32.dll,14",CItemManager::ICON_SIZE_TYPE_SMALL);
|
|
}
|
|
|
|
void CMenuContainer::AddInternetSearch( size_t index )
|
|
{
|
|
MenuItem item(MENU_SEARCH_INTERNET);
|
|
item.name=FindTranslation(L"Menu.SearchInternet",L"Search the Internet");
|
|
item.pItemInfo=GetInternetIcon(false);
|
|
m_Items.insert(m_Items.begin()+index,1,item);
|
|
}
|
|
|
|
void CMenuContainer::AddStandardItems( void )
|
|
{
|
|
if (m_pStdItem && m_pStdItem->id!=MENU_NO)
|
|
{
|
|
bool bItemsFirst=(m_Options&(CONTAINER_ITEMS_FIRST|CONTAINER_SEARCH))==CONTAINER_ITEMS_FIRST;
|
|
if (!m_Items.empty() && !(s_bWin7Style && !m_bSubMenu && GetSettingInt(L"ProgramsStyle")==PROGRAMS_HIDDEN))
|
|
{
|
|
MenuItem item(MENU_SEPARATOR);
|
|
if (m_pStdItem->id==MENU_COLUMN_PADDING)
|
|
item.bAlignBottom=true;
|
|
if (bItemsFirst)
|
|
m_Items.insert(m_Items.begin(),item);
|
|
else
|
|
m_Items.push_back(item);
|
|
}
|
|
size_t menuIdx=bItemsFirst?0:m_Items.size();
|
|
bool bBreak=false, bAlignBottom=false, bInlineFirst=false;
|
|
const StdMenuItem *pInlineParent=NULL;
|
|
int searchProviderIndex=-1;
|
|
m_SearchProvidersCount=0;
|
|
MenuSkin::TIconSize mainIconSize=s_Skin.Main_icon_size;
|
|
for (const StdMenuItem *pStdItem=m_pStdItem;;pStdItem++)
|
|
{
|
|
if (pStdItem->id==MENU_LAST)
|
|
{
|
|
if (pInlineParent)
|
|
{
|
|
pStdItem=pInlineParent;
|
|
pInlineParent=NULL;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
if (pStdItem->id==MENU_IGNORE)
|
|
continue;
|
|
if (m_bSubMenu && pStdItem->id==s_ShutdownCommand)
|
|
continue;
|
|
|
|
if (pStdItem->id==MENU_COLUMN_BREAK && m_bTwoColumns)
|
|
mainIconSize=s_Skin.Main2_icon_size;
|
|
|
|
int stdOptions=GetStdOptions(pStdItem->id);
|
|
if (!(stdOptions&MENU_ENABLED)) continue;
|
|
|
|
if (s_bWin7Style && m_bSubMenu && pStdItem->command && (pStdItem->id==MENU_SWITCHUSER || pStdItem->id==MENU_SECURITY || pStdItem->id==MENU_LOGOFF || pStdItem->id==MENU_LOCK || pStdItem->id==MENU_DISCONNECT
|
|
|| pStdItem->id==MENU_UNDOCK || pStdItem->id==MENU_RESTART || pStdItem->id==MENU_SLEEP || pStdItem->id==MENU_HIBERNATE || pStdItem->id==MENU_SHUTDOWN
|
|
|| pStdItem->id==MENU_RESTART_NOUPDATE || pStdItem->id==MENU_SHUTDOWN_NOUPDATE))
|
|
{
|
|
CString commands=GetSettingString(L"ShutdownW7");
|
|
const wchar_t *str=commands;
|
|
bool bFound=false, bEmpty=true;
|
|
const wchar_t *commandName=pStdItem->command;
|
|
if (pStdItem->id==MENU_SHUTDOWN_NOUPDATE)
|
|
commandName=L"shutdown";
|
|
else if (pStdItem->id==MENU_RESTART_NOUPDATE)
|
|
commandName=L"restart";
|
|
while (*str)
|
|
{
|
|
wchar_t token[100];
|
|
str=GetToken(str,token,_countof(token),L" \t;,");
|
|
if (*token) bEmpty=false;
|
|
if (_wcsicmp(commandName,token)==0)
|
|
{
|
|
bFound=true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bFound && !bEmpty) continue;
|
|
}
|
|
|
|
if (pStdItem->id==MENU_SEPARATOR && menuIdx>0 && m_Items[menuIdx-1].id==MENU_SEPARATOR)
|
|
{
|
|
// prevent double separators unless that's exactly what is requested
|
|
if (pStdItem>m_pStdItem && pStdItem[-1].id!=MENU_SEPARATOR)
|
|
continue;
|
|
}
|
|
if (pStdItem->id==MENU_COLUMN_BREAK)
|
|
{
|
|
bBreak=true;
|
|
continue;
|
|
}
|
|
if (pStdItem->id==MENU_COLUMN_PADDING)
|
|
{
|
|
bAlignBottom=true;
|
|
continue;
|
|
}
|
|
|
|
if (!pInlineParent && pStdItem->submenu && (pStdItem->settings&StdMenuItem::MENU_INLINE))
|
|
{
|
|
pInlineParent=pStdItem;
|
|
pStdItem=pInlineParent->submenu-1;
|
|
bInlineFirst=true;
|
|
continue;
|
|
}
|
|
if (s_bWin7Style && pStdItem->id==MENU_SEARCH_BOX)
|
|
{
|
|
MenuItem item(MENU_EMPTY);
|
|
m_Items.insert(m_Items.begin()+menuIdx,1,item);
|
|
menuIdx++;
|
|
searchProviderIndex=(int)menuIdx;
|
|
if (GetSettingBool(L"SearchInternet"))
|
|
{
|
|
AddInternetSearch(menuIdx);
|
|
menuIdx++;
|
|
m_SearchProvidersCount++;
|
|
}
|
|
}
|
|
|
|
bool bSearchProvider7=false;
|
|
if (s_bWin7Style && !m_bSubMenu && pStdItem->command)
|
|
{
|
|
// if after environment substitution there are %1 or %2 left, this is likely a search provider
|
|
wchar_t buf[1024];
|
|
Strcpy(buf,_countof(buf),pStdItem->command);
|
|
DoEnvironmentSubst(buf,_countof(buf));
|
|
const wchar_t *ptr=wcsstr(buf,L"%1");
|
|
if (ptr && !isalnum(ptr[2]))
|
|
bSearchProvider7=true;
|
|
else
|
|
{
|
|
ptr=wcsstr(buf,L"%2");
|
|
if (ptr && !isalnum(ptr[2]))
|
|
bSearchProvider7=true;
|
|
}
|
|
}
|
|
|
|
MenuItem item(pStdItem->id);
|
|
item.pStdItem=pStdItem;
|
|
if (pInlineParent)
|
|
item.bInline=true;
|
|
|
|
if (!bSearchProvider7)
|
|
{
|
|
item.bBreak=bBreak;
|
|
bBreak=false;
|
|
}
|
|
item.bAlignBottom=bAlignBottom;
|
|
item.bInlineFirst=bInlineFirst;
|
|
bAlignBottom=bInlineFirst=false;
|
|
TNetworkType networkType=NETWORK_NONE;
|
|
|
|
Assert(pStdItem->folder1 || !pStdItem->folder2);
|
|
if (pStdItem->id==MENU_APPS)
|
|
{
|
|
wchar_t path[_MAX_PATH]=METRO_APP_ROOT;
|
|
DoEnvironmentSubst(path,_countof(path));
|
|
item.pItem1=ILCreateFromPath(path);
|
|
item.bFolder=true;
|
|
item.name=FindTranslation(L"Menu.Apps",L"Apps");
|
|
}
|
|
else if (pStdItem->id==MENU_PROGRAMS && GetSettingInt(L"PinnedPrograms")==PINNED_PROGRAMS_PINNED)
|
|
{
|
|
ShGetKnownFolderIDList(FOLDERID_StartMenu,&item.pItem1);
|
|
if (!s_bNoCommonFolders)
|
|
ShGetKnownFolderIDList(FOLDERID_CommonStartMenu,&item.pItem2);
|
|
item.bFolder=true;
|
|
}
|
|
else if (pStdItem->folder1)
|
|
{
|
|
ShGetKnownFolderIDList(*pStdItem->folder1,&item.pItem1);
|
|
if (pStdItem->folder2)
|
|
ShGetKnownFolderIDList(*pStdItem->folder2,&item.pItem2);
|
|
if (!item.pItem1 && item.pItem2)
|
|
{
|
|
item.pItem1=item.pItem2;
|
|
item.pItem2=NULL;
|
|
}
|
|
item.bFolder=(stdOptions&MENU_EXPANDED) && !(item.pStdItem->settings&StdMenuItem::MENU_NOEXPAND);
|
|
}
|
|
else if (pStdItem->link)
|
|
{
|
|
SFGAOF flags=0;
|
|
wchar_t buf[1024];
|
|
Strcpy(buf,_countof(buf),item.pStdItem->link);
|
|
DoEnvironmentSubst(buf,_countof(buf));
|
|
bool bLibrary=_wcsicmp(PathFindExtension(buf),L".library-ms")==0;
|
|
wchar_t *second=wcschr(buf,';');
|
|
if (!bLibrary && second && !(item.pStdItem->settings&StdMenuItem::MENU_NOEXPAND))
|
|
{
|
|
wchar_t *end= second;
|
|
while (end>buf)
|
|
{
|
|
*end=0;
|
|
end--;
|
|
if (*end!=' ')
|
|
break;
|
|
}
|
|
MenuParseDisplayName(buf,&item.pItem1,&flags,&networkType);
|
|
second++;
|
|
while (*second==' ')
|
|
second++;
|
|
SFGAOF flags2=0;
|
|
TNetworkType networkType2;
|
|
MenuParseDisplayName(second,&item.pItem2,&flags2,&networkType2);
|
|
if (!item.pItem1 && item.pItem2)
|
|
{
|
|
item.pItem1=item.pItem2;
|
|
item.pItem2=NULL;
|
|
flags=flags2;
|
|
networkType=networkType2;
|
|
}
|
|
if (item.pItem1)
|
|
{
|
|
item.bLink=(flags&SFGAO_LINK)!=0;
|
|
item.bFolder=((flags&SFGAO_FOLDER) && (!(flags&(SFGAO_STREAM|SFGAO_LINK)) || (s_bExpandLinks && item.bLink)));
|
|
}
|
|
}
|
|
else if (SUCCEEDED(MenuParseDisplayName(buf,&item.pItem1,&flags,&networkType)))
|
|
{
|
|
if (bLibrary) flags&=~SFGAO_STREAM;
|
|
item.bLink=(flags&SFGAO_LINK)!=0;
|
|
item.bFolder=((flags&SFGAO_FOLDER) && !(item.pStdItem->settings&StdMenuItem::MENU_NOEXPAND) && (!(flags&(SFGAO_STREAM|SFGAO_LINK)) || (s_bExpandLinks && item.bLink)));
|
|
}
|
|
}
|
|
if ((pStdItem->submenu && pStdItem->id!=MENU_SEARCH_BOX && (stdOptions&MENU_EXPANDED)) || pStdItem->id==MENU_RECENT_PROGRAMS)
|
|
item.bFolder=true;
|
|
|
|
item.bSplit=item.bFolder && (item.pStdItem->settings&StdMenuItem::MENU_SPLIT_BUTTON)!=0;
|
|
|
|
// get icon
|
|
CItemManager::TIconSizeType iconSizeType;
|
|
int refreshFlags;
|
|
if (bSearchProvider7 || m_bSubMenu)
|
|
{
|
|
iconSizeType=CItemManager::ICON_SIZE_TYPE_SMALL;
|
|
refreshFlags=CItemManager::INFO_SMALL_ICON;
|
|
}
|
|
else if (s_bWin7Style)
|
|
{
|
|
iconSizeType=CItemManager::ICON_SIZE_TYPE_EXTRA_LARGE;
|
|
refreshFlags=CItemManager::INFO_EXTRA_LARGE_ICON;
|
|
}
|
|
else if (mainIconSize==MenuSkin::ICON_SIZE_LARGE)
|
|
{
|
|
iconSizeType=CItemManager::ICON_SIZE_TYPE_LARGE;
|
|
refreshFlags=CItemManager::INFO_LARGE_ICON;
|
|
}
|
|
else if (mainIconSize==MenuSkin::ICON_SIZE_SMALL)
|
|
{
|
|
iconSizeType=CItemManager::ICON_SIZE_TYPE_SMALL;
|
|
refreshFlags=CItemManager::INFO_SMALL_ICON;
|
|
}
|
|
else
|
|
{
|
|
iconSizeType=CItemManager::ICON_SIZE_TYPE_SMALL;
|
|
refreshFlags=0;
|
|
}
|
|
if (pStdItem->link)
|
|
refreshFlags|=CItemManager::INFO_LINK|CItemManager::INFO_METRO;
|
|
if ((refreshFlags&CItemManager::INFO_ICON)==0)
|
|
item.pItemInfo=NULL;
|
|
else if (pStdItem->iconPath)
|
|
{
|
|
if (_wcsicmp(pStdItem->iconPath,L"none")==0)
|
|
item.pItemInfo=NULL;
|
|
else
|
|
item.pItemInfo=g_ItemManager.GetCustomIcon(pStdItem->iconPath,iconSizeType);
|
|
}
|
|
else if (networkType!=NETWORK_NONE && networkType!=NETWORK_FILE)
|
|
{
|
|
item.pItemInfo=g_ItemManager.GetCustomIcon(GetDefaultNetworkIcon(networkType),iconSizeType);
|
|
}
|
|
else if (item.pItem1)
|
|
{
|
|
CComPtr<IShellItem> pItem;
|
|
if (SUCCEEDED(SHCreateItemFromIDList(item.pItem1,IID_IShellItem,(void**)&pItem)))
|
|
{
|
|
item.pItemInfo=g_ItemManager.GetItemInfo(pItem,item.pItem1,refreshFlags);
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
item.bLink=item.bMetroLink=item.pItemInfo->IsMetroLink();
|
|
item.bMetroApp=item.pItemInfo->IsMetroApp();
|
|
}
|
|
}
|
|
else
|
|
item.pItemInfo=g_ItemManager.GetCustomIcon(NULL,iconSizeType);
|
|
|
|
// get name
|
|
if (pStdItem->label && _wcsicmp(pStdItem->label,L"none")==0)
|
|
{
|
|
item.name.Empty();
|
|
}
|
|
else if (pStdItem->label)
|
|
{
|
|
if (item.id==MENU_LOGOFF)
|
|
{
|
|
// construct the text Log Off <username>...
|
|
wchar_t user[256]={0};
|
|
ULONG size=_countof(user);
|
|
if (!GetUserNameEx(NameDisplay,user,&size))
|
|
{
|
|
// GetUserNameEx may fail (for example on Home editions). use the login name
|
|
size=_countof(user);
|
|
GetUserName(user,&size);
|
|
}
|
|
item.name.Format(pStdItem->label,user);
|
|
}
|
|
else if (item.id==MENU_SHUTDOWN_BUTTON)
|
|
{
|
|
s_ShutdownCommand=MENU_NO;
|
|
int shutdown=GetSettingInt(L"ShutdownCommand");
|
|
if (shutdown<0) shutdown=0;
|
|
if (shutdown>=SHUTDOWN_TYPE_COUNT) shutdown=SHUTDOWN_TYPE_COUNT-1;
|
|
|
|
bool enabled[SHUTDOWN_TYPE_COUNT]={0};
|
|
enabled[SHUTDOWN_TYPE_SHUTDOWN]=(GetStdOptions(MENU_SHUTDOWN)&MENU_ENABLED)!=0;
|
|
enabled[SHUTDOWN_TYPE_RESTART]=(GetStdOptions(MENU_RESTART)&MENU_ENABLED)!=0;
|
|
enabled[SHUTDOWN_TYPE_LOGOFF]=(GetStdOptions(MENU_LOGOFF)&MENU_ENABLED)!=0;
|
|
enabled[SHUTDOWN_TYPE_SLEEP]=(GetStdOptions(MENU_SLEEP)&MENU_ENABLED)!=0;
|
|
enabled[SHUTDOWN_TYPE_HIBERNATE]=(GetStdOptions(MENU_HIBERNATE)&MENU_ENABLED)!=0;
|
|
enabled[SHUTDOWN_TYPE_LOCK]=(GetStdOptions(MENU_LOCK)&MENU_ENABLED)!=0;
|
|
enabled[SHUTDOWN_TYPE_SWITCHUSER]=(GetStdOptions(MENU_SWITCHUSER)&MENU_ENABLED)!=0;
|
|
enabled[SHUTDOWN_TYPE_SHUTDOWN_BOX]=(GetStdOptions(MENU_SHUTDOWN_BOX)&MENU_ENABLED)!=0;
|
|
if (!enabled[shutdown])
|
|
{
|
|
for (int i=1;i<SHUTDOWN_TYPE_COUNT;i++)
|
|
{
|
|
if (enabled[i])
|
|
{
|
|
shutdown=i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!enabled[shutdown])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (shutdown==SHUTDOWN_TYPE_SHUTDOWN)
|
|
{
|
|
item.name=FindTranslation(L"Menu.Shutdown",L"Sh&ut Down");
|
|
if (s_bHasUpdates)
|
|
const_cast<StdMenuItem*>(item.pStdItem)->tip=FindTranslation(L"Menu.ShutdownUpdate",L"Update and shut down");
|
|
else
|
|
const_cast<StdMenuItem*>(item.pStdItem)->tip=FindTranslation(L"Menu.ShutdownTip",L"");
|
|
s_ShutdownCommand=MENU_SHUTDOWN;
|
|
}
|
|
if (shutdown==SHUTDOWN_TYPE_RESTART)
|
|
{
|
|
item.name=FindTranslation(L"Menu.Restart",L"&Restart");
|
|
if (s_bHasUpdates && GetWinVersion()>=WIN_VER_WIN8)
|
|
const_cast<StdMenuItem*>(item.pStdItem)->tip=FindTranslation(L"Menu.RestartUpdate",L"Update and restart");
|
|
else
|
|
const_cast<StdMenuItem*>(item.pStdItem)->tip=FindTranslation(L"Menu.RestartTip",L"");
|
|
s_ShutdownCommand=MENU_RESTART;
|
|
}
|
|
if (shutdown==SHUTDOWN_TYPE_LOGOFF)
|
|
{
|
|
item.name=FindTranslation(L"Menu.LogOffShort",L"Log off");
|
|
const_cast<StdMenuItem*>(item.pStdItem)->tip=FindTranslation(L"Menu.LogOffTip",L"");
|
|
s_ShutdownCommand=MENU_LOGOFF;
|
|
}
|
|
if (shutdown==SHUTDOWN_TYPE_SLEEP)
|
|
{
|
|
item.name=FindTranslation(L"Menu.Sleep",L"&Sleep");
|
|
const_cast<StdMenuItem*>(item.pStdItem)->tip=FindTranslation(L"Menu.SleepTip",L"");
|
|
s_ShutdownCommand=MENU_SLEEP;
|
|
}
|
|
if (shutdown==SHUTDOWN_TYPE_HIBERNATE)
|
|
{
|
|
item.name=FindTranslation(L"Menu.Hibernate",L"&Hibernate");
|
|
const_cast<StdMenuItem*>(item.pStdItem)->tip=FindTranslation(L"Menu.HibernateTip",L"");
|
|
s_ShutdownCommand=MENU_HIBERNATE;
|
|
}
|
|
if (shutdown==SHUTDOWN_TYPE_SHUTDOWN_BOX)
|
|
{
|
|
item.name=FindTranslation(L"Menu.ShutdownBox",L"Sh&ut Down...");
|
|
const_cast<StdMenuItem*>(item.pStdItem)->tip=L"";
|
|
s_ShutdownCommand=MENU_SHUTDOWN_BOX;
|
|
}
|
|
if (shutdown==SHUTDOWN_TYPE_LOCK)
|
|
{
|
|
item.name=FindTranslation(L"Menu.Lock",L"Lock");
|
|
const_cast<StdMenuItem*>(item.pStdItem)->tip=FindTranslation(L"Menu.LockTip",L"");
|
|
s_ShutdownCommand=MENU_LOCK;
|
|
}
|
|
if (shutdown==SHUTDOWN_TYPE_SWITCHUSER)
|
|
{
|
|
item.name=FindTranslation(L"Menu.SwitchUser",L"Switch User");
|
|
const_cast<StdMenuItem*>(item.pStdItem)->tip=FindTranslation(L"Menu.SwitchUserTip",L"");
|
|
s_ShutdownCommand=MENU_SWITCHUSER;
|
|
}
|
|
}
|
|
else if (s_bHasUpdates && m_bSubMenu && item.id==MENU_SHUTDOWN)
|
|
item.name=FindTranslation(L"Menu.ShutdownUpdate",L"Update and shut down");
|
|
else if (s_bHasUpdates && m_bSubMenu && item.id==MENU_RESTART && GetWinVersion()>=WIN_VER_WIN8)
|
|
item.name=FindTranslation(L"Menu.RestartUpdate",L"Update and restart");
|
|
else
|
|
item.name=pStdItem->label;
|
|
}
|
|
else if (item.pItem1)
|
|
{
|
|
if (item.pItemInfo)
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
if (item.pItemInfo->IsMetroLink())
|
|
item.name=item.pItemInfo->GetMetroName();
|
|
}
|
|
if (item.name.IsEmpty())
|
|
{
|
|
SHFILEINFO info={0};
|
|
SHGetFileInfo((LPCWSTR)item.pItem1,0,&info,sizeof(info),SHGFI_PIDL|SHGFI_DISPLAYNAME);
|
|
item.name=info.szDisplayName;
|
|
}
|
|
if (wcschr(item.name,'&'))
|
|
item.name.Replace(L"&",L"&&");
|
|
}
|
|
else if (item.name.IsEmpty() && item.id!=MENU_SEPARATOR && item.id!=MENU_SEARCH_BOX && !item.bInline)
|
|
{
|
|
if ((pStdItem->command && wcscmp(pStdItem->command,L"<blank>")!=0) || pStdItem->link || pStdItem->folder1 || pStdItem->submenu || pStdItem->id!=MENU_CUSTOM)
|
|
item.name=LoadStringEx(IDS_NO_TEXT);
|
|
else
|
|
{
|
|
item.id=MENU_SEPARATOR;
|
|
item.bBlankSeparator=true;
|
|
}
|
|
}
|
|
|
|
item.bPrograms=(item.id==MENU_PROGRAMS || item.id==MENU_FAVORITES);
|
|
if (item.bInline)
|
|
item.bFolder=false;
|
|
|
|
if (bSearchProvider7)
|
|
{
|
|
item.bInline=false;
|
|
item.bFolder=false;
|
|
item.id=MENU_SEARCH_PROVIDER;
|
|
if (searchProviderIndex>=0)
|
|
{
|
|
m_Items.insert(m_Items.begin()+searchProviderIndex,1,item);
|
|
searchProviderIndex++;
|
|
menuIdx++;
|
|
m_SearchProvidersCount++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_Items.insert(m_Items.begin()+menuIdx,1,item);
|
|
menuIdx++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CMenuContainer::UpdateAccelerators( int first, int last )
|
|
{
|
|
TRecentKeys recentKeys=(TRecentKeys)GetSettingInt(L"RecentProgKeys");
|
|
|
|
for (int i=first;i<last;i++)
|
|
{
|
|
MenuItem &item=m_Items[i];
|
|
if (item.id==MENU_SEPARATOR || item.id==MENU_EMPTY || item.id==MENU_EMPTY_TOP || item.id==MENU_SEARCH_EMPTY || item.id==MENU_SEARCH_BOX || item.name.IsEmpty() || (item.id==MENU_RECENT && recentKeys!=RECENT_KEYS_NORMAL))
|
|
continue;
|
|
|
|
const wchar_t *name=item.name;
|
|
wchar_t buf[2]={name[0],0};
|
|
while (1)
|
|
{
|
|
const wchar_t *c=wcschr(name,'&');
|
|
if (!c || !c[1]) break;
|
|
if (c[1]!='&')
|
|
{
|
|
buf[0]=c[1];
|
|
item.bCustomAccelerator=true;
|
|
break;
|
|
}
|
|
name=c+1;
|
|
}
|
|
CharUpper(buf); // always upper case
|
|
item.accelerator=buf[0];
|
|
}
|
|
}
|
|
|
|
void CMenuContainer::UpdateAutoComplete( const wchar_t *text )
|
|
{
|
|
m_bInSearchUpdate=true;
|
|
m_SearchBox.SetWindowText(text);
|
|
m_bInSearchUpdate=false;
|
|
int len=Strlen(text);
|
|
m_SearchBox.SendMessage(EM_SETSEL,len,len);
|
|
}
|
|
|
|
struct UserAssistItem
|
|
{
|
|
wchar_t name[_MAX_PATH];
|
|
float rank;
|
|
FILETIME timestamp;
|
|
unsigned int mfuHash; // original case
|
|
unsigned int nameHash; // all caps
|
|
const CItemManager::ItemInfo *pLinkInfo;
|
|
|
|
bool operator<( const UserAssistItem &item ) { return (rank>item.rank) || (rank==item.rank && CompareFileTime(×tamp,&item.timestamp)>0); }
|
|
};
|
|
|
|
static const wchar_t *g_MfuIgnoreWords[]={
|
|
L"DOCUMENTATION",
|
|
L"HELP",
|
|
L"INSTALL",
|
|
L"MORE INFO",
|
|
L"READ ME",
|
|
L"READ FIRST",
|
|
L"README",
|
|
L"REMOVE",
|
|
L"SETUP",
|
|
L"SUPPORT",
|
|
L"WHAT'S NEW",
|
|
};
|
|
|
|
static const wchar_t *g_MfuIgnoreExes[]={
|
|
L"APPLAUNCH.EXE",
|
|
L"CONTROL.EXE",
|
|
L"DFSVC.EXE",
|
|
L"DLLHOST.EXE",
|
|
L"GUESTMODEMSG.EXE",
|
|
L"HH.EXE",
|
|
L"INSTALL.EXE",
|
|
L"ISUNINST.EXE",
|
|
L"LNKSTUB.EXE",
|
|
L"MMC.EXE",
|
|
L"MSHTA.EXE",
|
|
L"MSIEXEC.EXE",
|
|
L"MSOOBE.EXE",
|
|
L"RUNDLL32.EXE",
|
|
L"SETUP.EXE",
|
|
L"ST5UNST.EXE",
|
|
L"UNWISE.EXE",
|
|
L"UNWISE32.EXE",
|
|
L"WERFAULT.EXE",
|
|
L"WINHLP32.EXE",
|
|
L"WLRMDR.EXE",
|
|
L"WUAPP.EXE",
|
|
};
|
|
|
|
void CMenuContainer::GetRecentPrograms( std::vector<MenuItem> &items, int maxCount )
|
|
{
|
|
bool bShowMetro=GetSettingBool(L"RecentMetroApps");
|
|
const std::vector<MenuItem> &mainItems=s_Menus[0]->m_Items;
|
|
|
|
int iconSizeFlag=(!m_bSubMenu && s_Skin.Main_icon_size==MenuSkin::ICON_SIZE_LARGE)?CItemManager::INFO_LARGE_ICON:CItemManager::INFO_SMALL_ICON;
|
|
if (s_RecentPrograms==RECENT_PROGRAMS_RECENT)
|
|
{
|
|
for (int i=0;i<MRU_PROGRAMS_COUNT;i++)
|
|
{
|
|
if (s_MRUShortcuts[i].IsEmpty()) break;
|
|
CComPtr<IShellItem> pItem;
|
|
CAbsolutePidl pidl;
|
|
bool bApp=(wcsncmp(s_MRUShortcuts[i],L"APP:",4)==0);
|
|
if (bApp)
|
|
{
|
|
if (SUCCEEDED(SHCreateItemInKnownFolder(FOLDERID_AppsFolder2,0,(const wchar_t*)s_MRUShortcuts[i]+4,IID_IShellItem,(void**)&pItem)) && FAILED(SHGetIDListFromObject(pItem,&pidl)))
|
|
pItem=NULL;
|
|
}
|
|
else if (SUCCEEDED(MenuParseDisplayName(s_MRUShortcuts[i],&pidl,NULL,NULL)))
|
|
SHCreateItemFromIDList(pidl,IID_IShellItem,(void**)&pItem);
|
|
if (pItem)
|
|
{
|
|
CComString pName;
|
|
if (SUCCEEDED(pItem->GetDisplayName(SIGDN_NORMALDISPLAY,&pName)))
|
|
{
|
|
if (bApp && wcsncmp(pName,L"@{",2)==0)
|
|
continue;
|
|
// new item
|
|
MenuItem item(MENU_RECENT);
|
|
item.bLink=true;
|
|
int refreshFlags=CItemManager::INFO_LINK|CItemManager::INFO_LINK_APPID|CItemManager::INFO_METRO|iconSizeFlag;
|
|
item.pItemInfo=g_ItemManager.GetItemInfo(pItem,pidl,refreshFlags);
|
|
|
|
// see if it is already in the main menu
|
|
bool bFound=false;
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
for (std::vector<MenuItem>::const_iterator it=mainItems.begin();it!=mainItems.end();++it)
|
|
{
|
|
if (!it->pItemInfo) continue;
|
|
if (it->pItemInfo==item.pItemInfo)
|
|
{
|
|
bFound=true;
|
|
break;
|
|
}
|
|
if (!it->pItemInfo->IsLink() && !it->pItemInfo->IsMetroApp())
|
|
continue;
|
|
// if the item is an app, check if the link has the same target pidl
|
|
// if the item has appid, compare by appid. otherwise compare by target path (shouldn't happen)
|
|
if (bApp && it->pItemInfo->IsLink())
|
|
{
|
|
// for apps compare by pidl
|
|
if (ILIsEqual(pidl,it->pItemInfo->GetTargetPidl()))
|
|
{
|
|
bFound=true;
|
|
break;
|
|
}
|
|
}
|
|
else if (!item.pItemInfo->GetAppid().IsEmpty())
|
|
{
|
|
if (_wcsicmp(item.pItemInfo->GetAppid(),it->pItemInfo->GetAppid())==0)
|
|
{
|
|
bFound=true;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!item.pItemInfo->GetTargetPATH().IsEmpty() && wcscmp(item.pItemInfo->GetTargetPATH(),it->pItemInfo->GetTargetPATH())==0)
|
|
{
|
|
bFound=true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (bFound) continue;
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
if (item.pItemInfo->IsMetroApp() && !bShowMetro)
|
|
continue;
|
|
if (item.pItemInfo->IsMetroLink())
|
|
{
|
|
if (!bShowMetro) continue;
|
|
item.bMetroLink=true;
|
|
if (_wcsicmp(item.pItemInfo->GetAppid(),DESKTOP_APP_ID)==0)
|
|
continue;
|
|
if (item.pItemInfo->GetMetroName().IsEmpty())
|
|
item.SetName(pName,(m_Options&CONTAINER_NOEXTENSIONS)!=0);
|
|
else
|
|
item.SetName(item.pItemInfo->GetMetroName(),false);
|
|
}
|
|
else
|
|
item.SetName(pName,(m_Options&CONTAINER_NOEXTENSIONS)!=0);
|
|
item.bMetroApp=item.pItemInfo->IsMetroApp();
|
|
}
|
|
item.pItem1=pidl.Detach();
|
|
|
|
items.push_back(item);
|
|
}
|
|
}
|
|
if ((int)items.size()==maxCount)
|
|
break;
|
|
}
|
|
}
|
|
else if (s_RecentPrograms==RECENT_PROGRAMS_FREQUENT)
|
|
{
|
|
ULONGLONG curTime;
|
|
GetSystemTimeAsFileTime((FILETIME*)&curTime);
|
|
std::vector<UserAssistItem> uaItems;
|
|
CRegKey regKeyApp, regKeyLink;
|
|
if (regKeyApp.Open(HKEY_CURRENT_USER,USERASSIST_APPIDS_KEY,KEY_READ)!=ERROR_SUCCESS ||
|
|
regKeyLink.Open(HKEY_CURRENT_USER,USERASSIST_LINKS_KEY,KEY_READ)!=ERROR_SUCCESS)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"Failed to open UserAssist registry key");
|
|
return;
|
|
}
|
|
|
|
// collect links with positive rank from regKeyLink
|
|
for (int idx=0;;idx++)
|
|
{
|
|
UserAssistItem uaItem;
|
|
memset(&uaItem,0,sizeof(uaItem));
|
|
DWORD len=_countof(uaItem.name);
|
|
UserAssistData data;
|
|
memset(&data,0,sizeof(data));
|
|
DWORD size=sizeof(data);
|
|
DWORD type;
|
|
LONG res=RegEnumValue(regKeyLink,idx,uaItem.name,&len,NULL,&type,(BYTE*)&data,&size);
|
|
if (res==ERROR_NO_MORE_ITEMS)
|
|
break;
|
|
if (!*uaItem.name)
|
|
continue;
|
|
if (type!=REG_BINARY)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"Not binary: '%s'",uaItem.name);
|
|
continue;
|
|
}
|
|
if (size!=sizeof(data))
|
|
{
|
|
LOG_MENU(LOG_MFU,L"Wrong size (%d): '%s'",size,uaItem.name);
|
|
continue;
|
|
}
|
|
uaItem.mfuHash=CalcFNVHash(uaItem.name);
|
|
EncodeRot13(uaItem.name);
|
|
if (data.timestamp.dwLowDateTime==0 && data.timestamp.dwHighDateTime==0)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"Zero timestamp: '%s'",uaItem.name);
|
|
continue;
|
|
}
|
|
// determine rank
|
|
uaItem.rank=data.count/10.f;
|
|
float weight=0.95f;
|
|
for (int i=0, idx=data.last;i<_countof(data.history);i++,idx=(idx+9)%10,weight-=0.07f)
|
|
{
|
|
float h=data.history[idx];
|
|
if (h<0 || h>1) break;
|
|
uaItem.rank+=h*weight;
|
|
}
|
|
if (uaItem.rank==0)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"Zero rank: '%s'",uaItem.name);
|
|
continue;
|
|
}
|
|
|
|
// decode name
|
|
const wchar_t *ext=PathFindExtension(uaItem.name);
|
|
if (uaItem.name[0]=='{')
|
|
{
|
|
wchar_t *end=wcschr(uaItem.name+1,'}');
|
|
if (end && end[1]=='\\')
|
|
{
|
|
end[1]=0;
|
|
GUID guid;
|
|
HRESULT hr=CLSIDFromString(uaItem.name,&guid);
|
|
end[1]='\\';
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CComString pPath;
|
|
if (SUCCEEDED(SHGetKnownFolderPath(guid,KF_FLAG_DONT_VERIFY,NULL,&pPath)))
|
|
{
|
|
wchar_t path[_MAX_PATH];
|
|
Sprintf(path,_countof(path),L"%s%s",(const wchar_t*)pPath,end+1);
|
|
Strcpy(uaItem.name,_countof(uaItem.name),path);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
LOG_MENU(LOG_MFU,L"UserAssist: '%s', %d, %.3f",uaItem.name,data.count,uaItem.rank);
|
|
bool bIgnore=false;
|
|
wchar_t NAME[_MAX_PATH];
|
|
Strcpy(NAME,_countof(NAME),uaItem.name);
|
|
CharUpper(NAME);
|
|
uaItem.nameHash=CalcFNVHash(NAME);
|
|
for (std::vector<UserAssistItem>::const_iterator it=uaItems.begin();it!=uaItems.end();++it)
|
|
{
|
|
if (uaItem.nameHash==it->nameHash)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping: Already in list");
|
|
bIgnore=true;
|
|
break;
|
|
}
|
|
}
|
|
if (bIgnore) continue;
|
|
const wchar_t *fname=PathFindFileName(NAME);
|
|
for (int i=0;i<_countof(g_MfuIgnoreWords);i++)
|
|
if (wcswcs(fname,g_MfuIgnoreWords[i]))
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping: Contains bad word");
|
|
bIgnore=true;
|
|
break;
|
|
}
|
|
if (bIgnore) continue;
|
|
|
|
uaItem.pLinkInfo=g_ItemManager.GetItemInfo(uaItem.name,CItemManager::INFO_LINK|CItemManager::INFO_LINK_APPID|CItemManager::INFO_METRO|CItemManager::INFO_VALIDATE_FILE);
|
|
if (!uaItem.pLinkInfo)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping: File missing");
|
|
continue;
|
|
}
|
|
wchar_t appid[_MAX_PATH];
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
if (uaItem.pLinkInfo->GetLocation()!=CItemManager::LOCATION_START_MENU && uaItem.pLinkInfo->GetLocation()!=CItemManager::LOCATION_METRO && uaItem.pLinkInfo->GetLocation()!=CItemManager::LOCATION_GAMES)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping: Not from start menu");
|
|
continue;
|
|
}
|
|
if (uaItem.pLinkInfo->IsNoPin())
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping: No pin");
|
|
continue;
|
|
}
|
|
if (uaItem.pLinkInfo->GetAppid().IsEmpty())
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping: No AppId");
|
|
continue;
|
|
}
|
|
if (!uaItem.pLinkInfo->GetTargetPATH().IsEmpty())
|
|
{
|
|
const wchar_t *fname=PathFindFileName(uaItem.pLinkInfo->GetTargetPATH());
|
|
for (int i=0;i<_countof(g_MfuIgnoreExes);i++)
|
|
if (wcswcs(fname,g_MfuIgnoreExes[i]))
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping: Target contains bad word: '%s'",uaItem.pLinkInfo->GetTargetPATH());
|
|
bIgnore=true;
|
|
break;
|
|
}
|
|
}
|
|
if (uaItem.pLinkInfo->IsMetroLink())
|
|
{
|
|
if (!bShowMetro)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping: No show metro");
|
|
continue;
|
|
}
|
|
if (_wcsicmp(uaItem.pLinkInfo->GetAppid(),DESKTOP_APP_ID)==0)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping: Ignore desktop");
|
|
continue;
|
|
}
|
|
if (uaItem.pLinkInfo->GetMetroName().IsEmpty())
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping: No Metro name");
|
|
continue;
|
|
}
|
|
}
|
|
if (bIgnore) continue;
|
|
Strcpy(appid,_countof(appid),uaItem.pLinkInfo->GetAppid());
|
|
}
|
|
|
|
uaItem.timestamp=data.timestamp;
|
|
size=sizeof(data);
|
|
EncodeRot13(appid);
|
|
if (regKeyApp.QueryBinaryValue(appid,&data,&size)!=ERROR_SUCCESS)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping: Missing appid entry: '%s'",appid);
|
|
continue;
|
|
}
|
|
if (CompareFileTime(&uaItem.timestamp,&data.timestamp)<0)
|
|
uaItem.timestamp=data.timestamp;
|
|
|
|
{
|
|
float rank=data.count/10.f;
|
|
float weight=0.95f;
|
|
for (int i=0, idx=data.last;i<_countof(data.history);i++,idx=(idx+9)%10,weight-=0.07f)
|
|
{
|
|
float h=data.history[idx];
|
|
if (h<0 || h>1) break;
|
|
rank+=h*weight;
|
|
}
|
|
if (uaItem.rank<rank)
|
|
{
|
|
uaItem.rank=rank;
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Corrected rank: %.3f",rank);
|
|
}
|
|
}
|
|
|
|
uaItems.push_back(uaItem);
|
|
}
|
|
|
|
if (GetWinVersion()>=WIN_VER_WIN10 && bShowMetro)
|
|
{
|
|
// collect apps with positive rank from regKeyApp
|
|
for (int idx=0;;idx++)
|
|
{
|
|
UserAssistItem uaItem;
|
|
memset(&uaItem,0,sizeof(uaItem));
|
|
DWORD len=_countof(uaItem.name);
|
|
UserAssistData data;
|
|
memset(&data,0,sizeof(data));
|
|
DWORD size=sizeof(data);
|
|
DWORD type;
|
|
LONG res=RegEnumValue(regKeyApp,idx,uaItem.name,&len,NULL,&type,(BYTE*)&data,&size);
|
|
if (res==ERROR_NO_MORE_ITEMS)
|
|
break;
|
|
if (!*uaItem.name)
|
|
continue;
|
|
if (type!=REG_BINARY)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"Not binary: '%s'",uaItem.name);
|
|
continue;
|
|
}
|
|
if (size!=sizeof(data))
|
|
{
|
|
LOG_MENU(LOG_MFU,L"Wrong size (%d): '%s'",size,uaItem.name);
|
|
continue;
|
|
}
|
|
uaItem.mfuHash=CalcFNVHash(uaItem.name);
|
|
EncodeRot13(uaItem.name);
|
|
if (data.timestamp.dwLowDateTime==0 && data.timestamp.dwHighDateTime==0)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"Zero timestamp: '%s'",uaItem.name);
|
|
continue;
|
|
}
|
|
|
|
// determine rank
|
|
uaItem.rank=data.count/10.f;
|
|
float weight=0.95f;
|
|
for (int i=0, idx=data.last;i<_countof(data.history);i++,idx=(idx+9)%10,weight-=0.07f)
|
|
{
|
|
float h=data.history[idx];
|
|
if (h<0 || h>1) break;
|
|
uaItem.rank+=h*weight;
|
|
}
|
|
if (uaItem.rank==0)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"Zero rank: '%s'",uaItem.name);
|
|
continue;
|
|
}
|
|
|
|
if (_wcsicmp(uaItem.name,DESKTOP_APP_ID)==0)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping: Ignore desktop");
|
|
continue;
|
|
}
|
|
|
|
uaItem.pLinkInfo=g_ItemManager.GetMetroAppInfo10(uaItem.name);
|
|
if (!uaItem.pLinkInfo)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping '%s': Not a valid app",uaItem.name);
|
|
continue;
|
|
}
|
|
|
|
LOG_MENU(LOG_MFU,L"UserAssist: '%s', %d, %.3f",uaItem.name,data.count,uaItem.rank);
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
if (uaItem.pLinkInfo->GetMetroName().IsEmpty() || wcsncmp(uaItem.pLinkInfo->GetMetroName(), L"@{",2)==0)
|
|
{
|
|
LOG_MENU(LOG_MFU, L"UserAssist: Dropping: No metro name");
|
|
continue;
|
|
}
|
|
if (uaItem.pLinkInfo->IsNoPin())
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping: No pin");
|
|
continue;
|
|
}
|
|
if (uaItem.pLinkInfo->GetPackagePath().IsEmpty() || GetFileAttributes(uaItem.pLinkInfo->GetPackagePath())==INVALID_FILE_ATTRIBUTES)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping: Missing package path");
|
|
continue;
|
|
}
|
|
|
|
CAbsolutePidl pidl=uaItem.pLinkInfo->GetPidl();
|
|
|
|
// see if it is already in the main menu
|
|
bool bFound=false;
|
|
for (std::vector<MenuItem>::const_iterator it=mainItems.begin();it!=mainItems.end();++it)
|
|
{
|
|
if (!it->pItemInfo) continue;
|
|
if (!it->pItemInfo->IsLink()) continue;
|
|
if (ILIsEqual(pidl,it->pItemInfo->GetTargetPidl()))
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping '%s', already in main menu",uaItem.name);
|
|
bFound=true;
|
|
break;
|
|
}
|
|
}
|
|
if (bFound) continue;
|
|
}
|
|
|
|
uaItem.timestamp=data.timestamp;
|
|
uaItems.push_back(uaItem);
|
|
}
|
|
}
|
|
|
|
// sort by rank
|
|
std::sort(uaItems.begin(),uaItems.end());
|
|
|
|
g_ItemManager.WaitForShortcuts(CPoint((s_StartRect.left+s_StartRect.right)/2,(s_StartRect.top+s_StartRect.bottom)/2));
|
|
|
|
// create a menu item for each program
|
|
for (int i=0;i<(int)uaItems.size();i++)
|
|
{
|
|
UserAssistItem &uaItem=uaItems[i];
|
|
if (!uaItem.pLinkInfo) continue;
|
|
|
|
bool bMetroLink, bExplicitAppId, bMetroApp;
|
|
CString appid, targetPATH, metroName;
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
bMetroLink=uaItem.pLinkInfo->IsMetroLink();
|
|
bMetroApp=uaItem.pLinkInfo->IsMetroApp();
|
|
bExplicitAppId=uaItem.pLinkInfo->IsExplicitAppId();
|
|
appid=uaItem.pLinkInfo->GetAppid();
|
|
targetPATH=uaItem.pLinkInfo->GetTargetPATH();
|
|
if (bMetroLink)
|
|
metroName=uaItem.pLinkInfo->GetMetroName();
|
|
// clear all other items with the same link target
|
|
for (int j=i+1;j<(int)uaItems.size();j++)
|
|
{
|
|
UserAssistItem &uaItem2=uaItems[j];
|
|
if (!uaItem2.pLinkInfo) continue;
|
|
if (_wcsicmp(appid,uaItem2.pLinkInfo->GetAppid())==0)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping '%s', duplicate appid '%s'",uaItem2.name,appid);
|
|
uaItem2.pLinkInfo=NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bExplicitAppId)
|
|
{
|
|
CRegKey keyPin;
|
|
if (keyPin.Open(HKEY_LOCAL_MACHINE,L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileAssociation\\NoStartPageAppUserModelIDs",KEY_READ)==ERROR_SUCCESS)
|
|
{
|
|
if (keyPin.QueryValue(appid,NULL,NULL,NULL)==ERROR_SUCCESS)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping '%s', NoStartPageAppUserModelIDs",uaItem.name);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wchar_t text[1024];
|
|
{
|
|
Sprintf(text,_countof(text),L"Applications\\%s",PathFindFileName(targetPATH));
|
|
CRegKey keyPin;
|
|
if (keyPin.Open(HKEY_CLASSES_ROOT,text,KEY_READ)==ERROR_SUCCESS)
|
|
{
|
|
if (keyPin.QueryValue(L"NoStartPage",NULL,NULL,NULL)==ERROR_SUCCESS)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping '%s', NoStartPage",uaItem.name);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if (wcschr(appid,'\\'))
|
|
{
|
|
Sprintf(text,_countof(text),L"Applications\\%s",PathFindFileName(appid));
|
|
CRegKey keyPin;
|
|
if (keyPin.Open(HKEY_CLASSES_ROOT,text,KEY_READ)==ERROR_SUCCESS)
|
|
{
|
|
if (keyPin.QueryValue(L"NoStartPage",NULL,NULL,NULL)==ERROR_SUCCESS)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping '%s', NoStartPage",uaItem.name);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// see if it is in the taskbar
|
|
if (!bMetroLink && g_ItemManager.IsTaskbarPinned(appid))
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping '%s', pinned to taskbar",uaItem.name);
|
|
continue;
|
|
}
|
|
// see if it is already in the main menu
|
|
bool bFound=false;
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
for (std::vector<MenuItem>::const_iterator it=mainItems.begin();it!=mainItems.end();++it)
|
|
{
|
|
if (!it->pItemInfo) continue;
|
|
if (it->pItemInfo==uaItem.pLinkInfo)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping '%s', already in main menu",uaItem.name);
|
|
bFound=true;
|
|
break;
|
|
}
|
|
if (!it->pItemInfo->IsLink() && !it->pItemInfo->IsMetroApp())
|
|
continue;
|
|
if (_wcsicmp(appid,it->pItemInfo->GetAppid())==0)
|
|
{
|
|
LOG_MENU(LOG_MFU,L"UserAssist: Dropping '%s', already in main menu",uaItem.name);
|
|
bFound=true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (bFound) continue;
|
|
|
|
MenuItem item(MENU_RECENT);
|
|
item.bLink=true;
|
|
item.pItemInfo=uaItem.pLinkInfo;
|
|
item.mfuHash=uaItem.mfuHash;
|
|
item.bMetroLink=bMetroLink;
|
|
item.bMetroApp=bMetroApp;
|
|
g_ItemManager.UpdateItemInfo(uaItem.pLinkInfo,iconSizeFlag);
|
|
CComPtr<IShellItem> pItem;
|
|
if (bMetroLink)
|
|
{
|
|
item.SetName(metroName,false);
|
|
item.pItem1=ILCloneFull(uaItem.pLinkInfo->GetPidl());
|
|
items.push_back(item);
|
|
}
|
|
else if (item.name.IsEmpty() && SUCCEEDED(SHCreateItemFromIDList(uaItem.pLinkInfo->GetPidl(),IID_IShellItem,(void**)&pItem)))
|
|
{
|
|
CComString pName;
|
|
if (SUCCEEDED(pItem->GetDisplayName(SIGDN_NORMALDISPLAY,&pName)))
|
|
{
|
|
item.SetName(pName,(m_Options&CONTAINER_NOEXTENSIONS)!=0);
|
|
item.pItem1=ILCloneFull(uaItem.pLinkInfo->GetPidl());
|
|
items.push_back(item);
|
|
}
|
|
}
|
|
|
|
if ((int)items.size()==maxCount)
|
|
break;
|
|
}
|
|
}
|
|
|
|
TRecentKeys recentKeys=(TRecentKeys)GetSettingInt(L"RecentProgKeys");
|
|
for (int idx=0;idx<(int)items.size();idx++)
|
|
{
|
|
MenuItem &item=items[idx];
|
|
item.mruOrder=idx;
|
|
if (recentKeys==RECENT_KEYS_DIGITS)
|
|
item.name.Replace(L"&",L"&&");
|
|
if (idx<10)
|
|
{
|
|
if (recentKeys>=RECENT_KEYS_DIGITS)
|
|
{
|
|
item.accelerator=((idx+1)%10)+'0';
|
|
item.bCustomAccelerator=true;
|
|
}
|
|
if (recentKeys==RECENT_KEYS_DIGITS)
|
|
{
|
|
CString str=item.name;
|
|
item.name.Format(L"&%d %s",(idx+1)%10,str);
|
|
item.nameOffset=item.name.GetLength()-str.GetLength();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CMenuContainer::ClearItems( const std::vector<MenuItem>::iterator &begin, const std::vector<MenuItem>::iterator &end )
|
|
{
|
|
for (std::vector<MenuItem>::iterator it=begin;it!=end;++it)
|
|
{
|
|
if (it->pItem1) ILFree(it->pItem1);
|
|
if (it->pItem2) ILFree(it->pItem2);
|
|
}
|
|
if (s_pDragSource==this && m_Items.begin()+m_DragIndex>=begin)
|
|
s_pDragSource=NULL; // freeing the dragged item
|
|
m_Items.erase(begin,end);
|
|
}
|
|
|
|
void CMenuContainer::AddJumpListItems( std::vector<MenuItem> &items )
|
|
{
|
|
s_JumpList.Clear();
|
|
g_ItemManager.UpdateItemInfo(s_JumpAppInfo,CItemManager::INFO_LINK_APPID);
|
|
CString appid;
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
appid=s_JumpAppInfo->GetAppid();
|
|
}
|
|
if (!appid.IsEmpty())
|
|
{
|
|
int maxHeight=65536, sepHeight=0, itemHeight=0;
|
|
if (s_bWin7Style)
|
|
{
|
|
itemHeight=s_Skin.ItemSettings[MenuSkin::LIST_ITEM].itemHeight;
|
|
sepHeight=s_Skin.ItemSettings[MenuSkin::LIST_SEPARATOR].itemHeight;
|
|
maxHeight=m_Items[m_OriginalCount-1].itemRect.top-s_Skin.Main_jump_padding.top;
|
|
}
|
|
GetJumplist(appid,s_JumpList,GetSettingInt(L"MaxJumplists"),maxHeight,sepHeight,itemHeight);
|
|
}
|
|
|
|
for (int g=0;g<(int)s_JumpList.groups.size();g++)
|
|
{
|
|
const CJumpGroup &group=s_JumpList.groups[g];
|
|
if (group.bHidden) continue;
|
|
{
|
|
MenuItem item(MENU_SEPARATOR);
|
|
item.SetName(group.name,false);
|
|
items.push_back(item);
|
|
}
|
|
for (int i=0;i<(int)group.items.size();i++)
|
|
{
|
|
const CJumpItem &jumpItem=group.items[i];
|
|
if (jumpItem.bHidden) continue;
|
|
|
|
MenuItem item(MENU_NO);
|
|
if (jumpItem.type==CJumpItem::TYPE_LINK)
|
|
{
|
|
item.SetName(jumpItem.name,false);
|
|
CComQIPtr<IShellLink> pLink(jumpItem.pItem);
|
|
if (pLink)
|
|
{
|
|
pLink->GetIDList(&item.pItem1);
|
|
item.pItemInfo = g_ItemManager.GetLinkIcon(pLink, CItemManager::ICON_SIZE_TYPE_SMALL);
|
|
}
|
|
}
|
|
else if (jumpItem.type==CJumpItem::TYPE_ITEM)
|
|
{
|
|
item.SetName(jumpItem.name,false);
|
|
CComQIPtr<IShellItem> pItem(jumpItem.pItem);
|
|
if (pItem)
|
|
SHGetIDListFromObject(pItem,&item.pItem1);
|
|
}
|
|
else if (jumpItem.type==CJumpItem::TYPE_SEPARATOR)
|
|
{
|
|
item.id=MENU_SEPARATOR;
|
|
}
|
|
item.bSplit=(jumpItem.type!=CJumpItem::TYPE_SEPARATOR && group.type!=CJumpGroup::TYPE_TASKS);
|
|
if (item.pItem1 && !item.pItemInfo)
|
|
{
|
|
CComPtr<IShellItem> pItem;
|
|
if (SUCCEEDED(SHCreateItemFromIDList(item.pItem1,IID_IShellItem,(void**)&pItem)))
|
|
{
|
|
// do some pidl laundering. sometimes the pidls from the jumplists may contain weird hidden data, which affects the icon
|
|
// so do a round-trip convertion of the pidl to a display name
|
|
CComString pName;
|
|
if (SUCCEEDED(pItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,&pName)))
|
|
{
|
|
CComPtr<IShellItem> pItem2;
|
|
CAbsolutePidl pidl2;
|
|
if (SUCCEEDED(MenuParseDisplayName(pName,&pidl2,NULL,NULL)) && SUCCEEDED(SHCreateItemFromIDList(pidl2,IID_IShellItem,(void**)&pItem2)))
|
|
{
|
|
int order;
|
|
if (SUCCEEDED(pItem->Compare(pItem2,SICHINT_CANONICAL,&order)) && order==0)
|
|
{
|
|
ILFree(item.pItem1);
|
|
item.pItem1=pidl2.Detach();
|
|
pItem=pItem2;
|
|
}
|
|
}
|
|
}
|
|
item.pItemInfo=g_ItemManager.GetItemInfo(pItem,item.pItem1,CItemManager::INFO_SMALL_ICON);
|
|
}
|
|
}
|
|
item.jumpIndex=MAKELONG(g,i);
|
|
items.push_back(item);
|
|
#ifdef REPEAT_JUMPLIST_ITEMS
|
|
for (int i=0;i<REPEAT_JUMPLIST_ITEMS;i++)
|
|
{
|
|
item.pItem1=ILCloneFull(item.pItem1);
|
|
items.push_back(item);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (items.empty() || (m_bTwoColumns && items.size()==m_OriginalCount))
|
|
{
|
|
// add (Empty) item to the empty submenus
|
|
MenuItem item(MENU_EMPTY);
|
|
item.name=FindTranslation(L"Menu.Empty",L"(Empty)");
|
|
items.push_back(item);
|
|
}
|
|
}
|
|
|
|
// Initialize the m_Items list
|
|
void CMenuContainer::InitItems( void )
|
|
{
|
|
ClearItems(m_Items.begin(),m_Items.end());
|
|
m_pShellView=NULL;
|
|
m_RefreshPosted=0;
|
|
m_bRefreshItems=false;
|
|
SetSubmenu(-1);
|
|
SetContextItem(-1);
|
|
s_HotPos=GetMessagePos();
|
|
m_ScrollCount=0;
|
|
m_SearchScrollCount=0;
|
|
m_SearchScrollHeight=0;
|
|
m_SearchScrollPos=0;
|
|
m_SearchIndex=-1;
|
|
|
|
if (m_Options&CONTAINER_JUMPLIST)
|
|
{
|
|
AddJumpListItems(m_Items);
|
|
m_ScrollCount=0;
|
|
if (m_Items.size()>0 && m_Items[0].id!=MENU_EMPTY)
|
|
m_ScrollCount=(int)m_Items.size();
|
|
m_OriginalScrollCount=m_ScrollCount;
|
|
UpdateAccelerators(0,(int)m_Items.size());
|
|
return;
|
|
}
|
|
|
|
if ((m_Options&CONTAINER_DOCUMENTS) && s_MaxRecentDocuments>0) // create the recent documents list
|
|
{
|
|
Assert(m_Path1[0] && !m_Path2[0]);
|
|
|
|
// find all documents
|
|
|
|
// with many recent files it takes a long time to go through the IShellFolder enumeration
|
|
// so use FindFirstFile directly
|
|
wchar_t recentPath[_MAX_PATH];
|
|
SHGetPathFromIDList(m_Path1[0],recentPath);
|
|
wchar_t find[_MAX_PATH];
|
|
Sprintf(find,_countof(find),L"%s\\*.lnk",recentPath);
|
|
|
|
std::vector<Document> docs;
|
|
|
|
WIN32_FIND_DATA data;
|
|
HANDLE h=FindFirstFile(find,&data);
|
|
while (h!=INVALID_HANDLE_VALUE)
|
|
{
|
|
Document doc;
|
|
doc.name.Format(L"%s\\%s",recentPath,data.cFileName);
|
|
doc.time=data.ftLastWriteTime;
|
|
docs.push_back(doc);
|
|
if (!FindNextFile(h,&data))
|
|
{
|
|
FindClose(h);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// sort by time
|
|
std::sort(docs.begin(),docs.end());
|
|
|
|
size_t count=0;
|
|
CComPtr<IShellLink> pLink;
|
|
if (SUCCEEDED(pLink.CoCreateInstance(CLSID_ShellLink)))
|
|
{
|
|
CComQIPtr<IPersistFile> pFile(pLink);
|
|
if (pFile)
|
|
{
|
|
// go through the items until we find s_MaxRecentDocuments documents
|
|
for (std::vector<Document>::const_iterator it=docs.begin();it!=docs.end();++it)
|
|
{
|
|
wchar_t path[_MAX_PATH];
|
|
// find the target of the lnk file
|
|
if (SUCCEEDED(pFile->Load(it->name,STGM_READ)) && SUCCEEDED(pLink->GetPath(path,_countof(path),&data,0)))
|
|
{
|
|
// check if it is link to a file or directory
|
|
if (path[0] && !(data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY))
|
|
{
|
|
CAbsolutePidl pidl;
|
|
MenuParseDisplayName(it->name,&pidl,NULL,NULL);
|
|
CComPtr<IShellItem> pItem;
|
|
CComString pName;
|
|
if (pidl && SUCCEEDED(SHCreateItemFromIDList(pidl,IID_IShellItem,(void**)&pItem)) && SUCCEEDED(pItem->GetDisplayName(SIGDN_NORMALDISPLAY,&pName)))
|
|
{
|
|
if (_wcsicmp(PathFindExtension(pName),L".lnk")==0)
|
|
continue;
|
|
MenuItem item(MENU_NO);
|
|
item.pItem1=pidl.Detach();
|
|
item.pItemInfo=g_ItemManager.GetItemInfo(pItem,item.pItem1,CItemManager::INFO_SMALL_ICON);
|
|
item.SetName(pName,(m_Options&CONTAINER_NOEXTENSIONS)!=0);
|
|
|
|
m_Items.push_back(item);
|
|
count++;
|
|
if ((int)count>=s_MaxRecentDocuments) break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((m_Options&CONTAINER_APPS) && GetWinVersion()>=WIN_VER_WIN8)
|
|
{
|
|
std::vector<MetroLink> links;
|
|
GetMetroLinks(links,true);
|
|
|
|
for (std::vector<MetroLink>::iterator it=links.begin();it!=links.end();++it)
|
|
{
|
|
const CItemManager::ItemInfo *pInfo=g_ItemManager.GetItemInfo(it->pItem,it->pidl,CItemManager::INFO_METRO|CItemManager::INFO_SMALL_ICON);
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
if (_wcsicmp(pInfo->GetAppid(),DESKTOP_APP_ID)==0)
|
|
continue;
|
|
CString name;
|
|
if (pInfo->IsMetroLink())
|
|
name=pInfo->GetMetroName();
|
|
else
|
|
{
|
|
CComString pName;
|
|
if (FAILED(it->pItem->GetDisplayName(SIGDN_NORMALDISPLAY,&pName)))
|
|
continue;
|
|
if (wcsncmp(pName,L"@{",2)==0)
|
|
continue; // bad name
|
|
name=pName;
|
|
}
|
|
MenuItem item(MENU_NO);
|
|
item.SetName(name,false);
|
|
StringUpper(name);
|
|
item.nameHash=CalcFNVHash(name);
|
|
item.pItemInfo=pInfo;
|
|
item.pItem1=it->pidl.Detach();
|
|
item.bMetroLink=pInfo->IsMetroLink();
|
|
item.bMetroApp=item.pItemInfo->IsMetroApp();
|
|
m_Items.push_back(item);
|
|
}
|
|
}
|
|
|
|
// add first folder
|
|
if (!(m_Options&CONTAINER_DOCUMENTS) && !(m_Options&CONTAINER_APPS))
|
|
{
|
|
if (m_Path1[0])
|
|
{
|
|
CComPtr<IShellItem> pItem;
|
|
if (SUCCEEDED(SHCreateItemFromIDList(m_Path1[0],IID_IShellItem,(void**)&pItem)))
|
|
{
|
|
pItem->BindToHandler(NULL,BHID_SFViewObject,IID_IShellView,(void**)&m_pShellView);
|
|
m_pDropFolder[0]=pItem;
|
|
CComString pName;
|
|
if (SUCCEEDED(pItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,&pName)))
|
|
{
|
|
pName.MakeUpper();
|
|
m_FolderHash[0]=CalcFNVHash(pName);
|
|
}
|
|
AddFirstFolder(pItem,m_Items,m_Options);
|
|
}
|
|
}
|
|
|
|
// add second folder
|
|
if (m_Path2[0])
|
|
{
|
|
CComPtr<IShellItem> pItem;
|
|
if (SUCCEEDED(SHCreateItemFromIDList(m_Path2[0],IID_IShellItem,(void**)&pItem)))
|
|
{
|
|
CComString pName;
|
|
if (SUCCEEDED(pItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,&pName)))
|
|
{
|
|
pName.MakeUpper();
|
|
m_FolderHash[0]=CalcFNVHash(pName,m_FolderHash[0]);
|
|
}
|
|
AddSecondFolder(pItem,m_Items,m_Options);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_Options&CONTAINER_ALLPROGRAMS)
|
|
{
|
|
std::vector<MenuItem> items;
|
|
if (m_Path1[1])
|
|
{
|
|
CComPtr<IShellItem> pItem;
|
|
if (SUCCEEDED(SHCreateItemFromIDList(m_Path1[1],IID_IShellItem,(void**)&pItem)))
|
|
{
|
|
m_pDropFolder[1]=pItem;
|
|
CComString pName;
|
|
if (SUCCEEDED(pItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,&pName)))
|
|
{
|
|
pName.MakeUpper();
|
|
m_FolderHash[1]=CalcFNVHash(pName);
|
|
}
|
|
AddFirstFolder(pItem,items,m_Options);
|
|
}
|
|
}
|
|
|
|
// add second folder
|
|
if (m_Path2[1])
|
|
{
|
|
CComPtr<IShellItem> pItem;
|
|
if (SUCCEEDED(SHCreateItemFromIDList(m_Path2[1],IID_IShellItem,(void**)&pItem)))
|
|
{
|
|
CComString pName;
|
|
if (SUCCEEDED(pItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,&pName)))
|
|
{
|
|
pName.MakeUpper();
|
|
m_FolderHash[1]=CalcFNVHash(pName,m_FolderHash[1]);
|
|
}
|
|
AddSecondFolder(pItem,items,m_Options);
|
|
}
|
|
}
|
|
if (!items.empty())
|
|
{
|
|
if (!m_Items.empty())
|
|
{
|
|
MenuItem item(MENU_SEPARATOR);
|
|
item.priority=1;
|
|
m_Items.push_back(item);
|
|
}
|
|
for (std::vector<MenuItem>::iterator it=items.begin();it!=items.end();++it)
|
|
it->priority=2;
|
|
m_Items.insert(m_Items.end(),items.begin(),items.end());
|
|
}
|
|
}
|
|
|
|
// sort m_Items or read order from the registry
|
|
LoadItemOrder();
|
|
|
|
if (m_Items.size()>MAX_MENU_ITEMS)
|
|
{
|
|
for (size_t i=MAX_MENU_ITEMS;i<m_Items.size();i++)
|
|
{
|
|
if (m_Items[i].pItem1) ILFree(m_Items[i].pItem1);
|
|
if (m_Items[i].pItem2) ILFree(m_Items[i].pItem2);
|
|
}
|
|
m_Items.resize(MAX_MENU_ITEMS);
|
|
}
|
|
|
|
if (m_Options&CONTAINER_CONTROLPANEL)
|
|
{
|
|
// expand Administrative Tools. must be done after the sorting because we don't want the folder to jump to the top
|
|
unsigned int AdminToolsHash=CalcFNVHash(L"::{D20EA4E1-3957-11D2-A40B-0C5020524153}");
|
|
for (std::vector<MenuItem>::iterator it=m_Items.begin();it!=m_Items.end();++it)
|
|
if (it->nameHash==AdminToolsHash)
|
|
{
|
|
it->bFolder=true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (m_Items.empty() && m_Path1[0] && m_pDropFolder[0])
|
|
{
|
|
// add (Empty) item to the empty submenus
|
|
MenuItem item(m_bSubMenu?MENU_EMPTY:MENU_EMPTY_TOP);
|
|
item.name=FindTranslation(L"Menu.Empty",L"(Empty)");
|
|
m_Items.push_back(item);
|
|
}
|
|
|
|
if (!m_bSubMenu)
|
|
{
|
|
for (std::vector<MenuItem>::iterator it=m_Items.begin();it!=m_Items.end();++it)
|
|
{
|
|
MenuItem &item=*it;
|
|
if (item.bLink && !item.bFolder && item.pItem1)
|
|
g_ItemManager.UpdateItemInfo(item.pItemInfo,CItemManager::INFO_LINK_APPID);
|
|
}
|
|
}
|
|
|
|
if (m_Options&CONTAINER_RECENT)
|
|
{
|
|
int nRecent=GetSettingInt(L"MaxRecentPrograms");
|
|
if (nRecent<0)
|
|
nRecent=-nRecent;
|
|
if (nRecent>MRU_PROGRAMS_COUNT) nRecent=MRU_PROGRAMS_COUNT;
|
|
if (nRecent>0)
|
|
{
|
|
// prepend recent programs
|
|
std::vector<MenuItem> items;
|
|
GetRecentPrograms(items,nRecent);
|
|
if (!items.empty())
|
|
{
|
|
MenuItem item(MENU_SEPARATOR);
|
|
if (GetSettingBool(L"RecentProgsTop"))
|
|
{
|
|
items.push_back(item);
|
|
m_Items.insert(m_Items.begin(),items.begin(),items.end());
|
|
}
|
|
else
|
|
{
|
|
m_Items.push_back(item);
|
|
m_Items.insert(m_Items.end(),items.begin(),items.end());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!m_bSubMenu && GetSettingBool(L"EnableJumplists"))
|
|
{
|
|
for (std::vector<MenuItem>::iterator it=m_Items.begin();it!=m_Items.end();++it)
|
|
{
|
|
MenuItem &item=*it;
|
|
if (item.bLink && !item.bFolder && item.pItem1)
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
item.bFolder=(!item.pItemInfo->GetAppid().IsEmpty() && HasJumplist(item.pItemInfo->GetAppid()));
|
|
item.bHasJumpList=item.bFolder;
|
|
item.bSplit=item.bFolder;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_ScrollCount=(int)m_Items.size();
|
|
if (m_ScrollCount>0 && m_Items[m_ScrollCount-1].id==MENU_PROGRAMS_TREE)
|
|
m_ScrollCount--;
|
|
|
|
if (s_bWin7Style && !m_bSubMenu && GetSettingInt(L"ProgramsStyle")!=PROGRAMS_HIDDEN)
|
|
{
|
|
MenuItem item(MENU_PROGRAMS_TREE);
|
|
m_Items.push_back(item);
|
|
}
|
|
AddStandardItems();
|
|
|
|
// remove trailing separators
|
|
while (!m_Items.empty() && m_Items[m_Items.size()-1].id==MENU_SEPARATOR && !m_Items[m_Items.size()-1].bInline)
|
|
m_Items.pop_back();
|
|
|
|
if (m_Items.empty())
|
|
{
|
|
// add (Empty) item to the empty submenus
|
|
MenuItem item(MENU_EMPTY);
|
|
item.name=FindTranslation(L"Menu.Empty",L"(Empty)");
|
|
m_Items.push_back(item);
|
|
}
|
|
|
|
if (m_bSubMenu)
|
|
{
|
|
m_ScrollCount=(int)m_Items.size();
|
|
m_SearchIndex=-1;
|
|
for (int i=0;i<(int)m_Items.size();i++)
|
|
{
|
|
if (m_Items[i].id==MENU_SEARCH_BOX)
|
|
m_SearchIndex=i;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_ProgramButtonIndex=m_ProgramTreeIndex=-1;
|
|
m_SearchIndex=-1;
|
|
for (int i=0;i<(int)m_Items.size();i++)
|
|
{
|
|
if (m_Items[i].id==MENU_PROGRAMS_TREE)
|
|
m_ProgramTreeIndex=i;
|
|
if (m_Items[i].id==MENU_PROGRAMS)
|
|
m_ProgramButtonIndex=i;
|
|
if (m_Items[i].id==MENU_SEARCH_BOX)
|
|
m_SearchIndex=i;
|
|
}
|
|
m_SearchItemCount=1;
|
|
if (s_bWin7Style)
|
|
m_SearchItemCount=m_SearchProvidersCount+2;
|
|
}
|
|
|
|
m_OriginalCount=(int)m_Items.size();
|
|
m_OriginalScrollCount=m_ScrollCount;
|
|
UpdateAccelerators(0,m_OriginalCount);
|
|
}
|
|
|
|
int CMenuContainer::AddSearchItems( const std::vector<SearchItem> &items, const CString &categoryName, unsigned int categoryHash, int originalCount )
|
|
{
|
|
if (m_Items.size()>MAX_MENU_ITEMS-2)
|
|
return 0;
|
|
bool bFirst=true;
|
|
int count=0;
|
|
for (std::vector<SearchItem>::const_iterator it=items.begin();it!=items.end();++it)
|
|
{
|
|
CComPtr<IShellItem> pItem;
|
|
if (FAILED(SHCreateItemFromIDList(it->info->GetPidl(),IID_IShellItem,(void**)&pItem)))
|
|
continue;
|
|
|
|
CComString pName;
|
|
if (SUCCEEDED(pItem->GetDisplayName(categoryHash==CSearchManager::CATEGORY_AUTOCOMPLETE?SIGDN_PARENTRELATIVEEDITING:SIGDN_NORMALDISPLAY,&pName)))
|
|
{
|
|
if (bFirst)
|
|
{
|
|
bFirst=false;
|
|
if (!categoryName.IsEmpty())
|
|
{
|
|
MenuItem item(MENU_SEARCH_CATEGORY);
|
|
item.name.Format(L"%s (%d)",categoryName,originalCount);
|
|
item.nameHash=CalcFNVHash(categoryName);
|
|
item.categoryHash=categoryHash;
|
|
if (categoryHash!=CSearchManager::CATEGORY_PROGRAM || categoryHash!=CSearchManager::CATEGORY_SETTING)
|
|
item.bSplit=(s_Skin.More_bitmap_Size.cx>0);
|
|
m_Items.push_back(item);
|
|
}
|
|
}
|
|
|
|
MenuItem item(MENU_NO);
|
|
item.categoryHash=categoryHash;
|
|
item.pItemInfo=it->info;
|
|
g_ItemManager.UpdateItemInfo(it->info,CItemManager::INFO_SMALL_ICON);
|
|
bool bMetroLink, bMetroApp;
|
|
CString metroName;
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
bMetroLink=item.pItemInfo->IsMetroLink();
|
|
bMetroApp=item.pItemInfo->IsMetroApp();
|
|
if (bMetroLink)
|
|
metroName=item.pItemInfo->GetMetroName();
|
|
}
|
|
if (!it->name.IsEmpty())
|
|
item.SetName(it->name,false);
|
|
else if (bMetroLink && !metroName.IsEmpty())
|
|
item.SetName(metroName,false);
|
|
else
|
|
item.SetName(pName,(m_Options&CONTAINER_NOEXTENSIONS)!=0);
|
|
item.bMetroLink=bMetroLink;
|
|
item.bMetroApp=bMetroApp;
|
|
item.pItem1=ILCloneFull(it->info->GetPidl());
|
|
wchar_t name[_MAX_PATH];
|
|
Strcpy(name,_countof(name),item.name);
|
|
CharUpper(name);
|
|
item.nameHash=CalcFNVHash(name,categoryHash);
|
|
m_Items.push_back(item);
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
// Initialize the m_Items list with the search results
|
|
bool CMenuContainer::InitSearchItems( void )
|
|
{
|
|
if (m_bSubMenu)
|
|
ClearItems(m_Items.begin(),m_Items.end());
|
|
else
|
|
ClearItems(m_Items.begin()+m_OriginalCount,m_Items.end());
|
|
m_RefreshPosted=0;
|
|
SetSubmenu(-1);
|
|
SetContextItem(-1);
|
|
s_HotPos=GetMessagePos();
|
|
m_ScrollCount=0;
|
|
g_SearchManager.GetSearchResults(s_SearchResults);
|
|
bool bAutoComlpete=!s_SearchResults.autoCompletePath.IsEmpty();
|
|
m_SearchScrollCount=0;
|
|
m_SearchScrollHeight=0;
|
|
m_SearchScrollPos=0;
|
|
unsigned int runCategoryHash=0;
|
|
CString runCommand;
|
|
CComString runExe;
|
|
if (!bAutoComlpete && !s_bNoRun && s_SearchResults.programs.empty() && s_SearchResults.settings.empty() && s_SearchResults.metrosettings.empty())
|
|
{
|
|
if (s_bWin7Style)
|
|
m_SearchBox.GetWindowText(runCommand);
|
|
else
|
|
m_pParent->m_SearchBox.GetWindowText(runCommand);
|
|
|
|
// validate execute item
|
|
if (_wcsnicmp(runCommand,L"www.",4)==0 || _wcsnicmp(runCommand,L"http:",5)==0)
|
|
runCategoryHash=CSearchManager::CATEGORY_INTERNET;
|
|
else if (_wcsnicmp(runCommand,L"shell:",6)==0)
|
|
{
|
|
CAbsolutePidl pidl;
|
|
if (SUCCEEDED(SHParseDisplayName(runCommand,NULL,&pidl,0,NULL)))
|
|
runCategoryHash=CSearchManager::CATEGORY_PROGRAM;
|
|
}
|
|
else if (wcsncmp(runCommand,L"\\\\",2)!=0 && SUCCEEDED(SHEvaluateSystemCommandTemplate(runCommand,&runExe,NULL,NULL)))
|
|
runCategoryHash=CSearchManager::CATEGORY_PROGRAM;
|
|
if (runCategoryHash)
|
|
s_SearchResults.programs.push_back(NULL);
|
|
}
|
|
std::vector<SearchItem> items;
|
|
std::vector<int> counts;
|
|
int sepHeight=0, itemHeight=0, maxHeight=0, reservedHeight=0;
|
|
int maxCount=0;
|
|
if (s_bWin7Style)
|
|
{
|
|
sepHeight=s_Skin.ItemSettings[s_Skin.More_bitmap_Size.cx?MenuSkin::LIST_SEPARATOR_SPLIT:MenuSkin::LIST_SEPARATOR].itemHeight;
|
|
itemHeight=s_Skin.ItemSettings[MenuSkin::LIST_ITEM].itemHeight;
|
|
// total height minus the search box and the "more results"/"search internet"
|
|
maxHeight=m_Items[m_SearchIndex].itemRect.top-s_Skin.Main_search_padding.top-s_Skin.Search_padding.top;
|
|
maxHeight-=itemHeight*(m_SearchItemCount-1);
|
|
if (!s_SearchResults.bSearching && !HasMoreResults())
|
|
maxHeight+=itemHeight;
|
|
}
|
|
if (bAutoComlpete)
|
|
{
|
|
items.reserve(s_SearchResults.autocomplete.size());
|
|
for (std::vector<const CItemManager::ItemInfo*>::const_iterator it=s_SearchResults.autocomplete.begin();it!=s_SearchResults.autocomplete.end() && (int)items.size()<MAX_MENU_ITEMS;++it)
|
|
items.push_back(SearchItem(*it));
|
|
int count=AddSearchItems(items,L"",CSearchManager::CATEGORY_AUTOCOMPLETE,0);
|
|
if (s_bWin7Style)
|
|
{
|
|
m_SearchScrollHeight=maxHeight/itemHeight;
|
|
m_SearchScrollCount=count;
|
|
}
|
|
}
|
|
if (s_bWin7Style)
|
|
{
|
|
// calculate the allowed counts per category
|
|
int selectedCount=0;
|
|
if (!s_SearchResults.programs.empty())
|
|
{
|
|
counts.push_back((int)s_SearchResults.programs.size());
|
|
if (m_SearchCategoryHash==CSearchManager::CATEGORY_PROGRAM)
|
|
selectedCount=(int)s_SearchResults.programs.size();
|
|
}
|
|
if (!s_SearchResults.metrosettings.empty())
|
|
{
|
|
counts.push_back((int)s_SearchResults.metrosettings.size());
|
|
if (m_SearchCategoryHash==CSearchManager::CATEGORY_METROSETTING)
|
|
selectedCount=(int)s_SearchResults.metrosettings.size();
|
|
}
|
|
if (!s_SearchResults.settings.empty())
|
|
{
|
|
counts.push_back((int)s_SearchResults.settings.size());
|
|
if (m_SearchCategoryHash==CSearchManager::CATEGORY_SETTING)
|
|
selectedCount=(int)s_SearchResults.settings.size();
|
|
}
|
|
for (std::list<CSearchManager::SearchCategory>::const_iterator it=s_SearchResults.indexed.begin();it!=s_SearchResults.indexed.end();++it)
|
|
{
|
|
if (!it->items.empty())
|
|
{
|
|
counts.push_back((int)it->items.size());
|
|
if (m_SearchCategoryHash==it->categoryHash)
|
|
selectedCount=(int)it->items.size();
|
|
}
|
|
}
|
|
|
|
int n=(int)counts.size();
|
|
if (n>0)
|
|
{
|
|
int totalCount=(maxHeight-n*sepHeight)/itemHeight;
|
|
maxCount=1;
|
|
if (totalCount>n)
|
|
{
|
|
std::sort(counts.begin(),counts.end());
|
|
for (int i=0;i<n;i++)
|
|
{
|
|
if (counts[i]*(n-i)<=totalCount)
|
|
{
|
|
maxCount=counts[i];
|
|
totalCount-=maxCount;
|
|
}
|
|
else
|
|
{
|
|
maxCount=(totalCount+n-i-1)/(n-i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (maxCount<3) maxCount=3;
|
|
|
|
reservedHeight=selectedCount>0?(sepHeight+selectedCount*itemHeight):0;
|
|
if (reservedHeight>maxHeight) reservedHeight=maxHeight;
|
|
maxHeight-=reservedHeight;
|
|
}
|
|
}
|
|
|
|
// add categories
|
|
std::list<CSearchManager::SearchCategory>::const_iterator it=s_SearchResults.indexed.begin();
|
|
for (size_t idx=0;idx<s_SearchResults.indexed.size()+3;idx++)
|
|
{
|
|
items.clear();
|
|
unsigned int categoryHash;
|
|
if (idx==0)
|
|
categoryHash=CSearchManager::CATEGORY_PROGRAM;
|
|
else if (idx==1)
|
|
categoryHash=CSearchManager::CATEGORY_METROSETTING;
|
|
else if (idx==2)
|
|
categoryHash=CSearchManager::CATEGORY_SETTING;
|
|
else
|
|
categoryHash=it->categoryHash;
|
|
|
|
int count=0;
|
|
if (s_bWin7Style)
|
|
{
|
|
int h=(categoryHash==m_SearchCategoryHash?reservedHeight:maxHeight);
|
|
count=(h-sepHeight)/itemHeight;
|
|
if (categoryHash!=m_SearchCategoryHash && count>maxCount)
|
|
count=maxCount;
|
|
}
|
|
else
|
|
{
|
|
count=GetSettingInt(categoryHash==m_SearchCategoryHash?L"SearchResultsMax":L"SearchResults");
|
|
}
|
|
if (count<=0)
|
|
{
|
|
if (idx>=3) ++it;
|
|
continue;
|
|
}
|
|
|
|
const wchar_t *name;
|
|
int originalCount=0;
|
|
if (idx==0)
|
|
{
|
|
originalCount=(int)s_SearchResults.programs.size();
|
|
if (count>originalCount)
|
|
count=originalCount;
|
|
items.reserve(count);
|
|
for (std::vector<const CItemManager::ItemInfo*>::const_iterator it=s_SearchResults.programs.begin();it!=s_SearchResults.programs.end() && (int)items.size()<count;++it)
|
|
items.push_back(SearchItem(*it));
|
|
name=FindTranslation(L"Search.CategoryPrograms",L"Programs");
|
|
}
|
|
else if (idx==1)
|
|
{
|
|
originalCount=(int)s_SearchResults.metrosettings.size();
|
|
if (count>originalCount)
|
|
count=originalCount;
|
|
items.reserve(count);
|
|
for (std::vector<const CItemManager::ItemInfo*>::const_iterator it=s_SearchResults.metrosettings.begin();it!=s_SearchResults.metrosettings.end() && (int)items.size()<count;++it)
|
|
items.push_back(SearchItem(*it));
|
|
name=FindTranslation(L"Search.CategoryPCSettings", L"Modern Settings");
|
|
}
|
|
else if (idx==2)
|
|
{
|
|
originalCount=(int)s_SearchResults.settings.size();
|
|
if (count>originalCount)
|
|
count=originalCount;
|
|
items.reserve(count);
|
|
for (std::vector<const CItemManager::ItemInfo*>::const_iterator it=s_SearchResults.settings.begin();it!=s_SearchResults.settings.end() && (int)items.size()<count;++it)
|
|
items.push_back(SearchItem(*it));
|
|
name=FindTranslation(L"Search.CategorySettings",L"Settings");
|
|
}
|
|
else
|
|
{
|
|
originalCount=(int)it->items.size();
|
|
if (count>originalCount)
|
|
count=originalCount;
|
|
items.reserve(count);
|
|
for (int i=0;i<count;i++)
|
|
{
|
|
PIDLIST_ABSOLUTE pidl=it->items[i].pidl;
|
|
CComPtr<IShellItem> pItem;
|
|
if (SUCCEEDED(SHCreateItemFromIDList(pidl,IID_IShellItem,(void**)&pItem)))
|
|
items.push_back(SearchItem(it->items[i].name,g_ItemManager.GetItemInfo(pItem,pidl,0)));
|
|
}
|
|
name=it->name;
|
|
++it;
|
|
}
|
|
if (items.empty())
|
|
continue;
|
|
if (idx==0 && runCategoryHash)
|
|
{
|
|
MenuItem item1(MENU_SEARCH_CATEGORY);
|
|
item1.categoryHash=runCategoryHash;
|
|
item1.name=runCategoryHash==CSearchManager::CATEGORY_INTERNET?FindTranslation(L"Search.CategoryInternet",L"Internet"):FindTranslation(L"Search.CategoryPrograms",L"Programs");
|
|
item1.nameHash=CalcFNVHash(item1.name);
|
|
m_Items.push_back(item1);
|
|
|
|
MenuItem item2(MENU_SEARCH_EXECUTE);
|
|
item2.name=runCommand;
|
|
if (runCategoryHash==CSearchManager::CATEGORY_INTERNET)
|
|
item2.pItemInfo=GetInternetIcon(true);
|
|
else if (runExe)
|
|
{
|
|
item2.pItemInfo=g_ItemManager.GetItemInfo(CString(runExe),CItemManager::INFO_SMALL_ICON);
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
item2.pItem1=ILCloneFull(item2.pItemInfo->GetPidl());
|
|
}
|
|
else
|
|
item2.pItemInfo=g_ItemManager.GetCustomIcon(L"imageres.dll,100",CItemManager::ICON_SIZE_TYPE_SMALL);
|
|
m_Items.push_back(item2);
|
|
count=1;
|
|
}
|
|
else
|
|
{
|
|
count=AddSearchItems(items,name,categoryHash,originalCount);
|
|
}
|
|
if (s_bWin7Style && categoryHash!=m_SearchCategoryHash && count>0)
|
|
maxHeight-=sepHeight+count*itemHeight;
|
|
}
|
|
if (s_bWin7Style)
|
|
{
|
|
UpdateAccelerators(m_OriginalCount,(int)m_Items.size());
|
|
MenuItem &item=m_Items[m_SearchIndex-m_SearchItemCount+1];
|
|
if (s_SearchResults.bSearching)
|
|
{
|
|
item.id=MENU_SEARCH_EMPTY;
|
|
item.name=FindTranslation(L"Menu.Searching",L"Searching...");
|
|
item.pItemInfo=g_ItemManager.GetCustomIcon(L"imageres.dll,8",CItemManager::ICON_SIZE_TYPE_SMALL);
|
|
}
|
|
else
|
|
{
|
|
item.id=MENU_MORE_RESULTS;
|
|
item.name=FindTranslation(L"Menu.MoreResults",L"See more results");
|
|
item.pItemInfo=g_ItemManager.GetCustomIcon(L"imageres.dll,177",CItemManager::ICON_SIZE_TYPE_SMALL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_ScrollCount=(int)m_Items.size();
|
|
bool bInternet=GetSettingBool(L"SearchInternet");
|
|
if (s_SearchResults.bSearching)
|
|
{
|
|
MenuItem item(MENU_SEARCH_EMPTY);
|
|
item.name=FindTranslation(L"Menu.Searching",L"Searching...");
|
|
item.pItemInfo=g_ItemManager.GetCustomIcon(L"imageres.dll,8",CItemManager::ICON_SIZE_TYPE_SMALL);
|
|
m_Items.push_back(item);
|
|
}
|
|
else
|
|
{
|
|
if (m_Items.empty())
|
|
{
|
|
MenuItem item(MENU_SEARCH_EMPTY);
|
|
item.name=FindTranslation(L"Menu.NoMatch",L"No items match your search.");
|
|
m_Items.push_back(item);
|
|
}
|
|
if (HasMoreResults())
|
|
{
|
|
{
|
|
MenuItem item(MENU_SEPARATOR);
|
|
m_Items.push_back(item);
|
|
}
|
|
MenuItem item(MENU_MORE_RESULTS);
|
|
item.name=FindTranslation(L"Menu.MoreResults",L"See more results");
|
|
item.pItemInfo=g_ItemManager.GetCustomIcon(L"imageres.dll,177",CItemManager::ICON_SIZE_TYPE_SMALL);
|
|
m_Items.push_back(item);
|
|
}
|
|
else if (bInternet)
|
|
{
|
|
MenuItem item(MENU_SEPARATOR);
|
|
m_Items.push_back(item);
|
|
}
|
|
if (bInternet)
|
|
AddInternetSearch(m_Items.size());
|
|
}
|
|
AddStandardItems();
|
|
UpdateAccelerators(m_ScrollCount,(int)m_Items.size());
|
|
}
|
|
|
|
if (!s_SearchResults.bSearching && (m_Items.empty() || (m_bTwoColumns && m_Items.size()==m_OriginalCount)))
|
|
{
|
|
MenuItem item(MENU_SEARCH_EMPTY);
|
|
item.name=FindTranslation(L"Menu.NoMatch",L"No items match your search.");
|
|
m_Items.push_back(item);
|
|
}
|
|
return s_SearchResults.bSearching;
|
|
}
|
|
|
|
HBITMAP CMenuContainer::GetArrowsBitmap( unsigned int color )
|
|
{
|
|
if (!s_ArrowsBitmap)
|
|
{
|
|
int id=s_Skin.Dpi>=144?IDB_ARROWS150:IDB_ARROWS;
|
|
s_ArrowsBitmap=(HBITMAP)LoadImage(g_Instance,MAKEINTRESOURCE(id),IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION);
|
|
s_LastArrowColor=0xFFFFFF;
|
|
}
|
|
if (s_LastArrowColor!=color)
|
|
{
|
|
s_LastArrowColor=color;
|
|
color=0xFF000000|(color<<16)|(color&0xFF00)|((color>>16)&0xFF);
|
|
BITMAP info;
|
|
GetObject(s_ArrowsBitmap,sizeof(info),&info);
|
|
int n=info.bmWidth*info.bmHeight;
|
|
for (int p=0;p<n;p++)
|
|
{
|
|
unsigned int &pixel=((unsigned int*)info.bmBits)[p];
|
|
pixel=((pixel>>24)*0x01010101)&color;
|
|
}
|
|
}
|
|
return s_ArrowsBitmap;
|
|
}
|
|
|
|
// Calculate the size and create the background bitmaps
|
|
void CMenuContainer::InitWindow( bool bDontShrink )
|
|
{
|
|
POINT corner;
|
|
RECT rc;
|
|
GetWindowRect(&rc);
|
|
corner.x=(m_Options&CONTAINER_LEFT)?rc.left:rc.right;
|
|
corner.y=(m_Options&CONTAINER_TOP)?rc.top:rc.bottom;
|
|
RECT menuRect;
|
|
InitWindowInternal(bDontShrink,corner,menuRect);
|
|
InitWindowFinalize(menuRect);
|
|
}
|
|
|
|
void CMenuContainer::InitWindowInternal( bool bDontShrink, const POINT &corner, RECT &menuRect )
|
|
{
|
|
bool bRecentReverse=GetSettingInt(L"MaxRecentPrograms")<0;
|
|
bool bRecentByName=GetSettingBool(L"RecentSortName");
|
|
|
|
int firstRecent=-1, lastRecent=-1;
|
|
if ((bRecentReverse || bRecentByName) && (!m_bSubMenu || (m_Options&CONTAINER_RECENT)))
|
|
{
|
|
for (int i=0;i<(int)m_Items.size();i++)
|
|
{
|
|
if (m_Items[i].id==MENU_RECENT)
|
|
{
|
|
if (firstRecent==-1) firstRecent=i;
|
|
lastRecent=i+1;
|
|
}
|
|
else if (firstRecent!=-1)
|
|
break;
|
|
}
|
|
if (firstRecent>=0)
|
|
std::sort(m_Items.begin()+firstRecent,m_Items.begin()+lastRecent,MenuItem::MruOrderComparator());
|
|
}
|
|
|
|
m_bTwoColumns=(!m_bSubMenu && s_Skin.TwoColumns);
|
|
if (!m_pParent && !s_Theme && IsAppThemed())
|
|
{
|
|
s_Theme=OpenThemeData(m_hWnd,L"toolbar");
|
|
s_PagerTheme=OpenThemeData(m_hWnd,L"scrollbar");
|
|
}
|
|
if (!m_pParent && !s_Tooltip.m_hWnd)
|
|
{
|
|
s_Tooltip=CreateWindowEx(WS_EX_TOPMOST|WS_EX_TOOLWINDOW|WS_EX_TRANSPARENT|(s_bRTL?WS_EX_LAYOUTRTL:0),TOOLTIPS_CLASS,NULL,WS_POPUP|TTS_NOPREFIX|TTS_ALWAYSTIP,0,0,0,0,NULL,NULL,g_Instance,NULL);
|
|
s_Tooltip.SendMessage(TTM_SETMAXTIPWIDTH,0,500);
|
|
TOOLINFO tool={sizeof(tool),TTF_ABSOLUTE|TTF_TRACK|TTF_TRANSPARENT|(s_bRTL?TTF_RTLREADING:0U)};
|
|
tool.uId=1;
|
|
s_Tooltip.SendMessage(TTM_ADDTOOL,0,(LPARAM)&tool);
|
|
}
|
|
RECT menuPadding[2];
|
|
if (m_bSubMenu)
|
|
{
|
|
menuPadding[0]=s_Skin.Submenu_padding;
|
|
memset(&menuPadding[1],0,sizeof(menuPadding[1]));
|
|
}
|
|
else if (s_MenuMode==MODE_SEARCH)
|
|
{
|
|
menuPadding[0]=s_Skin.Main_search_padding;
|
|
memset(&menuPadding[1],0,sizeof(menuPadding[1]));
|
|
}
|
|
else if (s_MenuMode==MODE_JUMPLIST)
|
|
{
|
|
menuPadding[0]=s_Skin.Main_padding;
|
|
menuPadding[1]=s_Skin.Main_jump_padding;
|
|
}
|
|
else
|
|
{
|
|
menuPadding[0]=s_Skin.Main_padding;
|
|
menuPadding[1]=s_Skin.Main2_padding;
|
|
}
|
|
|
|
// calculate maximum height
|
|
int maxHeight[2]; // excluding padding
|
|
int maxWidth=m_MaxWidth;
|
|
int borderHeight=0;
|
|
{
|
|
const RECT &mainRect=m_bSubMenu?s_MenuLimits:s_MainMenuLimits;
|
|
maxHeight[0]=maxHeight[1]=(mainRect.bottom-mainRect.top);
|
|
// adjust for padding
|
|
RECT rc={0,0,0,0};
|
|
AdjustWindowRect(&rc,GetWindowLong(GWL_STYLE),FALSE);
|
|
maxWidth-=rc.right-rc.left;
|
|
maxWidth-=menuPadding[0].left+menuPadding[0].right;
|
|
if (m_bSubMenu)
|
|
{
|
|
borderHeight=rc.bottom;
|
|
maxHeight[0]-=menuPadding[0].top+menuPadding[0].bottom;
|
|
}
|
|
else
|
|
{
|
|
if (m_Options&CONTAINER_TOP)
|
|
maxHeight[0]=maxHeight[1]=mainRect.bottom-corner.y;
|
|
else
|
|
maxHeight[0]=maxHeight[1]=corner.y-mainRect.top;
|
|
maxHeight[0]-=rc.bottom-rc.top;
|
|
maxHeight[1]-=rc.bottom-rc.top;
|
|
maxHeight[0]-=menuPadding[0].top+menuPadding[0].bottom;
|
|
maxHeight[1]-=menuPadding[1].top+menuPadding[1].bottom;
|
|
if (s_UserPicture.m_hWnd && !(m_Options&CONTAINER_TOP) && s_Skin.User_bitmap_outside)
|
|
{
|
|
maxHeight[0]-=s_Skin.User_bitmapSize.cy-s_Skin.User_frame_position.x;
|
|
maxHeight[1]-=s_Skin.User_bitmapSize.cy-s_Skin.User_frame_position.x;
|
|
}
|
|
}
|
|
}
|
|
#ifdef _DEBUG
|
|
// maxHeight[0]/=3; maxHeight[1]/=3; // uncomment to test for smaller screen
|
|
#endif
|
|
|
|
HDC hdc=CreateCompatibleDC(NULL);
|
|
int arrowSize[2];
|
|
if (m_bSubMenu)
|
|
{
|
|
const MenuSkin::ItemDrawSettings &settings=s_Skin.ItemSettings[MenuSkin::SUBMENU_ITEM];
|
|
arrowSize[0]=settings.arrPadding.cx+settings.arrPadding.cy;
|
|
if (m_Options&CONTAINER_JUMPLIST)
|
|
arrowSize[0]+=s_Skin.Pin_bitmap_Size.cx;
|
|
else
|
|
arrowSize[0]+=settings.arrSize.cx;
|
|
}
|
|
else
|
|
{
|
|
const MenuSkin::ItemDrawSettings &settings=s_Skin.ItemSettings[MenuSkin::COLUMN1_ITEM];
|
|
arrowSize[0]=settings.arrPadding.cx+settings.arrPadding.cy+settings.arrSize.cx;
|
|
}
|
|
{
|
|
const MenuSkin::ItemDrawSettings &settings=s_Skin.ItemSettings[MenuSkin::COLUMN2_ITEM];
|
|
arrowSize[1]=settings.arrPadding.cx+settings.arrPadding.cy+settings.arrSize.cx;
|
|
}
|
|
int expandoSize=s_Skin.GetArrowsBitmapSizes()[6].y;
|
|
|
|
HGDIOBJ font0=GetCurrentObject(hdc,OBJ_FONT);
|
|
int fixedWidth[2]={-1,-1};
|
|
int maxItemWidth[2]={65536,65536};
|
|
if (m_bSubMenu)
|
|
{
|
|
int numChar=GetSettingInt(L"MaxMenuWidth");
|
|
maxItemWidth[0]=numChar?s_Skin.ItemSettings[MenuSkin::SUBMENU_ITEM].textMetrics.tmAveCharWidth*numChar:65536;
|
|
}
|
|
else
|
|
{
|
|
int numChar=GetSettingInt(L"MaxMainMenuWidth");
|
|
int width=s_Skin.ItemSettings[MenuSkin::COLUMN1_ITEM].textMetrics.tmAveCharWidth;
|
|
maxItemWidth[0]=numChar?width*numChar:65536;
|
|
maxItemWidth[1]=numChar?s_Skin.ItemSettings[MenuSkin::COLUMN2_ITEM].textMetrics.tmAveCharWidth*numChar:65536;
|
|
if (s_bWin7Style)
|
|
{
|
|
if (s_MenuMode==MODE_SEARCH)
|
|
{
|
|
fixedWidth[0]=s_MenuWidthNormal-s_Skin.Main_search_padding.left-s_Skin.Main_search_padding.right;
|
|
fixedWidth[1]=0;
|
|
maxItemWidth[0]=65536;
|
|
}
|
|
else if (s_MenuMode==MODE_JUMPLIST)
|
|
{
|
|
fixedWidth[0]=width*s_ProgramsWidth;
|
|
fixedWidth[1]=width*s_JumplistWidth;
|
|
maxItemWidth[0]=65536;
|
|
maxItemWidth[1]=65536;
|
|
}
|
|
else
|
|
{
|
|
fixedWidth[0]=width*s_ProgramsWidth;
|
|
maxItemWidth[0]=65536;
|
|
maxItemWidth[1]=65536;
|
|
}
|
|
}
|
|
s_MenuWidthJump=width*(s_ProgramsWidth+s_JumplistWidth)+s_Skin.Main_padding.left+s_Skin.Main_padding.right+s_Skin.Main_jump_padding.left+s_Skin.Main_jump_padding.right;
|
|
}
|
|
m_ScrollButtonSize=s_Skin.ItemSettings[m_bSubMenu?MenuSkin::SUBMENU_ITEM:MenuSkin::COLUMN1_ITEM].itemHeight;
|
|
if (!s_bHasTouch)
|
|
m_ScrollButtonSize/=2;
|
|
if (m_ScrollButtonSize<MIN_SCROLL_HEIGHT) m_ScrollButtonSize=MIN_SCROLL_HEIGHT;
|
|
|
|
// calculate item sizes
|
|
std::vector<int> columnWidths;
|
|
columnWidths.push_back(0);
|
|
|
|
bool bMultiColumn=s_ScrollMenus!=0 && (m_Options&CONTAINER_MULTICOLUMN);
|
|
int shutdownIndex=-1;
|
|
|
|
{
|
|
int row=0, column=0, subColumn=0;
|
|
int y=0;
|
|
int maxw=0;
|
|
int index=0;
|
|
for (int i=0;i<(int)m_Items.size();i++)
|
|
{
|
|
MenuItem &item=m_Items[i];
|
|
|
|
if (m_bTwoColumns && column==0 && i>0 && item.bBreak)
|
|
{
|
|
// start a new column
|
|
column++;
|
|
columnWidths.push_back(0);
|
|
row=0;
|
|
y=0;
|
|
if (s_UserPicture.m_hWnd)
|
|
{
|
|
if (!s_Skin.User_bitmap_outside || (m_Options&CONTAINER_TOP))
|
|
y=s_Skin.User_bitmapSize.cy+s_Skin.User_image_padding.x+s_Skin.User_image_padding.y;
|
|
else
|
|
y=s_Skin.User_frame_position.x+s_Skin.User_image_padding.y-menuPadding[0].top;
|
|
}
|
|
index=1;
|
|
}
|
|
item.bNew=false;
|
|
if (m_bTwoColumns && i<m_OriginalCount && s_MenuMode!=MODE_NORMAL && (i<=m_SearchIndex-m_SearchItemCount || i>m_SearchIndex) && item.id!=MENU_SHUTDOWN_BUTTON)
|
|
{
|
|
// hide original items based on mode
|
|
if (s_MenuMode==MODE_JUMPLIST)
|
|
{
|
|
if (column==1)
|
|
{
|
|
item.itemRect.top=item.itemRect.bottom=0;
|
|
continue;
|
|
}
|
|
}
|
|
if (s_MenuMode==MODE_SEARCH)
|
|
{
|
|
item.itemRect.top=item.itemRect.bottom=0;
|
|
continue;
|
|
}
|
|
}
|
|
if (i==m_OriginalCount)
|
|
{
|
|
y=0;
|
|
row=0;
|
|
column=index=(s_MenuMode==MODE_JUMPLIST)?1:0;
|
|
if (column==1 && columnWidths.size()==1)
|
|
columnWidths.push_back(0);
|
|
}
|
|
if (item.id!=MENU_RECENT && !(m_Options&CONTAINER_SEARCH) && s_Skin.bHasNewItem && i<m_OriginalCount)
|
|
{
|
|
if (item.id==MENU_PROGRAMS)
|
|
{
|
|
if (s_bWin7Style && GetWinVersion()>=WIN_VER_WIN8 && GetSettingBool(L"AllProgramsMetro"))
|
|
item.bNew=g_ItemManager.HasNewPrograms(false) || g_ItemManager.HasNewApps(false);
|
|
else
|
|
item.bNew=g_ItemManager.HasNewPrograms(false);
|
|
}
|
|
else if (item.id==MENU_APPS)
|
|
item.bNew=g_ItemManager.HasNewApps(false);
|
|
else if (item.bFolder)
|
|
item.bNew=(item.pItem1 && g_ItemManager.IsNewProgram(item.pItem1,true,false)) || (item.pItem2 && g_ItemManager.IsNewProgram(item.pItem2,true,false));
|
|
else if (item.pItemInfo)
|
|
item.bNew=(item.pItem1 && g_ItemManager.IsNewProgram(item.pItem1,false,item.bMetroApp));
|
|
}
|
|
if (item.id==MENU_SHUTDOWN_BUTTON)
|
|
{
|
|
if (s_MenuMode==MODE_SEARCH)
|
|
item.drawType=MenuSkin::SHUTDOWN_BUTTON_SEARCH;
|
|
else if (s_MenuMode==MODE_JUMPLIST)
|
|
item.drawType=MenuSkin::SHUTDOWN_BUTTON_JUMP;
|
|
else
|
|
item.drawType=MenuSkin::SHUTDOWN_BUTTON;
|
|
}
|
|
else if (s_bWin7Style && item.id==MENU_SEARCH_CATEGORY)
|
|
{
|
|
item.drawType=(item.bSplit)?MenuSkin::LIST_SEPARATOR_SPLIT:MenuSkin::LIST_SEPARATOR;
|
|
}
|
|
else if (s_bWin7Style && item.id==MENU_PROGRAMS)
|
|
{
|
|
if (GetSettingInt(L"ProgramsStyle")==PROGRAMS_INLINE)
|
|
item.drawType=item.bNew?MenuSkin::PROGRAMS_BUTTON_NEW:MenuSkin::PROGRAMS_BUTTON;
|
|
else
|
|
item.drawType=item.bNew?MenuSkin::PROGRAMS_CASCADING_NEW:MenuSkin::PROGRAMS_CASCADING;
|
|
}
|
|
else if (s_bWin7Style && m_bTwoColumns && (s_MenuMode==MODE_SEARCH || s_MenuMode==MODE_JUMPLIST) && i>=m_OriginalCount)
|
|
{
|
|
if (item.id==MENU_SEPARATOR)
|
|
item.drawType=MenuSkin::LIST_SEPARATOR;
|
|
else if (item.jumpIndex<0)
|
|
item.drawType=MenuSkin::LIST_ITEM;
|
|
else
|
|
item.drawType=(s_JumpList.groups[LOWORD(item.jumpIndex)].type==CJumpGroup::TYPE_TASKS)?MenuSkin::LIST_ITEM:MenuSkin::LIST_SPLIT;
|
|
}
|
|
else if (s_bWin7Style && (i>m_SearchIndex-m_SearchItemCount && i<m_SearchIndex))
|
|
{
|
|
item.drawType=MenuSkin::LIST_ITEM;
|
|
}
|
|
else if (m_bTwoColumns && index==1)
|
|
{
|
|
if (item.bInline) item.drawType=MenuSkin::COLUMN2_INLINE;
|
|
else if (item.id==MENU_SEPARATOR) item.drawType=MenuSkin::COLUMN2_SEPARATOR;
|
|
else if (item.bSplit) item.drawType=MenuSkin::COLUMN2_SPLIT;
|
|
else if (item.bNew) item.drawType=MenuSkin::COLUMN2_NEW;
|
|
else item.drawType=MenuSkin::COLUMN2_ITEM;
|
|
}
|
|
else if (m_bSubMenu)
|
|
{
|
|
if (item.id==MENU_SEPARATOR) item.drawType=MenuSkin::SUBMENU_SEPARATOR;
|
|
else if (item.id==MENU_SEARCH_CATEGORY) item.drawType=(item.bSplit)?MenuSkin::SUBMENU_SEPARATOR_SPLIT:MenuSkin::SUBMENU_SEPARATOR;
|
|
else if (item.bSplit) item.drawType=MenuSkin::SUBMENU_SPLIT;
|
|
else if (item.bNew) item.drawType=MenuSkin::SUBMENU_NEW;
|
|
else item.drawType=MenuSkin::SUBMENU_ITEM;
|
|
}
|
|
else
|
|
{
|
|
if (item.id==MENU_SEPARATOR) item.drawType=MenuSkin::COLUMN1_SEPARATOR;
|
|
else if (item.bSplit) item.drawType=MenuSkin::COLUMN1_SPLIT;
|
|
else if (item.bNew) item.drawType=MenuSkin::COLUMN1_NEW;
|
|
else item.drawType=MenuSkin::COLUMN1_ITEM;
|
|
}
|
|
const MenuSkin::ItemDrawSettings &settings=s_Skin.ItemSettings[item.drawType];
|
|
|
|
SelectObject(hdc,settings.font);
|
|
int w=0, h=0;
|
|
int iconSize=0;
|
|
if (settings.iconSize==MenuSkin::ICON_SIZE_SMALL)
|
|
iconSize=g_ItemManager.SMALL_ICON_SIZE;
|
|
else if (settings.iconSize==MenuSkin::ICON_SIZE_LARGE)
|
|
iconSize=g_ItemManager.LARGE_ICON_SIZE;
|
|
if (item.id==MENU_PROGRAMS_TREE)
|
|
h=0; // hide it for now
|
|
else if (!s_bShowTopEmpty && m_Items.size()>1 && (m_Items[i].id==MENU_EMPTY_TOP || (i>0 && m_Items[i-1].id==MENU_EMPTY_TOP)))
|
|
h=0; // this is the first (Empty) item in the top menu. hide it for now
|
|
else if (item.bInline)
|
|
{
|
|
h=iconSize+settings.iconPadding.top+settings.iconPadding.bottom;
|
|
w=iconSize+settings.iconPadding.left+settings.iconPadding.right;
|
|
}
|
|
else if ((item.id==MENU_SEPARATOR || item.id==MENU_SEARCH_CATEGORY) && !item.bBlankSeparator)
|
|
{
|
|
if (!item.name.IsEmpty())
|
|
{
|
|
h=settings.itemHeight;
|
|
RECT rcText={0,0,0,0};
|
|
DrawText(hdc,item.name,-1,&rcText,DT_CALCRECT|DT_SINGLELINE|DT_HIDEPREFIX);
|
|
w=rcText.right;
|
|
if (w>maxItemWidth[index]) w=maxItemWidth[index];
|
|
int textEnd=w;
|
|
w+=settings.textPadding.left+settings.textPadding.right+arrowSize[index];
|
|
int textStart=settings.textPadding.left;
|
|
if (item.id==MENU_SEARCH_CATEGORY)
|
|
{
|
|
w+=settings.iconPadding.left+settings.iconPadding.right+expandoSize;
|
|
textStart+=settings.iconPadding.left+settings.iconPadding.right+expandoSize;
|
|
if (item.bSplit)
|
|
w+=settings.arrPadding.cx+settings.arrPadding.cy+s_Skin.More_bitmap_Size.cx+1;
|
|
}
|
|
textEnd+=textStart;
|
|
item.textStart=(short)textStart;
|
|
item.textEnd=(short)textEnd;
|
|
}
|
|
else if (y>0 || (i>0 && i==m_ProgramTreeIndex+1))
|
|
h=settings.sepHeight;
|
|
else
|
|
h=0; // ignore separators at the top of the column
|
|
}
|
|
else if (item.id==MENU_SEARCH_BOX)
|
|
{
|
|
h=settings.textMetrics.tmHeight*12/8+s_Skin.Search_padding.top+s_Skin.Search_padding.bottom; // 12 DLUs
|
|
w=settings.textMetrics.tmAveCharWidth*25;
|
|
}
|
|
else if (s_bWin7Style && i>m_SearchIndex-m_SearchItemCount && i<m_SearchIndex && (s_MenuMode!=MODE_SEARCH || (item.id==MENU_MORE_RESULTS && !HasMoreResults())))
|
|
{
|
|
h=0;
|
|
}
|
|
else if (item.id==MENU_SHUTDOWN_BUTTON)
|
|
{
|
|
shutdownIndex=i;
|
|
RECT rcText={0,0,0,0};
|
|
DrawText(hdc,item.name,-1,&rcText,DT_CALCRECT|DT_HIDEPREFIX|DT_SINGLELINE);
|
|
w=rcText.right;
|
|
if (s_bHasUpdates)
|
|
w+=settings.iconPadding.left+settings.iconPadding.right+s_Skin.Shutdown_bitmap_Size.cx;
|
|
if (w<settings.textMetrics.tmAveCharWidth*6)
|
|
w=settings.textMetrics.tmAveCharWidth*6;
|
|
w+=s_Skin.Shutdown_padding.left+s_Skin.Shutdown_padding.right+settings.textPadding.left+settings.textPadding.right+
|
|
settings.arrPadding.cx+settings.arrPadding.cy+settings.arrSize.cx;
|
|
h=s_Skin.Shutdown_padding.top+s_Skin.Shutdown_padding.bottom+settings.itemHeight;
|
|
}
|
|
else if (s_bWin7Style && item.id==MENU_PROGRAMS)
|
|
{
|
|
if (GetSettingInt(L"ProgramsStyle")!=PROGRAMS_HIDDEN)
|
|
h=settings.itemHeight;
|
|
else
|
|
h=0;
|
|
w=fixedWidth[0];
|
|
}
|
|
else
|
|
{
|
|
h=settings.itemHeight;
|
|
RECT rcText={0,0,0,0};
|
|
DrawText(hdc,item.name,-1,&rcText,DT_CALCRECT|DT_SINGLELINE|(item.id==MENU_NO?DT_NOPREFIX:DT_HIDEPREFIX));
|
|
w=rcText.right;
|
|
if (w>maxItemWidth[index]) w=maxItemWidth[index];
|
|
w+=settings.iconPadding.left+settings.iconPadding.right+settings.textPadding.left+settings.textPadding.right+arrowSize[index]+iconSize;
|
|
}
|
|
if (bMultiColumn && y>0 && y+h>maxHeight[0])
|
|
{
|
|
if (item.id==MENU_SEPARATOR && !item.bBlankSeparator && !item.bInline)
|
|
h=0; // ignore separators at the bottom of the column
|
|
else
|
|
{
|
|
// start a new column
|
|
column++;
|
|
columnWidths.push_back(0);
|
|
row=0;
|
|
y=0;
|
|
}
|
|
}
|
|
else if (item.id==MENU_SEPARATOR && !item.bBlankSeparator && !item.bInline && m_bTwoColumns && column==0 && i+1<(int)m_Items.size() && m_Items[i+1].bBreak)
|
|
h=0;
|
|
item.row=row;
|
|
item.column=column;
|
|
item.itemRect.top=y;
|
|
item.itemRect.bottom=y+h;
|
|
item.itemRect.left=0;
|
|
if (item.bInline)
|
|
{
|
|
if (item.bInlineFirst)
|
|
{
|
|
subColumn=0;
|
|
}
|
|
else
|
|
{
|
|
item.row=row=row-1;
|
|
item.itemRect.top-=h;
|
|
item.itemRect.bottom-=h;
|
|
h=0;
|
|
}
|
|
item.itemRect.left=w*subColumn;
|
|
if (item.id==MENU_SEPARATOR)
|
|
{
|
|
w=0;
|
|
subColumn--;
|
|
}
|
|
subColumn++;
|
|
}
|
|
item.itemRect.right=item.itemRect.left+w;
|
|
if (columnWidths[column]<item.itemRect.right)
|
|
columnWidths[column]=item.itemRect.right;
|
|
y+=h;
|
|
row++;
|
|
}
|
|
}
|
|
|
|
SelectObject(hdc,font0);
|
|
DeleteDC(hdc);
|
|
|
|
if (columnWidths.size()==1)
|
|
{
|
|
if (s_bWin7Style && !m_bSubMenu)
|
|
columnWidths.push_back(0);
|
|
else
|
|
m_bTwoColumns=false;
|
|
}
|
|
else if (columnWidths.size()==2 && s_bWin7Style && !m_bSubMenu && columnWidths[1]<CItemManager::EXTRA_LARGE_ICON_SIZE)
|
|
columnWidths[1]=CItemManager::EXTRA_LARGE_ICON_SIZE;
|
|
|
|
// calculate width of each column
|
|
if (!m_bTwoColumns && GetSettingBool(L"SameSizeColumns"))
|
|
{
|
|
int maxw=0;
|
|
for (size_t i=0;i<columnWidths.size();i++)
|
|
if (maxw<columnWidths[i])
|
|
maxw=columnWidths[i];
|
|
for (size_t i=0;i<columnWidths.size();i++)
|
|
columnWidths[i]=maxw;
|
|
}
|
|
if (bDontShrink && columnWidths[0]<m_rContent.right-m_rContent.left)
|
|
columnWidths[0]=m_rContent.right-m_rContent.left;
|
|
if (s_bWin7Style)
|
|
{
|
|
if (fixedWidth[0]>=0)
|
|
columnWidths[0]=fixedWidth[0];
|
|
if (fixedWidth[1]>=0)
|
|
columnWidths[1]=fixedWidth[1];
|
|
}
|
|
|
|
if (s_ScrollMenus==2 && columnWidths.size()>1 && m_bSubMenu)
|
|
{
|
|
// auto - determine if we should have 1 column or many
|
|
int width=0;
|
|
for (size_t i=0;i<columnWidths.size();i++)
|
|
{
|
|
if (i>0) width+=s_Skin.Submenu_separatorWidth;
|
|
width+=columnWidths[i];
|
|
}
|
|
if (width>maxWidth)
|
|
{
|
|
bMultiColumn=false;
|
|
// the columns don't fit on screen, switch to one scrollable column
|
|
int y=0;
|
|
columnWidths.resize(1);
|
|
columnWidths[0]=0;
|
|
for (size_t i=0;i<m_Items.size();i++)
|
|
{
|
|
MenuItem &item=m_Items[i];
|
|
const MenuSkin::ItemDrawSettings &settings=s_Skin.ItemSettings[item.drawType];
|
|
int h=settings.itemHeight;
|
|
if (item.id==MENU_SEPARATOR && !item.bBlankSeparator && item.name.IsEmpty())
|
|
{
|
|
h=(y==0)?0:settings.sepHeight;
|
|
}
|
|
if (columnWidths[0]<item.itemRect.right) columnWidths[0]=item.itemRect.right;
|
|
item.row=(int)i;
|
|
item.column=0;
|
|
item.itemRect.top=y;
|
|
item.itemRect.bottom=y+h;
|
|
y+=h;
|
|
}
|
|
}
|
|
}
|
|
|
|
// calculate the horizontal position of each item
|
|
int maxw=0;
|
|
int maxh[2]={0,0};
|
|
int scrollWidth=GetSystemMetrics(SM_CXVSCROLL);
|
|
{
|
|
m_ColumnOffsets.resize(columnWidths.size());
|
|
for (size_t i=0;i<columnWidths.size();i++)
|
|
{
|
|
if (i>0) maxw+=m_bSubMenu?s_Skin.Submenu_separatorWidth:s_Skin.Main_separatorWidth;
|
|
m_ColumnOffsets[i]=maxw;
|
|
maxw+=columnWidths[i];
|
|
}
|
|
columnWidths.push_back(maxw);
|
|
bool bInline=false;
|
|
for (int i=0;i<(int)m_Items.size();i++)
|
|
{
|
|
MenuItem &item=m_Items[i];
|
|
if (item.bInline)
|
|
{
|
|
item.itemRect.left+=m_ColumnOffsets[item.column];
|
|
item.itemRect.right+=m_ColumnOffsets[item.column];
|
|
bInline=true;
|
|
}
|
|
else if (item.id==MENU_SHUTDOWN_BUTTON)
|
|
{
|
|
int x=s_Skin.ItemSettings[MenuSkin::COLUMN1_ITEM].textMetrics.tmAveCharWidth*s_ProgramsWidth;
|
|
x+=s_Skin.Main_padding.left+s_Skin.Main_padding.right+s_Skin.Main2_padding.left;
|
|
item.itemRect.right+=x-item.itemRect.left;
|
|
item.itemRect.left=x;
|
|
}
|
|
else if (s_bWin7Style && item.id==MENU_SEARCH_BOX)
|
|
{
|
|
item.itemRect.left=0;
|
|
item.itemRect.right=s_Skin.ItemSettings[MenuSkin::COLUMN1_ITEM].textMetrics.tmAveCharWidth*s_ProgramsWidth;
|
|
}
|
|
else
|
|
{
|
|
item.itemRect.left=m_ColumnOffsets[item.column];
|
|
item.itemRect.right=item.itemRect.left+columnWidths[item.column];
|
|
if (s_MenuMode==MODE_SEARCH && !m_bSubMenu && (item.id==MENU_NO || item.id==MENU_SEARCH_EXECUTE) && i>=m_OriginalCount)
|
|
{
|
|
if ((item.categoryHash&CSearchManager::CATEGORY_MASK)!=CSearchManager::CATEGORY_AUTOCOMPLETE)
|
|
item.itemRect.left+=s_Skin.Main_search_indent;
|
|
else if (s_bWin7Style)
|
|
item.itemRect.right-=scrollWidth;
|
|
}
|
|
}
|
|
if (m_bTwoColumns)
|
|
{
|
|
if (maxh[item.column]<item.itemRect.bottom)
|
|
maxh[item.column]=item.itemRect.bottom;
|
|
}
|
|
else
|
|
{
|
|
if (maxh[0]<item.itemRect.bottom)
|
|
maxh[0]=item.itemRect.bottom;
|
|
}
|
|
}
|
|
|
|
if (bInline)
|
|
{
|
|
// center inline groups
|
|
for (size_t i=0;i<m_Items.size();i++)
|
|
{
|
|
MenuItem &item=m_Items[i];
|
|
if (item.bInlineFirst)
|
|
{
|
|
int i1=(int)i;
|
|
bool bSepLeft=(item.id==MENU_SEPARATOR);
|
|
int w=item.itemRect.right-item.itemRect.left;
|
|
for (i++;i<m_Items.size();i++)
|
|
{
|
|
if (!m_Items[i].bInline || m_Items[i].bInlineFirst)
|
|
break;
|
|
w+=(m_Items[i].itemRect.right-m_Items[i].itemRect.left);
|
|
}
|
|
w=(columnWidths[item.column]-w);
|
|
int i2=(int)i;
|
|
i--;
|
|
bool bSepRight=(m_Items[i].id==MENU_SEPARATOR);
|
|
if (!bSepLeft && !bSepRight)
|
|
w/=2; // centered
|
|
else if (bSepRight)
|
|
w=0;
|
|
int first=-1, last=-1;
|
|
for (int j=i1;j<i2;j++)
|
|
{
|
|
if (m_Items[j].id!=MENU_SEPARATOR)
|
|
{
|
|
if (first<0) first=j;
|
|
last=j;
|
|
}
|
|
OffsetRect(&m_Items[j].itemRect,w,0);
|
|
m_Items[j].bInlineFirst=false;
|
|
}
|
|
if (first>=0)
|
|
{
|
|
m_Items[first].bInlineFirst=true;
|
|
m_Items[last].bInlineLast=true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_Bitmap)
|
|
{
|
|
DeleteObject(m_Bitmap);
|
|
m_Bitmap=NULL;
|
|
}
|
|
if (m_Region)
|
|
{
|
|
DeleteObject(m_Region);
|
|
m_Region=NULL;
|
|
}
|
|
|
|
m_ExtraTop=m_ExtraBottom=m_ExtraBorder=0;
|
|
if (!bMultiColumn && maxh[0]>maxHeight[0] && m_ScrollCount>0 && m_bSubMenu)
|
|
{
|
|
int d=menuPadding[0].top+menuPadding[0].bottom+maxh[0]-maxHeight[1];
|
|
if (d<=menuPadding[0].top)
|
|
m_ExtraTop=d;
|
|
else
|
|
{
|
|
m_ExtraTop=menuPadding[0].top;
|
|
d-=menuPadding[0].top;
|
|
if (d<=menuPadding[0].bottom)
|
|
m_ExtraBottom=d;
|
|
else
|
|
m_ExtraBottom=menuPadding[0].bottom;
|
|
}
|
|
m_ExtraBorder=borderHeight;
|
|
maxHeight[0]=maxHeight[1];
|
|
}
|
|
|
|
int totalWidth, totalHeight;
|
|
memset(&m_rContent2,0,sizeof(m_rContent2));
|
|
bool bSetMenuSize=(s_MenuHeight==-1);
|
|
if (!m_bSubMenu)
|
|
{
|
|
if (s_MenuMaxHeight[0]==-1)
|
|
{
|
|
s_MenuMaxHeight[0]=maxh[0];
|
|
s_MenuMaxHeight[1]=maxh[1];
|
|
}
|
|
else if (bSetMenuSize)
|
|
{
|
|
maxh[0]=s_MenuMaxHeight[0];
|
|
maxh[1]=s_MenuMaxHeight[1];
|
|
}
|
|
}
|
|
{
|
|
int w1=maxw, w2=0;
|
|
int h1=(maxh[0]<maxHeight[0]?maxh[0]:maxHeight[0]);
|
|
int h2=(maxh[1]<maxHeight[1]?maxh[1]:maxHeight[1]);
|
|
if (m_bTwoColumns && columnWidths.size()>2)
|
|
{
|
|
w1=columnWidths[0];
|
|
w2=columnWidths[1];
|
|
|
|
if (s_bWin7Style)
|
|
{
|
|
if (bSetMenuSize)
|
|
{
|
|
int minh=s_Skin.ItemSettings[MenuSkin::LIST_ITEM].itemHeight*GetSettingInt(L"MinMainHeight");
|
|
if (h1<minh)
|
|
h1=minh;
|
|
s_MenuHeight=h1+menuPadding[0].top+menuPadding[0].bottom;
|
|
int q=h2+menuPadding[1].top+menuPadding[1].bottom;
|
|
if (s_MenuHeight<q)
|
|
s_MenuHeight=q;
|
|
q=maxHeight[0]+menuPadding[0].top+menuPadding[0].bottom;
|
|
if (s_MenuHeight>q)
|
|
s_MenuHeight=q;
|
|
}
|
|
h1=s_MenuHeight-menuPadding[0].top-menuPadding[0].bottom;
|
|
h2=s_MenuHeight-menuPadding[1].top-menuPadding[1].bottom;
|
|
}
|
|
}
|
|
if (!m_bSubMenu)
|
|
{
|
|
if (s_bWin7Style)
|
|
{
|
|
s_BackgroundW1=w1;
|
|
s_BackgroundW2=w2;
|
|
s_BackgroundH1=h1;
|
|
s_BackgroundH2=h2;
|
|
if (s_OldMenuState.mode==MODE_UNKNOWN)
|
|
CreateBackground(w1,w2,h1,h2,totalWidth,totalHeight,true);
|
|
else
|
|
CreateContentRects(w1,w2,h1,h2,totalWidth,totalHeight);
|
|
}
|
|
else if (s_Skin.Main_bitmap.GetBitmap() || s_Skin.User_image_size || m_bTwoColumns || s_Skin.User_name_position.left!=s_Skin.User_name_position.right)
|
|
{
|
|
CreateBackground(w1,w2,h1,h2,totalWidth,totalHeight,true);
|
|
}
|
|
else
|
|
{
|
|
m_rContent.left=menuPadding[0].left;
|
|
m_rContent.top=menuPadding[0].top;
|
|
m_rContent.right=menuPadding[0].left+w1;
|
|
m_rContent.bottom=menuPadding[0].top+h1;
|
|
totalWidth=menuPadding[0].left+menuPadding[0].right+w1;
|
|
totalHeight=menuPadding[0].top+menuPadding[0].bottom+h1;
|
|
}
|
|
if (bSetMenuSize)
|
|
{
|
|
s_MenuWidthMax=s_MenuWidthJump;
|
|
if (s_MenuWidthMax<totalWidth)
|
|
s_MenuWidthMax=totalWidth;
|
|
if (s_MenuMode==MODE_NORMAL)
|
|
s_MenuWidthNormal=totalWidth;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bDontShrink && h1<m_rContent.bottom-m_rContent.top)
|
|
h1=m_rContent.bottom-m_rContent.top;
|
|
|
|
if (s_Skin.Submenu_bitmap.GetBitmap())
|
|
CreateSubmenuRegion(w1,h1);
|
|
|
|
m_rContent.left=menuPadding[0].left;
|
|
m_rContent.top=menuPadding[0].top-m_ExtraTop;
|
|
m_rContent.right=m_rContent.left+w1;
|
|
m_rContent.bottom=m_rContent.top+h1;
|
|
totalWidth=menuPadding[0].left+menuPadding[0].right+w1;
|
|
totalHeight=menuPadding[0].top+menuPadding[0].bottom+h1-m_ExtraTop-m_ExtraBottom;
|
|
}
|
|
// offset the items
|
|
for (size_t i=0;i<m_Items.size();i++)
|
|
{
|
|
MenuItem &item=m_Items[i];
|
|
int dx=m_rContent.left;
|
|
int dy=m_rContent.top;
|
|
if (m_bTwoColumns && item.column==1)
|
|
{
|
|
dx=m_rContent2.left-m_ColumnOffsets[1];
|
|
dy=m_rContent2.top;
|
|
}
|
|
if (item.id==MENU_SHUTDOWN_BUTTON)
|
|
dx=0;
|
|
OffsetRect(&item.itemRect,dx,dy);
|
|
}
|
|
|
|
if (m_bTwoColumns && columnWidths.size()>2)
|
|
{
|
|
int dh1=0, dh2=0;
|
|
for (int i=0;i<m_OriginalCount;i++)
|
|
{
|
|
const MenuItem &item=m_Items[i];
|
|
if (item.column==0)
|
|
{
|
|
if (dh1<item.itemRect.bottom)
|
|
dh1=item.itemRect.bottom;
|
|
}
|
|
else
|
|
{
|
|
if (dh2<item.itemRect.bottom)
|
|
dh2=item.itemRect.bottom;
|
|
}
|
|
}
|
|
m_rContent.bottom=totalHeight-menuPadding[0].bottom;
|
|
m_rContent2.bottom=totalHeight-menuPadding[1].bottom;
|
|
dh1=m_rContent.bottom-dh1;
|
|
dh2=(s_MenuMode==MODE_SEARCH?m_rContent.bottom:m_rContent2.bottom)-dh2;
|
|
if (!s_bWin7Style)
|
|
{
|
|
if (dh1<0) dh1=0;
|
|
if (dh2<0) dh2=0;
|
|
}
|
|
|
|
bool bAlign1=false, bAlign2=false;
|
|
for (int i=0;i<m_OriginalCount;i++)
|
|
{
|
|
MenuItem &item=m_Items[i];
|
|
if (item.column==0)
|
|
{
|
|
if (item.bAlignBottom)
|
|
bAlign1=true;
|
|
if (bAlign1)
|
|
OffsetRect(&item.itemRect,0,dh1);
|
|
}
|
|
else
|
|
{
|
|
if (item.bAlignBottom)
|
|
bAlign2=true;
|
|
if (bAlign2)
|
|
OffsetRect(&item.itemRect,0,dh2);
|
|
}
|
|
if (item.id==MENU_SHUTDOWN_BUTTON)
|
|
{
|
|
item.itemRect.left+=s_Skin.Shutdown_padding.left;
|
|
item.itemRect.right-=s_Skin.Shutdown_padding.right;
|
|
item.itemRect.top+=s_Skin.Shutdown_padding.top;
|
|
item.itemRect.bottom-=s_Skin.Shutdown_padding.bottom;
|
|
}
|
|
}
|
|
// trim overlapping items
|
|
if (s_MenuMode==MODE_NORMAL || s_MenuMode==MODE_JUMPLIST || s_MenuMode==MODE_PROGRAMS)
|
|
{
|
|
int extra=-dh1;
|
|
if (extra>0)
|
|
{
|
|
// remove extra programs
|
|
std::vector<MenuItem>::reverse_iterator pBegin=m_Items.rend(), pEnd=m_Items.rend(); // pinned
|
|
std::vector<MenuItem>::reverse_iterator rBegin=m_Items.rend(), rEnd=m_Items.rend(); // recent
|
|
for (std::vector<MenuItem>::reverse_iterator it=m_Items.rbegin();it!=m_Items.rend();++it)
|
|
{
|
|
if (it->id==MENU_NO && it->column==0)
|
|
{
|
|
if (pBegin==m_Items.rend())
|
|
pBegin=it;
|
|
}
|
|
else
|
|
{
|
|
if (pEnd==m_Items.rend() && pBegin!=m_Items.rend())
|
|
pEnd=it;
|
|
}
|
|
|
|
if (it->id==MENU_RECENT && it->column==0)
|
|
{
|
|
if (rBegin==m_Items.rend())
|
|
rBegin=it;
|
|
}
|
|
else
|
|
{
|
|
if (rEnd==m_Items.rend() && rBegin!=m_Items.rend())
|
|
rEnd=it;
|
|
}
|
|
}
|
|
|
|
// remove recent
|
|
int dy=0;
|
|
for (std::vector<MenuItem>::reverse_iterator it=rBegin;it!=rEnd;++it)
|
|
{
|
|
int h=it->itemRect.bottom-it->itemRect.top;
|
|
it->itemRect.bottom=it->itemRect.top;
|
|
extra-=h;
|
|
dy+=h;
|
|
if (it+1==rEnd && pBegin!=pEnd)
|
|
{
|
|
// removing the last recent, remove the separator between recent and pinned
|
|
if (GetSettingBool(L"RecentProgsTop"))
|
|
it=pEnd;
|
|
else
|
|
it=rEnd;
|
|
Assert(it->id==MENU_SEPARATOR);
|
|
h=it->itemRect.bottom-it->itemRect.top;
|
|
it->itemRect.bottom=it->itemRect.top;
|
|
extra-=h;
|
|
dy+=h;
|
|
break;
|
|
}
|
|
if (extra<=0) break;
|
|
}
|
|
|
|
if (dy>0 && GetSettingBool(L"RecentProgsTop") && pBegin!=pEnd)
|
|
{
|
|
// move pinned and the separator
|
|
for (std::vector<MenuItem>::reverse_iterator it=pBegin;it!=rBegin;++it)
|
|
{
|
|
it->itemRect.top-=dy;
|
|
it->itemRect.bottom-=dy;
|
|
}
|
|
}
|
|
|
|
// remove pinned
|
|
for (std::vector<MenuItem>::reverse_iterator it=pBegin;it!=pEnd && extra>0;++it)
|
|
{
|
|
int h=it->itemRect.bottom-it->itemRect.top;
|
|
it->itemRect.bottom=it->itemRect.top;
|
|
extra-=h;
|
|
if (extra<=0) break;
|
|
}
|
|
}
|
|
}
|
|
if (s_MenuMode==MODE_NORMAL || s_MenuMode==MODE_PROGRAMS)
|
|
{
|
|
int extra=-dh2;
|
|
if (extra>0)
|
|
{
|
|
// remove extra items
|
|
for (std::vector<MenuItem>::reverse_iterator it=m_Items.rbegin();it!=m_Items.rend();++it)
|
|
{
|
|
if (it->id==MENU_SHUTDOWN_BUTTON) continue;
|
|
if (it->column==0) break;
|
|
int h=it->itemRect.bottom-it->itemRect.top;
|
|
it->itemRect.bottom=it->itemRect.top;
|
|
extra-=h;
|
|
if (extra<=0) break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (firstRecent>=0)
|
|
{
|
|
// reorder recent items
|
|
int top=m_Items[firstRecent].itemRect.top;
|
|
int firstRow=m_Items[firstRecent].row;
|
|
if (bRecentByName)
|
|
std::sort(m_Items.begin()+firstRecent,m_Items.begin()+lastRecent,MenuItem::MruNameComparator());
|
|
|
|
TRecentKeys recentKeys=(TRecentKeys)GetSettingInt(L"RecentProgKeys");
|
|
if (recentKeys>=RECENT_KEYS_DIGITS)
|
|
{
|
|
// reassign accelerators
|
|
int num=0;
|
|
for (int idx=firstRecent;idx<lastRecent;idx++)
|
|
{
|
|
MenuItem &item=m_Items[idx];
|
|
item.accelerator=(num<10)?((num+1)%10)+'0':0;
|
|
item.bCustomAccelerator=true;
|
|
if (recentKeys==RECENT_KEYS_DIGITS)
|
|
{
|
|
CString str;
|
|
if (item.nameOffset>0)
|
|
str=(const wchar_t*)item.name+item.nameOffset;
|
|
else
|
|
str=item.name;
|
|
if (num<10)
|
|
item.name.Format(L"&%d %s",(num+1)%10,str);
|
|
else
|
|
item.name=str;
|
|
item.nameOffset=item.name.GetLength()-str.GetLength();
|
|
}
|
|
if (item.itemRect.bottom>item.itemRect.top)
|
|
num++;
|
|
}
|
|
}
|
|
|
|
if (bRecentReverse)
|
|
std::reverse(m_Items.begin()+firstRecent,m_Items.begin()+lastRecent);
|
|
for (int i=firstRecent;i<lastRecent;i++)
|
|
{
|
|
RECT &rc=m_Items[i].itemRect;
|
|
int h=rc.bottom-rc.top;
|
|
rc.top=top;
|
|
top+=h;
|
|
rc.bottom=top;
|
|
m_Items[i].row=firstRow-firstRecent+i;
|
|
}
|
|
}
|
|
}
|
|
|
|
// create pager
|
|
if (!bMultiColumn && maxh[0]>maxHeight[0] && m_ScrollCount>0 && (m_bSubMenu || !s_bWin7Style))
|
|
{
|
|
int d=maxh[0]-maxHeight[0];
|
|
m_ScrollHeight=m_Items[m_ScrollCount-1].itemRect.bottom-d-m_rContent.top;
|
|
if (m_ScrollHeight<=0)
|
|
{
|
|
if (m_ScrollCount<(int)m_Items.size())
|
|
d=m_Items[m_ScrollCount].itemRect.bottom-m_rContent.top;
|
|
m_ScrollOffset=m_ScrollHeight=0;
|
|
for (int i=0;i<m_ScrollCount;i++)
|
|
m_Items[i].itemRect.bottom=m_Items[i].itemRect.top;
|
|
}
|
|
for (size_t i=m_ScrollCount;i<m_Items.size();i++)
|
|
if (m_Items[i].column==0)
|
|
OffsetRect(&m_Items[i].itemRect,0,-d);
|
|
|
|
std::map<unsigned int,int>::iterator it=s_MenuScrolls.find(m_FolderHash[0]);
|
|
if (it!=s_MenuScrolls.end())
|
|
{
|
|
m_ScrollOffset=it->second; // restore the scroll position if the same menu has been opened before
|
|
if (m_ScrollOffset>d) m_ScrollOffset=d;
|
|
}
|
|
else if ((m_Options&CONTAINER_SEARCH) && !bDontShrink)
|
|
{
|
|
// fit current category
|
|
if (m_SearchCategoryHash!=CSearchManager::CATEGORY_INVALID)
|
|
{
|
|
for (int i=0;i<m_ScrollCount;i++)
|
|
if (m_Items[i].id==MENU_SEARCH_CATEGORY && m_Items[i].categoryHash==m_SearchCategoryHash)
|
|
{
|
|
size_t first=i;
|
|
size_t last=i;
|
|
for (i++;i<m_ScrollCount;i++)
|
|
{
|
|
if (m_Items[i].categoryHash==m_SearchCategoryHash)
|
|
last=i;
|
|
else
|
|
break;
|
|
}
|
|
int top=m_Items[first].itemRect.top;
|
|
int bottom=m_Items[last].itemRect.bottom;
|
|
if (m_ScrollOffset<bottom-m_ScrollHeight+m_ScrollButtonSize)
|
|
m_ScrollOffset=bottom-m_ScrollHeight+m_ScrollButtonSize;
|
|
if (m_ScrollOffset>top)
|
|
m_ScrollOffset=top;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
m_ScrollOffset=0;
|
|
}
|
|
else
|
|
m_ScrollOffset=m_ScrollHeight=0;
|
|
UpdateScroll();
|
|
m_bScrollUpHot=m_bScrollDownHot=false;
|
|
|
|
// hide items that didn't fit
|
|
if (!m_bSubMenu)
|
|
{
|
|
for (int i=m_ScrollCount;i<m_OriginalCount;i++)
|
|
{
|
|
int bottom=m_Items[i].column==0?m_rContent.bottom:m_rContent2.bottom;
|
|
if (m_Items[i].itemRect.bottom>bottom)
|
|
m_Items[i].itemRect.bottom=m_Items[i].itemRect.top;
|
|
}
|
|
}
|
|
|
|
m_rMenu.left=m_rMenu.top=0;
|
|
m_rMenu.right=totalWidth;
|
|
m_rMenu.bottom=totalHeight;
|
|
int oldOffset=m_BitmapOffset;
|
|
if (!m_bSubMenu)
|
|
{
|
|
m_BitmapOffset=0;
|
|
if (s_bWin7Style && s_Skin.Main_opacity!=MenuSkin::OPACITY_SOLID)
|
|
{
|
|
if (!(m_Options&CONTAINER_LEFT) && !s_bRTL)
|
|
m_BitmapOffset=s_MenuWidthMax-totalWidth;
|
|
if ((m_Options&CONTAINER_LEFT) && s_bRTL)
|
|
m_BitmapOffset=s_MenuWidthMax-totalWidth;
|
|
totalWidth=s_MenuWidthMax;
|
|
}
|
|
}
|
|
if (m_BitmapOffset>0)
|
|
{
|
|
OffsetRect(&m_rMenu,m_BitmapOffset,0);
|
|
OffsetRect(&m_rContent,m_BitmapOffset,0);
|
|
OffsetRect(&m_rContent2,m_BitmapOffset,0);
|
|
if (m_Region && !s_bRTL)
|
|
OffsetRgn(m_Region,m_BitmapOffset,0);
|
|
for (std::vector<MenuItem>::iterator it=m_Items.begin();it!=m_Items.end();++it)
|
|
OffsetRect(&it->itemRect,m_BitmapOffset,0);
|
|
}
|
|
if (m_SearchIndex>=0)
|
|
{
|
|
m_Items[m_SearchIndex].itemRect.left+=s_Skin.Search_padding.left;
|
|
m_Items[m_SearchIndex].itemRect.top+=s_Skin.Search_padding.top;
|
|
m_Items[m_SearchIndex].itemRect.bottom-=s_Skin.Search_padding.bottom;
|
|
m_Items[m_SearchIndex].itemRect.right-=s_Skin.Search_padding.right;
|
|
RECT itemRect;
|
|
GetItemRect(m_SearchIndex,itemRect);
|
|
itemRect.right-=(itemRect.bottom-itemRect.top);
|
|
if (!s_Skin.Search_frame)
|
|
InflateRect(&itemRect,-1,-3);
|
|
if (m_SearchBox.m_hWnd)
|
|
{
|
|
if (oldOffset==m_BitmapOffset)
|
|
m_SearchBox.SetWindowPos(NULL,&itemRect,SWP_NOZORDER);
|
|
}
|
|
else
|
|
{
|
|
m_SearchBox.Create(L"EDIT",m_hWnd,itemRect,NULL,WS_CHILD|(s_Skin.Search_frame?WS_BORDER:0)|ES_AUTOHSCROLL|ES_WANTRETURN);
|
|
SetWindowSubclass(m_SearchBox,SubclassSearchBox,(UINT_PTR)this,0);
|
|
int index=(m_bTwoColumns && m_Items[m_SearchIndex].column==1)?1:0;
|
|
if (index==1 && (m_SearchIndex==0 || m_Items[m_SearchIndex-1].column==0))
|
|
m_SearchBox.SetFont(s_Skin.ItemSettings[MenuSkin::COLUMN2_ITEM].font);
|
|
else
|
|
m_SearchBox.SetFont(s_Skin.ItemSettings[MenuSkin::COLUMN1_ITEM].font);
|
|
m_SearchIcons=(HBITMAP)LoadImage(g_Instance,MAKEINTRESOURCE(IDB_SEARCH_ICONS),IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION);
|
|
PremultiplyBitmap(m_SearchIcons,0xFFFFFF);
|
|
}
|
|
}
|
|
|
|
if (m_bTwoColumns && s_MenuMode==MODE_JUMPLIST)
|
|
{
|
|
// trim jumplist items after creating the search box
|
|
int maxH=m_rContent2.bottom;
|
|
if (m_SearchIndex>=0)
|
|
{
|
|
int h=m_Items[m_SearchIndex].itemRect.top-s_Skin.Search_padding.top-s_Skin.Search_background_jump_padding.top;
|
|
if (maxH>h) maxH=h;
|
|
}
|
|
if (shutdownIndex>=0)
|
|
{
|
|
int h=m_Items[shutdownIndex].itemRect.top;
|
|
if (maxH>h) maxH=h;
|
|
}
|
|
|
|
for (std::vector<MenuItem>::iterator it=m_Items.begin()+m_OriginalCount;it!=m_Items.end();++it)
|
|
{
|
|
if (it->itemRect.bottom>maxH)
|
|
it->itemRect.bottom=it->itemRect.top;
|
|
}
|
|
}
|
|
|
|
// calculate padding rect
|
|
if (m_bSubMenu)
|
|
{
|
|
m_rPadding.top=-1;
|
|
m_rPadding.left=m_rPadding.right=m_rPadding.bottom=0;
|
|
int padColumn=-1;
|
|
for (size_t i=0;i<m_Items.size();i++)
|
|
{
|
|
MenuItem &item=m_Items[i];
|
|
if (item.id==MENU_NO)
|
|
{
|
|
m_rPadding.left=item.itemRect.left;
|
|
m_rPadding.right=item.itemRect.right;
|
|
m_rPadding.top=item.itemRect.bottom;
|
|
m_rPadding.bottom=-1;
|
|
padColumn=item.column;
|
|
}
|
|
else if (m_rPadding.bottom==-1 && padColumn==item.column)
|
|
{
|
|
m_rPadding.bottom=item.itemRect.top;
|
|
}
|
|
}
|
|
if (m_rPadding.top>=0 && m_rPadding.bottom==-1)
|
|
{
|
|
m_rPadding.bottom=totalHeight-(m_bSubMenu?menuPadding[0].bottom:menuPadding[0].bottom);
|
|
}
|
|
}
|
|
menuRect.top=menuRect.left=0;
|
|
menuRect.right=totalWidth;
|
|
menuRect.bottom=totalHeight;
|
|
if ((m_bSubMenu?s_Skin.Submenu_opacity:s_Skin.Main_opacity)==MenuSkin::OPACITY_SOLID)
|
|
AdjustWindowRect(&menuRect,GetWindowLong(GWL_STYLE),FALSE);
|
|
int dx=corner.x-((m_Options&CONTAINER_LEFT)?menuRect.left:menuRect.right);
|
|
int dy;
|
|
if (m_Options&CONTAINER_SEARCH)
|
|
{
|
|
RECT itemRect;
|
|
m_pParent->GetItemRect(m_ParentIndex,itemRect);
|
|
m_pParent->MapWindowPoints(NULL,&itemRect);
|
|
dy=(m_Options&CONTAINER_TOP)?(itemRect.top-menuPadding[0].top-menuRect.top):(itemRect.bottom+menuPadding[0].bottom-menuRect.bottom);
|
|
}
|
|
else
|
|
{
|
|
dy=corner.y-((m_Options&CONTAINER_TOP)?menuRect.top:menuRect.bottom);
|
|
}
|
|
OffsetRect(&menuRect,dx,dy);
|
|
if (m_bSubMenu)
|
|
{
|
|
// make the menu fit on screen
|
|
int dy2=0;
|
|
if (menuRect.bottom>s_MenuLimits.bottom)
|
|
dy2=s_MenuLimits.bottom-menuRect.bottom;
|
|
if (menuRect.top+dy2<s_MenuLimits.top)
|
|
dy2=s_MenuLimits.top-menuRect.top;
|
|
OffsetRect(&menuRect,0,dy2);
|
|
}
|
|
if (s_UserPicture.m_hWnd && s_MenuMode!=MODE_SEARCH && columnWidths.size()>2 && columnWidths[1]==0)
|
|
{
|
|
s_UserPicture.DestroyWindow();
|
|
s_UserPictureRect.top=s_UserPictureRect.bottom=0;
|
|
}
|
|
if (s_UserPicture.m_hWnd)
|
|
{
|
|
s_UserPictureRect.bottom=s_Skin.User_frame_position.x;
|
|
if (!s_Skin.User_bitmap_outside || (m_Options&CONTAINER_TOP))
|
|
s_UserPictureRect.bottom=m_rContent2.top+s_Skin.User_bitmapSize.cy+s_Skin.User_image_padding.x;
|
|
s_UserPictureRect.bottom+=menuRect.top;
|
|
s_UserPictureRect.top=s_UserPictureRect.bottom-s_Skin.User_bitmapSize.cy;
|
|
if (s_bRTL)
|
|
s_UserPictureRect.left=menuRect.right-(m_rContent2.left+m_rContent2.right+s_Skin.User_bitmapSize.cx)/2;
|
|
else
|
|
s_UserPictureRect.left=menuRect.left+(m_rContent2.left+m_rContent2.right-s_Skin.User_bitmapSize.cx)/2;
|
|
s_UserPictureRect.right=s_UserPictureRect.left+s_Skin.User_bitmapSize.cx;
|
|
}
|
|
|
|
// create scrollbar
|
|
if (m_SearchScrollCount>m_SearchScrollHeight)
|
|
{
|
|
if (!m_Scrollbar.m_hWnd)
|
|
{
|
|
m_Scrollbar.Create(WC_SCROLLBAR,m_hWnd,NULL,NULL,WS_CHILD|SBS_VERT);
|
|
SetWindowSubclass(m_Scrollbar,SubclassScrollbar,(UINT_PTR)this,0);
|
|
if (s_Skin.BHasScrollbar)
|
|
m_ScrollTheme=OpenThemeData(m_Scrollbar,L"scrollbar");
|
|
}
|
|
RECT rcScroll=m_rContent;
|
|
rcScroll.bottom=rcScroll.top+m_SearchScrollHeight*s_Skin.ItemSettings[MenuSkin::LIST_ITEM].itemHeight;
|
|
rcScroll.left=rcScroll.right-scrollWidth;
|
|
SCROLLINFO info={sizeof(info),SIF_ALL,0,m_SearchScrollCount-1,(UINT)m_SearchScrollHeight};
|
|
m_Scrollbar.SetScrollInfo(SB_CTL,&info,FALSE);
|
|
m_Scrollbar.SetWindowPos(NULL,&rcScroll,SWP_NOZORDER|SWP_SHOWWINDOW);
|
|
}
|
|
else if (m_Scrollbar.m_hWnd)
|
|
m_Scrollbar.ShowWindow(SW_HIDE);
|
|
|
|
m_bTrackMouse=false;
|
|
m_bScrollTimerMouse=false;
|
|
m_bScrollTimerTouch=false;
|
|
m_InsertMark=-1;
|
|
m_HotItem=-1;
|
|
m_bHotArrow=false;
|
|
SetSubmenu(-1);
|
|
m_MouseWheel=0;
|
|
|
|
if (!m_bSubMenu)
|
|
{
|
|
TOOLINFO tool={sizeof(tool),TTF_SUBCLASS|TTF_TRANSPARENT|(s_bRTL?TTF_RTLREADING:0U)};
|
|
tool.hwnd=m_hWnd;
|
|
tool.uId=2;
|
|
s_Tooltip.SendMessage(TTM_DELTOOL,0,(LPARAM)&tool);
|
|
tool.uId=3;
|
|
s_Tooltip.SendMessage(TTM_DELTOOL,0,(LPARAM)&tool);
|
|
tool.uId=(UINT_PTR)s_UserPicture.m_hWnd;
|
|
s_Tooltip.SendMessage(TTM_DELTOOL,0,(LPARAM)&tool);
|
|
|
|
if (m_rUser1.left<m_rUser1.right || m_rUser2.left<m_rUser2.right || s_UserPicture.m_hWnd)
|
|
{
|
|
// construct the text Log Off <username>...
|
|
wchar_t user[256]={0};
|
|
ULONG size=_countof(user);
|
|
if (!GetUserNameEx(NameDisplay,user,&size))
|
|
{
|
|
// GetUserNameEx may fail (for example on Home editions). use the login name
|
|
DWORD size=_countof(user);
|
|
GetUserName(user,&size);
|
|
}
|
|
tool.lpszText=user;
|
|
|
|
if (m_rUser1.left<m_rUser1.right)
|
|
{
|
|
tool.uId=2;
|
|
tool.rect=m_rUser1;
|
|
s_Tooltip.SendMessage(TTM_ADDTOOL,0,(LPARAM)&tool);
|
|
}
|
|
if (m_rUser2.left<m_rUser2.right)
|
|
{
|
|
tool.uId=3;
|
|
tool.rect=m_rUser2;
|
|
s_Tooltip.SendMessage(TTM_ADDTOOL,0,(LPARAM)&tool);
|
|
}
|
|
if (s_UserPicture.m_hWnd)
|
|
{
|
|
tool.uFlags|=TTF_IDISHWND;
|
|
tool.uId=(UINT_PTR)s_UserPicture.m_hWnd;
|
|
s_Tooltip.SendMessage(TTM_ADDTOOL,0,(LPARAM)&tool);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_pParent && (m_pParent->m_Items[m_ParentIndex].id==MENU_PROGRAMS || m_pParent->m_Items[m_ParentIndex].id==MENU_APPS))
|
|
{
|
|
ULONGLONG curTime;
|
|
GetSystemTimeAsFileTime((FILETIME*)&curTime);
|
|
CRegKey regKey;
|
|
if (regKey.Open(HKEY_CURRENT_USER,L"Software\\OpenShell\\StartMenu",KEY_WRITE)!=ERROR_SUCCESS)
|
|
regKey.Create(HKEY_CURRENT_USER,L"Software\\OpenShell\\StartMenu");
|
|
|
|
if (m_pParent->m_Items[m_ParentIndex].id==MENU_PROGRAMS)
|
|
regKey.SetQWORDValue(L"LastProgramsTime",curTime);
|
|
else if (m_pParent->m_Items[m_ParentIndex].id==MENU_APPS)
|
|
regKey.SetQWORDValue(L"LastAppsTime",curTime);
|
|
}
|
|
}
|
|
|
|
void CMenuContainer::InitWindowFinalize( const RECT &menuRect )
|
|
{
|
|
SetWindowPos(NULL,&menuRect,SWP_NOZORDER|SWP_NOACTIVATE|SWP_DEFERERASE);
|
|
// for some reason the region must be set after the call to SetWindowPos. otherwise it doesn't work for RTL windows
|
|
if (m_bSubMenu || !s_bWin7Style || s_OldMenuState.mode==MODE_UNKNOWN)
|
|
ApplyRegion(TRUE);
|
|
Invalidate();
|
|
}
|
|
|
|
void CMenuContainer::ApplyRegion( BOOL bRedraw )
|
|
{
|
|
if (m_Region)
|
|
{
|
|
int size=GetRegionData(m_Region,0,NULL);
|
|
std::vector<char> buf(size);
|
|
GetRegionData(m_Region,size,(RGNDATA*)&buf[0]);
|
|
XFORM xform={1,0,0,1};
|
|
if (s_bRTL)
|
|
{
|
|
// mirror the region (again)
|
|
xform.eM11=-1;
|
|
xform.eDx=(float)(m_rMenu.right+m_rMenu.left-m_BitmapOffset);
|
|
}
|
|
HRGN rgn=ExtCreateRegion(&xform,size,(RGNDATA*)&buf[0]);
|
|
|
|
if (!SetWindowRgn(rgn,bRedraw))
|
|
DeleteObject(rgn); // otherwise the OS takes ownership of the region, no need to free
|
|
}
|
|
else
|
|
SetWindowRgn(NULL,bRedraw);
|
|
}
|
|
|
|
void CMenuContainer::UpdateScroll( void )
|
|
{
|
|
if (m_ScrollHeight==0)
|
|
m_bScrollUp=m_bScrollDown=false;
|
|
else
|
|
{
|
|
m_bScrollUp=(m_ScrollOffset>0);
|
|
m_bScrollDown=(m_ScrollOffset+m_ScrollHeight<m_Items[m_ScrollCount-1].itemRect.bottom-m_rContent.top);
|
|
}
|
|
}
|
|
|
|
void CMenuContainer::UpdateScroll( const POINT *pt, bool bTouch )
|
|
{
|
|
if (m_bScrollUp)
|
|
{
|
|
RECT rc=m_rContent;
|
|
rc.bottom=rc.top+m_ScrollButtonSize;
|
|
bool bHot=pt && PtInRect(&rc,*pt);
|
|
if (m_bScrollUpHot!=bHot)
|
|
{
|
|
m_bScrollUpHot=bHot;
|
|
Invalidate();
|
|
}
|
|
}
|
|
else
|
|
m_bScrollUpHot=false;
|
|
|
|
if (m_bScrollDown)
|
|
{
|
|
RECT rc=m_rContent;
|
|
rc.bottom=m_rContent.top+m_ScrollHeight;
|
|
rc.top=rc.bottom-m_ScrollButtonSize;
|
|
bool bHot=pt && PtInRect(&rc,*pt);
|
|
if (m_bScrollDownHot!=bHot)
|
|
{
|
|
m_bScrollDownHot=bHot;
|
|
Invalidate();
|
|
}
|
|
}
|
|
else
|
|
m_bScrollDownHot=false;
|
|
|
|
if (m_bScrollUpHot || m_bScrollDownHot)
|
|
{
|
|
if (!bTouch && !m_bScrollTimerMouse)
|
|
{
|
|
m_bScrollTimerMouse=true;
|
|
SetTimer(TIMER_SCROLL_MOUSE,50);
|
|
}
|
|
if (bTouch && !m_bScrollTimerTouch)
|
|
{
|
|
m_bScrollTimerTouch=true;
|
|
SetTimer(TIMER_SCROLL_TOUCH,50);
|
|
}
|
|
}
|
|
else if (!bTouch)
|
|
{
|
|
if (m_bScrollTimerMouse)
|
|
{
|
|
m_bScrollTimerMouse=false;
|
|
KillTimer(TIMER_SCROLL_MOUSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_bScrollTimerTouch)
|
|
{
|
|
m_bScrollTimerTouch=false;
|
|
KillTimer(TIMER_SCROLL_TOUCH);
|
|
}
|
|
}
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnCreate( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
MenuSkin::TOpacity opacity=(m_bSubMenu?s_Skin.Submenu_opacity:s_Skin.Main_opacity);
|
|
if (opacity==MenuSkin::OPACITY_ALPHA || opacity==MenuSkin::OPACITY_FULLALPHA)
|
|
{
|
|
MARGINS margins={-1};
|
|
DwmExtendFrameIntoClientArea(m_hWnd,&margins);
|
|
}
|
|
else if ((opacity==MenuSkin::OPACITY_GLASS || opacity==MenuSkin::OPACITY_FULLGLASS) && GetWinVersion()>=WIN_VER_WIN10)
|
|
{
|
|
tSetWindowCompositionAttribute SetWindowCompositionAttribute=(tSetWindowCompositionAttribute)GetProcAddress(GetModuleHandle(L"user32.dll"),"SetWindowCompositionAttribute");
|
|
if (SetWindowCompositionAttribute)
|
|
{
|
|
int a=((GetSettingInt(L"GlassOpacity")*255)/100)<<24;
|
|
int data[4]={3,0x13};
|
|
bool bDef=true;
|
|
if (GetSettingBool(L"GlassOverride"))
|
|
data[2]=(GetSettingInt(L"GlassColor",bDef)&0xFFFFFF)|a;
|
|
if (bDef)
|
|
{
|
|
int dr, dg, db;
|
|
GetMetroGlassColor(dr,dg,db);
|
|
data[2]=dr|(dg<<8)|(db<<16)|a;
|
|
}
|
|
WINCOMPATTRDATA attrData={0x13,&data,sizeof(data)};
|
|
SetWindowCompositionAttribute(m_hWnd,&attrData);
|
|
}
|
|
}
|
|
|
|
if (!m_pParent)
|
|
BufferedPaintInit();
|
|
if (this==s_Menus[0])
|
|
s_FirstMenu=m_hWnd;
|
|
else
|
|
InitWindow();
|
|
if (m_Options&CONTAINER_SEARCH)
|
|
s_SearchMenu=m_hWnd;
|
|
s_HotPos=GetMessagePos();
|
|
m_pAccessible=NULL;
|
|
if (GetSettingBool(L"EnableAccessibility"))
|
|
{
|
|
if (SUCCEEDED(m_pAccessibleContext.CoCreateInstance(CLSID_ContextSwitcher)))
|
|
{
|
|
CreateAccessibleData createData={this};
|
|
ComCallData callData={};
|
|
callData.pUserDefined=&createData;
|
|
if (SUCCEEDED(m_pAccessibleContext->ContextCallback(CreateAccessible,&callData,IID_IAccessible,4,NULL)))
|
|
{
|
|
if (FAILED(CoGetInterfaceAndReleaseStream(createData.pStream,IID_IAccessible,(void**)&m_pAccessible)))
|
|
{
|
|
m_pAccessibleContext=NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pAccessibleContext=NULL;
|
|
}
|
|
}
|
|
NotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART,m_hWnd,OBJID_CLIENT,CHILDID_SELF);
|
|
}
|
|
m_pDropTargetProxy=new CDropTargetProxy(this);
|
|
RegisterDragDrop(m_hWnd,m_pDropTargetProxy);
|
|
if (!m_bSubMenu && s_pFrameworkInputPane)
|
|
s_pFrameworkInputPane->AdviseWithHWND(m_hWnd,this,&m_InputCookie);
|
|
PlayMenuSound(m_bSubMenu?SOUND_POPUP:SOUND_MAIN);
|
|
return 0;
|
|
}
|
|
|
|
HRESULT __stdcall CMenuContainer::CreateAccessible( ComCallData *pData )
|
|
{
|
|
CreateAccessibleData *pCreateData=(CreateAccessibleData*)pData->pUserDefined;
|
|
CComPtr<CMenuAccessible> pAccessible=new CMenuAccessible(pCreateData->pMenu);
|
|
HRESULT hr=CoMarshalInterThreadInterfaceInStream(IID_IAccessible,pAccessible,&pCreateData->pStream);
|
|
if (FAILED(hr))
|
|
{
|
|
pAccessible->Reset();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT __stdcall CMenuContainer::ReleaseAccessible( ComCallData *pData )
|
|
{
|
|
return CoDisconnectContext(INFINITE);
|
|
}
|
|
|
|
bool CMenuContainer::GetItemRect( int index, RECT &rc )
|
|
{
|
|
if (index>=0 && index<(int)m_Items.size())
|
|
{
|
|
rc=m_Items[index].itemRect;
|
|
if (m_ScrollHeight>0 && index<m_ScrollCount)
|
|
{
|
|
OffsetRect(&rc,0,-m_ScrollOffset);
|
|
if (m_bScrollUp && rc.bottom<=m_rContent.top+m_ScrollButtonSize)
|
|
return false;
|
|
if (m_bScrollDown && rc.top>=m_rContent.top+m_ScrollHeight-m_ScrollButtonSize)
|
|
return false;
|
|
}
|
|
if (m_SearchScrollCount>m_SearchScrollHeight && index>=m_OriginalCount)
|
|
{
|
|
OffsetRect(&rc,0,-m_SearchScrollPos*(rc.bottom-rc.top));
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int CMenuContainer::HitTest( const POINT &pt, bool *bArrow, bool bDrop )
|
|
{
|
|
if (m_bScrollUp && pt.y<m_rContent.top+m_ScrollButtonSize)
|
|
return -1;
|
|
int start=0;
|
|
if (m_bScrollDown && pt.y>=m_rContent.top+m_ScrollHeight-m_ScrollButtonSize)
|
|
start=m_ScrollCount;
|
|
int n=(int)m_Items.size();
|
|
for (int i=start;i<n;i++)
|
|
{
|
|
if (!CanSelectItem(i,false)) continue;
|
|
RECT rc=m_Items[i].itemRect;
|
|
if (m_Items[i].id==MENU_SEARCH_BOX)
|
|
{
|
|
rc.left=rc.right-(rc.bottom-rc.top);
|
|
}
|
|
if (m_ScrollHeight>0 && i<m_ScrollCount)
|
|
{
|
|
OffsetRect(&rc,0,-m_ScrollOffset);
|
|
}
|
|
else if (m_SearchScrollCount>m_SearchScrollHeight && i>=m_OriginalCount)
|
|
{
|
|
OffsetRect(&rc,0,-m_SearchScrollPos*(rc.bottom-rc.top));
|
|
}
|
|
else if (bDrop && m_bTwoColumns && i<n-1 && m_Items[i+1].column==0 && m_Items[i+1].bAlignBottom)
|
|
rc.bottom=m_Items[i+1].itemRect.top; // when dropping on the padding of the first column, assume the item above the padding was hit
|
|
if (PtInRect(&rc,pt))
|
|
{
|
|
if (bArrow)
|
|
{
|
|
*bArrow=false;
|
|
const MenuItem &item=m_Items[i];
|
|
if (item.bSplit)
|
|
{
|
|
const MenuSkin::ItemDrawSettings &settings=s_Skin.ItemSettings[item.drawType];
|
|
int arrWidth=settings.arrPadding.cx+settings.arrPadding.cy;
|
|
if (item.jumpIndex>=0)
|
|
arrWidth+=s_Skin.Pin_bitmap_Size.cx;
|
|
else if (item.id==MENU_SEARCH_CATEGORY)
|
|
arrWidth+=s_Skin.More_bitmap_Size.cx;
|
|
else
|
|
arrWidth+=settings.arrSize.cx;
|
|
*bArrow=(pt.x>=item.itemRect.right-arrWidth);
|
|
}
|
|
else if (item.id==MENU_SEARCH_CATEGORY && item.categoryHash>=CSearchManager::CATEGORY_FILE)
|
|
{
|
|
int x=pt.x-rc.left;
|
|
*bArrow=(x>=item.textStart && x<item.textEnd);
|
|
}
|
|
}
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void CMenuContainer::InvalidateItem( int index )
|
|
{
|
|
if (index>=0)
|
|
{
|
|
RECT rc;
|
|
GetItemRect(index,rc);
|
|
InvalidateRect(&rc);
|
|
}
|
|
}
|
|
|
|
void CMenuContainer::SetHotItem( int index, bool bArrow, bool bShowTip )
|
|
{
|
|
if (index<0 && (m_Options&CONTAINER_SEARCH))
|
|
return;
|
|
if (index>=0)
|
|
s_bOverrideFirstDown=false;
|
|
if (index==m_HotItem && bArrow==m_bHotArrow) return;
|
|
if ((index>=0)!=(m_HotItem>=0))
|
|
{
|
|
InvalidateItem(m_Submenu);
|
|
InvalidateItem(m_ContextItem);
|
|
}
|
|
if (m_HotItem>=0 && m_HotItem==m_ProgramTreeIndex && s_MenuMode==MODE_PROGRAMS)
|
|
m_pProgramsTree->Invalidate();
|
|
else
|
|
InvalidateItem(m_HotItem);
|
|
if (index>=0 && index==m_ProgramTreeIndex && s_MenuMode==MODE_PROGRAMS)
|
|
m_pProgramsTree->Invalidate();
|
|
else
|
|
{
|
|
InvalidateItem(index);
|
|
if (index>=0 && m_pProgramsTree && m_pProgramsTree->m_hWnd && m_pProgramsTree->m_hWnd==GetFocus())
|
|
SetFocus();
|
|
}
|
|
m_HotItem=index;
|
|
m_bHotArrow=bArrow;
|
|
s_pTipMenu=NULL;
|
|
s_TipItem=-1;
|
|
UpdateUserPicture();
|
|
if (index>=0)
|
|
{
|
|
s_pHotMenu=this;
|
|
s_HotItem=index;
|
|
}
|
|
else if (s_pHotMenu==this)
|
|
{
|
|
s_pHotMenu=NULL;
|
|
s_HotItem=-1;
|
|
if (s_Tooltip.m_hWnd)
|
|
{
|
|
TOOLINFO tool={sizeof(tool),TTF_ABSOLUTE|TTF_TRACK|TTF_TRANSPARENT};
|
|
tool.uId=1;
|
|
s_Tooltip.SendMessage(TTM_TRACKACTIVATE,FALSE,(LPARAM)&tool);
|
|
}
|
|
}
|
|
else
|
|
return;
|
|
if (index>=0 && index<(int)m_Items.size())
|
|
{
|
|
if (bShowTip)
|
|
{
|
|
int show, hide;
|
|
if (m_Items[index].bFolder && m_Items[index].id!=MENU_SHUTDOWN_BUTTON)
|
|
show=s_TipShowTimeFolder, hide=s_TipHideTimeFolder;
|
|
else
|
|
show=s_TipShowTime, hide=s_TipHideTime;
|
|
if (s_Tooltip.m_hWnd)
|
|
{
|
|
TOOLINFO tool={sizeof(tool),TTF_ABSOLUTE|TTF_TRACK|TTF_TRANSPARENT};
|
|
tool.uId=1;
|
|
s_Tooltip.SendMessage(TTM_TRACKACTIVATE,FALSE,(LPARAM)&tool);
|
|
if (!s_Menus[0]->m_bDestroyed && hide>0)
|
|
{
|
|
s_pTipMenu=s_pHotMenu;
|
|
s_TipItem=s_HotItem;
|
|
s_Menus[0]->SetTimer(TIMER_TOOLTIP_SHOW,show);
|
|
}
|
|
}
|
|
}
|
|
NotifyWinEvent(EVENT_OBJECT_FOCUS,m_hWnd,OBJID_CLIENT,index+1);
|
|
}
|
|
}
|
|
|
|
void CMenuContainer::SetSubmenu( int index )
|
|
{
|
|
if (m_Submenu==index) return;
|
|
m_Submenu=index;
|
|
UpdateUserPicture();
|
|
}
|
|
|
|
void CMenuContainer::SetContextItem( int index )
|
|
{
|
|
if (m_ContextItem==index) return;
|
|
m_ContextItem=index;
|
|
UpdateUserPicture();
|
|
}
|
|
|
|
void CMenuContainer::SetClickItem( int index )
|
|
{
|
|
if (m_ClickIndex==index) return;
|
|
m_ClickIndex=index;
|
|
InvalidateItem(m_ClickIndex);
|
|
}
|
|
|
|
void CMenuContainer::UpdateUserPicture( void )
|
|
{
|
|
if (m_bTwoColumns && s_UserPicture.m_hWnd && s_UserPicture.IsWindowVisible())
|
|
{
|
|
HBITMAP bmp=NULL;
|
|
int bmpIndex=m_HotItem>=0?m_HotItem:(m_ContextItem>=0?m_ContextItem:m_Submenu);
|
|
if (bmpIndex>=0 && bmpIndex<m_OriginalCount && bmpIndex<(int)m_Items.size() && m_Items[bmpIndex].column==1 && m_Items[bmpIndex].pItemInfo && m_Items[bmpIndex].pItemInfo->extraLargeIcon)
|
|
bmp=m_Items[bmpIndex].pItemInfo->extraLargeIcon->bitmap;
|
|
s_UserPicture.StartImageTimer(bmp);
|
|
}
|
|
}
|
|
|
|
void CMenuContainer::SetInsertMark( int index, bool bAfter )
|
|
{
|
|
if (index==m_InsertMark && bAfter==m_bInsertAfter) return;
|
|
RECT rc;
|
|
if (GetInsertRect(rc))
|
|
InvalidateRect(&rc);
|
|
m_InsertMark=index;
|
|
m_bInsertAfter=bAfter;
|
|
if (GetInsertRect(rc))
|
|
InvalidateRect(&rc);
|
|
}
|
|
|
|
bool CMenuContainer::GetInsertRect( RECT &rc )
|
|
{
|
|
if (m_InsertMark<0 || m_InsertMark>=(int)m_Items.size())
|
|
return false;
|
|
const MenuItem &item=m_Items[m_InsertMark];
|
|
rc=item.itemRect;
|
|
if (m_bInsertAfter)
|
|
rc.top=rc.bottom;
|
|
if (m_ScrollHeight>0 && m_InsertMark<m_ScrollCount)
|
|
rc.top-=m_ScrollOffset;
|
|
const POINT *sizes=s_Skin.GetArrowsBitmapSizes();
|
|
int h=sizes[1].y;
|
|
rc.top-=h/2;
|
|
rc.bottom=rc.top+h;
|
|
return true;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnSetContextItem( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
for (int i=0;i<(int)m_Items.size();i++)
|
|
{
|
|
if (m_Items[i].nameHash==wParam)
|
|
{
|
|
SetContextItem(i);
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnColorEdit( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (!m_bNoSearchDraw)
|
|
PostMessage(MCM_REDRAWEDIT);
|
|
|
|
HDC hdc=(HDC)wParam;
|
|
SetTextColor(hdc,s_Skin.Search_text_colors[0]);
|
|
SetBkColor(hdc,s_Skin.Search_text_background);
|
|
SetDCBrushColor(hdc,s_Skin.Search_text_background);
|
|
return (LRESULT)GetStockObject(DC_BRUSH);
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnGesture( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
GESTUREINFO info={sizeof(info)};
|
|
if (GetGestureInfo((HGESTUREINFO)lParam,&info) && info.dwID==GID_PAN && info.hwndTarget==m_hWnd)
|
|
{
|
|
if (m_Submenu>=0)
|
|
{
|
|
SetActiveWindow();
|
|
CloseSubMenus(0,this);
|
|
}
|
|
if (info.dwFlags&GF_BEGIN)
|
|
{
|
|
m_PanPosY=info.ptsLocation.y;
|
|
BeginPanningFeedback(m_hWnd);
|
|
m_Overpan=0;
|
|
}
|
|
else if (info.dwFlags&GF_END)
|
|
{
|
|
EndPanningFeedback(m_hWnd,TRUE);
|
|
m_Overpan=0;
|
|
s_HotPos=GetMessagePos();
|
|
}
|
|
else
|
|
{
|
|
int dy=info.ptsLocation.y-m_PanPosY;
|
|
m_Overpan+=dy;
|
|
if (dy!=0 && (m_ScrollHeight>0 || m_SearchScrollCount>0))
|
|
{
|
|
bool bOverpan=false;
|
|
if (m_SearchScrollCount>0)
|
|
{
|
|
int height=s_Skin.ItemSettings[MenuSkin::LIST_ITEM].itemHeight;
|
|
int count=dy/height;
|
|
m_PanPosY+=count*height;
|
|
int pos0=m_SearchScrollPos;
|
|
int pos=m_SearchScrollPos-count;
|
|
m_SearchScrollPos=m_Scrollbar.SetScrollPos(SB_CTL,pos);
|
|
if (m_SearchScrollPos!=pos0)
|
|
InvalidateRect(&m_rContent);
|
|
bOverpan=(m_SearchScrollPos!=pos);
|
|
}
|
|
else
|
|
{
|
|
m_PanPosY=info.ptsLocation.y;
|
|
int scroll=m_ScrollOffset;
|
|
scroll-=dy;
|
|
if (scroll<0)
|
|
{
|
|
scroll=0;
|
|
bOverpan=true;
|
|
}
|
|
int total=m_Items[m_ScrollCount-1].itemRect.bottom-m_rContent.top-m_ScrollHeight;
|
|
if (scroll>total)
|
|
{
|
|
scroll=total;
|
|
bOverpan=true;
|
|
}
|
|
if (m_ScrollOffset!=scroll)
|
|
{
|
|
m_ScrollOffset=scroll;
|
|
UpdateScroll();
|
|
Invalidate();
|
|
s_HotPos=-1;
|
|
}
|
|
}
|
|
if (bOverpan)
|
|
UpdatePanningFeedback(m_hWnd,0,m_Overpan,info.dwFlags&GF_INERTIA);
|
|
else
|
|
m_Overpan=0;
|
|
}
|
|
}
|
|
CloseGestureInfoHandle((HGESTUREINFO)lParam);
|
|
return 0;
|
|
}
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnGestureNotify( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (!s_bHasTouch)
|
|
{
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
GESTURENOTIFYSTRUCT *pNotify=(GESTURENOTIFYSTRUCT*)lParam;
|
|
if (pNotify->hwndTarget==m_hWnd)
|
|
{
|
|
// if clicked on a scrollable item
|
|
bool bScrollable=false;
|
|
POINT pt={pNotify->ptsLocation.x,pNotify->ptsLocation.y};
|
|
ScreenToClient(&pt);
|
|
int idx=HitTest(pt,NULL);
|
|
if (idx>=0)
|
|
{
|
|
if (idx<m_ScrollCount && m_ScrollHeight>0)
|
|
bScrollable=true;
|
|
else if (idx>=m_OriginalCount && m_SearchScrollCount>0)
|
|
bScrollable=true;
|
|
}
|
|
if (bScrollable)
|
|
{
|
|
GESTURECONFIG config={GID_PAN,GC_PAN_WITH_SINGLE_FINGER_VERTICALLY|GC_PAN_WITH_INERTIA,GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY};
|
|
SetGestureConfig(pNotify->hwndTarget,0,1,&config,sizeof(config));
|
|
}
|
|
else
|
|
{
|
|
GESTURECONFIG config={0,0,GC_ALLGESTURES};
|
|
SetGestureConfig(pNotify->hwndTarget,0,1,&config,sizeof(config));
|
|
}
|
|
}
|
|
else if (m_pProgramsTree && pNotify->hwndTarget==m_pProgramsTree->m_hWnd)
|
|
{
|
|
GESTURECONFIG config={0,GC_ALLGESTURES,0};
|
|
SetGestureConfig(pNotify->hwndTarget,0,1,&config,sizeof(config));
|
|
}
|
|
else if (pNotify->hwndTarget==m_Scrollbar.m_hWnd)
|
|
{
|
|
GESTURECONFIG config={0,0,GC_ALLGESTURES};
|
|
SetGestureConfig(pNotify->hwndTarget,0,1,&config,sizeof(config));
|
|
}
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnPointerDown( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
m_PointerId=0;
|
|
if (s_bHasTouch && IS_POINTER_INCONTACT_WPARAM(wParam) && IS_POINTER_PRIMARY_WPARAM(wParam) && IS_POINTER_FIRSTBUTTON_WPARAM(wParam))
|
|
{
|
|
CPoint pt(lParam);
|
|
ScreenToClient(&pt);
|
|
UpdateScroll(&pt,true);
|
|
if (m_bScrollTimerTouch)
|
|
{
|
|
m_PointerId=GET_POINTERID_WPARAM(wParam);
|
|
return 0;
|
|
}
|
|
}
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnPointerUpdate( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (s_bHasTouch && m_PointerId==GET_POINTERID_WPARAM(wParam))
|
|
{
|
|
if (IS_POINTER_INCONTACT_WPARAM(wParam) && IS_POINTER_FIRSTBUTTON_WPARAM(wParam))
|
|
{
|
|
CPoint pt(lParam);
|
|
ScreenToClient(&pt);
|
|
UpdateScroll(&pt,true);
|
|
}
|
|
else
|
|
{
|
|
KillTimer(TIMER_SCROLL_TOUCH);
|
|
m_bScrollTimerTouch=false;
|
|
if (m_bScrollUpHot || m_bScrollDownHot)
|
|
{
|
|
m_bScrollUpHot=m_bScrollDownHot=false;
|
|
Invalidate();
|
|
}
|
|
m_PointerId=0;
|
|
}
|
|
return 0;
|
|
}
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnPointerUp( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (s_bHasTouch && m_PointerId==GET_POINTERID_WPARAM(wParam))
|
|
{
|
|
KillTimer(TIMER_SCROLL_TOUCH);
|
|
m_bScrollTimerTouch=false;
|
|
if (m_bScrollUpHot || m_bScrollDownHot)
|
|
{
|
|
m_bScrollUpHot=m_bScrollDownHot=false;
|
|
Invalidate();
|
|
}
|
|
m_PointerId=0;
|
|
return 0;
|
|
}
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
STDMETHODIMP CMenuContainer::QueryInterface( REFIID riid, void **ppvObject )
|
|
{
|
|
if (riid==IID_IUnknown || riid==IID_IDropTarget)
|
|
{
|
|
*ppvObject=static_cast<IDropTarget*>(this);
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
if (riid==__uuidof(IFrameworkInputPaneHandler))
|
|
{
|
|
*ppvObject=static_cast<IFrameworkInputPaneHandler*>(this);
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
*ppvObject=NULL;
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CMenuContainer::Showing( RECT *prcInputPaneScreenLocation, BOOL fEnsureFocusedElementInView )
|
|
{
|
|
NotifyDisplayChange();
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CMenuContainer::Hiding( BOOL fEnsureFocusedElementInView )
|
|
{
|
|
NotifyDisplayChange();
|
|
return S_OK;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnRedrawEdit( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
m_SearchBox.RedrawWindow();
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnRefreshIcons( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
for (std::vector<CMenuContainer*>::iterator it=s_Menus.begin();it!=s_Menus.end();++it)
|
|
if (!(*it)->m_bDestroyed)
|
|
{
|
|
(*it)->Invalidate();
|
|
if (m_pProgramsTree && m_pProgramsTree->m_hWnd)
|
|
m_pProgramsTree->Invalidate();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void CMenuContainer::RefreshIcons( void )
|
|
{
|
|
// this is called from the background thread
|
|
HWND first=s_FirstMenu; // must copy into a temp variable because we don't want the value to change in the middle of the next two lines
|
|
if (first)
|
|
::PostMessage(first,MCM_REFRESHICONS,0,0);
|
|
}
|
|
|
|
void CMenuContainer::RefreshSearch( void )
|
|
{
|
|
// this is called from the background thread
|
|
HWND search=s_SearchMenu; // must copy into a temp variable because we don't want the value to change in the middle of the next two lines
|
|
if (search)
|
|
::PostMessage(search,MCM_REFRESH,0,0);
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnSetHotItem( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
int index=(int)wParam;
|
|
while (index<(int)m_Items.size() && !CanSelectItem(index,false))
|
|
index++;
|
|
if (index<(int)m_Items.size())
|
|
SetHotItem(index,false,true);
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnStartMenuMsg( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (lParam)
|
|
s_StartMenuParams=*(StartMenuParams*)lParam;
|
|
return 0;
|
|
}
|
|
|
|
void CMenuContainer::SetSearchState( TSearchState state )
|
|
{
|
|
if (m_SearchState==state)
|
|
return;
|
|
if (m_Submenu!=-1)
|
|
{
|
|
InvalidateRect(&m_Items[m_Submenu].itemRect);
|
|
SetSubmenu(-1);
|
|
}
|
|
InvalidateRect(&m_Items[m_SearchIndex].itemRect);
|
|
if (m_SearchState==SEARCH_TEXT && state!=SEARCH_TEXT)
|
|
{
|
|
// close the search menu
|
|
m_SearchScrollCount=0;
|
|
if (s_MenuMode==MODE_SEARCH)
|
|
SetMenuMode(s_PreSearchMenuMode);
|
|
else
|
|
CloseSubMenus(CLOSE_ONLY_SEARCH,this); // can't use CLOSE_POST here because the menu needs to be closed while m_bInSearchUpdate is set
|
|
g_SearchManager.BeginSearch(CString());
|
|
}
|
|
m_SearchState=state;
|
|
if (m_SearchState==SEARCH_NONE)
|
|
s_bDisableHover=false;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnEditChange( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
|
|
{
|
|
s_bPendingSearchEnter=false;
|
|
m_SearchBox.RedrawWindow();
|
|
wchar_t text[256];
|
|
m_SearchBox.GetWindowText(text,_countof(text));
|
|
DoEnvironmentSubst(text,_countof(text));
|
|
unsigned int hash=CalcFNVHash(text);
|
|
if (m_SearchHash!=hash && !m_bInSearchUpdate)
|
|
SetTimer(TIMER_SEARCH,100);
|
|
m_SearchHash=hash;
|
|
return 0;
|
|
}
|
|
|
|
void CMenuContainer::UpdateSearchResults( bool bForceShowAll )
|
|
{
|
|
if (m_bInSearchUpdate)
|
|
return;
|
|
m_bInSearchUpdate=true;
|
|
wchar_t text[256];
|
|
m_SearchBox.GetWindowText(text,_countof(text));
|
|
DoEnvironmentSubst(text,_countof(text));
|
|
wchar_t *pText=text;
|
|
while (*pText==' ' || *pText=='\t')
|
|
pText++;
|
|
TSearchState state=SEARCH_NONE;
|
|
if (*pText)
|
|
{
|
|
int len=Strlen(pText);
|
|
while (len>0 && (pText[len-1]==' ' || pText[len-1]=='\t'))
|
|
len--;
|
|
pText[len]=0;
|
|
CharUpper(pText);
|
|
s_SearchResults.currentString=pText;
|
|
g_SearchManager.BeginSearch(s_SearchResults.currentString);
|
|
s_SearchResults.bSearching=true;
|
|
s_bPendingSearchEnter=false;
|
|
if (s_bWin7Style)
|
|
{
|
|
MenuItem &item=m_Items[m_SearchIndex-m_SearchItemCount+1];
|
|
item.id=MENU_SEARCH_EMPTY;
|
|
item.name=FindTranslation(L"Menu.Searching",L"Searching...");
|
|
item.pItemInfo=g_ItemManager.GetCustomIcon(L"imageres.dll,8",CItemManager::ICON_SIZE_TYPE_SMALL);
|
|
}
|
|
if (m_Submenu!=m_SearchIndex && s_MenuMode!=MODE_SEARCH)
|
|
{
|
|
ActivateData data;
|
|
data.bNoModifiers=true;
|
|
ActivateItem(m_SearchIndex,ACTIVATE_OPEN_SEARCH,NULL,&data);
|
|
}
|
|
Assert(s_SearchMenu);
|
|
RefreshSearch();
|
|
state=SEARCH_TEXT;
|
|
}
|
|
else if (GetFocus()==m_SearchBox.m_hWnd)
|
|
{
|
|
state=SEARCH_BLANK;
|
|
}
|
|
SetSearchState(state);
|
|
m_bInSearchUpdate=false;
|
|
}
|
|
|
|
// Turn on the keyboard cues from now on. This is done when a keyboard action is detected
|
|
void CMenuContainer::ShowKeyboardCues( void )
|
|
{
|
|
if (!s_bKeyboardCues)
|
|
{
|
|
s_bKeyboardCues=true;
|
|
for (std::vector<CMenuContainer*>::const_iterator it=s_Menus.begin();it!=s_Menus.end();++it)
|
|
(*it)->Invalidate();
|
|
}
|
|
}
|
|
|
|
void CMenuContainer::SetActiveWindow( void )
|
|
{
|
|
HWND active=GetActiveWindow();
|
|
if (active!=m_hWnd && active!=m_SearchBox.m_hWnd)
|
|
::SetActiveWindow(m_hWnd);
|
|
if (!m_bSubMenu && s_bBehindTaskbar && s_TaskBar)
|
|
SetWindowPos(s_TaskBar,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE); // make sure the top menu stays behind the taskbar
|
|
}
|
|
|
|
void CMenuContainer::PostRefreshMessage( void )
|
|
{
|
|
if (!m_bDestroyed)
|
|
{
|
|
if (!InterlockedExchange(&m_RefreshPosted,1))
|
|
PostMessage(MCM_REFRESH);
|
|
}
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnSysCommand( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if ((wParam&0xFFF0)==SC_KEYMENU)
|
|
{
|
|
// stops Alt from activating the window menu
|
|
ShowKeyboardCues();
|
|
s_bOverrideFirstDown=false;
|
|
}
|
|
else
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnSettingChange( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (wParam==SPI_SETWORKAREA)
|
|
NotifyDisplayChange();
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
void CMenuContainer::NotifyDisplayChange( void )
|
|
{
|
|
if (!m_bSubMenu && !m_bWorkAreaPosted && !s_bLockWorkArea)
|
|
{
|
|
m_bWorkAreaPosted=true;
|
|
PostMessage(MCM_WORKAREACHANGED);
|
|
}
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnDisplayChange( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
NotifyDisplayChange();
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnWorkAreaChanged( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
Assert(!m_bSubMenu);
|
|
Assert(!s_bLockWorkArea);
|
|
|
|
// resize main menu
|
|
RECT taskbarRect;
|
|
UINT uEdge=GetTaskbarPosition(s_TaskBar,NULL,NULL,&taskbarRect);
|
|
if (uEdge==s_TaskBarEdge)
|
|
{
|
|
RECT area=CalculateWorkArea(taskbarRect);
|
|
if (memcmp(&area,&s_MainMenuLimits,sizeof(RECT))!=0)
|
|
{
|
|
s_MainMenuLimits=area;
|
|
s_MenuHeight=-1;
|
|
POINT corner=CalculateCorner();
|
|
RECT menuRect;
|
|
InitWindowInternal(false,corner,menuRect);
|
|
if (s_MenuMode==MODE_PROGRAMS)
|
|
{
|
|
// resize programs tree
|
|
MenuItem &item=m_Items[m_ProgramTreeIndex];
|
|
item.itemRect=m_rContent;
|
|
item.itemRect.bottom=m_Items[m_ProgramTreeIndex+1].itemRect.top;
|
|
RECT rc;
|
|
m_pProgramsTree->GetWindowRect(&rc);
|
|
int dh=rc.bottom-rc.top;
|
|
m_pProgramsTree->GetClientRect(&rc);
|
|
dh-=rc.bottom;
|
|
int itemHeight=TreeView_GetItemHeight(m_pProgramsTree->m_hWnd);
|
|
rc=item.itemRect;
|
|
int h=rc.bottom-rc.top;
|
|
int n=(h-dh)/itemHeight;
|
|
rc.bottom=rc.top+n*itemHeight+dh;
|
|
m_pProgramsTree->SetWindowPos(NULL,&rc,SWP_NOZORDER|SWP_NOACTIVATE);
|
|
}
|
|
else if (s_MenuMode==MODE_SEARCH)
|
|
{
|
|
// HACK: before initializing the search items we need to know the size of the menu, so InitWindow needs to be called twice
|
|
InitSearchItems();
|
|
InitWindowInternal(false,corner,menuRect);
|
|
}
|
|
|
|
if (s_UserPicture.m_hWnd && s_UserPictureRect.top<s_UserPictureRect.bottom)
|
|
{
|
|
s_UserPicture.SetWindowPos(NULL,&s_UserPictureRect,SWP_NOZORDER|SWP_NOACTIVATE);
|
|
s_UserPicture.Update();
|
|
}
|
|
InitWindowFinalize(menuRect);
|
|
UpdateWindow();
|
|
}
|
|
}
|
|
|
|
m_bWorkAreaPosted=false;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (wParam==TIMER_HOVER)
|
|
{
|
|
LOG_MENU(LOG_MOUSE,L"End Hover, hover=%d%s, hot=%d, submenu=%d",m_HoverItem,m_bHoverArrow?L"(arrow)":L"",m_HotItem,m_Submenu);
|
|
// the mouse hovers over an item. open it.
|
|
if (m_HoverItem>=0)
|
|
{
|
|
if (m_HoverItem!=m_Submenu && m_HoverItem!=m_SubJumpItem && m_HoverItem==m_HotItem && m_bHoverArrow==m_bHotArrow && !s_bDisableHover && m_SearchState<=SEARCH_BLANK)
|
|
{
|
|
if (m_HoverItem==m_ProgramTreeIndex)
|
|
m_pProgramsTree->SetFocus();
|
|
ActivateItem(m_HoverItem,ACTIVATE_OPEN,NULL);
|
|
m_SubShowTime=GetTickCount();
|
|
}
|
|
if (m_HoverItem==m_ProgramButtonIndex)
|
|
m_bDisableProgHover=true;
|
|
m_HoverItem=-1;
|
|
KillTimer(TIMER_HOVER);
|
|
}
|
|
return 0;
|
|
}
|
|
if (wParam==TIMER_SCROLL_MOUSE || wParam==TIMER_SCROLL_TOUCH)
|
|
{
|
|
if (wParam==TIMER_SCROLL_MOUSE && s_bHasTouch && GetKeyState(VK_LBUTTON)>=0)
|
|
return 0;
|
|
int speed=GetSettingInt(m_bSubMenu?L"SubMenuScrollSpeed":L"MainMenuScrollSpeed");
|
|
if (speed<1) speed=1;
|
|
if (speed>20) speed=20;
|
|
int scroll=m_ScrollOffset;
|
|
if (m_bScrollUp && m_bScrollUpHot)
|
|
{
|
|
scroll-=s_Skin.ItemSettings[m_bSubMenu?MenuSkin::SUBMENU_ITEM:MenuSkin::COLUMN1_ITEM].itemHeight*speed/6;
|
|
if (scroll<0) scroll=0;
|
|
}
|
|
else if (m_bScrollDown && m_bScrollDownHot)
|
|
{
|
|
scroll+=s_Skin.ItemSettings[m_bSubMenu?MenuSkin::SUBMENU_ITEM:MenuSkin::COLUMN1_ITEM].itemHeight*speed/6;
|
|
int total=m_Items[m_ScrollCount-1].itemRect.bottom-m_rContent.top-m_ScrollHeight;
|
|
if (scroll>total) scroll=total;
|
|
}
|
|
if (m_ScrollOffset!=scroll)
|
|
{
|
|
m_ScrollOffset=scroll;
|
|
UpdateScroll();
|
|
if (!m_bScrollUp && !m_bScrollDown)
|
|
KillTimer(wParam);
|
|
Invalidate();
|
|
}
|
|
}
|
|
if (wParam==TIMER_TOOLTIP_SHOW)
|
|
{
|
|
KillTimer(TIMER_TOOLTIP_SHOW);
|
|
|
|
if (!s_pHotMenu || s_pHotMenu->m_bDestroyed)
|
|
return 0;
|
|
if (s_pHotMenu!=s_pTipMenu || s_HotItem!=s_TipItem)
|
|
return 0;
|
|
|
|
if (std::find(s_Menus.begin(),s_Menus.end(),s_pHotMenu)==s_Menus.end())
|
|
return 0;
|
|
|
|
if (s_HotItem>=(int)s_pHotMenu->m_Items.size())
|
|
return 0;
|
|
|
|
if (!m_bSubMenu && s_MenuMode==MODE_SEARCH && s_SearchResults.bSearching)
|
|
return 0;
|
|
|
|
TOOLINFO tool={sizeof(tool),TTF_ABSOLUTE|TTF_TRACK|TTF_TRANSPARENT|(s_bRTL?TTF_RTLREADING:0U)};
|
|
tool.uId=1;
|
|
|
|
wchar_t text[1024];
|
|
if (!s_pHotMenu->GetDescription(s_HotItem,text,_countof(text)))
|
|
return 0;
|
|
|
|
RECT rc;
|
|
s_pHotMenu->GetItemRect(s_HotItem,rc);
|
|
s_pHotMenu->MapWindowPoints(NULL,&rc);
|
|
DWORD pos=GetMessagePos();
|
|
POINT pt={(short)LOWORD(pos),(short)HIWORD(pos)};
|
|
if (PtInRect(&rc,pt))
|
|
{
|
|
pt.x+=8;
|
|
pt.y+=16;
|
|
}
|
|
else if (!(s_pHotMenu->m_Options&CONTAINER_SEARCH))
|
|
{
|
|
pt.x=(rc.left+rc.right)/2;
|
|
pt.y=rc.bottom;
|
|
}
|
|
else
|
|
return 0;
|
|
|
|
tool.lpszText=text;
|
|
s_Tooltip.SendMessage(TTM_UPDATETIPTEXT,0,(LPARAM)&tool);
|
|
s_Tooltip.SendMessage(TTM_TRACKPOSITION,0,MAKELONG(pt.x,pt.y));
|
|
s_Tooltip.SendMessage(TTM_TRACKACTIVATE,TRUE,(LPARAM)&tool);
|
|
|
|
// make sure the tooltip is inside the monitor
|
|
s_Tooltip.GetWindowRect(&rc);
|
|
int dx=0, dy=0;
|
|
if (rc.left<s_MenuLimits.left) dx=s_MenuLimits.left-rc.left;
|
|
if (rc.right+dx>s_MenuLimits.right) dx-=rc.right-s_MenuLimits.right;
|
|
if (rc.top<s_MenuLimits.top) dy=s_MenuLimits.top-rc.top;
|
|
if (rc.bottom+dy>s_MenuLimits.bottom) dy-=rc.bottom-s_MenuLimits.bottom;
|
|
if (dx || dy)
|
|
s_Tooltip.SendMessage(TTM_TRACKPOSITION,0,MAKELONG(pt.x+dx,pt.y+dy));
|
|
|
|
if (s_pHotMenu->m_Items[s_HotItem].bFolder && s_pHotMenu->m_Items[s_HotItem].id!=MENU_SHUTDOWN_BUTTON)
|
|
SetTimer(TIMER_TOOLTIP_HIDE,s_TipHideTimeFolder);
|
|
else
|
|
SetTimer(TIMER_TOOLTIP_HIDE,s_TipHideTime);
|
|
return 0;
|
|
}
|
|
if (wParam==TIMER_TOOLTIP_HIDE)
|
|
{
|
|
TOOLINFO tool={sizeof(tool),TTF_ABSOLUTE|TTF_TRACK|TTF_TRANSPARENT};
|
|
tool.uId=1;
|
|
s_Tooltip.SendMessage(TTM_TRACKACTIVATE,FALSE,(LPARAM)&tool);
|
|
KillTimer(TIMER_TOOLTIP_HIDE);
|
|
return 0;
|
|
}
|
|
if (wParam==TIMER_BALLOON_HIDE)
|
|
{
|
|
TOOLINFO tool={sizeof(tool)};
|
|
tool.uId=1;
|
|
if (s_TooltipBalloon.m_hWnd)
|
|
s_TooltipBalloon.SendMessage(TTM_TRACKACTIVATE,FALSE,(LPARAM)&tool);
|
|
KillTimer(TIMER_BALLOON_HIDE);
|
|
}
|
|
if (wParam==TIMER_SEARCH)
|
|
{
|
|
UpdateSearchResults(false);
|
|
KillTimer(TIMER_SEARCH);
|
|
}
|
|
if (wParam==TIMER_DRAG)
|
|
{
|
|
if (!s_bDragClosed)
|
|
{
|
|
// if the mouse is outside of the menu for more than 4 seconds close the menu
|
|
DWORD pos=GetMessagePos();
|
|
POINT pt={(short)LOWORD(pos),(short)HIWORD(pos)};
|
|
HWND hWnd=WindowFromPoint(pt);
|
|
if (hWnd) hWnd=GetAncestor(hWnd,GA_ROOT);
|
|
wchar_t name[256];
|
|
if (hWnd)
|
|
GetClassName(hWnd,name,_countof(name));
|
|
else
|
|
name[0]=0;
|
|
|
|
if (_wcsicmp(name,L"OpenShell.CMenuContainer")!=0)
|
|
{
|
|
int dt=GetMessageTime()-m_DragTime;
|
|
if (dt>GetSettingInt(L"DragHideDelay"))
|
|
{
|
|
HideStartMenu();
|
|
KillTimer(TIMER_DRAG);
|
|
s_bDragClosed=true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_DragTime=GetMessageTime();
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Handle right-click and the menu keyboard button
|
|
LRESULT CMenuContainer::OnContextMenu( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (s_bNoContextMenu) return 0;
|
|
POINT pt={(short)LOWORD(lParam),(short)HIWORD(lParam)};
|
|
int index;
|
|
BOOL bPad=FALSE;
|
|
if (pt.x!=-1 || pt.y!=-1)
|
|
{
|
|
POINT pt2=pt;
|
|
ScreenToClient(&pt2);
|
|
index=HitTest(pt2,NULL);
|
|
if (index<0)
|
|
bPad=PtInRect(&m_rPadding,pt2);
|
|
if (index<0 && !bPad) return 0;
|
|
ActivateItem(index,ACTIVATE_MENU,&pt);
|
|
}
|
|
else
|
|
{
|
|
index=m_HotItem;
|
|
if (index<0 && !bPad) return 0;
|
|
ActivateItem(index,ACTIVATE_MENU,NULL);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnVScroll( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
int pos0=m_SearchScrollPos;
|
|
int pos=pos0;
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case SB_TOP:
|
|
pos=0;
|
|
break;
|
|
case SB_BOTTOM:
|
|
pos=m_SearchScrollCount;
|
|
break;
|
|
case SB_LINEUP:
|
|
pos--;
|
|
break;
|
|
case SB_LINEDOWN:
|
|
pos++;
|
|
break;
|
|
case SB_PAGEUP:
|
|
pos-=m_SearchScrollHeight;
|
|
break;
|
|
case SB_PAGEDOWN:
|
|
pos+=m_SearchScrollHeight;
|
|
break;
|
|
case SB_THUMBTRACK:
|
|
pos=HIWORD(wParam);
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
m_SearchScrollPos=m_Scrollbar.SetScrollPos(SB_CTL,pos);
|
|
if (m_SearchScrollPos!=pos0)
|
|
InvalidateRect(&m_rContent);
|
|
return 0;
|
|
}
|
|
|
|
bool CMenuContainer::CanSelectItem( int index, bool bKeyboard )
|
|
{
|
|
if (!m_bSubMenu)
|
|
{
|
|
if (s_MenuMode==MODE_PROGRAMS && index<m_ScrollCount)
|
|
return false;
|
|
if (s_bWin7Style && s_MenuMode!=MODE_PROGRAMS && index==m_ProgramTreeIndex)
|
|
return false;
|
|
}
|
|
const MenuItem &item=m_Items[index];
|
|
if (!m_bSubMenu && s_MenuMode==MODE_SEARCH && index<m_OriginalCount && item.id!=MENU_SEARCH_BOX && item.id!=MENU_SHUTDOWN_BUTTON && item.id!=MENU_MORE_RESULTS && item.id!=MENU_SEARCH_INTERNET && item.id!=MENU_SEARCH_PROVIDER)
|
|
return false;
|
|
if (item.id==MENU_SEPARATOR || item.id==MENU_SEARCH_EMPTY)
|
|
return false;
|
|
if (item.itemRect.bottom==item.itemRect.top)
|
|
return false;
|
|
if (bKeyboard && item.id==MENU_SEARCH_BOX && GetSettingInt(L"SearchBox")!=SEARCHBOX_NORMAL)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnKeyDown( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
ShowKeyboardCues();
|
|
bool bOldOverride=s_bOverrideFirstDown;
|
|
s_bOverrideFirstDown=false;
|
|
|
|
if (wParam==VK_TAB)
|
|
{
|
|
if (s_bWin7Style && m_bTwoColumns)
|
|
{
|
|
if (s_MenuMode==MODE_SEARCH)
|
|
return 0; // no tabbing in search because the search box keeps the focus at all times
|
|
// tab order - 0 - left column, 1 - all programs, 2 - search, 3 - right column, 4 - shutdown
|
|
int tab=1; // so if nothing is selected the first tab goes to the search box
|
|
if (m_SearchBox.m_hWnd && GetFocus()==m_SearchBox.m_hWnd)
|
|
tab=2;
|
|
else if (m_pProgramsTree && m_pProgramsTree->m_hWnd && m_pProgramsTree->m_hWnd==GetFocus())
|
|
tab=0;
|
|
else if (m_HotItem>=0)
|
|
{
|
|
const MenuItem &item=m_Items[m_HotItem];
|
|
if (item.id==MENU_PROGRAMS)
|
|
tab=1;
|
|
else if (item.id==MENU_SEARCH_BOX)
|
|
tab=2;
|
|
else if (item.id==MENU_SHUTDOWN_BUTTON)
|
|
tab=4;
|
|
else
|
|
tab=(item.column==0?0:3);
|
|
}
|
|
if (GetKeyState(VK_SHIFT)<0)
|
|
{
|
|
tab=(tab+4)%5;
|
|
if (tab==2 && m_SearchIndex==-1)
|
|
tab=1;
|
|
if (tab==4 && GetSettingInt(L"ShutdownCommand")==SHUTDOWN_TYPE_NONE)
|
|
tab=3;
|
|
}
|
|
else
|
|
{
|
|
tab=(tab+1)%5;
|
|
if (tab==2 && m_SearchIndex==-1)
|
|
tab=3;
|
|
if (tab==4 && GetSettingInt(L"ShutdownCommand")==SHUTDOWN_TYPE_NONE)
|
|
tab=0;
|
|
}
|
|
int index=-1;
|
|
if (tab==0 || tab==3)
|
|
{
|
|
int column=(tab==0)?0:1;
|
|
int miny=32768;
|
|
for (int i=0;i<(int)m_Items.size();i++)
|
|
if (m_Items[i].column==column && m_Items[i].itemRect.top<miny && CanSelectItem(i))
|
|
{
|
|
miny=m_Items[i].itemRect.top;
|
|
index=i;
|
|
}
|
|
}
|
|
else if (tab==1)
|
|
index=m_ProgramButtonIndex;
|
|
else if (tab==2)
|
|
index=m_SearchIndex;
|
|
else if (tab==4)
|
|
{
|
|
for (int i=0;i<(int)m_Items.size();i++)
|
|
if (m_Items[i].id==MENU_SHUTDOWN_BUTTON)
|
|
{
|
|
index=i;
|
|
break;
|
|
}
|
|
}
|
|
if (index>=0)
|
|
{
|
|
CloseSubMenus(CLOSE_KEEP_MODE,this);
|
|
ActivateItem(index,ACTIVATE_SELECT,NULL);
|
|
}
|
|
return 0;
|
|
}
|
|
else if (m_SearchBox.m_hWnd && m_SearchState==SEARCH_NONE)
|
|
{
|
|
// destroy old submenus
|
|
CloseSubMenus(0,this);
|
|
ActivateItem(m_SearchIndex,ACTIVATE_SELECT,NULL);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int index=m_HotItem;
|
|
|
|
if (index>=0 && m_SearchState==SEARCH_NONE)
|
|
{
|
|
if (wParam==VK_F2)
|
|
{
|
|
if (m_Items[index].id==MENU_NO && m_Items[index].pItem1 && !m_Items[index].pItem2)
|
|
{
|
|
ActivateItem(index,ACTIVATE_RENAME,NULL);
|
|
if (IsWindow()) PostMessage(MCM_SETHOTITEM,index);
|
|
}
|
|
return 0;
|
|
}
|
|
if (wParam==VK_DELETE)
|
|
{
|
|
if ((m_Items[index].id==MENU_NO || m_Items[index].id==MENU_RECENT) && m_Items[index].pItem1 && !m_Items[index].pItem2)
|
|
{
|
|
ActivateItem(index,ACTIVATE_DELETE,NULL);
|
|
if (IsWindow()) PostMessage(MCM_SETHOTITEM,index);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
if (!m_bSubMenu && m_SearchIndex>=0 && wParam=='F' && GetKeyState(VK_CONTROL)<0)
|
|
{
|
|
ActivateItem(m_SearchIndex,ACTIVATE_SELECT,NULL);
|
|
return 0;
|
|
}
|
|
|
|
if (wParam==VK_HOME || wParam==VK_END)
|
|
{
|
|
// select first or last in the given column
|
|
int column=-1;
|
|
if (s_bWin7Style && m_bTwoColumns && m_HotItem>=0)
|
|
column=m_Items[m_HotItem].column;
|
|
int index=-1;
|
|
for (int i=0;i<(int)m_Items.size();i++)
|
|
{
|
|
const MenuItem &item=m_Items[i];
|
|
if ((column==-1 || item.column==column) && CanSelectItem(i) && item.id!=MENU_SEARCH_BOX)
|
|
{
|
|
if (s_bWin7Style && m_bTwoColumns && (item.id==MENU_PROGRAMS || item.id==MENU_MORE_RESULTS || item.id==MENU_SEARCH_INTERNET || item.id==MENU_SEARCH_PROVIDER || item.id==MENU_SHUTDOWN_BUTTON))
|
|
continue;
|
|
index=i;
|
|
if (wParam==VK_HOME) break;
|
|
}
|
|
}
|
|
if (index>=0)
|
|
{
|
|
CloseSubMenus(CLOSE_KEEP_MODE,this);
|
|
ActivateItem(index,ACTIVATE_SELECT,NULL);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if (wParam==VK_PRIOR || wParam==VK_NEXT)
|
|
{
|
|
int index=m_HotItem<0?0:m_HotItem;
|
|
if (m_ScrollHeight>0)
|
|
{
|
|
// scrolling menu
|
|
if (index>=m_ScrollCount) return 0;
|
|
int count=m_ScrollHeight/s_Skin.ItemSettings[m_bSubMenu?MenuSkin::SUBMENU_ITEM:MenuSkin::COLUMN1_ITEM].itemHeight-1;
|
|
int newIndex=index;
|
|
for (int i=0;i<count;i++)
|
|
{
|
|
if (wParam==VK_PRIOR)
|
|
{
|
|
newIndex--;
|
|
if (newIndex<0) break;
|
|
}
|
|
else
|
|
{
|
|
newIndex++;
|
|
if (newIndex>=m_ScrollCount) break;
|
|
}
|
|
if (CanSelectItem(newIndex))
|
|
index=newIndex;
|
|
}
|
|
}
|
|
else if (m_SearchScrollCount>m_SearchScrollHeight)
|
|
{
|
|
int index0=index;
|
|
if (wParam==VK_PRIOR)
|
|
{
|
|
if (index<m_OriginalCount)
|
|
index=m_OriginalCount;
|
|
else
|
|
{
|
|
index-=m_SearchScrollHeight;
|
|
if (index<m_OriginalCount) index=m_OriginalCount;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (index<m_OriginalCount)
|
|
index=m_OriginalCount;
|
|
else
|
|
{
|
|
int last=(int)m_Items.size()-1;
|
|
index+=m_SearchScrollHeight;
|
|
if (index>last) index=last;
|
|
}
|
|
}
|
|
if (index0==index) return 0;
|
|
if (m_Items[index].pItemInfo)
|
|
{
|
|
CString path;
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
path=m_Items[index].pItemInfo->GetPath();
|
|
}
|
|
if (!path.IsEmpty())
|
|
UpdateAutoComplete(path);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// multiple columns
|
|
if (!m_bSubMenu) return 0;
|
|
if (wParam==VK_PRIOR)
|
|
{
|
|
int column=m_Items[index].column;
|
|
if (index>0 && m_Items.rbegin()->column>0 && m_Items[index-1].column!=column)
|
|
column--;
|
|
for (int i=0;i<index;i++)
|
|
if (CanSelectItem(i) && m_Items[i].column==column)
|
|
{
|
|
index=i;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int column=m_Items[index].column;
|
|
if (index<(int)m_Items.size()-1 && m_Items.rbegin()->column>0 && m_Items[index+1].column!=column)
|
|
column++;
|
|
for (int i=index;i<(int)m_Items.size();i++)
|
|
if (CanSelectItem(i) && m_Items[i].column==column)
|
|
index=i;
|
|
}
|
|
}
|
|
if (index>=0)
|
|
{
|
|
CloseSubMenus(0,this);
|
|
ActivateItem(index,ACTIVATE_SELECT,NULL);
|
|
}
|
|
}
|
|
|
|
if (wParam!=VK_UP && wParam!=VK_DOWN && wParam!=VK_LEFT && wParam!=VK_RIGHT && wParam!=VK_ESCAPE && wParam!=VK_RETURN)
|
|
return TRUE;
|
|
|
|
if (index<0 && m_SearchState!=SEARCH_NONE)
|
|
index=m_SearchIndex;
|
|
if (index<0) index=-1;
|
|
bool bProgramsTree=(!m_bSubMenu && s_MenuMode==MODE_PROGRAMS && GetFocus()==m_pProgramsTree->m_hWnd);
|
|
if (bProgramsTree)
|
|
index=m_ProgramTreeIndex;
|
|
|
|
int n=(int)m_Items.size();
|
|
|
|
if (wParam==VK_UP)
|
|
{
|
|
// previous item
|
|
int best=-1;
|
|
if (index<0)
|
|
{
|
|
// no item is selected - find the first selectable item in the last column then go up
|
|
int col=(m_bTwoColumns?1:0);
|
|
index=0;
|
|
for (int i=0;i<n;i++)
|
|
{
|
|
const MenuItem &item=m_Items[i];
|
|
if (item.column==col && CanSelectItem(i) && (!item.bInline || item.bInlineFirst) && (s_MenuMode!=MODE_SEARCH || item.id!=MENU_SHUTDOWN_BUTTON))
|
|
{
|
|
index=i;
|
|
break;
|
|
}
|
|
}
|
|
best=index;
|
|
}
|
|
if (m_SearchScrollCount>0 && index==m_SearchIndex-m_SearchItemCount+1)
|
|
{
|
|
best=m_OriginalCount+m_SearchScrollCount-1;
|
|
}
|
|
else if (m_SearchScrollCount>0 && index>m_OriginalCount)
|
|
{
|
|
best=index-1;
|
|
}
|
|
else
|
|
{
|
|
int col=m_Items[index].column;
|
|
int x0=m_Items[index].itemRect.left;
|
|
int y0=m_Items[index].itemRect.top;
|
|
int scrollOffset=0;
|
|
if (m_ScrollCount>0)
|
|
scrollOffset=m_Items[m_ScrollCount-1].itemRect.bottom-m_rContent.top-m_ScrollHeight;
|
|
if (index<m_ScrollCount)
|
|
y0-=scrollOffset;
|
|
int dist=0x7FFFFFFF;
|
|
for (int i=1;i<n;i++)
|
|
{
|
|
int idx=(index+n-i)%n;
|
|
if (!CanSelectItem(idx))
|
|
continue;
|
|
const MenuItem &item=m_Items[idx];
|
|
int d=0x7FFFFFFE;
|
|
int bottom=item.itemRect.bottom;
|
|
if (idx<m_ScrollCount)
|
|
bottom-=scrollOffset;
|
|
if (!(m_Options&CONTAINER_SEARCH))
|
|
{
|
|
if (m_SearchScrollCount>0 && i>=m_OriginalCount)
|
|
continue;
|
|
if (item.column==col && bottom<=y0)
|
|
{
|
|
d=((y0-bottom)<<16)+abs(item.itemRect.left-x0);
|
|
}
|
|
else if (item.bInline && !item.bInlineFirst)
|
|
continue;
|
|
else if (s_MenuMode==MODE_SEARCH && item.id==MENU_SHUTDOWN_BUTTON)
|
|
continue;
|
|
}
|
|
if (d<dist)
|
|
{
|
|
dist=d;
|
|
best=idx;
|
|
}
|
|
}
|
|
}
|
|
if (best>=0)
|
|
{
|
|
ActivateItem(best,ACTIVATE_SELECT,NULL);
|
|
if ((m_Items[best].categoryHash&CSearchManager::CATEGORY_MASK)==CSearchManager::CATEGORY_AUTOCOMPLETE && m_Items[best].pItemInfo)
|
|
{
|
|
CString path;
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
path=m_Items[best].pItemInfo->GetPath();
|
|
}
|
|
if (!path.IsEmpty())
|
|
{
|
|
if (m_Options&CONTAINER_SEARCH)
|
|
m_pParent->UpdateAutoComplete(path);
|
|
else
|
|
UpdateAutoComplete(path);
|
|
}
|
|
}
|
|
if (!m_bSubMenu && s_MenuMode==MODE_PROGRAMS && best==m_ProgramTreeIndex)
|
|
m_pProgramsTree->SelectLast();
|
|
}
|
|
}
|
|
if (wParam==VK_DOWN)
|
|
{
|
|
// next item
|
|
if (bOldOverride)
|
|
index=-1;
|
|
int best=-1;
|
|
if (index<0)
|
|
{
|
|
// no item is selected - find the last selectable item then go down
|
|
index=0;
|
|
for (int i=n-1;i>=0;i--)
|
|
{
|
|
const MenuItem &item=m_Items[i];
|
|
if (CanSelectItem(i) && (!item.bInline || item.bInlineFirst) && (s_MenuMode!=MODE_SEARCH || item.id!=MENU_SHUTDOWN_BUTTON))
|
|
{
|
|
index=i;
|
|
break;
|
|
}
|
|
}
|
|
best=index;
|
|
}
|
|
if (m_SearchScrollCount>0 && index==m_SearchIndex)
|
|
{
|
|
best=m_OriginalCount;
|
|
}
|
|
else if (m_SearchScrollCount>0 && index>=m_OriginalCount && index<n-1)
|
|
{
|
|
best=index+1;
|
|
}
|
|
else
|
|
{
|
|
int col=m_Items[index].column;
|
|
int x0=m_Items[index].itemRect.left;
|
|
int y0=m_Items[index].itemRect.bottom;
|
|
int scrollOffset=0;
|
|
if (m_ScrollCount>0)
|
|
scrollOffset=m_Items[m_ScrollCount-1].itemRect.bottom-m_rContent.top-m_ScrollHeight;
|
|
if (index<m_ScrollCount)
|
|
y0-=scrollOffset;
|
|
int dist=0x7FFFFFFF;
|
|
for (int i=1;i<n;i++)
|
|
{
|
|
int idx=(index+i)%n;
|
|
if (!CanSelectItem(idx))
|
|
continue;
|
|
const MenuItem &item=m_Items[idx];
|
|
int top=item.itemRect.top;
|
|
if (idx<m_ScrollCount)
|
|
top-=scrollOffset;
|
|
int d=0x7FFFFFFE;
|
|
if (!(m_Options&CONTAINER_SEARCH))
|
|
{
|
|
if (m_SearchScrollCount>0 && i>=m_OriginalCount)
|
|
continue;
|
|
if (item.column==col && top>=y0)
|
|
{
|
|
d=((top-y0)<<16)+abs(item.itemRect.left-x0);
|
|
}
|
|
else if (item.bInline && !item.bInlineFirst)
|
|
continue;
|
|
else if (s_MenuMode==MODE_SEARCH && item.id==MENU_SHUTDOWN_BUTTON)
|
|
continue;
|
|
}
|
|
if (d<dist)
|
|
{
|
|
dist=d;
|
|
best=idx;
|
|
}
|
|
}
|
|
}
|
|
if (best>=0)
|
|
{
|
|
ActivateItem(best,ACTIVATE_SELECT,NULL);
|
|
if ((m_Items[best].categoryHash&CSearchManager::CATEGORY_MASK)==CSearchManager::CATEGORY_AUTOCOMPLETE && m_Items[best].pItemInfo)
|
|
{
|
|
CString path;
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
path=m_Items[best].pItemInfo->GetPath();
|
|
}
|
|
if (!path.IsEmpty())
|
|
{
|
|
if (m_Options&CONTAINER_SEARCH)
|
|
m_pParent->UpdateAutoComplete(path);
|
|
else
|
|
UpdateAutoComplete(path);
|
|
}
|
|
}
|
|
if (!m_bSubMenu && s_MenuMode==MODE_PROGRAMS && best==m_ProgramTreeIndex)
|
|
m_pProgramsTree->SelectFirst();
|
|
}
|
|
}
|
|
if (wParam==VK_ESCAPE && s_MenuMode==MODE_JUMPLIST)
|
|
{
|
|
SetMenuMode(MODE_NORMAL,true);
|
|
return 0;
|
|
}
|
|
bool bBack=((wParam==VK_LEFT && !s_bRTL) || (wParam==VK_RIGHT && s_bRTL));
|
|
if (wParam==VK_ESCAPE || (bBack && GetKeyState(VK_CONTROL)>=0 && (s_Menus.size()>1 || (s_Menus.size()==1 && m_bSubMenu))))
|
|
{
|
|
// close top menu
|
|
if (!s_Menus[s_Menus.size()-1]->m_bDestroyed)
|
|
s_Menus[s_Menus.size()-1]->PostMessage(WM_CLOSE);
|
|
if (s_Menus.size()>=2 && !s_Menus[s_Menus.size()-2]->m_bDestroyed)
|
|
s_Menus[s_Menus.size()-2]->SetActiveWindow();
|
|
if (s_Menus.size()==1)
|
|
{
|
|
if (m_bSubMenu)
|
|
{
|
|
::SetFocus(g_ProgramsButton);
|
|
}
|
|
else
|
|
{
|
|
// HACK: stops the call to SetActiveWindow(NULL). The correct behavior is to not close the taskbar when Esc is pressed
|
|
s_TaskbarState&=~ABS_AUTOHIDE;
|
|
}
|
|
}
|
|
}
|
|
else if (bBack && index>=0)
|
|
{
|
|
if (m_Items[index].bInline && !m_Items[index].bInlineFirst)
|
|
{
|
|
index--;
|
|
while (!CanSelectItem(index))
|
|
index--;
|
|
if (index>=0)
|
|
ActivateItem(index,ACTIVATE_SELECT,NULL);
|
|
}
|
|
else
|
|
{
|
|
if (s_MenuMode==MODE_JUMPLIST && m_Items[index].jumpIndex>=0)
|
|
{
|
|
SetMenuMode(MODE_NORMAL,true);
|
|
return 0;
|
|
}
|
|
int column=(m_Items[index].column+(int)m_ColumnOffsets.size()-1)%(int)m_ColumnOffsets.size();
|
|
int y0=(m_Items[index].itemRect.top+m_Items[index].itemRect.bottom)/2;
|
|
if (index<m_ScrollCount) y0-=m_ScrollOffset;
|
|
if (m_bTwoColumns && bProgramsTree)
|
|
{
|
|
HTREEITEM hItem=TreeView_GetSelection(m_pProgramsTree->m_hWnd);
|
|
RECT rc={0};
|
|
if (hItem)
|
|
TreeView_GetItemRect(m_pProgramsTree->m_hWnd,hItem,&rc,TRUE);
|
|
m_pProgramsTree->MapWindowPoints(m_hWnd,&rc);
|
|
y0=(rc.top+rc.bottom)/2;
|
|
}
|
|
int dist=INT_MAX;
|
|
index=-1;
|
|
for (int i=0;i<n;i++)
|
|
{
|
|
if (m_Items[i].column==column && CanSelectItem(i))
|
|
{
|
|
if (m_Items[i].bInline && !m_Items[i].bInlineLast)
|
|
continue;
|
|
int ytop=m_Items[i].itemRect.top+1, ybottom=m_Items[i].itemRect.bottom-1;
|
|
if (i<m_ScrollCount)
|
|
{
|
|
ytop-=m_ScrollOffset;
|
|
ybottom-=m_ScrollOffset;
|
|
}
|
|
int d=min(abs(ytop-y0),abs(ybottom-y0));
|
|
if (dist>d)
|
|
{
|
|
index=i;
|
|
dist=d;
|
|
}
|
|
}
|
|
}
|
|
if (index>=0)
|
|
{
|
|
ActivateItem(index,ACTIVATE_SELECT,NULL);
|
|
if (s_MenuMode==MODE_PROGRAMS && index==m_ProgramTreeIndex)
|
|
{
|
|
POINT pt={0,y0};
|
|
MapWindowPoints(m_pProgramsTree->m_hWnd,&pt,1);
|
|
m_pProgramsTree->SelectItem(pt.y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool bForward=((wParam==VK_RIGHT && !s_bRTL) || (wParam==VK_LEFT && s_bRTL));
|
|
if (wParam==VK_RETURN || bForward)
|
|
{
|
|
// open submenu
|
|
if (index>=0)
|
|
{
|
|
if (m_Items[index].bFolder && (bForward || !m_Items[index].bSplit) && (wParam==VK_RETURN || GetKeyState(VK_CONTROL)>=0))
|
|
ActivateItem(index,ACTIVATE_OPEN_KBD,NULL);
|
|
else if (wParam==VK_RETURN)
|
|
ActivateItem(index,ACTIVATE_EXECUTE,NULL);
|
|
else if (bForward)
|
|
{
|
|
if (m_Items[index].bInline && !m_Items[index].bInlineLast)
|
|
{
|
|
index++;
|
|
while (!CanSelectItem(index))
|
|
index++;
|
|
if (index>=0)
|
|
ActivateItem(index,ACTIVATE_SELECT,NULL);
|
|
}
|
|
else
|
|
{
|
|
int column=(m_Items[index].column+1)%(int)m_ColumnOffsets.size();
|
|
int y0=(m_Items[index].itemRect.top+m_Items[index].itemRect.bottom)/2;
|
|
if (index<m_ScrollCount) y0-=m_ScrollOffset;
|
|
if (m_bTwoColumns && bProgramsTree)
|
|
{
|
|
HTREEITEM hItem=TreeView_GetSelection(m_pProgramsTree->m_hWnd);
|
|
RECT rc={0};
|
|
if (hItem)
|
|
TreeView_GetItemRect(m_pProgramsTree->m_hWnd,hItem,&rc,TRUE);
|
|
m_pProgramsTree->MapWindowPoints(m_hWnd,&rc);
|
|
y0=(rc.top+rc.bottom)/2;
|
|
}
|
|
int dist=INT_MAX;
|
|
index=-1;
|
|
for (int i=0;i<n;i++)
|
|
{
|
|
if (m_Items[i].column==column && CanSelectItem(i) && (!m_Items[i].bInline || m_Items[i].bInlineFirst))
|
|
{
|
|
int ytop=m_Items[i].itemRect.top+1, ybottom=m_Items[i].itemRect.bottom-1;
|
|
if (i<m_ScrollCount)
|
|
{
|
|
ytop-=m_ScrollOffset;
|
|
ybottom-=m_ScrollOffset;
|
|
}
|
|
int d=min(abs(ytop-y0),abs(ybottom-y0));
|
|
if (dist>d)
|
|
{
|
|
index=i;
|
|
dist=d;
|
|
}
|
|
}
|
|
}
|
|
if (index>=0)
|
|
{
|
|
ActivateItem(index,ACTIVATE_SELECT,NULL);
|
|
if (s_MenuMode==MODE_PROGRAMS && index==m_ProgramTreeIndex)
|
|
{
|
|
POINT pt={y0,0};
|
|
MapWindowPoints(m_pProgramsTree->m_hWnd,&pt,1);
|
|
m_pProgramsTree->SelectItem(pt.y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (bForward)
|
|
{
|
|
for (int i=n-1;i>=0;i--)
|
|
{
|
|
if (CanSelectItem(i) && (!m_Items[i].bInline || m_Items[i].bInlineFirst))
|
|
{
|
|
ActivateItem(i,ACTIVATE_SELECT,NULL);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnSysKeyDown( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (wParam==VK_RETURN && m_HotItem>=0)
|
|
{
|
|
int index=m_HotItem;
|
|
if (m_Items[index].pItem1 && !m_Items[index].pItem2)
|
|
{
|
|
POINT pt={0,0};
|
|
ActivateItem(index,ACTIVATE_PROPERTIES,&pt);
|
|
PostMessage(MCM_SETHOTITEM,index);
|
|
}
|
|
}
|
|
else
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnChar( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (wParam>=0xD800 && wParam<=0xDBFF)
|
|
return TRUE; // don't support supplementary characters
|
|
|
|
// find the current menu item
|
|
int index=m_HotItem;
|
|
if (index<0) index=-1;
|
|
|
|
// find the next item with that accelerator
|
|
wchar_t buf[2]={(wchar_t)wParam,0};
|
|
CharUpper(buf);
|
|
|
|
int n=(int)m_Items.size();
|
|
|
|
int first=-1, count=0, firstCustom=-1, countCustom=0;
|
|
for (int i=1;i<=n;i++)
|
|
{
|
|
int idx=(index+2*n+i)%n;
|
|
if (m_Items[idx].accelerator==buf[0] && CanSelectItem(idx))
|
|
{
|
|
if (first==-1)
|
|
first=idx;
|
|
count++;
|
|
if (m_Items[idx].bCustomAccelerator)
|
|
{
|
|
if (firstCustom==-1)
|
|
firstCustom=idx;
|
|
countCustom++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (count==0)
|
|
return TRUE; // no item was found
|
|
|
|
if (countCustom>1 || (countCustom==0 && count>1))
|
|
{
|
|
// multiple items have the same accelerator. select the next one
|
|
ActivateItem(first,ACTIVATE_SELECT,NULL);
|
|
return 0;
|
|
}
|
|
|
|
if (countCustom==1)
|
|
first=firstCustom;
|
|
|
|
// exactly 1 item has that accelerator
|
|
if (m_Items[first].bHasJumpList && GetSettingInt(L"JumplistKeys")==0)
|
|
{
|
|
ActivateItem(first,ACTIVATE_SELECT,NULL);
|
|
return 0;
|
|
}
|
|
ActivateData data;
|
|
data.bNoModifiers=true;
|
|
if (!m_Items[first].bFolder || (!m_Items[first].bHasJumpList && m_Items[first].bSplit) || (m_Items[first].bHasJumpList && GetSettingInt(L"JumplistKeys")==1))
|
|
{
|
|
ActivateItem(first,ACTIVATE_EXECUTE,NULL,&data);
|
|
return 0;
|
|
}
|
|
|
|
// m_Items[first].bFolder
|
|
ActivateItem(first,ACTIVATE_OPEN_KBD,NULL,&data);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
LOG_MENU(LOG_OPEN,L"Close Menu, ptr=%p",this);
|
|
if (m_pAccessible)
|
|
{
|
|
NotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND,m_hWnd,OBJID_CLIENT,CHILDID_SELF);
|
|
m_pAccessibleContext->ContextCallback(ReleaseAccessible,NULL,IID_IAccessible,4,NULL);
|
|
m_pAccessibleContext=NULL;
|
|
m_pAccessible=NULL;
|
|
}
|
|
if (m_pDropTargetHelper && m_pDragObject)
|
|
{
|
|
m_pDropTargetHelper->DragLeave();
|
|
}
|
|
m_pDragObject=NULL;
|
|
m_pDropTargetHelper=NULL;
|
|
m_pDropTargetProxy->Reset();
|
|
m_pDropTargetProxy=NULL;
|
|
RevokeDragDrop(m_hWnd);
|
|
// remember the scroll position
|
|
if (m_ScrollHeight>0 && m_FolderHash[0])
|
|
s_MenuScrolls[m_FolderHash[0]]=m_ScrollOffset;
|
|
else
|
|
s_MenuScrolls.erase(m_FolderHash[0]);
|
|
|
|
if (s_pHotMenu==this)
|
|
{
|
|
s_pHotMenu=NULL;
|
|
s_HotItem=-1;
|
|
}
|
|
if (s_pTipMenu==this)
|
|
{
|
|
s_pTipMenu=NULL;
|
|
TOOLINFO tool={sizeof(tool),TTF_ABSOLUTE|TTF_TRACK|TTF_TRANSPARENT};
|
|
tool.uId=1;
|
|
s_Tooltip.SendMessage(TTM_TRACKACTIVATE,FALSE,(LPARAM)&tool);
|
|
}
|
|
if ((m_Options&CONTAINER_SEARCH) && !m_pParent->m_bDestroyed && !m_pParent->m_bInSearchUpdate)
|
|
{
|
|
m_pParent->m_SearchBox.SetWindowText(L"");
|
|
}
|
|
m_bDestroyed=true;
|
|
if (this==s_Menus[0])
|
|
{
|
|
// cleanup when the last menu is closed
|
|
if (s_Theme)
|
|
CloseThemeData(s_Theme);
|
|
s_Theme=NULL;
|
|
if (s_PagerTheme)
|
|
CloseThemeData(s_PagerTheme);
|
|
s_PagerTheme=NULL;
|
|
if (s_Tooltip.m_hWnd)
|
|
s_Tooltip.DestroyWindow();
|
|
s_Tooltip.m_hWnd=NULL;
|
|
s_TooltipBalloon.m_hWnd=NULL; // the balloon tooltip is owned, no need to be destroyed
|
|
if (s_UserPicture.m_hWnd)
|
|
s_UserPicture.DestroyWindow();
|
|
s_UserPicture.m_hWnd=NULL;
|
|
s_pHotMenu=NULL;
|
|
s_HotItem=-1;
|
|
if (!m_bSubMenu)
|
|
EnableStartTooltip(true);
|
|
BufferedPaintUnInit();
|
|
if (!m_bSubMenu && (s_TaskbarState&ABS_AUTOHIDE))
|
|
{
|
|
HWND capture=GetCapture();
|
|
if (!capture || !(capture==s_TaskBar || ::IsChild(s_TaskBar,capture)))
|
|
::SetActiveWindow(NULL); // close the taskbar if it is auto-hide and doesn't have the mouse capture
|
|
}
|
|
if (s_XMouse)
|
|
SystemParametersInfo(SPI_SETACTIVEWINDOWTRACKING,NULL,(PVOID)TRUE,SPIF_SENDCHANGE);
|
|
g_SearchManager.CloseMenu();
|
|
if (m_pProgramsTree && m_pProgramsTree->m_hWnd && s_MenuMode==MODE_PROGRAMS)
|
|
s_ProgramsScrollPos=m_pProgramsTree->GetScrollPos(SB_VERT);
|
|
s_bAllPrograms=false;
|
|
if ((m_Options&CONTAINER_ALLPROGRAMS) && g_TopWin7Menu && ::IsWindowVisible(g_TopWin7Menu))
|
|
{
|
|
::ShowWindow(g_UserPic,SW_SHOW);
|
|
::SetFocus(g_ProgramsButton);
|
|
CPoint pt(GetMessagePos());
|
|
RECT rc;
|
|
::GetWindowRect(g_TopWin7Menu,&rc);
|
|
if (PtInRect(&rc,pt))
|
|
{
|
|
::ScreenToClient(g_TopWin7Menu,&pt);
|
|
::PostMessage(g_TopWin7Menu,WM_MOUSEMOVE,0,MAKELONG(pt.x,pt.y));
|
|
}
|
|
}
|
|
s_FirstMenu=NULL;
|
|
if (!(m_Options&CONTAINER_ALLPROGRAMS))
|
|
{
|
|
g_CurrentCSMTaskbar=-1;
|
|
PressStartButton(s_TaskBarId,false);
|
|
}
|
|
s_TaskBar=s_StartButton=NULL;
|
|
s_TaskBarId=-1;
|
|
g_ItemManager.SaveCacheFile();
|
|
if (s_ArrowsBitmap) DeleteObject(s_ArrowsBitmap);
|
|
s_ArrowsBitmap=NULL;
|
|
CloseLog();
|
|
}
|
|
if (m_Options&CONTAINER_SEARCH)
|
|
s_SearchMenu=NULL;
|
|
if (m_ScrollTheme)
|
|
{
|
|
CloseThemeData(m_ScrollTheme);
|
|
m_ScrollTheme=NULL;
|
|
}
|
|
|
|
if (s_pFrameworkInputPane && m_InputCookie)
|
|
s_pFrameworkInputPane->Unadvise(m_InputCookie);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnShowWindow( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (!wParam && !m_bSubMenu && s_UserPicture)
|
|
s_UserPicture.ShowWindow(SW_HIDE);
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnRefresh( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
m_RefreshPosted=0;
|
|
if ((m_Options&CONTAINER_SEARCH) || (!m_bSubMenu && s_MenuMode==MODE_SEARCH))
|
|
{
|
|
// update search results
|
|
unsigned int hash=0;
|
|
int index=m_ContextItem==-1?m_HotItem:m_ContextItem;
|
|
if (index>=0)
|
|
{
|
|
if (index>=m_OriginalCount && index<(int)m_Items.size())
|
|
hash=m_Items[index].nameHash;
|
|
else if (s_bWin7Style && index>m_SearchIndex-m_SearchItemCount && index<=m_SearchIndex && m_Items[index].id!=MENU_SEARCH_EMPTY)
|
|
hash=m_SearchIndex-index+1;
|
|
}
|
|
bool bSearching=InitSearchItems();
|
|
InitWindow(bSearching && s_MenuMode!=MODE_SEARCH);
|
|
Invalidate();
|
|
int hotItem=-1;
|
|
if (s_bWin7Style && hash==1)
|
|
hotItem=m_SearchIndex;
|
|
else if (s_bWin7Style && hash==2)
|
|
hotItem=m_SearchIndex-1;
|
|
else if (s_bWin7Style && hash==3)
|
|
hotItem=m_SearchIndex-2;
|
|
else
|
|
{
|
|
for (int i=m_OriginalCount;i<(int)m_Items.size();i++)
|
|
{
|
|
if (hash && m_Items[i].nameHash==hash)
|
|
{
|
|
hotItem=i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (m_ContextItem!=-1)
|
|
SetContextItem(hotItem);
|
|
if (hotItem==-1 && m_OriginalCount<(int)m_Items.size())
|
|
{
|
|
if (s_SearchResults.autoCompletePath.IsEmpty() && wcsncmp(s_SearchResults.currentString,L"\\\\",2)!=0)
|
|
{
|
|
if (m_Items[m_OriginalCount].id==MENU_SEARCH_EMPTY)
|
|
{
|
|
if (!bSearching)
|
|
{
|
|
for (int i=0;i<(int)m_Items.size();i++)
|
|
{
|
|
if (m_Items[i].id==MENU_MORE_RESULTS)
|
|
{
|
|
hotItem=i;
|
|
break;
|
|
}
|
|
else if (m_Items[i].id==MENU_SEARCH_INTERNET || m_Items[i].id==MENU_SEARCH_PROVIDER)
|
|
{
|
|
hotItem=i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (m_Items[m_OriginalCount].id==MENU_SEARCH_CATEGORY)
|
|
hotItem=m_OriginalCount+1;
|
|
}
|
|
else
|
|
hotItem=-1;
|
|
}
|
|
if (hotItem>=0)
|
|
{
|
|
ActivateItem(hotItem,ACTIVATE_SELECT,NULL);
|
|
if (s_bPendingSearchEnter)
|
|
{
|
|
ActivateItem(hotItem,ACTIVATE_EXECUTE,NULL);
|
|
s_bPendingSearchEnter=false;
|
|
}
|
|
}
|
|
else
|
|
SetHotItem(-1);
|
|
}
|
|
else if (s_MenuMode==MODE_JUMPLIST)
|
|
{
|
|
OpenJumpList(m_SubJumpItem,false);
|
|
}
|
|
else
|
|
{
|
|
// updates the menu after drag/drop, delete, or rename operation
|
|
for (std::vector<CMenuContainer*>::reverse_iterator it=s_Menus.rbegin();*it!=this;++it)
|
|
if (!(*it)->m_bDestroyed)
|
|
(*it)->PostMessage(WM_CLOSE);
|
|
if (m_ScrollHeight>0 && m_FolderHash[0])
|
|
s_MenuScrolls[m_FolderHash[0]]=m_ScrollOffset;
|
|
else
|
|
s_MenuScrolls.erase(m_FolderHash[0]);
|
|
if (!m_bSubMenu && !s_bWin7Style)
|
|
s_MenuMaxHeight[0]=-1;
|
|
InitItems();
|
|
InitWindow();
|
|
Invalidate();
|
|
SetFocus();
|
|
SetHotItem(-1);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnActivate( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (LOWORD(wParam)!=WA_INACTIVE)
|
|
{
|
|
if (s_Tooltip.m_hWnd)
|
|
s_Tooltip.SetWindowPos(HWND_TOP,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
|
|
return 0;
|
|
}
|
|
#ifndef PREVENT_CLOSING
|
|
if (s_bPreventClosing)
|
|
return 0;
|
|
|
|
if (lParam)
|
|
{
|
|
// check if another menu window is being activated
|
|
// if not, close all menus
|
|
for (std::vector<CMenuContainer*>::const_iterator it=s_Menus.begin();it!=s_Menus.end();++it)
|
|
if ((*it)->m_hWnd==(HWND)lParam || (*it)->m_SearchBox.m_hWnd==(HWND)lParam)
|
|
return 0;
|
|
|
|
if ((HWND)lParam==g_OwnerWindow || (HWND)lParam==g_TopWin7Menu)
|
|
return 0;
|
|
}
|
|
|
|
for (std::vector<CMenuContainer*>::reverse_iterator it=s_Menus.rbegin();it!=s_Menus.rend();++it)
|
|
if ((*it)->m_hWnd && !(*it)->m_bDestroyed)
|
|
{
|
|
(*it)->PostMessage(WM_CLOSE);
|
|
(*it)->m_bClosing=true;
|
|
}
|
|
if (g_TopWin7Menu && s_bAllPrograms) ::PostMessage(g_TopWin7Menu,WM_CLOSE,0,0);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnMouseActivate( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (m_Submenu>=0 || (m_Options&CONTAINER_SEARCH))
|
|
return MA_NOACTIVATE;
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnMouseMove( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (!m_bTrackMouse)
|
|
{
|
|
TRACKMOUSEEVENT track={sizeof(track),TME_LEAVE,m_hWnd,0};
|
|
TrackMouseEvent(&track);
|
|
m_bTrackMouse=true;
|
|
}
|
|
if (!(wParam&MK_LBUTTON) && m_ClickIndex==-2)
|
|
SetClickItem(-1);
|
|
if (s_HotPos==GetMessagePos())
|
|
return 0; // HACK - ignore the mouse if it hasn't moved since last time. otherwise the mouse can override the keyboard navigation
|
|
s_HotPos=GetMessagePos();
|
|
POINT pt={(short)LOWORD(lParam),(short)HIWORD(lParam)};
|
|
bool bArrow=false;
|
|
int index=HitTest(pt,&bArrow);
|
|
if (index!=m_ProgramButtonIndex)
|
|
m_bDisableProgHover=false;
|
|
if (GetCapture()==m_hWnd)
|
|
{
|
|
if (m_ClickIndex!=index)
|
|
{
|
|
if (!DragOut(m_ClickIndex,(m_Options&CONTAINER_APPS)!=0))
|
|
SetHotItem(-2);
|
|
}
|
|
else
|
|
SetHotItem(index,bArrow,true);
|
|
}
|
|
else
|
|
{
|
|
if (index>=0 && m_Items[index].id==MENU_SEPARATOR)
|
|
index=m_HotItem;
|
|
SetHotItem(index,bArrow,true);
|
|
|
|
UpdateScroll(&pt,false);
|
|
|
|
if (m_Submenu<0 && !(m_Options&CONTAINER_SEARCH) && m_SearchState==SEARCH_NONE)
|
|
SetFocus();
|
|
if (index>=0)
|
|
{
|
|
if ((m_Submenu>=0 && index!=m_Submenu) || (m_Submenu<0 && m_Items[index].bFolder) || (s_MenuMode==MODE_JUMPLIST && m_SubJumpItem>=0 && index!=m_SubJumpItem && index<m_OriginalCount))
|
|
{
|
|
// initialize the hover timer
|
|
if ((m_HoverItem!=index || m_bHoverArrow!=bArrow) && !s_bDisableHover && m_SearchState<=SEARCH_BLANK)
|
|
{
|
|
m_HoverItem=index;
|
|
m_bHoverArrow=bArrow;
|
|
if (m_Items[m_HotItem].id==MENU_SHUTDOWN_BUTTON && !bArrow)
|
|
KillTimer(TIMER_HOVER);
|
|
else
|
|
{
|
|
int time=s_HoverTime;
|
|
if (!bArrow && m_Items[m_HotItem].bSplit)
|
|
time=s_SplitHoverTime;
|
|
else if (s_bWin7Style && index==m_ProgramButtonIndex && GetSettingInt(L"ProgramsStyle")==PROGRAMS_INLINE)
|
|
time=m_bDisableProgHover?-1:s_ProgramsHoverTime;
|
|
if (time>=0)
|
|
SetTimer(TIMER_HOVER,time);
|
|
}
|
|
LOG_MENU(LOG_MOUSE,L"Start Hover, index=%d",index);
|
|
}
|
|
}
|
|
else
|
|
m_HoverItem=-1;
|
|
}
|
|
else
|
|
m_HoverItem=-1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnMouseLeave( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (m_bTrackMouse) // HACK - somehow after a context menu WM_MOUSELEAVE comes even if we are not tracking the mouse
|
|
{
|
|
UpdateScroll(NULL,false);
|
|
SetHotItem(-1);
|
|
m_bTrackMouse=false;
|
|
m_bDisableProgHover=false;
|
|
if (m_HoverItem!=-1)
|
|
{
|
|
KillTimer(TIMER_HOVER);
|
|
m_HoverItem=-1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnMouseWheel( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
POINT pt={(short)LOWORD(lParam),(short)HIWORD(lParam)};
|
|
HWND hwnd=WindowFromPoint(pt);
|
|
if (hwnd!=m_hWnd)
|
|
{
|
|
for (std::vector<CMenuContainer*>::iterator it=s_Menus.begin();it!=s_Menus.end();++it)
|
|
{
|
|
if ((*it)->m_hWnd==hwnd)
|
|
{
|
|
(*it)->SendMessage(uMsg,wParam,lParam);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
if (m_ScrollCount<1 && m_SearchScrollCount<1) return 0; // nothing to scroll
|
|
UINT lines;
|
|
if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&lines,FALSE))
|
|
lines=3;
|
|
if (lines<1) lines=1;
|
|
|
|
m_MouseWheel+=lines*(short)HIWORD(wParam);
|
|
int n=m_MouseWheel/WHEEL_DELTA;
|
|
m_MouseWheel-=n*WHEEL_DELTA;
|
|
if (m_SearchScrollCount>0)
|
|
{
|
|
int pos=m_SearchScrollPos;
|
|
m_SearchScrollPos=m_Scrollbar.SetScrollPos(SB_CTL,m_SearchScrollPos-n);
|
|
if (m_SearchScrollPos!=pos)
|
|
{
|
|
Invalidate();
|
|
s_HotPos=-1;
|
|
ScreenToClient(&pt);
|
|
OnMouseMove(WM_MOUSEMOVE,LOWORD(wParam),MAKELONG(pt.x,pt.y),bHandled);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int scroll=m_ScrollOffset;
|
|
scroll-=n*s_Skin.ItemSettings[m_bSubMenu?MenuSkin::SUBMENU_ITEM:MenuSkin::COLUMN1_ITEM].itemHeight;
|
|
if (scroll<0) scroll=0;
|
|
int total=m_Items[m_ScrollCount-1].itemRect.bottom-m_rContent.top-m_ScrollHeight;
|
|
if (scroll>total) scroll=total;
|
|
if (m_ScrollOffset!=scroll)
|
|
{
|
|
m_ScrollOffset=scroll;
|
|
UpdateScroll();
|
|
Invalidate();
|
|
s_HotPos=-1;
|
|
ScreenToClient(&pt);
|
|
OnMouseMove(WM_MOUSEMOVE,LOWORD(wParam),MAKELONG(pt.x,pt.y),bHandled);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool CMenuContainer::GetDescription( int index, wchar_t *text, int size )
|
|
{
|
|
if (index<0 || index>=(int)m_Items.size())
|
|
return false;
|
|
const MenuItem &item=m_Items[index];
|
|
bool bLabel=false;
|
|
if (item.bStartScreen)
|
|
return false;
|
|
if (item.bInline)
|
|
{
|
|
int len=0;
|
|
for (const wchar_t *c=item.name;*c && len<size-1;c++)
|
|
if (c[0]!='&' || c[1]=='&')
|
|
text[len++]=*c;
|
|
text[len]=0;
|
|
bLabel=len>0;
|
|
text+=len;
|
|
size-=len;
|
|
}
|
|
if (item.id==MENU_PROGRAMS && s_MenuMode==MODE_PROGRAMS)
|
|
return false;
|
|
if (item.pStdItem && item.pStdItem->tip)
|
|
{
|
|
if (_wcsicmp(item.pStdItem->tip,L"none")==0)
|
|
return false;
|
|
// get the tip for the standard item
|
|
if (bLabel)
|
|
Sprintf(text,size,L"\r\n%s",item.pStdItem->tip);
|
|
else
|
|
Strcpy(text,size,item.pStdItem->tip);
|
|
return true;
|
|
}
|
|
|
|
if (item.id==MENU_SEARCH_CATEGORY && item.categoryHash>=CSearchManager::CATEGORY_FILE && m_bHotArrow)
|
|
{
|
|
Sprintf(text,size,L"%s (Ctrl+Enter)",FindTranslation(L"Menu.MoreResults",L"See more results"));
|
|
return true;
|
|
}
|
|
if (item.id==MENU_NO && item.categoryHash==CSearchManager::CATEGORY_METROSETTING)
|
|
{
|
|
// try to get the description from the XML file. looks like it is always the same as the display name though
|
|
CComPtr<IXMLDOMDocument> pDoc;
|
|
if (SUCCEEDED(pDoc.CoCreateInstance(L"Msxml2.FreeThreadedDOMDocument")))
|
|
{
|
|
pDoc->put_async(VARIANT_FALSE);
|
|
VARIANT_BOOL loaded;
|
|
if (pDoc->load(CComVariant(item.pItemInfo->PATH),&loaded)==S_OK && loaded==VARIANT_TRUE)
|
|
{
|
|
CComPtr<IXMLDOMNode> pDescription;
|
|
HRESULT res=pDoc->selectSingleNode(CComBSTR(L"PCSettings/SearchableContent/SettingInformation/Description"),&pDescription);
|
|
if (res==S_OK)
|
|
{
|
|
CComBSTR desc;
|
|
if (pDescription->get_text(&desc)==S_OK)
|
|
{
|
|
if (SUCCEEDED(SHLoadIndirectString(desc,text,size,NULL)))
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (item.jumpIndex>=0 && item.id!=MENU_SEPARATOR && item.id!=MENU_EMPTY)
|
|
{
|
|
const CJumpGroup &group=s_JumpList.groups[LOWORD(item.jumpIndex)];
|
|
const CJumpItem &jumpItem=group.items[HIWORD(item.jumpIndex)];
|
|
if (m_bHotArrow)
|
|
{
|
|
if (group.type==CJumpGroup::TYPE_PINNED)
|
|
Strcpy(text,size,FindTranslation(L"Jumplist.UnpinTip",L"Unpin from this list"));
|
|
else
|
|
Strcpy(text,size,FindTranslation(L"Jumplist.PinTip",L"Pin to this list"));
|
|
return true;
|
|
}
|
|
if (jumpItem.type==CJumpItem::TYPE_ITEM)
|
|
{
|
|
CComQIPtr<IShellItem> pItem(jumpItem.pItem);
|
|
if (pItem)
|
|
{
|
|
{
|
|
CComString pName;
|
|
if (SUCCEEDED(pItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEEDITING,&pName)))
|
|
{
|
|
Strcpy(text,size,pName);
|
|
return true;
|
|
}
|
|
}
|
|
CComPtr<IQueryInfo> pQueryInfo;
|
|
if (SUCCEEDED(pItem->BindToHandler(NULL,BHID_SFUIObject,IID_IQueryInfo,(void**)&pQueryInfo)))
|
|
{
|
|
CComString pTip;
|
|
if (FAILED(pQueryInfo->GetInfoTip(QITIPF_LINKNOTARGET,&pTip)) || !pTip)
|
|
return false;
|
|
|
|
Strcpy(text,size,pTip);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
else if (jumpItem.type==CJumpItem::TYPE_LINK)
|
|
{
|
|
CComQIPtr<IShellLink> pLink(jumpItem.pItem);
|
|
if (pLink)
|
|
{
|
|
if (SUCCEEDED(pLink->GetDescription(text,size)) && text[0])
|
|
return true;
|
|
if (jumpItem.bHasArguments)
|
|
{
|
|
// don't use default tip for items with arguments
|
|
Strcpy(text,size,item.name);
|
|
return true;
|
|
}
|
|
if (pLink->GetPath(text,size,NULL,0)==S_OK)
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((item.categoryHash&CSearchManager::CATEGORY_MASK)==CSearchManager::CATEGORY_FILE)
|
|
{
|
|
// for search files show the path
|
|
if (item.pItemInfo)
|
|
{
|
|
bool bShowPath;
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
bShowPath=!item.pItemInfo->GetPath().IsEmpty();
|
|
}
|
|
if (bShowPath)
|
|
{
|
|
CComPtr<IShellItem> pItem;
|
|
if (SUCCEEDED(SHCreateItemFromIDList(item.pItemInfo->GetPidl(),IID_IShellItem,(void**)&pItem)))
|
|
{
|
|
CComString pName;
|
|
if (SUCCEEDED(pItem->GetDisplayName(SIGDN_FILESYSPATH,&pName)))
|
|
{
|
|
Strcpy(text,size,pName);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (item.pItem1)
|
|
{
|
|
if (item.pItemInfo)
|
|
{
|
|
CString path;
|
|
{
|
|
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
|
path=item.pItemInfo->GetPath();
|
|
}
|
|
if (!path.IsEmpty() && PathIsNetworkPath(path))
|
|
{
|
|
Strcpy(text,size,path);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// get the tip from the shell
|
|
CComPtr<IShellItem> pItem;
|
|
if (FAILED(SHCreateItemFromIDList(item.pItem1,IID_IShellItem,(void**)&pItem)))
|
|
return bLabel;
|
|
|
|
CComPtr<IQueryInfo> pQueryInfo;
|
|
if (FAILED(pItem->BindToHandler(NULL,BHID_SFUIObject,IID_IQueryInfo,(void**)&pQueryInfo)))
|
|
return bLabel;
|
|
|
|
CComString pTip;
|
|
HRESULT hr=pQueryInfo->GetInfoTip(QITIPF_DEFAULT,&pTip);
|
|
if (FAILED(hr) || !pTip)
|
|
return bLabel;
|
|
|
|
if (bLabel)
|
|
Sprintf(text,size,L"\r\n%s",(const wchar_t*)pTip);
|
|
else
|
|
Strcpy(text,size,pTip);
|
|
return true;
|
|
}
|
|
return bLabel;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnLButtonDown( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (!GetCapture())
|
|
{
|
|
if (m_Submenu<0 && !(m_Options&CONTAINER_SEARCH) && m_SearchState==SEARCH_NONE)
|
|
SetFocus();
|
|
POINT pt={(short)LOWORD(lParam),(short)HIWORD(lParam)};
|
|
SetClickItem(-1);
|
|
if (m_rUser1.left<m_rUser1.right && PtInRect(&m_rUser1,pt))
|
|
{
|
|
RunUserCommand(true);
|
|
}
|
|
if (m_rUser2.left<m_rUser2.right && PtInRect(&m_rUser2,pt))
|
|
{
|
|
RunUserCommand(false);
|
|
}
|
|
bool bArrow=false;
|
|
int index=HitTest(pt,&bArrow);
|
|
if (index<0)
|
|
{
|
|
if (m_Submenu>=0)
|
|
{
|
|
SetActiveWindow(); // must be done before the children are destroyed
|
|
// close all child menus
|
|
CloseSubMenus(0,this);
|
|
SetHotItem(-1); // must be done after the children are destroyed
|
|
}
|
|
return 0;
|
|
}
|
|
const MenuItem &item=m_Items[index];
|
|
if (item.id==MENU_SEPARATOR) return 0;
|
|
if (index==m_ProgramButtonIndex && GetSettingInt(L"ProgramsStyle")==PROGRAMS_INLINE)
|
|
{
|
|
m_bDisableProgHover=true;
|
|
KillTimer(TIMER_HOVER);
|
|
}
|
|
SetClickItem(index);
|
|
m_bClickArrow=bArrow;
|
|
SetCapture();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnLButtonDblClick( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
SetClickItem(-1);
|
|
// execute item under the mouse
|
|
POINT pt={(short)LOWORD(lParam),(short)HIWORD(lParam)};
|
|
bool bArrow;
|
|
int index=HitTest(pt,&bArrow);
|
|
if (index<0) return 0;
|
|
const MenuItem &item=m_Items[index];
|
|
if (item.id==MENU_SEPARATOR) return 0;
|
|
ClientToScreen(&pt);
|
|
if (s_bWin7Style && item.id==MENU_PROGRAMS) // only single clicks for All Programs
|
|
OnLButtonDown(WM_LBUTTONDOWN,wParam,lParam,bHandled);
|
|
else if (!bArrow) // ignore double-click on the split arrow
|
|
ActivateItem(index,ACTIVATE_EXECUTE,&pt);
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnLButtonUp( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (GetCapture()==m_hWnd)
|
|
ReleaseCapture();
|
|
else if (m_ClickIndex!=-2)
|
|
return 0;
|
|
POINT pt={(short)LOWORD(lParam),(short)HIWORD(lParam)};
|
|
bool bArrow=false;
|
|
int index=HitTest(pt,&bArrow);
|
|
if (m_ClickIndex!=-2 && (index!=m_ClickIndex || bArrow!=m_bClickArrow))
|
|
{
|
|
InvalidateItem(m_ClickIndex);
|
|
SetHotItem(-1);
|
|
return 0;
|
|
}
|
|
if (index<0) return 0;
|
|
const MenuItem &item=m_Items[index];
|
|
POINT pt2=pt;
|
|
ClientToScreen(&pt2);
|
|
if (!item.bFolder)
|
|
{
|
|
if (item.jumpIndex>=0 && m_bHotArrow)
|
|
{
|
|
const CJumpGroup &group=s_JumpList.groups[LOWORD(item.jumpIndex)];
|
|
const CJumpItem &jumpItem=group.items[HIWORD(item.jumpIndex)];
|
|
PinJumpItem(s_JumpAppInfo,s_JumpList,LOWORD(item.jumpIndex),HIWORD(item.jumpIndex),group.type!=CJumpGroup::TYPE_PINNED,-1);
|
|
PostRefreshMessage();
|
|
}
|
|
else if (item.id==MENU_SEARCH_CATEGORY && item.categoryHash>=CSearchManager::CATEGORY_FILE && m_bHotArrow)
|
|
{
|
|
ActivateData data;
|
|
data.bArrow=true;
|
|
ActivateItem(index,ACTIVATE_EXECUTE,&pt2,&data);
|
|
}
|
|
else
|
|
ActivateItem(index,ACTIVATE_EXECUTE,&pt2);
|
|
}
|
|
else
|
|
{
|
|
const MenuItem &item=m_Items[index];
|
|
if (item.bSplit)
|
|
{
|
|
if (!bArrow)
|
|
{
|
|
ActivateItem(index,ACTIVATE_EXECUTE,&pt2);
|
|
return 0;
|
|
}
|
|
if ((index==m_Submenu || index==m_SubJumpItem) && (!m_SubShowTime || (int)(GetTickCount()-m_SubShowTime)>500))
|
|
{
|
|
// second click on the arrow closes the menus
|
|
SetActiveWindow();
|
|
// destroy old submenus
|
|
CloseSubMenus(0,this);
|
|
SetHotItem(index,true,true);
|
|
KillTimer(TIMER_HOVER);
|
|
return 0;
|
|
}
|
|
}
|
|
else if (s_bWin7Style && item.id==MENU_PROGRAMS && GetSettingInt(L"ProgramsStyle")==PROGRAMS_INLINE && m_SubShowTime && (int)(GetTickCount()-m_SubShowTime)<500)
|
|
return 0; // ignore clicks soon after the programs open
|
|
if (index!=m_Submenu)
|
|
{
|
|
ActivateItem(index,ACTIVATE_OPEN,NULL);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnRButtonDown( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (!GetCapture())
|
|
{
|
|
POINT pt={(short)LOWORD(lParam),(short)HIWORD(lParam)};
|
|
SetClickItem(-1);
|
|
int index=HitTest(pt,NULL);
|
|
if (index>=0)
|
|
{
|
|
if (m_Items[index].id==MENU_SEPARATOR) return 0;
|
|
}
|
|
else if (!PtInRect(&m_rPadding,pt))
|
|
return 0;
|
|
SetClickItem(index);
|
|
SetCapture();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnRButtonUp( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (GetCapture()!=m_hWnd)
|
|
return 0;
|
|
ReleaseCapture();
|
|
if (s_bNoContextMenu) return 0;
|
|
POINT pt={(short)LOWORD(lParam),(short)HIWORD(lParam)};
|
|
bool bArrow=false;
|
|
int index=HitTest(pt,&bArrow);
|
|
if (index>=0)
|
|
{
|
|
if (m_Items[index].id==MENU_SEPARATOR) return 0;
|
|
if (m_Items[index].id!=MENU_SEARCH_CATEGORY || m_Items[index].categoryHash<CSearchManager::CATEGORY_FILE)
|
|
bArrow=false;
|
|
}
|
|
else if (!PtInRect(&m_rPadding,pt))
|
|
return 0;
|
|
SetHotItem(index,bArrow,true);
|
|
ClientToScreen(&pt);
|
|
ActivateData data;
|
|
data.bArrow=bArrow;
|
|
ActivateItem(index,ACTIVATE_MENU,&pt,&data);
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnSetCursor( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (m_rUser1.left<m_rUser1.right)
|
|
{
|
|
DWORD pos=GetMessagePos();
|
|
POINT pt={(short)LOWORD(pos),(short)HIWORD(pos)};
|
|
ScreenToClient(&pt);
|
|
if (PtInRect(&m_rUser1,pt))
|
|
{
|
|
SetCursor(LoadCursor(NULL,IDC_HAND));
|
|
return TRUE;
|
|
}
|
|
}
|
|
if (m_rUser2.left<m_rUser2.right)
|
|
{
|
|
DWORD pos=GetMessagePos();
|
|
POINT pt={(short)LOWORD(pos),(short)HIWORD(pos)};
|
|
ScreenToClient(&pt);
|
|
if (PtInRect(&m_rUser2,pt))
|
|
{
|
|
SetCursor(LoadCursor(NULL,IDC_HAND));
|
|
return TRUE;
|
|
}
|
|
}
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
void CMenuContainer::PlayMenuSound( TMenuSound sound )
|
|
{
|
|
const wchar_t *setting=NULL;
|
|
switch (sound)
|
|
{
|
|
case SOUND_MAIN:
|
|
setting=L"SoundMain";
|
|
break;
|
|
case SOUND_POPUP:
|
|
setting=L"SoundPopup";
|
|
break;
|
|
case SOUND_COMMAND:
|
|
setting=L"SoundCommand";
|
|
break;
|
|
case SOUND_DROP:
|
|
setting=L"SoundDrop";
|
|
break;
|
|
case SOUND_BUTTON_HOVER:
|
|
setting=L"SoundButtonHover";
|
|
break;
|
|
}
|
|
CString str=GetSettingString(setting);
|
|
if (_wcsicmp(PathFindExtension(str),L".wav")==0)
|
|
{
|
|
wchar_t path[_MAX_PATH];
|
|
Strcpy(path,_countof(path),str);
|
|
DoEnvironmentSubst(path,_countof(path));
|
|
PlaySound(path,NULL,SND_FILENAME|SND_ASYNC|SND_NODEFAULT|SND_SYSTEM);
|
|
}
|
|
else if (_wcsicmp(str,L"none")==0)
|
|
return;
|
|
else
|
|
PlaySound(str,NULL,SND_APPLICATION|SND_ALIAS|SND_ASYNC|SND_NODEFAULT|SND_SYSTEM);
|
|
}
|
|
|
|
void CMenuContainer::SaveItemOrder( const std::vector<SortMenuItem> &items )
|
|
{
|
|
if ((m_Options&CONTAINER_DROP) && m_FolderHash[0])
|
|
{
|
|
// save item names in the registry
|
|
CRegKey regOrder;
|
|
wchar_t name[100];
|
|
if (regOrder.Open(HKEY_CURRENT_USER,L"Software\\OpenShell\\StartMenu\\Order")!=ERROR_SUCCESS)
|
|
regOrder.Create(HKEY_CURRENT_USER,L"Software\\OpenShell\\StartMenu\\Order");
|
|
std::vector<unsigned int> hashes[2];
|
|
for (std::vector<SortMenuItem>::const_iterator it=items.begin();it!=items.end();++it)
|
|
{
|
|
if (m_FolderHash[1] && it->priority==2)
|
|
hashes[1].push_back(it->nameHash);
|
|
else
|
|
hashes[0].push_back(it->nameHash);
|
|
}
|
|
|
|
Sprintf(name,_countof(name),L"%08X",m_FolderHash[0]);
|
|
if (hashes[0].empty())
|
|
regOrder.SetBinaryValue(name,NULL,0);
|
|
else
|
|
regOrder.SetBinaryValue(name,&hashes[0][0],(int)hashes[0].size()*4);
|
|
if (m_FolderHash[1])
|
|
{
|
|
Sprintf(name,_countof(name),L"%08X",m_FolderHash[1]);
|
|
if (hashes[1].empty())
|
|
regOrder.SetBinaryValue(name,NULL,0);
|
|
else
|
|
regOrder.SetBinaryValue(name,&hashes[1][0],(int)hashes[1].size()*4);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CMenuContainer::LoadItemOrder( void )
|
|
{
|
|
bool bLoaded=false;
|
|
if ((m_Options&CONTAINER_DROP) && m_FolderHash[0])
|
|
{
|
|
// load item names from the registry
|
|
std::vector<unsigned int> hashes[2];
|
|
CRegKey regOrder;
|
|
if (regOrder.Open(HKEY_CURRENT_USER,L"Software\\OpenShell\\StartMenu\\Order",KEY_READ)==ERROR_SUCCESS)
|
|
{
|
|
wchar_t name[100];
|
|
{
|
|
ULONG size=0;
|
|
Sprintf(name,_countof(name),L"%08X",m_FolderHash[0]);
|
|
regOrder.QueryBinaryValue(name,NULL,&size);
|
|
if (size>0 && !(size&3))
|
|
{
|
|
hashes[0].resize(size/4);
|
|
regOrder.QueryBinaryValue(name,&hashes[0][0],&size);
|
|
bLoaded=true;
|
|
}
|
|
}
|
|
if (m_FolderHash[1])
|
|
{
|
|
ULONG size=0;
|
|
Sprintf(name,_countof(name),L"%08X",m_FolderHash[1]);
|
|
regOrder.QueryBinaryValue(name,NULL,&size);
|
|
if (size>0 && !(size&3))
|
|
{
|
|
hashes[1].resize(size/4);
|
|
regOrder.QueryBinaryValue(name,&hashes[1][0],&size);
|
|
bLoaded=true;
|
|
}
|
|
}
|
|
}
|
|
if (hashes[0].size()==1 && hashes[0][0]=='AUTO')
|
|
{
|
|
m_Options|=CONTAINER_AUTOSORT;
|
|
for (std::vector<MenuItem>::iterator it=m_Items.begin();it!=m_Items.end();++it)
|
|
it->row=0;
|
|
}
|
|
else
|
|
{
|
|
m_Options&=~CONTAINER_AUTOSORT;
|
|
|
|
// assign each m_Item an index based on its position in items. store in row
|
|
// unknown items get the index of the blank item, or at the end
|
|
for (std::vector<MenuItem>::iterator it=m_Items.begin();it!=m_Items.end();++it)
|
|
{
|
|
unsigned int hash=it->nameHash;
|
|
const std::vector<unsigned int> &hashRef=(it->priority==0?hashes[0]:hashes[1]);
|
|
it->row=(int)hashRef.size();
|
|
for (int i=0;i<(int)hashRef.size();i++)
|
|
{
|
|
if (hashRef[i]==hash)
|
|
{
|
|
it->row=i;
|
|
break;
|
|
}
|
|
else if (hashRef[i]==FNV_HASH0)
|
|
it->row=i;
|
|
}
|
|
if (m_Options&CONTAINER_SORTZA)
|
|
it->row=-it->row;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (std::vector<MenuItem>::iterator it=m_Items.begin();it!=m_Items.end();++it)
|
|
it->row=0;
|
|
}
|
|
|
|
if (!(m_Options&CONTAINER_DOCUMENTS) || GetSettingInt(L"SortRecentDocuments")!=2)
|
|
{
|
|
// sort by row, then by bFolder, then by name
|
|
s_bExtensionSort=(m_Options&CONTAINER_DOCUMENTS) && GetSettingInt(L"SortRecentDocuments")==1;
|
|
std::sort(m_Items.begin(),m_Items.end());
|
|
s_bExtensionSort=false;
|
|
}
|
|
if (m_Options&CONTAINER_SORTZA)
|
|
std::reverse(m_Items.begin(),m_Items.end());
|
|
|
|
if ((m_Options&CONTAINER_DROP) && (m_Options&CONTAINER_SORTONCE) && !bLoaded)
|
|
{
|
|
std::vector<SortMenuItem> items;
|
|
for (std::vector<MenuItem>::const_iterator it=m_Items.begin();it!=m_Items.end();++it)
|
|
{
|
|
if (it->id==MENU_NO)
|
|
{
|
|
SortMenuItem item(*it);
|
|
items.push_back(item);
|
|
}
|
|
}
|
|
SaveItemOrder(items);
|
|
}
|
|
}
|
|
|
|
void CMenuContainer::AddMRUAppId( const wchar_t *appid )
|
|
{
|
|
wchar_t path[256];
|
|
Sprintf(path,_countof(path),L"APP:%s",appid);
|
|
AddMRUShortcut(path);
|
|
}
|
|
|
|
void CMenuContainer::AddMRUShortcut( const wchar_t *path )
|
|
{
|
|
if (!*path) return;
|
|
Assert(s_bMRULoaded);
|
|
bool bFound=false;
|
|
for (int i=0;i<MRU_PROGRAMS_COUNT;i++)
|
|
{
|
|
if (_wcsicmp(s_MRUShortcuts[i],path)==0)
|
|
{
|
|
if (i>0)
|
|
{
|
|
CString str=s_MRUShortcuts[i];
|
|
for (;i>0;i--)
|
|
s_MRUShortcuts[i]=s_MRUShortcuts[i-1];
|
|
s_MRUShortcuts[0]=str;
|
|
}
|
|
bFound=true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
for (int i=MRU_PROGRAMS_COUNT-1;i>0;i--)
|
|
s_MRUShortcuts[i]=s_MRUShortcuts[i-1];
|
|
s_MRUShortcuts[0]=path;
|
|
}
|
|
|
|
SaveMRUShortcuts();
|
|
}
|
|
|
|
void CMenuContainer::DeleteMRUAppId( const wchar_t *appid )
|
|
{
|
|
wchar_t path[256];
|
|
Sprintf(path,_countof(path),L"APP:%s",appid);
|
|
DeleteMRUShortcut(path);
|
|
}
|
|
|
|
void CMenuContainer::DeleteMRUShortcut( const wchar_t *path )
|
|
{
|
|
Assert(s_bMRULoaded);
|
|
if (path)
|
|
{
|
|
for (int i=0;i<MRU_PROGRAMS_COUNT;i++)
|
|
{
|
|
if (_wcsicmp(s_MRUShortcuts[i],path)==0)
|
|
{
|
|
for (int j=i;j<MRU_PROGRAMS_COUNT-1;j++)
|
|
s_MRUShortcuts[j]=s_MRUShortcuts[j+1];
|
|
s_MRUShortcuts[MRU_PROGRAMS_COUNT-1].Empty();
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i=0;i<MRU_PROGRAMS_COUNT;i++)
|
|
s_MRUShortcuts[i].Empty();
|
|
}
|
|
|
|
SaveMRUShortcuts();
|
|
}
|
|
|
|
void CMenuContainer::SaveMRUShortcuts( void )
|
|
{
|
|
Assert(s_bMRULoaded);
|
|
CRegKey regMRU;
|
|
if (regMRU.Open(HKEY_CURRENT_USER,L"Software\\OpenShell\\StartMenu\\MRU",KEY_READ|KEY_WRITE)!=ERROR_SUCCESS)
|
|
regMRU.Create(HKEY_CURRENT_USER,L"Software\\OpenShell\\StartMenu\\MRU");
|
|
|
|
bool bDelete=false;
|
|
for (int i=0;i<MRU_PROGRAMS_COUNT;i++)
|
|
{
|
|
wchar_t name[10];
|
|
Sprintf(name,_countof(name),L"%d",i);
|
|
if (s_MRUShortcuts[i].IsEmpty())
|
|
bDelete=true; // delete the rest!
|
|
if (bDelete)
|
|
{
|
|
wchar_t path[256];
|
|
ULONG size=_countof(path);
|
|
if (regMRU.QueryStringValue(name,path,&size)!=ERROR_SUCCESS)
|
|
break;
|
|
regMRU.DeleteValue(name);
|
|
}
|
|
else
|
|
regMRU.SetStringValue(name,s_MRUShortcuts[i]);
|
|
}
|
|
}
|
|
|
|
void CMenuContainer::LoadMRUShortcuts( void )
|
|
{
|
|
for (int i=0;i<MRU_PROGRAMS_COUNT;i++)
|
|
s_MRUShortcuts[i].Empty();
|
|
CRegKey regMRU;
|
|
if (regMRU.Open(HKEY_CURRENT_USER,L"Software\\OpenShell\\StartMenu\\MRU",KEY_READ)==ERROR_SUCCESS)
|
|
{
|
|
for (int i=0;i<MRU_PROGRAMS_COUNT;i++)
|
|
{
|
|
wchar_t name[10];
|
|
Sprintf(name,_countof(name),L"%d",i);
|
|
wchar_t path[256];
|
|
ULONG size=_countof(path);
|
|
if (regMRU.QueryStringValue(name,path,&size)!=ERROR_SUCCESS)
|
|
break;
|
|
s_MRUShortcuts[i]=path;
|
|
}
|
|
}
|
|
s_bMRULoaded=true;
|
|
}
|
|
|
|
void CMenuContainer::RemoveMFUShortcut( unsigned int hash, bool bAppId )
|
|
{
|
|
CRegKey regKey;
|
|
if (regKey.Open(HKEY_CURRENT_USER,bAppId?USERASSIST_APPIDS_KEY:USERASSIST_LINKS_KEY,KEY_READ|KEY_WRITE)==ERROR_SUCCESS)
|
|
{
|
|
for (int idx=0;;idx++)
|
|
{
|
|
wchar_t name[_MAX_PATH];
|
|
DWORD len=_countof(name);
|
|
LONG res=RegEnumValue(regKey,idx,name,&len,NULL,NULL,NULL,0);
|
|
if (res==ERROR_NO_MORE_ITEMS)
|
|
break;
|
|
if (CalcFNVHash(name)==hash)
|
|
{
|
|
regKey.DeleteValue(name);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LRESULT CMenuContainer::OnGetAccObject( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if ((DWORD)lParam==(DWORD)OBJID_CLIENT && m_pAccessible)
|
|
{
|
|
return LresultFromObject(IID_IAccessible,wParam,m_pAccessible);
|
|
}
|
|
else
|
|
{
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool CMenuContainer::CloseStartMenu( void )
|
|
{
|
|
if (s_Menus.empty()) return false;
|
|
if (!CMenuContainer::CanShowMenu()) return false;
|
|
|
|
HWND taskBar=s_TaskBar?s_TaskBar:g_TaskBar;
|
|
::SetActiveWindow(s_StartButton?s_StartButton:taskBar);
|
|
CloseSubMenus(0,NULL);
|
|
|
|
if (s_LastFGWindow && s_LastFGWindow!=GetDesktopWindow() && s_LastFGWindow!=GetShellWindow() && taskBar)
|
|
{
|
|
// don't activate the last application if it was a full-screen window on the same monitor as the taskbar.
|
|
// leave the taskbar up instead
|
|
MONITORINFO info={sizeof(info)};
|
|
GetMonitorInfo(MonitorFromWindow(taskBar,MONITOR_DEFAULTTOPRIMARY),&info);
|
|
RECT rc;
|
|
::GetWindowRect(s_LastFGWindow,&rc);
|
|
if (memcmp(&info.rcMonitor,&rc,sizeof(RECT))!=0)
|
|
SetForegroundWindow(s_LastFGWindow);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CMenuContainer::HideStartMenu( void )
|
|
{
|
|
for (std::vector<CMenuContainer*>::iterator it=s_Menus.begin();it!=s_Menus.end();++it)
|
|
if (!(*it)->m_bDestroyed)
|
|
(*it)->ShowWindow(SW_HIDE);
|
|
}
|
|
|
|
bool CMenuContainer::IsMenuWindow( HWND hWnd )
|
|
{
|
|
for (std::vector<CMenuContainer*>::iterator it=s_Menus.begin();it!=s_Menus.end();++it)
|
|
if (hWnd==(*it)->m_hWnd || (*it)->IsChild(hWnd))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool CMenuContainer::CloseProgramsMenu( void )
|
|
{
|
|
if (s_Menus.empty()) return false;
|
|
|
|
for (std::vector<CMenuContainer*>::const_reverse_iterator it=s_Menus.rbegin();it!=s_Menus.rend();++it)
|
|
if (!(*it)->m_bDestroyed)
|
|
(*it)->PostMessage(WM_CLOSE);
|
|
|
|
return true;
|
|
}
|
|
|
|
static void NewVersionCallback( VersionData &data )
|
|
{
|
|
wchar_t path[_MAX_PATH];
|
|
GetModuleFileName(g_Instance,path,_countof(path));
|
|
PathRemoveFileSpec(path);
|
|
PathAppend(path,L"Update.exe");
|
|
wchar_t cmdLine[1024];
|
|
Sprintf(cmdLine,_countof(cmdLine),L"\"%s\" -popup",path);
|
|
STARTUPINFO startupInfo={sizeof(startupInfo)};
|
|
// don't display busy cursor as we are doing this on background
|
|
startupInfo.dwFlags=STARTF_FORCEOFFFEEDBACK;
|
|
PROCESS_INFORMATION processInfo{};
|
|
if (CreateProcess(path,cmdLine,NULL,NULL,TRUE,0,NULL,NULL,&startupInfo,&processInfo))
|
|
{
|
|
CloseHandle(processInfo.hThread);
|
|
CloseHandle(processInfo.hProcess);
|
|
}
|
|
}
|
|
|
|
static bool CheckForUpdates( void )
|
|
{
|
|
bool bHasUpdates=false;
|
|
if (GetWinVersion()<WIN_VER_WIN8)
|
|
{
|
|
CRegKey regKey;
|
|
if (regKey.Open(HKEY_LOCAL_MACHINE,L"Software\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Auto Update\\UAS",KEY_READ)==ERROR_SUCCESS)
|
|
{
|
|
DWORD val;
|
|
if (regKey.QueryDWORDValue(L"UpdateCount",val)==ERROR_SUCCESS)
|
|
{
|
|
LOG_MENU(LOG_OPEN,L"WU: UpdateCount=%d",val);
|
|
bHasUpdates=val>0;
|
|
}
|
|
}
|
|
}
|
|
if (!bHasUpdates)
|
|
{
|
|
CComPtr<ISystemInformation> pSysInfo;
|
|
pSysInfo.CoCreateInstance(CLSID_SystemInformation);
|
|
if (pSysInfo)
|
|
{
|
|
VARIANT_BOOL reboot;
|
|
if (SUCCEEDED(pSysInfo->get_RebootRequired(&reboot)) && reboot)
|
|
{
|
|
LOG_MENU(LOG_OPEN,L"WU: Reboot required");
|
|
bHasUpdates=true;
|
|
}
|
|
}
|
|
}
|
|
if (!bHasUpdates && GetWinVersion()>=WIN_VER_WIN8)
|
|
{
|
|
typedef HRESULT (WINAPI *FGetAutoUpdateNotification)(DWORD,DWORD*,DWORD*,DWORD*);
|
|
HMODULE mod=LoadLibrary(L"wuaext.dll");
|
|
if (mod)
|
|
{
|
|
FGetAutoUpdateNotification fun=(FGetAutoUpdateNotification)GetProcAddress(mod,"GetAutoUpdateNotification");
|
|
if (fun)
|
|
{
|
|
DWORD a,b,c;
|
|
HRESULT hr=fun(0,&a,&b,&c);
|
|
bHasUpdates=(a==1 || a==2);
|
|
LOG_MENU(LOG_OPEN,L"WU: GetAutoUpdateNotification: %d, %d, %d, %d",hr,a,b,c);
|
|
}
|
|
FreeLibrary(mod);
|
|
}
|
|
}
|
|
return bHasUpdates;
|
|
}
|
|
|
|
static void CreateStartScreenFile( const wchar_t *fname )
|
|
{
|
|
wchar_t link[_MAX_PATH];
|
|
GetModuleFileName(g_Instance,link,_countof(link));
|
|
PathRemoveFileSpec(link);
|
|
PathAppend(link,L"Start Screen.lnk");
|
|
CopyFile(link,fname,TRUE);
|
|
}
|
|
|
|
bool CMenuContainer::HasMoreResults( void )
|
|
{
|
|
if (s_HasMoreResults==-1)
|
|
s_HasMoreResults=(GetSettingBool(L"SearchFiles") && HasSearchService())?1:0;
|
|
return s_HasMoreResults!=0;
|
|
}
|
|
|
|
RECT CMenuContainer::CalculateWorkArea( const RECT &taskbarRect )
|
|
{
|
|
RECT rc=s_MenuLimits;
|
|
if ((s_TaskBarEdge==ABE_LEFT || s_TaskBarEdge==ABE_RIGHT) && GetSettingBool(L"ShowNextToTaskbar"))
|
|
{
|
|
// when the taskbar is on the side and the menu is not on top of it
|
|
// the start button is assumed at the top
|
|
if (s_TaskBarEdge==ABE_LEFT)
|
|
rc.left=taskbarRect.right;
|
|
else
|
|
rc.right=taskbarRect.left;
|
|
}
|
|
else
|
|
{
|
|
if (s_TaskBarEdge==ABE_BOTTOM)
|
|
{
|
|
// taskbar is at the bottom
|
|
rc.bottom=taskbarRect.top;
|
|
}
|
|
else if (s_TaskBarEdge==ABE_TOP)
|
|
{
|
|
// taskbar is at the top
|
|
rc.top=taskbarRect.bottom;
|
|
}
|
|
else
|
|
{
|
|
// taskbar is on the side, start button must be at the top
|
|
rc.top=s_StartRect.bottom;
|
|
}
|
|
}
|
|
|
|
if (!s_bLockWorkArea)
|
|
{
|
|
// exclude floating keyboard
|
|
if (s_pFrameworkInputPane)
|
|
{
|
|
RECT kbdRect;
|
|
if (SUCCEEDED(s_pFrameworkInputPane->Location(&kbdRect)))
|
|
{
|
|
if (rc.top<kbdRect.bottom && rc.bottom>kbdRect.top && rc.left<kbdRect.right && rc.right>kbdRect.left)
|
|
{
|
|
HMONITOR monitor=MonitorFromWindow(m_hWnd,MONITOR_DEFAULTTONULL);
|
|
if (monitor)
|
|
{
|
|
MONITORINFO info={sizeof(info)};
|
|
GetMonitorInfo(monitor,&info);
|
|
if (kbdRect.bottom==info.rcMonitor.bottom && kbdRect.left==info.rcMonitor.left && kbdRect.right==info.rcMonitor.right)
|
|
{
|
|
// the keyboard is docked at the bottom of the monitor
|
|
rc.bottom=kbdRect.top;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
POINT CMenuContainer::CalculateCorner( void )
|
|
{
|
|
RECT margin={0,0,0,0};
|
|
if (IsAppThemed())
|
|
AdjustWindowRect(&margin,GetWindowLong(GWL_STYLE),FALSE);
|
|
|
|
POINT corner;
|
|
if (m_Options&CONTAINER_LEFT)
|
|
corner.x=s_MainMenuLimits.left+margin.left;
|
|
else
|
|
corner.x=s_MainMenuLimits.right+margin.right;
|
|
|
|
if (m_Options&CONTAINER_TOP)
|
|
{
|
|
if (s_bBehindTaskbar)
|
|
corner.y=s_MainMenuLimits.top+margin.top;
|
|
else
|
|
corner.y=s_MainMenuLimits.top;
|
|
}
|
|
else
|
|
corner.y=s_MainMenuLimits.bottom+margin.bottom;
|
|
|
|
return corner;
|
|
}
|
|
|
|
// Toggles the start menu
|
|
HWND CMenuContainer::ToggleStartMenu( int taskbarId, bool bKeyboard, bool bAllPrograms )
|
|
{
|
|
s_bAllPrograms=false;
|
|
if (bAllPrograms)
|
|
{
|
|
if (CloseProgramsMenu())
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
::ShowWindow(g_UserPic,SW_HIDE);
|
|
}
|
|
else
|
|
{
|
|
if (!CanShowMenu())
|
|
return NULL;
|
|
if (!bKeyboard) s_LastFGWindow=NULL;
|
|
bool bSameTaskbar=(s_TaskBarId==taskbarId);
|
|
if (CloseStartMenu())
|
|
{
|
|
if (bSameTaskbar)
|
|
return NULL;
|
|
}
|
|
|
|
s_LastFGWindow=GetForegroundWindow();
|
|
SetForegroundWindow(GetTaskbarInfo(taskbarId)->startButton);
|
|
EnableStartTooltip(false);
|
|
}
|
|
|
|
{
|
|
CRegKey regKey;
|
|
if (regKey.Open(HKEY_CURRENT_USER,GetSettingsRegPath())!=ERROR_SUCCESS)
|
|
regKey.Create(HKEY_CURRENT_USER,GetSettingsRegPath());
|
|
|
|
DWORD val;
|
|
if (regKey.QueryDWORDValue(L"ShowedStyle2",val)!=ERROR_SUCCESS)
|
|
{
|
|
regKey.SetDWORDValue(L"ShowedStyle2",1);
|
|
if (GetSettingBool(L"EnableSettings") && !IsSettingLocked(L"MenuStyle") && !IsSettingForcedDefault(L"MenuStyle"))
|
|
{
|
|
if (regKey.QueryDWORDValue(L"ShowedStyle2",val)==ERROR_SUCCESS && val)
|
|
{
|
|
EditSettings(false,IDS_STYLE_SETTINGS);
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (GetSettingInt(L"CompatibilityFixes")&COMPATIBILITY_CRASH_TEST)
|
|
*(int*)0=0;
|
|
g_ItemManager.RefreshInfos();
|
|
s_bWin7Style=GetSettingInt(L"MenuStyle")==MENU_WIN7;
|
|
|
|
if (!s_StartMenuMsg)
|
|
s_StartMenuMsg=RegisterWindowMessage(L"OpenShellMenu.StartMenuMsg");
|
|
s_StartMenuParams.uEdge=0xFFFFFFFF;
|
|
s_TaskBarId=taskbarId;
|
|
TaskbarInfo *taskBar=GetTaskbarInfo(taskbarId);
|
|
s_TaskBar=taskBar->taskBar;
|
|
s_StartButton=taskBar->startButton;
|
|
s_bAllPrograms=bAllPrograms;
|
|
s_MenuMode=MODE_NORMAL;
|
|
s_PreSearchMenuMode=MODE_NORMAL;
|
|
s_MenuHeight=-1;
|
|
s_MenuMaxHeight[0]=-1;
|
|
s_MenuWidthJump=0;
|
|
s_MenuWidthMax=0;
|
|
s_MenuWidthNormal=-1;
|
|
s_ProgramsWidth=GetSettingInt(L"ProgramsWidth");
|
|
s_JumplistWidth=GetSettingInt(L"JumplistWidth");
|
|
s_BackgroundW1=s_BackgroundW2=s_BackgroundH1=s_BackgroundH2=0;
|
|
ClearOldState();
|
|
int categories=0;
|
|
{
|
|
CRegKey regKey;
|
|
if (regKey.Open(HKEY_CURRENT_USER,L"Software\\OpenShell\\StartMenu\\Settings",KEY_READ|KEY_WOW64_64KEY)==ERROR_SUCCESS)
|
|
{
|
|
DWORD log;
|
|
if (regKey.QueryDWORDValue(L"LogCategories",log)==ERROR_SUCCESS)
|
|
categories=log;
|
|
}
|
|
}
|
|
#ifdef BUILD_BETA
|
|
categories=LOG_ALL;
|
|
#endif
|
|
if (categories!=0)
|
|
{
|
|
wchar_t path[_MAX_PATH]=L"%LOCALAPPDATA%\\OpenShell";
|
|
DoEnvironmentSubst(path,_MAX_PATH);
|
|
SHCreateDirectory(NULL,path);
|
|
Strcat(path,_countof(path),L"\\StartMenuLog.txt");
|
|
InitLog(categories,path);
|
|
}
|
|
|
|
{
|
|
CSettingsLockWrite lock;
|
|
UpdateDefaultSettings();
|
|
}
|
|
|
|
// initialize all settings
|
|
bool bErr=false;
|
|
HMONITOR initialMonitor=MonitorFromWindow(s_TaskBar,MONITOR_DEFAULTTONEAREST);
|
|
int dpi=CItemManager::GetDPI(true);
|
|
if (!CItemManager::GetDPIOverride() && GetWinVersion()>=WIN_VER_WIN81)
|
|
{
|
|
HMODULE shModule=GetModuleHandle(L"Shcore.dll");
|
|
if (shModule)
|
|
{
|
|
typedef HRESULT (WINAPI *tGetDpiForMonitor)( HMONITOR monitor, UINT dpiType, UINT *dpiX, UINT *dpiY );
|
|
tGetDpiForMonitor GetDpiForMonitor=(tGetDpiForMonitor)GetProcAddress(shModule,"GetDpiForMonitor");
|
|
if (GetDpiForMonitor)
|
|
{
|
|
UINT dpiX, dpiY;
|
|
if (SUCCEEDED(GetDpiForMonitor(initialMonitor,0,&dpiX,&dpiY)))
|
|
dpi=dpiY;
|
|
}
|
|
}
|
|
}
|
|
if (bAllPrograms)
|
|
{
|
|
bErr=!s_Skin.LoadMenuSkin(GetSettingString(L"SkinA"),GetSettingString(L"SkinVariationA"),GetSettingString(L"SkinOptionsA"),MenuSkin::SKIN_TYPE_ALL_PROGRAMS,LOADMENU_RESOURCES,dpi);
|
|
if (bErr)
|
|
s_Skin.LoadDefaultMenuSkin(MenuSkin::SKIN_TYPE_ALL_PROGRAMS,LOADMENU_RESOURCES,dpi);
|
|
}
|
|
else if (s_bWin7Style)
|
|
{
|
|
bErr=!s_Skin.LoadMenuSkin(GetSettingString(L"SkinW7"),GetSettingString(L"SkinVariationW7"),GetSettingString(L"SkinOptionsW7"),MenuSkin::SKIN_TYPE_WIN7,LOADMENU_RESOURCES,dpi);
|
|
if (bErr)
|
|
s_Skin.LoadDefaultMenuSkin(MenuSkin::SKIN_TYPE_WIN7,LOADMENU_RESOURCES,dpi);
|
|
}
|
|
else if (GetSettingInt(L"MenuStyle")==1)
|
|
{
|
|
bErr=!s_Skin.LoadMenuSkin(GetSettingString(L"SkinC2"),GetSettingString(L"SkinVariationC2"),GetSettingString(L"SkinOptionsC2"),MenuSkin::SKIN_TYPE_CLASSIC2,LOADMENU_RESOURCES,dpi);
|
|
if (bErr)
|
|
s_Skin.LoadDefaultMenuSkin(MenuSkin::SKIN_TYPE_CLASSIC2,LOADMENU_RESOURCES,dpi);
|
|
}
|
|
else
|
|
{
|
|
bErr=!s_Skin.LoadMenuSkin(GetSettingString(L"SkinC1"),GetSettingString(L"SkinVariationC1"),GetSettingString(L"SkinOptionsC1"),MenuSkin::SKIN_TYPE_CLASSIC1,LOADMENU_RESOURCES,dpi);
|
|
if (bErr)
|
|
s_Skin.LoadDefaultMenuSkin(MenuSkin::SKIN_TYPE_CLASSIC1,LOADMENU_RESOURCES,dpi);
|
|
}
|
|
|
|
const MenuSkin &s_Skin=CMenuContainer::s_Skin; // shadow s_Skin with a const reference to catch any modifications to non-mutable members
|
|
g_CurrentCSMTaskbar=s_TaskBarId;
|
|
PressStartButton(s_TaskBarId,true);
|
|
g_ItemManager.ResetTempIcons();
|
|
s_ScrollMenus=GetSettingInt(L"ScrollType");
|
|
s_bExpandLinks=GetSettingBool(L"ExpandFolderLinks");
|
|
s_bLogicalSort=GetSettingBool(L"NumericSort");
|
|
s_MaxRecentDocuments=GetSettingInt(L"MaxRecentDocuments");
|
|
s_ShellFormat=RegisterClipboardFormat(CFSTR_SHELLIDLIST);
|
|
s_ShellUrlFormat=RegisterClipboardFormat(CFSTR_INETURL);
|
|
s_DescriptorFormat=RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
|
|
s_ContentsFormat=RegisterClipboardFormat(CFSTR_FILECONTENTS);
|
|
s_MetroLinkFormat=RegisterClipboardFormat(L"OpenShell.MetroLink");
|
|
s_PreferredEffectFormat=RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT);
|
|
s_DropDescriptionFormat=RegisterClipboardFormat(CFSTR_DROPDESCRIPTION);
|
|
s_bNoCommonFolders=(SHRestricted(REST_NOCOMMONGROUPS)!=0);
|
|
s_bNoRun=(SHRestricted(REST_NORUN)!=0);
|
|
s_bNoClose=(SHRestricted(REST_NOCLOSE)!=0);
|
|
s_bHasTouch=GetWinVersion()>=WIN_VER_WIN8 && GetSettingBool(L"EnableTouch") && (GetSystemMetrics(SM_DIGITIZER)&NID_INTEGRATED_TOUCH)!=0;
|
|
s_HasMoreResults=-1;
|
|
s_bDisableHover=false;
|
|
s_bDragClosed=false;
|
|
s_bPendingSearchEnter=false;
|
|
InitTouchHelper();
|
|
|
|
bool bRemote=GetSystemMetrics(SM_REMOTESESSION)!=0;
|
|
wchar_t wabPath[_MAX_PATH]=L"%ProgramFiles%\\Windows Mail\\wab.exe";
|
|
DoEnvironmentSubst(wabPath,_countof(wabPath));
|
|
HANDLE hWab=CreateFile(wabPath,0,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
|
|
bool bPeople=(hWab!=INVALID_HANDLE_VALUE);
|
|
if (bPeople) CloseHandle(hWab);
|
|
s_bRTL=s_Skin.ForceRTL || IsLanguageRTL();
|
|
|
|
{
|
|
APPBARDATA appbar={sizeof(appbar)};
|
|
s_TaskbarState=(DWORD)SHAppBarMessage(ABM_GETSTATE,&appbar);
|
|
}
|
|
|
|
// the taskbar on Windows 7 (and most likely later versions) is always on top even though it doesn't have the ABS_ALWAYSONTOP flag.
|
|
if (GetWinVersion()>=WIN_VER_WIN7)
|
|
{
|
|
// also check the WS_EX_TOPMOST style - maybe some tool like DisableTaskbarOnTop is messing with it
|
|
if (::GetWindowLong(s_TaskBar,GWL_EXSTYLE)&WS_EX_TOPMOST)
|
|
s_TaskbarState|=ABS_ALWAYSONTOP;
|
|
}
|
|
|
|
if (!bAllPrograms && (s_TaskbarState&ABS_AUTOHIDE))
|
|
{
|
|
::SetActiveWindow(s_TaskBar);
|
|
}
|
|
if (!bAllPrograms)
|
|
{
|
|
// set the taskbar as the foreground window so all keyboard input is sent to the taskbar thread (and be later captured by the start menu)
|
|
SetForegroundWindow(s_TaskBar);
|
|
}
|
|
|
|
if (s_bActiveDirectory==-1)
|
|
{
|
|
DOMAIN_CONTROLLER_INFO *info;
|
|
DWORD err=DsGetDcName(NULL,NULL,NULL,NULL,DS_RETURN_FLAT_NAME,&info);
|
|
if (err==ERROR_SUCCESS)
|
|
{
|
|
s_bActiveDirectory=1;
|
|
NetApiBufferFree(info);
|
|
}
|
|
else
|
|
s_bActiveDirectory=0;
|
|
}
|
|
|
|
if (GetWinVersion()>=WIN_VER_WIN8 && !s_pFrameworkInputPane && !(GetSettingInt(L"CompatibilityFixes")&COMPATIBILITY_NO_TOUCH_KBD))
|
|
{
|
|
s_pFrameworkInputPane.CoCreateInstance(CLSID_FrameworkInputPane);
|
|
}
|
|
|
|
s_bHasUpdates=(!bRemote || GetSettingBool(L"RemoteShutdown")) && GetSettingBool(L"CheckWinUpdates") && CheckForUpdates();
|
|
|
|
// Check control panel options for power buttons
|
|
bool bHibernate = true, bSleep = true, bLock = true;
|
|
{
|
|
CRegKey regKeyButtons;
|
|
if (regKeyButtons.Open(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FlyoutMenuSettings", KEY_READ) == ERROR_SUCCESS)
|
|
{
|
|
DWORD dwValue = 1;
|
|
if (regKeyButtons.QueryDWORDValue(L"ShowHibernateOption", dwValue) == ERROR_SUCCESS)
|
|
if (dwValue == 0)
|
|
bHibernate = false;
|
|
|
|
if (regKeyButtons.QueryDWORDValue(L"ShowLockOption", dwValue) == ERROR_SUCCESS)
|
|
if (dwValue == 0)
|
|
bLock = false;
|
|
|
|
if (regKeyButtons.QueryDWORDValue(L"ShowSleepOption", dwValue) == ERROR_SUCCESS)
|
|
if (dwValue == 0)
|
|
bSleep = false;
|
|
}
|
|
}
|
|
|
|
if (bHibernate || bSleep)
|
|
{
|
|
SYSTEM_POWER_CAPABILITIES powerCaps;
|
|
GetPwrCapabilities(&powerCaps);
|
|
|
|
// no sleep capabilities, turn off the sleep option
|
|
if (!(powerCaps.SystemS1 || powerCaps.SystemS2 || powerCaps.SystemS3 || powerCaps.AoAc))
|
|
{
|
|
bSleep = false;
|
|
}
|
|
|
|
// no hibernate capabilities, turn off hibernate option
|
|
if (!powerCaps.HiberFilePresent)
|
|
{
|
|
bHibernate = false;
|
|
/* disabled for now, use group policy to hide Hibernate
|
|
// disable hibernate if hybrid sleep (fast s4) is enabled
|
|
SYSTEM_POWER_STATUS status;
|
|
if (GetSystemPowerStatus(&status) && (status.ACLineStatus==0 || status.ACLineStatus==1))
|
|
{
|
|
GUID *pScheme;
|
|
if (PowerGetActiveScheme(NULL,&pScheme)==ERROR_SUCCESS)
|
|
{
|
|
DWORD index;
|
|
if ((status.ACLineStatus==1?PowerReadACValueIndex:PowerReadDCValueIndex)(NULL,pScheme,&GUID_SLEEP_SUBGROUP,&GUID_HIBERNATE_FASTS4_POLICY,&index)==ERROR_SUCCESS && index)
|
|
bHibernate=false;
|
|
LocalFree(pScheme);
|
|
}
|
|
}*/
|
|
}
|
|
}
|
|
|
|
for (int i=0;i<_countof(g_StdOptions);i++)
|
|
{
|
|
switch (g_StdOptions[i].id)
|
|
{
|
|
case MENU_COMPUTER:
|
|
if (s_bWin7Style)
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
else
|
|
{
|
|
g_StdOptions[i].options=0;
|
|
int show=GetSettingInt(L"Computer");
|
|
if (show==1)
|
|
g_StdOptions[i].options=MENU_ENABLED;
|
|
else if (show==2 || show==3)
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
}
|
|
break;
|
|
case MENU_FAVORITES:
|
|
if (s_bWin7Style)
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
else
|
|
{
|
|
g_StdOptions[i].options=0;
|
|
int show=GetSettingInt(L"Favorites");
|
|
if (show==1)
|
|
g_StdOptions[i].options=MENU_ENABLED;
|
|
else if (show==2)
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
}
|
|
break;
|
|
case MENU_DOCUMENTS:
|
|
if (s_bWin7Style)
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
else
|
|
{
|
|
g_StdOptions[i].options=0;
|
|
int show=GetSettingInt(L"Documents");
|
|
if (show==1)
|
|
g_StdOptions[i].options=MENU_ENABLED;
|
|
else if (show==2)
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
}
|
|
break;
|
|
case MENU_LOGOFF:
|
|
if (s_bWin7Style)
|
|
g_StdOptions[i].options=SHRestricted(REST_STARTMENULOGOFF)!=1?MENU_ENABLED|MENU_EXPANDED:0;
|
|
else
|
|
g_StdOptions[i].options=GetSettingBool(L"LogOff")?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_DISCONNECT:
|
|
g_StdOptions[i].options=(bRemote && !SHRestricted(REST_NODISCONNECT))?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_SHUTDOWN:
|
|
case MENU_RESTART:
|
|
g_StdOptions[i].options=(!s_bNoClose && (!bRemote || GetSettingBool(L"RemoteShutdown")))?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_SHUTDOWN_NOUPDATE:
|
|
g_StdOptions[i].options=(s_bHasUpdates && !s_bNoClose && (!bRemote || GetSettingBool(L"RemoteShutdown")))?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_RESTART_NOUPDATE:
|
|
g_StdOptions[i].options=(s_bHasUpdates && GetWinVersion()>=WIN_VER_WIN8 && !s_bNoClose && (!bRemote || GetSettingBool(L"RemoteShutdown")))?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_SHUTDOWN_BOX:
|
|
g_StdOptions[i].options=0;
|
|
if (!bRemote || GetSettingBool(L"RemoteShutdown"))
|
|
{
|
|
int show=GetSettingInt(L"Shutdown");
|
|
if (show==1)
|
|
g_StdOptions[i].options=MENU_ENABLED;
|
|
else if (show==2)
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
}
|
|
break;
|
|
case MENU_SHUTDOWN_BUTTON:
|
|
g_StdOptions[i].options=GetSettingInt(L"ShutdownCommand")>SHUTDOWN_TYPE_NONE?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_UNDOCK:
|
|
{
|
|
HW_PROFILE_INFO info;
|
|
GetCurrentHwProfile(&info);
|
|
if ((info.dwDockInfo&(DOCKINFO_DOCKED|DOCKINFO_UNDOCKED))!=DOCKINFO_DOCKED)
|
|
g_StdOptions[i].options=0;
|
|
else if (s_bWin7Style)
|
|
g_StdOptions[i].options=SHRestricted(REST_NOSMEJECTPC)?0:MENU_ENABLED|MENU_EXPANDED;
|
|
else
|
|
g_StdOptions[i].options=GetSettingBool(L"Undock")?MENU_ENABLED|MENU_EXPANDED:0;
|
|
}
|
|
break;
|
|
case MENU_CONTROLPANEL:
|
|
if (s_bWin7Style)
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
else
|
|
{
|
|
g_StdOptions[i].options=0;
|
|
int show=GetSettingInt(L"ControlPanel");
|
|
if (show==1)
|
|
g_StdOptions[i].options=MENU_ENABLED;
|
|
else if (show==2)
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
}
|
|
break;
|
|
case MENU_SECURITY:
|
|
g_StdOptions[i].options=bRemote?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_NETWORK:
|
|
if (s_bWin7Style)
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
else
|
|
{
|
|
g_StdOptions[i].options=0;
|
|
int show=GetSettingInt(L"Network");
|
|
if (show==1)
|
|
g_StdOptions[i].options=MENU_ENABLED;
|
|
else if (show==2)
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
}
|
|
break;
|
|
case MENU_PRINTERS:
|
|
if (s_bWin7Style)
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
else
|
|
{
|
|
g_StdOptions[i].options=0;
|
|
int show=GetSettingInt(L"Printers");
|
|
if (show==1)
|
|
g_StdOptions[i].options=MENU_ENABLED;
|
|
else if (show==2)
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
}
|
|
break;
|
|
|
|
case MENU_SEARCH_PRINTER:
|
|
g_StdOptions[i].options=s_bActiveDirectory==1?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_SEARCH_COMPUTERS:
|
|
g_StdOptions[i].options=(s_bActiveDirectory==1 && !SHRestricted(REST_HASFINDCOMPUTERS))?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_SEARCH_PEOPLE:
|
|
g_StdOptions[i].options=bPeople?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
|
|
case MENU_HELP:
|
|
if (s_bWin7Style)
|
|
g_StdOptions[i].options=SHRestricted(REST_NOSMHELP)?0:MENU_ENABLED|MENU_EXPANDED;
|
|
else
|
|
g_StdOptions[i].options=GetSettingBool(L"Help")?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_RUN:
|
|
if (s_bWin7Style)
|
|
g_StdOptions[i].options=s_bNoRun?0:MENU_ENABLED|MENU_EXPANDED;
|
|
else
|
|
g_StdOptions[i].options=GetSettingBool(L"Run")?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_TASKBAR:
|
|
g_StdOptions[i].options=!SHRestricted(REST_NOSETTASKBAR)?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_FEATURES:
|
|
g_StdOptions[i].options=(!SHRestricted(REST_NOSETFOLDERS) && !SHRestricted(REST_NOCONTROLPANEL))?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_CLASSIC_SETTINGS:
|
|
g_StdOptions[i].options=GetSettingBool(L"EnableSettings")?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_SEARCH:
|
|
g_StdOptions[i].options=GetSettingBool(L"Search")?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_SEARCH_BOX:
|
|
g_StdOptions[i].options=GetSettingInt(L"SearchBox")!=SEARCHBOX_HIDDEN?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_USERFILES:
|
|
if (s_bWin7Style)
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
else
|
|
{
|
|
g_StdOptions[i].options=0;
|
|
int show=GetSettingInt(L"UserFiles");
|
|
if (show==1)
|
|
g_StdOptions[i].options=MENU_ENABLED;
|
|
else if (show==2)
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
}
|
|
break;
|
|
case MENU_USERDOCUMENTS:
|
|
if (s_bWin7Style)
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
else
|
|
{
|
|
g_StdOptions[i].options=0;
|
|
int show=GetSettingInt(L"UserDocuments");
|
|
if (show==1)
|
|
g_StdOptions[i].options=MENU_ENABLED;
|
|
else if (show==2)
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
}
|
|
break;
|
|
case MENU_USERPICTURES:
|
|
if (s_bWin7Style)
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
else
|
|
{
|
|
g_StdOptions[i].options=0;
|
|
int show=GetSettingInt(L"UserPictures");
|
|
if (show==1)
|
|
g_StdOptions[i].options=MENU_ENABLED;
|
|
else if (show==2)
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
}
|
|
break;
|
|
case MENU_LOCK:
|
|
g_StdOptions[i].options=(bLock)?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_SLEEP:
|
|
g_StdOptions[i].options=(!s_bNoClose && bSleep)?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_HIBERNATE:
|
|
g_StdOptions[i].options=(!s_bNoClose && bHibernate)?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_SWITCHUSER:
|
|
{
|
|
g_StdOptions[i].options=MENU_ENABLED|MENU_EXPANDED;
|
|
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)
|
|
g_StdOptions[i].options=0;
|
|
}
|
|
}
|
|
break;
|
|
case MENU_APPS:
|
|
g_StdOptions[i].options=(s_bWin7Style || (GetWinVersion()>=WIN_VER_WIN8 && GetSettingBool(L"ShowAppsMenu")))?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
case MENU_PCSETTINGS:
|
|
g_StdOptions[i].options=(GetWinVersion()>=WIN_VER_WIN8)?MENU_ENABLED|MENU_EXPANDED:0;
|
|
break;
|
|
}
|
|
LOG_MENU(LOG_OPEN,L"ItemOptions[%d]=%d",i,g_StdOptions[i].options);
|
|
}
|
|
|
|
s_bNoDragDrop=!GetSettingBool(L"EnableDragDrop");
|
|
s_bNoContextMenu=!GetSettingBool(L"EnableContextMenu");
|
|
s_bKeyboardCues=bKeyboard;
|
|
s_RecentPrograms=(TRecentPrograms)GetSettingInt(L"RecentPrograms");
|
|
if (s_RecentPrograms!=RECENT_PROGRAMS_NONE)
|
|
LoadMRUShortcuts();
|
|
s_ShutdownCommand=MENU_NO;
|
|
|
|
// create the top menu from the Start Menu folders
|
|
CAbsolutePidl path1;
|
|
CAbsolutePidl path2;
|
|
s_PinFolder.Empty();
|
|
if (bAllPrograms || GetSettingInt(L"PinnedPrograms")==PINNED_PROGRAMS_FAST)
|
|
{
|
|
ShGetKnownFolderIDList(FOLDERID_StartMenu,&path1);
|
|
CComString pPath;
|
|
ShGetKnownFolderPath(FOLDERID_StartMenu,&pPath);
|
|
if (pPath)
|
|
s_PinFolder=pPath;
|
|
if (!s_bNoCommonFolders)
|
|
ShGetKnownFolderIDList(FOLDERID_CommonStartMenu,&path2);
|
|
}
|
|
else
|
|
{
|
|
wchar_t path[_MAX_PATH]=START_MENU_PINNED_ROOT;
|
|
DoEnvironmentSubst(path,_countof(path));
|
|
SHCreateDirectory(NULL,path);
|
|
s_PinFolder=path;
|
|
SHParseDisplayName(path,NULL,&path1,0,NULL);
|
|
}
|
|
#ifndef STARTSCREEN_WIN7
|
|
if (GetWinVersion()>=WIN_VER_WIN8)
|
|
#endif
|
|
{
|
|
bool bPinned=GetSettingInt(L"PinnedPrograms")==PINNED_PROGRAMS_PINNED;
|
|
bool bShortcut=GetSettingBool(L"StartScreenShortcut");
|
|
wchar_t path[_MAX_PATH]=START_MENU_PINNED_ROOT L"\\" STARTSCREEN_COMMAND;
|
|
DoEnvironmentSubst(path,_countof(path));
|
|
if (bPinned)
|
|
{
|
|
if (GetFileAttributes(path)==INVALID_FILE_ATTRIBUTES)
|
|
{
|
|
if (bShortcut)
|
|
CreateStartScreenFile(path);
|
|
}
|
|
else if (!bShortcut)
|
|
DeleteFile(path);
|
|
}
|
|
CComString pPath;
|
|
ShGetKnownFolderPath(FOLDERID_StartMenu,&pPath);
|
|
Sprintf(path,_countof(path),L"%s\\" STARTSCREEN_COMMAND,(const wchar_t*)pPath);
|
|
if (GetFileAttributes(path)==INVALID_FILE_ATTRIBUTES)
|
|
{
|
|
if (!bPinned && bShortcut)
|
|
CreateStartScreenFile(path);
|
|
}
|
|
else if (bPinned || !bShortcut)
|
|
DeleteFile(path);
|
|
}
|
|
|
|
int options=CONTAINER_PROGRAMS|CONTAINER_DRAG|CONTAINER_DROP;
|
|
unsigned int rootSettings=0;
|
|
const StdMenuItem *pRoot=NULL;
|
|
if (bAllPrograms)
|
|
{
|
|
options|=CONTAINER_ALLPROGRAMS;
|
|
}
|
|
else
|
|
{
|
|
pRoot=ParseCustomMenu(rootSettings);
|
|
}
|
|
|
|
bool bTopMost=(s_TaskbarState&ABS_ALWAYSONTOP)!=0 || bAllPrograms;
|
|
|
|
SystemParametersInfo(SPI_GETACTIVEWINDOWTRACKING,NULL,&s_XMouse,0);
|
|
if (s_XMouse)
|
|
SystemParametersInfo(SPI_SETACTIVEWINDOWTRACKING,NULL,(PVOID)FALSE,SPIF_SENDCHANGE);
|
|
|
|
s_bBehindTaskbar=!bAllPrograms;
|
|
s_bShowTopEmpty=false;
|
|
DWORD dwStyle=WS_POPUP|WS_CLIPCHILDREN;
|
|
s_SubmenuStyle=WS_POPUP;
|
|
|
|
bool bTheme=IsAppThemed()!=FALSE;
|
|
if (bTheme)
|
|
{
|
|
if (s_Skin.Main_opacity==MenuSkin::OPACITY_SOLID)
|
|
dwStyle|=WS_BORDER;
|
|
if (s_Skin.Submenu_opacity==MenuSkin::OPACITY_SOLID)
|
|
s_SubmenuStyle|=WS_BORDER;
|
|
}
|
|
else
|
|
{
|
|
if (s_Skin.Main_opacity==MenuSkin::OPACITY_SOLID)
|
|
dwStyle|=s_Skin.Main_thin_frame?WS_BORDER:WS_DLGFRAME;
|
|
if (s_Skin.Submenu_opacity==MenuSkin::OPACITY_SOLID)
|
|
s_SubmenuStyle|=s_Skin.Submenu_thin_frame?WS_BORDER:WS_DLGFRAME;
|
|
}
|
|
|
|
if (s_bWin7Style)
|
|
{
|
|
for (int i=MenuSkin::SHUTDOWN_BUTTON;i<=MenuSkin::SHUTDOWN_BUTTON_JUMP;i++)
|
|
{
|
|
const MenuSkin::ItemDrawSettings &settings=s_Skin.ItemSettings[i];
|
|
int textHeight=settings.textMetrics.tmHeight+settings.textPadding.top+settings.textPadding.bottom;
|
|
int iconHeight=0;
|
|
if (s_bHasUpdates)
|
|
iconHeight=s_Skin.Shutdown_bitmap_Size.cy;
|
|
iconHeight+=settings.iconPadding.top+settings.iconPadding.bottom;
|
|
if (iconHeight<textHeight)
|
|
{
|
|
settings.iconTopOffset=(textHeight-iconHeight)/2;
|
|
settings.textTopOffset=0;
|
|
settings.itemHeight=textHeight;
|
|
}
|
|
else
|
|
{
|
|
settings.iconTopOffset=0;
|
|
settings.textTopOffset=(iconHeight-textHeight)/2;
|
|
settings.itemHeight=iconHeight;
|
|
}
|
|
}
|
|
}
|
|
|
|
s_HoverTime=GetSettingInt(L"MenuDelay");
|
|
s_SplitHoverTime=((s_HoverTime?s_HoverTime:100)*GetSettingInt(L"SplitMenuDelay"))/100;
|
|
s_ProgramsHoverTime=((s_HoverTime?s_HoverTime:100)*GetSettingInt(L"ProgramsMenuDelay"))/100;
|
|
|
|
CMenuContainer *pStartMenu;
|
|
if (bAllPrograms)
|
|
pStartMenu=new CSubMenuContainer(NULL,bAllPrograms?0:-1,options,pRoot,path1,path2);
|
|
else
|
|
pStartMenu=new CMenuContainer(NULL,bAllPrograms?0:-1,options,pRoot,path1,path2);
|
|
|
|
HWND owner=NULL;
|
|
if (bAllPrograms)
|
|
{
|
|
APPBARDATA appbar={sizeof(appbar),s_TaskBar};
|
|
SHAppBarMessage(ABM_GETTASKBARPOS,&appbar);
|
|
if (appbar.uEdge==ABE_LEFT || appbar.uEdge==ABE_RIGHT)
|
|
owner=g_TopWin7Menu;
|
|
}
|
|
|
|
RECT dummyRc;
|
|
{
|
|
MONITORINFO info={sizeof(MONITORINFO)};
|
|
GetMonitorInfo(initialMonitor,&info);
|
|
RECT rc={info.rcMonitor.left,info.rcMonitor.top,info.rcMonitor.left+100,info.rcMonitor.top+100};
|
|
if (!pStartMenu->Create(owner,&rc,bAllPrograms?s_SubmenuStyle:dwStyle,WS_EX_TOOLWINDOW|((bTopMost || !s_bBehindTaskbar)?WS_EX_TOPMOST:0)|(s_bRTL?WS_EX_LAYOUTRTL:0)))
|
|
{
|
|
delete pStartMenu;
|
|
return NULL;
|
|
}
|
|
dummyRc=rc;
|
|
}
|
|
|
|
if (GetSettingBool(L"MenuShadow") && s_Skin.Main_shadow==MenuSkin::SHADOW_ON)
|
|
SetClassLongPtr(pStartMenu->m_hWnd,GCL_STYLE,GetClassLongPtr(pStartMenu->m_hWnd,GCL_STYLE)|CS_DROPSHADOW);
|
|
else
|
|
SetClassLongPtr(pStartMenu->m_hWnd,GCL_STYLE,GetClassLongPtr(pStartMenu->m_hWnd,GCL_STYLE)&~CS_DROPSHADOW);
|
|
|
|
if (s_bWin7Style && !s_bAllPrograms && s_Skin.User_bitmapSize.cx>0)
|
|
{
|
|
s_UserPicture.Create(pStartMenu->m_hWnd,NULL,NULL,WS_POPUP,WS_EX_TOOLWINDOW|WS_EX_LAYERED);
|
|
s_UserPicture.Init(pStartMenu);
|
|
}
|
|
dummyRc.right++;
|
|
pStartMenu->SetWindowPos(NULL,&dummyRc,SWP_NOZORDER);
|
|
|
|
memset(&s_StartRect,0,sizeof(s_StartRect));
|
|
|
|
HMONITOR s_MenuMonitor=MonitorFromWindow(bAllPrograms?g_ProgramsButton:pStartMenu->m_hWnd,MONITOR_DEFAULTTONEAREST);
|
|
s_bLockWorkArea=true;
|
|
RECT taskbarRect;
|
|
if (initialMonitor!=s_MenuMonitor && s_StartMenuParams.uEdge==0xFFFFFFFF)
|
|
{
|
|
// somebody has moved the menu to another monitor. recalculate the working area and the taskbar orientation
|
|
MONITORINFO info={sizeof(info)};
|
|
GetMonitorInfo(s_MenuMonitor,&info);
|
|
s_MenuLimits=info.rcMonitor;
|
|
s_StartButton=s_TaskBar=NULL;
|
|
if (bAllPrograms)
|
|
{
|
|
::GetWindowRect(g_ProgramsButton,&s_StartRect);
|
|
}
|
|
else
|
|
{
|
|
RECT rc;
|
|
pStartMenu->GetWindowRect(&rc);
|
|
s_StartRect=rc;
|
|
taskbarRect=info.rcMonitor;
|
|
int dx=(rc.left+rc.right-info.rcMonitor.left-info.rcMonitor.right)/2;
|
|
int dy=(rc.top+rc.bottom-info.rcMonitor.top-info.rcMonitor.bottom)/2;
|
|
if (dx<0 && dy<0)
|
|
{
|
|
// top-left corner
|
|
s_StartRect.bottom=s_StartRect.top;
|
|
s_StartRect.right=s_StartRect.left;
|
|
if (rc.top-info.rcMonitor.top>rc.left-info.rcMonitor.left)
|
|
{
|
|
// top
|
|
taskbarRect.bottom=rc.top;
|
|
s_TaskBarEdge=ABE_TOP;
|
|
}
|
|
else
|
|
{
|
|
// left
|
|
taskbarRect.right=rc.left;
|
|
s_TaskBarEdge=ABE_LEFT;
|
|
}
|
|
}
|
|
else if (dx<0 && dy>=0)
|
|
{
|
|
// bottom-left corner
|
|
s_StartRect.top=s_StartRect.bottom;
|
|
s_StartRect.right=s_StartRect.left;
|
|
if (info.rcMonitor.bottom-rc.bottom>rc.left-info.rcMonitor.left)
|
|
{
|
|
// bottom
|
|
taskbarRect.top=rc.bottom;
|
|
s_TaskBarEdge=ABE_BOTTOM;
|
|
}
|
|
else
|
|
{
|
|
// left
|
|
taskbarRect.right=rc.left;
|
|
s_TaskBarEdge=ABE_LEFT;
|
|
}
|
|
}
|
|
else if (dx>=0 && dy<0)
|
|
{
|
|
// top-right corner
|
|
s_StartRect.bottom=s_StartRect.top;
|
|
s_StartRect.left=s_StartRect.right;
|
|
if (rc.top-info.rcMonitor.top>info.rcMonitor.right-rc.right)
|
|
{
|
|
// top
|
|
taskbarRect.bottom=rc.top;
|
|
s_TaskBarEdge=ABE_TOP;
|
|
}
|
|
else
|
|
{
|
|
// right
|
|
taskbarRect.left=rc.right;
|
|
s_TaskBarEdge=ABE_RIGHT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// bottom-right corner
|
|
s_StartRect.top=s_StartRect.bottom;
|
|
s_StartRect.left=s_StartRect.right;
|
|
if (info.rcMonitor.bottom-rc.bottom>info.rcMonitor.right-rc.right)
|
|
{
|
|
// bottom
|
|
taskbarRect.top=rc.bottom;
|
|
s_TaskBarEdge=ABE_BOTTOM;
|
|
}
|
|
else
|
|
{
|
|
// right
|
|
taskbarRect.left=rc.right;
|
|
s_TaskBarEdge=ABE_RIGHT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (s_StartMenuParams.uEdge!=0xFFFFFFFF)
|
|
{
|
|
s_StartButton=s_StartMenuParams.startButton;
|
|
s_TaskBar=s_StartMenuParams.taskbar;
|
|
s_TaskBarEdge=s_StartMenuParams.uEdge;
|
|
s_MenuLimits=s_StartMenuParams.monitorRect;
|
|
s_StartRect=s_StartMenuParams.startButtonRect;
|
|
taskbarRect=s_StartMenuParams.taskbarRect;
|
|
}
|
|
else
|
|
{
|
|
s_bLockWorkArea=false;
|
|
MONITORINFO info={sizeof(info)};
|
|
GetMonitorInfo(s_MenuMonitor,&info);
|
|
s_TaskBarEdge=GetTaskbarPosition(s_TaskBar,NULL,NULL,&taskbarRect);
|
|
RECT rc=taskbarRect;
|
|
LOG_MENU(LOG_OPEN,L"Taskbar Rect: %d, %d, %d, %d",rc.left,rc.top,rc.right,rc.bottom);
|
|
{
|
|
RECT box;
|
|
if (::GetWindowRgnBox(s_TaskBar,&box))
|
|
{
|
|
LOG_MENU(LOG_OPEN,L"Taskbar Region: %d, %d, %d, %d",box.left,box.top,box.right,box.bottom);
|
|
::GetWindowRect(s_TaskBar,&rc);
|
|
OffsetRect(&box,rc.left,rc.top);
|
|
IntersectRect(&rc,&taskbarRect,&box);
|
|
}
|
|
}
|
|
switch (s_TaskBarEdge)
|
|
{
|
|
case ABE_LEFT: rc.right=info.rcWork.right; break;
|
|
case ABE_RIGHT: rc.left=info.rcWork.left; break;
|
|
case ABE_TOP: rc.bottom=info.rcWork.bottom; break;
|
|
case ABE_BOTTOM: rc.top=info.rcWork.top; break;
|
|
}
|
|
IntersectRect(&s_MenuLimits,&rc,&info.rcMonitor);
|
|
|
|
if (s_StartButton)
|
|
{
|
|
::GetWindowRect(s_StartButton,&s_StartRect);
|
|
}
|
|
else if (s_TaskBar)
|
|
{
|
|
// no start button. try to guess the rect
|
|
if (taskBar->oldButton)
|
|
{
|
|
::GetWindowRect(taskBar->oldButton,&s_StartRect);
|
|
}
|
|
else
|
|
{
|
|
s_StartRect=taskbarRect;
|
|
if (s_TaskBarEdge==ABE_LEFT || s_TaskBarEdge==ABE_RIGHT)
|
|
{
|
|
::GetWindowRect(taskBar->rebar,&rc);
|
|
s_StartRect.bottom=rc.top;
|
|
}
|
|
else if (::GetWindowLong(s_TaskBar,GWL_EXSTYLE)&WS_EX_LAYOUTRTL)
|
|
s_StartRect.left=s_StartRect.right-(s_StartRect.bottom-s_StartRect.top);
|
|
else
|
|
s_StartRect.right=s_StartRect.left+(s_StartRect.bottom-s_StartRect.top);
|
|
}
|
|
}
|
|
}
|
|
LOG_MENU(LOG_OPEN,L"Main Rect: %d, %d, %d, %d",s_MenuLimits.left,s_MenuLimits.top,s_MenuLimits.right,s_MenuLimits.bottom);
|
|
LOG_MENU(LOG_OPEN,L"Start Rect: %d, %d, %d, %d",s_StartRect.left,s_StartRect.top,s_StartRect.right,s_StartRect.bottom);
|
|
LOG_MENU(LOG_OPEN,L"Start Button: %08X",s_StartButton);
|
|
|
|
s_TipShowTime=400;
|
|
s_TipHideTime=4000;
|
|
CString delay=GetSettingString(L"InfotipDelay");
|
|
if (!delay.IsEmpty())
|
|
{
|
|
wchar_t token[256];
|
|
const wchar_t *str=GetToken(delay,token,_countof(token),L", \t");
|
|
int time=_wtol(token);
|
|
if (time>=0) s_TipShowTime=time;
|
|
str=GetToken(str,token,_countof(token),L", \t");
|
|
time=_wtol(token);
|
|
if (time>=0) s_TipHideTime=time;
|
|
}
|
|
if (s_TipShowTime>30000) s_TipShowTime=30000;
|
|
if (s_TipHideTime>30000) s_TipHideTime=30000;
|
|
|
|
s_TipHideTimeFolder=s_TipShowTimeFolder=0;
|
|
delay=GetSettingString(L"FolderInfotipDelay");
|
|
if (!delay.IsEmpty())
|
|
{
|
|
wchar_t token[256];
|
|
const wchar_t *str=GetToken(delay,token,_countof(token),L", \t");
|
|
int time=_wtol(token);
|
|
if (time>=0) s_TipShowTimeFolder=time;
|
|
str=GetToken(str,token,_countof(token),L", \t");
|
|
time=_wtol(token);
|
|
if (time>=0) s_TipHideTimeFolder=time;
|
|
}
|
|
if (s_TipShowTimeFolder>30000) s_TipShowTimeFolder=30000;
|
|
if (s_TipHideTimeFolder>30000) s_TipHideTimeFolder=30000;
|
|
|
|
DWORD animFlags=0;
|
|
{
|
|
int anim=GetSettingInt(bAllPrograms?L"SubMenuAnimation":L"MainMenuAnimation");
|
|
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;
|
|
}
|
|
|
|
s_Skin.Submenu_padding=s_Skin.Submenu_padding0;
|
|
s_Skin.Caption_padding=s_Skin.Caption_padding0;
|
|
s_Skin.Main_padding=s_Skin.Main_padding0;
|
|
s_Skin.Main2_padding=s_Skin.Main2_padding0;
|
|
s_Skin.Main_search_padding=s_Skin.Main_search_padding0;
|
|
s_Skin.Main_jump_padding=s_Skin.Main_jump_padding0;
|
|
|
|
{
|
|
RECT margin={0,0,0,0};
|
|
AdjustWindowRect(&margin,s_SubmenuStyle,FALSE);
|
|
s_Skin.Submenu_padding.left+=margin.left; if (s_Skin.Submenu_padding.left<0) s_Skin.Submenu_padding.left=0;
|
|
s_Skin.Submenu_padding.right-=margin.right; if (s_Skin.Submenu_padding.right<0) s_Skin.Submenu_padding.right=0;
|
|
s_Skin.Submenu_padding.top+=margin.top; if (s_Skin.Submenu_padding.top<0) s_Skin.Submenu_padding.top=0;
|
|
s_Skin.Submenu_padding.bottom-=margin.bottom; if (s_Skin.Submenu_padding.bottom<0) s_Skin.Submenu_padding.bottom=0;
|
|
}
|
|
|
|
POINT corner;
|
|
|
|
memset(&s_MainMenuLimits,0,sizeof(RECT));
|
|
if (bAllPrograms)
|
|
{
|
|
RECT rc;
|
|
if (!::GetWindowRect(g_ProgramsButton,&rc))
|
|
memset(&rc,0,sizeof(rc));
|
|
if (s_StartRect.right+s_StartRect.left<s_MenuLimits.left+s_MenuLimits.right)
|
|
{
|
|
// start button on the left
|
|
options|=CONTAINER_LEFT;
|
|
corner.x=rc.right-s_Skin.Submenu_padding.left+s_Skin.AllPrograms_offset;
|
|
s_bExpandRight=true;
|
|
}
|
|
else
|
|
{
|
|
// start button on the right
|
|
s_bExpandRight=false;
|
|
corner.x=rc.left+s_Skin.Submenu_padding.right-s_Skin.AllPrograms_offset;
|
|
}
|
|
corner.y=rc.bottom;
|
|
options|=CONTAINER_MULTICOLUMN|CONTAINER_MULTICOL_REC;
|
|
pStartMenu->m_Options=options;
|
|
s_MainMenuLimits=s_MenuLimits;
|
|
}
|
|
else
|
|
{
|
|
RECT margin={0,0,0,0};
|
|
AdjustWindowRect(&margin,dwStyle,FALSE);
|
|
if (s_Skin.Main_bitmap_slices_X[1]>0)
|
|
{
|
|
s_Skin.Caption_padding.left+=margin.left; if (s_Skin.Caption_padding.left<0) s_Skin.Caption_padding.left=0;
|
|
s_Skin.Caption_padding.top+=margin.top; if (s_Skin.Caption_padding.top<0) s_Skin.Caption_padding.top=0;
|
|
s_Skin.Caption_padding.bottom-=margin.bottom; if (s_Skin.Caption_padding.bottom<0) s_Skin.Caption_padding.bottom=0;
|
|
}
|
|
else
|
|
{
|
|
// no caption
|
|
s_Skin.Main_padding.left+=margin.left; if (s_Skin.Main_padding.left<0) s_Skin.Main_padding.left=0;
|
|
if (s_Skin.Main2_padding.left>=0)
|
|
{
|
|
s_Skin.Main2_padding.left+=margin.left; if (s_Skin.Main2_padding.left<0) s_Skin.Main2_padding.left=0;
|
|
}
|
|
}
|
|
s_Skin.Main_padding.right-=margin.right; if (s_Skin.Main_padding.right<0) s_Skin.Main_padding.right=0;
|
|
s_Skin.Main_padding.top+=margin.top; if (s_Skin.Main_padding.top<0) s_Skin.Main_padding.top=0;
|
|
s_Skin.Main_padding.bottom-=margin.bottom; if (s_Skin.Main_padding.bottom<0) s_Skin.Main_padding.bottom=0;
|
|
if (s_Skin.Main2_padding.left>=0)
|
|
{
|
|
s_Skin.Main2_padding.right-=margin.right; if (s_Skin.Main2_padding.right<0) s_Skin.Main2_padding.right=0;
|
|
s_Skin.Main2_padding.top+=margin.top; if (s_Skin.Main2_padding.top<0) s_Skin.Main2_padding.top=0;
|
|
s_Skin.Main2_padding.bottom-=margin.bottom; if (s_Skin.Main2_padding.bottom<0) s_Skin.Main2_padding.bottom=0;
|
|
}
|
|
if (s_bWin7Style)
|
|
{
|
|
s_Skin.Main_search_padding.left+=margin.left; if (s_Skin.Main_search_padding.left<0) s_Skin.Main_search_padding.left=0;
|
|
s_Skin.Main_search_padding.right-=margin.right; if (s_Skin.Main_search_padding.right<0) s_Skin.Main_search_padding.right=0;
|
|
s_Skin.Main_search_padding.top+=margin.top; if (s_Skin.Main_search_padding.top<0) s_Skin.Main_search_padding.top=0;
|
|
s_Skin.Main_search_padding.bottom-=margin.bottom; if (s_Skin.Main_search_padding.bottom<0) s_Skin.Main_search_padding.bottom=0;
|
|
|
|
s_Skin.Main_jump_padding.right-=margin.right; if (s_Skin.Main_jump_padding.right<0) s_Skin.Main_jump_padding.right=0;
|
|
s_Skin.Main_jump_padding.top+=margin.top; if (s_Skin.Main_jump_padding.top<0) s_Skin.Main_jump_padding.top=0;
|
|
s_Skin.Main_jump_padding.bottom-=margin.bottom; if (s_Skin.Main_jump_padding.bottom<0) s_Skin.Main_jump_padding.bottom=0;
|
|
}
|
|
|
|
if (!bTheme)
|
|
memset(&margin,0,sizeof(margin)); // in Classic mode don't offset the main menu by the border size
|
|
|
|
// determine options
|
|
if (s_TaskBarEdge==ABE_LEFT || s_TaskBarEdge==ABE_RIGHT || s_TaskBarEdge==ABE_TOP)
|
|
{
|
|
options|=CONTAINER_TOP;
|
|
animFlags|=AW_VER_POSITIVE;
|
|
}
|
|
else
|
|
{
|
|
animFlags|=AW_VER_NEGATIVE;
|
|
}
|
|
|
|
if (s_StartRect.right+s_StartRect.left<s_MenuLimits.left+s_MenuLimits.right)
|
|
{
|
|
// start button on the left
|
|
options|=CONTAINER_LEFT;
|
|
s_bExpandRight=true;
|
|
}
|
|
else
|
|
{
|
|
// start button on the right
|
|
s_bExpandRight=false;
|
|
}
|
|
|
|
if ((s_TaskBarEdge==ABE_LEFT || s_TaskBarEdge==ABE_RIGHT) && !GetSettingBool(L"ShowNextToTaskbar"))
|
|
s_bBehindTaskbar=false;
|
|
|
|
if (GetSettingBool(L"MainSortZA")) options|=CONTAINER_SORTZA;
|
|
if (GetSettingBool(L"MainSortOnce")) options|=CONTAINER_SORTONCE;
|
|
if (s_RecentPrograms!=RECENT_PROGRAMS_NONE && !(rootSettings&StdMenuItem::MENU_NORECENT))
|
|
options|=CONTAINER_RECENT;
|
|
pStartMenu->m_Options=options;
|
|
|
|
s_MainMenuLimits=pStartMenu->CalculateWorkArea(taskbarRect);
|
|
corner=pStartMenu->CalculateCorner();
|
|
}
|
|
|
|
// reposition start menu
|
|
if (bTopMost || !s_bBehindTaskbar)
|
|
animFlags|=AW_TOPMOST;
|
|
pStartMenu->SetWindowPos((animFlags&AW_TOPMOST)?HWND_TOPMOST:HWND_TOP,corner.x,corner.y,0,0,(initialMonitor!=s_MenuMonitor && !bAllPrograms)?SWP_NOMOVE|SWP_NOSIZE:0);
|
|
|
|
pStartMenu->InitItems();
|
|
pStartMenu->m_MaxWidth=s_MainMenuLimits.right-s_MainMenuLimits.left;
|
|
g_ItemManager.UpdateNewPrograms(CPoint((s_StartRect.left+s_StartRect.right)/2,(s_StartRect.top+s_StartRect.bottom)/2));
|
|
|
|
pStartMenu->InitWindow();
|
|
pStartMenu->SetHotItem((bKeyboard && bAllPrograms)?0:-1);
|
|
bool bTreeSelected=false;
|
|
if (s_bWin7Style && GetSettingInt(L"ProgramsStyle")==PROGRAMS_INLINE && GetSettingBool(L"OpenPrograms"))
|
|
{
|
|
pStartMenu->SetMenuMode(MODE_PROGRAMS);
|
|
if (pStartMenu->m_SearchIndex<0 || GetSettingInt(L"SearchBox")!=SEARCHBOX_NORMAL || !GetSettingBool(L"SearchSelect"))
|
|
{
|
|
bTreeSelected=true;
|
|
pStartMenu->SetHotItem(pStartMenu->m_ProgramTreeIndex,false,false);
|
|
}
|
|
}
|
|
|
|
if (bAllPrograms)
|
|
{
|
|
::InvalidateRect(g_ProgramsButton,NULL,TRUE);
|
|
::UpdateWindow(g_ProgramsButton);
|
|
}
|
|
|
|
BOOL animate;
|
|
if ((animFlags&(AW_BLEND|AW_SLIDE))==0)
|
|
animate=FALSE;
|
|
else
|
|
SystemParametersInfo(SPI_GETMENUANIMATION,NULL,&animate,0);
|
|
|
|
if (s_TaskBar && s_bBehindTaskbar)
|
|
::SetWindowPos(s_TaskBar,bTopMost?HWND_TOPMOST:HWND_TOP,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE); // bring the start button on top
|
|
|
|
int speed=0;
|
|
if (animate)
|
|
{
|
|
speed=GetSettingInt(bAllPrograms?L"SubMenuAnimationSpeed":L"MainMenuAnimationSpeed");
|
|
if (speed<=0) speed=MENU_ANIM_SPEED;
|
|
else if (speed>=10000) speed=10000;
|
|
}
|
|
{
|
|
RECT rc;
|
|
pStartMenu->GetWindowRect(&rc);
|
|
pStartMenu->AnimateMenu(animFlags,speed,rc);
|
|
}
|
|
|
|
s_bOverrideFirstDown=false;
|
|
if (pStartMenu->m_SearchIndex>=0 && GetSettingInt(L"SearchBox")==SEARCHBOX_NORMAL && GetSettingBool(L"SearchSelect"))
|
|
{
|
|
pStartMenu->ActivateItem(pStartMenu->m_SearchIndex,ACTIVATE_SELECT,NULL);
|
|
if (pStartMenu->m_bTwoColumns && pStartMenu->m_Items[pStartMenu->m_SearchIndex].column==0 && pStartMenu->m_SearchIndex+1<(int)pStartMenu->m_Items.size() && pStartMenu->m_Items[pStartMenu->m_SearchIndex+1].column==1)
|
|
s_bOverrideFirstDown=true;
|
|
}
|
|
else if (!bTreeSelected)
|
|
{
|
|
pStartMenu->SetFocus();
|
|
if (!bAllPrograms)
|
|
pStartMenu->SetHotItem(-1);
|
|
}
|
|
SetForegroundWindow(pStartMenu->m_hWnd);
|
|
SwitchToThisWindow(pStartMenu->m_hWnd,FALSE); // just in case
|
|
if (s_TaskBar && s_bBehindTaskbar)
|
|
{
|
|
// position the start button on top
|
|
if (s_StartButton)
|
|
::SetWindowPos(s_StartButton,bTopMost?HWND_TOPMOST:HWND_TOP,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
|
|
// position the start menu behind the taskbar
|
|
pStartMenu->SetWindowPos(s_TaskBar,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
|
|
}
|
|
if (bErr && GetSettingBool(L"ReportSkinErrors") && !*MenuSkin::s_SkinError)
|
|
{
|
|
Strcpy(MenuSkin::s_SkinError,_countof(MenuSkin::s_SkinError),LoadStringEx(IDS_SKIN_ERR_UNKNOWN));
|
|
}
|
|
if (*MenuSkin::s_SkinError && GetSettingBool(L"ReportSkinErrors") && s_StartButton)
|
|
{
|
|
Strcat(MenuSkin::s_SkinError,_countof(MenuSkin::s_SkinError),LoadStringEx(IDS_SKIN_ERR_DISABLE));
|
|
s_TooltipBalloon=CreateWindowEx(WS_EX_TOPMOST|WS_EX_TOOLWINDOW|(s_bRTL?WS_EX_LAYOUTRTL:0),TOOLTIPS_CLASS,NULL,WS_POPUP|TTS_BALLOON|TTS_CLOSE|TTS_NOPREFIX,0,0,0,0,pStartMenu->m_hWnd,NULL,g_Instance,NULL);
|
|
s_TooltipBalloon.SendMessage(TTM_SETMAXTIPWIDTH,0,500);
|
|
TOOLINFO tool={sizeof(tool),TTF_TRANSPARENT|TTF_TRACK|(s_bRTL?TTF_RTLREADING:0U)};
|
|
tool.uId=1;
|
|
tool.lpszText=MenuSkin::s_SkinError;
|
|
s_TooltipBalloon.SendMessage(TTM_ADDTOOL,0,(LPARAM)&tool);
|
|
if (bErr)
|
|
{
|
|
s_TooltipBalloon.SendMessage(TTM_SETTITLE,TTI_ERROR,(LPARAM)(const wchar_t*)LoadStringEx(IDS_SKIN_ERR));
|
|
}
|
|
else
|
|
{
|
|
s_TooltipBalloon.SendMessage(TTM_SETTITLE,TTI_WARNING,(LPARAM)(const wchar_t*)LoadStringEx(IDS_SKIN_WARN));
|
|
}
|
|
RECT rc;
|
|
::GetWindowRect(s_StartButton,&rc);
|
|
s_TooltipBalloon.SendMessage(TTM_TRACKPOSITION,0,MAKELONG((rc.left+rc.right)/2,(rc.top+rc.bottom)/2));
|
|
s_TooltipBalloon.SendMessage(TTM_TRACKACTIVATE,TRUE,(LPARAM)&tool);
|
|
pStartMenu->SetTimer(TIMER_BALLOON_HIDE,10000);
|
|
}
|
|
CheckForNewVersion(NULL,COMPONENT_MENU,CHECK_AUTO,NewVersionCallback);
|
|
|
|
return pStartMenu->m_hWnd;
|
|
}
|
|
|
|
bool CMenuContainer::ProcessMouseMessage( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
if (uMsg==WM_MOUSEMOVE)
|
|
{
|
|
if (!s_bAllPrograms)
|
|
return false;
|
|
if (hwnd && hwnd==g_ProgramsButton)
|
|
return true;
|
|
for (std::vector<CMenuContainer*>::const_iterator it=s_Menus.begin();it!=s_Menus.end();++it)
|
|
if ((*it)->m_hWnd==hwnd && (*it)->m_ContextItem<0)
|
|
{
|
|
(*it)->SendMessage(WM_MOUSEMOVE,wParam,lParam);
|
|
return true;
|
|
}
|
|
}
|
|
if (uMsg==WM_MOUSEHOVER)
|
|
{
|
|
if (hwnd && hwnd==g_ProgramsButton && GetSettingBool(L"CascadeAll"))
|
|
return true;
|
|
if (!s_bAllPrograms)
|
|
return false;
|
|
for (std::vector<CMenuContainer*>::const_iterator it=s_Menus.begin();it!=s_Menus.end();++it)
|
|
if ((*it)->m_hWnd==hwnd)
|
|
return false;
|
|
// if the mouse hovers over some window, close the menus
|
|
CloseSubMenus(0,NULL);
|
|
::ShowWindow(g_UserPic,SW_SHOW);
|
|
CPoint pt(GetMessagePos());
|
|
RECT rc;
|
|
::GetWindowRect(g_TopWin7Menu,&rc);
|
|
if (PtInRect(&rc,pt))
|
|
{
|
|
::ScreenToClient(g_TopWin7Menu,&pt);
|
|
::PostMessage(g_TopWin7Menu,WM_MOUSEMOVE,0,MAKELONG(pt.x,pt.y));
|
|
}
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Win7 stuff
|
|
void CMenuContainer::SetMenuMode( TMenuMode mode, bool bKeyboard )
|
|
{
|
|
if (mode==s_MenuMode) return;
|
|
InitializeOldState();
|
|
|
|
if (mode==MODE_SEARCH)
|
|
{
|
|
// switch to search - delete all additional items
|
|
ClearItems(m_Items.begin()+m_OriginalCount,m_Items.end());
|
|
}
|
|
if (s_MenuMode==MODE_SEARCH)
|
|
{
|
|
// switch from search - restore scroll count
|
|
m_ScrollCount=m_OriginalScrollCount;
|
|
}
|
|
|
|
s_MenuMode=mode;
|
|
|
|
s_bOverrideFirstDown=false;
|
|
if (s_OldMenuState.mode==MODE_PROGRAMS)
|
|
{
|
|
// hide programs tree
|
|
m_pProgramsTree->ShowWindow(SW_HIDE);
|
|
s_ProgramsScrollPos=m_pProgramsTree->GetScrollPos(SB_VERT);
|
|
}
|
|
|
|
if (s_MenuMode==MODE_JUMPLIST)
|
|
{
|
|
// from any to jumplist
|
|
InitWindow();
|
|
if (bKeyboard)
|
|
{
|
|
for (int i=m_OriginalCount;i<(int)m_Items.size();i++)
|
|
{
|
|
if (m_Items[i].jumpIndex>=0)
|
|
{
|
|
SetHotItem(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
SetHotItem(-1);
|
|
}
|
|
else if (s_MenuMode==MODE_SEARCH)
|
|
{
|
|
// from any to search
|
|
InitWindow();
|
|
s_SearchMenu=m_hWnd;
|
|
}
|
|
else if (s_OldMenuState.mode==MODE_JUMPLIST || s_OldMenuState.mode==MODE_SEARCH)
|
|
{
|
|
// from search and jumplist to program or normal
|
|
if (m_bRefreshItems)
|
|
InitItems();
|
|
else
|
|
ClearItems(m_Items.begin()+m_OriginalCount,m_Items.end());
|
|
s_JumpAppInfo=NULL;
|
|
int hotItem=m_HotItem;
|
|
InitWindow();
|
|
if (s_UserPicture.m_hWnd && s_UserPictureRect.top<s_UserPictureRect.bottom)
|
|
{
|
|
s_UserPicture.SetWindowPos(NULL,&s_UserPictureRect,SWP_NOZORDER|SWP_NOACTIVATE);
|
|
s_UserPicture.Update();
|
|
}
|
|
if (s_OldMenuState.mode==MODE_JUMPLIST && m_SubJumpItem!=-1)
|
|
{
|
|
if (bKeyboard || m_HotItem>=m_OriginalCount)
|
|
{
|
|
s_OldMenuState.hotItem=m_SubJumpItem;
|
|
s_OldMenuState.bHotArrow=true;
|
|
SetHotItem(m_SubJumpItem);
|
|
}
|
|
else
|
|
SetHotItem(hotItem);
|
|
}
|
|
m_SubJumpItem=-1;
|
|
s_SearchMenu=NULL;
|
|
}
|
|
else
|
|
{
|
|
InvalidateRect(&m_rContent);
|
|
}
|
|
|
|
if (s_MenuMode==MODE_PROGRAMS)
|
|
{
|
|
for (std::vector<CMenuContainer*>::reverse_iterator it=s_Menus.rbegin();*it!=this;++it)
|
|
if (!(*it)->m_bDestroyed)
|
|
(*it)->PostMessage(WM_CLOSE);
|
|
|
|
// initialize programs tree
|
|
MenuItem &item=m_Items[m_ProgramTreeIndex];
|
|
item.itemRect=m_rContent;
|
|
item.itemRect.bottom=m_Items[m_ProgramTreeIndex+1].itemRect.top;
|
|
bool bNewTree=!m_pProgramsTree;
|
|
if (bNewTree)
|
|
{
|
|
m_pProgramsTree=new CProgramsTree();
|
|
m_pProgramsTree->Create(this);
|
|
m_pProgramsTree->CreateItems();
|
|
}
|
|
SetHotItem(m_ProgramTreeIndex);
|
|
RECT rc;
|
|
m_pProgramsTree->GetWindowRect(&rc);
|
|
int dh=rc.bottom-rc.top;
|
|
m_pProgramsTree->GetClientRect(&rc);
|
|
dh-=rc.bottom;
|
|
int itemHeight=TreeView_GetItemHeight(m_pProgramsTree->m_hWnd);
|
|
rc=item.itemRect;
|
|
int h=rc.bottom-rc.top;
|
|
int n=(h-dh)/itemHeight;
|
|
rc.bottom=rc.top+n*itemHeight+dh;
|
|
m_pProgramsTree->SetWindowPos(NULL,&rc,SWP_NOZORDER|SWP_NOACTIVATE);
|
|
if (bNewTree)
|
|
{
|
|
for (int i=0;i<s_ProgramsScrollPos;i++)
|
|
m_pProgramsTree->SendMessage(WM_VSCROLL,SB_LINEDOWN); // using SetSrollPos doesn't quite work because the contents are not scrolled during WM_PRINT
|
|
}
|
|
|
|
ULONGLONG curTime;
|
|
GetSystemTimeAsFileTime((FILETIME*)&curTime);
|
|
CRegKey regKey;
|
|
if (regKey.Open(HKEY_CURRENT_USER,L"Software\\OpenShell\\StarMenu",KEY_WRITE)!=ERROR_SUCCESS)
|
|
regKey.Create(HKEY_CURRENT_USER,L"Software\\OpenShell\\StartMenu");
|
|
regKey.SetQWORDValue(L"LastProgramsTime",curTime);
|
|
if (s_OldMenuState.mode!=MODE_SEARCH)
|
|
m_pProgramsTree->SetFocus();
|
|
TreeView_SelectItem(m_pProgramsTree->m_hWnd,NULL);
|
|
}
|
|
|
|
if (m_Bitmap)
|
|
{
|
|
DeleteObject(m_Bitmap);
|
|
m_Bitmap=NULL;
|
|
}
|
|
if (s_UserPicture.m_hWnd && s_MenuMode!=MODE_NORMAL && s_MenuMode!=MODE_PROGRAMS)
|
|
s_UserPicture.SetWindowPos(NULL,0,0,0,0,SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE|SWP_HIDEWINDOW|SWP_NOACTIVATE);
|
|
if (!m_bClosing && s_Skin.Main_opacity!=MenuSkin::OPACITY_SOLID && GetSettingBool(L"MainMenuAnimate") && IsWindowVisible())
|
|
AnimateBackground();
|
|
else
|
|
{
|
|
int tw, th;
|
|
CreateBackground(s_BackgroundW1,s_BackgroundW2,s_BackgroundH1,s_BackgroundH2,tw,th,true);
|
|
OffsetRect(&m_rContent,m_BitmapOffset,0);
|
|
OffsetRect(&m_rContent2,m_BitmapOffset,0);
|
|
if (m_Region && !s_bRTL)
|
|
OffsetRgn(m_Region,m_BitmapOffset,0);
|
|
if (m_SearchBox.m_hWnd && m_SearchIndex>=0)
|
|
{
|
|
RECT itemRect;
|
|
GetItemRect(m_SearchIndex,itemRect);
|
|
itemRect.right-=(itemRect.bottom-itemRect.top);
|
|
if (!s_Skin.Search_frame)
|
|
InflateRect(&itemRect,-1,-3);
|
|
m_SearchBox.SetWindowPos(NULL,&itemRect,SWP_NOZORDER);
|
|
}
|
|
Invalidate();
|
|
ApplyRegion(TRUE);
|
|
}
|
|
|
|
if (s_MenuMode==MODE_PROGRAMS)
|
|
{
|
|
// show programs tree
|
|
m_pProgramsTree->ShowWindow(SW_SHOW);
|
|
if (s_OldMenuState.mode!=MODE_SEARCH)
|
|
m_pProgramsTree->SetFocus();
|
|
m_pProgramsTree->RedrawWindow();
|
|
}
|
|
if (s_UserPicture.m_hWnd && (s_MenuMode==MODE_NORMAL || s_MenuMode==MODE_PROGRAMS) && !m_bClosing && IsWindowVisible())
|
|
s_UserPicture.SetWindowPos(NULL,0,0,0,0,SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE|SWP_SHOWWINDOW|SWP_NOACTIVATE);
|
|
ClearOldState();
|
|
}
|
|
|
|
void CMenuContainer::AnimateBackground( void )
|
|
{
|
|
TMenuMode newMode=s_MenuMode;
|
|
int newHotItem=m_HotItem;
|
|
bool bNewHotArrow=m_bHotArrow;
|
|
int width1=s_OldMenuState.mode==MODE_JUMPLIST?s_MenuWidthJump:s_MenuWidthNormal;
|
|
int width2=s_MenuMode==MODE_JUMPLIST?s_MenuWidthJump:s_MenuWidthNormal;
|
|
|
|
int totalDW=width2-width1;
|
|
int totalDX=m_BitmapOffset-s_OldMenuState.bitmapOffset;
|
|
m_BitmapOffset=s_OldMenuState.bitmapOffset;
|
|
m_rMenu.left=m_BitmapOffset;
|
|
m_rMenu.right=m_rMenu.left+width1;
|
|
|
|
for (std::vector<MenuItem>::iterator it=m_Items.begin();it!=m_Items.end();++it)
|
|
{
|
|
if (it->column==1 && it->id!=MENU_SHUTDOWN_BUTTON)
|
|
it->itemRect.right-=totalDW;
|
|
OffsetRect(&it->itemRect,-totalDX,0);
|
|
}
|
|
|
|
LARGE_INTEGER time0;
|
|
QueryPerformanceCounter(&time0);
|
|
LARGE_INTEGER freq;
|
|
QueryPerformanceFrequency(&freq);
|
|
|
|
unsigned int *bits1=NULL, *bits2=NULL;
|
|
HBITMAP bitmap1=NULL, bitmap2=NULL;
|
|
|
|
int oldDW=0, oldDX=0;
|
|
HDC hDst=CreateCompatibleDC(NULL);
|
|
if (s_bRTL) SetLayout(hDst,LAYOUT_RTL);
|
|
HGDIOBJ bmp0=GetCurrentObject(hDst,OBJ_BITMAP);
|
|
int step=25;
|
|
for (s_OldMenuState.blend=step;s_OldMenuState.blend<100;s_OldMenuState.blend+=step)
|
|
{
|
|
int dx=(totalDX*s_OldMenuState.blend)/100;
|
|
int dw=(totalDW*s_OldMenuState.blend)/100;
|
|
|
|
int ddw=dw-oldDW; oldDW=dw;
|
|
int ddx=dx-oldDX; oldDX=dx;
|
|
|
|
for (std::vector<MenuItem>::iterator it=m_Items.begin();it!=m_Items.end();++it)
|
|
{
|
|
if (it->column==1 && it->id!=MENU_SHUTDOWN_BUTTON)
|
|
it->itemRect.right+=ddw;
|
|
OffsetRect(&it->itemRect,ddx,0);
|
|
}
|
|
|
|
for (std::vector<MenuItem>::iterator it=s_OldMenuState.items.begin();it!=s_OldMenuState.items.end();++it)
|
|
{
|
|
if (it->column==1 && it->id!=MENU_SHUTDOWN_BUTTON)
|
|
it->itemRect.right+=ddw;
|
|
OffsetRect(&it->itemRect,ddx,0);
|
|
}
|
|
|
|
if (ddx && s_MenuMode==MODE_PROGRAMS)
|
|
{
|
|
RECT rc;
|
|
m_pProgramsTree->GetWindowRect(&rc);
|
|
::MapWindowPoints(NULL,m_hWnd,(POINT*)&rc,2);
|
|
m_pProgramsTree->SetWindowPos(NULL,rc.left+ddx,rc.top,0,0,SWP_NOZORDER|SWP_NOSIZE);
|
|
}
|
|
if (m_SearchBox.m_hWnd && m_SearchIndex>=0)
|
|
{
|
|
RECT itemRect;
|
|
GetItemRect(m_SearchIndex,itemRect);
|
|
itemRect.right-=(itemRect.bottom-itemRect.top);
|
|
if (!s_Skin.Search_frame)
|
|
InflateRect(&itemRect,-1,-3);
|
|
m_SearchBox.SetWindowPos(NULL,&itemRect,SWP_NOZORDER);
|
|
}
|
|
|
|
m_BitmapOffset+=ddx;
|
|
m_rMenu.left=m_BitmapOffset;
|
|
m_rMenu.right=m_rMenu.left+width1+dw;
|
|
|
|
BITMAPINFO dib={sizeof(dib)};
|
|
dib.bmiHeader.biWidth=(m_rMenu.right-m_rMenu.left);
|
|
dib.bmiHeader.biHeight=-(m_rMenu.bottom-m_rMenu.top);
|
|
dib.bmiHeader.biPlanes=1;
|
|
dib.bmiHeader.biBitCount=32;
|
|
dib.bmiHeader.biCompression=BI_RGB;
|
|
|
|
// draw old menu
|
|
s_MenuMode=s_OldMenuState.mode;
|
|
m_HotItem=s_OldMenuState.hotItem;
|
|
m_bHotArrow=s_OldMenuState.bHotArrow;
|
|
m_Items.swap(s_OldMenuState.items);
|
|
|
|
int tw, th;
|
|
HBITMAP bmp1=bitmap1;
|
|
RECT rContentA1, rContentB1;
|
|
if (!bmp1)
|
|
{
|
|
Assert(!m_Bitmap);
|
|
CreateBackground(s_OldMenuState.w1,s_OldMenuState.w2+dw,s_OldMenuState.h1,s_OldMenuState.h2,tw,th,false);
|
|
Assert(tw==m_rMenu.right-m_rMenu.left && th==m_rMenu.bottom-m_rMenu.top);
|
|
rContentA1=m_rContent;
|
|
rContentB1=m_rContent2;
|
|
OffsetRect(&m_rContent,m_BitmapOffset,0);
|
|
OffsetRect(&m_rContent2,m_BitmapOffset,0);
|
|
|
|
bmp1=CreateDIBSection(hDst,&dib,DIB_RGB_COLORS,(void**)&bits1,NULL,0);
|
|
SelectObject(hDst,bmp1);
|
|
SetViewportOrgEx(hDst,-m_BitmapOffset,0,NULL);
|
|
DrawBackground(hDst,m_rMenu);
|
|
if (s_MenuMode==MODE_PROGRAMS)
|
|
{
|
|
RECT rc;
|
|
m_pProgramsTree->GetWindowRect(&rc);
|
|
::MapWindowPoints(NULL,m_hWnd,(POINT*)&rc,2);
|
|
SetViewportOrgEx(hDst,rc.left-m_BitmapOffset,rc.top,NULL);
|
|
m_pProgramsTree->GetClientRect(&rc);
|
|
m_pProgramsTree->DrawTree(hDst,rc);
|
|
m_pProgramsTree->Print(hDst,PRF_NONCLIENT);
|
|
}
|
|
if (m_Bitmap)
|
|
DeleteObject(m_Bitmap);
|
|
m_Bitmap=NULL;
|
|
SetViewportOrgEx(hDst,0,0,NULL);
|
|
SelectObject(hDst,bmp0);
|
|
if (totalDW==0)
|
|
bitmap1=bmp1;
|
|
}
|
|
else
|
|
{
|
|
CreateContentRects(s_OldMenuState.w1,s_OldMenuState.w2+dw,s_OldMenuState.h1,s_OldMenuState.h2,tw,th);
|
|
rContentA1=m_rContent;
|
|
rContentB1=m_rContent2;
|
|
OffsetRect(&m_rContent,m_BitmapOffset,0);
|
|
OffsetRect(&m_rContent2,m_BitmapOffset,0);
|
|
}
|
|
bool bOpaqueA1=(s_Skin.Main_opacity==MenuSkin::OPACITY_GLASS || s_Skin.Main_opacity==MenuSkin::OPACITY_ALPHA);
|
|
bool bOpaqueB1=(s_Skin.Main2_opacity==MenuSkin::OPACITY_GLASS || s_Skin.Main2_opacity==MenuSkin::OPACITY_ALPHA);
|
|
if (s_MenuMode==MODE_JUMPLIST)
|
|
bOpaqueB1=(s_Skin.Jumplist_opacity==MenuSkin::OPACITY_GLASS || s_Skin.Jumplist_opacity==MenuSkin::OPACITY_ALPHA);
|
|
|
|
// draw new menu
|
|
s_MenuMode=newMode;
|
|
m_HotItem=newHotItem;
|
|
m_bHotArrow=bNewHotArrow;
|
|
m_Items.swap(s_OldMenuState.items);
|
|
|
|
HBITMAP bmp2=bitmap2;
|
|
RECT rContentA2, rContentB2;
|
|
if (!bmp2)
|
|
{
|
|
if (s_BackgroundW2>0)
|
|
CreateBackground(s_BackgroundW1,s_BackgroundW2+dw-totalDW,s_BackgroundH1,s_BackgroundH2,tw,th,true);
|
|
else
|
|
CreateBackground(s_BackgroundW1+dw-totalDW,s_BackgroundW2,s_BackgroundH1,s_BackgroundH2,tw,th,true);
|
|
Assert(tw==m_rMenu.right-m_rMenu.left && th==m_rMenu.bottom-m_rMenu.top);
|
|
rContentA2=m_rContent;
|
|
rContentB2=m_rContent2;
|
|
OffsetRect(&m_rContent,m_BitmapOffset,0);
|
|
OffsetRect(&m_rContent2,m_BitmapOffset,0);
|
|
|
|
bmp2=CreateDIBSection(hDst,&dib,DIB_RGB_COLORS,(void**)&bits2,NULL,0);
|
|
SelectObject(hDst,bmp2);
|
|
SetViewportOrgEx(hDst,-m_BitmapOffset,0,NULL);
|
|
DrawBackground(hDst,m_rMenu);
|
|
if (s_MenuMode==MODE_PROGRAMS)
|
|
{
|
|
RECT rc;
|
|
m_pProgramsTree->GetWindowRect(&rc);
|
|
::MapWindowPoints(NULL,m_hWnd,(POINT*)&rc,2);
|
|
SetViewportOrgEx(hDst,rc.left-m_BitmapOffset,rc.top,NULL);
|
|
m_pProgramsTree->GetClientRect(&rc);
|
|
m_pProgramsTree->DrawTree(hDst,rc);
|
|
m_pProgramsTree->Print(hDst,PRF_NONCLIENT);
|
|
}
|
|
if (m_Bitmap)
|
|
DeleteObject(m_Bitmap);
|
|
m_Bitmap=NULL;
|
|
SetViewportOrgEx(hDst,0,0,NULL);
|
|
SelectObject(hDst,bmp0);
|
|
if (totalDW==0)
|
|
bitmap2=bmp2;
|
|
|
|
if (m_Region && !s_bRTL)
|
|
OffsetRgn(m_Region,m_BitmapOffset,0);
|
|
}
|
|
else
|
|
{
|
|
if (s_BackgroundW2>0)
|
|
CreateContentRects(s_BackgroundW1,s_BackgroundW2+dw-totalDW,s_BackgroundH1,s_BackgroundH2,tw,th);
|
|
else
|
|
CreateContentRects(s_BackgroundW1+dw-totalDW,s_BackgroundW2,s_BackgroundH1,s_BackgroundH2,tw,th);
|
|
rContentA2=m_rContent;
|
|
rContentB2=m_rContent2;
|
|
OffsetRect(&m_rContent,m_BitmapOffset,0);
|
|
OffsetRect(&m_rContent2,m_BitmapOffset,0);
|
|
}
|
|
|
|
bool bOpaqueA2=(s_Skin.Main_opacity==MenuSkin::OPACITY_GLASS || s_Skin.Main_opacity==MenuSkin::OPACITY_ALPHA);
|
|
bool bOpaqueB2=(s_Skin.Main2_opacity==MenuSkin::OPACITY_GLASS || s_Skin.Main2_opacity==MenuSkin::OPACITY_ALPHA);
|
|
if (s_MenuMode==MODE_JUMPLIST)
|
|
bOpaqueB2=(s_Skin.Jumplist_opacity==MenuSkin::OPACITY_GLASS || s_Skin.Jumplist_opacity==MenuSkin::OPACITY_ALPHA);
|
|
|
|
if (s_bRTL)
|
|
{
|
|
int q;
|
|
q=rContentA1.right;
|
|
rContentA1.right=dib.bmiHeader.biWidth-rContentA1.left;
|
|
rContentA1.left=dib.bmiHeader.biWidth-q;
|
|
q=rContentB1.right;
|
|
rContentB1.right=dib.bmiHeader.biWidth-rContentB1.left;
|
|
rContentB1.left=dib.bmiHeader.biWidth-q;
|
|
q=rContentA2.right;
|
|
rContentA2.right=dib.bmiHeader.biWidth-rContentA2.left;
|
|
rContentA2.left=dib.bmiHeader.biWidth-q;
|
|
q=rContentB2.right;
|
|
rContentB2.right=dib.bmiHeader.biWidth-rContentB2.left;
|
|
rContentB2.left=dib.bmiHeader.biWidth-q;
|
|
}
|
|
|
|
Assert(!m_Bitmap);
|
|
unsigned int *bits3;
|
|
m_Bitmap=CreateDIBSection(hDst,&dib,DIB_RGB_COLORS,(void**)&bits3,NULL,0);
|
|
|
|
// blend
|
|
int blend2=s_OldMenuState.blend;
|
|
int blend1=100-blend2;
|
|
for (int y=0,i=0;y<-dib.bmiHeader.biHeight;y++)
|
|
{
|
|
for (int x=0;x<dib.bmiHeader.biWidth;x++,i++)
|
|
{
|
|
unsigned int pixel1=bits1[i];
|
|
int r1=pixel1&255;
|
|
int g1=(pixel1>>8)&255;
|
|
int b1=(pixel1>>16)&255;
|
|
int a1=pixel1>>24;
|
|
if ((bOpaqueA1 && x>=rContentA1.left && x<rContentA1.right && y>=rContentA1.top && y<rContentA1.bottom) ||
|
|
(bOpaqueB1 && x>=rContentB1.left && x<rContentB1.right && y>=rContentB1.top && y<rContentB1.bottom))
|
|
a1=255;
|
|
|
|
unsigned int pixel2=bits2[i];
|
|
int r2=pixel2&255;
|
|
int g2=(pixel2>>8)&255;
|
|
int b2=(pixel2>>16)&255;
|
|
int a2=pixel2>>24;
|
|
if ((bOpaqueA2 && x>=rContentA2.left && x<rContentA2.right && y>=rContentA2.top && y<rContentA2.bottom) ||
|
|
(bOpaqueB2 && x>=rContentB2.left && x<rContentB2.right && y>=rContentB2.top && y<rContentB2.bottom))
|
|
a2=255;
|
|
|
|
r2=(r1*blend1+r2*blend2)/100;
|
|
g2=(g1*blend1+g2*blend2)/100;
|
|
b2=(b1*blend1+b2*blend2)/100;
|
|
a2=(a1*blend1+a2*blend2)/100;
|
|
bits3[i]=(a2<<24)|(b2<<16)|(g2<<8)|r2;
|
|
}
|
|
}
|
|
if (!bitmap1) DeleteObject(bmp1);
|
|
if (!bitmap2) DeleteObject(bmp2);
|
|
|
|
// draw
|
|
Invalidate();
|
|
ApplyRegion(TRUE);
|
|
UpdateWindow();
|
|
DeleteObject(m_Bitmap);
|
|
m_Bitmap=NULL;
|
|
|
|
LARGE_INTEGER time;
|
|
QueryPerformanceCounter(&time);
|
|
LONGLONG dt=(time.QuadPart-time0.QuadPart)*1000/freq.QuadPart;
|
|
if (dt<33)
|
|
Sleep(33-(int)dt);
|
|
time0=time;
|
|
}
|
|
SelectObject(hDst,bmp0);
|
|
DeleteDC(hDst);
|
|
if (bitmap1) DeleteObject(bitmap1);
|
|
if (bitmap2) DeleteObject(bitmap2);
|
|
|
|
int ddw=totalDW-oldDW;
|
|
int ddx=totalDX-oldDX;
|
|
for (std::vector<MenuItem>::iterator it=m_Items.begin();it!=m_Items.end();++it)
|
|
{
|
|
if (it->column==1 && it->id!=MENU_SHUTDOWN_BUTTON)
|
|
it->itemRect.right+=ddw;
|
|
OffsetRect(&it->itemRect,ddx,0);
|
|
}
|
|
if (ddx && s_MenuMode==MODE_PROGRAMS)
|
|
{
|
|
RECT rc;
|
|
m_pProgramsTree->GetWindowRect(&rc);
|
|
::MapWindowPoints(NULL,m_hWnd,(POINT*)&rc,2);
|
|
m_pProgramsTree->SetWindowPos(NULL,rc.left+ddx,rc.top,0,0,SWP_NOZORDER|SWP_NOSIZE);
|
|
}
|
|
if (m_SearchBox.m_hWnd && m_SearchIndex>=0)
|
|
{
|
|
RECT itemRect;
|
|
GetItemRect(m_SearchIndex,itemRect);
|
|
itemRect.right-=(itemRect.bottom-itemRect.top);
|
|
if (!s_Skin.Search_frame)
|
|
InflateRect(&itemRect,-1,-3);
|
|
m_SearchBox.SetWindowPos(NULL,&itemRect,SWP_NOZORDER);
|
|
}
|
|
|
|
m_BitmapOffset+=ddx;
|
|
m_rMenu.left=m_BitmapOffset;
|
|
m_rMenu.right=m_rMenu.left+width2;
|
|
int tw, th;
|
|
CreateBackground(s_BackgroundW1,s_BackgroundW2,s_BackgroundH1,s_BackgroundH2,tw,th,true);
|
|
OffsetRect(&m_rContent,m_BitmapOffset,0);
|
|
OffsetRect(&m_rContent2,m_BitmapOffset,0);
|
|
if (m_Region && !s_bRTL)
|
|
OffsetRgn(m_Region,m_BitmapOffset,0);
|
|
|
|
Invalidate();
|
|
ApplyRegion(TRUE);
|
|
}
|
|
|
|
void CMenuContainer::InitializeOldState( void )
|
|
{
|
|
s_OldMenuState.mode=s_MenuMode;
|
|
s_OldMenuState.w1=s_BackgroundW1;
|
|
s_OldMenuState.w2=s_BackgroundW2;
|
|
s_OldMenuState.h1=s_BackgroundH1;
|
|
s_OldMenuState.h2=s_BackgroundH2;
|
|
s_OldMenuState.bitmapOffset=m_BitmapOffset;
|
|
s_OldMenuState.hotItem=m_HotItem;
|
|
s_OldMenuState.bHotArrow=m_bHotArrow;
|
|
s_OldMenuState.items.resize(m_Items.size());
|
|
for (size_t i=0;i<m_Items.size();i++)
|
|
{
|
|
s_OldMenuState.items[i].id=m_Items[i].id;
|
|
s_OldMenuState.items[i].name=m_Items[i].name;
|
|
s_OldMenuState.items[i].pItemInfo=m_Items[i].pItemInfo;
|
|
s_OldMenuState.items[i].drawType=m_Items[i].drawType;
|
|
s_OldMenuState.items[i].column=m_Items[i].column;
|
|
s_OldMenuState.items[i].row=m_Items[i].row;
|
|
s_OldMenuState.items[i].itemRect=m_Items[i].itemRect;
|
|
s_OldMenuState.items[i].bFolder=m_Items[i].bFolder;
|
|
s_OldMenuState.items[i].bSplit=m_Items[i].bSplit;
|
|
s_OldMenuState.items[i].bNew=m_Items[i].bNew;
|
|
}
|
|
}
|
|
|
|
void CMenuContainer::ClearOldState( void )
|
|
{
|
|
s_OldMenuState.mode=MODE_UNKNOWN;
|
|
s_OldMenuState.items.clear();
|
|
}
|
|
|
|
void CMenuContainer::OpenJumpList( int index, bool bKeyboard )
|
|
{
|
|
if (s_MenuMode==MODE_JUMPLIST)
|
|
{
|
|
InitializeOldState();
|
|
}
|
|
|
|
ClearItems(m_Items.begin()+m_OriginalCount,m_Items.end());
|
|
Assert(m_Items[index].bHasJumpList);
|
|
s_JumpAppInfo=m_Items[index].pItemInfo;
|
|
m_SubJumpItem=index;
|
|
AddJumpListItems(m_Items);
|
|
UpdateAccelerators(m_OriginalCount,(int)m_Items.size());
|
|
|
|
// add jumplist contents
|
|
if (s_MenuMode==MODE_JUMPLIST)
|
|
{
|
|
InitWindow();
|
|
AnimateBackground();
|
|
ClearOldState();
|
|
if (bKeyboard)
|
|
{
|
|
for (int i=m_OriginalCount;i<(int)m_Items.size();i++)
|
|
{
|
|
if (m_Items[i].jumpIndex>=0)
|
|
{
|
|
SetHotItem(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
SetHotItem(-1);
|
|
}
|
|
else
|
|
SetMenuMode(MODE_JUMPLIST,bKeyboard);
|
|
}
|
|
|
|
void CMenuContainer::OpenSearchList( void )
|
|
{
|
|
s_PreSearchMenuMode=s_MenuMode==MODE_PROGRAMS?MODE_PROGRAMS:MODE_NORMAL;
|
|
SetMenuMode(MODE_SEARCH);
|
|
}
|