Windows 11 start menu button support

- handling of `Taskbar alignment` setting (left/center)
  - start menu position is based on position of start button
  - mouse clicks to original button now work properly (without triggering original menu)
  - custom button is properly positioned
  - Win+X works properly
This commit is contained in:
ge0rdi
2022-11-12 19:54:29 +01:00
parent f42980e090
commit 04770c403d
7 changed files with 295 additions and 210 deletions

View File

@@ -733,6 +733,19 @@ bool IsWin10RS4( void )
return bIsRS4;
}
static bool IsWin11Helper()
{
auto version = GetOSVersion();
return version.dwMajorVersion >= 10 && version.dwBuildNumber >= 22000;
}
// Returns true if the version is Windows11 or later
bool IsWin11(void)
{
static bool bIsWin11 = IsWin11Helper();
return bIsWin11;
}
// Wrapper for IShellFolder::ParseDisplayName
HRESULT ShParseDisplayName( const wchar_t *pszName, PIDLIST_ABSOLUTE *ppidl, SFGAOF sfgaoIn, SFGAOF *psfgaoOut )
{
@@ -909,3 +922,31 @@ HFONT CreateFontSetting( const wchar_t *fontStr, int dpi )
int size=-_wtol(token);
return CreateFont(size*dpi/72,0,0,0,weight,bItalic?1:0,0,0,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,name);
}
static UINT WINAPI GetDpiForWindow(HWND hwnd)
{
static auto p = static_cast<decltype(&GetDpiForWindow)>((void*)GetProcAddress(GetModuleHandle(L"user32.dll"), "GetDpiForWindow"));
if (p)
return p(hwnd);
return 0;
}
UINT GetDpi(HWND hwnd)
{
UINT dpi = GetDpiForWindow(hwnd);
if (!dpi)
{
// fall-back for older systems
HDC hdc = GetDC(nullptr);
dpi = GetDeviceCaps(hdc, LOGPIXELSY);
ReleaseDC(nullptr, hdc);
}
return dpi;
}
int ScaleForDpi(HWND hwnd, int value)
{
return MulDiv(value, GetDpi(hwnd), USER_DEFAULT_SCREEN_DPI);
}

View File

@@ -67,6 +67,9 @@ bool IsWin10RS1( void );
// Returns true if the version is Windows10 RS4 (Spring Creator Update) or later
bool IsWin10RS4( void );
// Returns true if the version is Windows11 or later
bool IsWin11();
// Wrapper for IShellFolder::ParseDisplayName
HRESULT ShParseDisplayName( const wchar_t *pszName, PIDLIST_ABSOLUTE *ppidl, SFGAOF sfgaoIn, SFGAOF *psfgaoOut );
@@ -82,6 +85,12 @@ void StringUpper( CString &str );
// Create a font from the user settings
HFONT CreateFontSetting( const wchar_t *fontStr, int dpi );
// Return DPI of given window (or system DPI on older systems)
UINT GetDpi(HWND hwnd = nullptr);
// Scale given value according to DPI of window
int ScaleForDpi(HWND hwnd, int value);
extern HINSTANCE g_Instance;
const int ANIM_BUTTON_TAG1='ANM';

View File

