diff --git a/Src/StartMenu/StartMenuDLL/ItemManager.cpp b/Src/StartMenu/StartMenuDLL/ItemManager.cpp index 27b2d17ed..ce62d87e7 100644 --- a/Src/StartMenu/StartMenuDLL/ItemManager.cpp +++ b/Src/StartMenu/StartMenuDLL/ItemManager.cpp @@ -482,17 +482,23 @@ void CItemManager::LoadIconData::Init( void ) m_IconSizes[4]=LARGE_ICON_SIZE-2; m_IconSizes[5]=EXTRA_LARGE_ICON_SIZE-2; - for (int i=0;i<_countof(m_TempLists);i++) + if (FAILED(m_pFactory.CoCreateInstance(CLSID_WICImagingFactory))) + m_pFactory.CoCreateInstance(CLSID_WICImagingFactory1); +} + +IImageList2 *CItemManager::LoadIconData::GetTempList( int index ) +{ + if (!m_TempLists[index]) { - m_TempLists[i]=ImageList_Create(m_IconSizes[i],m_IconSizes[i],ILC_COLOR32,0,1); - if (m_TempLists[i]) + const int size=m_IconSizes[index]; + m_TempLists[index]=ImageList_Create(size,size,ILC_COLOR32,0,1); + if (m_TempLists[index]) { - ImageList_SetImageCount(m_TempLists[i],1); - HIMAGELIST_QueryInterface(m_TempLists[i],IID_IImageList2,(void**)&m_pTempLists[i]); + ImageList_SetImageCount(m_TempLists[index],1); + HIMAGELIST_QueryInterface(m_TempLists[index],IID_IImageList2,(void**)&m_pTempLists[index]); } } - if (FAILED(m_pFactory.CoCreateInstance(CLSID_WICImagingFactory))) - m_pFactory.CoCreateInstance(CLSID_WICImagingFactory1); + return m_pTempLists[index]; } void CItemManager::LoadIconData::Close( void ) @@ -502,6 +508,7 @@ void CItemManager::LoadIconData::Close( void ) m_pTempLists[i]=NULL; if (m_TempLists[i]) ImageList_Destroy(m_TempLists[i]); + m_TempLists[i]=NULL; } m_pFactory=NULL; } @@ -673,6 +680,11 @@ void CItemManager::Close( void ) } m_LoadingStage=LOAD_STOPPED; + // No worker can replace icons after the joins above. + for (HBITMAP bitmap : m_OldBitmaps) + DeleteObject(bitmap); + m_OldBitmaps.clear(); + for (std::multimap::const_iterator it=m_IconInfos.begin();it!=m_IconInfos.end();++it) { if (it->second.bitmap) @@ -1254,28 +1266,6 @@ void CItemManager::QueueItemInfo( ItemInfo *pInfo, int refreshFlags ) } } -void CItemManager::WaitForShortcuts( const POINT &balloonPos ) -{ - if (m_PreloadItemsThreadId) - { - if (WaitForSingleObject(m_DoneEvent,1000)!=WAIT_TIMEOUT) - return; - CWindow tooltip=CreateWindowEx(WS_EX_TOPMOST|WS_EX_TOOLWINDOW|(IsLanguageRTL()?WS_EX_LAYOUTRTL:0),TOOLTIPS_CLASS,NULL,WS_POPUP|TTS_BALLOON|TTS_NOPREFIX,0,0,0,0,NULL,NULL,g_Instance,NULL); - tooltip.SendMessage(TTM_SETMAXTIPWIDTH,0,500); - TOOLINFO tool={sizeof(tool),TTF_TRANSPARENT|TTF_TRACK|(IsLanguageRTL()?TTF_RTLREADING:0U)}; - tool.uId=1; - CString message=LoadStringEx(IDS_MENU_BUSY); - tool.lpszText=(LPWSTR)(const wchar_t*)message; - tooltip.SendMessage(TTM_ADDTOOL,0,(LPARAM)&tool); - tooltip.SendMessage(TTM_SETTITLE,TTI_INFO,(LPARAM)(const wchar_t*)LoadStringEx(IDS_APP_TITLE)); - tooltip.SendMessage(TTM_TRACKPOSITION,0,MAKELONG(balloonPos.x,balloonPos.y)); - tooltip.SendMessage(TTM_TRACKACTIVATE,TRUE,(LPARAM)&tool); - tooltip.SendMessage(TTM_UPDATE); - WaitForSingleObject(m_DoneEvent,INFINITE); - tooltip.DestroyWindow(); - } -} - bool CItemManager::IsTaskbarPinned( const wchar_t *appid ) { Assert(GetCurrentThreadId()==m_MainThreadId); @@ -1389,12 +1379,22 @@ bool CItemManager::IsPathUsed( CRegKey ®Key, const wchar_t *path, const FILET return false; } -void CItemManager::UpdateNewPrograms( const POINT &balloonPos ) +void CItemManager::ResetNewPrograms( void ) { Assert(GetCurrentThreadId()==m_MainThreadId); m_NewPrograms.clear(); m_NewProgramRoots.clear(); m_bHasNewPrograms[0]=m_bHasNewPrograms[1]=m_bHasNewApps[0]=m_bHasNewApps[1]=false; +} + +bool CItemManager::AreShortcutsReady( void ) const +{ + return !m_PreloadItemsThread || !m_DoneEvent || WaitForSingleObject(m_DoneEvent,0)!=WAIT_TIMEOUT; +} + +void CItemManager::UpdateNewPrograms( void ) +{ + ResetNewPrograms(); #ifdef FORCE_ALL_NEW m_bHasNewPrograms[0]=m_bHasNewPrograms[1]=m_bHasNewApps[0]=m_bHasNewApps[1]=true; #endif @@ -1456,7 +1456,6 @@ void CItemManager::UpdateNewPrograms( const POINT &balloonPos ) LONGLONG curTime; GetSystemTimeAsFileTime((FILETIME*)&curTime); - WaitForShortcuts(balloonPos); LARGE_INTEGER newestProgram={0}, newestApp={0}; { RWLock lock(this,true,RWLOCK_ITEMS); @@ -1596,7 +1595,7 @@ void CItemManager::UpdateNewPrograms( const POINT &balloonPos ) if (newestProgram.QuadPart || newestApp.QuadPart) { CRegKey regKey; - ULONGLONG val1, val2; + ULONGLONG val1=0, val2=0; if (regKey.Open(HKEY_CURRENT_USER,L"Software\\OpenShell\\StartMenu",KEY_READ)==ERROR_SUCCESS) { if (regKey.QueryQWORDValue(L"LastProgramsTime",val1)!=ERROR_SUCCESS) @@ -2207,9 +2206,9 @@ HICON CItemManager::LoadShellIcon( int index, int iconSize ) return NULL; HICON hIcon; - if (data.m_pTempLists[sizeIndex]) + if (IImageList2 *tempList=data.GetTempList(sizeIndex)) { - if (SUCCEEDED(data.m_pTempLists[sizeIndex]->ReplaceFromImageList(0,pImageList,index,NULL,0)) && SUCCEEDED(data.m_pTempLists[sizeIndex]->GetIcon(0,ILD_TRANSPARENT,&hIcon))) + if (SUCCEEDED(tempList->ReplaceFromImageList(0,pImageList,index,NULL,0)) && SUCCEEDED(tempList->GetIcon(0,ILD_TRANSPARENT,&hIcon))) { AddTrackedIcon(hIcon); return hIcon; @@ -2725,7 +2724,7 @@ void CItemManager::LoadFolderItems( IShellItem *pFolder, int refreshFlags, int l refreshFlags&=~INFO_ICON; CComPtr pChild; CAbsolutePidl childPidl; - while (enumerator.GetNext(pChild,childPidl)) + while (m_LoadingStage==LOAD_LOADING && enumerator.GetNext(pChild,childPidl)) { if (location==CItemManager::LOCATION_DESKTOP) { @@ -2944,7 +2943,7 @@ void CItemManager::PreloadItemsThread( void ) if (!FindNextChangeNotification(handles[dir])) ResetEvent(handles[dir]); // so we don't wake on this event again - Sleep(1000); // hopefully whatever file operation is in progress will finish in a second + if (WaitForSingleObject(m_ExitEvent,1000)!=WAIT_TIMEOUT) break; } for (int i=0;i1024*1024) return false; if (size>0) { PIDLIST_ABSOLUTE pidl=(PIDLIST_ABSOLUTE)CoTaskMemAlloc(size); @@ -3114,13 +3116,30 @@ static bool ReadCacheFile( HANDLE file, CAbsolutePidl &data, int size ) ILFree(pidl); return false; } - data.Attach(pidl); + // Validate the item lengths and the final zero before passing the list to the shell. + const BYTE *bytes=reinterpret_cast(pidl); + int offset=0; + while (size-offset>=sizeof(USHORT)) + { + USHORT itemSize; + memcpy(&itemSize,bytes+offset,sizeof(itemSize)); + if (!itemSize && size-offset==sizeof(USHORT)) + { + data.Attach(pidl); + return true; + } + if (itemSizesize-offset) break; + offset+=itemSize; + } + ILFree(pidl); + return false; } return true; } static bool ReadCacheFile( HANDLE file, CString &data, int len ) { + if (len<0 || len>32767) return false; if (len>0) { DWORD q; @@ -3134,10 +3153,13 @@ static bool ReadCacheFile( HANDLE file, CString &data, int len ) return true; } +static bool ValidCacheBitmapSize( int width, int height ) +{ + return width>0 && width<=1024 && height>0 && height<=1024; +} + static bool ReadCacheFile( HANDLE file, HDC hdc, HBITMAP &data, int width, int height ) { - std::vector bits(width*height); - if (bits.empty()) return false; BITMAPINFO bi={0}; bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth=width; @@ -3146,66 +3168,74 @@ static bool ReadCacheFile( HANDLE file, HDC hdc, HBITMAP &data, int width, int h bi.bmiHeader.biBitCount=32; DWORD q; int size=width*height*4; - if (!ReadFile(file,&bits[0],size,&q,NULL) || q!=size) - return false; unsigned int *pBits; data=CreateDIBSection(hdc,&bi,DIB_RGB_COLORS,(void**)&pBits,NULL,0); if (!data) return false; - memcpy(pBits,&bits[0],size); + if (!ReadFile(file,pBits,size,&q,NULL) || q!=size) + { + DeleteObject(data); + data=NULL; + return false; + } return true; } -static void WriteCacheFile( HANDLE file, DWORD data ) +class CacheWriter { - DWORD q; - WriteFile(file,&data,sizeof(data),&q,NULL); -} + HANDLE m_File; + bool m_Ok=true; -static void WriteCacheFile( HANDLE file, const IconData &data ) -{ - DWORD q; - WriteFile(file,&data,sizeof(data),&q,NULL); -} + void Write( const void *data, DWORD size ) + { + if (!m_Ok || !size) return; + DWORD written=0; + m_Ok=WriteFile(m_File,data,size,&written,NULL) && written==size; + } -static void WriteCacheFile( HANDLE file, const ItemData &data ) -{ - DWORD q; - WriteFile(file,&data,sizeof(data),&q,NULL); -} +public: + explicit CacheWriter( HANDLE file ) : m_File(file) {} -static void WriteCacheFile( HANDLE file, PIDLIST_ABSOLUTE data, int size ) -{ - if (size>0) + template void WriteValue( const T &data ) { - DWORD q; - WriteFile(file,data,size,&q,NULL); + Write(&data,sizeof(data)); } -} -static void WriteCacheFile( HANDLE file, const CString &data ) -{ - if (!data.IsEmpty()) + void WriteValue( const CString &data ) { - DWORD q; - WriteFile(file,(const wchar_t*)data,data.GetLength()*2,&q,NULL); + Write((const wchar_t*)data,data.GetLength()*sizeof(wchar_t)); } -} -static void WriteCacheFile( HANDLE file, HDC hdc, HBITMAP data, int width, int height ) -{ - std::vector bits(width*height); - if (bits.empty()) return; - BITMAPINFO bi={0}; - bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); - bi.bmiHeader.biWidth=width; - bi.bmiHeader.biHeight=height; - bi.bmiHeader.biPlanes=1; - bi.bmiHeader.biBitCount=32; - GetDIBits(hdc,data,0,height,&bits[0],&bi,DIB_RGB_COLORS); - DWORD q; - WriteFile(file,&bits[0],width*height*4,&q,NULL); -} + void WriteValue( PIDLIST_ABSOLUTE data, int size ) + { + Write(data,size); + } + + void WriteValue( HDC hdc, HBITMAP data, int width, int height ) + { + if (!m_Ok) return; + if (!hdc || !ValidCacheBitmapSize(width,height)) + { + m_Ok=false; + return; + } + std::vector bits(width*height); + BITMAPINFO bi={0}; + bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); + bi.bmiHeader.biWidth=width; + bi.bmiHeader.biHeight=height; + bi.bmiHeader.biPlanes=1; + bi.bmiHeader.biBitCount=32; + m_Ok=GetDIBits(hdc,data,0,height,bits.data(),&bi,DIB_RGB_COLORS)==height; + Write(bits.data(),width*height*sizeof(DWORD)); + } + + bool Finish( void ) + { + bool complete=m_Ok && FlushFileBuffers(m_File); + return CloseHandle(m_File) && complete; + } +}; bool CItemManager::CompareModuleTimeStamp( const CString &PATH, const FILETIME ×tamp, std::vector &modules ) { @@ -3282,6 +3312,11 @@ void CItemManager::LoadCacheFile( void ) bError=true; break; } + if (!ValidCacheBitmapSize(data.bitmapW,data.bitmapH)) + { + bError=true; + break; + } if (size1==SMALL_ICON_SIZE && size2==LARGE_ICON_SIZE && size3==EXTRA_LARGE_ICON_SIZE && CompareModuleTimeStamp(info.PATH,info.timestamp,modules)) { if (!ReadCacheFile(file,hdc,info.bitmap,data.bitmapW,data.bitmapH)) @@ -3367,21 +3402,26 @@ void CItemManager::LoadCacheFile( void ) tag=ReadCacheFile(file); } - if (tag=='BLAK') + if (!bError && tag=='BLAK') { - int count=ReadCacheFile(file); - for (int i=0;i::const_iterator it=m_IconInfos.begin();it!=m_IconInfos.end();++it) { @@ -3396,25 +3436,31 @@ void CItemManager::LoadCacheFile( void ) DWORD CALLBACK CItemManager::SaveCacheFileThread( void *param ) { CItemManager *pThis=(CItemManager*)param; - wchar_t path[_MAX_PATH]=L"%LOCALAPPDATA%\\OpenShell"; - DoEnvironmentSubst(path,_MAX_PATH); - SHCreateDirectory(NULL,path); - Strcat(path,_countof(path),L"\\DataCache.tmp"); - HANDLE file=CreateFile(path,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); - if (file==INVALID_HANDLE_VALUE) return 0; - - WriteCacheFile(file,'CLSH'); - WriteCacheFile(file,GetVersionEx(g_Instance)); - WriteCacheFile(file,CACHE_FILE_VERSION); - WriteCacheFile(file,SMALL_ICON_SIZE); - WriteCacheFile(file,LARGE_ICON_SIZE); - WriteCacheFile(file,EXTRA_LARGE_ICON_SIZE); + wchar_t directory[_MAX_PATH]=L"%LOCALAPPDATA%\\OpenShell"; + DoEnvironmentSubst(directory,_MAX_PATH); + SHCreateDirectory(NULL,directory); + wchar_t path[_MAX_PATH]; + if (!GetTempFileName(directory,L"OSC",0,path)) return 0; + HANDLE file=CreateFile(path,GENERIC_WRITE,0,NULL,TRUNCATE_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + if (file==INVALID_HANDLE_VALUE) + { + DeleteFile(path); + return 0; + } + + CacheWriter writer(file); + writer.WriteValue('CLSH'); + writer.WriteValue(GetVersionEx(g_Instance)); + writer.WriteValue(CACHE_FILE_VERSION); + writer.WriteValue(SMALL_ICON_SIZE); + writer.WriteValue(LARGE_ICON_SIZE); + writer.WriteValue(EXTRA_LARGE_ICON_SIZE); { wchar_t languages[100]; DWORD size=0; DWORD len=_countof(languages); GetUserPreferredUILanguages(MUI_LANGUAGE_ID,&size,languages,&len); - WriteCacheFile(file,CalcFNVHash(languages,len*2,FNV_HASH0)); + writer.WriteValue(CalcFNVHash(languages,len*2,FNV_HASH0)); } std::vector*> iconInfos; @@ -3422,7 +3468,7 @@ DWORD CALLBACK CItemManager::SaveCacheFileThread( void *param ) RWLock lock(pThis,false,RWLOCK_ICONS); for (std::multimap::const_iterator it=pThis->m_IconInfos.begin();it!=pThis->m_IconInfos.end();++it) { - if (!it->second.bTemp && !it->second.bMetro && !it->second.PATH.IsEmpty() && it->second.PATH[1]!='#' && it->first!=0) + if (!it->second.bTemp && !it->second.bMetro && it->second.PATH.GetLength()>1 && it->second.PATH[1]!='#' && it->first!=0) iconInfos.push_back(&*it); } } @@ -3454,15 +3500,15 @@ DWORD CALLBACK CItemManager::SaveCacheFileThread( void *param ) data.sizeType=(*it)->second.sizeType; data.timestamp=(*it)->second.timestamp; data.PATHLen=(*it)->second.PATH.GetLength(); - BITMAP bmp; + BITMAP bmp={0}; GetObject((*it)->second.bitmap,sizeof(bmp),&bmp); data.bitmapW=bmp.bmWidth; data.bitmapH=bmp.bmHeight; - WriteCacheFile(file,'ICON'); - WriteCacheFile(file,data); - WriteCacheFile(file,(*it)->second.PATH); - WriteCacheFile(file,hdc,(*it)->second.bitmap,data.bitmapW,data.bitmapH); + writer.WriteValue('ICON'); + writer.WriteValue(data); + writer.WriteValue((*it)->second.PATH); + writer.WriteValue(hdc,(*it)->second.bitmap,data.bitmapW,data.bitmapH); } DeleteDC(hdc); @@ -3513,35 +3559,37 @@ DWORD CALLBACK CItemManager::SaveCacheFileThread( void *param ) data.iconColor=(*it)->second.iconColor; data.iconIndex=(*it)->second.iconIndex; - WriteCacheFile(file,'ITEM'); - WriteCacheFile(file,data); - WriteCacheFile(file,(*it)->second.GetLatestPidl(),data.pidlSize); - WriteCacheFile(file,(*it)->second.path); - WriteCacheFile(file,(*it)->second.PATH); - WriteCacheFile(file,(*it)->second.targetPidl,data.targetPidlSize); - WriteCacheFile(file,(*it)->second.targetPATH); - WriteCacheFile(file,(*it)->second.appid); - WriteCacheFile(file,(*it)->second.metroName); - WriteCacheFile(file,(*it)->second.iconPath); + writer.WriteValue('ITEM'); + writer.WriteValue(data); + writer.WriteValue((*it)->second.GetLatestPidl(),data.pidlSize); + writer.WriteValue((*it)->second.path); + writer.WriteValue((*it)->second.PATH); + writer.WriteValue((*it)->second.targetPidl,data.targetPidlSize); + writer.WriteValue((*it)->second.targetPATH); + writer.WriteValue((*it)->second.appid); + writer.WriteValue((*it)->second.metroName); + writer.WriteValue((*it)->second.iconPath); if (log) fwprintf(log,L"0x%08X - %s\r\n",(*it)->first,(const wchar_t*)(*it)->second.PATH); } { - WriteCacheFile(file,'BLAK'); - WriteCacheFile(file,(DWORD)blackList.size()); + writer.WriteValue('BLAK'); + writer.WriteValue((DWORD)blackList.size()); for (std::vector::const_iterator it=blackList.begin();it!=blackList.end();++it) - WriteCacheFile(file,*it); + writer.WriteValue(*it); } if (log) fclose(log); - CloseHandle(file); + bool complete=writer.Finish(); wchar_t path2[_MAX_PATH]=L"%LOCALAPPDATA%\\OpenShell\\DataCache.db"; DoEnvironmentSubst(path2,_MAX_PATH); - MoveFileEx(path,path2,MOVEFILE_REPLACE_EXISTING); + if (!complete || !MoveFileEx(path,path2,MOVEFILE_REPLACE_EXISTING)) + DeleteFile(path); return 0; } void CItemManager::SaveCacheFile( void ) { + if (m_CacheCleared) return; #ifdef DISABLE_CACHE return; #endif @@ -3564,40 +3612,22 @@ void CItemManager::SaveCacheFile( void ) m_SaveCacheThread=CreateThread(NULL,0,SaveCacheFileThread,this,0,NULL); } -void CItemManager::ClearCache( void ) +bool CItemManager::ClearCache( void ) { - // The save thread keeps pointers to persistent cache entries while serializing them. - // Let it finish before clearing the containers those pointers refer to. - if (m_SaveCacheThread) - { - WaitForSingleObject(m_SaveCacheThread,INFINITE); - CloseHandle(m_SaveCacheThread); - m_SaveCacheThread=NULL; - } - - Lock cleanupLock(this,LOCK_CLEANUP); - RWLock itemLock(this,true,RWLOCK_ITEMS); - RWLock iconLock(this,true,RWLOCK_ICONS); - - wchar_t path[_MAX_PATH]=L"%LOCALAPPDATA%\\OpenShell\\DataCache.db"; - DoEnvironmentSubst(path,_MAX_PATH); - DeleteFile(path); - - m_BlackListInfos10.clear(); - m_ItemInfos.clear(); - for (std::multimap::const_iterator it=m_IconInfos.begin();it!=m_IconInfos.end();++it) + if (m_SaveCacheThread && WaitForSingleObject(m_SaveCacheThread,INFINITE)!=WAIT_OBJECT_0) + return false; + wchar_t path[_MAX_PATH]; + DWORD length=ExpandEnvironmentStrings(L"%LOCALAPPDATA%\\OpenShell\\DataCache.db",path,_countof(path)); + if (!length || length>_countof(path) || path[0]=='%') return false; + if (!DeleteFile(path)) { - if (it->second.bitmap) - DeleteObject(it->second.bitmap); + DWORD error=GetLastError(); + if (error!=ERROR_FILE_NOT_FOUND && error!=ERROR_PATH_NOT_FOUND) return false; } - m_IconInfos.clear(); - m_MetroItemInfos10.clear(); - CreateDefaultIcons(); - ItemInfo &item=m_ItemInfos.emplace(0,ItemInfo())->second; - item.bIconOnly=true; - item.smallIcon=m_DefaultSmallIcon; - item.largeIcon=m_DefaultLargeIcon; - item.extraLargeIcon=m_DefaultExtraLargeIcon; + // Menu items and workers may still reference the in-memory cache. + // Let the next launch rebuild it rather than saving these entries again. + m_CacheCleared=true; + return true; } int CItemManager::GetIconSize(TIconSizeType iconSizeType) const diff --git a/Src/StartMenu/StartMenuDLL/ItemManager.h b/Src/StartMenu/StartMenuDLL/ItemManager.h index e10775bdf..a8fbf2753 100644 --- a/Src/StartMenu/StartMenuDLL/ItemManager.h +++ b/Src/StartMenu/StartMenuDLL/ItemManager.h @@ -34,7 +34,7 @@ class CItemManager void ResetTempIcons( void ); void LoadCacheFile( void ); void SaveCacheFile( void ); - void ClearCache( void ); + bool ClearCache( void ); static int GetDPI( bool bOverride ) { return (bOverride && s_DPIOverride)?s_DPIOverride:s_DPI; } static bool GetDPIOverride( void ) { return s_DPIOverride!=0; } @@ -178,9 +178,10 @@ class CItemManager const ItemInfo* GetLinkIcon(IShellLink* link, TIconSizeType iconSizeType); const ItemInfo *GetMetroAppInfo10( const wchar_t *appid ); void UpdateItemInfo( const ItemInfo *pInfo, int refreshFlags, bool bHasWriteLock=false ); - void WaitForShortcuts( const POINT &balloonPos ); bool IsTaskbarPinned( const wchar_t *appid ); - void UpdateNewPrograms( const POINT &balloonPos ); + void ResetNewPrograms( void ); + bool AreShortcutsReady( void ) const; + void UpdateNewPrograms( void ); bool IsNewProgram( PIDLIST_ABSOLUTE pidl, bool bFolder, bool bMetroApp ); bool HasNewPrograms( bool bReal ) { return m_bHasNewPrograms[bReal?0:1]; } bool HasNewApps( bool bReal ) { return m_bHasNewApps[bReal?0:1]; } @@ -270,14 +271,16 @@ class CItemManager HANDLE m_PreloadItemsThread; HANDLE m_RefreshInfoThread; HANDLE m_SaveCacheThread; + bool m_CacheCleared=false; DWORD m_MainThreadId, m_PreloadItemsThreadId, m_RefreshInfoThreadId; // per-thread info used to load icons struct LoadIconData { int m_IconSizes[ICON_SIZE_COUNT]; - HIMAGELIST m_TempLists[ICON_SIZE_COUNT]; + HIMAGELIST m_TempLists[ICON_SIZE_COUNT]={}; CComPtr m_pTempLists[ICON_SIZE_COUNT]; + IImageList2 *GetTempList( int index ); CComPtr m_pFactory; void Init( void ); diff --git a/Src/StartMenu/StartMenuDLL/MenuContainer.cpp b/Src/StartMenu/StartMenuDLL/MenuContainer.cpp index 3337b66a8..0375cc542 100644 --- a/Src/StartMenu/StartMenuDLL/MenuContainer.cpp +++ b/Src/StartMenu/StartMenuDLL/MenuContainer.cpp @@ -2015,8 +2015,6 @@ void CMenuContainer::GetRecentPrograms( std::vector &items, int maxCou // 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++) { @@ -3284,22 +3282,8 @@ void CMenuContainer::InitWindowInternal( bool bDontShrink, const POINT &corner, if (column==1 && columnWidths.size()==1) columnWidths.push_back(0); } - if (item.id!=MENU_RECENT && !(m_Options&CONTAINER_SEARCH) && s_Skin.bHasNewItem && i=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 (i=WIN_VER_WIN8 && GetSettingBool(L"AllProgramsMetro") && g_ItemManager.HasNewApps(false)); + if (item.id==MENU_APPS) + return g_ItemManager.HasNewApps(false); + if (item.bFolder) + return (item.pItem1 && g_ItemManager.IsNewProgram(item.pItem1,true,false)) || + (item.pItem2 && g_ItemManager.IsNewProgram(item.pItem2,true,false)); + return item.pItemInfo && item.pItem1 && g_ItemManager.IsNewProgram(item.pItem1,false,item.bMetroApp); +} + +void CMenuContainer::RefreshNewPrograms( void ) +{ + for (int i=0;iIsWindow()) + m_pProgramsTree->RefreshNewPrograms(); + Invalidate(FALSE); +} + LRESULT CMenuContainer::OnTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { + if (wParam==TIMER_NEW_PROGRAMS) + { + if (!g_ItemManager.AreShortcutsReady()) return 0; + KillTimer(TIMER_NEW_PROGRAMS); + CComPtr keepAlive(static_cast(this)); + g_ItemManager.UpdateNewPrograms(); + if (!m_bDestroyed) + { + for (CMenuContainer *menu : s_Menus) + if (!menu->m_bDestroyed) menu->RefreshNewPrograms(); + } + return 0; + } + 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); @@ -8559,7 +8593,7 @@ HWND CMenuContainer::ToggleStartMenu( int taskbarId, bool bKeyboard, bool bAllPr 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)); + g_ItemManager.ResetNewPrograms(); pStartMenu->InitWindow(); pStartMenu->SetHotItem((bKeyboard && bAllPrograms)?0:-1); @@ -8615,6 +8649,8 @@ HWND CMenuContainer::ToggleStartMenu( int taskbarId, bool bKeyboard, bool bAllPr if (!bAllPrograms) pStartMenu->SetHotItem(-1); } + if (GetSettingBool(L"HighlightNew")) + pStartMenu->SetTimer(TIMER_NEW_PROGRAMS,100); SetForegroundWindow(pStartMenu->m_hWnd); SwitchToThisWindow(pStartMenu->m_hWnd,FALSE); // just in case if (s_TaskBar && s_bBehindTaskbar) diff --git a/Src/StartMenu/StartMenuDLL/MenuContainer.h b/Src/StartMenu/StartMenuDLL/MenuContainer.h index 057982104..08cba98f3 100644 --- a/Src/StartMenu/StartMenuDLL/MenuContainer.h +++ b/Src/StartMenu/StartMenuDLL/MenuContainer.h @@ -763,6 +763,7 @@ class CMenuContainer: public IDropTarget, public IFrameworkInputPaneHandler, pub TIMER_BALLOON_HIDE=6, TIMER_SEARCH=7, TIMER_DRAG=8, + TIMER_NEW_PROGRAMS=9, MCM_REFRESH=WM_USER+10, // posted to force the container to refresh its contents MCM_SETCONTEXTITEM=WM_USER+11, // sets the item for the context menu. wParam is the nameHash of the item @@ -801,6 +802,8 @@ class CMenuContainer: public IDropTarget, public IFrameworkInputPaneHandler, pub void InitItems( void ); bool InitSearchItems( void ); void InitWindow( bool bDontShrink=false ); + bool IsNewMenuItem( const MenuItem &item ) const; + void RefreshNewPrograms( void ); void InitWindowInternal( bool bDontShrink, const POINT &corner, RECT &menuRect ); void InitWindowFinalize( const RECT &menuRect ); diff --git a/Src/StartMenu/StartMenuDLL/ProgramsTree.cpp b/Src/StartMenu/StartMenuDLL/ProgramsTree.cpp index 2e55c32b5..1f3af87c0 100644 --- a/Src/StartMenu/StartMenuDLL/ProgramsTree.cpp +++ b/Src/StartMenu/StartMenuDLL/ProgramsTree.cpp @@ -22,6 +22,32 @@ bool CProgramsTree::s_bFoldersFirst; const wchar_t *ORDER_PREFIX=L"#"; +void CProgramsTree::RefreshNewPrograms( void ) +{ + for (HTREEITEM node=TreeView_GetRoot(m_hWnd);node;) + { + TVITEM item={TVIF_PARAM}; + item.hItem=node; + if (TreeView_GetItem(m_hWnd,&item) && item.lParam) + { + CTreeItem *data=reinterpret_cast(item.lParam); + data->bNew=data->bApps?g_ItemManager.HasNewApps(false): + (data->pItemInfo1 && g_ItemManager.IsNewProgram(data->pItemInfo1->GetPidl(),data->bFolder,data->bApp)) || + (data->pItemInfo2 && g_ItemManager.IsNewProgram(data->pItemInfo2->GetPidl(),data->bFolder,false)); + } + HTREEITEM child=TreeView_GetChild(m_hWnd,node); + if (child) + node=child; + else + { + while (node && !TreeView_GetNextSibling(m_hWnd,node)) + node=TreeView_GetParent(m_hWnd,node); + if (node) node=TreeView_GetNextSibling(m_hWnd,node); + } + } + Invalidate(FALSE); +} + CProgramsTree::CProgramsTree( void ) { m_RefCount=1; diff --git a/Src/StartMenu/StartMenuDLL/ProgramsTree.h b/Src/StartMenu/StartMenuDLL/ProgramsTree.h index 6abb77bc2..a63f69f7d 100644 --- a/Src/StartMenu/StartMenuDLL/ProgramsTree.h +++ b/Src/StartMenu/StartMenuDLL/ProgramsTree.h @@ -93,6 +93,7 @@ class CProgramsTree: public IDropTarget, public CWindowImpl Assert(m_RefCount==0); } void Create( CMenuContainer *pOwner ); + void RefreshNewPrograms( void ); virtual WNDPROC GetWindowProc( void ) { return CustomWindowProc; } static LRESULT CALLBACK CustomWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); diff --git a/Src/StartMenu/StartMenuDLL/SearchManager.cpp b/Src/StartMenu/StartMenuDLL/SearchManager.cpp index 037794941..455687163 100644 --- a/Src/StartMenu/StartMenuDLL/SearchManager.cpp +++ b/Src/StartMenu/StartMenuDLL/SearchManager.cpp @@ -58,8 +58,11 @@ void CSearchManager::Init( void ) InitializeCriticalSection(&m_CriticalSections[i]); m_SearchEvent=CreateEvent(NULL,FALSE,FALSE,NULL); m_ExitEvent=CreateEvent(NULL,TRUE,FALSE,NULL); - for (int i=0;i<_countof(m_SearchThreads);i++) - m_SearchThreads[i]=CreateThread(NULL,0,StaticSearchThread,this,0,NULL); + if (m_SearchEvent && m_ExitEvent) + { + for (int i=0;i<_countof(m_SearchThreads);i++) + m_SearchThreads[i]=CreateThread(NULL,0,StaticSearchThread,this,0,NULL); + } m_MainThreadId=GetCurrentThreadId(); LoadItemRanks(); } @@ -67,11 +70,17 @@ void CSearchManager::Init( void ) void CSearchManager::Close( void ) { if (!m_bInitialized) return; - SetEvent(m_ExitEvent); - WaitForMultipleObjects(_countof(m_SearchThreads),m_SearchThreads,TRUE,INFINITE); - CloseHandle(m_SearchEvent); - for (int i=0;i<_countof(m_SearchThreads);i++) - CloseHandle(m_SearchThreads[i]); + if (m_ExitEvent) SetEvent(m_ExitEvent); + for (HANDLE &thread : m_SearchThreads) + { + if (!thread) continue; + WaitForSingleObject(thread,INFINITE); + CloseHandle(thread); + thread=NULL; + } + if (m_SearchEvent) CloseHandle(m_SearchEvent); + if (m_ExitEvent) CloseHandle(m_ExitEvent); + m_SearchEvent=m_ExitEvent=NULL; for (int i=0;i