From 04770c403d4419e673d4fe725d290be0bec78df1 Mon Sep 17 00:00:00 2001 From: ge0rdi Date: Sat, 12 Nov 2022 19:54:29 +0100 Subject: [PATCH] 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 --- Src/Lib/ResourceHelper.cpp | 41 ++ Src/Lib/ResourceHelper.h | 9 + Src/StartMenu/StartMenuDLL/MenuContainer.cpp | 24 +- Src/StartMenu/StartMenuDLL/StartButton.cpp | 50 +-- Src/StartMenu/StartMenuDLL/StartButton.h | 2 +- Src/StartMenu/StartMenuDLL/StartMenuDLL.cpp | 373 +++++++++++-------- Src/StartMenu/StartMenuDLL/StartMenuDLL.h | 6 +- 7 files changed, 295 insertions(+), 210 deletions(-) diff --git a/Src/Lib/ResourceHelper.cpp b/Src/Lib/ResourceHelper.cpp index d7f7db6..525facf 100644 --- a/Src/Lib/ResourceHelper.cpp +++ b/Src/Lib/ResourceHelper.cpp @@ -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((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); +} diff --git a/Src/Lib/ResourceHelper.h b/Src/Lib/ResourceHelper.h index ac7399a..d44eb6b 100644 --- a/Src/Lib/ResourceHelper.h +++ b/Src/Lib/ResourceHelper.h @@ -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'; diff --git a/Src/StartMenu/StartMenuDLL/MenuContainer.cpp b/Src/StartMenu/StartMenuDLL/MenuContainer.cpp index 1f7788b..0de4d05 100644 --- a/Src/StartMenu/StartMenuDLL/MenuContainer.cpp +++ b/Src/StartMenu/StartMenuDLL/MenuContainer.cpp @@ -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) { diff --git a/Src/StartMenu/StartMenuDLL/StartButton.cpp b/Src/StartMenu/StartMenuDLL/StartButton.cpp index 0748274..0ea3dc6 100644 --- a/Src/StartMenu/StartMenuDLL/StartButton.cpp +++ b/Src/StartMenu/StartMenuDLL/StartButton.cpp @@ -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 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; } diff --git a/Src/StartMenu/StartMenuDLL/StartButton.h b/Src/StartMenu/StartMenuDLL/StartButton.h index 13b8686..7ff7ffb 100644 --- a/Src/StartMenu/StartMenuDLL/StartButton.h +++ b/Src/StartMenu/StartMenuDLL/StartButton.h @@ -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 ); diff --git a/Src/StartMenu/StartMenuDLL/StartMenuDLL.cpp b/Src/StartMenu/StartMenuDLL/StartMenuDLL.cpp index cdeca18..6a0ec53 100644 --- a/Src/StartMenu/StartMenuDLL/StartMenuDLL.cpp +++ b/Src/StartMenu/StartMenuDLL/StartMenuDLL.cpp @@ -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.ytaskBar,GWL_EXSTYLE)&WS_EX_LAYOUTRTL) - return pt.x>rc.left; + return pt.y>=rc.top && pt.yrc.left && pt.x<=rc.right; else - return pt.x=rc.left && pt.xtaskbarId) != 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 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.rightinfo.rcMonitor.right-5); - else if (uEdge==ABE_TOP) - bHide=(rcTask.bottominfo.rcMonitor.bottom-5); - if (bHide) - buttonFlags=(buttonFlags&~SWP_SHOWWINDOW)|SWP_HIDEWINDOW; - } - if (uEdge==ABE_TOP || uEdge==ABE_BOTTOM) - { - if (rcTask.leftinfo.rcMonitor.right) rcTask.right=info.rcMonitor.right; - } - else - { - if (rcTask.toptaskbarId)) - { - bool bClassic; - if (GetWinVersion()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()info.rcMonitor.right) rcTask2.right=info.rcMonitor.right; - } - else - { - if (rcTask2.topRelease(); @@ -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()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 ) { diff --git a/Src/StartMenu/StartMenuDLL/StartMenuDLL.h b/Src/StartMenu/StartMenuDLL/StartMenuDLL.h index 2601727..fb27b98 100644 --- a/Src/StartMenu/StartMenuDLL/StartMenuDLL.h +++ b/Src/StartMenu/StartMenuDLL/StartMenuDLL.h @@ -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 trayButtons; // ordered by Z order (for win10)