@@ -345,7 +345,8 @@ 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;
HWND CMenuContainer::s_TaskBar;
HWND CMenuContainer::s_StartButton; // custom start button (if any)
UINT CMenuContainer::s_TaskBarEdge;
RECT CMenuContainer::s_StartRect;
HWND CMenuContainer::s_LastFGWindow;
@@ -7507,6 +7508,7 @@ RECT CMenuContainer::CalculateWorkArea( const RECT &taskbarRect )
return rc;
}
// Calculates start menu position
POINT CMenuContainer::CalculateCorner( void )
{
RECT margin={0,0,0,0};
@@ -7514,10 +7516,24 @@ POINT CMenuContainer::CalculateCorner( void )
AdjustWindowRect(&margin,GetWindowLong(GWL_STYLE),FALSE);
POINT corner;
if (m_Options&CONTAINER_LEFT)
corner.x=s_MainMenuLimits.left+margin.left;
if (IsWin11())
{
// start button can be in the center on Win11
// we want to show menu at the position of start button
if (m_Options&CONTAINER_LEFT)
corner.x=s_StartRect.left+margin.left;
else
corner.x=s_StartRect.right+margin.right;
}
else
corner.x=s_MainMenuLimits.right+margin.right;
{
// start button can be only in corner on older systems
// we can use screen limits to determine menu position
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)
{

View File

@@ -154,6 +154,7 @@ LRESULT CStartButton::OnCreate( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& b
OnThemeChanged(WM_THEMECHANGED,0,0,bHandled);
m_bPressed=true;
SetPressed(false);
ResizeClient(m_Size.cx,m_Size.cy);
bHandled=FALSE;
return 0;
}
@@ -534,12 +535,12 @@ void CStartButton::LoadBitmap( void )
if (!m_Bitmap)
{
int id;
int dpi=CItemManager::GetDPI(false);
int dpi=GetDpi(GetParent());
if (dpi<120)
id=IDB_BUTTON96;
else if (dpi<144)
id=IDB_BUTTON120;
else if (dpi<180)
else if (dpi<168)
id=IDB_BUTTON144;
else
id=IDB_BUTTON180;
@@ -604,55 +605,12 @@ void CStartButton::LoadBitmap( void )
static std::map<int,CStartButton> g_StartButtons;
HWND CreateStartButton( int taskbarId, HWND taskBar, HWND rebar, const RECT &rcTask )
HWND CreateStartButton( int taskbarId, HWND taskBar, HWND rebar )
{
bool bRTL=(GetWindowLongPtr(rebar,GWL_EXSTYLE)&WS_EX_LAYOUTRTL)!=0;
DWORD styleTopmost=GetWindowLongPtr(taskBar,GWL_EXSTYLE)&WS_EX_TOPMOST;
CStartButton &button=g_StartButtons[taskbarId];
button.Create(taskBar,NULL,NULL,WS_POPUP,styleTopmost|WS_EX_TOOLWINDOW|WS_EX_LAYERED,0U,(void*)(intptr_t)(taskbarId*2+(bRTL?1:0)));
SIZE size=button.GetSize();
RECT rcButton;
MONITORINFO info;
UINT uEdge=GetTaskbarPosition(taskBar,&info,NULL,NULL);
if (uEdge==ABE_LEFT || uEdge==ABE_RIGHT)
{
if (GetSettingInt(L"StartButtonType")!=START_BUTTON_CUSTOM || !GetSettingBool(L"StartButtonAlign"))
rcButton.left=(rcTask.left+rcTask.right-size.cx)/2;
else if (uEdge==ABE_LEFT)
rcButton.left=rcTask.left;
else
rcButton.left=rcTask.right-size.cx;
rcButton.top=rcTask.top;
}
else
{
if (bRTL)
rcButton.left=rcTask.right-size.cx;
else
rcButton.left=rcTask.left;
if (GetSettingInt(L"StartButtonType")!=START_BUTTON_CUSTOM || !GetSettingBool(L"StartButtonAlign"))
rcButton.top=(rcTask.top+rcTask.bottom-size.cy)/2;
else if (uEdge==ABE_TOP)
rcButton.top=rcTask.top;
else
rcButton.top=rcTask.bottom-size.cy;
}
rcButton.right=rcButton.left+size.cx;
rcButton.bottom=rcButton.top+size.cy;
g_bAllowMoveButton=true;
button.SetWindowPos(HWND_TOP,&rcButton,SWP_SHOWWINDOW|SWP_NOOWNERZORDER|SWP_NOACTIVATE);
g_bAllowMoveButton=false;
RECT rc;
IntersectRect(&rc,&rcButton,&info.rcMonitor);
HRGN rgn=CreateRectRgn(rc.left-rcButton.left,rc.top-rcButton.top,rc.right-rcButton.left,rc.bottom-rcButton.top);
if (!SetWindowRgn(button,rgn,FALSE))
{
AddTrackedObject(rgn);
DeleteObject(rgn);
}
button.UpdateButton();
return button.m_hWnd;
}

View File

@@ -12,7 +12,7 @@ enum TStartButtonType
// START_BUTTON_METRO,
};
HWND CreateStartButton( int taskbarId, HWND taskBar, HWND rebar, const RECT &rcTask );
HWND CreateStartButton( int taskbarId, HWND taskBar, HWND rebar );
void DestroyStartButton( int taskbarId );
void UpdateStartButton( int taskbarId );
void PressStartButton( int taskbarId, bool bPressed );

View File

@@ -47,7 +47,7 @@ static HWND g_Tooltip;
static TOOLINFO g_StartButtonTool;
static bool g_bHotkeyShift;
static int g_HotkeyCSM, g_HotkeyWSM, g_HotkeyShiftID, g_HotkeyCSMID, g_HotkeyWSMID;
static HHOOK g_ProgHook, g_StartHook, g_AppManagerHook, g_NewWindowHook, g_StartMenuHook;
static HHOOK g_ProgHook, g_StartHook, g_StartMouseHook, g_AppManagerHook, g_NewWindowHook, g_StartMenuHook;
static bool g_bAllProgramsTimer;
static bool g_bInMenu;
static DWORD g_LastClickTime;
@@ -402,6 +402,7 @@ static TaskbarInfo *FindTaskBarInfoBar( HWND bar )
static LRESULT CALLBACK HookProgManThread( int code, WPARAM wParam, LPARAM lParam );
static LRESULT CALLBACK HookDesktopThread( int code, WPARAM wParam, LPARAM lParam );
static LRESULT CALLBACK HookDesktopThreadMouse(int code, WPARAM wParam, LPARAM lParam);
static BOOL CALLBACK FindTooltipEnum( HWND hwnd, LPARAM lParam )
{
@@ -671,21 +672,45 @@ UINT GetTaskbarPosition( HWND taskBar, MONITORINFO *pInfo, HMONITOR *pMonitor, R
bool PointAroundStartButton( size_t taskbarId, const CPoint &pt )
{
const TaskbarInfo *taskBar=GetTaskbarInfo(taskbarId);
if (!taskBar || !taskBar->startButton) return false;
RECT rc;
if (!taskBar || !(taskBar->startButton || taskBar->oldButton)) return false;
CRect rc;
GetWindowRect(taskBar->taskBar,&rc);
if (!PtInRect(&rc,pt))
return false;
UINT uEdge=GetTaskbarPosition(taskBar->taskBar,NULL,NULL,NULL);
bool rtl=GetWindowLongPtr(taskBar->taskBar,GWL_EXSTYLE)&WS_EX_LAYOUTRTL;
CRect rcStart;
if (taskBar->startButton)
GetWindowRect(taskBar->startButton,&rcStart);
CRect rcOld;
if (taskBar->oldButton)
{
GetWindowRect(taskBar->oldButton,&rcOld);
if (IsWin11())
{
// on Win11 the Start button rectangle is a bit smaller that actual XAML active area
// lets make it a bit wider to avoid accidental original Start menu triggers
const int adjust=ScaleForDpi(taskBar->taskBar,1);
if (rtl)
rcOld.left-=adjust;
else
rcOld.right+=adjust;
}
}
rc.UnionRect(&rcStart,&rcOld);
// check if the point is inside the start button rect
GetWindowRect(taskBar->startButton,&rc);
UINT uEdge=GetTaskbarPosition(taskBar->taskBar,NULL,NULL,NULL);
if (uEdge==ABE_LEFT || uEdge==ABE_RIGHT)
return pt.y<rc.bottom;
else if (GetWindowLongPtr(taskBar->taskBar,GWL_EXSTYLE)&WS_EX_LAYOUTRTL)
return pt.x>rc.left;
return pt.y>=rc.top && pt.y<rc.bottom;
else if (rtl)
return pt.x>rc.left && pt.x<=rc.right;
else
return pt.x<rc.right;
return pt.x>=rc.left && pt.x<rc.right;
}
// declare few interfaces so we don't need the Win8 SDK
@@ -1186,24 +1211,156 @@ void EnableHotkeys( THotkeys enable )
}
}
static void UpdateStartButtonPosition(const TaskbarInfo* taskBar, const WINDOWPOS* pPos)
{
if (IsStartButtonSmallIcons(taskBar->taskbarId) != IsTaskbarSmallIcons())
RecreateStartButton(taskBar->taskbarId);
RECT rcTask;
GetWindowRect(taskBar->taskBar, &rcTask);
MONITORINFO info;
UINT uEdge = GetTaskbarPosition(taskBar->taskBar, &info, NULL, NULL);
DWORD buttonFlags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE;
if (IsWindowVisible(taskBar->taskBar))
buttonFlags |= SWP_SHOWWINDOW;
else
buttonFlags |= SWP_HIDEWINDOW;
APPBARDATA appbar = { sizeof(appbar) };
if (SHAppBarMessage(ABM_GETSTATE, &appbar) & ABS_AUTOHIDE)
{
bool bHide = false;
if (uEdge == ABE_LEFT)
bHide = (rcTask.right < info.rcMonitor.left + 5);
else if (uEdge == ABE_RIGHT)
bHide = (rcTask.left > info.rcMonitor.right - 5);
else if (uEdge == ABE_TOP)
bHide = (rcTask.bottom < info.rcMonitor.top + 5);
else
bHide = (rcTask.top > info.rcMonitor.bottom - 5);
if (bHide)
buttonFlags = (buttonFlags & ~SWP_SHOWWINDOW) | SWP_HIDEWINDOW;
}
if (uEdge == ABE_TOP || uEdge == ABE_BOTTOM)
{
if (rcTask.left < info.rcMonitor.left) rcTask.left = info.rcMonitor.left;
if (rcTask.right > info.rcMonitor.right) rcTask.right = info.rcMonitor.right;
}
else
{
if (rcTask.top < info.rcMonitor.top) rcTask.top = info.rcMonitor.top;
}
HWND zPos = NULL;
if (pPos->flags & SWP_NOZORDER)
buttonFlags |= SWP_NOZORDER;
else
{
zPos = pPos->hwndInsertAfter;
if (zPos == HWND_TOP && !(GetWindowLongPtr(taskBar->startButton, GWL_EXSTYLE) & WS_EX_TOPMOST))
zPos = HWND_TOPMOST;
if (zPos == HWND_TOPMOST && !(GetWindowLongPtr(taskBar->taskBar, GWL_EXSTYLE) & WS_EX_TOPMOST))
zPos = HWND_TOP;
if (zPos == HWND_BOTTOM)
buttonFlags |= SWP_NOZORDER;
if (zPos == taskBar->startButton)
buttonFlags |= SWP_NOZORDER;
}
if (!IsStartButtonSmallIcons(taskBar->taskbarId))
{
bool bClassic;
if (GetWinVersion() < WIN_VER_WIN8)
bClassic = !IsAppThemed();
else
{
HIGHCONTRAST contrast = { sizeof(contrast) };
bClassic = (SystemParametersInfo(SPI_GETHIGHCONTRAST, sizeof(contrast), &contrast, 0) && (contrast.dwFlags & HCF_HIGHCONTRASTON));
}
if (!bClassic)
{
if (uEdge == ABE_TOP)
OffsetRect(&rcTask, 0, -1);
else if (uEdge == ABE_BOTTOM)
OffsetRect(&rcTask, 0, 1);
}
}
RECT rcOldButton;
if (taskBar->oldButton)
GetWindowRect(taskBar->oldButton, &rcOldButton);
int x, y;
if (uEdge == ABE_LEFT || uEdge == ABE_RIGHT)
{
if (GetSettingInt(L"StartButtonType") != START_BUTTON_CUSTOM || !GetSettingBool(L"StartButtonAlign"))
x = (rcTask.left + rcTask.right - taskBar->startButtonSize.cx) / 2;
else if (uEdge == ABE_LEFT)
x = rcTask.left;
else
x = rcTask.right - taskBar->startButtonSize.cx;
y = taskBar->oldButton ? rcOldButton.top : rcTask.top;
}
else
{
if (GetWindowLongPtr(taskBar->rebar, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
x = (taskBar->oldButton ? rcOldButton.right : rcTask.right) - taskBar->startButtonSize.cx;
else
x = taskBar->oldButton ? rcOldButton.left : rcTask.left;
if (GetSettingInt(L"StartButtonType") != START_BUTTON_CUSTOM || !GetSettingBool(L"StartButtonAlign"))
y = (rcTask.top + rcTask.bottom - taskBar->startButtonSize.cy) / 2;
else if (uEdge == ABE_TOP)
y = rcTask.top;
else
y = rcTask.bottom - taskBar->startButtonSize.cy;
}
// Start button on Win11 is a bit shifted to the right
// We will shift our Aero button to cover original button
if (IsWin11() && (x == 0) && (GetStartButtonType() == START_BUTTON_AERO))
x += ScaleForDpi(taskBar->taskBar, 6);
RECT rcButton = { x, y, x + taskBar->startButtonSize.cx, y + taskBar->startButtonSize.cy };
RECT rc;
IntersectRect(&rc, &rcButton, &info.rcMonitor);
HRGN rgn = CreateRectRgn(rc.left - x, rc.top - y, rc.right - x, rc.bottom - y);
if (!SetWindowRgn(taskBar->startButton, rgn, FALSE))
{
AddTrackedObject(rgn);
DeleteObject(rgn);
}
SetWindowPos(taskBar->startButton, zPos, x, y, 0, 0, buttonFlags);
if (buttonFlags & SWP_SHOWWINDOW)
UpdateStartButton(taskBar->taskbarId);
}
static LRESULT CALLBACK SubclassWin81StartButton( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
{
TaskbarInfo* taskBar = GetTaskbarInfo((int)dwRefData);
if (uMsg==WM_WINDOWPOSCHANGING)
{
// keep the original start button hidden at all times
const TaskbarInfo *taskBar=GetTaskbarInfo((int)dwRefData);
if (taskBar && taskBar->bHideButton)
{
((WINDOWPOS*)lParam)->flags&=~SWP_SHOWWINDOW;
}
}
if (uMsg==WM_WINDOWPOSCHANGED)
{
if (taskBar && taskBar->bReplaceButton)
{
UpdateStartButtonPosition(taskBar,(WINDOWPOS*)lParam);
}
}
if (uMsg==WM_SIZE)
{
RECT rc;
GetWindowRect(hWnd,&rc);
rc.right-=rc.left;
rc.bottom-=rc.top;
TaskbarInfo *taskBar=GetTaskbarInfo((int)dwRefData);
if (taskBar && (taskBar->oldButtonSize.cx!=rc.right || taskBar->oldButtonSize.cy!=rc.bottom))
{
taskBar->oldButtonSize.cx=rc.right;
@@ -1467,6 +1624,15 @@ static void ComputeTaskbarColors( int *data )
static void ShowWinX( void )
{
if (IsWin11())
{
HWND hwnd=FindWindowEx(NULL,NULL,L"Shell_TrayWnd",NULL);
if (hwnd)
PostMessage(hwnd,WM_HOTKEY,590,MAKELPARAM(MOD_WIN,'X'));
return;
}
if (GetWinVersion()>=WIN_VER_WIN10)
{
CComPtr<IUnknown> pImmersiveShell;
@@ -1651,116 +1817,7 @@ static LRESULT CALLBACK SubclassTaskBarProc( HWND hWnd, UINT uMsg, WPARAM wParam
{
if (taskBar->bReplaceButton)
{
if (IsStartButtonSmallIcons(taskBar->taskbarId)!=IsTaskbarSmallIcons())
RecreateStartButton((int)dwRefData);
WINDOWPOS *pPos=(WINDOWPOS*)lParam;
RECT rcTask;
GetWindowRect(hWnd,&rcTask);
MONITORINFO info;
UINT uEdge=GetTaskbarPosition(hWnd,&info,NULL,NULL);
DWORD buttonFlags=SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSIZE;
if (IsWindowVisible(taskBar->taskBar))
buttonFlags|=SWP_SHOWWINDOW;
else
buttonFlags|=SWP_HIDEWINDOW;
APPBARDATA appbar={sizeof(appbar)};
if (SHAppBarMessage(ABM_GETSTATE,&appbar)&ABS_AUTOHIDE)
{
bool bHide=false;
if (uEdge==ABE_LEFT)
bHide=(rcTask.right<info.rcMonitor.left+5);
else if (uEdge==ABE_RIGHT)
bHide=(rcTask.left>info.rcMonitor.right-5);
else if (uEdge==ABE_TOP)
bHide=(rcTask.bottom<info.rcMonitor.top+5);
else
bHide=(rcTask.top>info.rcMonitor.bottom-5);
if (bHide)
buttonFlags=(buttonFlags&~SWP_SHOWWINDOW)|SWP_HIDEWINDOW;
}
if (uEdge==ABE_TOP || uEdge==ABE_BOTTOM)
{
if (rcTask.left<info.rcMonitor.left) rcTask.left=info.rcMonitor.left;
if (rcTask.right>info.rcMonitor.right) rcTask.right=info.rcMonitor.right;
}
else
{
if (rcTask.top<info.rcMonitor.top) rcTask.top=info.rcMonitor.top;
}
if (!IsStartButtonSmallIcons(taskBar->taskbarId))
{
bool bClassic;
if (GetWinVersion()<WIN_VER_WIN8)
bClassic=!IsAppThemed();
else
{
HIGHCONTRAST contrast={sizeof(contrast)};
bClassic=(SystemParametersInfo(SPI_GETHIGHCONTRAST,sizeof(contrast),&contrast,0) && (contrast.dwFlags&HCF_HIGHCONTRASTON));
}
if (!bClassic)
{
if (uEdge==ABE_TOP)
OffsetRect(&rcTask,0,-1);
else if (uEdge==ABE_BOTTOM)
OffsetRect(&rcTask,0,1);
}
}
HWND zPos=NULL;
if (pPos->flags&SWP_NOZORDER)
buttonFlags|=SWP_NOZORDER;
else
{
zPos=pPos->hwndInsertAfter;
if (zPos==HWND_TOP && !(GetWindowLongPtr(taskBar->startButton,GWL_EXSTYLE)&WS_EX_TOPMOST))
zPos=HWND_TOPMOST;
if (zPos==HWND_TOPMOST && !(GetWindowLongPtr(hWnd,GWL_EXSTYLE)&WS_EX_TOPMOST))
zPos=HWND_TOP;
if (zPos==HWND_BOTTOM)
buttonFlags|=SWP_NOZORDER;
if (zPos==taskBar->startButton)
buttonFlags|=SWP_NOZORDER;
}
int x, y;
if (uEdge==ABE_LEFT || uEdge==ABE_RIGHT)
{
if (GetSettingInt(L"StartButtonType")!=START_BUTTON_CUSTOM || !GetSettingBool(L"StartButtonAlign"))
x=(rcTask.left+rcTask.right-taskBar->startButtonSize.cx)/2;
else if (uEdge==ABE_LEFT)
x=rcTask.left;
else
x=rcTask.right-taskBar->startButtonSize.cx;
y=rcTask.top;
}
else
{
if (GetWindowLongPtr(taskBar->rebar,GWL_EXSTYLE)&WS_EX_LAYOUTRTL)
x=rcTask.right-taskBar->startButtonSize.cx;
else
x=rcTask.left;
if (GetSettingInt(L"StartButtonType")!=START_BUTTON_CUSTOM || !GetSettingBool(L"StartButtonAlign"))
y=(rcTask.top+rcTask.bottom-taskBar->startButtonSize.cy)/2;
else if (uEdge==ABE_TOP)
y=rcTask.top;
else
y=rcTask.bottom-taskBar->startButtonSize.cy;
}
RECT rcButton={x,y,x+taskBar->startButtonSize.cx,y+taskBar->startButtonSize.cy};
RECT rc;
IntersectRect(&rc,&rcButton,&info.rcMonitor);
HRGN rgn=CreateRectRgn(rc.left-x,rc.top-y,rc.right-x,rc.bottom-y);
if (!SetWindowRgn(taskBar->startButton,rgn,FALSE))
{
AddTrackedObject(rgn);
DeleteObject(rgn);
}
g_bAllowMoveButton=true;
SetWindowPos(taskBar->startButton,zPos,x,y,0,0,buttonFlags);
g_bAllowMoveButton=false;
if (buttonFlags&SWP_SHOWWINDOW)
UpdateStartButton(taskBar->taskbarId);
UpdateStartButtonPosition(taskBar,(WINDOWPOS*)lParam);
}
if (taskBar->oldButton && GetWinVersion()<WIN_VER_WIN10)
{
@@ -2872,6 +2929,9 @@ static void InitStartMenuDLL( void )
DWORD progThread=GetWindowThreadProcessId(g_ProgWin,NULL);
g_ProgHook=SetWindowsHookEx(WH_GETMESSAGE,HookProgManThread,NULL,progThread);
g_StartHook=SetWindowsHookEx(WH_GETMESSAGE,HookDesktopThread,NULL,GetCurrentThreadId());
if (IsWin11())
g_StartMouseHook=SetWindowsHookEx(WH_MOUSE,HookDesktopThreadMouse,NULL,GetCurrentThreadId());
HWND hwnd=FindWindow(L"OpenShellMenu.CStartHookWindow",L"StartHookWindow");
LoadLibrary(L"StartMenuDLL.dll"); // keep the DLL from unloading
if (hwnd) PostMessage(hwnd,WM_CLEAR,0,0); // tell the exe to unhook this hook
@@ -2993,39 +3053,6 @@ static void RecreateStartButton( size_t taskbarId )
continue;
if (taskBar.bRecreatingButton)
continue;
RECT rcTask;
GetWindowRect(taskBar.taskBar,&rcTask);
RECT rcTask2=rcTask;
MONITORINFO info;
UINT uEdge=GetTaskbarPosition(taskBar.taskBar,&info,NULL,NULL);
if (uEdge==ABE_TOP || uEdge==ABE_BOTTOM)
{
if (rcTask2.left<info.rcMonitor.left) rcTask2.left=info.rcMonitor.left;
if (rcTask2.right>info.rcMonitor.right) rcTask2.right=info.rcMonitor.right;
}
else
{
if (rcTask2.top<info.rcMonitor.top) rcTask2.top=info.rcMonitor.top;
}
if (!IsTaskbarSmallIcons())
{
bool bClassic;
if (GetWinVersion()<WIN_VER_WIN8)
bClassic=!IsAppThemed();
else
{
HIGHCONTRAST contrast={sizeof(contrast)};
bClassic=(SystemParametersInfo(SPI_GETHIGHCONTRAST,sizeof(contrast),&contrast,0) && (contrast.dwFlags&HCF_HIGHCONTRASTON));
}
if (!bClassic)
{
if (uEdge==ABE_TOP)
OffsetRect(&rcTask2,0,-1);
else if (uEdge==ABE_BOTTOM)
OffsetRect(&rcTask2,0,1);
}
}
taskBar.bRecreatingButton=true;
{
@@ -3034,7 +3061,7 @@ static void RecreateStartButton( size_t taskbarId )
RevokeDragDrop(taskBar.startButton);
DestroyStartButton(taskBar.taskbarId);
}
taskBar.startButton=CreateStartButton(taskBar.taskbarId,taskBar.taskBar,taskBar.rebar,rcTask2);
taskBar.startButton=CreateStartButton(taskBar.taskbarId,taskBar.taskBar,taskBar.rebar);
CStartMenuTarget *pNewTarget=new CStartMenuTarget(taskBar.taskbarId);
RegisterDragDrop(taskBar.startButton,pNewTarget);
pNewTarget->Release();
@@ -3050,6 +3077,8 @@ static void RecreateStartButton( size_t taskbarId )
taskBar.oldButtonSize.cy=rc.bottom-rc.top;
}
RECT rcTask;
GetWindowRect(taskBar.taskBar,&rcTask);
PostMessage(taskBar.taskBar,WM_SIZE,SIZE_RESTORED,MAKELONG(rcTask.right-rcTask.left,rcTask.bottom-rcTask.top));
}
}
@@ -3099,6 +3128,8 @@ static void CleanStartMenuDLL( void )
HWND hwnd=FindWindow(L"OpenShellMenu.CStartHookWindow",L"StartHookWindow");
UnhookWindowsHookEx(g_ProgHook);
UnhookWindowsHookEx(g_StartHook);
if (g_StartMouseHook) UnhookWindowsHookEx(g_StartMouseHook);
g_StartMouseHook=NULL;
if (g_AppManagerHook) UnhookWindowsHookEx(g_AppManagerHook);
g_AppManagerHook=NULL;
if (g_NewWindowHook) UnhookWindowsHookEx(g_NewWindowHook);
@@ -3120,7 +3151,8 @@ static void CleanStartMenuDLL( void )
if (it->second.oldButton)
{
RemoveWindowSubclass(it->second.oldButton,SubclassWin81StartButton,'CLSH');
SetWindowPos(it->second.oldButton,NULL,0,0,0,0,SWP_NOSIZE|SWP_NOZORDER);
if (GetWinVersion()<WIN_VER_WIN10 && GetTaskbarPosition(it->second.taskBar,NULL,NULL,NULL)==ABE_BOTTOM)
SetWindowPos(it->second.oldButton,NULL,0,0,0,0,SWP_NOSIZE|SWP_NOZORDER);
RevokeDragDrop(it->second.oldButton);
if (it->second.pOriginalTarget)
RegisterDragDrop(it->second.oldButton,it->second.pOriginalTarget);
@@ -3383,6 +3415,35 @@ static LRESULT CALLBACK HookProgManThread( int code, WPARAM wParam, LPARAM lPara
return CallNextHookEx(NULL,code,wParam,lParam);
}
// WH_MOUSE hook for taskbar thread (Win11+)
static LRESULT CALLBACK HookDesktopThreadMouse(int code, WPARAM wParam, LPARAM lParam)
{
if (code == HC_ACTION)
{
// we need to steal mouse messages that are issues in start button area
// so that they won't get to XAML framework that is handling original start button
auto info = (const MOUSEHOOKSTRUCT*)lParam;
{
auto taskBar = FindTaskBarInfoButton(info->hwnd); // click on start button
if (!taskBar)
{
taskBar = FindTaskBarInfoBar(GetAncestor(info->hwnd, GA_ROOT)); // click on taskbar
if (taskBar && !PointAroundStartButton(taskBar->taskbarId))
taskBar = NULL;
}
if (taskBar && (info->hwnd != taskBar->startButton) && taskBar->oldButton)
{
// steal messages from other than our custom button window
PostMessage(taskBar->oldButton, (UINT)wParam, 0, MAKELPARAM(info->pt.x, info->pt.y));
return 1;
}
}
}
return CallNextHookEx(NULL, code, wParam, lParam);
}
// WH_GETMESSAGE hook for the taskbar thread
static LRESULT CALLBACK HookDesktopThread( int code, WPARAM wParam, LPARAM lParam )
{

View File

@@ -51,7 +51,7 @@ struct TaskbarInfo
int taskbarId;
HWND taskBar;
HWND startButton; // either own start button or the win7 start button (depending on bReplaceButton)
HWND oldButton; // win81 start button (child of taskBar)
HWND oldButton; // win8.1+ start button (child of taskBar)
HWND rebar;
HWND taskList;
HWND chevron;
@@ -61,8 +61,8 @@ struct TaskbarInfo
int pointerId;
bool bTimer;
bool bCustomLook;
bool bReplaceButton;
bool bHideButton;
bool bReplaceButton; // replace start button with own one
bool bHideButton; // hide old start button (if we have own button)
bool bRecreatingButton;
bool bThemeChanging;
std::vector<HWND> trayButtons; // ordered by Z order (for win10)