mirror of
https://github.com/Open-Shell/Open-Shell-Menu.git
synced 2026-10-09 21:21:14 +11:00
Compare commits
9
Commits
da73edf4ea
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e1fe220d18 | ||
|
|
a43cf39441 | ||
|
|
93db2153c0 | ||
|
|
88e8cd8653 | ||
|
|
ef61ce1dc0 | ||
|
|
2e2f681c5b | ||
|
|
523ff4b9f4 | ||
|
|
1e7a52a5ab | ||
|
|
1384d4eb04 |
@@ -135,6 +135,8 @@ int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpstrC
|
|||||||
FARPROC proc=GetProcAddress(dll,"ShowExplorerSettings");
|
FARPROC proc=GetProcAddress(dll,"ShowExplorerSettings");
|
||||||
if (!proc) return 2;
|
if (!proc) return 2;
|
||||||
|
|
||||||
|
HRESULT comResult=CoInitialize(NULL);
|
||||||
proc();
|
proc();
|
||||||
|
if (SUCCEEDED(comResult)) CoUninitialize();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -252,6 +252,8 @@ int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HRESULT comResult=CoInitialize(NULL);
|
||||||
ShowIESettings();
|
ShowIESettings();
|
||||||
|
if (SUCCEEDED(comResult)) CoUninitialize();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -70,7 +70,7 @@ BEGIN
|
|||||||
EDITTEXT IDC_EDITSEARCH,22,7,120,12,ES_AUTOHSCROLL
|
EDITTEXT IDC_EDITSEARCH,22,7,120,12,ES_AUTOHSCROLL
|
||||||
CONTROL "Show all settings",IDC_CHECKALL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,7,79,12
|
CONTROL "Show all settings",IDC_CHECKALL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,7,79,12
|
||||||
CONTROL "<a>Help...</a>",IDC_LINKHELP,"SysLink",WS_TABSTOP,348,9,26,10,WS_EX_TRANSPARENT
|
CONTROL "<a>Help...</a>",IDC_LINKHELP,"SysLink",WS_TABSTOP,348,9,26,10,WS_EX_TRANSPARENT
|
||||||
CONTROL "",IDC_TABSETTINGS,"SysTabControl32",TCS_MULTILINE | TCS_FOCUSNEVER,7,20,367,169
|
CONTROL "",IDC_TABSETTINGS,"SysTabControl32",TCS_MULTILINE | WS_TABSTOP,7,20,367,169
|
||||||
CONTROL "<a>Open-Shell Homepage</a>",IDC_LINKWEB,"SysLink",WS_TABSTOP,7,195,75,10,WS_EX_TRANSPARENT
|
CONTROL "<a>Open-Shell Homepage</a>",IDC_LINKWEB,"SysLink",WS_TABSTOP,7,195,75,10,WS_EX_TRANSPARENT
|
||||||
CONTROL "Name of translator goes <a href=""http://www.yoursite.com"">here</a>",IDC_SYSLINKLOC,
|
CONTROL "Name of translator goes <a href=""http://www.yoursite.com"">here</a>",IDC_SYSLINKLOC,
|
||||||
"SysLink",NOT WS_VISIBLE | WS_TABSTOP,80,195,111,10
|
"SysLink",NOT WS_VISIBLE | WS_TABSTOP,80,195,111,10
|
||||||
@@ -282,7 +282,9 @@ END
|
|||||||
|
|
||||||
STRINGTABLE
|
STRINGTABLE
|
||||||
BEGIN
|
BEGIN
|
||||||
IDS_INITIATE_FAIL "Failed to initiate the download."
|
IDS_SETTINGS_PAGES "Settings pages"
|
||||||
|
IDS_SETTING_MODIFIED "modified"
|
||||||
|
IDS_INITIATE_FAIL "Failed to initiate the download."
|
||||||
IDS_UPDATE_TITLE "Open-Shell Update"
|
IDS_UPDATE_TITLE "Open-Shell Update"
|
||||||
IDS_INST_DOWNLOAD_FAIL "Failed to download the new version."
|
IDS_INST_DOWNLOAD_FAIL "Failed to download the new version."
|
||||||
IDS_INST_SAVE_FAIL "Failed to save file '%s'."
|
IDS_INST_SAVE_FAIL "Failed to save file '%s'."
|
||||||
|
|||||||
+81
-11
@@ -1110,6 +1110,7 @@ class CSettingsDlg: public CResizeableDlg<CSettingsDlg>
|
|||||||
public:
|
public:
|
||||||
CSettingsDlg( void );
|
CSettingsDlg( void );
|
||||||
void Init( CSetting *pSettings, ICustomSettings *pCustom, int tab, const wchar_t* appId );
|
void Init( CSetting *pSettings, ICustomSettings *pCustom, int tab, const wchar_t* appId );
|
||||||
|
bool NavigateTab( bool bPrevious );
|
||||||
|
|
||||||
BEGIN_MSG_MAP( CSettingsDlg )
|
BEGIN_MSG_MAP( CSettingsDlg )
|
||||||
MESSAGE_HANDLER( WM_INITDIALOG, OnInitDialog )
|
MESSAGE_HANDLER( WM_INITDIALOG, OnInitDialog )
|
||||||
@@ -1186,7 +1187,7 @@ private:
|
|||||||
const wchar_t* m_AppId;
|
const wchar_t* m_AppId;
|
||||||
|
|
||||||
void AddTabs( int name, const CSetting *pSelect=NULL );
|
void AddTabs( int name, const CSetting *pSelect=NULL );
|
||||||
void SetCurTab( int index, bool bReset, const CSetting *pSelect=NULL );
|
void SetCurTab( int index, bool bReset, const CSetting *pSelect=NULL, bool bFocusPanel=true );
|
||||||
bool IsTabValid( void );
|
bool IsTabValid( void );
|
||||||
void StorePlacement( void );
|
void StorePlacement( void );
|
||||||
|
|
||||||
@@ -1312,6 +1313,7 @@ LRESULT CSettingsDlg::OnInitDialog( UINT uMsg, WPARAM wParam, LPARAM lParam, BOO
|
|||||||
icon=(HICON)LoadImage(GetModuleHandle(L"shell32.dll"),MAKEINTRESOURCE(323),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),LR_DEFAULTCOLOR);
|
icon=(HICON)LoadImage(GetModuleHandle(L"shell32.dll"),MAKEINTRESOURCE(323),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),LR_DEFAULTCOLOR);
|
||||||
SendDlgItemMessage(IDC_ICONSEARCH,STM_SETICON,(WPARAM)icon);
|
SendDlgItemMessage(IDC_ICONSEARCH,STM_SETICON,(WPARAM)icon);
|
||||||
SendDlgItemMessage(IDC_EDITSEARCH,EM_SETCUEBANNER,FALSE,(LPARAM)(const wchar_t*)LoadStringEx(IDS_SEARCH_PROMPT));
|
SendDlgItemMessage(IDC_EDITSEARCH,EM_SETCUEBANNER,FALSE,(LPARAM)(const wchar_t*)LoadStringEx(IDS_SEARCH_PROMPT));
|
||||||
|
SetControlAccessibleName(GetDlgItem(IDC_EDITSEARCH),LoadStringEx(IDS_SEARCH_PROMPT));
|
||||||
SetWindowSubclass(GetDlgItem(IDC_EDITSEARCH),SubclassSearchBoxProc,'CLSH',0);
|
SetWindowSubclass(GetDlgItem(IDC_EDITSEARCH),SubclassSearchBoxProc,'CLSH',0);
|
||||||
|
|
||||||
CWindow tooltip;
|
CWindow tooltip;
|
||||||
@@ -1364,6 +1366,7 @@ LRESULT CSettingsDlg::OnInitDialog( UINT uMsg, WPARAM wParam, LPARAM lParam, BOO
|
|||||||
|
|
||||||
SIZE maxSize={0,0};
|
SIZE maxSize={0,0};
|
||||||
m_Tabs=GetDlgItem(IDC_TABSETTINGS);
|
m_Tabs=GetDlgItem(IDC_TABSETTINGS);
|
||||||
|
m_Tabs.SetWindowText(LoadStringEx(IDS_SETTINGS_PAGES));
|
||||||
m_Panel=NULL;
|
m_Panel=NULL;
|
||||||
int idx=0;
|
int idx=0;
|
||||||
for (const CSetting *pSetting=m_pSettings;pSetting->name;pSetting++)
|
for (const CSetting *pSetting=m_pSettings;pSetting->name;pSetting++)
|
||||||
@@ -1418,7 +1421,8 @@ LRESULT CSettingsDlg::OnInitDialog( UINT uMsg, WPARAM wParam, LPARAM lParam, BOO
|
|||||||
ShowWindow(SW_MAXIMIZE);
|
ShowWindow(SW_MAXIMIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
GetDlgItem(IDC_BUTTONBACKUP).SetFocus();
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT CSettingsDlg::OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
LRESULT CSettingsDlg::OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
||||||
@@ -1477,6 +1481,14 @@ void CSettingsDlg::AddTabs( int name, const CSetting *pSelect )
|
|||||||
if (pSetting->nameID==name)
|
if (pSetting->nameID==name)
|
||||||
idx=i;
|
idx=i;
|
||||||
}
|
}
|
||||||
|
int tabCount=TabCtrl_GetItemCount(m_Tabs);
|
||||||
|
LONG_PTR tabStyle=m_Tabs.GetWindowLongPtr(GWL_STYLE);
|
||||||
|
if (tabCount<=1)
|
||||||
|
tabStyle=(tabStyle&~WS_TABSTOP)|TCS_FOCUSNEVER;
|
||||||
|
else
|
||||||
|
tabStyle=(tabStyle|WS_TABSTOP)&~TCS_FOCUSNEVER;
|
||||||
|
m_Tabs.SetWindowLongPtr(GWL_STYLE,tabStyle);
|
||||||
|
m_Tabs.SetWindowPos(NULL,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_FRAMECHANGED);
|
||||||
m_Index=-1;
|
m_Index=-1;
|
||||||
TabCtrl_SetCurSel(m_Tabs,idx);
|
TabCtrl_SetCurSel(m_Tabs,idx);
|
||||||
m_Tabs.InvalidateRect(NULL);
|
m_Tabs.InvalidateRect(NULL);
|
||||||
@@ -1499,20 +1511,23 @@ LRESULT CSettingsDlg::OnKeyDown( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&
|
|||||||
if (wParam==VK_TAB && GetKeyState(VK_CONTROL)<0)
|
if (wParam==VK_TAB && GetKeyState(VK_CONTROL)<0)
|
||||||
{
|
{
|
||||||
int sel=TabCtrl_GetCurSel(m_Tabs);
|
int sel=TabCtrl_GetCurSel(m_Tabs);
|
||||||
|
int count=TabCtrl_GetItemCount(m_Tabs);
|
||||||
if (GetKeyState(VK_SHIFT)<0)
|
if (GetKeyState(VK_SHIFT)<0)
|
||||||
{
|
{
|
||||||
if (sel>0)
|
if (count>0)
|
||||||
{
|
{
|
||||||
TabCtrl_SetCurSel(m_Tabs,sel-1);
|
int next=(sel+count-1)%count;
|
||||||
SetCurTab(sel-1,false);
|
TabCtrl_SetCurSel(m_Tabs,next);
|
||||||
|
SetCurTab(next,false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (sel<TabCtrl_GetItemCount(m_Tabs)-1)
|
if (count>0)
|
||||||
{
|
{
|
||||||
TabCtrl_SetCurSel(m_Tabs,sel+1);
|
int next=(sel+1)%count;
|
||||||
SetCurTab(sel+1,false);
|
TabCtrl_SetCurSel(m_Tabs,next);
|
||||||
|
SetCurTab(next,false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1740,6 +1755,7 @@ LRESULT CSettingsDlg::OnCheckAll( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL
|
|||||||
{
|
{
|
||||||
m_bBasic=bBasic;
|
m_bBasic=bBasic;
|
||||||
AddTabs(-1);
|
AddTabs(-1);
|
||||||
|
::SetFocus(hWndCtl);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1758,7 +1774,7 @@ LRESULT CSettingsDlg::OnSearchChange( WORD wNotifyCode, WORD wID, HWND hWndCtl,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSettingsDlg::SetCurTab( int index, bool bReset, const CSetting *pSelect )
|
void CSettingsDlg::SetCurTab( int index, bool bReset, const CSetting *pSelect, bool bFocusPanel )
|
||||||
{
|
{
|
||||||
if (m_Index==index && !bReset) return;
|
if (m_Index==index && !bReset) return;
|
||||||
m_Index=index;
|
m_Index=index;
|
||||||
@@ -1778,12 +1794,59 @@ void CSettingsDlg::SetCurTab( int index, bool bReset, const CSetting *pSelect )
|
|||||||
::MapWindowPoints(NULL,m_hWnd,(POINT*)&rc,2);
|
::MapWindowPoints(NULL,m_hWnd,(POINT*)&rc,2);
|
||||||
TabCtrl_AdjustRect(m_Tabs,FALSE,&rc);
|
TabCtrl_AdjustRect(m_Tabs,FALSE,&rc);
|
||||||
HWND hwnd=pPanel->Activate(pGroup,rc,bReset);
|
HWND hwnd=pPanel->Activate(pGroup,rc,bReset);
|
||||||
|
CString pageTitle=LoadStringEx(pGroup->nameID);
|
||||||
|
::SetWindowText(hwnd,pageTitle);
|
||||||
if (hwnd!=m_Panel)
|
if (hwnd!=m_Panel)
|
||||||
{
|
{
|
||||||
if (m_Panel) ::ShowWindow(m_Panel,SW_HIDE);
|
if (m_Panel) ::ShowWindow(m_Panel,SW_HIDE);
|
||||||
m_Panel=hwnd;
|
m_Panel=hwnd;
|
||||||
::SetFocus(m_Panel);
|
|
||||||
}
|
}
|
||||||
|
if (bFocusPanel) ::SetFocus(m_Panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CSettingsDlg::NavigateTab( bool bPrevious )
|
||||||
|
{
|
||||||
|
HWND focus=::GetFocus();
|
||||||
|
HWND firstPanel=m_Panel?::GetNextDlgTabItem(m_Panel,NULL,FALSE):NULL;
|
||||||
|
HWND lastPanel=m_Panel?::GetNextDlgTabItem(m_Panel,NULL,TRUE):NULL;
|
||||||
|
HWND targets[]={
|
||||||
|
GetDlgItem(IDC_BUTTONBACKUP),
|
||||||
|
GetDlgItem(IDC_CHECKALL),
|
||||||
|
GetDlgItem(IDC_EDITSEARCH),
|
||||||
|
GetDlgItem(IDC_TABSETTINGS),
|
||||||
|
firstPanel,
|
||||||
|
GetDlgItem(IDOK),
|
||||||
|
GetDlgItem(IDCANCEL),
|
||||||
|
GetDlgItem(IDC_LINKHELP),
|
||||||
|
GetDlgItem(IDC_LINKWEB),
|
||||||
|
};
|
||||||
|
|
||||||
|
int current=-1;
|
||||||
|
if (m_Panel && (focus==m_Panel || ::IsChild(m_Panel,focus)))
|
||||||
|
{
|
||||||
|
HWND next=::GetNextDlgTabItem(m_Panel,focus,bPrevious);
|
||||||
|
HWND wrapped=bPrevious?lastPanel:firstPanel;
|
||||||
|
if (next && next!=wrapped)
|
||||||
|
return false; // Let IsDialogMessage move within the active page.
|
||||||
|
current=4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i=0;i<_countof(targets);i++)
|
||||||
|
if (focus==targets[i]) { current=i; break; }
|
||||||
|
}
|
||||||
|
if (current<0) return false;
|
||||||
|
|
||||||
|
for (int step=1;step<=_countof(targets);step++)
|
||||||
|
{
|
||||||
|
int index=(current+(bPrevious?-step:step)+_countof(targets)*2)%_countof(targets);
|
||||||
|
HWND target=(index==4 && bPrevious)?lastPanel:targets[index];
|
||||||
|
if (!target || !::IsWindowVisible(target) || !::IsWindowEnabled(target)) continue;
|
||||||
|
if (index==3 && !(::GetWindowLongPtr(target,GWL_STYLE)&WS_TABSTOP)) continue;
|
||||||
|
::SetFocus(target);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT CSettingsDlg::OnSelChanging( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
LRESULT CSettingsDlg::OnSelChanging( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
||||||
@@ -1793,7 +1856,9 @@ LRESULT CSettingsDlg::OnSelChanging( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
|||||||
|
|
||||||
LRESULT CSettingsDlg::OnSelChange( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
LRESULT CSettingsDlg::OnSelChange( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
||||||
{
|
{
|
||||||
SetCurTab(TabCtrl_GetCurSel(m_Tabs),false);
|
// Mouse clicks and Left/Right navigation keep focus on the tab strip.
|
||||||
|
// Ctrl+Tab is handled separately and moves focus into the new page.
|
||||||
|
SetCurTab(TabCtrl_GetCurSel(m_Tabs),false,NULL,false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1926,6 +1991,11 @@ bool IsSettingsMessage( MSG *msg )
|
|||||||
g_SettingsDlg.SendMessage(WM_KEYDOWN,VK_TAB,msg->lParam);
|
g_SettingsDlg.SendMessage(WM_KEYDOWN,VK_TAB,msg->lParam);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (msg->message==WM_KEYDOWN && msg->wParam==VK_TAB)
|
||||||
|
{
|
||||||
|
if (g_SettingsDlg.NavigateTab(GetKeyState(VK_SHIFT)<0))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (msg->message==WM_KEYDOWN && msg->wParam==VK_RETURN && GetKeyState(VK_CONTROL)<0)
|
if (msg->message==WM_KEYDOWN && msg->wParam==VK_RETURN && GetKeyState(VK_CONTROL)<0)
|
||||||
{
|
{
|
||||||
g_SettingsDlg.SendMessage(WM_COMMAND,IDOK,0);
|
g_SettingsDlg.SendMessage(WM_COMMAND,IDOK,0);
|
||||||
|
|||||||
@@ -16,6 +16,202 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <oleacc.h>
|
||||||
|
|
||||||
|
// Local constants avoid forcing every executable that links the Lib static
|
||||||
|
// library to define the oleacc GUID symbols.
|
||||||
|
static const GUID CLSID_SettingsAccPropServices={0xb5f8350b,0x0548,0x48b1,{0xa6,0xee,0x88,0xbd,0x00,0xb4,0xa5,0xe7}};
|
||||||
|
static const GUID PROPID_SettingsAccState={0xa8d4d5b0,0x0a21,0x42d0,{0xa5,0xc0,0x51,0x4e,0x98,0x4f,0x45,0x7b}};
|
||||||
|
static const GUID PROPID_SettingsAccName={0x608d3df8,0x8128,0x4aa7,{0xa4,0x28,0xf5,0x5e,0x49,0x26,0x72,0x91}};
|
||||||
|
static const GUID PROPID_SettingsAccRole={0xcb905ff2,0x7bd1,0x4c05,{0xb3,0xc8,0xe6,0xc2,0x41,0x36,0x4d,0x70}};
|
||||||
|
|
||||||
|
class CSettingsTreeAccServer: public IAccPropServer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CSettingsTreeAccServer( void ): m_RefCount(1)
|
||||||
|
{
|
||||||
|
CoCreateInstance(CLSID_SettingsAccPropServices,NULL,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&m_Props));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID iid, void **object )
|
||||||
|
{
|
||||||
|
if (!object) return E_POINTER;
|
||||||
|
*object=NULL;
|
||||||
|
if (iid==IID_IUnknown || iid==IID_IAccPropServer)
|
||||||
|
{
|
||||||
|
*object=static_cast<IAccPropServer*>(this);
|
||||||
|
AddRef();
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
virtual ULONG STDMETHODCALLTYPE AddRef( void ) { return InterlockedIncrement(&m_RefCount); }
|
||||||
|
virtual ULONG STDMETHODCALLTYPE Release( void )
|
||||||
|
{
|
||||||
|
ULONG count=InterlockedDecrement(&m_RefCount);
|
||||||
|
if (!count) delete this;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE GetPropValue( const BYTE *identity, DWORD identitySize, MSAAPROPID prop, VARIANT *value, BOOL *hasProp )
|
||||||
|
{
|
||||||
|
if (!value || !hasProp) return E_POINTER;
|
||||||
|
VariantInit(value);
|
||||||
|
*hasProp=FALSE;
|
||||||
|
if (!m_Props) return S_OK;
|
||||||
|
|
||||||
|
HWND tree=NULL;
|
||||||
|
DWORD objectId=0, childId=0;
|
||||||
|
if (FAILED(m_Props->DecomposeHwndIdentityString(identity,identitySize,&tree,&objectId,&childId)) || objectId!=OBJID_CLIENT || childId==CHILDID_SELF)
|
||||||
|
return S_OK;
|
||||||
|
HTREEITEM hItem=TreeView_MapAccIDToHTREEITEM(tree,childId);
|
||||||
|
if (!hItem) return S_OK;
|
||||||
|
|
||||||
|
wchar_t text[256];
|
||||||
|
TVITEM item={TVIF_IMAGE|TVIF_STATE|TVIF_TEXT,hItem,0,TVIS_SELECTED|TVIS_EXPANDED|TVIS_CUT,text,_countof(text)};
|
||||||
|
if (!TreeView_GetItem(tree,&item)) return S_OK;
|
||||||
|
if (prop==PROPID_SettingsAccRole)
|
||||||
|
{
|
||||||
|
if (item.iImage&SETTING_STATE_CHECKBOX)
|
||||||
|
value->lVal=ROLE_SYSTEM_CHECKBUTTON;
|
||||||
|
else if (item.iImage&SETTING_STATE_RADIO)
|
||||||
|
value->lVal=ROLE_SYSTEM_RADIOBUTTON;
|
||||||
|
else
|
||||||
|
return S_OK;
|
||||||
|
value->vt=VT_I4;
|
||||||
|
*hasProp=TRUE;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
if (prop==PROPID_SettingsAccName)
|
||||||
|
{
|
||||||
|
// A sighted user can see which child choice is checked without
|
||||||
|
// opening the group. Give screen-reader users the same summary.
|
||||||
|
for (HTREEITEM child=TreeView_GetChild(tree,hItem);child;child=TreeView_GetNextSibling(tree,child))
|
||||||
|
{
|
||||||
|
wchar_t childText[256];
|
||||||
|
TVITEM childItem={TVIF_IMAGE|TVIF_TEXT,child,0,0,childText,_countof(childText)};
|
||||||
|
if (TreeView_GetItem(tree,&childItem) && (childItem.iImage&SETTING_STATE_CHECKED))
|
||||||
|
{
|
||||||
|
CString name;
|
||||||
|
name.Format(L"%s: %s",text,childText);
|
||||||
|
value->vt=VT_BSTR;
|
||||||
|
value->bstrVal=SysAllocString(name);
|
||||||
|
if (!value->bstrVal) return E_OUTOFMEMORY;
|
||||||
|
*hasProp=TRUE;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
if (prop!=PROPID_SettingsAccState) return S_OK;
|
||||||
|
LONG state=STATE_SYSTEM_SELECTABLE|STATE_SYSTEM_FOCUSABLE;
|
||||||
|
if (item.state&TVIS_SELECTED)
|
||||||
|
{
|
||||||
|
state|=STATE_SYSTEM_SELECTED;
|
||||||
|
if (GetFocus()==tree) state|=STATE_SYSTEM_FOCUSED;
|
||||||
|
}
|
||||||
|
if (TreeView_GetChild(tree,hItem))
|
||||||
|
state|=(item.state&TVIS_EXPANDED)?STATE_SYSTEM_EXPANDED:STATE_SYSTEM_COLLAPSED;
|
||||||
|
if (item.state&TVIS_CUT || (item.iImage&SETTING_STATE_DISABLED))
|
||||||
|
state|=STATE_SYSTEM_UNAVAILABLE;
|
||||||
|
if ((item.iImage&(SETTING_STATE_CHECKBOX|SETTING_STATE_RADIO)) && (item.iImage&SETTING_STATE_CHECKED))
|
||||||
|
state|=STATE_SYSTEM_CHECKED;
|
||||||
|
RECT rect;
|
||||||
|
if (!TreeView_GetItemRect(tree,hItem,&rect,FALSE))
|
||||||
|
state|=STATE_SYSTEM_INVISIBLE;
|
||||||
|
|
||||||
|
value->vt=VT_I4;
|
||||||
|
value->lVal=state;
|
||||||
|
*hasProp=TRUE;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
LONG m_RefCount;
|
||||||
|
CComPtr<IAccPropServices> m_Props;
|
||||||
|
};
|
||||||
|
|
||||||
|
void EnableSettingsTreeAccessibility( HWND tree )
|
||||||
|
{
|
||||||
|
CComPtr<IAccPropServices> props;
|
||||||
|
if (FAILED(CoCreateInstance(CLSID_SettingsAccPropServices,NULL,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&props)))) return;
|
||||||
|
CSettingsTreeAccServer *server=new CSettingsTreeAccServer;
|
||||||
|
MSAAPROPID property=PROPID_SettingsAccState;
|
||||||
|
props->SetHwndPropServer(tree,OBJID_CLIENT,CHILDID_SELF,&property,1,server,ANNO_CONTAINER);
|
||||||
|
server->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ClearSettingsTreeItemAccessibilityImpl( IAccPropServices *props, HWND tree )
|
||||||
|
{
|
||||||
|
MSAAPROPID properties[]={PROPID_SettingsAccState,PROPID_SettingsAccName,PROPID_SettingsAccRole};
|
||||||
|
for (HTREEITEM item=TreeView_GetRoot(tree);item;)
|
||||||
|
{
|
||||||
|
props->ClearHwndProps(tree,OBJID_CLIENT,TreeView_MapHTREEITEMToAccID(tree,item),properties,_countof(properties));
|
||||||
|
HTREEITEM next=TreeView_GetChild(tree,item);
|
||||||
|
if (!next)
|
||||||
|
{
|
||||||
|
next=TreeView_GetNextSibling(tree,item);
|
||||||
|
while (!next && (item=TreeView_GetParent(tree,item))!=NULL)
|
||||||
|
next=TreeView_GetNextSibling(tree,item);
|
||||||
|
}
|
||||||
|
item=next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearSettingsTreeItemAccessibility( HWND tree )
|
||||||
|
{
|
||||||
|
if (!tree || !IsWindow(tree)) return;
|
||||||
|
CComPtr<IAccPropServices> props;
|
||||||
|
if (FAILED(CoCreateInstance(CLSID_SettingsAccPropServices,NULL,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&props)))) return;
|
||||||
|
ClearSettingsTreeItemAccessibilityImpl(props,tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearSettingsTreeAccessibility( HWND tree )
|
||||||
|
{
|
||||||
|
if (!tree || !IsWindow(tree)) return;
|
||||||
|
CComPtr<IAccPropServices> props;
|
||||||
|
if (FAILED(CoCreateInstance(CLSID_SettingsAccPropServices,NULL,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&props)))) return;
|
||||||
|
|
||||||
|
// Release all per-item servers while their accessibility IDs can still be
|
||||||
|
// resolved, then remove the container server and the tree-level name.
|
||||||
|
ClearSettingsTreeItemAccessibilityImpl(props,tree);
|
||||||
|
MSAAPROPID properties[]={PROPID_SettingsAccState,PROPID_SettingsAccName,PROPID_SettingsAccRole};
|
||||||
|
props->ClearHwndProps(tree,OBJID_CLIENT,CHILDID_SELF,properties,_countof(properties));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetControlAccessibleName( HWND control, const wchar_t *name )
|
||||||
|
{
|
||||||
|
CComPtr<IAccPropServices> props;
|
||||||
|
if (SUCCEEDED(CoCreateInstance(CLSID_SettingsAccPropServices,NULL,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&props))))
|
||||||
|
props->SetHwndPropStr(control,OBJID_CLIENT,CHILDID_SELF,PROPID_SettingsAccName,name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSettingsTreeAccessibleName( HWND tree, const wchar_t *name )
|
||||||
|
{
|
||||||
|
SetControlAccessibleName(tree,name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSettingsTreeItemAccessibleName( HWND tree, HTREEITEM item, const wchar_t *name )
|
||||||
|
{
|
||||||
|
CComPtr<IAccPropServices> props;
|
||||||
|
if (SUCCEEDED(CoCreateInstance(CLSID_SettingsAccPropServices,NULL,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&props))))
|
||||||
|
props->SetHwndPropStr(tree,OBJID_CLIENT,TreeView_MapHTREEITEMToAccID(tree,item),PROPID_SettingsAccName,name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSettingsTreeItemAccessibleRole( HWND tree, HTREEITEM item, LONG role )
|
||||||
|
{
|
||||||
|
CComPtr<IAccPropServices> props;
|
||||||
|
if (SUCCEEDED(CoCreateInstance(CLSID_SettingsAccPropServices,NULL,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&props))))
|
||||||
|
{
|
||||||
|
// Some settings hosts do not ask a container annotation server for
|
||||||
|
// descendant state. Bind the dynamic state provider to the item too.
|
||||||
|
CSettingsTreeAccServer *server=new CSettingsTreeAccServer;
|
||||||
|
MSAAPROPID stateProperty=PROPID_SettingsAccState;
|
||||||
|
props->SetHwndPropServer(tree,OBJID_CLIENT,TreeView_MapHTREEITEMToAccID(tree,item),&stateProperty,1,server,ANNO_THIS);
|
||||||
|
server->Release();
|
||||||
|
CComVariant value(role);
|
||||||
|
props->SetHwndProp(tree,OBJID_CLIENT,TreeView_MapHTREEITEMToAccID(tree,item),PROPID_SettingsAccRole,value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const KNOWNFOLDERID FOLDERID_DesktopRoot={'DESK', 'TO', 'P', {'D', 'E', 'S', 'K', 'T', 'O', 'P', 0x00}};
|
const KNOWNFOLDERID FOLDERID_DesktopRoot={'DESK', 'TO', 'P', {'D', 'E', 'S', 'K', 'T', 'O', 'P', 0x00}};
|
||||||
|
|
||||||
@@ -2334,7 +2530,6 @@ public:
|
|||||||
NOTIFY_HANDLER( IDC_SETTINGS, TVN_KEYDOWN, OnKeyDown )
|
NOTIFY_HANDLER( IDC_SETTINGS, TVN_KEYDOWN, OnKeyDown )
|
||||||
NOTIFY_HANDLER( IDC_SETTINGS, TVN_GETINFOTIP, OnGetInfoTip )
|
NOTIFY_HANDLER( IDC_SETTINGS, TVN_GETINFOTIP, OnGetInfoTip )
|
||||||
NOTIFY_HANDLER( IDC_SETTINGS, TVN_SELCHANGED, OnSelChanged )
|
NOTIFY_HANDLER( IDC_SETTINGS, TVN_SELCHANGED, OnSelChanged )
|
||||||
NOTIFY_HANDLER( IDC_SETTINGS, TVN_ITEMEXPANDING, OnExpanding )
|
|
||||||
END_MSG_MAP()
|
END_MSG_MAP()
|
||||||
|
|
||||||
BEGIN_RESIZE_MAP
|
BEGIN_RESIZE_MAP
|
||||||
@@ -2364,7 +2559,6 @@ protected:
|
|||||||
LRESULT OnClick( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
LRESULT OnClick( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
||||||
LRESULT OnGetInfoTip( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
LRESULT OnGetInfoTip( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
||||||
LRESULT OnSelChanged( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
LRESULT OnSelChanged( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
||||||
LRESULT OnExpanding( int idCtrl, LPNMHDR pnmh, BOOL& bHandled ) { return TRUE; } // prevent collapsing
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CWindow m_Tree;
|
CWindow m_Tree;
|
||||||
@@ -2398,6 +2592,32 @@ static LRESULT CALLBACK SubclassTreeProc( HWND hWnd, UINT uMsg, WPARAM wParam, L
|
|||||||
{
|
{
|
||||||
if (uMsg==WM_COMMAND)
|
if (uMsg==WM_COMMAND)
|
||||||
return SendMessage(GetParent(hWnd),uMsg,wParam,lParam);
|
return SendMessage(GetParent(hWnd),uMsg,wParam,lParam);
|
||||||
|
if (uMsg==WM_KEYDOWN && (wParam==VK_LEFT || wParam==VK_RIGHT) && GetKeyState(VK_MENU)>=0)
|
||||||
|
{
|
||||||
|
HTREEITEM item=TreeView_GetSelection(hWnd);
|
||||||
|
if (!item) return 0;
|
||||||
|
HTREEITEM child=TreeView_GetChild(hWnd,item);
|
||||||
|
TVITEM state={TVIF_STATE,item,0,TVIS_EXPANDED};
|
||||||
|
TreeView_GetItem(hWnd,&state);
|
||||||
|
if (wParam==VK_LEFT)
|
||||||
|
{
|
||||||
|
if (child && (state.state&TVIS_EXPANDED))
|
||||||
|
TreeView_Expand(hWnd,item,TVE_COLLAPSE);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HTREEITEM parent=TreeView_GetParent(hWnd,item);
|
||||||
|
if (parent) TreeView_SelectItem(hWnd,parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (child)
|
||||||
|
{
|
||||||
|
if (state.state&TVIS_EXPANDED)
|
||||||
|
TreeView_SelectItem(hWnd,child);
|
||||||
|
else
|
||||||
|
TreeView_Expand(hWnd,item,TVE_EXPAND);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2534,6 +2754,16 @@ LRESULT CTreeSettingsDlg::OnInitDialog( UINT uMsg, WPARAM wParam, LPARAM lParam,
|
|||||||
SetWindowTheme(m_Tree,L"Explorer",NULL);
|
SetWindowTheme(m_Tree,L"Explorer",NULL);
|
||||||
}
|
}
|
||||||
m_Tree.SendMessage(TVM_SETEXTENDEDSTYLE,TVS_EX_DOUBLEBUFFER,TVS_EX_DOUBLEBUFFER);
|
m_Tree.SendMessage(TVM_SETEXTENDEDSTYLE,TVS_EX_DOUBLEBUFFER,TVS_EX_DOUBLEBUFFER);
|
||||||
|
EnableSettingsTreeAccessibility(m_Tree);
|
||||||
|
CString tip;
|
||||||
|
GetDlgItemText(IDC_STATICTIP,tip);
|
||||||
|
int line=tip.Find(L'\n');
|
||||||
|
if (line>=0)
|
||||||
|
{
|
||||||
|
tip=tip.Mid(line+1);
|
||||||
|
tip.Trim();
|
||||||
|
SetControlAccessibleName(GetDlgItem(IDC_STATICTIP),tip);
|
||||||
|
}
|
||||||
SetWindowSubclass(m_Tree,SubclassTreeProc,'CLSH',0);
|
SetWindowSubclass(m_Tree,SubclassTreeProc,'CLSH',0);
|
||||||
HINSTANCE hInstance=_AtlBaseModule.GetResourceInstance();
|
HINSTANCE hInstance=_AtlBaseModule.GetResourceInstance();
|
||||||
|
|
||||||
@@ -2567,6 +2797,7 @@ LRESULT CTreeSettingsDlg::OnInitDialog( UINT uMsg, WPARAM wParam, LPARAM lParam,
|
|||||||
|
|
||||||
LRESULT CTreeSettingsDlg::OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
LRESULT CTreeSettingsDlg::OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
||||||
{
|
{
|
||||||
|
ClearSettingsTreeAccessibility(m_Tree);
|
||||||
DestroyIcon(m_PlayIcon);
|
DestroyIcon(m_PlayIcon);
|
||||||
bHandled=FALSE;
|
bHandled=FALSE;
|
||||||
m_EditMode=EDIT_NONE;
|
m_EditMode=EDIT_NONE;
|
||||||
@@ -3201,6 +3432,7 @@ void CTreeSettingsDlg::ItemSelected( HTREEITEM hItem, CSetting *pSetting, bool b
|
|||||||
if (mode!=EDIT_NONE)
|
if (mode!=EDIT_NONE)
|
||||||
{
|
{
|
||||||
CString str=LoadStringEx(pSetting->nameID);
|
CString str=LoadStringEx(pSetting->nameID);
|
||||||
|
SetControlAccessibleName(m_EditBox,str);
|
||||||
TVITEM item={TVIF_TEXT,hItem,0,0,(LPWSTR)(LPCWSTR)str};
|
TVITEM item={TVIF_TEXT,hItem,0,0,(LPWSTR)(LPCWSTR)str};
|
||||||
TreeView_SetItem(m_Tree,&item);
|
TreeView_SetItem(m_Tree,&item);
|
||||||
m_Tree.GetClientRect(&rc);
|
m_Tree.GetClientRect(&rc);
|
||||||
@@ -3242,6 +3474,12 @@ void CTreeSettingsDlg::ItemSelected( HTREEITEM hItem, CSetting *pSetting, bool b
|
|||||||
m_EditBox.SetWindowPos(NULL,&rc,SWP_NOZORDER|SWP_SHOWWINDOW);
|
m_EditBox.SetWindowPos(NULL,&rc,SWP_NOZORDER|SWP_SHOWWINDOW);
|
||||||
SendMessage(WM_NEXTDLGCTL,(LPARAM)m_EditBox.m_hWnd,TRUE);
|
SendMessage(WM_NEXTDLGCTL,(LPARAM)m_EditBox.m_hWnd,TRUE);
|
||||||
SetWindowSubclass(m_EditBox,SubclassEditProc,'CLSH',(mode==EDIT_HOTKEY)?1:((mode==EDIT_HOTKEY_ANY)?2:0));
|
SetWindowSubclass(m_EditBox,SubclassEditProc,'CLSH',(mode==EDIT_HOTKEY)?1:((mode==EDIT_HOTKEY_ANY)?2:0));
|
||||||
|
// The same overlay edit is reused while Up/Down moves through the
|
||||||
|
// tree. Its HWND and keyboard focus do not change, so explicitly
|
||||||
|
// announce that its accessible name has changed.
|
||||||
|
NotifyWinEvent(EVENT_OBJECT_NAMECHANGE,m_EditBox,OBJID_CLIENT,CHILDID_SELF);
|
||||||
|
if (::GetFocus()==m_EditBox)
|
||||||
|
NotifyWinEvent(EVENT_OBJECT_FOCUS,m_EditBox,OBJID_CLIENT,CHILDID_SELF);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_EditBox.ShowWindow(SW_HIDE);
|
m_EditBox.ShowWindow(SW_HIDE);
|
||||||
@@ -3385,11 +3623,14 @@ HTREEITEM CTreeSettingsDlg::FindSettingsItem( const wchar_t *name )
|
|||||||
|
|
||||||
void CTreeSettingsDlg::SetGroup( CSetting *pGroup, const CString &filter, const CSetting *pSelect )
|
void CTreeSettingsDlg::SetGroup( CSetting *pGroup, const CString &filter, const CSetting *pSelect )
|
||||||
{
|
{
|
||||||
|
CString groupName=LoadStringEx(pGroup->nameID);
|
||||||
|
SetSettingsTreeAccessibleName(m_Tree,groupName);
|
||||||
ItemSelected(NULL,NULL,false);
|
ItemSelected(NULL,NULL,false);
|
||||||
m_pGroup=pGroup;
|
m_pGroup=pGroup;
|
||||||
// fill tree control
|
// fill tree control
|
||||||
m_Tree.SendMessage(WM_SETREDRAW,FALSE);
|
m_Tree.SendMessage(WM_SETREDRAW,FALSE);
|
||||||
TreeView_SelectItem(m_Tree,NULL);
|
TreeView_SelectItem(m_Tree,NULL);
|
||||||
|
ClearSettingsTreeItemAccessibility(m_Tree);
|
||||||
TreeView_DeleteAllItems(m_Tree);
|
TreeView_DeleteAllItems(m_Tree);
|
||||||
int level=0;
|
int level=0;
|
||||||
HTREEITEM hRadioParent=NULL;
|
HTREEITEM hRadioParent=NULL;
|
||||||
@@ -3566,9 +3807,14 @@ void CTreeSettingsDlg::UpdateGroup( const CSetting *pModified )
|
|||||||
RECT rc;
|
RECT rc;
|
||||||
TreeView_GetItemRect(m_Tree,hItem,&rc,FALSE);
|
TreeView_GetItemRect(m_Tree,hItem,&rc,FALSE);
|
||||||
m_Tree.InvalidateRect(&rc);
|
m_Tree.InvalidateRect(&rc);
|
||||||
|
NotifyWinEvent(EVENT_OBJECT_STATECHANGE,m_Tree,OBJID_CLIENT,TreeView_MapHTREEITEMToAccID(m_Tree,hItem));
|
||||||
}
|
}
|
||||||
|
if (pSetting->type==CSetting::TYPE_BOOL)
|
||||||
|
SetSettingsTreeItemAccessibleRole(m_Tree,hItem,ROLE_SYSTEM_CHECKBUTTON);
|
||||||
|
|
||||||
// update radio buttons
|
// update radio buttons
|
||||||
|
wchar_t selectedText[256];
|
||||||
|
selectedText[0]=0;
|
||||||
if (pSetting->type==CSetting::TYPE_INT && pSetting[1].type==CSetting::TYPE_RADIO)
|
if (pSetting->type==CSetting::TYPE_INT && pSetting[1].type==CSetting::TYPE_RADIO)
|
||||||
{
|
{
|
||||||
int val=0;
|
int val=0;
|
||||||
@@ -3598,9 +3844,37 @@ void CTreeSettingsDlg::UpdateGroup( const CSetting *pModified )
|
|||||||
RECT rc;
|
RECT rc;
|
||||||
TreeView_GetItemRect(m_Tree,hRadio,&rc,FALSE);
|
TreeView_GetItemRect(m_Tree,hRadio,&rc,FALSE);
|
||||||
m_Tree.InvalidateRect(&rc);
|
m_Tree.InvalidateRect(&rc);
|
||||||
|
NotifyWinEvent(EVENT_OBJECT_STATECHANGE,m_Tree,OBJID_CLIENT,TreeView_MapHTREEITEMToAccID(m_Tree,hRadio));
|
||||||
}
|
}
|
||||||
|
SetSettingsTreeItemAccessibleRole(m_Tree,hRadio,ROLE_SYSTEM_RADIOBUTTON);
|
||||||
|
}
|
||||||
|
for (HTREEITEM hRadio=TreeView_GetChild(m_Tree,hItem);hRadio;hRadio=TreeView_GetNextSibling(m_Tree,hRadio))
|
||||||
|
{
|
||||||
|
TVITEM radioName={TVIF_IMAGE|TVIF_TEXT,hRadio,0,0,selectedText,_countof(selectedText)};
|
||||||
|
if (TreeView_GetItem(m_Tree,&radioName) && (radioName.iImage&SETTING_STATE_CHECKED)) break;
|
||||||
|
selectedText[0]=0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bold is the visual indication that a setting differs from its
|
||||||
|
// default. Expose the same information in the accessible name.
|
||||||
|
wchar_t parentText[256];
|
||||||
|
TVITEM parentName={TVIF_TEXT,hItem,0,0,parentText,_countof(parentText)};
|
||||||
|
TreeView_GetItem(m_Tree,&parentName);
|
||||||
|
CString accessibleName=parentText;
|
||||||
|
if (selectedText[0])
|
||||||
|
{
|
||||||
|
accessibleName+=L": ";
|
||||||
|
accessibleName+=selectedText;
|
||||||
|
}
|
||||||
|
if (!bDefault)
|
||||||
|
{
|
||||||
|
accessibleName+=L", ";
|
||||||
|
accessibleName+=LoadStringEx(IDS_SETTING_MODIFIED);
|
||||||
|
}
|
||||||
|
SetSettingsTreeItemAccessibleName(m_Tree,hItem,accessibleName);
|
||||||
|
if (pSetting==pModified)
|
||||||
|
NotifyWinEvent(EVENT_OBJECT_NAMECHANGE,m_Tree,OBJID_CLIENT,TreeView_MapHTREEITEMToAccID(m_Tree,hItem));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,17 @@ class CSettingsTree;
|
|||||||
class ISettingsPanel;
|
class ISettingsPanel;
|
||||||
struct CSetting;
|
struct CSetting;
|
||||||
|
|
||||||
|
// Adds the checked/unchecked and unavailable states used by the settings
|
||||||
|
// trees to their MSAA/UIA representation. The visual state remains provided
|
||||||
|
// by Open-Shell's existing image list.
|
||||||
|
void EnableSettingsTreeAccessibility( HWND tree );
|
||||||
|
void ClearSettingsTreeItemAccessibility( HWND tree );
|
||||||
|
void ClearSettingsTreeAccessibility( HWND tree );
|
||||||
|
void SetControlAccessibleName( HWND control, const wchar_t *name );
|
||||||
|
void SetSettingsTreeAccessibleName( HWND tree, const wchar_t *name );
|
||||||
|
void SetSettingsTreeItemAccessibleName( HWND tree, HTREEITEM item, const wchar_t *name );
|
||||||
|
void SetSettingsTreeItemAccessibleRole( HWND tree, HTREEITEM item, LONG role );
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// CResizeableDlg - a dialog that rearranges its controls when it gets resized
|
// CResizeableDlg - a dialog that rearranges its controls when it gets resized
|
||||||
|
|||||||
@@ -139,6 +139,8 @@
|
|||||||
#define IDS_BMP_FILTERS2 4077
|
#define IDS_BMP_FILTERS2 4077
|
||||||
#define IDS_UNSAVED_CHANGES 4078
|
#define IDS_UNSAVED_CHANGES 4078
|
||||||
#define IDS_UNSAVED_TITLE 4079
|
#define IDS_UNSAVED_TITLE 4079
|
||||||
|
#define IDS_SETTINGS_PAGES 4080
|
||||||
|
#define IDS_SETTING_MODIFIED 4081
|
||||||
|
|
||||||
// Next default values for new objects
|
// Next default values for new objects
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -47,6 +47,69 @@ struct Chunk
|
|||||||
int start1, start2, len;
|
int start1, start2, len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool IsExplorerShellRunning( void )
|
||||||
|
{
|
||||||
|
HWND shellWindow=GetShellWindow();
|
||||||
|
if (!shellWindow)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DWORD shellProcessId=0;
|
||||||
|
GetWindowThreadProcessId(shellWindow,&shellProcessId);
|
||||||
|
if (!shellProcessId)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DWORD currentSession=0;
|
||||||
|
DWORD shellSession=0;
|
||||||
|
if (!ProcessIdToSessionId(GetCurrentProcessId(),¤tSession) ||
|
||||||
|
!ProcessIdToSessionId(shellProcessId,&shellSession) ||
|
||||||
|
currentSession!=shellSession)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE process=OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,FALSE,shellProcessId);
|
||||||
|
if (!process)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
wchar_t path[_MAX_PATH];
|
||||||
|
DWORD pathSize=_countof(path);
|
||||||
|
bool isExplorer=false;
|
||||||
|
if (QueryFullProcessImageName(process,0,path,&pathSize))
|
||||||
|
isExplorer=_wcsicmp(PathFindFileName(path),L"explorer.exe")==0;
|
||||||
|
|
||||||
|
CloseHandle(process);
|
||||||
|
return isExplorer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RestoreExplorerShellIfNeeded( bool wasRunning )
|
||||||
|
{
|
||||||
|
if (!wasRunning)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Restart Manager normally brings Explorer back before msiexec exits.
|
||||||
|
// Give it a short grace period before applying our fallback so we don't
|
||||||
|
// race a normal restart or create an extra Explorer process.
|
||||||
|
for (int i=0;i<50;i++)
|
||||||
|
{
|
||||||
|
if (IsExplorerShellRunning())
|
||||||
|
return;
|
||||||
|
Sleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t explorerPath[_MAX_PATH];
|
||||||
|
UINT len=GetWindowsDirectory(explorerPath,_countof(explorerPath));
|
||||||
|
if (!len || len>=_countof(explorerPath) || !PathAppend(explorerPath,L"explorer.exe"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
STARTUPINFO startupInfo={sizeof(startupInfo)};
|
||||||
|
PROCESS_INFORMATION processInfo={};
|
||||||
|
if (CreateProcess(explorerPath,NULL,NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo))
|
||||||
|
{
|
||||||
|
CloseHandle(processInfo.hThread);
|
||||||
|
CloseHandle(processInfo.hProcess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void WriteFileXOR( HANDLE hFile, const unsigned char *buf, int size )
|
static void WriteFileXOR( HANDLE hFile, const unsigned char *buf, int size )
|
||||||
{
|
{
|
||||||
if (size>0)
|
if (size>0)
|
||||||
@@ -409,6 +472,11 @@ int APIENTRY wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCm
|
|||||||
if (extractType == ARM64)
|
if (extractType == ARM64)
|
||||||
Wow64DisableWow64FsRedirection(&wow64FsRedirVal);
|
Wow64DisableWow64FsRedirection(&wow64FsRedirVal);
|
||||||
|
|
||||||
|
// Remember whether this interactive session had the Explorer desktop shell.
|
||||||
|
// If Restart Manager closes it during MSI processing but fails to bring it
|
||||||
|
// back, restore only the shell that was present before setup started.
|
||||||
|
const bool explorerWasRunning=IsExplorerShellRunning();
|
||||||
|
|
||||||
// start the installer
|
// start the installer
|
||||||
STARTUPINFO startupInfo={sizeof(startupInfo)};
|
STARTUPINFO startupInfo={sizeof(startupInfo)};
|
||||||
PROCESS_INFORMATION processInfo;
|
PROCESS_INFORMATION processInfo;
|
||||||
@@ -438,6 +506,12 @@ int APIENTRY wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCm
|
|||||||
GetExitCodeProcess(processInfo.hProcess,&code);
|
GetExitCodeProcess(processInfo.hProcess,&code);
|
||||||
CloseHandle(processInfo.hProcess);
|
CloseHandle(processInfo.hProcess);
|
||||||
DeleteFile(msiName);
|
DeleteFile(msiName);
|
||||||
|
|
||||||
|
// Only repair the shell after a successful transaction. Reboot-required
|
||||||
|
// outcomes deliberately keep Windows Installer in control of recovery.
|
||||||
|
if (code==ERROR_SUCCESS)
|
||||||
|
RestoreExplorerShellIfNeeded(explorerWasRunning);
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,14 @@ HRESULT STDMETHODCALLTYPE CMenuAccessible::get_accName( VARIANT varChild, BSTR *
|
|||||||
if (!m_pOwner) return RPC_E_DISCONNECTED;
|
if (!m_pOwner) return RPC_E_DISCONNECTED;
|
||||||
*pszName=NULL;
|
*pszName=NULL;
|
||||||
if (varChild.vt!=VT_I4) return S_FALSE;
|
if (varChild.vt!=VT_I4) return S_FALSE;
|
||||||
if (varChild.lVal==CHILDID_SELF) return S_FALSE;
|
if (varChild.lVal==CHILDID_SELF)
|
||||||
|
{
|
||||||
|
if (m_pOwner->m_pParent && m_pOwner->m_ParentIndex>=0 && m_pOwner->m_ParentIndex<(int)m_pOwner->m_pParent->m_Items.size())
|
||||||
|
*pszName=SysAllocString(m_pOwner->m_pParent->m_Items[m_pOwner->m_ParentIndex].name);
|
||||||
|
else
|
||||||
|
*pszName=SysAllocString(L"Start");
|
||||||
|
return *pszName?S_OK:E_OUTOFMEMORY;
|
||||||
|
}
|
||||||
int index=varChild.lVal-1;
|
int index=varChild.lVal-1;
|
||||||
if (index<0 || index>=(int)m_pOwner->m_Items.size()) return S_FALSE;
|
if (index<0 || index>=(int)m_pOwner->m_Items.size()) return S_FALSE;
|
||||||
if (m_pOwner->m_Items[index].id==MENU_SEPARATOR) return S_FALSE;
|
if (m_pOwner->m_Items[index].id==MENU_SEPARATOR) return S_FALSE;
|
||||||
@@ -105,7 +112,10 @@ HRESULT STDMETHODCALLTYPE CMenuAccessible::get_accState( VARIANT varChild, VARIA
|
|||||||
if (m_pOwner->m_HotItem==index)
|
if (m_pOwner->m_HotItem==index)
|
||||||
flags|=STATE_SYSTEM_FOCUSED;
|
flags|=STATE_SYSTEM_FOCUSED;
|
||||||
if (item.bFolder)
|
if (item.bFolder)
|
||||||
|
{
|
||||||
flags|=STATE_SYSTEM_HASPOPUP;
|
flags|=STATE_SYSTEM_HASPOPUP;
|
||||||
|
flags|=(m_pOwner->m_Submenu==index)?STATE_SYSTEM_EXPANDED:STATE_SYSTEM_COLLAPSED;
|
||||||
|
}
|
||||||
if (item.id==MENU_SEPARATOR)
|
if (item.id==MENU_SEPARATOR)
|
||||||
flags=0;
|
flags=0;
|
||||||
RECT rc;
|
RECT rc;
|
||||||
@@ -167,7 +177,12 @@ HRESULT STDMETHODCALLTYPE CMenuAccessible::get_accDefaultAction( VARIANT varChil
|
|||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
const CMenuContainer::MenuItem &item=m_pOwner->m_Items[index];
|
const CMenuContainer::MenuItem &item=m_pOwner->m_Items[index];
|
||||||
if (item.id!=MENU_SEPARATOR && item.id!=MENU_EMPTY && item.id!=MENU_EMPTY_TOP)
|
if (item.id!=MENU_SEPARATOR && item.id!=MENU_EMPTY && item.id!=MENU_EMPTY_TOP)
|
||||||
*pszDefaultAction=SysAllocString(item.bFolder?FindTranslation(L"Menu.ActionOpen",L"Open"):FindTranslation(L"Menu.ActionExecute",L"Execute"));
|
{
|
||||||
|
if (item.bFolder)
|
||||||
|
*pszDefaultAction=SysAllocString(m_pOwner->m_Submenu==index?FindTranslation(L"Menu.ActionClose",L"Close"):FindTranslation(L"Menu.ActionOpen",L"Open"));
|
||||||
|
else
|
||||||
|
*pszDefaultAction=SysAllocString(FindTranslation(L"Menu.ActionExecute",L"Execute"));
|
||||||
|
}
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3337,19 +3337,19 @@ void CItemManager::LoadCacheFile( void )
|
|||||||
info.iconColor=data.iconColor;
|
info.iconColor=data.iconColor;
|
||||||
info.iconIndex=data.iconIndex;
|
info.iconIndex=data.iconIndex;
|
||||||
|
|
||||||
info.smallIcon=data.smallIcon<(int)remapIcons.size()?remapIcons[data.smallIcon]:NULL;
|
info.smallIcon=data.smallIcon>=0 && (size_t)data.smallIcon<remapIcons.size()?remapIcons[data.smallIcon]:NULL;
|
||||||
if (!info.smallIcon)
|
if (!info.smallIcon)
|
||||||
{
|
{
|
||||||
info.validFlags&=~INFO_SMALL_ICON;
|
info.validFlags&=~INFO_SMALL_ICON;
|
||||||
info.smallIcon=m_DefaultSmallIcon;
|
info.smallIcon=m_DefaultSmallIcon;
|
||||||
}
|
}
|
||||||
info.largeIcon=data.largeIcon<(int)remapIcons.size()?remapIcons[data.largeIcon]:NULL;
|
info.largeIcon=data.largeIcon>=0 && (size_t)data.largeIcon<remapIcons.size()?remapIcons[data.largeIcon]:NULL;
|
||||||
if (!info.largeIcon)
|
if (!info.largeIcon)
|
||||||
{
|
{
|
||||||
info.validFlags&=~INFO_LARGE_ICON;
|
info.validFlags&=~INFO_LARGE_ICON;
|
||||||
info.largeIcon=m_DefaultLargeIcon;
|
info.largeIcon=m_DefaultLargeIcon;
|
||||||
}
|
}
|
||||||
info.extraLargeIcon=data.extraLargeIcon<(int)remapIcons.size()?remapIcons[data.extraLargeIcon]:NULL;
|
info.extraLargeIcon=data.extraLargeIcon>=0 && (size_t)data.extraLargeIcon<remapIcons.size()?remapIcons[data.extraLargeIcon]:NULL;
|
||||||
if (!info.extraLargeIcon)
|
if (!info.extraLargeIcon)
|
||||||
{
|
{
|
||||||
info.validFlags&=~INFO_EXTRA_LARGE_ICON;
|
info.validFlags&=~INFO_EXTRA_LARGE_ICON;
|
||||||
@@ -3422,7 +3422,7 @@ DWORD CALLBACK CItemManager::SaveCacheFileThread( void *param )
|
|||||||
RWLock lock(pThis,false,RWLOCK_ICONS);
|
RWLock lock(pThis,false,RWLOCK_ICONS);
|
||||||
for (std::multimap<unsigned int,IconInfo>::const_iterator it=pThis->m_IconInfos.begin();it!=pThis->m_IconInfos.end();++it)
|
for (std::multimap<unsigned int,IconInfo>::const_iterator it=pThis->m_IconInfos.begin();it!=pThis->m_IconInfos.end();++it)
|
||||||
{
|
{
|
||||||
if (!it->second.PATH.IsEmpty() && it->second.PATH[1]!='#' && it->first!=0)
|
if (!it->second.bTemp && !it->second.bMetro && !it->second.PATH.IsEmpty() && it->second.PATH[1]!='#' && it->first!=0)
|
||||||
iconInfos.push_back(&*it);
|
iconInfos.push_back(&*it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3433,7 +3433,7 @@ DWORD CALLBACK CItemManager::SaveCacheFileThread( void *param )
|
|||||||
RWLock lock(pThis,false,RWLOCK_ITEMS);
|
RWLock lock(pThis,false,RWLOCK_ITEMS);
|
||||||
for (std::multimap<unsigned int,ItemInfo>::const_iterator it=pThis->m_ItemInfos.begin();it!=pThis->m_ItemInfos.end();++it)
|
for (std::multimap<unsigned int,ItemInfo>::const_iterator it=pThis->m_ItemInfos.begin();it!=pThis->m_ItemInfos.end();++it)
|
||||||
{
|
{
|
||||||
if (it->first!=0)
|
if (!it->second.bTemp && it->first!=0)
|
||||||
itemInfos.push_back(&*it);
|
itemInfos.push_back(&*it);
|
||||||
}
|
}
|
||||||
for (std::set<unsigned int>::const_iterator it=pThis->m_BlackListInfos10.begin();it!=pThis->m_BlackListInfos10.end();++it)
|
for (std::set<unsigned int>::const_iterator it=pThis->m_BlackListInfos10.begin();it!=pThis->m_BlackListInfos10.end();++it)
|
||||||
@@ -3566,6 +3566,15 @@ void CItemManager::SaveCacheFile( void )
|
|||||||
|
|
||||||
void CItemManager::ClearCache( void )
|
void 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);
|
Lock cleanupLock(this,LOCK_CLEANUP);
|
||||||
RWLock itemLock(this,true,RWLOCK_ITEMS);
|
RWLock itemLock(this,true,RWLOCK_ITEMS);
|
||||||
RWLock iconLock(this,true,RWLOCK_ICONS);
|
RWLock iconLock(this,true,RWLOCK_ICONS);
|
||||||
|
|||||||
@@ -63,14 +63,6 @@ static auto ExecuteOnSTAThread(TFunc&& func) -> decltype(func())
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrapper for IContextMenu::InvokeCommand that runs on separate STA thread and pumps messages
|
|
||||||
static HRESULT InvokeCommandSafe(IContextMenu* pMenu, LPCMINVOKECOMMANDINFO pInfo)
|
|
||||||
{
|
|
||||||
return ExecuteOnSTAThread([&]() {
|
|
||||||
return pMenu->InvokeCommand(pInfo);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrapper for SHOpenFolderAndSelectItems that runs on separate STA thread and pumps messages
|
// Wrapper for SHOpenFolderAndSelectItems that runs on separate STA thread and pumps messages
|
||||||
static HRESULT SHOpenFolderAndSelectItemsSafe(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD dwFlags)
|
static HRESULT SHOpenFolderAndSelectItemsSafe(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD dwFlags)
|
||||||
{
|
{
|
||||||
@@ -3182,12 +3174,13 @@ void CMenuContainer::ActivateItem( int index, TActivateType type, const POINT *p
|
|||||||
{
|
{
|
||||||
HRESULT hr{};
|
HRESULT hr{};
|
||||||
auto verb = GetContextMenuItemVerb(pInvokeMenu, (UINT_PTR)info.lpVerbW);
|
auto verb = GetContextMenuItemVerb(pInvokeMenu, (UINT_PTR)info.lpVerbW);
|
||||||
// if the verb is "properties", we need to invoke it directly in this UI thread (as it needs to be called on thread that crated context menu object),
|
// "opencontaining" may block the UI thread on recent Windows 11 versions.
|
||||||
// otherwise we will invoke the command on separate STA thread to make sure it won't block UI thread
|
// Use the shell API on a worker STA for that operation, without passing
|
||||||
if (verb.CompareNoCase(L"properties") == 0)
|
// the apartment-bound IContextMenu interface to another thread.
|
||||||
hr = pInvokeMenu->InvokeCommand((LPCMINVOKECOMMANDINFO)&info);
|
if (verb.CompareNoCase(L"opencontaining") == 0)
|
||||||
|
hr = SHOpenFolderAndSelectItemsSafe(pItemPidl1, 0, NULL, 0);
|
||||||
else
|
else
|
||||||
hr = InvokeCommandSafe(pInvokeMenu, (LPCMINVOKECOMMANDINFO)&info);
|
hr = pInvokeMenu->InvokeCommand((LPCMINVOKECOMMANDINFO)&info);
|
||||||
LOG_MENU(LOG_EXECUTE,L"Invoke command, ptr=%p, res=%d",this,hr);
|
LOG_MENU(LOG_EXECUTE,L"Invoke command, ptr=%p, res=%d",this,hr);
|
||||||
executeSuccess=SUCCEEDED(hr);
|
executeSuccess=SUCCEEDED(hr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2537,10 +2537,11 @@ void CMenuContainer::InitItems( void )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_Items.empty() && m_Path1[0] && m_pDropFolder[0])
|
if (!m_bSubMenu && m_Items.empty() && m_Path1[0] && m_pDropFolder[0])
|
||||||
{
|
{
|
||||||
// add (Empty) item to the empty submenus
|
// Keep the top-level drop target placeholder. Submenus defer their
|
||||||
MenuItem item(m_bSubMenu?MENU_EMPTY:MENU_EMPTY_TOP);
|
// empty-state decision until after custom/standard items are appended.
|
||||||
|
MenuItem item(MENU_EMPTY_TOP);
|
||||||
item.name=FindTranslation(L"Menu.Empty",L"(Empty)");
|
item.name=FindTranslation(L"Menu.Empty",L"(Empty)");
|
||||||
m_Items.push_back(item);
|
m_Items.push_back(item);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1185,13 +1185,23 @@ void CMenuContainer::CreateBackground( int width1, int width2, int height1, int
|
|||||||
|
|
||||||
if (opacity!=MenuSkin::OPACITY_SOLID && !bMask)
|
if (opacity!=MenuSkin::OPACITY_SOLID && !bMask)
|
||||||
{
|
{
|
||||||
// set to opaque
|
// set the visible part to opaque. BitBlt/AlphaBlend above clip to
|
||||||
|
// the destination bitmap automatically, but this direct pixel pass
|
||||||
|
// must do the same before forming a pointer into the DIB.
|
||||||
SelectObject(hdc,bmp0); // deselect m_Bitmap so all the GDI operations get flushed
|
SelectObject(hdc,bmp0); // deselect m_Bitmap so all the GDI operations get flushed
|
||||||
unsigned int *bits2=bits+pos.y*totalWidth+pos.x;
|
RECT imageRect={pos.x,pos.y,pos.x+s_Skin.User_image_size,pos.y+s_Skin.User_image_size};
|
||||||
alpha<<=24;
|
RECT bitmapRect={0,0,totalWidth,totalHeight};
|
||||||
for (int y=0;y<s_Skin.User_image_size;y++,bits2+=totalWidth)
|
RECT clippedRect;
|
||||||
for (int x=0;x<s_Skin.User_image_size;x++)
|
if (IntersectRect(&clippedRect,&imageRect,&bitmapRect))
|
||||||
bits2[x]=alpha|(bits2[x]&0xFFFFFF);
|
{
|
||||||
|
unsigned int opaqueAlpha=alpha<<24;
|
||||||
|
for (int y=clippedRect.top;y<clippedRect.bottom;y++)
|
||||||
|
{
|
||||||
|
unsigned int *row=bits+y*totalWidth+clippedRect.left;
|
||||||
|
for (int x=clippedRect.left;x<clippedRect.right;x++,row++)
|
||||||
|
*row=opaqueAlpha|(*row&0xFFFFFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
SelectObject(hdc,m_Bitmap);
|
SelectObject(hdc,m_Bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -207,6 +207,10 @@ LRESULT CSkinSettingsDlg::OnInitDialog( UINT uMsg, WPARAM wParam, LPARAM lParam,
|
|||||||
EnableThemeDialogTexture(m_hWnd,ETDT_ENABLETAB);
|
EnableThemeDialogTexture(m_hWnd,ETDT_ENABLETAB);
|
||||||
|
|
||||||
m_Tree=GetDlgItem(IDC_SKINOPTIONS);
|
m_Tree=GetDlgItem(IDC_SKINOPTIONS);
|
||||||
|
EnableSettingsTreeAccessibility(m_Tree);
|
||||||
|
CString optionsName;
|
||||||
|
GetDlgItemText(IDC_STATICOPT,optionsName);
|
||||||
|
SetSettingsTreeAccessibleName(m_Tree,optionsName);
|
||||||
SetWindowSubclass(m_Tree,SubclassTreeProc,'CLSH',0);
|
SetWindowSubclass(m_Tree,SubclassTreeProc,'CLSH',0);
|
||||||
TreeView_SetImageList(m_Tree,GetSettingsImageList(m_Tree),TVSIL_NORMAL);
|
TreeView_SetImageList(m_Tree,GetSettingsImageList(m_Tree),TVSIL_NORMAL);
|
||||||
m_Tree.SendMessage(TVM_SETEXTENDEDSTYLE,TVS_EX_DOUBLEBUFFER,TVS_EX_DOUBLEBUFFER);
|
m_Tree.SendMessage(TVM_SETEXTENDEDSTYLE,TVS_EX_DOUBLEBUFFER,TVS_EX_DOUBLEBUFFER);
|
||||||
@@ -281,6 +285,7 @@ LRESULT CSkinSettingsDlg::OnInitDialog( UINT uMsg, WPARAM wParam, LPARAM lParam,
|
|||||||
|
|
||||||
LRESULT CSkinSettingsDlg::OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
LRESULT CSkinSettingsDlg::OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
||||||
{
|
{
|
||||||
|
ClearSettingsTreeAccessibility(m_Tree);
|
||||||
m_EditMode=SKIN_OPTION_NONE;
|
m_EditMode=SKIN_OPTION_NONE;
|
||||||
bHandled=FALSE;
|
bHandled=FALSE;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -290,6 +295,7 @@ LRESULT CSkinSettingsDlg::OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BO
|
|||||||
void CSkinSettingsDlg::InitSkinUI( void )
|
void CSkinSettingsDlg::InitSkinUI( void )
|
||||||
{
|
{
|
||||||
m_Tree.SetRedraw(FALSE);
|
m_Tree.SetRedraw(FALSE);
|
||||||
|
ClearSettingsTreeItemAccessibility(m_Tree);
|
||||||
TreeView_DeleteAllItems(m_Tree);
|
TreeView_DeleteAllItems(m_Tree);
|
||||||
m_VariationIndex=-1;
|
m_VariationIndex=-1;
|
||||||
m_EditItemIndex=-1;
|
m_EditItemIndex=-1;
|
||||||
@@ -396,10 +402,12 @@ void CSkinSettingsDlg::UpdateSkinSettings( void )
|
|||||||
{
|
{
|
||||||
item.iImage=item.iSelectedImage=image;
|
item.iImage=item.iSelectedImage=image;
|
||||||
TreeView_SetItem(m_Tree,&item);
|
TreeView_SetItem(m_Tree,&item);
|
||||||
|
NotifyWinEvent(EVENT_OBJECT_STATECHANGE,m_Tree,OBJID_CLIENT,TreeView_MapHTREEITEMToAccID(m_Tree,hVar));
|
||||||
RECT rc;
|
RECT rc;
|
||||||
TreeView_GetItemRect(m_Tree,hVar,&rc,FALSE);
|
TreeView_GetItemRect(m_Tree,hVar,&rc,FALSE);
|
||||||
m_Tree.InvalidateRect(&rc);
|
m_Tree.InvalidateRect(&rc);
|
||||||
}
|
}
|
||||||
|
SetSettingsTreeItemAccessibleRole(m_Tree,hVar,ROLE_SYSTEM_RADIOBUTTON);
|
||||||
}
|
}
|
||||||
hItem=TreeView_GetNextSibling(m_Tree,hItem);
|
hItem=TreeView_GetNextSibling(m_Tree,hItem);
|
||||||
}
|
}
|
||||||
@@ -442,6 +450,8 @@ void CSkinSettingsDlg::UpdateSkinSettings( void )
|
|||||||
item.iImage=item.iSelectedImage=image;
|
item.iImage=item.iSelectedImage=image;
|
||||||
item.mask|=TVIF_TEXT;
|
item.mask|=TVIF_TEXT;
|
||||||
TreeView_SetItem(m_Tree,&item);
|
TreeView_SetItem(m_Tree,&item);
|
||||||
|
NotifyWinEvent(EVENT_OBJECT_STATECHANGE,m_Tree,OBJID_CLIENT,TreeView_MapHTREEITEMToAccID(m_Tree,hItem));
|
||||||
|
SetSettingsTreeItemAccessibleRole(m_Tree,hItem,option.groupId>=0?ROLE_SYSTEM_RADIOBUTTON:ROLE_SYSTEM_CHECKBUTTON);
|
||||||
item.mask&=~TVIF_TEXT;
|
item.mask&=~TVIF_TEXT;
|
||||||
RECT rc;
|
RECT rc;
|
||||||
TreeView_GetItemRect(m_Tree,hItem,&rc,FALSE);
|
TreeView_GetItemRect(m_Tree,hItem,&rc,FALSE);
|
||||||
|
|||||||
@@ -2918,6 +2918,28 @@ bool MenuSkin::LoadSkin( HMODULE hMod, const wchar_t *variation, const wchar_t *
|
|||||||
ItemSettings[COLUMN2_INLINE].bmpIconFrame.bIsOwned=false;
|
ItemSettings[COLUMN2_INLINE].bmpIconFrame.bIsOwned=false;
|
||||||
ItemSettings[COLUMN2_INLINE].bmpSeparator.bIsOwned=false;
|
ItemSettings[COLUMN2_INLINE].bmpSeparator.bIsOwned=false;
|
||||||
|
|
||||||
|
// A skin's "new item" colors must not override the user's High Contrast
|
||||||
|
// palette. This only changes the highlighted-new variants while High
|
||||||
|
// Contrast is active; normal themed rendering remains untouched.
|
||||||
|
HIGHCONTRAST contrast={sizeof(contrast)};
|
||||||
|
if (SystemParametersInfo(SPI_GETHIGHCONTRAST,sizeof(contrast),&contrast,0) && (contrast.dwFlags&HCF_HIGHCONTRASTON))
|
||||||
|
{
|
||||||
|
const int newItems[]={COLUMN1_NEW,COLUMN2_NEW,SUBMENU_NEW,PROGRAMS_TREE_NEW,PROGRAMS_BUTTON_NEW,PROGRAMS_CASCADING_NEW};
|
||||||
|
for (int i=0;i<_countof(newItems);i++)
|
||||||
|
{
|
||||||
|
ItemDrawSettings &settings=ItemSettings[newItems[i]];
|
||||||
|
settings.bmpSelection.Reset(true);
|
||||||
|
settings.bmpSelection=GetSysColor(COLOR_HIGHLIGHT);
|
||||||
|
settings.glowSize=0;
|
||||||
|
for (int j=0;j<_countof(settings.textColors);j++)
|
||||||
|
{
|
||||||
|
settings.textColors[j]=GetSysColor(COLOR_HIGHLIGHTTEXT);
|
||||||
|
settings.textShadowColors[j]=GetSysColor(COLOR_HIGHLIGHT);
|
||||||
|
}
|
||||||
|
settings.arrColors[0]=settings.arrColors[1]=GetSysColor(COLOR_HIGHLIGHTTEXT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HDC hdc=CreateCompatibleDC(NULL);
|
HDC hdc=CreateCompatibleDC(NULL);
|
||||||
HGDIOBJ font0=GetCurrentObject(hdc,OBJ_FONT);
|
HGDIOBJ font0=GetCurrentObject(hdc,OBJ_FONT);
|
||||||
for (int i=0;i<_countof(ItemSettings);i++)
|
for (int i=0;i<_countof(ItemSettings);i++)
|
||||||
|
|||||||
@@ -4229,6 +4229,17 @@ if (!g_bTrimHooks)
|
|||||||
}
|
}
|
||||||
else if (bShowWinX)
|
else if (bShowWinX)
|
||||||
{
|
{
|
||||||
|
// Win+X is shown asynchronously on Windows 11. Cancel any pending
|
||||||
|
// hover-open timer first, otherwise it can open the configured
|
||||||
|
// hover menu a moment later and dismiss Win+X again.
|
||||||
|
if (taskBar->bTimer)
|
||||||
|
{
|
||||||
|
taskBar->bTimer=false;
|
||||||
|
if (taskBar->startButton)
|
||||||
|
KillTimer(taskBar->startButton,'CLSM');
|
||||||
|
if (taskBar->oldButton && taskBar->oldButton!=taskBar->startButton)
|
||||||
|
KillTimer(taskBar->oldButton,'CLSM');
|
||||||
|
}
|
||||||
ShowWinX();
|
ShowWinX();
|
||||||
}
|
}
|
||||||
else if (bShowWin7)
|
else if (bShowWin7)
|
||||||
|
|||||||
Reference in New Issue
Block a user