mirror of
https://github.com/Open-Shell/Open-Shell-Menu.git
synced 2026-04-11 17:37:22 +10:00
Windows 11 22H2 introduced new touch-optimized taskbar for devices with touch screen. It seems that in this mode taskbar window size is bigger than actual taskbar on screen. There is region defined for the window that covers actually displayed portion of the window. We should account for that region (if present) when obtaining taskbar window dimensions. More info about how to enable/disable touch taskbar: https://www.elevenforum.com/t/turn-on-or-off-tablet-optimized-taskbar-in-windows-11.5133/
4296 lines
135 KiB
C++
4296 lines
135 KiB
C++
// Classic Shell (c) 2009-2017, Ivo Beltchev
|
|
// Open-Shell (c) 2017-2018, The Open-Shell Team
|
|
// Confidential information of Ivo Beltchev. Not for disclosure or distribution without prior written consent from the author
|
|
|
|
#include "stdafx.h"
|
|
#include "resource.h"
|
|
#include "StartMenuDLL.h"
|
|
#include "StartButton.h"
|
|
#include "MenuContainer.h"
|
|
#include "SettingsParser.h"
|
|
#include "Translations.h"
|
|
#include "Settings.h"
|
|
#include "SettingsUI.h"
|
|
#include "ResourceHelper.h"
|
|
#include "LogManager.h"
|
|
#include "TouchHelper.h"
|
|
#include "IatHookHelper.h"
|
|
#include "dllmain.h"
|
|
#include <uxtheme.h>
|
|
#include <dwmapi.h>
|
|
#include <htmlhelp.h>
|
|
#include <dbghelp.h>
|
|
#include <set>
|
|
#include <Thumbcache.h>
|
|
|
|
#define HOOK_DROPTARGET // define this to replace the IDropTarget of the start button
|
|
#define START_TOUCH // touch support for the start button
|
|
|
|
#ifdef BUILD_SETUP
|
|
#ifndef HOOK_DROPTARGET
|
|
#define HOOK_DROPTARGET // make sure it is defined in Setup
|
|
#endif
|
|
#endif
|
|
|
|
const int MAIN_TASK_BAR=0;
|
|
typedef std::map<size_t,TaskbarInfo> id_taskbar_map;
|
|
id_taskbar_map g_TaskbarInfos;
|
|
static int g_LastTaskbar=MAIN_TASK_BAR;
|
|
static int g_NextTaskbar=0;
|
|
HWND g_TaskBar, g_OwnerWindow;
|
|
HWND g_TopWin7Menu, g_AllPrograms, g_ProgramsButton, g_UserPic; // from the Windows menu
|
|
HWND g_ProgWin;
|
|
HMONITOR g_WSMHMonitor;
|
|
static HWND g_WinStartButton;
|
|
static UINT g_StartMenuMsg;
|
|
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_StartMouseHook, g_AppManagerHook, g_NewWindowHook, g_StartMenuHook;
|
|
static bool g_bAllProgramsTimer;
|
|
static bool g_bInMenu;
|
|
static DWORD g_LastClickTime;
|
|
static DWORD g_LastHoverPos;
|
|
static bool g_bCrashDump;
|
|
static int g_SkipMetroCount;
|
|
static DWORD g_StartButtonOldSizes[12];
|
|
const int FIRST_BUTTON_BITMAP=6801;
|
|
static HWND g_TopDesktopBar;
|
|
static DWORD g_AppManagerThread;
|
|
static std::set<HWND> g_EdgeWindows;
|
|
static bool g_bTrimHooks;
|
|
static DWORD g_TaskbarThreadId;
|
|
static HWND g_CurrentTaskList, g_CurrentTaskChevron, g_CurrentRebar, g_CurrentTaskbarPart, g_CurrentTaskbarButton, g_CurrentDesktopButton;
|
|
static HBITMAP g_TaskbarTexture;
|
|
static SIZE g_TaskbarTextureSize;
|
|
static TTaskbarTile g_TaskbarTileH, g_TaskbarTileV;
|
|
static RECT g_TaskbarMargins;
|
|
int g_CurrentCSMTaskbar=-1, g_CurrentWSMTaskbar=-1;
|
|
|
|
static void FindWindowsMenu( void );
|
|
static void RecreateStartButton( size_t taskbarId );
|
|
static bool WindowsMenuOpened( void );
|
|
|
|
static tSetWindowCompositionAttribute SetWindowCompositionAttribute;
|
|
|
|
enum
|
|
{
|
|
OPEN_NOTHING,
|
|
OPEN_CLASSIC,
|
|
OPEN_WINDOWS,
|
|
OPEN_CUSTOM,
|
|
OPEN_BOTH,
|
|
OPEN_DESKTOP,
|
|
OPEN_CORTANA,
|
|
};
|
|
|
|
// MiniDumpNormal - minimal information
|
|
// MiniDumpWithDataSegs - include global variables
|
|
// MiniDumpWithFullMemory - include heap
|
|
MINIDUMP_TYPE MiniDumpType=MiniDumpNormal;
|
|
|
|
static DWORD WINAPI SaveCrashDump( void *pExceptionInfo )
|
|
{
|
|
HMODULE dbghelp=NULL;
|
|
{
|
|
wchar_t path[_MAX_PATH]=L"%LOCALAPPDATA%";
|
|
DoEnvironmentSubst(path,_countof(path));
|
|
|
|
dbghelp=LoadLibrary(L"dbghelp.dll");
|
|
|
|
LPCTSTR szResult = NULL;
|
|
|
|
typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
|
|
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
|
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
|
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
|
|
);
|
|
MINIDUMPWRITEDUMP dump=NULL;
|
|
if (dbghelp)
|
|
dump=(MINIDUMPWRITEDUMP)GetProcAddress(dbghelp,"MiniDumpWriteDump");
|
|
if (dump)
|
|
{
|
|
HANDLE file;
|
|
for (int i=1;;i++)
|
|
{
|
|
wchar_t fname[_MAX_PATH];
|
|
Sprintf(fname,_countof(fname),L"%s\\CSM_Crash%d.dmp",path,i);
|
|
file=CreateFile(fname,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
|
|
if (file!=INVALID_HANDLE_VALUE || GetLastError()!=ERROR_FILE_EXISTS) break;
|
|
}
|
|
if (file!=INVALID_HANDLE_VALUE)
|
|
{
|
|
_MINIDUMP_EXCEPTION_INFORMATION ExInfo;
|
|
ExInfo.ThreadId = GetCurrentThreadId();
|
|
ExInfo.ExceptionPointers = (_EXCEPTION_POINTERS*)pExceptionInfo;
|
|
ExInfo.ClientPointers = NULL;
|
|
|
|
dump(GetCurrentProcess(),GetCurrentProcessId(),file,MiniDumpType,&ExInfo,NULL,NULL);
|
|
CloseHandle(file);
|
|
}
|
|
}
|
|
}
|
|
if (dbghelp) FreeLibrary(dbghelp);
|
|
TerminateProcess(GetCurrentProcess(),10);
|
|
return 0;
|
|
}
|
|
|
|
LONG _stdcall TopLevelFilter( _EXCEPTION_POINTERS *pExceptionInfo )
|
|
{
|
|
if (pExceptionInfo->ExceptionRecord->ExceptionCode==EXCEPTION_STACK_OVERFLOW)
|
|
{
|
|
// start a new thread to get a fresh stack (hoping there is enough stack left for CreateThread)
|
|
HANDLE thread=CreateThread(NULL,0,SaveCrashDump,pExceptionInfo,0,NULL);
|
|
WaitForSingleObject(thread,INFINITE);
|
|
CloseHandle(thread);
|
|
}
|
|
else
|
|
SaveCrashDump(pExceptionInfo);
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
|
|
void InvalidParameterHandler( const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved )
|
|
{
|
|
*(int*)0=0; // force a crash to generate a dump
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
interface ISwitchModeManager: public IUnknown
|
|
{
|
|
STDMETHOD(method3)();
|
|
STDMETHOD(method4)();
|
|
STDMETHOD(method5)();
|
|
STDMETHOD(method6)();
|
|
STDMETHOD(method7)();
|
|
STDMETHOD(ShowLauncherTipContextMenu)( POINT *pt );
|
|
};
|
|
|
|
interface IImmersiveLauncherThumbnailProvider: public IUnknown
|
|
{
|
|
STDMETHOD(GetBitmap)( SIZE size, int scale, int, ISharedBitmap **ppBitmap );
|
|
};
|
|
|
|
interface IImmersiveMonitor: public IUnknown
|
|
{
|
|
STDMETHOD(method3)();
|
|
STDMETHOD(method4)();
|
|
STDMETHOD(GetHandle)(HMONITOR*);
|
|
};
|
|
|
|
interface IImmersiveLauncher80: public IUnknown
|
|
{
|
|
STDMETHOD(ShowStartView)( int method );
|
|
STDMETHOD(method4)();
|
|
STDMETHOD(method5)();
|
|
STDMETHOD(method6)();
|
|
STDMETHOD(method7)();
|
|
STDMETHOD(Dismiss)( int method );
|
|
};
|
|
|
|
interface IImmersiveLauncher81: public IUnknown
|
|
{
|
|
STDMETHOD(ShowStartView)( int method, int flags );
|
|
STDMETHOD(method4)();
|
|
STDMETHOD(method5)();
|
|
STDMETHOD(method6)();
|
|
STDMETHOD(method7)();
|
|
STDMETHOD(method8)();
|
|
STDMETHOD(method9)();
|
|
STDMETHOD(IsVisible)(BOOL *);
|
|
STDMETHOD(method11)();
|
|
STDMETHOD(method12)();
|
|
STDMETHOD(method13)();
|
|
STDMETHOD(method14)();
|
|
STDMETHOD(method15)();
|
|
STDMETHOD(method16)();
|
|
STDMETHOD(method17)();
|
|
STDMETHOD(ConnectToMonitor)(IUnknown *);
|
|
STDMETHOD(GetMonitor)(IImmersiveMonitor **);
|
|
};
|
|
|
|
interface IImmersiveLauncher10RS: public IUnknown
|
|
{
|
|
STDMETHOD(ShowStartView)( int method, int flags );
|
|
STDMETHOD(method4)();
|
|
STDMETHOD(method5)();
|
|
STDMETHOD(method6)();
|
|
STDMETHOD(IsVisible)(BOOL *);
|
|
STDMETHOD(method8)();
|
|
STDMETHOD(method9)();
|
|
STDMETHOD(ConnectToMonitor)(IUnknown *);
|
|
STDMETHOD(GetMonitor)(IImmersiveMonitor **);
|
|
};
|
|
|
|
static const GUID SID_SwitchModeManager={0x085920a1,0x28d3,0x44c1,{0x89,0x7d,0x3b,0xe6,0xd0,0x4b,0x2e,0x07}};
|
|
static const GUID IID_ISwitchModeManager={0x976c17be,0xe2d5,0x4f36,{0x93,0x4a,0x7e,0x82,0xf7,0x10,0xea,0xe1}};
|
|
|
|
static const GUID SID_ImmersiveLauncherThumbnailProvider={0x66ce8036,0x400c,0x42f7,{0x99,0x34,0x02,0xf8,0x84,0xfe,0x27,0x4f}};
|
|
static const GUID IID_IImmersiveLauncherThumbnailProvider={0x35c01454,0x53f4,0x4818,{0xba,0x8c,0x7a,0xba,0xdc,0x0f,0xfe,0xe6}};
|
|
|
|
static const GUID SID_ImmersiveLauncher={0x6f86e01c,0xc649,0x4d61,{0xbe,0x23,0xf1,0x32,0x2d,0xde,0xca,0x9d}};
|
|
static const GUID IID_IImmersiveLauncher80={0xfd8b3e33,0xa1f7,0x4e9a,{0x80,0xad,0x80,0x02,0xc7,0x46,0xbe,0x37}};
|
|
static const GUID IID_IImmersiveLauncher81={0x93f91f5a,0xa4ca,0x4205,{0x9b,0xeb,0xce,0x4d,0x17,0xc7,0x08,0xf9}};
|
|
static const GUID IID_IImmersiveLauncher10RS={0xd8d60399,0xa0f1,0xf987,{0x55,0x51,0x32,0x1f,0xd1,0xb4,0x98,0x64}}; // 14257
|
|
|
|
static const GUID IID_IImmersiveLauncherProvider={0x6d5140c1,0x7436,0x11ce,{0x80,0x34,0x00,0xaa,0x00,0x60,0x09,0xfa}};
|
|
|
|
static const CLSID CLSID_ImmersiveShell={0xc2f03a33, 0x21f5, 0x47fa, {0xb4, 0xbb, 0x15, 0x63, 0x62, 0xa2, 0xf2, 0x39}};
|
|
|
|
static const GUID SID_LauncherTipContextMenu={0xb8c1db5f, 0xcbb3, 0x48bc, {0xaf, 0xd9, 0xce, 0x6b, 0x88, 0x0c, 0x79, 0xed}};
|
|
|
|
interface ILauncherTipContextMenu: public IUnknown
|
|
{
|
|
STDMETHOD(ShowLauncherTipContextMenu)( POINT *pt );
|
|
};
|
|
|
|
interface IImmersiveMonitorService: public IUnknown
|
|
{
|
|
STDMETHOD(method3)();
|
|
STDMETHOD(method4)();
|
|
STDMETHOD(method5)();
|
|
STDMETHOD(GetFromHandle)(HMONITOR, IUnknown **);
|
|
STDMETHOD(method7)();
|
|
STDMETHOD(method8)();
|
|
STDMETHOD(method9)();
|
|
STDMETHOD(method10)();
|
|
STDMETHOD(method11)();
|
|
STDMETHOD(method12)();
|
|
STDMETHOD(method13)();
|
|
STDMETHOD(SetImmersiveMonitor)(IUnknown *);
|
|
};
|
|
|
|
static const GUID SID_IImmersiveMonitorService={0x47094e3a,0x0cf2,0x430f,{0x80,0x6f,0xcf,0x9e,0x4f,0x0f,0x12,0xdd}};
|
|
static const GUID IID_IImmersiveMonitorService={0x4d4c1e64,0xe410,0x4faa,{0xba,0xfa,0x59,0xca,0x06,0x9b,0xfe,0xc2}};
|
|
|
|
|
|
struct StartScreenThumbInfo
|
|
{
|
|
SIZE size;
|
|
HBITMAP bitmap;
|
|
HANDLE event;
|
|
};
|
|
|
|
static bool CreateImmersiveShell( CComPtr<IUnknown> &ptr )
|
|
{
|
|
if (GetWinVersion()<WIN_VER_WIN8)
|
|
return false;
|
|
ptr.CoCreateInstance(CLSID_ImmersiveShell);
|
|
return ptr.p!=NULL;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// COwnerWindow - a special window used as owner for some UI elements, like the ones created by IContextMenu::InvokeCommand.
|
|
// A menu window cannot be used because it may disappear immediately after InvokeCommand. Some UI elements, like the UAC-related
|
|
// stuff can be created long after InvokeCommand returns and the menu may be deleted by then.
|
|
class COwnerWindow: public CWindowImpl<COwnerWindow>
|
|
{
|
|
public:
|
|
DECLARE_WND_CLASS_EX(L"OpenShell.COwnerWindow",0,COLOR_MENU)
|
|
|
|
// message handlers
|
|
BEGIN_MSG_MAP( COwnerWindow )
|
|
MESSAGE_HANDLER( WM_ACTIVATE, OnActivate )
|
|
MESSAGE_HANDLER( WM_SYSCOLORCHANGE, OnColorChange )
|
|
MESSAGE_HANDLER( WM_SETTINGCHANGE, OnSettingChange )
|
|
MESSAGE_HANDLER( WM_DISPLAYCHANGE, OnDisplayChange )
|
|
END_MSG_MAP()
|
|
|
|
protected:
|
|
LRESULT OnActivate( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (LOWORD(wParam)!=WA_INACTIVE)
|
|
return 0;
|
|
|
|
if (CMenuContainer::s_bPreventClosing)
|
|
return 0;
|
|
|
|
// check if another menu window is being activated
|
|
// if not, close all menus
|
|
for (std::vector<CMenuContainer*>::const_iterator it=CMenuContainer::s_Menus.begin();it!=CMenuContainer::s_Menus.end();++it)
|
|
if ((*it)->m_hWnd==(HWND)lParam)
|
|
return 0;
|
|
|
|
for (std::vector<CMenuContainer*>::reverse_iterator it=CMenuContainer::s_Menus.rbegin();it!=CMenuContainer::s_Menus.rend();++it)
|
|
if (!(*it)->m_bDestroyed)
|
|
(*it)->PostMessage(WM_CLOSE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
LRESULT OnColorChange( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
CMenuContainer::s_Skin.Hash=0;
|
|
return 0;
|
|
}
|
|
|
|
|
|
LRESULT OnSettingChange( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (wParam==SPI_SETWORKAREA)
|
|
{
|
|
if (!CMenuContainer::s_Menus.empty())
|
|
CMenuContainer::s_Menus[0]->NotifyDisplayChange();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
LRESULT OnDisplayChange( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (!CMenuContainer::s_Menus.empty())
|
|
CMenuContainer::s_Menus[0]->NotifyDisplayChange();
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
static COwnerWindow g_Owner;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool TaskbarInfo::HasPart( HWND part ) const
|
|
{
|
|
for (std::vector<HWND>::const_iterator it=taskbarParts.begin();it!=taskbarParts.end();++it)
|
|
if (*it==part)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
static const TaskbarInfo *GetDefaultTaskbarInfo( void )
|
|
{
|
|
if (GetSettingBool(L"AllTaskbars"))
|
|
{
|
|
HMONITOR monitor=MonitorFromPoint(CPoint(GetMessagePos()),MONITOR_DEFAULTTONEAREST);
|
|
for (std::map<size_t,TaskbarInfo>::const_iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it)
|
|
{
|
|
MONITORINFO info;
|
|
HMONITOR monitor2=NULL;
|
|
if (GetTaskbarPosition(it->second.taskBar,&info,&monitor2,NULL)!=0xFFFFFFFF && monitor2==monitor)
|
|
return &it->second;
|
|
}
|
|
id_taskbar_map::const_iterator it=g_TaskbarInfos.find(g_LastTaskbar);
|
|
if (it!=g_TaskbarInfos.end())
|
|
return &it->second;
|
|
}
|
|
return &g_TaskbarInfos.begin()->second;
|
|
}
|
|
|
|
TaskbarInfo *GetTaskbarInfo( size_t taskbarId )
|
|
{
|
|
std::map<size_t,TaskbarInfo>::iterator it=g_TaskbarInfos.find(taskbarId);
|
|
return (it==g_TaskbarInfos.end())?NULL:&it->second;
|
|
}
|
|
|
|
static TaskbarInfo *FindTaskBarInfoButton( HWND button )
|
|
{
|
|
for (id_taskbar_map::iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it)
|
|
if (it->second.startButton==button || it->second.oldButton==button)
|
|
return &it->second;
|
|
return NULL;
|
|
}
|
|
|
|
static TaskbarInfo *FindTaskBarInfoBar( HWND bar )
|
|
{
|
|
for (id_taskbar_map::iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it)
|
|
if (it->second.taskBar==bar)
|
|
return &it->second;
|
|
return NULL;
|
|
}
|
|
|
|
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 )
|
|
{
|
|
// look for tooltip control in the current thread that has a tool for g_TaskBar+g_StartButton
|
|
wchar_t name[256];
|
|
GetClassName(hwnd,name,_countof(name));
|
|
if (_wcsicmp(name,TOOLTIPS_CLASS)!=0) return TRUE;
|
|
TOOLINFO info={sizeof(info),0,g_TaskBar,(UINT_PTR)g_WinStartButton};
|
|
if (SendMessage(hwnd,TTM_GETTOOLINFO,0,(LPARAM)&info))
|
|
{
|
|
g_Tooltip=hwnd;
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL CALLBACK FindStartButtonEnum( HWND hwnd, LPARAM lParam )
|
|
{
|
|
// look for top-level window in the current thread with class "button"
|
|
wchar_t name[256];
|
|
GetClassName(hwnd,name,_countof(name));
|
|
if (_wcsicmp(name,L"button")!=0) return TRUE;
|
|
g_WinStartButton=hwnd;
|
|
return FALSE;
|
|
}
|
|
|
|
static BOOL CALLBACK FindTaskBarEnum( HWND hwnd, LPARAM lParam )
|
|
{
|
|
// look for top-level window with class "Shell_TrayWnd" and process ID=lParam
|
|
DWORD process;
|
|
GetWindowThreadProcessId(hwnd,&process);
|
|
if (process!=lParam) return TRUE;
|
|
wchar_t name[256];
|
|
GetClassName(hwnd,name,_countof(name));
|
|
if (_wcsicmp(name,L"Shell_TrayWnd")!=0) return TRUE;
|
|
g_TaskBar=hwnd;
|
|
return FALSE;
|
|
}
|
|
|
|
// Find the taskbar window for the given process
|
|
STARTMENUAPI HWND FindTaskBar( DWORD process )
|
|
{
|
|
g_WinStartButton=NULL;
|
|
g_TaskBar=NULL;
|
|
g_Tooltip=NULL;
|
|
// find the taskbar
|
|
EnumWindows(FindTaskBarEnum,process);
|
|
if (!g_TaskBar)
|
|
g_TaskBar=FindWindowEx(GetDesktopWindow(),NULL,L"Shell_TrayWnd",NULL);
|
|
if (g_TaskBar)
|
|
{
|
|
// find start button
|
|
if (GetWinVersion()==WIN_VER_WIN7)
|
|
EnumThreadWindows(GetWindowThreadProcessId(g_TaskBar,NULL),FindStartButtonEnum,NULL);
|
|
if (GetWindowThreadProcessId(g_TaskBar,NULL)==GetCurrentThreadId())
|
|
{
|
|
// find tooltip
|
|
if (g_WinStartButton)
|
|
{
|
|
EnumThreadWindows(GetWindowThreadProcessId(g_TaskBar,NULL),FindTooltipEnum,NULL);
|
|
if (g_Tooltip)
|
|
{
|
|
g_StartButtonTool.cbSize=sizeof(g_StartButtonTool);
|
|
g_StartButtonTool.hwnd=g_TaskBar;
|
|
g_StartButtonTool.uId=(UINT_PTR)g_WinStartButton;
|
|
SendMessage(g_Tooltip,TTM_GETTOOLINFO,0,(LPARAM)&g_StartButtonTool);
|
|
}
|
|
}
|
|
g_OwnerWindow=g_Owner.Create(NULL,0,0,WS_POPUP,WS_EX_TOOLWINDOW|WS_EX_TOPMOST);
|
|
}
|
|
}
|
|
return g_TaskBar;
|
|
}
|
|
|
|
#ifdef HOOK_DROPTARGET
|
|
class CStartMenuTarget: public IDropTarget
|
|
{
|
|
public:
|
|
CStartMenuTarget( int taskbarId ) { m_RefCount=1; m_TaskbarId=taskbarId; }
|
|
// IUnknown
|
|
virtual STDMETHODIMP QueryInterface( REFIID riid, void **ppvObject )
|
|
{
|
|
*ppvObject=NULL;
|
|
if (IID_IUnknown==riid || IID_IDropTarget==riid)
|
|
{
|
|
AddRef();
|
|
*ppvObject=(IDropTarget*)this;
|
|
return S_OK;
|
|
}
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
virtual ULONG STDMETHODCALLTYPE AddRef( void )
|
|
{
|
|
return InterlockedIncrement(&m_RefCount);
|
|
}
|
|
|
|
virtual ULONG STDMETHODCALLTYPE Release( void )
|
|
{
|
|
long nTemp=InterlockedDecrement(&m_RefCount);
|
|
if (!nTemp) delete this;
|
|
return nTemp;
|
|
}
|
|
|
|
// IDropTarget
|
|
virtual HRESULT STDMETHODCALLTYPE DragEnter( IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect )
|
|
{
|
|
FORMATETC format1={(CLIPFORMAT)RegisterClipboardFormat(CFSTR_SHELLIDLIST),NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL};
|
|
FORMATETC format2={(CLIPFORMAT)RegisterClipboardFormat(CFSTR_INETURL),NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL};
|
|
if (pDataObj->QueryGetData(&format1)==S_OK || pDataObj->QueryGetData(&format2)==S_OK)
|
|
{
|
|
PostMessage(g_TaskBar,g_StartMenuMsg,(grfKeyState&MK_SHIFT)?MSG_SHIFTDRAG:MSG_DRAG,m_TaskbarId);
|
|
}
|
|
*pdwEffect=DROPEFFECT_NONE;
|
|
return S_OK;
|
|
}
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE DragOver( DWORD grfKeyState, POINTL pt, DWORD *pdwEffect ) { return *pdwEffect=DROPEFFECT_NONE; return S_OK; }
|
|
virtual HRESULT STDMETHODCALLTYPE DragLeave( void ) { return S_OK; }
|
|
virtual HRESULT STDMETHODCALLTYPE Drop( IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect ) { return *pdwEffect=DROPEFFECT_NONE; return S_OK; }
|
|
|
|
private:
|
|
LONG m_RefCount;
|
|
int m_TaskbarId;
|
|
};
|
|
|
|
#endif
|
|
|
|
static CComPtr<IDropTarget> g_pOriginalTarget;
|
|
|
|
static void FindTaskBar( void )
|
|
{
|
|
if (!g_TaskBar)
|
|
{
|
|
g_StartMenuMsg=RegisterWindowMessage(L"OpenShellMenu.StartMenuMsg");
|
|
FindTaskBar(GetCurrentProcessId());
|
|
if (g_TaskBar)
|
|
{
|
|
g_HotkeyShiftID=GlobalAddAtom(L"OpenShellMenu.HotkeyShift");
|
|
g_HotkeyCSMID=GlobalAddAtom(L"OpenShellMenu.HotkeyCSM");
|
|
g_HotkeyWSMID=GlobalAddAtom(L"OpenShellMenu.HotkeyWSM");
|
|
EnableHotkeys(HOTKEYS_NORMAL);
|
|
srand(GetTickCount());
|
|
}
|
|
if (!g_TaskBar) g_TaskBar=(HWND)1;
|
|
}
|
|
}
|
|
|
|
void EnableStartTooltip( bool bEnable )
|
|
{
|
|
if (g_Tooltip)
|
|
{
|
|
SendMessage(g_Tooltip,TTM_POP,0,0);
|
|
if (bEnable)
|
|
SendMessage(g_Tooltip,TTM_UPDATETIPTEXT,0,(LPARAM)&g_StartButtonTool);
|
|
else
|
|
{
|
|
TOOLINFO info=g_StartButtonTool;
|
|
info.lpszText=(LPWSTR)L"";
|
|
SendMessage(g_Tooltip,TTM_UPDATETIPTEXT,0,(LPARAM)&info);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Restore the original drop target
|
|
static void UnhookDropTarget( void )
|
|
{
|
|
if (g_pOriginalTarget)
|
|
{
|
|
RevokeDragDrop(g_WinStartButton);
|
|
if (g_pOriginalTarget)
|
|
RegisterDragDrop(g_WinStartButton,g_pOriginalTarget);
|
|
g_pOriginalTarget=NULL;
|
|
}
|
|
}
|
|
|
|
// Toggle the start menu. bKeyboard - set to true to show the keyboard cues
|
|
STARTMENUAPI HWND ToggleStartMenu( int taskbarId, bool bKeyboard )
|
|
{
|
|
if (taskbarId==-1)
|
|
{
|
|
if (g_TaskbarInfos.find(-1)==g_TaskbarInfos.end())
|
|
{
|
|
g_TaskbarInfos[-1].taskBar=g_TaskBar;
|
|
}
|
|
}
|
|
g_LastTaskbar=taskbarId;
|
|
return CMenuContainer::ToggleStartMenu(taskbarId,bKeyboard,false);
|
|
}
|
|
|
|
UINT GetTaskbarPosition( HWND taskBar, MONITORINFO *pInfo, HMONITOR *pMonitor, RECT *pRc )
|
|
{
|
|
if (!IsWindow(taskBar))
|
|
return 0xFFFFFFFF;
|
|
if (taskBar==g_TaskBar)
|
|
{
|
|
APPBARDATA appbar={sizeof(appbar),taskBar};
|
|
SHAppBarMessage(ABM_GETTASKBARPOS,&appbar);
|
|
if (pRc)
|
|
{
|
|
if (RECT rc; GetWindowRgnBox(taskBar,&rc)!=ERROR)
|
|
{
|
|
MapWindowPoints(taskBar,NULL,(POINT*)&rc,2);
|
|
appbar.rc=rc;
|
|
}
|
|
*pRc=appbar.rc;
|
|
RECT rc;
|
|
GetWindowRect(taskBar,&rc);
|
|
if (appbar.uEdge==ABE_LEFT || appbar.uEdge==ABE_RIGHT)
|
|
{
|
|
if (pRc->top<rc.top) pRc->top=rc.top;
|
|
if (pRc->bottom>rc.bottom) pRc->bottom=rc.bottom;
|
|
}
|
|
else if (appbar.uEdge==ABE_TOP || appbar.uEdge==ABE_BOTTOM)
|
|
{
|
|
if (pRc->left<rc.left) pRc->left=rc.left;
|
|
if (pRc->right>rc.right) pRc->right=rc.right;
|
|
}
|
|
}
|
|
HMONITOR monitor=MonitorFromRect(&appbar.rc,MONITOR_DEFAULTTONEAREST);
|
|
if (pMonitor) *pMonitor=monitor;
|
|
if (pInfo)
|
|
{
|
|
pInfo->cbSize=sizeof(MONITORINFO);
|
|
GetMonitorInfo(monitor,pInfo);
|
|
}
|
|
return appbar.uEdge;
|
|
}
|
|
RECT rc;
|
|
if (GetWindowRgnBox(taskBar,&rc)!=ERROR)
|
|
MapWindowPoints(taskBar,NULL,(POINT*)&rc,2);
|
|
else
|
|
GetWindowRect(taskBar,&rc);
|
|
MONITORINFO info={sizeof(info)};
|
|
HMONITOR monitor=MonitorFromRect(&rc,MONITOR_DEFAULTTONEAREST);
|
|
GetMonitorInfo(monitor,&info);
|
|
if (pMonitor) *pMonitor=monitor;
|
|
int dx=rc.left+rc.right-info.rcWork.left-info.rcWork.right;
|
|
int dy=rc.top+rc.bottom-info.rcWork.top-info.rcWork.bottom;
|
|
if (pInfo) *pInfo=info;
|
|
bool bAutoHide=false;
|
|
if (pRc)
|
|
{
|
|
GetWindowRect(taskBar,pRc);
|
|
APPBARDATA appbar={sizeof(appbar)};
|
|
bAutoHide=(SHAppBarMessage(ABM_GETSTATE,&appbar)&ABS_AUTOHIDE)!=0;
|
|
}
|
|
if (dx<-abs(dy))
|
|
{
|
|
if (bAutoHide && pRc->left<info.rcWork.left)
|
|
OffsetRect(pRc,info.rcWork.left-pRc->left,0);
|
|
return ABE_LEFT;
|
|
}
|
|
if (dx>abs(dy))
|
|
{
|
|
if (bAutoHide && pRc->right>info.rcWork.right)
|
|
OffsetRect(pRc,info.rcWork.right-pRc->right,0);
|
|
return ABE_RIGHT;
|
|
}
|
|
if (dy<-abs(dx))
|
|
{
|
|
if (bAutoHide && pRc->top<info.rcWork.top)
|
|
OffsetRect(pRc,0,info.rcWork.top-pRc->top);
|
|
return ABE_TOP;
|
|
}
|
|
if (bAutoHide && pRc->bottom>info.rcWork.bottom)
|
|
OffsetRect(pRc,0,info.rcWork.bottom-pRc->bottom);
|
|
return ABE_BOTTOM;
|
|
}
|
|
|
|
// Returns true if the mouse is on the taskbar portion of the start button
|
|
bool PointAroundStartButton( size_t taskbarId, const CPoint &pt )
|
|
{
|
|
const TaskbarInfo *taskBar=GetTaskbarInfo(taskbarId);
|
|
if (!taskBar || !(taskBar->startButton || taskBar->oldButton)) return false;
|
|
CRect rc;
|
|
GetWindowRect(taskBar->taskBar,&rc);
|
|
if (!PtInRect(&rc,pt))
|
|
return false;
|
|
|
|
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
|
|
UINT uEdge=GetTaskbarPosition(taskBar->taskBar,NULL,NULL,NULL);
|
|
if (uEdge==ABE_LEFT || uEdge==ABE_RIGHT)
|
|
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.left && pt.x<rc.right;
|
|
}
|
|
|
|
// declare few interfaces so we don't need the Win8 SDK
|
|
#ifndef __IAppVisibility_INTERFACE_DEFINED__
|
|
typedef enum MONITOR_APP_VISIBILITY
|
|
{
|
|
MAV_UNKNOWN = 0,
|
|
MAV_NO_APP_VISIBLE = 1,
|
|
MAV_APP_VISIBLE = 2
|
|
} MONITOR_APP_VISIBILITY;
|
|
|
|
MIDL_INTERFACE("6584CE6B-7D82-49C2-89C9-C6BC02BA8C38")
|
|
IAppVisibilityEvents : public IUnknown
|
|
{
|
|
public:
|
|
virtual HRESULT STDMETHODCALLTYPE AppVisibilityOnMonitorChanged( HMONITOR hMonitor, MONITOR_APP_VISIBILITY previousMode, MONITOR_APP_VISIBILITY currentMode ) = 0;
|
|
virtual HRESULT STDMETHODCALLTYPE LauncherVisibilityChange( BOOL currentVisibleState ) = 0;
|
|
};
|
|
|
|
MIDL_INTERFACE("2246EA2D-CAEA-4444-A3C4-6DE827E44313")
|
|
IAppVisibility : public IUnknown
|
|
{
|
|
public:
|
|
virtual HRESULT STDMETHODCALLTYPE GetAppVisibilityOnMonitor( HMONITOR hMonitor, MONITOR_APP_VISIBILITY *pMode ) = 0;
|
|
virtual HRESULT STDMETHODCALLTYPE IsLauncherVisible( BOOL *pfVisible ) = 0;
|
|
virtual HRESULT STDMETHODCALLTYPE Advise( IAppVisibilityEvents *pCallback, DWORD *pdwCookie ) = 0;
|
|
virtual HRESULT STDMETHODCALLTYPE Unadvise( DWORD dwCookie ) = 0;
|
|
};
|
|
|
|
#endif
|
|
|
|
void ResetHotCorners( void )
|
|
{
|
|
for (std::set<HWND>::const_iterator it=g_EdgeWindows.begin();it!=g_EdgeWindows.end();++it)
|
|
ShowWindow(*it,SW_SHOW);
|
|
g_EdgeWindows.clear();
|
|
}
|
|
|
|
void RedrawTaskbars( void )
|
|
{
|
|
for (id_taskbar_map::const_iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it)
|
|
InvalidateRect(it->second.taskBar,NULL,TRUE);
|
|
}
|
|
|
|
static CComPtr<IAppVisibility> g_pAppVisibility;
|
|
static DWORD g_AppVisibilityMonitorCookie;
|
|
|
|
class CMonitorModeEvents: public IAppVisibilityEvents
|
|
{
|
|
public:
|
|
CMonitorModeEvents( void ) { m_RefCount=1; }
|
|
// IUnknown
|
|
virtual STDMETHODIMP QueryInterface( REFIID riid, void **ppvObject )
|
|
{
|
|
*ppvObject=NULL;
|
|
if (IID_IUnknown==riid || __uuidof(IAppVisibilityEvents)==riid)
|
|
{
|
|
AddRef();
|
|
*ppvObject=(IDropTarget*)this;
|
|
return S_OK;
|
|
}
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
virtual ULONG STDMETHODCALLTYPE AddRef( void )
|
|
{
|
|
return InterlockedIncrement(&m_RefCount);
|
|
}
|
|
|
|
virtual ULONG STDMETHODCALLTYPE Release( void )
|
|
{
|
|
long nTemp=InterlockedDecrement(&m_RefCount);
|
|
if (!nTemp) delete this;
|
|
return nTemp;
|
|
}
|
|
|
|
// IAppVisibilityEvents
|
|
virtual HRESULT STDMETHODCALLTYPE AppVisibilityOnMonitorChanged( HMONITOR hMonitor, MONITOR_APP_VISIBILITY previousMode, MONITOR_APP_VISIBILITY currentMode )
|
|
{
|
|
if (GetWinVersion()<WIN_VER_WIN10)
|
|
{
|
|
ResetHotCorners();
|
|
if (IsWin81Update1() && GetSettingBool(L"CustomTaskbar"))
|
|
PostMessage(g_TaskBar,g_StartMenuMsg,MSG_REDRAWTASKBAR,0);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE LauncherVisibilityChange( BOOL currentVisibleState )
|
|
{
|
|
CComPtr<IUnknown> pImmersiveShell;
|
|
if (GetWinVersion()>=WIN_VER_WIN10 && CreateImmersiveShell(pImmersiveShell))
|
|
{
|
|
int taskbarId=-1;
|
|
if (currentVisibleState)
|
|
{
|
|
taskbarId=MAIN_TASK_BAR;
|
|
CComPtr<IImmersiveMonitor> pMonitor;
|
|
{
|
|
CComPtr<IImmersiveLauncher81> pLauncher;
|
|
IUnknown_QueryService(pImmersiveShell,SID_ImmersiveLauncher,IID_IImmersiveLauncher81,(void**)&pLauncher);
|
|
if (pLauncher)
|
|
pLauncher->GetMonitor(&pMonitor);
|
|
}
|
|
if (!pMonitor)
|
|
{
|
|
CComPtr<IImmersiveLauncher10RS> pLauncher;
|
|
IUnknown_QueryService(pImmersiveShell,SID_ImmersiveLauncher,IID_IImmersiveLauncher10RS,(void**)&pLauncher);
|
|
if (pLauncher)
|
|
pLauncher->GetMonitor(&pMonitor);
|
|
}
|
|
if (pMonitor)
|
|
{
|
|
HMONITOR monitor;
|
|
if (SUCCEEDED(pMonitor->GetHandle(&monitor)))
|
|
{
|
|
for (id_taskbar_map::const_iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it)
|
|
{
|
|
if (monitor==MonitorFromWindow(it->second.taskBar,MONITOR_DEFAULTTONULL))
|
|
{
|
|
taskbarId=it->second.taskbarId;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (g_CurrentWSMTaskbar!=taskbarId)
|
|
{
|
|
if (g_CurrentWSMTaskbar!=-1 && g_CurrentWSMTaskbar!=g_CurrentCSMTaskbar)
|
|
PressStartButton(g_CurrentWSMTaskbar,false);
|
|
g_CurrentWSMTaskbar=taskbarId;
|
|
if (g_CurrentWSMTaskbar!=-1)
|
|
PressStartButton(g_CurrentWSMTaskbar,true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ResetHotCorners();
|
|
if (IsWin81Update1() && GetSettingBool(L"CustomTaskbar"))
|
|
PostMessage(g_TaskBar,g_StartMenuMsg,MSG_REDRAWTASKBAR,0);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
private:
|
|
LONG m_RefCount;
|
|
};
|
|
|
|
static const CLSID CLSID_MetroMode={0x7E5FE3D9,0x985F,0x4908,{0x91, 0xF9, 0xEE, 0x19, 0xF9, 0xFD, 0x15, 0x14}};
|
|
|
|
BOOL CALLBACK AppVisibleProc( HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData )
|
|
{
|
|
bool *pData=(bool*)dwData;
|
|
MONITOR_APP_VISIBILITY mode;
|
|
if (SUCCEEDED(g_pAppVisibility->GetAppVisibilityOnMonitor(hMonitor,&mode)) && mode==MAV_APP_VISIBLE)
|
|
*pData=true;
|
|
return !*pData;
|
|
}
|
|
|
|
enum TMetroMode
|
|
{
|
|
METRO_NONE,
|
|
METRO_LAUNCHER,
|
|
METRO_APP,
|
|
};
|
|
|
|
static TMetroMode GetMetroMode( HMONITOR hMonitor )
|
|
{
|
|
if (!g_pAppVisibility) return METRO_NONE;
|
|
|
|
BOOL bLauncher;
|
|
if (SUCCEEDED(g_pAppVisibility->IsLauncherVisible(&bLauncher)) && bLauncher)
|
|
{
|
|
if (!hMonitor) return METRO_LAUNCHER;
|
|
HWND launcher=FindWindow(L"ImmersiveLauncher",NULL);
|
|
if (launcher && hMonitor==MonitorFromWindow(launcher,MONITOR_DEFAULTTONULL))
|
|
return METRO_LAUNCHER;
|
|
}
|
|
|
|
if (hMonitor)
|
|
{
|
|
MONITOR_APP_VISIBILITY mode;
|
|
if (SUCCEEDED(g_pAppVisibility->GetAppVisibilityOnMonitor(hMonitor,&mode)) && mode==MAV_APP_VISIBLE)
|
|
return METRO_APP;
|
|
}
|
|
else
|
|
{
|
|
bool bAppVisible=false;
|
|
EnumDisplayMonitors(NULL,NULL,AppVisibleProc,(LPARAM)&bAppVisible);
|
|
if (bAppVisible) return METRO_APP;
|
|
}
|
|
return METRO_NONE;
|
|
}
|
|
|
|
static bool GetWin10TabletMode( void )
|
|
{
|
|
CRegKey regKey;
|
|
if (regKey.Open(HKEY_CURRENT_USER,L"Software\\Microsoft\\Windows\\CurrentVersion\\ImmersiveShell",KEY_READ|KEY_WOW64_64KEY)==ERROR_SUCCESS)
|
|
{
|
|
DWORD val;
|
|
return regKey.QueryDWORDValue(L"TabletMode",val)==ERROR_SUCCESS && val;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static LRESULT CALLBACK HookAppManager( int code, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
if (code==HC_ACTION && wParam)
|
|
{
|
|
MSG *msg=(MSG*)lParam;
|
|
if (msg->message==g_StartMenuMsg && (msg->wParam==MSG_WINXMENU || msg->wParam==MSG_METROTHUMBNAIL || msg->wParam==MSG_SHIFTWIN))
|
|
{
|
|
HWND hwnd=FindWindow(L"ModeInputWnd",NULL);
|
|
if (hwnd)
|
|
{
|
|
DWORD process;
|
|
GetWindowThreadProcessId(hwnd,&process);
|
|
if (process==GetCurrentProcessId())
|
|
{
|
|
IObjectWithSite *pObject=(IObjectWithSite*)GetWindowLongPtr(hwnd,0);
|
|
if (pObject)
|
|
{
|
|
CComPtr<IUnknown> pSite;
|
|
pObject->GetSite(IID_IUnknown,(void**)&pSite);
|
|
if (pSite)
|
|
{
|
|
if (msg->wParam==MSG_WINXMENU)
|
|
{
|
|
CPoint pt(msg->lParam);
|
|
CComPtr<ISwitchModeManager> pSwitchModeManager;
|
|
IUnknown_QueryService(pSite,SID_SwitchModeManager,IID_ISwitchModeManager,(void**)&pSwitchModeManager);
|
|
if (pSwitchModeManager)
|
|
{
|
|
pSwitchModeManager->ShowLauncherTipContextMenu(&pt);
|
|
// set the current immersive monitor AFTER the menu returns (this way Search is shown in the correct monitor)
|
|
CComPtr<IImmersiveMonitorService> pMonitorService;
|
|
IUnknown_QueryService(pSite,SID_IImmersiveMonitorService,IID_IImmersiveMonitorService,(void**)&pMonitorService);
|
|
if (pMonitorService)
|
|
{
|
|
HMONITOR monitor=MonitorFromPoint(pt,MONITOR_DEFAULTTONEAREST);
|
|
if (GetWinVersion()==WIN_VER_WIN8)
|
|
{
|
|
CComPtr<IUnknown> pMonitor;
|
|
pMonitorService->GetFromHandle(monitor,&pMonitor);
|
|
if (pMonitor)
|
|
pMonitorService->SetImmersiveMonitor(pMonitor);
|
|
}
|
|
else if (GetWinVersion()>WIN_VER_WIN8)
|
|
{
|
|
// doesn't seem to be doing anything on 8.1, but do it just in case
|
|
CComPtr<IUnknown> pMonitor;
|
|
pMonitorService->GetFromHandle(monitor,&pMonitor);
|
|
if (pMonitor)
|
|
{
|
|
CComPtr<IImmersiveLauncher81> pLauncher;
|
|
IUnknown_QueryService(pSite,SID_ImmersiveLauncher,IID_IImmersiveLauncher81,(void**)&pLauncher);
|
|
if (pLauncher)
|
|
pLauncher->ConnectToMonitor(pMonitor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (msg->wParam==MSG_METROTHUMBNAIL)
|
|
{
|
|
StartScreenThumbInfo &info=*(StartScreenThumbInfo*)msg->lParam;
|
|
CComPtr<IUnknown> pLauncher;
|
|
IUnknown_QueryService(pSite,SID_ImmersiveLauncher,IID_IImmersiveLauncherProvider,(void**)&pLauncher);
|
|
if (pLauncher)
|
|
{
|
|
CComPtr<IImmersiveLauncherThumbnailProvider> pProvider;
|
|
IUnknown_QueryService(pLauncher,SID_ImmersiveLauncherThumbnailProvider,IID_IImmersiveLauncherThumbnailProvider,(void**)&pProvider);
|
|
if (pProvider)
|
|
{
|
|
CComPtr<ISharedBitmap> pBitmap;
|
|
if (SUCCEEDED(pProvider->GetBitmap(info.size,100,1,&pBitmap)) && pBitmap)
|
|
{
|
|
pBitmap->Detach(&info.bitmap);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (msg->wParam==MSG_SHIFTWIN)
|
|
{
|
|
if (GetWinVersion()==WIN_VER_WIN8)
|
|
{
|
|
HMONITOR monitor=(HMONITOR)msg->lParam;
|
|
if (monitor)
|
|
{
|
|
CComPtr<IImmersiveMonitorService> pMonitorService;
|
|
IUnknown_QueryService(pSite,SID_IImmersiveMonitorService,IID_IImmersiveMonitorService,(void**)&pMonitorService);
|
|
if (pMonitorService)
|
|
{
|
|
CComPtr<IUnknown> pMonitor;
|
|
pMonitorService->GetFromHandle(monitor,&pMonitor);
|
|
if (pMonitor)
|
|
pMonitorService->SetImmersiveMonitor(pMonitor);
|
|
}
|
|
}
|
|
CComPtr<IImmersiveLauncher80> pLauncher;
|
|
IUnknown_QueryService(pSite,SID_ImmersiveLauncher,IID_IImmersiveLauncher80,(void**)&pLauncher);
|
|
if (pLauncher)
|
|
pLauncher->ShowStartView(5);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (msg->wParam==MSG_METROTHUMBNAIL)
|
|
{
|
|
// set the event no matter if successful
|
|
StartScreenThumbInfo &info=*(StartScreenThumbInfo*)msg->lParam;
|
|
SetEvent(info.event);
|
|
}
|
|
}
|
|
int corner;
|
|
if ((msg->message==WM_MOUSEMOVE || msg->message==WM_LBUTTONDOWN) && (corner=GetSettingInt(L"DisableHotCorner"))>0)
|
|
{
|
|
{
|
|
// ignore the mouse messages if there is a menu
|
|
GUITHREADINFO info={sizeof(info)};
|
|
if (GetGUIThreadInfo(GetCurrentThreadId(),&info) && (info.flags&GUI_INMENUMODE))
|
|
return CallNextHookEx(NULL,code,wParam,lParam);
|
|
}
|
|
CPoint pt(GetMessagePos());
|
|
HMONITOR monitor=MonitorFromPoint(pt,MONITOR_DEFAULTTONEAREST);
|
|
if (GetMetroMode(monitor)!=METRO_NONE)
|
|
{
|
|
if (!IsWin81Update1())
|
|
return CallNextHookEx(NULL,code,wParam,lParam);
|
|
typedef BOOL (WINAPI *tGetWindowBand)(HWND,DWORD*);
|
|
static tGetWindowBand GetWindowBand=(tGetWindowBand)GetProcAddress(GetModuleHandle(L"user32.dll"),"GetWindowBand");
|
|
for (id_taskbar_map::const_iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it)
|
|
{
|
|
DWORD band;
|
|
if (!GetWindowBand || !GetWindowBand(it->second.taskBar,&band) || band==1)
|
|
continue;
|
|
UINT uEdge=GetTaskbarPosition(it->second.taskBar,NULL,NULL,NULL);
|
|
if (uEdge!=ABE_BOTTOM)
|
|
continue;
|
|
|
|
// check if the mouse is over the taskbar
|
|
RECT taskRect;
|
|
GetWindowRect(it->second.taskBar,&taskRect);
|
|
if (PtInRect(&taskRect,pt))
|
|
{
|
|
POINT pt2=pt;
|
|
ScreenToClient(it->second.taskBar,&pt2);
|
|
if (pt2.x<32)
|
|
{
|
|
if (msg->message==WM_LBUTTONDOWN)
|
|
{
|
|
// forward the mouse click to the taskbar
|
|
PostMessage(it->second.taskBar,WM_NCLBUTTONDOWN,MK_LBUTTON,MAKELONG(pt.x,pt.y));
|
|
msg->message=WM_NULL;
|
|
}
|
|
wchar_t className[256]={0};
|
|
GetClassName(msg->hwnd,className,_countof(className));
|
|
if (wcscmp(className,L"ImmersiveSwitchList")==0)
|
|
{
|
|
// suppress the opening of the ImmersiveSwitchList
|
|
msg->message=WM_NULL;
|
|
ShowWindow(msg->hwnd,SW_HIDE); // hide the popup
|
|
}
|
|
if (wcscmp(className,L"EdgeUiInputWndClass")==0)
|
|
{
|
|
// suppress the hot corners
|
|
msg->message=WM_NULL;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return CallNextHookEx(NULL,code,wParam,lParam);
|
|
}
|
|
if (corner==1)
|
|
{
|
|
for (id_taskbar_map::const_iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it)
|
|
{
|
|
UINT uEdge=GetTaskbarPosition(it->second.taskBar,NULL,NULL,NULL);
|
|
if (uEdge==ABE_BOTTOM)
|
|
{
|
|
// check if the mouse is over the taskbar
|
|
RECT taskRect;
|
|
GetWindowRect(it->second.taskBar,&taskRect);
|
|
if (PtInRect(&taskRect,pt))
|
|
{
|
|
POINT pt2=pt;
|
|
ScreenToClient(it->second.taskBar,&pt2);
|
|
if (pt2.x<32)
|
|
{
|
|
corner=2;
|
|
if (msg->message==WM_LBUTTONDOWN)
|
|
{
|
|
// forward the mouse click to the taskbar
|
|
PostMessage(it->second.taskBar,WM_NCLBUTTONDOWN,MK_LBUTTON,MAKELONG(pt.x,pt.y));
|
|
msg->message=WM_NULL;
|
|
}
|
|
wchar_t className[256]={0};
|
|
GetClassName(msg->hwnd,className,_countof(className));
|
|
if (wcscmp(className,L"ImmersiveSwitchList")==0)
|
|
{
|
|
// suppress the opening of the ImmersiveSwitchList
|
|
msg->message=WM_NULL;
|
|
ShowWindow(msg->hwnd,SW_HIDE); // hide the popup
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (corner==2)
|
|
{
|
|
wchar_t className[256]={0};
|
|
GetClassName(msg->hwnd,className,_countof(className));
|
|
if (wcscmp(className,L"EdgeUiInputWndClass")==0)
|
|
{
|
|
// suppress the hot corners
|
|
msg->message=WM_NULL;
|
|
ShowWindow(msg->hwnd,SW_HIDE);
|
|
g_EdgeWindows.insert(msg->hwnd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return CallNextHookEx(NULL,code,wParam,lParam);
|
|
}
|
|
|
|
static LRESULT CALLBACK HookNewWindow( int code, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
if (code==HCBT_CREATEWND)
|
|
{
|
|
CBT_CREATEWND *pCreate=(CBT_CREATEWND*)lParam;
|
|
if (pCreate->lpcs->lpszClass>(LPTSTR)0xFFFF && (_wcsicmp(pCreate->lpcs->lpszClass,L"Shell_SecondaryTrayWnd")==0 ||
|
|
_wcsicmp(pCreate->lpcs->lpszClass,L"ToolbarWindow32")==0 || _wcsicmp(pCreate->lpcs->lpszClass,L"TrayClockWClass")==0 || _wcsicmp(pCreate->lpcs->lpszClass,L"ClockButton")==0))
|
|
PostMessage(g_TaskBar,g_StartMenuMsg,MSG_NEWTASKBAR,wParam);
|
|
}
|
|
return CallNextHookEx(NULL,code,wParam,lParam);
|
|
}
|
|
|
|
// Set the hotkeys and controls for the start menu
|
|
void EnableHotkeys( THotkeys enable )
|
|
{
|
|
if (g_bTrimHooks) return;
|
|
if (!g_TaskBar)
|
|
return;
|
|
if (GetWindowThreadProcessId(g_TaskBar,NULL)!=GetCurrentThreadId())
|
|
{
|
|
PostMessage(g_TaskBar,g_StartMenuMsg,MSG_HOTKEYS,enable);
|
|
return;
|
|
}
|
|
|
|
// must be executed in the same thread as the start button (otherwise RegisterHotKey doesn't work). also prevents race conditions
|
|
bool bHook=(enable==HOTKEYS_SETTINGS || (enable==HOTKEYS_NORMAL && GetSettingInt(L"ShiftWin")!=0));
|
|
if (bHook)
|
|
{
|
|
RegisterHotKey(g_TaskBar,g_HotkeyShiftID,MOD_SHIFT|MOD_WIN,0);
|
|
g_bHotkeyShift=true;
|
|
}
|
|
else if (g_bHotkeyShift)
|
|
{
|
|
UnregisterHotKey(g_TaskBar,g_HotkeyShiftID);
|
|
g_bHotkeyShift=false;
|
|
}
|
|
|
|
if (g_HotkeyCSM)
|
|
UnregisterHotKey(g_TaskBar,g_HotkeyCSMID);
|
|
g_HotkeyCSM=0;
|
|
|
|
if (g_HotkeyWSM)
|
|
UnregisterHotKey(g_TaskBar,g_HotkeyWSMID);
|
|
g_HotkeyWSM=0;
|
|
|
|
if (enable==HOTKEYS_NORMAL)
|
|
{
|
|
g_HotkeyCSM=GetSettingInt(L"CSMHotkey");
|
|
if (g_HotkeyCSM)
|
|
{
|
|
int mod=MOD_NOREPEAT;
|
|
if (g_HotkeyCSM&(HOTKEYF_SHIFT<<8)) mod|=MOD_SHIFT;
|
|
if (g_HotkeyCSM&(HOTKEYF_CONTROL<<8)) mod|=MOD_CONTROL;
|
|
if (g_HotkeyCSM&(HOTKEYF_ALT<<8)) mod|=MOD_ALT;
|
|
RegisterHotKey(g_TaskBar,g_HotkeyCSMID,mod,g_HotkeyCSM&255);
|
|
}
|
|
|
|
g_HotkeyWSM=GetSettingInt(L"WSMHotkey");
|
|
if (g_HotkeyWSM)
|
|
{
|
|
int mod=MOD_NOREPEAT;
|
|
if (g_HotkeyWSM&(HOTKEYF_SHIFT<<8)) mod|=MOD_SHIFT;
|
|
if (g_HotkeyWSM&(HOTKEYF_CONTROL<<8)) mod|=MOD_CONTROL;
|
|
if (g_HotkeyWSM&(HOTKEYF_ALT<<8)) mod|=MOD_ALT;
|
|
RegisterHotKey(g_TaskBar,g_HotkeyWSMID,mod,g_HotkeyWSM&255);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void UpdateStartButtonPosition(const TaskbarInfo* taskBar, const WINDOWPOS* pPos)
|
|
{
|
|
if (IsStartButtonSmallIcons(taskBar->taskbarId) != IsTaskbarSmallIcons())
|
|
RecreateStartButton(taskBar->taskbarId);
|
|
|
|
RECT rcTask;
|
|
MONITORINFO info;
|
|
UINT uEdge = GetTaskbarPosition(taskBar->taskBar, &info, NULL, &rcTask);
|
|
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 == info.rcMonitor.left) && (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
|
|
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;
|
|
if (taskBar && (taskBar->oldButtonSize.cx!=rc.right || taskBar->oldButtonSize.cy!=rc.bottom))
|
|
{
|
|
taskBar->oldButtonSize.cx=rc.right;
|
|
taskBar->oldButtonSize.cy=rc.bottom;
|
|
RECT rcTask;
|
|
GetWindowRect(taskBar->taskBar,&rcTask);
|
|
PostMessage(taskBar->taskBar,WM_SIZE,SIZE_RESTORED,MAKELONG(rcTask.right-rcTask.left,rcTask.bottom-rcTask.top));
|
|
}
|
|
}
|
|
if (uMsg==WM_POINTERACTIVATE && CMenuContainer::IsMenuOpened())
|
|
return MA_NOACTIVATE;
|
|
#ifdef START_TOUCH
|
|
if (uMsg==WM_POINTERUP || uMsg==WM_POINTERUPDATE || uMsg==WM_POINTERUP)
|
|
{
|
|
POINTER_INPUT_TYPE type;
|
|
GetPointerType2(GET_POINTERID_WPARAM(wParam),&type);
|
|
if (type==PT_TOUCH)
|
|
{
|
|
return SendMessage(GetParent(hWnd),uMsg,wParam,lParam);
|
|
}
|
|
}
|
|
#endif
|
|
if (uMsg==WM_PAINT && GetWinVersion()>=WIN_VER_WIN10)
|
|
{
|
|
g_CurrentTaskbarButton=hWnd;
|
|
LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
g_CurrentTaskbarButton=NULL;
|
|
return res;
|
|
}
|
|
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
static bool g_bSuppressMessage243;
|
|
|
|
static LRESULT CALLBACK SubclassWin7StartButton( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
|
|
{
|
|
if (uMsg==243 && g_bSuppressMessage243)
|
|
{
|
|
// HACK: if the start button is smaller than the original, some NC clicks on the taskbar may be interpreted as clicks on the start button and open the WSM
|
|
// This is prevented by suppressing message 243 while processing WM_NCLBUTTONDOWN on the taskbar
|
|
return 0;
|
|
}
|
|
if (uMsg==WM_WINDOWPOSCHANGING)
|
|
{
|
|
// keep the Win7 start button hidden at all times
|
|
((WINDOWPOS*)lParam)->flags&=~SWP_SHOWWINDOW;
|
|
}
|
|
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
static LRESULT CALLBACK SubclassUserPicProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
|
|
{
|
|
if (uMsg==WM_WINDOWPOSCHANGING && !(((WINDOWPOS*)lParam)->flags&SWP_NOMOVE))
|
|
{
|
|
if (GetSettingBool(L"HideUserPic"))
|
|
{
|
|
((WINDOWPOS*)lParam)->x=-32000;
|
|
((WINDOWPOS*)lParam)->y=-32000;
|
|
}
|
|
}
|
|
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
static LRESULT CALLBACK SubclassTopMenuProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
|
|
{
|
|
if (uMsg==WM_ACTIVATE && GetSettingBool(L"CascadeAll"))
|
|
{
|
|
if (!wParam)
|
|
{
|
|
if (CMenuContainer::s_bPreventClosing) return 0;
|
|
// check if another menu window is being activated
|
|
// if not, close all menus
|
|
for (std::vector<CMenuContainer*>::const_iterator it=CMenuContainer::s_Menus.begin();it!=CMenuContainer::s_Menus.end();++it)
|
|
if ((*it)->m_hWnd==(HWND)lParam)
|
|
return 0;
|
|
}
|
|
}
|
|
if (uMsg==WM_WINDOWPOSCHANGED && (((WINDOWPOS*)lParam)->flags&SWP_SHOWWINDOW))
|
|
{
|
|
g_LastHoverPos=GetMessagePos();
|
|
if (g_ProgramsButton && GetSettingInt(L"InitiallySelect")==1)
|
|
PostMessage(hWnd,WM_CLEAR,'CLSH',0);
|
|
g_CurrentWSMTaskbar=MAIN_TASK_BAR;
|
|
PressStartButton(MAIN_TASK_BAR,true);
|
|
}
|
|
if (uMsg==WM_CLEAR && wParam=='CLSH' && g_ProgramsButton)
|
|
{
|
|
SetFocus(g_ProgramsButton);
|
|
return 0;
|
|
}
|
|
if (uMsg==WM_SHOWWINDOW)
|
|
{
|
|
if (!wParam)
|
|
{
|
|
CMenuContainer::CloseProgramsMenu();
|
|
g_CurrentWSMTaskbar=-1;
|
|
PressStartButton(MAIN_TASK_BAR,false);
|
|
}
|
|
g_bAllProgramsTimer=false;
|
|
if (g_ProgramsButton) KillTimer(g_ProgramsButton,'CLSM');
|
|
}
|
|
if (uMsg==WM_DESTROY)
|
|
g_TopWin7Menu=NULL;
|
|
if (uMsg==WM_ACTIVATEAPP && !wParam)
|
|
{
|
|
if (CMenuContainer::s_bPreventClosing) return 0;
|
|
}
|
|
if (uMsg==WM_MOUSEACTIVATE && GetSettingBool(L"CascadeAll") && CMenuContainer::IsMenuOpened())
|
|
{
|
|
CPoint pt(GetMessagePos());
|
|
if (g_ProgramsButton && WindowFromPoint(pt)==g_ProgramsButton)
|
|
return MA_NOACTIVATEANDEAT;
|
|
CMenuContainer::CloseProgramsMenu();
|
|
return MA_ACTIVATEANDEAT;
|
|
}
|
|
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
static LRESULT CALLBACK SubclassProgramsProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
|
|
{
|
|
if (uMsg==WM_COMMAND && wParam==IDOK && GetSettingBool(L"CascadeAll"))
|
|
{
|
|
if (GetKeyState(VK_SHIFT)<0)
|
|
{
|
|
if (CMenuContainer::IsMenuOpened())
|
|
return 0; // ignore shift+click when the menu is opened
|
|
}
|
|
else
|
|
{
|
|
if (!CMenuContainer::IsMenuOpened())
|
|
CMenuContainer::ToggleStartMenu(MAIN_TASK_BAR,GetKeyState(VK_SPACE)<0 || GetKeyState(VK_RETURN)<0 || GetKeyState(VK_LEFT)<0 || GetKeyState(VK_RIGHT)<0,true);
|
|
return 0;
|
|
}
|
|
}
|
|
if (uMsg==WM_DRAWITEM && wParam==IDOK && CMenuContainer::IsMenuOpened())
|
|
{
|
|
DRAWITEMSTRUCT *pDraw=(DRAWITEMSTRUCT*)lParam;
|
|
pDraw->itemState=ODS_HOTLIGHT; // draw highlighted when the menu is open
|
|
}
|
|
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
static BOOL CALLBACK FindWindowsMenuProc( HWND hwnd, LPARAM lParam )
|
|
{
|
|
wchar_t name[100];
|
|
GetClassName(hwnd,name,_countof(name));
|
|
if (_wcsicmp(name,L"DV2ControlHost")==0)
|
|
{
|
|
HWND w1=hwnd;
|
|
if (GetWinVersion()==WIN_VER_VISTA)
|
|
{
|
|
w1=FindWindowEx(w1,NULL,L"Desktop Open Pane Host",NULL);
|
|
if (!w1) return TRUE;
|
|
}
|
|
w1=FindWindowEx(w1,NULL,L"Desktop More Programs Pane",NULL);
|
|
if (!w1) return TRUE;
|
|
|
|
g_TopWin7Menu=hwnd;
|
|
g_AllPrograms=w1;
|
|
g_ProgramsButton=GetDlgItem(w1,IDOK); // this may not exist
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static void FindWindowsMenu( void )
|
|
{
|
|
if (g_TopWin7Menu) return;
|
|
if (GetWinVersion()<WIN_VER_WIN8)
|
|
{
|
|
Assert(GetCurrentThreadId()==GetWindowThreadProcessId(g_TaskBar,NULL));
|
|
EnumThreadWindows(GetCurrentThreadId(),FindWindowsMenuProc,0);
|
|
if (g_TopWin7Menu)
|
|
{
|
|
g_UserPic=FindWindow(L"Desktop User Picture",NULL);
|
|
SetWindowSubclass(g_UserPic,SubclassUserPicProc,'CLSH',0);
|
|
SetWindowSubclass(g_TopWin7Menu,SubclassTopMenuProc,'CLSH',0);
|
|
SetWindowSubclass(g_AllPrograms,SubclassProgramsProc,'CLSH',0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void PrintTaskbarBackground( HDC hdc, const RECT &rcClient, const RECT &rcPaint, UINT uEdge )
|
|
{
|
|
FillRect(hdc,&rcPaint,(HBRUSH)GetStockObject(BLACK_BRUSH));
|
|
HDC hsrc=CreateCompatibleDC(hdc);
|
|
HGDIOBJ bmp0=SelectObject(hsrc,g_TaskbarTexture);
|
|
|
|
int countH=1, countV=1;
|
|
int offsX=0, offsY=0;
|
|
if (g_TaskbarTileH==TILE_TILE)
|
|
{
|
|
countH=(rcClient.right-rcClient.left+g_TaskbarTextureSize.cx-1)/g_TaskbarTextureSize.cx;
|
|
if (uEdge==ABE_LEFT)
|
|
offsX=rcClient.right-rcClient.left-countH*g_TaskbarTextureSize.cx;
|
|
}
|
|
if (g_TaskbarTileV==TILE_TILE)
|
|
{
|
|
countV=(rcClient.bottom-rcClient.top+g_TaskbarTextureSize.cy-1)/g_TaskbarTextureSize.cy;
|
|
if (uEdge==ABE_TOP)
|
|
offsY=rcClient.bottom-rcClient.top-countV*g_TaskbarTextureSize.cy;
|
|
}
|
|
|
|
for (int y=0;y<countV;y++)
|
|
{
|
|
RECT rSrc={0,0,g_TaskbarTextureSize.cx,g_TaskbarTextureSize.cy};
|
|
RECT rDst=rcClient;
|
|
if (g_TaskbarTileV==TILE_TILE)
|
|
{
|
|
rDst.top+=g_TaskbarTextureSize.cy*y+offsY;
|
|
rDst.bottom=rDst.top+g_TaskbarTextureSize.cy;
|
|
}
|
|
if (rDst.bottom<=rcPaint.top) continue;
|
|
if (rDst.top>=rcPaint.bottom) break;
|
|
for (int x=0;x<countH;x++)
|
|
{
|
|
if (g_TaskbarTileH==TILE_TILE)
|
|
{
|
|
rDst.left=rcClient.left+g_TaskbarTextureSize.cx*x+offsX;
|
|
rDst.right=rDst.left+g_TaskbarTextureSize.cx;
|
|
}
|
|
if (rDst.right<=rcPaint.left) continue;
|
|
if (rDst.left>=rcPaint.right) break;
|
|
MarginsBlit(hsrc,hdc,rSrc,rDst,g_TaskbarMargins,true);
|
|
}
|
|
}
|
|
|
|
SelectObject(hsrc,bmp0);
|
|
DeleteDC(hsrc);
|
|
}
|
|
|
|
static void ComputeTaskbarColors( int *data )
|
|
{
|
|
bool bDefLook;
|
|
int look=GetSettingInt(L"TaskbarLook",bDefLook);
|
|
if (GetWinVersion()<WIN_VER_WIN10 || look==TASKBAR_AEROGLASS || (look==TASKBAR_TRANSPARENT && g_TaskbarTexture))
|
|
{
|
|
memset(data,0,16);
|
|
}
|
|
else
|
|
{
|
|
bool bTransparent;
|
|
DWORD color0=GetMetroTaskbarColor(bTransparent);
|
|
data[0]=look+1; // 1 - opaque, 2 - transparent, 3 - glass
|
|
if (bDefLook)
|
|
data[0]=bTransparent?2:1;
|
|
data[1]=0x13;
|
|
int a=GetSettingInt(L"TaskbarOpacity")*255/100;
|
|
if ((TTaskbarLook)GetSettingInt(L"TaskbarLook")==TASKBAR_OPAQUE)
|
|
a=255;
|
|
if (a<0) a=0;
|
|
if (a>255) a=255;
|
|
bool bDefColor;
|
|
DWORD color=GetSettingInt(L"TaskbarColor",bDefColor);
|
|
if (bDefColor)
|
|
color=color0;
|
|
data[2]=(color&0xFFFFFF)|(a<<24);
|
|
}
|
|
data[3]=0;
|
|
}
|
|
|
|
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;
|
|
if (CreateImmersiveShell(pImmersiveShell))
|
|
{
|
|
CComPtr<IImmersiveMonitorService> pMonitorService;
|
|
IUnknown_QueryService(pImmersiveShell,SID_IImmersiveMonitorService,IID_IImmersiveMonitorService,(void**)&pMonitorService);
|
|
if (pMonitorService)
|
|
{
|
|
CPoint pt(GetMessagePos());
|
|
HMONITOR monitor=MonitorFromPoint(pt,MONITOR_DEFAULTTONEAREST);
|
|
CComPtr<IUnknown> pMonitor;
|
|
pMonitorService->GetFromHandle(monitor,&pMonitor);
|
|
if (pMonitorService)
|
|
{
|
|
CComPtr<ILauncherTipContextMenu> pMenu;
|
|
IUnknown_QueryService(pMonitor,SID_LauncherTipContextMenu,SID_LauncherTipContextMenu,(void**)&pMenu);
|
|
if (pMenu)
|
|
pMenu->ShowLauncherTipContextMenu(&pt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (g_AppManagerThread)
|
|
PostThreadMessage(g_AppManagerThread,g_StartMenuMsg,MSG_WINXMENU,GetMessagePos());
|
|
}
|
|
|
|
static LRESULT CALLBACK SubclassTrayButtonProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
|
|
{
|
|
if (uMsg==WM_WINDOWPOSCHANGING)
|
|
{
|
|
const TaskbarInfo *taskBar=GetTaskbarInfo((int)dwRefData);
|
|
if (taskBar && (taskBar->bReplaceButton || taskBar->bHideButton))
|
|
{
|
|
WINDOWPOS *pPos=(WINDOWPOS*)lParam;
|
|
if (!(pPos->flags&SWP_NOMOVE) || !(pPos->flags&SWP_NOSIZE))
|
|
{
|
|
if (pPos->flags&(SWP_NOMOVE|SWP_NOSIZE))
|
|
{
|
|
RECT rc;
|
|
GetWindowRect(hWnd,&rc);
|
|
MapWindowPoints(NULL,GetParent(hWnd),(POINT*)&rc,2);
|
|
if (pPos->flags&SWP_NOMOVE)
|
|
{
|
|
pPos->x=rc.left;
|
|
pPos->y=rc.top;
|
|
}
|
|
else
|
|
{
|
|
pPos->cx=rc.right-rc.left;
|
|
pPos->cy=rc.bottom-rc.top;
|
|
}
|
|
}
|
|
int dx=0, dy=0;
|
|
UINT uEdge=GetTaskbarPosition(taskBar->taskBar,NULL,NULL,NULL);
|
|
if (uEdge==ABE_LEFT || uEdge==ABE_RIGHT)
|
|
{
|
|
dy=taskBar->startButtonSize.cy-taskBar->oldButtonSize.cy;
|
|
}
|
|
else
|
|
{
|
|
dx=taskBar->startButtonSize.cx-taskBar->oldButtonSize.cx;
|
|
}
|
|
if (dx || dy)
|
|
{
|
|
pPos->x+=dx;
|
|
pPos->y+=dy;
|
|
pPos->flags&=~(SWP_NOMOVE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
static LRESULT CALLBACK SubclassTaskBarProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
|
|
{
|
|
if (uMsg==WM_MOUSEACTIVATE && (HIWORD(lParam)==WM_MBUTTONDOWN || GetWinVersion()>=WIN_VER_WIN10))
|
|
{
|
|
if (GetWinVersion()>=WIN_VER_WIN10 && CMenuContainer::IsMenuOpened() && CMenuContainer::HasInputHandler() && GetFocus())
|
|
{
|
|
// Win10: if the taskbar is clicked while the menu is opened, check if the touch keyboard button was clicked and ignore the activation
|
|
// Otherwise the click on the touch keyboard button will deactivate the menu (possibly because both run on the same thread)
|
|
// On Win8.1 the button already handles this and returns MA_NOACTIVATE
|
|
HWND hwnd=WindowFromPoint(CPoint(GetMessagePos()));
|
|
if (hwnd)
|
|
{
|
|
wchar_t className[256];
|
|
GetClassName(hwnd,className,_countof(className));
|
|
if (_wcsicmp(className,L"TIPBand")==0)
|
|
return MA_NOACTIVATE;
|
|
}
|
|
}
|
|
FindWindowsMenu();
|
|
if (g_TopWin7Menu && WindowsMenuOpened())
|
|
{
|
|
DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
return MA_ACTIVATEANDEAT; // ignore the next middle click, so it doesn't re-open the start menu
|
|
}
|
|
}
|
|
TaskbarInfo *taskBar=GetTaskbarInfo((int)dwRefData);
|
|
if (taskBar && (uMsg==WM_NCMOUSEMOVE || uMsg==WM_MOUSEMOVE) && PointAroundStartButton((int)dwRefData))
|
|
TaskBarMouseMove(taskBar->taskbarId);
|
|
if (taskBar && uMsg==WM_POINTERACTIVATE && CMenuContainer::IsMenuOpened())
|
|
return MA_NOACTIVATE;
|
|
static int touchTime;
|
|
#ifdef START_TOUCH
|
|
if (taskBar && (uMsg==WM_NCPOINTERDOWN || (uMsg==WM_POINTERDOWN && IS_POINTER_INCONTACT_WPARAM(wParam) && IS_POINTER_PRIMARY_WPARAM(wParam) && IS_POINTER_FIRSTBUTTON_WPARAM(wParam))))
|
|
{
|
|
POINTER_INPUT_TYPE type;
|
|
GetPointerType2(GET_POINTERID_WPARAM(wParam),&type);
|
|
if (type==PT_TOUCH)
|
|
{
|
|
if (PointAroundStartButton((int)dwRefData,CPoint(lParam)))
|
|
{
|
|
taskBar->pointerId=GET_POINTERID_WPARAM(wParam);
|
|
touchTime=GetMessageTime();
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
if (taskBar && (uMsg==WM_NCPOINTERUPDATE || uMsg==WM_POINTERUPDATE) && taskBar->pointerId==GET_POINTERID_WPARAM(wParam))
|
|
{
|
|
if (uMsg==WM_NCPOINTERUPDATE)
|
|
{
|
|
POINTER_INFO info;
|
|
if (GetPointerInfo2(taskBar->pointerId,&info) && (info.pointerFlags&4)!=0)
|
|
{
|
|
int time=GetMessageTime();
|
|
if (time-touchTime>500)
|
|
{
|
|
taskBar->pointerId=0;
|
|
ShowWinX();
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else if (IS_POINTER_INCONTACT_WPARAM(wParam))
|
|
{
|
|
int time=GetMessageTime();
|
|
if (time-touchTime>500)
|
|
{
|
|
taskBar->pointerId=0;
|
|
PostMessage(taskBar->startButton,WM_RBUTTONUP,0,MAKELPARAM(-1,-1));
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
uMsg=WM_POINTERUP;
|
|
}
|
|
if (taskBar && (uMsg==WM_POINTERUP || uMsg==WM_NCPOINTERUP) && taskBar->pointerId==GET_POINTERID_WPARAM(wParam))
|
|
{
|
|
if (PointAroundStartButton((int)dwRefData,CPoint(lParam)))
|
|
{
|
|
int control=GetSettingInt(L"MouseClick");
|
|
if (control==OPEN_BOTH && GetWinVersion()>=WIN_VER_WIN10)
|
|
control=GetWin10TabletMode()?OPEN_WINDOWS:OPEN_CLASSIC;
|
|
if (control==OPEN_CLASSIC)
|
|
ToggleStartMenu(taskBar->taskbarId,false);
|
|
else if (control==OPEN_WINDOWS)
|
|
PostMessage(g_ProgWin,WM_SYSCOMMAND,SC_TASKLIST,'WSMM');
|
|
}
|
|
taskBar->pointerId=0;
|
|
return 0;
|
|
}
|
|
#endif
|
|
if (uMsg==WM_SHOWWINDOW && taskBar)
|
|
{
|
|
if (taskBar->bReplaceButton)
|
|
ShowWindow(taskBar->startButton,wParam?SW_SHOW:SW_HIDE);
|
|
}
|
|
if (uMsg==WM_WINDOWPOSCHANGING && taskBar && taskBar->bReplaceButton)
|
|
{
|
|
WINDOWPOS *pPos=(WINDOWPOS*)lParam;
|
|
if (!(pPos->flags&SWP_NOZORDER) && pPos->hwndInsertAfter==HWND_BOTTOM)
|
|
{
|
|
SetWindowPos(taskBar->startButton,HWND_BOTTOM,0,0,0,0,SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOMOVE);
|
|
pPos->hwndInsertAfter=taskBar->startButton;
|
|
}
|
|
}
|
|
if (uMsg==WM_WINDOWPOSCHANGED && taskBar)
|
|
{
|
|
if (taskBar->bReplaceButton)
|
|
{
|
|
UpdateStartButtonPosition(taskBar,(WINDOWPOS*)lParam);
|
|
}
|
|
if (taskBar->oldButton && GetWinVersion()<WIN_VER_WIN10)
|
|
{
|
|
UINT uEdge=GetTaskbarPosition(hWnd,NULL,NULL,NULL);
|
|
int x=(uEdge==ABE_BOTTOM?-1:0);
|
|
SetWindowPos(taskBar->oldButton,NULL,x,0,0,0,SWP_NOSIZE|SWP_NOZORDER);
|
|
}
|
|
}
|
|
if (uMsg==WM_THEMECHANGED && taskBar)
|
|
{
|
|
if (taskBar->bReplaceButton)
|
|
{
|
|
RecreateStartButton((int)dwRefData);
|
|
}
|
|
taskBar->bThemeChanging=true;
|
|
LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
taskBar->bThemeChanging=false;
|
|
return res;
|
|
}
|
|
if ((uMsg==WM_DWMCOLORIZATIONCOLORCHANGED || uMsg==WM_SETTINGCHANGE || uMsg==0x5CB || uMsg==0x5BB) && taskBar && taskBar->bCustomLook && SetWindowCompositionAttribute && GetWinVersion()>=WIN_VER_WIN10)
|
|
{
|
|
LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
int data[4];
|
|
ComputeTaskbarColors(data);
|
|
WINCOMPATTRDATA attrData={0x13,&data,sizeof(data)};
|
|
SetWindowCompositionAttribute(hWnd,&attrData);
|
|
return res;
|
|
}
|
|
if ((uMsg==WM_DWMCOLORIZATIONCOLORCHANGED || uMsg==WM_SETTINGCHANGE) && taskBar && taskBar->bCustomLook && SetWindowCompositionAttribute && GetWinVersion()<WIN_VER_WIN10)
|
|
{
|
|
LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
UpdateTaskBars(TASKBAR_UPDATE_TEXTURE);
|
|
return res;
|
|
}
|
|
if (uMsg==WM_PAINT && taskBar)
|
|
{
|
|
if (taskBar->bCustomLook)
|
|
{
|
|
TTaskbarLook look=(TTaskbarLook)GetSettingInt(L"TaskbarLook");
|
|
WORD winVer=GetWinVersion();
|
|
BOOL blurBehind;
|
|
int margin;
|
|
enum { FLAG_BLUR=1, FLAG_MARGIN=2, FLAG_ATTRIBUTE=4};
|
|
int flags=0;
|
|
if (winVer==WIN_VER_WIN7)
|
|
{
|
|
blurBehind=look==TASKBAR_GLASS;
|
|
margin=look==TASKBAR_OPAQUE?0:-1;
|
|
flags=FLAG_BLUR|FLAG_MARGIN;
|
|
}
|
|
else if (winVer==WIN_VER_WIN8)
|
|
{
|
|
blurBehind=look==TASKBAR_OPAQUE;
|
|
margin=look==TASKBAR_OPAQUE?0:-1;
|
|
flags=FLAG_BLUR|FLAG_MARGIN|((look==TASKBAR_TRANSPARENT && g_TaskbarTexture)?FLAG_ATTRIBUTE:0);
|
|
}
|
|
else if (winVer==WIN_VER_WIN81)
|
|
{
|
|
blurBehind=look==TASKBAR_OPAQUE;
|
|
margin=look==TASKBAR_OPAQUE?0:-1;
|
|
flags=FLAG_BLUR|FLAG_MARGIN|((look==TASKBAR_OPAQUE || g_TaskbarTexture)?FLAG_ATTRIBUTE:0);
|
|
}
|
|
else if (winVer>=WIN_VER_WIN10)
|
|
{
|
|
blurBehind=TRUE;
|
|
margin=look==TASKBAR_OPAQUE?0:-1;
|
|
flags=(look==TASKBAR_AEROGLASS?FLAG_BLUR:0)|(look!=TASKBAR_GLASS?FLAG_MARGIN:0)|FLAG_ATTRIBUTE;
|
|
}
|
|
|
|
if (flags&FLAG_BLUR)
|
|
{
|
|
DWM_BLURBEHIND blur={DWM_BB_ENABLE,blurBehind};
|
|
DwmEnableBlurBehindWindow(hWnd,&blur);
|
|
}
|
|
if (flags&FLAG_MARGIN)
|
|
{
|
|
MARGINS margins={margin};
|
|
DwmExtendFrameIntoClientArea(hWnd,&margins);
|
|
}
|
|
if (SetWindowCompositionAttribute && (flags&FLAG_ATTRIBUTE))
|
|
{
|
|
int data[4];
|
|
ComputeTaskbarColors(data);
|
|
WINCOMPATTRDATA attrData={0x13,&data,sizeof(data)};
|
|
SetWindowCompositionAttribute(hWnd,&attrData);
|
|
}
|
|
if (g_TaskbarTexture && IsAppThemed())
|
|
{
|
|
// draw taskbar background (behind start button and separators)
|
|
PAINTSTRUCT ps;
|
|
HDC hdc=BeginPaint(hWnd,&ps);
|
|
RECT rc;
|
|
GetClientRect(hWnd,&rc);
|
|
UINT uEdge=GetTaskbarPosition(hWnd,NULL,NULL,NULL);
|
|
PrintTaskbarBackground(hdc,rc,ps.rcPaint,uEdge);
|
|
EndPaint(hWnd,&ps);
|
|
return 0;
|
|
}
|
|
}
|
|
if (taskBar->bReplaceButton && g_WinStartButton && !IsAppThemed())
|
|
{
|
|
// prevent painting of the default classic button
|
|
PAINTSTRUCT ps;
|
|
HDC hdc=BeginPaint(hWnd,&ps);
|
|
EndPaint(hWnd,&ps);
|
|
return 0;
|
|
}
|
|
}
|
|
if (uMsg==WM_PRINTCLIENT && g_TaskbarTexture)
|
|
{
|
|
// print taskbar background - for background of buttons and tray area
|
|
HDC hdc=(HDC)wParam;
|
|
RECT rc;
|
|
GetClientRect(hWnd,&rc);
|
|
UINT uEdge=GetTaskbarPosition(hWnd,NULL,NULL,NULL);
|
|
PrintTaskbarBackground(hdc,rc,rc,uEdge);
|
|
return 0;
|
|
}
|
|
if (uMsg==0x5C5 && taskBar && taskBar->bCustomLook && IsWin81Update1()) // some secret message when the taskbar is raised to the top
|
|
{
|
|
// reset the opaqueness
|
|
PostMessage(g_TaskBar,g_StartMenuMsg,MSG_REDRAWTASKBAR,(LPARAM)hWnd);
|
|
}
|
|
if (uMsg==WM_DESTROY && taskBar)
|
|
{
|
|
if (taskBar->bReplaceButton)
|
|
DestroyStartButton(taskBar->taskbarId);
|
|
g_TaskbarInfos.erase(g_TaskbarInfos.find(taskBar->taskbarId));
|
|
}
|
|
if (uMsg==WM_TIMER && wParam=='CLSM')
|
|
{
|
|
if (GetMetroMode(NULL)==METRO_NONE)
|
|
{
|
|
KillTimer(hWnd,'CLSM');
|
|
return 0;
|
|
}
|
|
SetForegroundWindow(hWnd);
|
|
LogToFile(STARTUP_LOG,L"StartMenu DLL: skipping Metro");
|
|
if (GetSettingInt(L"SkipMetroCount")<0)
|
|
{
|
|
INPUT inputs[4]={
|
|
{INPUT_KEYBOARD},
|
|
{INPUT_KEYBOARD},
|
|
{INPUT_KEYBOARD},
|
|
{INPUT_KEYBOARD},
|
|
};
|
|
inputs[0].ki.wVk=VK_LWIN;
|
|
inputs[1].ki.wVk='D';
|
|
inputs[2].ki.wVk='D';
|
|
inputs[2].ki.dwFlags=KEYEVENTF_KEYUP;
|
|
inputs[3].ki.wVk=VK_LWIN;
|
|
inputs[3].ki.dwFlags=KEYEVENTF_KEYUP;
|
|
SendInput(_countof(inputs),inputs,sizeof(INPUT));
|
|
}
|
|
else
|
|
{
|
|
HWND hwnd=FindWindow(L"ModeInputWnd",NULL);
|
|
if (hwnd)
|
|
{
|
|
DWORD process;
|
|
GetWindowThreadProcessId(hwnd,&process);
|
|
if (process==GetCurrentProcessId())
|
|
{
|
|
IObjectWithSite *pObject=(IObjectWithSite*)GetWindowLongPtr(hwnd,0);
|
|
if (pObject)
|
|
{
|
|
CComPtr<IUnknown> pSite;
|
|
pObject->GetSite(IID_IUnknown,(void**)&pSite);
|
|
if (pSite)
|
|
{
|
|
CComPtr<IImmersiveLauncher80> pLauncher;
|
|
IUnknown_QueryService(pSite,SID_ImmersiveLauncher,IID_IImmersiveLauncher80,(void**)&pLauncher);
|
|
if (pLauncher)
|
|
pLauncher->Dismiss(5);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
g_SkipMetroCount--;
|
|
if (g_SkipMetroCount<=0)
|
|
KillTimer(hWnd,'CLSM');
|
|
return 0;
|
|
}
|
|
if (uMsg==WM_MOVE)
|
|
{
|
|
ResetHotCorners();
|
|
}
|
|
if (uMsg==WM_NCLBUTTONDOWN && taskBar && GetWinVersion()==WIN_VER_WIN7 && taskBar->bReplaceButton)
|
|
{
|
|
g_bSuppressMessage243=true;
|
|
LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
g_bSuppressMessage243=false;
|
|
return res;
|
|
}
|
|
if (uMsg==WM_PARENTNOTIFY && taskBar && LOWORD(wParam)==WM_CREATE && GetWinVersion()>=WIN_VER_WIN10)
|
|
{
|
|
wchar_t name[100];
|
|
HWND child=(HWND)lParam;
|
|
GetClassName(child,name,_countof(name));
|
|
if (_wcsicmp(name,L"TrayButton")==0 && GetParent(child)==hWnd)
|
|
{
|
|
bool bFound=false;
|
|
for (std::vector<HWND>::const_iterator it=taskBar->trayButtons.begin();it!=taskBar->trayButtons.end();++it)
|
|
if (*it==child)
|
|
{
|
|
bFound=true;
|
|
break;
|
|
}
|
|
if (!bFound)
|
|
{
|
|
taskBar->trayButtons.push_back(child);
|
|
SetWindowSubclass(child,SubclassTrayButtonProc,'CLSH',taskBar->taskbarId);
|
|
}
|
|
}
|
|
}
|
|
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
static LRESULT CALLBACK SubclassTaskListProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
|
|
{
|
|
if (uMsg==WM_PAINT && g_TaskbarTexture)
|
|
{
|
|
wchar_t name[100];
|
|
GetClassName(hWnd,name,_countof(name));
|
|
if (_wcsicmp(name,L"MSTaskSwWClass")==0)
|
|
{
|
|
// draw taskbar background (behind task list)
|
|
PAINTSTRUCT ps;
|
|
HDC hdc=BeginPaint(hWnd,&ps);
|
|
DrawThemeParentBackground(hWnd,hdc,NULL);
|
|
EndPaint(hWnd,&ps);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (uMsg==WM_PAINT || uMsg==WM_PRINT || uMsg==WM_PRINTCLIENT)
|
|
{
|
|
g_CurrentTaskList=hWnd;
|
|
LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
g_CurrentTaskList=NULL;
|
|
return res;
|
|
}
|
|
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
static LRESULT CALLBACK SubclassTrayChevronProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
|
|
{
|
|
if (uMsg==WM_PAINT || uMsg==WM_PRINT || uMsg==WM_PRINTCLIENT)
|
|
{
|
|
g_CurrentTaskChevron=hWnd;
|
|
LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
g_CurrentTaskChevron=NULL;
|
|
return res;
|
|
}
|
|
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
static LRESULT CALLBACK SubclassDesktopButtonProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
|
|
{
|
|
if (uMsg==WM_PAINT || uMsg==WM_PRINT || uMsg==WM_PRINTCLIENT)
|
|
{
|
|
g_CurrentDesktopButton=hWnd;
|
|
LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
g_CurrentDesktopButton=NULL;
|
|
return res;
|
|
}
|
|
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
static LRESULT CALLBACK SubclassRebarProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
|
|
{
|
|
if (uMsg==WM_WINDOWPOSCHANGING)
|
|
{
|
|
const TaskbarInfo *taskBar=GetTaskbarInfo((int)dwRefData);
|
|
if (taskBar && (taskBar->bReplaceButton || taskBar->bHideButton))
|
|
{
|
|
WINDOWPOS *pPos=(WINDOWPOS*)lParam;
|
|
if (!(pPos->flags&SWP_NOMOVE) || !(pPos->flags&SWP_NOSIZE))
|
|
{
|
|
if (pPos->flags&(SWP_NOMOVE|SWP_NOSIZE))
|
|
{
|
|
RECT rc;
|
|
GetWindowRect(hWnd,&rc);
|
|
MapWindowPoints(NULL,GetParent(hWnd),(POINT*)&rc,2);
|
|
if (pPos->flags&SWP_NOMOVE)
|
|
{
|
|
pPos->x=rc.left;
|
|
pPos->y=rc.top;
|
|
}
|
|
else
|
|
{
|
|
pPos->cx=rc.right-rc.left;
|
|
pPos->cy=rc.bottom-rc.top;
|
|
}
|
|
}
|
|
int dx=0, dy=0;
|
|
UINT uEdge=GetTaskbarPosition(taskBar->taskBar,NULL,NULL,NULL);
|
|
if (taskBar->oldButton)
|
|
{
|
|
if (uEdge==ABE_LEFT || uEdge==ABE_RIGHT)
|
|
{
|
|
dy=taskBar->startButtonSize.cy-taskBar->oldButtonSize.cy;
|
|
}
|
|
else
|
|
{
|
|
dx=taskBar->startButtonSize.cx-taskBar->oldButtonSize.cx;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (uEdge==ABE_LEFT || uEdge==ABE_RIGHT)
|
|
{
|
|
dy=taskBar->startButtonSize.cy-pPos->y;
|
|
}
|
|
else
|
|
{
|
|
dx=taskBar->startButtonSize.cx-pPos->x;
|
|
}
|
|
}
|
|
if (dx || dy)
|
|
{
|
|
pPos->x+=dx;
|
|
pPos->cx-=dx;
|
|
pPos->y+=dy;
|
|
pPos->cy-=dy;
|
|
pPos->flags&=~(SWP_NOMOVE|SWP_NOSIZE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (uMsg==WM_PAINT || uMsg==WM_PRINT || uMsg==WM_PRINTCLIENT)
|
|
{
|
|
g_CurrentRebar=hWnd;
|
|
LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
g_CurrentRebar=NULL;
|
|
return res;
|
|
}
|
|
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
static LRESULT CALLBACK SubclassTaskbarPartProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
|
|
{
|
|
if (uMsg==WM_PAINT || uMsg==WM_PRINT || uMsg==WM_PRINTCLIENT)
|
|
{
|
|
g_CurrentTaskbarPart=hWnd;
|
|
LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
g_CurrentTaskbarPart=NULL;
|
|
return res;
|
|
}
|
|
if (uMsg==WM_NCDESTROY)
|
|
{
|
|
TaskbarInfo *info=GetTaskbarInfo((int)dwRefData);
|
|
if (info)
|
|
{
|
|
for (std::vector<HWND>::const_iterator it=info->taskbarParts.begin();it!=info->taskbarParts.end();++it)
|
|
if (*it==hWnd)
|
|
{
|
|
info->taskbarParts.erase(it);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
static void HandleTaskbarParts( TaskbarInfo &taskBar, bool bPrimary )
|
|
{
|
|
if (taskBar.rebar)
|
|
{
|
|
int count=(int)SendMessage(taskBar.rebar,RB_GETBANDCOUNT,0,0);
|
|
for (int i=0;i<count;i++)
|
|
{
|
|
REBARBANDINFO info={sizeof(info),RBBIM_CHILD};
|
|
if (SendMessage(taskBar.rebar,RB_GETBANDINFO,i,(LPARAM)&info))
|
|
{
|
|
wchar_t name[100];
|
|
GetClassName(info.hwndChild,name,_countof(name));
|
|
if (_wcsicmp(name,L"ToolbarWindow32")==0 && !taskBar.HasPart(info.hwndChild))
|
|
{
|
|
SetWindowSubclass(info.hwndChild,SubclassTaskbarPartProc,'CLSH',taskBar.taskbarId);
|
|
taskBar.taskbarParts.push_back(info.hwndChild);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (bPrimary)
|
|
{
|
|
HWND tray=FindWindowEx(taskBar.taskBar,NULL,L"TrayNotifyWnd",NULL);
|
|
if (tray)
|
|
{
|
|
HWND clock=FindWindowEx(tray,NULL,L"TrayClockWClass",NULL);
|
|
if (clock && !taskBar.HasPart(clock))
|
|
{
|
|
SetWindowSubclass(clock,SubclassTaskbarPartProc,'CLSH',taskBar.taskbarId);
|
|
taskBar.taskbarParts.push_back(clock);
|
|
}
|
|
if (GetWinVersion()<=WIN_VER_WIN81)
|
|
{
|
|
taskBar.desktop=FindWindowEx(tray,NULL,L"TrayShowDesktopButtonWClass",NULL);
|
|
if (taskBar.desktop)
|
|
SetWindowSubclass(taskBar.desktop,SubclassDesktopButtonProc,'CLSH',taskBar.taskbarId);
|
|
}
|
|
}
|
|
}
|
|
else if (GetWinVersion()>=WIN_VER_WIN10)
|
|
{
|
|
HWND clock=FindWindowEx(taskBar.taskBar,NULL,L"ClockButton",NULL);
|
|
if (clock && !taskBar.HasPart(clock))
|
|
{
|
|
SetWindowSubclass(clock,SubclassTaskbarPartProc,'CLSH',taskBar.taskbarId);
|
|
taskBar.taskbarParts.push_back(clock);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void HandleSecondaryTaskbar( HWND hwnd )
|
|
{
|
|
int taskbarId=g_NextTaskbar++;
|
|
TaskbarInfo &taskBar=g_TaskbarInfos[taskbarId];
|
|
taskBar.taskBar=hwnd;
|
|
taskBar.taskbarId=taskbarId;
|
|
|
|
taskBar.rebar=FindWindowEx(hwnd,NULL,L"WorkerW",NULL);
|
|
if (taskBar.rebar)
|
|
{
|
|
SetWindowSubclass(taskBar.rebar,SubclassRebarProc,'CLSH',taskbarId);
|
|
taskBar.taskList=FindWindowEx(taskBar.rebar,NULL,L"MSTaskListWClass",NULL);
|
|
if (taskBar.taskList)
|
|
SetWindowSubclass(taskBar.taskList,SubclassTaskListProc,'CLSH',taskbarId);
|
|
}
|
|
if (GetWinVersion()>WIN_VER_WIN8)
|
|
{
|
|
taskBar.oldButton=FindWindowEx(taskBar.taskBar,NULL,L"Start",NULL);
|
|
if (taskBar.oldButton)
|
|
{
|
|
if (GetWinVersion()>=WIN_VER_WIN10)
|
|
{
|
|
taskBar.pOriginalTarget=(IDropTarget*)GetProp(taskBar.oldButton,L"OleDropTargetInterface");
|
|
if (taskBar.pOriginalTarget)
|
|
RevokeDragDrop(taskBar.oldButton);
|
|
}
|
|
|
|
CStartMenuTarget *pNewTarget=new CStartMenuTarget(taskBar.taskbarId);
|
|
RegisterDragDrop(taskBar.oldButton,pNewTarget);
|
|
pNewTarget->Release();
|
|
if (GetWinVersion()<WIN_VER_WIN10 && GetTaskbarPosition(taskBar.taskBar,NULL,NULL,NULL)==ABE_BOTTOM)
|
|
SetWindowPos(taskBar.oldButton,NULL,-1,0,0,0,SWP_NOSIZE|SWP_NOZORDER);
|
|
SetWindowSubclass(taskBar.oldButton,SubclassWin81StartButton,'CLSH',taskBar.taskbarId);
|
|
}
|
|
}
|
|
if (GetWinVersion()>=WIN_VER_WIN10)
|
|
{
|
|
for (HWND button=FindWindowEx(taskBar.taskBar,NULL,L"TrayButton",NULL);button;button=FindWindowEx(taskBar.taskBar,button,L"TrayButton",NULL))
|
|
{
|
|
taskBar.trayButtons.push_back(button);
|
|
SetWindowSubclass(button,SubclassTrayButtonProc,'CLSH',taskBar.taskbarId);
|
|
}
|
|
HWND search=FindWindowEx(taskBar.taskBar,NULL,L"TrayDummySearchControl",NULL);
|
|
if (search)
|
|
{
|
|
taskBar.trayButtons.push_back(search);
|
|
SetWindowSubclass(search,SubclassTrayButtonProc,'CLSH',taskBar.taskbarId);
|
|
}
|
|
}
|
|
HandleTaskbarParts(taskBar,false);
|
|
SetWindowSubclass(taskBar.taskBar,SubclassTaskBarProc,'CLSH',taskbarId);
|
|
UpdateTaskBars(TASKBAR_UPDATE);
|
|
UpdateTaskBars(TASKBAR_UPDATE_TEXTURE);
|
|
}
|
|
|
|
static BOOL CALLBACK HookAllTaskbarsEnum( HWND hwnd, LPARAM lParam )
|
|
{
|
|
// look for top-level windows with class "Shell_SecondaryTrayWnd" in the current thread
|
|
if (GetWindowThreadProcessId(hwnd,NULL)!=GetCurrentThreadId()) return TRUE;
|
|
wchar_t name[256];
|
|
GetClassName(hwnd,name,_countof(name));
|
|
if (_wcsicmp(name,L"Shell_SecondaryTrayWnd")==0)
|
|
HandleSecondaryTaskbar(hwnd);
|
|
return TRUE;
|
|
}
|
|
|
|
void UpdateTaskBars( TUpdateTaskbar update )
|
|
{
|
|
if (update==TASKBAR_UPDATE_TEXTURE)
|
|
{
|
|
if (g_TaskbarTexture)
|
|
DeleteObject(g_TaskbarTexture);
|
|
g_TaskbarTexture=NULL;
|
|
if (GetSettingBool(L"CustomTaskbar"))
|
|
{
|
|
g_TaskbarTileH=g_TaskbarTileV=TILE_STRETCH;
|
|
g_TaskbarMargins.left=g_TaskbarMargins.right=g_TaskbarMargins.top=g_TaskbarMargins.bottom=0;
|
|
TTaskbarLook look=(TTaskbarLook)GetSettingInt(L"TaskbarLook");
|
|
bool bDefOpacity;
|
|
int opacity=GetSettingInt(L"TaskbarOpacity",bDefOpacity);
|
|
if (look==TASKBAR_OPAQUE)
|
|
opacity=100, bDefOpacity=true;
|
|
bool bDefColor;
|
|
COLORREF color=GetSettingInt(L"TaskbarColor",bDefColor);
|
|
wchar_t fname[_MAX_PATH];
|
|
Strcpy(fname,_countof(fname),GetSettingString(L"TaskbarTexture"));
|
|
DoEnvironmentSubst(fname,_countof(fname));
|
|
if (*fname)
|
|
{
|
|
g_TaskbarTexture=LoadImageResource(NULL,fname,false,true);
|
|
g_TaskbarTileH=(TTaskbarTile)GetSettingInt(L"TaskbarTileH");
|
|
g_TaskbarTileV=(TTaskbarTile)GetSettingInt(L"TaskbarTileV");
|
|
if (g_TaskbarTileH==TILE_STRETCH)
|
|
{
|
|
CString borders=GetSettingString(L"TaskbarBordersH");
|
|
if (!borders.IsEmpty())
|
|
{
|
|
wchar_t token[256];
|
|
const wchar_t *str=GetToken(borders,token,_countof(token),L", \t");
|
|
g_TaskbarMargins.left=_wtol(token);
|
|
if (g_TaskbarMargins.left<0) g_TaskbarMargins.left=0;
|
|
str=GetToken(str,token,_countof(token),L", \t");
|
|
g_TaskbarMargins.right=_wtol(token);
|
|
if (g_TaskbarMargins.right<0) g_TaskbarMargins.right=0;
|
|
}
|
|
}
|
|
if (g_TaskbarTileV==TILE_STRETCH)
|
|
{
|
|
CString borders=GetSettingString(L"TaskbarBordersV");
|
|
if (!borders.IsEmpty())
|
|
{
|
|
wchar_t token[256];
|
|
const wchar_t *str=GetToken(borders,token,_countof(token),L", \t");
|
|
g_TaskbarMargins.top=_wtol(token);
|
|
if (g_TaskbarMargins.top<0) g_TaskbarMargins.top=0;
|
|
str=GetToken(str,token,_countof(token),L", \t");
|
|
g_TaskbarMargins.bottom=_wtol(token);
|
|
if (g_TaskbarMargins.bottom<0) g_TaskbarMargins.bottom=0;
|
|
}
|
|
}
|
|
}
|
|
else if (GetWinVersion()<WIN_VER_WIN10 && (!bDefColor || !bDefOpacity))
|
|
{
|
|
if (bDefColor && GetWinVersion()>WIN_VER_WIN7)
|
|
{
|
|
color=GetSystemGlassColor8();
|
|
color=((color&0xFF)<<16)|(color&0xFF00)|((color>>16)&0xFF);
|
|
}
|
|
BITMAPINFO bi={0};
|
|
bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
|
|
bi.bmiHeader.biWidth=bi.bmiHeader.biHeight=32;
|
|
bi.bmiHeader.biPlanes=1;
|
|
bi.bmiHeader.biBitCount=32;
|
|
|
|
HDC hdc=CreateCompatibleDC(NULL);
|
|
unsigned int *bits;
|
|
g_TaskbarTexture=CreateDIBSection(hdc,&bi,DIB_RGB_COLORS,(void**)&bits,NULL,0);
|
|
if (g_TaskbarTexture)
|
|
{
|
|
unsigned int val=((color&0xFF)<<16)|(color&0x00FF00)|((color>>16)&0xFF)|0xFF000000;
|
|
int count=bi.bmiHeader.biWidth*bi.bmiHeader.biHeight;
|
|
for (int i=0;i<count;i++)
|
|
bits[i]=val;
|
|
}
|
|
DeleteDC(hdc);
|
|
}
|
|
if (g_TaskbarTexture)
|
|
{
|
|
BITMAP info;
|
|
GetObject(g_TaskbarTexture,sizeof(info),&info);
|
|
int a=255;
|
|
BOOL comp=FALSE;
|
|
if (look!=TASKBAR_OPAQUE && SUCCEEDED(DwmIsCompositionEnabled(&comp)) && comp)
|
|
a=opacity*255/100;
|
|
if (a<0) a=0;
|
|
if (a<255)
|
|
{
|
|
int count=info.bmHeight*info.bmWidthBytes;
|
|
unsigned char *ptr=(unsigned char*)info.bmBits;
|
|
for (int i=0;i<count;i++,ptr++)
|
|
*ptr=*ptr*a/255;
|
|
}
|
|
g_TaskbarTextureSize.cx=info.bmWidth;
|
|
g_TaskbarTextureSize.cy=info.bmHeight;
|
|
int countH=g_TaskbarTileH==TILE_TILE?(255+info.bmWidth)/info.bmWidth:1;
|
|
int countV=g_TaskbarTileV==TILE_TILE?(255+info.bmHeight)/info.bmHeight:1;
|
|
if (countH>1 || countV>1)
|
|
{
|
|
// pretile texture
|
|
BITMAPINFO bi={0};
|
|
bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
|
|
bi.bmiHeader.biWidth=countH*info.bmWidth;
|
|
bi.bmiHeader.biHeight=countV*info.bmHeight;
|
|
bi.bmiHeader.biPlanes=1;
|
|
bi.bmiHeader.biBitCount=32;
|
|
|
|
HDC hdc=CreateCompatibleDC(NULL);
|
|
HDC hsrc=CreateCompatibleDC(hdc);
|
|
unsigned int *bits;
|
|
HBITMAP bmp=CreateDIBSection(hdc,&bi,DIB_RGB_COLORS,(void**)&bits,NULL,0);
|
|
if (bmp)
|
|
{
|
|
HGDIOBJ bmp01=SelectObject(hdc,bmp);
|
|
HGDIOBJ bmp02=SelectObject(hsrc,g_TaskbarTexture);
|
|
for (int y=0;y<countV;y++)
|
|
for (int x=0;x<countH;x++)
|
|
BitBlt(hdc,x*info.bmWidth,y*info.bmHeight,info.bmWidth,info.bmHeight,hsrc,0,0,SRCCOPY);
|
|
SelectObject(hsrc,bmp02);
|
|
SelectObject(hdc,bmp01);
|
|
DeleteObject(g_TaskbarTexture);
|
|
g_TaskbarTexture=bmp;
|
|
g_TaskbarTextureSize.cx*=countH;
|
|
g_TaskbarTextureSize.cy*=countV;
|
|
}
|
|
DeleteDC(hsrc);
|
|
DeleteDC(hdc);
|
|
}
|
|
}
|
|
for (id_taskbar_map::iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it)
|
|
RedrawWindow(it->second.taskBar,NULL,NULL,RDW_INVALIDATE|RDW_ALLCHILDREN);
|
|
}
|
|
return;
|
|
}
|
|
bool bButton=false, bCustomLook= false, bAll= false;
|
|
if (update==TASKBAR_CLEAR)
|
|
{
|
|
if (g_TaskbarTexture)
|
|
DeleteObject(g_TaskbarTexture);
|
|
g_TaskbarTexture=NULL;
|
|
}
|
|
else
|
|
{
|
|
bButton=GetSettingBool(L"EnableStartButton");
|
|
bCustomLook=GetSettingBool(L"CustomTaskbar");
|
|
bAll=GetSettingBool(L"AllTaskbars");
|
|
}
|
|
if (g_bTrimHooks)
|
|
bButton=false;
|
|
for (id_taskbar_map::iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it)
|
|
{
|
|
TaskbarInfo &taskBar=it->second;
|
|
bool bButton2=bButton && (bAll || taskBar.taskBar==g_TaskBar);
|
|
bool bHideButton2=bButton;
|
|
if (taskBar.oldButton)
|
|
{
|
|
if (bHideButton2 && !bButton2)
|
|
{
|
|
// reposition rebar
|
|
if (taskBar.oldButton)
|
|
{
|
|
RECT rc;
|
|
GetWindowRect(taskBar.oldButton,&rc);
|
|
taskBar.oldButtonSize.cx=rc.right-rc.left;
|
|
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));
|
|
}
|
|
if (taskBar.bHideButton!=bHideButton2)
|
|
{
|
|
// show/hide 8.1 button
|
|
taskBar.bHideButton=bHideButton2;
|
|
if (bHideButton2)
|
|
{
|
|
ShowWindow(taskBar.oldButton,SW_HIDE);
|
|
}
|
|
else
|
|
{
|
|
ShowWindow(taskBar.oldButton,SW_SHOW);
|
|
}
|
|
}
|
|
}
|
|
if (taskBar.bReplaceButton!=bButton2)
|
|
{
|
|
// create or destroy button
|
|
taskBar.bReplaceButton=bButton2;
|
|
|
|
if (bButton2)
|
|
{
|
|
RecreateStartButton(it->first);
|
|
if (g_WinStartButton)
|
|
{
|
|
ShowWindow(g_WinStartButton,SW_HIDE);
|
|
SetWindowSubclass(g_WinStartButton,SubclassWin7StartButton,'CLSH',0);
|
|
if (GetWinVersion()==WIN_VER_WIN7)
|
|
{
|
|
// Windows 7 draws the start button on the taskbar as well
|
|
// so we zero out the bitmap resources
|
|
HMODULE hExplorer=GetModuleHandle(NULL);
|
|
for (int res=0;res<_countof(g_StartButtonOldSizes);res++)
|
|
{
|
|
HRSRC hrSrc=FindResource(hExplorer,MAKEINTRESOURCE(res+FIRST_BUTTON_BITMAP),RT_BITMAP);
|
|
if (hrSrc)
|
|
{
|
|
HGLOBAL hRes=LoadResource(hExplorer,hrSrc);
|
|
if (hRes)
|
|
{
|
|
void *pRes=LockResource(hRes);
|
|
if (pRes)
|
|
{
|
|
DWORD old;
|
|
BITMAPINFOHEADER *pHeader=(BITMAPINFOHEADER*)pRes;
|
|
if (pHeader->biWidth)
|
|
{
|
|
g_StartButtonOldSizes[res]=MAKELONG(pHeader->biWidth,pHeader->biHeight);
|
|
VirtualProtect(pRes,sizeof(BITMAPINFOHEADER),PAGE_READWRITE,&old);
|
|
pHeader->biHeight=pHeader->biWidth=0;
|
|
VirtualProtect(pRes,sizeof(BITMAPINFOHEADER),old,&old);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
SendMessage(taskBar.taskBar,WM_SETTINGCHANGE,0,0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (taskBar.startButton && taskBar.startButton!=g_WinStartButton)
|
|
{
|
|
RevokeDragDrop(taskBar.startButton);
|
|
DestroyStartButton(taskBar.taskbarId);
|
|
}
|
|
taskBar.startButton=taskBar.taskBar==g_TaskBar?g_WinStartButton:NULL;
|
|
taskBar.startButtonSize.cx=taskBar.startButtonSize.cy=0;
|
|
if (g_WinStartButton && g_WinStartButton==taskBar.startButton)
|
|
{
|
|
// restore the bitmap sizes
|
|
HMODULE hExplorer=GetModuleHandle(NULL);
|
|
for (int res=0;res<_countof(g_StartButtonOldSizes);res++)
|
|
{
|
|
HRSRC hrSrc=FindResource(hExplorer,MAKEINTRESOURCE(res+FIRST_BUTTON_BITMAP),RT_BITMAP);
|
|
if (hrSrc)
|
|
{
|
|
HGLOBAL hRes=LoadResource(hExplorer,hrSrc);
|
|
if (hRes)
|
|
{
|
|
void *pRes=LockResource(hRes);
|
|
if (pRes)
|
|
{
|
|
DWORD old;
|
|
BITMAPINFOHEADER *pHeader=(BITMAPINFOHEADER*)pRes;
|
|
if (g_StartButtonOldSizes[res])
|
|
{
|
|
VirtualProtect(pRes,sizeof(BITMAPINFOHEADER),PAGE_READWRITE,&old);
|
|
pHeader->biWidth=LOWORD(g_StartButtonOldSizes[res]);
|
|
pHeader->biHeight=HIWORD(g_StartButtonOldSizes[res]);
|
|
VirtualProtect(pRes,sizeof(BITMAPINFOHEADER),old,&old);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
RemoveWindowSubclass(g_WinStartButton,SubclassWin7StartButton,'CLSH');
|
|
SendMessage(g_WinStartButton,WM_THEMECHANGED,0,0);
|
|
ShowWindow(g_WinStartButton,SW_SHOW);
|
|
}
|
|
}
|
|
}
|
|
else if (update==TASKBAR_RECREATE_BUTTONS && bButton2)
|
|
{
|
|
RecreateStartButton(it->first);
|
|
}
|
|
if (taskBar.bCustomLook!=bCustomLook)
|
|
{
|
|
// set custom look
|
|
taskBar.bCustomLook=bCustomLook;
|
|
|
|
if (!bCustomLook && GetWinVersion()<WIN_VER_WIN10)
|
|
{
|
|
DWM_BLURBEHIND blur={DWM_BB_ENABLE,GetWinVersion()<WIN_VER_WIN8};
|
|
DwmEnableBlurBehindWindow(taskBar.taskBar,&blur);
|
|
if (GetWinVersion()==WIN_VER_WIN7)
|
|
{
|
|
MARGINS margins={0};
|
|
DwmExtendFrameIntoClientArea(taskBar.taskBar,&margins);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (id_taskbar_map::iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it)
|
|
{
|
|
TaskbarInfo &taskBar=it->second;
|
|
SendMessage(taskBar.taskBar,WM_SETTINGCHANGE,0,0);
|
|
InvalidateRect(taskBar.taskBar,NULL,TRUE);
|
|
PostMessage(taskBar.taskBar,WM_THEMECHANGED,0,0);
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// hooks for animating the start button
|
|
|
|
typedef void (WINAPI *tDwmpBeginTransitionRequest)(int param);
|
|
typedef void (WINAPI *tDwmpTransitionWindowWithRects)(HWND,int,RECT*,RECT*,RECT*,RECT*,RECT*);
|
|
typedef void (WINAPI *tDwmpEndTransitionRequest)(int param);
|
|
|
|
static IatHookData *g_DwmpBTRHook, *g_DwmpTWWRHook, *g_DwmpETRHook;
|
|
|
|
static tDwmpBeginTransitionRequest g_DwmpBeginTransitionRequest;
|
|
static tDwmpTransitionWindowWithRects g_DwmpTransitionWindowWithRects;
|
|
static tDwmpEndTransitionRequest g_DwmpEndTransitionRequest;
|
|
|
|
static HWND g_TransitionButton;
|
|
static HWND g_TransitionBar;
|
|
static RECT g_TransitionClip;
|
|
static POINT g_TransitionVector;
|
|
static bool g_bTransitionIn;
|
|
|
|
void WINAPI DwmpBeginTransitionRequest2( int param )
|
|
{
|
|
g_TransitionButton=NULL;
|
|
((tDwmpBeginTransitionRequest)g_DwmpBTRHook->oldProc)(param);
|
|
}
|
|
|
|
void WINAPI DwmpTransitionWindowWithRects2( HWND hWnd, int flags, RECT *prcClient1, RECT *prcStart, RECT *prcClient2, RECT *prcEnd, RECT *prcClip )
|
|
{
|
|
g_TransitionButton=NULL;
|
|
const TaskbarInfo *taskBar=FindTaskBarInfoBar(hWnd);
|
|
if (taskBar && taskBar->bCustomLook)
|
|
{
|
|
g_TransitionBar=hWnd;
|
|
TTaskbarLook look=(TTaskbarLook)GetSettingInt(L"TaskbarLook");
|
|
DWM_BLURBEHIND blur={DWM_BB_ENABLE,look==TASKBAR_OPAQUE};
|
|
DwmEnableBlurBehindWindow(hWnd,&blur);
|
|
int data[4];
|
|
ComputeTaskbarColors(data);
|
|
WINCOMPATTRDATA attrData={0x13,&data,sizeof(data)};
|
|
SetWindowCompositionAttribute(hWnd,&attrData);
|
|
}
|
|
if (taskBar && taskBar->startButton && prcStart && prcEnd && prcClip)
|
|
{
|
|
g_TransitionButton=taskBar->startButton;
|
|
g_TransitionVector.x=prcEnd->left-prcStart->left;
|
|
g_TransitionVector.y=prcEnd->top-prcStart->top;
|
|
g_TransitionClip=*prcClip;
|
|
g_bTransitionIn=true;
|
|
switch (GetTaskbarPosition(taskBar->taskBar,NULL,NULL,NULL))
|
|
{
|
|
case ABE_LEFT:
|
|
g_bTransitionIn=g_TransitionVector.x>0;
|
|
break;
|
|
case ABE_TOP:
|
|
g_bTransitionIn=g_TransitionVector.y>0;
|
|
break;
|
|
case ABE_RIGHT:
|
|
g_bTransitionIn=g_TransitionVector.x<0;
|
|
break;
|
|
default:
|
|
g_bTransitionIn=g_TransitionVector.y<0;
|
|
}
|
|
}
|
|
((tDwmpTransitionWindowWithRects)g_DwmpTWWRHook->oldProc)(hWnd,flags,prcClient1,prcStart,prcClient2,prcEnd,prcClip);
|
|
}
|
|
|
|
void WINAPI DwmpEndTransitionRequest2( int param )
|
|
{
|
|
((tDwmpEndTransitionRequest)g_DwmpETRHook->oldProc)(param);
|
|
if (g_TransitionBar)
|
|
{
|
|
TTaskbarLook look=(TTaskbarLook)GetSettingInt(L"TaskbarLook");
|
|
DWM_BLURBEHIND blur={DWM_BB_ENABLE,look==TASKBAR_OPAQUE};
|
|
DwmEnableBlurBehindWindow(g_TransitionBar,&blur);
|
|
int data[4];
|
|
ComputeTaskbarColors(data);
|
|
WINCOMPATTRDATA attrData={0x13,&data,sizeof(data)};
|
|
SetWindowCompositionAttribute(g_TransitionBar,&attrData);
|
|
g_TransitionBar=NULL;
|
|
}
|
|
if (g_TransitionButton)
|
|
{
|
|
HWND button=g_TransitionButton;
|
|
g_TransitionButton=NULL;
|
|
g_DwmpBeginTransitionRequest(15);
|
|
RECT rcClient;
|
|
GetClientRect(button,&rcClient);
|
|
RECT rcStart, rcEnd;
|
|
if (g_bTransitionIn)
|
|
{
|
|
GetWindowRect(button,&rcEnd);
|
|
rcStart=rcEnd;
|
|
OffsetRect(&rcStart,-g_TransitionVector.x,-g_TransitionVector.y);
|
|
}
|
|
else
|
|
{
|
|
GetWindowRect(button,&rcStart);
|
|
rcEnd=rcStart;
|
|
int dx=0, dy=0;
|
|
if (g_TransitionVector.x<0) // left
|
|
{
|
|
dx=g_TransitionClip.left-rcStart.right;
|
|
if (dx>0) dx=g_TransitionVector.x;
|
|
}
|
|
else if (g_TransitionVector.x>0) // right
|
|
{
|
|
dx=g_TransitionClip.right-rcStart.left;
|
|
if (dx<0) dx=g_TransitionVector.x;
|
|
}
|
|
else if (g_TransitionVector.y<0) // top
|
|
{
|
|
dy=g_TransitionClip.top-rcStart.bottom;
|
|
if (dy>0) dy=g_TransitionVector.y;
|
|
}
|
|
else if (g_TransitionVector.y>0) // bottom
|
|
{
|
|
dy=g_TransitionClip.bottom-rcStart.top;
|
|
if (dy<0) dy=g_TransitionVector.y;
|
|
}
|
|
OffsetRect(&rcEnd,dx,dy);
|
|
}
|
|
g_DwmpTransitionWindowWithRects(button,0x21800046,&rcClient,&rcStart,&rcClient,&rcEnd,&g_TransitionClip);
|
|
g_DwmpEndTransitionRequest(15);
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// hooks for skinning the taskbar
|
|
|
|
typedef void (WINAPI *tSHFillRectClr)(HDC hdc, const RECT *pRect, COLORREF color);
|
|
|
|
static IatHookData *g_SHFillRectClrHook, *g_StretchDIBitsHook;
|
|
static IatHookData *g_DrawThemeBackgroundHook, *g_DrawThemeTextHook, *g_DrawThemeTextExHook, *g_DrawThemeTextCtlHook, *g_SetWindowCompositionAttributeHook;
|
|
|
|
static tSHFillRectClr g_SHFillRectClr;
|
|
|
|
static void WINAPI SHFillRectClr2( HDC hdc, const RECT *pRect, COLORREF color )
|
|
{
|
|
if (!g_CurrentTaskList || !g_TaskbarTexture || GetCurrentThreadId()!=g_TaskbarThreadId)
|
|
g_SHFillRectClr(hdc,pRect,color);
|
|
}
|
|
|
|
static HRESULT STDAPICALLTYPE DrawThemeBackground2( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCRECT pRect, LPCRECT pClipRect )
|
|
{
|
|
if (g_CurrentTaskList && g_TaskbarTexture && iPartId==1 && iStateId==0 && GetCurrentThreadId()==g_TaskbarThreadId)
|
|
{
|
|
HWND taskbar=GetAncestor(g_CurrentTaskList,GA_ROOT);
|
|
RECT rcClient;
|
|
GetClientRect(taskbar,&rcClient);
|
|
MapWindowPoints(taskbar,g_CurrentTaskList,(POINT*)&rcClient,2);
|
|
PrintTaskbarBackground(hdc,rcClient,*pRect,0);
|
|
return S_OK;
|
|
}
|
|
if (g_CurrentDesktopButton && g_TaskbarTexture && GetCurrentThreadId()==g_TaskbarThreadId && hTheme==GetWindowTheme(g_CurrentDesktopButton))
|
|
{
|
|
HWND taskbar=GetAncestor(g_CurrentDesktopButton,GA_ROOT);
|
|
RECT rcClient;
|
|
GetClientRect(taskbar,&rcClient);
|
|
MapWindowPoints(taskbar,g_CurrentDesktopButton,(POINT*)&rcClient,2);
|
|
UINT uEdge=GetTaskbarPosition(taskbar,NULL,NULL,NULL);
|
|
PrintTaskbarBackground(hdc,rcClient,*pRect,uEdge);
|
|
return DrawThemeBackground(hTheme,hdc,iPartId,iStateId,pRect,pClipRect);
|
|
}
|
|
return DrawThemeBackground(hTheme,hdc,iPartId,iStateId,pRect,pClipRect);
|
|
}
|
|
|
|
// toolbar text, rebar band titles, clock
|
|
static HRESULT STDAPICALLTYPE DrawThemeText2( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, LPCRECT pRect )
|
|
{
|
|
if ((g_CurrentRebar || g_CurrentTaskbarPart) && GetCurrentThreadId()==g_TaskbarThreadId && GetSettingBool(L"CustomTaskbar"))
|
|
{
|
|
bool bDef;
|
|
COLORREF color=GetSettingInt(L"TaskbarTextColor",bDef)&0xFFFFFF;
|
|
if (!bDef)
|
|
{
|
|
// change the color for the toolbar titles, the toolbar buttons and the clock
|
|
DTTOPTS options={sizeof(options),DTT_TEXTCOLOR};
|
|
options.crText=color;
|
|
return DrawThemeTextEx(hTheme,hdc,iPartId,iStateId,pszText,iCharCount,dwTextFlags,(RECT*)pRect,&options);
|
|
}
|
|
}
|
|
return DrawThemeText(hTheme,hdc,iPartId,iStateId,pszText,iCharCount,dwTextFlags,dwTextFlags2,pRect);
|
|
}
|
|
|
|
// taskbar text
|
|
static HRESULT STDAPICALLTYPE DrawThemeTextEx2( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwFlags, LPRECT pRect, const DTTOPTS *pOptions )
|
|
{
|
|
if ((g_CurrentTaskList || g_CurrentTaskbarPart) && GetCurrentThreadId()==g_TaskbarThreadId && GetSettingBool(L"CustomTaskbar"))
|
|
{
|
|
bool bDef;
|
|
COLORREF color=GetSettingInt(L"TaskbarTextColor",bDef)&0xFFFFFF;
|
|
if (!bDef)
|
|
{
|
|
// change the color dor the taskbar buttons
|
|
DTTOPTS options=*pOptions;
|
|
options.dwFlags|=DTT_TEXTCOLOR;
|
|
options.crText=color;
|
|
return DrawThemeTextEx(hTheme,hdc,iPartId,iStateId,pszText,iCharCount,dwFlags,pRect,&options);
|
|
}
|
|
}
|
|
return DrawThemeTextEx(hTheme,hdc,iPartId,iStateId,pszText,iCharCount,dwFlags,pRect,pOptions);
|
|
}
|
|
|
|
static BLENDFUNCTION g_AlphaFunc={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
|
|
|
|
static int WINAPI StretchDIBits2( HDC hdc, int xDest, int yDest, int DestWidth, int DestHeight, int xSrc, int ySrc, int SrcWidth, int SrcHeight, CONST VOID *lpBits, CONST BITMAPINFO *lpbmi, UINT iUsage, DWORD rop )
|
|
{
|
|
if ((g_CurrentTaskChevron || g_CurrentTaskbarButton) && g_TaskbarTexture && GetCurrentThreadId()==g_TaskbarThreadId)
|
|
{
|
|
HDC hsrc=CreateCompatibleDC(hdc);
|
|
BITMAPINFO bi={0};
|
|
bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
|
|
bi.bmiHeader.biWidth=DestWidth;
|
|
bi.bmiHeader.biHeight=DestHeight;
|
|
bi.bmiHeader.biPlanes=1;
|
|
bi.bmiHeader.biBitCount=32;
|
|
HBITMAP bitmap=CreateDIBSection(hsrc,&bi,DIB_RGB_COLORS,NULL,NULL,0);
|
|
HGDIOBJ bmp0=SelectObject(hsrc,bitmap);
|
|
int res=StretchDIBits(hsrc,0,0,DestWidth,DestHeight,xSrc,ySrc,SrcWidth,SrcHeight,lpBits,lpbmi,iUsage,SRCCOPY);
|
|
AlphaBlend(hdc,xDest,yDest,DestWidth,DestHeight,hsrc,0,0,DestWidth,DestHeight,g_AlphaFunc);
|
|
SelectObject(hsrc,bmp0);
|
|
DeleteObject(bitmap);
|
|
DeleteDC(hsrc);
|
|
return res;
|
|
}
|
|
return StretchDIBits(hdc,xDest,yDest,DestWidth,DestHeight,xSrc,ySrc,SrcWidth,SrcHeight,lpBits,lpbmi,iUsage,rop);
|
|
}
|
|
|
|
static BOOL WINAPI SetWindowCompositionAttribute2( HWND hwnd, WINCOMPATTRDATA *pAttrData )
|
|
{
|
|
if (pAttrData->attribute==0x13 && GetCurrentThreadId()==g_TaskbarThreadId)
|
|
{
|
|
const TaskbarInfo *taskBar=FindTaskBarInfoBar(hwnd);
|
|
if (taskBar && taskBar->bCustomLook)
|
|
{
|
|
int data[4];
|
|
ComputeTaskbarColors(data);
|
|
WINCOMPATTRDATA attrData={0x13,&data,sizeof(data)};
|
|
if (data[0]==3 && taskBar->bThemeChanging)
|
|
{
|
|
// send extra attribute when dealing with glass. without it the image behind the glass may not update when the taskbar is resized
|
|
SetWindowCompositionAttribute(hwnd,pAttrData);
|
|
}
|
|
return SetWindowCompositionAttribute(hwnd,&attrData);
|
|
}
|
|
}
|
|
return SetWindowCompositionAttribute(hwnd,pAttrData);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// hooks for preventing shell hotkeys registration on Win11
|
|
|
|
using ShellRegisterHotKey_t = BOOL(WINAPI*)(HWND, int, UINT, UINT, HWND);
|
|
|
|
static IatHookData* g_ShellRegisterHotKeyHook;
|
|
static ShellRegisterHotKey_t g_ShellRegisterHotKey;
|
|
|
|
static BOOL WINAPI ShellRegisterHotKeyHook(HWND hWnd, int id, UINT fsModifiers, UINT vk, HWND hWndTarget)
|
|
{
|
|
// Win key
|
|
if (fsModifiers == MOD_WIN && vk == 0)
|
|
return FALSE;
|
|
|
|
// Ctrl+Esc
|
|
if (fsModifiers == MOD_CONTROL && vk == VK_ESCAPE)
|
|
return FALSE;
|
|
|
|
return g_ShellRegisterHotKey(hWnd, id, fsModifiers, vk, hWndTarget);
|
|
}
|
|
|
|
// one-time APC function to unregister shell hotkeys
|
|
void NTAPI DisableShellHotkeysFunc(ULONG_PTR Parameter)
|
|
{
|
|
UnregisterHotKey(NULL, 1);
|
|
UnregisterHotKey(NULL, 2);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void OpenCortana( void )
|
|
{
|
|
if (GetWinVersion()>=WIN_VER_WIN10)
|
|
ShellExecute(NULL,NULL,L"shell:::{2559a1f8-21d7-11d4-bdaf-00c04f60b9f0}",NULL,NULL,SW_SHOWNORMAL);
|
|
}
|
|
|
|
static void InitStartMenuDLL( void )
|
|
{
|
|
static bool initCalled = false;
|
|
if (initCalled)
|
|
return;
|
|
|
|
initCalled = true;
|
|
|
|
LogToFile(STARTUP_LOG, L"StartMenu DLL: InitStartMenuDLL");
|
|
WaitDllInitThread();
|
|
|
|
InitializeIatHooks();
|
|
if (IsWin81Update1())
|
|
{
|
|
HMODULE dwm=GetModuleHandle(L"dwmapi.dll");
|
|
if (dwm)
|
|
{
|
|
g_DwmpBeginTransitionRequest=(tDwmpBeginTransitionRequest)GetProcAddress(dwm,MAKEINTRESOURCEA(138));
|
|
g_DwmpTransitionWindowWithRects=(tDwmpTransitionWindowWithRects)GetProcAddress(dwm,MAKEINTRESOURCEA(141));
|
|
g_DwmpEndTransitionRequest=(tDwmpEndTransitionRequest)GetProcAddress(dwm,MAKEINTRESOURCEA(140));
|
|
if (g_DwmpBeginTransitionRequest && g_DwmpTransitionWindowWithRects && g_DwmpEndTransitionRequest)
|
|
{
|
|
g_DwmpBTRHook=SetIatHook(GetModuleHandle(NULL),"dwmapi.dll",MAKEINTRESOURCEA(138),DwmpBeginTransitionRequest2);
|
|
g_DwmpTWWRHook=SetIatHook(GetModuleHandle(NULL),"dwmapi.dll",MAKEINTRESOURCEA(141),DwmpTransitionWindowWithRects2);
|
|
g_DwmpETRHook=SetIatHook(GetModuleHandle(NULL),"dwmapi.dll",MAKEINTRESOURCEA(140),DwmpEndTransitionRequest2);
|
|
if (!g_DwmpBTRHook || !g_DwmpTWWRHook || !g_DwmpETRHook)
|
|
{
|
|
ClearIatHook(g_DwmpBTRHook);
|
|
g_DwmpBTRHook=NULL;
|
|
ClearIatHook(g_DwmpTWWRHook);
|
|
g_DwmpTWWRHook=NULL;
|
|
ClearIatHook(g_DwmpETRHook);
|
|
g_DwmpETRHook=NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (GetSettingBool(L"CustomTaskbar"))
|
|
{
|
|
auto module=GetModuleHandle(L"taskbar.dll");
|
|
if (!module)
|
|
module=GetModuleHandle(NULL);
|
|
|
|
if (GetWinVersion()>=WIN_VER_WIN10)
|
|
{
|
|
HMODULE shlwapi=GetModuleHandle(L"shlwapi.dll");
|
|
if (shlwapi)
|
|
{
|
|
g_SHFillRectClr=(tSHFillRectClr)GetProcAddress(shlwapi,MAKEINTRESOURCEA(197));
|
|
if (g_SHFillRectClr)
|
|
{
|
|
g_SHFillRectClrHook=SetIatHook(module,"shlwapi.dll",MAKEINTRESOURCEA(197),SHFillRectClr2);
|
|
if (!g_SHFillRectClrHook)
|
|
g_SHFillRectClrHook=SetIatHook(module,"api-ms-win-shlwapi-winrt-storage-l1-1-1.dll",MAKEINTRESOURCEA(197),SHFillRectClr2);
|
|
}
|
|
}
|
|
g_StretchDIBitsHook=SetIatHook(module,"gdi32.dll","StretchDIBits",StretchDIBits2);
|
|
if (!g_StretchDIBitsHook)
|
|
g_StretchDIBitsHook=SetIatHook(module,"ext-ms-win-gdi-draw-l1-1-0.dll","StretchDIBits",StretchDIBits2);
|
|
}
|
|
|
|
{
|
|
HWND dlg=CreateWindow(L"#32770",L"",WS_POPUP,0,0,0,0,NULL,0,0,0);
|
|
HWND toolbar=CreateWindow(TOOLBARCLASSNAME,L"",WS_CHILD|TBS_TOOLTIPS,0,0,0,0,dlg,0,0,0);
|
|
DestroyWindow(dlg);
|
|
}
|
|
|
|
if (GetWinVersion()<=WIN_VER_WIN81)
|
|
g_DrawThemeBackgroundHook=SetIatHook(module,"uxtheme.dll","DrawThemeBackground",DrawThemeBackground2);
|
|
g_DrawThemeTextHook=SetIatHook(module,"uxtheme.dll","DrawThemeText",DrawThemeText2);
|
|
g_DrawThemeTextExHook=SetIatHook(module,"uxtheme.dll","DrawThemeTextEx",DrawThemeTextEx2);
|
|
g_DrawThemeTextCtlHook=SetIatHook(GetModuleHandle(L"comctl32.dll"),"uxtheme.dll","DrawThemeText",DrawThemeText2);
|
|
if (GetWinVersion()>=WIN_VER_WIN10)
|
|
g_SetWindowCompositionAttributeHook=SetIatHook(module,"user32.dll","SetWindowCompositionAttribute",SetWindowCompositionAttribute2);
|
|
}
|
|
|
|
g_TaskbarThreadId=GetCurrentThreadId();
|
|
g_bTrimHooks=GetWinVersion()==WIN_VER_WIN7 && (GetSettingInt(L"CompatibilityFixes")&COMPATIBILITY_TRIM_HOOKS);
|
|
InitManagers(false);
|
|
int level=GetSettingInt(L"CrashDump");
|
|
if (level>=1 && level<=3)
|
|
{
|
|
if (level==1) MiniDumpType=MiniDumpNormal;
|
|
if (level==2) MiniDumpType=MiniDumpWithDataSegs;
|
|
if (level==3) MiniDumpType=MiniDumpWithFullMemory;
|
|
SetUnhandledExceptionFilter(TopLevelFilter);
|
|
_set_invalid_parameter_handler(InvalidParameterHandler);
|
|
g_bCrashDump=true;
|
|
}
|
|
FindTaskBar();
|
|
g_ProgWin=FindWindowEx(NULL,NULL,L"Progman",NULL);
|
|
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());
|
|
|
|
// hook ShellRegisterHotKey to prevent twinui.dll to install shell hotkeys (Win, Ctrl+Esc)
|
|
// without these hotkeys there is standard WM_SYSCOMMAND+SC_TASKLIST sent when start menu is invoked by keyboard shortcut
|
|
g_ShellRegisterHotKey = (ShellRegisterHotKey_t)GetProcAddress(GetModuleHandle(L"user32.dll"), MAKEINTRESOURCEA(2671));
|
|
auto twinui = GetModuleHandle(L"twinui.dll");
|
|
|
|
if (g_ShellRegisterHotKey && twinui)
|
|
{
|
|
g_ShellRegisterHotKeyHook = SetIatHook(twinui, "user32.dll" ,MAKEINTRESOURCEA(2671), ShellRegisterHotKeyHook);
|
|
|
|
// unregister shell hotkeys as they may be registered already
|
|
// this has to be done from context of thread that registered them
|
|
auto hwnd = FindWindow(L"ApplicationManager_ImmersiveShellWindow", NULL);
|
|
if (hwnd)
|
|
{
|
|
auto thread = OpenThread(THREAD_SET_CONTEXT, FALSE, GetWindowThreadProcessId(hwnd, NULL));
|
|
if (thread)
|
|
{
|
|
QueueUserAPC(DisableShellHotkeysFunc, thread, 0);
|
|
CloseHandle(thread);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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
|
|
if (GetWinVersion()>=WIN_VER_WIN8)
|
|
{
|
|
SetWindowCompositionAttribute=(tSetWindowCompositionAttribute)GetProcAddress(GetModuleHandle(L"user32.dll"),"SetWindowCompositionAttribute");
|
|
}
|
|
int taskbarId=g_NextTaskbar++;
|
|
TaskbarInfo &taskBar=g_TaskbarInfos[taskbarId];
|
|
taskBar.taskBar=g_TaskBar;
|
|
taskBar.taskbarId=taskbarId;
|
|
taskBar.rebar=FindWindowEx(g_TaskBar,NULL,REBARCLASSNAME,NULL);
|
|
if (taskBar.rebar)
|
|
{
|
|
SetWindowSubclass(taskBar.rebar,SubclassRebarProc,'CLSH',taskbarId);
|
|
// TaskBand window
|
|
HWND hwnd=FindWindowEx(taskBar.rebar,NULL,L"MSTaskSwWClass",NULL);
|
|
if (hwnd)
|
|
{
|
|
taskBar.taskList=hwnd;
|
|
// TaskList window
|
|
// it has to be visible, otherwise it won't receive WM_PAINT that we need to intercept
|
|
// in such case we will intercept parent instead
|
|
hwnd=FindWindowEx(hwnd,NULL,L"MSTaskListWClass",NULL);
|
|
if (hwnd&&IsWindowVisible(hwnd))
|
|
taskBar.taskList=hwnd;
|
|
}
|
|
if (taskBar.taskList)
|
|
SetWindowSubclass(taskBar.taskList,SubclassTaskListProc,'CLSH',taskbarId);
|
|
}
|
|
if (GetWinVersion()>WIN_VER_WIN8)
|
|
{
|
|
taskBar.oldButton=FindWindowEx(taskBar.taskBar,NULL,L"Start",NULL);
|
|
if (taskBar.oldButton)
|
|
{
|
|
if (GetWinVersion()>=WIN_VER_WIN10)
|
|
{
|
|
taskBar.pOriginalTarget=(IDropTarget*)GetProp(taskBar.oldButton,L"OleDropTargetInterface");
|
|
if (taskBar.pOriginalTarget)
|
|
RevokeDragDrop(taskBar.oldButton);
|
|
}
|
|
|
|
CStartMenuTarget *pNewTarget=new CStartMenuTarget(taskBar.taskbarId);
|
|
RegisterDragDrop(taskBar.oldButton,pNewTarget);
|
|
pNewTarget->Release();
|
|
if (GetWinVersion()<WIN_VER_WIN10 && GetTaskbarPosition(taskBar.taskBar,NULL,NULL,NULL)==ABE_BOTTOM)
|
|
SetWindowPos(taskBar.oldButton,NULL,-1,0,0,0,SWP_NOSIZE|SWP_NOZORDER);
|
|
SetWindowSubclass(taskBar.oldButton,SubclassWin81StartButton,'CLSH',taskBar.taskbarId);
|
|
}
|
|
}
|
|
if (GetWinVersion()>=WIN_VER_WIN10)
|
|
{
|
|
for (HWND button=FindWindowEx(g_TaskBar,NULL,L"TrayButton",NULL);button;button=FindWindowEx(g_TaskBar,button,L"TrayButton",NULL))
|
|
{
|
|
taskBar.trayButtons.push_back(button);
|
|
SetWindowSubclass(button,SubclassTrayButtonProc,'CLSH',taskBar.taskbarId);
|
|
}
|
|
HWND search=FindWindowEx(g_TaskBar,NULL,L"TrayDummySearchControl",NULL);
|
|
if (search)
|
|
{
|
|
taskBar.trayButtons.push_back(search);
|
|
SetWindowSubclass(search,SubclassTrayButtonProc,'CLSH',taskBar.taskbarId);
|
|
}
|
|
HWND tray=FindWindowEx(g_TaskBar,NULL,L"TrayNotifyWnd",NULL);
|
|
if (tray)
|
|
taskBar.chevron=FindWindowEx(tray,NULL,L"Button",NULL);
|
|
if (taskBar.chevron)
|
|
SetWindowSubclass(taskBar.chevron,SubclassTrayChevronProc,'CLSH',taskBar.taskbarId);
|
|
}
|
|
|
|
HandleTaskbarParts(taskBar,true);
|
|
if (!g_bTrimHooks)
|
|
SetWindowSubclass(taskBar.taskBar,SubclassTaskBarProc,'CLSH',taskbarId);
|
|
taskBar.startButton=g_WinStartButton;
|
|
|
|
#ifdef HOOK_DROPTARGET
|
|
if (g_WinStartButton)
|
|
{
|
|
g_pOriginalTarget=(IDropTarget*)GetProp(g_WinStartButton,L"OleDropTargetInterface");
|
|
if (g_pOriginalTarget)
|
|
RevokeDragDrop(g_WinStartButton);
|
|
|
|
CStartMenuTarget *pNewTarget=new CStartMenuTarget(taskbarId);
|
|
RegisterDragDrop(g_WinStartButton,pNewTarget);
|
|
pNewTarget->Release();
|
|
}
|
|
#endif
|
|
|
|
if (GetWinVersion()>=WIN_VER_WIN8)
|
|
{
|
|
g_pAppVisibility.CoCreateInstance(CLSID_MetroMode);
|
|
if (g_pAppVisibility)
|
|
{
|
|
CMonitorModeEvents *monitor=new CMonitorModeEvents();
|
|
g_pAppVisibility->Advise(monitor,&g_AppVisibilityMonitorCookie);
|
|
monitor->Release();
|
|
}
|
|
if (GetWinVersion()<WIN_VER_WIN10)
|
|
{
|
|
HWND hwndAppManager=FindWindow(L"ApplicationManager_DesktopShellWindow",NULL);
|
|
if (hwndAppManager)
|
|
{
|
|
g_AppManagerThread=GetWindowThreadProcessId(hwndAppManager,NULL);
|
|
g_AppManagerHook=SetWindowsHookEx(WH_GETMESSAGE,HookAppManager,g_Instance,g_AppManagerThread);
|
|
}
|
|
if (GetWinVersion()==WIN_VER_WIN8 && GetSettingBool(L"SkipMetro"))
|
|
{
|
|
g_SkipMetroCount=abs(GetSettingInt(L"SkipMetroCount"));
|
|
SetTimer(g_TaskBar,'CLSM',500,NULL);
|
|
PostMessage(g_TaskBar,WM_TIMER,'CLSM',0);
|
|
}
|
|
}
|
|
|
|
EnumWindows(HookAllTaskbarsEnum,0);
|
|
}
|
|
g_NewWindowHook=SetWindowsHookEx(WH_CBT,HookNewWindow,g_Instance,GetCurrentThreadId());
|
|
|
|
UpdateTaskBars(TASKBAR_RECREATE_BUTTONS);
|
|
UpdateTaskBars(TASKBAR_UPDATE_TEXTURE);
|
|
}
|
|
|
|
static void RecreateStartButton( size_t taskbarId )
|
|
{
|
|
for (id_taskbar_map::iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it)
|
|
{
|
|
TaskbarInfo &taskBar=it->second;
|
|
if (taskbarId>=0 && taskBar.taskbarId!=taskbarId)
|
|
continue;
|
|
if (taskBar.bRecreatingButton)
|
|
continue;
|
|
|
|
taskBar.bRecreatingButton=true;
|
|
{
|
|
if (taskBar.startButton && taskBar.startButton!=g_WinStartButton)
|
|
{
|
|
RevokeDragDrop(taskBar.startButton);
|
|
DestroyStartButton(taskBar.taskbarId);
|
|
}
|
|
taskBar.startButton=CreateStartButton(taskBar.taskbarId,taskBar.taskBar,taskBar.rebar);
|
|
CStartMenuTarget *pNewTarget=new CStartMenuTarget(taskBar.taskbarId);
|
|
RegisterDragDrop(taskBar.startButton,pNewTarget);
|
|
pNewTarget->Release();
|
|
}
|
|
taskBar.bRecreatingButton=false;
|
|
|
|
taskBar.startButtonSize=GetStartButtonSize(taskBar.taskbarId);
|
|
if (taskBar.oldButton)
|
|
{
|
|
RECT rc;
|
|
GetWindowRect(taskBar.oldButton,&rc);
|
|
taskBar.oldButtonSize.cx=rc.right-rc.left;
|
|
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));
|
|
for (auto btn : taskBar.trayButtons)
|
|
{
|
|
RECT rc;
|
|
GetWindowRect(btn,&rc);
|
|
SetWindowPos(btn,HWND_TOP,rc.left,rc.top,0,0,SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOZORDER);
|
|
}
|
|
}
|
|
}
|
|
|
|
static DWORD WINAPI ExitThreadProc( void *param )
|
|
{
|
|
Sleep(1000); // wait a second! hopefully by then the hooks will be finished and no more of our code will be executing
|
|
// send WM_CLOSE to the window in StartMenu.exe to close that process
|
|
if (param) PostMessage((HWND)param,WM_CLOSE,0,0);
|
|
FreeLibraryAndExitThread(g_Instance,0);
|
|
}
|
|
|
|
static void CleanStartMenuDLL( void )
|
|
{
|
|
ClearIatHook(g_DwmpBTRHook);
|
|
g_DwmpBTRHook=NULL;
|
|
ClearIatHook(g_DwmpTWWRHook);
|
|
g_DwmpTWWRHook=NULL;
|
|
ClearIatHook(g_DwmpETRHook);
|
|
g_DwmpETRHook=NULL;
|
|
ClearIatHook(g_SHFillRectClrHook);
|
|
g_SHFillRectClrHook=NULL;
|
|
ClearIatHook(g_StretchDIBitsHook);
|
|
g_StretchDIBitsHook=NULL;
|
|
|
|
ClearIatHook(g_DrawThemeBackgroundHook);
|
|
g_DrawThemeBackgroundHook=NULL;
|
|
ClearIatHook(g_DrawThemeTextHook);
|
|
g_DrawThemeTextHook=NULL;
|
|
ClearIatHook(g_DrawThemeTextExHook);
|
|
g_DrawThemeTextExHook=NULL;
|
|
ClearIatHook(g_DrawThemeTextCtlHook);
|
|
g_DrawThemeTextCtlHook=NULL;
|
|
ClearIatHook(g_SetWindowCompositionAttributeHook);
|
|
g_SetWindowCompositionAttributeHook=NULL;
|
|
ClearIatHook(g_ShellRegisterHotKeyHook);
|
|
g_ShellRegisterHotKeyHook=NULL;
|
|
|
|
CloseManagers(false);
|
|
ClearIatHooks();
|
|
|
|
// cleanup
|
|
if (g_Owner.m_hWnd) g_Owner.DestroyWindow();
|
|
CloseSettings();
|
|
CMenuContainer::CloseStartMenu();
|
|
CMenuFader::ClearAll();
|
|
UnhookDropTarget();
|
|
EnableHotkeys(HOTKEYS_CLEAR);
|
|
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);
|
|
g_NewWindowHook=NULL;
|
|
if (g_pAppVisibility)
|
|
{
|
|
g_pAppVisibility->Unadvise(g_AppVisibilityMonitorCookie);
|
|
g_pAppVisibility=NULL;
|
|
}
|
|
ResetHotCorners();
|
|
UpdateTaskBars(TASKBAR_CLEAR);
|
|
g_WinStartButton=NULL;
|
|
for (id_taskbar_map::const_iterator it=g_TaskbarInfos.begin();it!=g_TaskbarInfos.end();++it)
|
|
{
|
|
if (it->second.rebar)
|
|
RemoveWindowSubclass(it->second.rebar,SubclassRebarProc,'CLSH');
|
|
if (it->second.taskList)
|
|
RemoveWindowSubclass(it->second.taskList,SubclassTaskListProc,'CLSH');
|
|
if (it->second.oldButton)
|
|
{
|
|
RemoveWindowSubclass(it->second.oldButton,SubclassWin81StartButton,'CLSH');
|
|
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);
|
|
}
|
|
if (!g_bTrimHooks)
|
|
RemoveWindowSubclass(it->second.taskBar,SubclassTaskBarProc,'CLSH');
|
|
for (std::vector<HWND>::const_iterator it2=it->second.trayButtons.begin();it2!=it->second.trayButtons.end();++it2)
|
|
{
|
|
RemoveWindowSubclass(*it2,SubclassTrayButtonProc,'CLSH');
|
|
}
|
|
for (std::vector<HWND>::const_iterator it2=it->second.taskbarParts.begin();it2!=it->second.taskbarParts.end();++it2)
|
|
{
|
|
RemoveWindowSubclass(*it2,SubclassTaskbarPartProc,'CLSH');
|
|
}
|
|
if (it->second.chevron)
|
|
RemoveWindowSubclass(it->second.chevron,SubclassTrayChevronProc,'CLSH');
|
|
if (it->second.desktop)
|
|
RemoveWindowSubclass(it->second.desktop,SubclassDesktopButtonProc,'CLSH');
|
|
if (it->second.bTimer)
|
|
KillTimer(it->second.startButton,'CLSM');
|
|
RECT rcTask;
|
|
GetWindowRect(it->second.taskBar,&rcTask);
|
|
PostMessage(it->second.taskBar,WM_SIZE,SIZE_RESTORED,MAKELONG(rcTask.right-rcTask.left,rcTask.bottom-rcTask.top));
|
|
PostMessage(it->second.taskBar,WM_THEMECHANGED,0,0);
|
|
}
|
|
g_TaskbarInfos.clear();
|
|
if (g_TopWin7Menu)
|
|
{
|
|
RemoveWindowSubclass(g_UserPic,SubclassUserPicProc,'CLSH');
|
|
RemoveWindowSubclass(g_TopWin7Menu,SubclassTopMenuProc,'CLSH');
|
|
RemoveWindowSubclass(g_AllPrograms,SubclassProgramsProc,'CLSH');
|
|
}
|
|
if (g_bCrashDump)
|
|
{
|
|
SetUnhandledExceptionFilter(NULL);
|
|
g_bCrashDump=false;
|
|
}
|
|
|
|
// we need to unload the DLL here. but we can't just call FreeLibrary because it will unload the code
|
|
// while it is still executing. So we create a separate thread and use FreeLibraryAndExitThread
|
|
CreateThread(NULL,0,ExitThreadProc,(void*)hwnd,0,NULL);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
static BOOL CALLBACK FindImmersiveWindows( HWND hwnd, LPARAM lParam )
|
|
{
|
|
wchar_t name[100];
|
|
GetClassName(hwnd,name,_countof(name));
|
|
if (wcscmp(name,L"ImmersiveLauncher")==0)
|
|
((HWND*)lParam)[0]=hwnd;
|
|
if (wcscmp(name,L"ImmersiveBackgroundWindow")==0)
|
|
((HWND*)lParam)[1]=hwnd;
|
|
if (wcscmp(name,L"SearchPane")==0)
|
|
((HWND*)lParam)[2]=hwnd;
|
|
return TRUE;
|
|
}
|
|
|
|
static bool WindowsMenuOpened( void )
|
|
{
|
|
FindWindowsMenu();
|
|
CComPtr<IUnknown> pImmersiveShell;
|
|
if (GetWinVersion()>=WIN_VER_WIN10 && CreateImmersiveShell(pImmersiveShell))
|
|
{
|
|
{
|
|
CComPtr<IImmersiveLauncher81> pLauncher;
|
|
IUnknown_QueryService(pImmersiveShell,SID_ImmersiveLauncher,IID_IImmersiveLauncher81,(void**)&pLauncher);
|
|
BOOL bIsVisible;
|
|
if (pLauncher && SUCCEEDED(pLauncher->IsVisible(&bIsVisible)))
|
|
return bIsVisible!=0;
|
|
}
|
|
{
|
|
CComPtr<IImmersiveLauncher10RS> pLauncher;
|
|
IUnknown_QueryService(pImmersiveShell,SID_ImmersiveLauncher,IID_IImmersiveLauncher10RS,(void**)&pLauncher);
|
|
BOOL bIsVisible;
|
|
if (pLauncher && SUCCEEDED(pLauncher->IsVisible(&bIsVisible)))
|
|
return bIsVisible!=0;
|
|
}
|
|
}
|
|
if (GetWinVersion()>=WIN_VER_WIN8)
|
|
{
|
|
return GetMetroMode(NULL)!=METRO_NONE;
|
|
}
|
|
else
|
|
{
|
|
return g_TopWin7Menu && IsWindowVisible(g_TopWin7Menu);
|
|
}
|
|
}
|
|
|
|
static void OpenStartScreen( HMONITOR monitor )
|
|
{
|
|
CComPtr<IUnknown> pImmersiveShell;
|
|
if (CreateImmersiveShell(pImmersiveShell))
|
|
{
|
|
CComPtr<IUnknown> pMonitor;
|
|
if (GetWinVersion()==WIN_VER_WIN8)
|
|
{
|
|
if (monitor)
|
|
{
|
|
CComPtr<IImmersiveMonitorService> pMonitorService;
|
|
IUnknown_QueryService(pImmersiveShell,SID_IImmersiveMonitorService,IID_IImmersiveMonitorService,(void**)&pMonitorService);
|
|
if (pMonitorService)
|
|
{
|
|
CComPtr<IUnknown> pMonitor;
|
|
pMonitorService->GetFromHandle(monitor,&pMonitor);
|
|
if (pMonitor)
|
|
pMonitorService->SetImmersiveMonitor(pMonitor);
|
|
}
|
|
}
|
|
CComPtr<IImmersiveLauncher80> pLauncher;
|
|
IUnknown_QueryService(pImmersiveShell,SID_ImmersiveLauncher,IID_IImmersiveLauncher80,(void**)&pLauncher);
|
|
if (pLauncher)
|
|
pLauncher->ShowStartView(5);
|
|
return;
|
|
}
|
|
if (monitor)
|
|
{
|
|
CComPtr<IImmersiveMonitorService> pMonitorService;
|
|
IUnknown_QueryService(pImmersiveShell,SID_IImmersiveMonitorService,IID_IImmersiveMonitorService,(void**)&pMonitorService);
|
|
if (pMonitorService)
|
|
pMonitorService->GetFromHandle(monitor,&pMonitor);
|
|
}
|
|
{
|
|
CComPtr<IImmersiveLauncher81> pLauncher;
|
|
IUnknown_QueryService(pImmersiveShell,SID_ImmersiveLauncher,IID_IImmersiveLauncher81,(void**)&pLauncher);
|
|
if (pLauncher)
|
|
{
|
|
if (pMonitor)
|
|
pLauncher->ConnectToMonitor(pMonitor);
|
|
HRESULT hr=pLauncher->ShowStartView(GetWinVersion()>=WIN_VER_WIN10?11:5,0);
|
|
return;
|
|
}
|
|
}
|
|
{
|
|
CComPtr<IImmersiveLauncher10RS> pLauncher;
|
|
IUnknown_QueryService(pImmersiveShell,SID_ImmersiveLauncher,IID_IImmersiveLauncher10RS,(void**)&pLauncher);
|
|
if (pLauncher)
|
|
{
|
|
if (pMonitor)
|
|
pLauncher->ConnectToMonitor(pMonitor);
|
|
HRESULT hr=pLauncher->ShowStartView(GetWinVersion()>=WIN_VER_WIN10?11:5,0);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else if (g_AppManagerThread)
|
|
PostThreadMessage(g_AppManagerThread,g_StartMenuMsg,MSG_SHIFTWIN,(LPARAM)monitor);
|
|
}
|
|
|
|
// WH_GETMESSAGE hook for the Progman window
|
|
static LRESULT CALLBACK HookProgManThread( int code, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
if (code==HC_ACTION && wParam)
|
|
{
|
|
MSG *msg=(MSG*)lParam;
|
|
if (msg->message==WM_SYSCOMMAND && (msg->wParam&0xFFF0)==SC_TASKLIST)
|
|
{
|
|
if (GetWinVersion()<WIN_VER_WIN8 && !CMenuContainer::CanShowMenu())
|
|
msg->message=WM_NULL;
|
|
// Win button pressed
|
|
if (msg->lParam=='WSMK' || msg->lParam=='WSMM' || msg->lParam=='WSMH')
|
|
{
|
|
if ((g_AppManagerThread || GetWinVersion()>=WIN_VER_WIN10) && (msg->lParam=='WSMM' || msg->lParam=='WSMH' || (g_TaskbarInfos.size()>1 && GetSettingBool(L"OpenMouseMonitor"))))
|
|
{
|
|
if (!WindowsMenuOpened())
|
|
{
|
|
HMONITOR monitor=msg->lParam=='WSMH'?g_WSMHMonitor:MonitorFromPoint(CPoint(GetMessagePos()),MONITOR_DEFAULTTONULL);
|
|
OpenStartScreen(monitor);
|
|
msg->message=WM_NULL;
|
|
}
|
|
}
|
|
}
|
|
else if (msg->lParam=='CSM')
|
|
{
|
|
msg->message=WM_NULL;
|
|
PostMessage(g_TaskBar,g_StartMenuMsg,MSG_TOGGLE,0);
|
|
}
|
|
else
|
|
{
|
|
FindTaskBar();
|
|
int control=GetSettingInt(L"WinKey");
|
|
if (control==OPEN_BOTH)
|
|
{
|
|
if (GetWinVersion()>=WIN_VER_WIN10)
|
|
control=GetWin10TabletMode()?OPEN_WINDOWS:OPEN_CLASSIC;
|
|
else
|
|
control=GetMetroMode(MonitorFromPoint(CPoint(GetMessagePos()),MONITOR_DEFAULTTONEAREST))?OPEN_WINDOWS:OPEN_CLASSIC;
|
|
}
|
|
if (control==OPEN_DESKTOP)
|
|
{
|
|
TMetroMode metro=GetMetroMode(MonitorFromPoint(CPoint(GetMessagePos()),MONITOR_DEFAULTTONEAREST));
|
|
if (metro==METRO_NONE)
|
|
control=OPEN_CLASSIC;
|
|
else if (metro==METRO_APP)
|
|
control=OPEN_WINDOWS;
|
|
else
|
|
{
|
|
msg->message=WM_NULL;
|
|
SetForegroundWindow(GetDefaultTaskbarInfo()->taskBar);
|
|
}
|
|
}
|
|
|
|
if (control==OPEN_WINDOWS)
|
|
{
|
|
FindWindowsMenu();
|
|
if (g_TopWin7Menu && WindowsMenuOpened())
|
|
{
|
|
const TaskbarInfo *taskBar=GetDefaultTaskbarInfo();
|
|
SetForegroundWindow(taskBar->startButton?taskBar->startButton:taskBar->taskBar);
|
|
msg->message=WM_NULL;
|
|
}
|
|
else if (GetWinVersion()>=WIN_VER_WIN8 && g_TaskbarInfos.size()>1 && GetSettingBool(L"OpenMouseMonitor") && !WindowsMenuOpened())
|
|
{
|
|
HMONITOR monitor=MonitorFromPoint(CPoint(GetMessagePos()),MONITOR_DEFAULTTONULL);
|
|
OpenStartScreen(monitor);
|
|
msg->message=WM_NULL;
|
|
}
|
|
else
|
|
{
|
|
PostMessage(g_TaskBar,g_StartMenuMsg,MSG_NOP,0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
msg->message=WM_NULL;
|
|
if (control==OPEN_CLASSIC)
|
|
PostMessage(g_TaskBar,g_StartMenuMsg,MSG_TOGGLE,0);
|
|
else if (control==OPEN_CUSTOM)
|
|
{
|
|
CString commandText=GetSettingString(L"WinKeyCommand");
|
|
if (!commandText.IsEmpty())
|
|
{
|
|
wchar_t expandedCommand[_MAX_PATH]{};
|
|
::ExpandEnvironmentStrings(commandText, expandedCommand, _countof(expandedCommand));
|
|
ShellExecute(NULL,NULL,expandedCommand,NULL,NULL,SW_SHOWNORMAL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ((msg->message==WM_MOUSEMOVE || msg->message==WM_LBUTTONDOWN) && GetWinVersion()>=WIN_VER_WIN8 && HIWORD(msg->lParam)<10 && GetSettingInt(L"DisableHotCorner")==2)
|
|
{
|
|
if (msg->hwnd!=g_TopDesktopBar || !g_TopDesktopBar || !IsWindow(g_TopDesktopBar))
|
|
{
|
|
wchar_t name[100];
|
|
if (!GetClassName(msg->hwnd,name,_countof(name)) || _wcsicmp(name,L"WorkerW")!=0)
|
|
return CallNextHookEx(NULL,code,wParam,lParam);
|
|
HWND parent=GetParent(msg->hwnd);
|
|
if (parent!=g_ProgWin && !FindWindowEx(parent,NULL,L"SHELLDLL_DefView",NULL))
|
|
return CallNextHookEx(NULL,code,wParam,lParam);
|
|
g_EdgeWindows.erase(g_TopDesktopBar);
|
|
g_TopDesktopBar=msg->hwnd;
|
|
}
|
|
g_EdgeWindows.insert(g_TopDesktopBar);
|
|
ShowWindow(g_TopDesktopBar,SW_HIDE);
|
|
msg->message=WM_NULL;
|
|
}
|
|
}
|
|
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 )
|
|
{
|
|
if (code==HC_ACTION && wParam && !g_bInMenu)
|
|
{
|
|
MSG *msg=(MSG*)lParam;
|
|
FindTaskBar();
|
|
if (IsSettingsMessage(msg))
|
|
{
|
|
msg->message=WM_NULL;
|
|
return 0;
|
|
}
|
|
if (!g_bTrimHooks)
|
|
{
|
|
if (((msg->message>=WM_MOUSEFIRST && msg->message<=WM_MOUSELAST) || msg->message==WM_MOUSEHOVER || msg->message==WM_MOUSELEAVE) && GetWinVersion()<=WIN_VER_WIN7 && CMenuContainer::ProcessMouseMessage(msg->hwnd,msg->message,msg->wParam,msg->lParam))
|
|
{
|
|
msg->message=WM_NULL;
|
|
return 0;
|
|
}
|
|
}
|
|
if (msg->message==g_StartMenuMsg && msg->hwnd==g_TaskBar)
|
|
{
|
|
msg->message=WM_NULL;
|
|
static bool bProcessing; // prevent reentry
|
|
if (!bProcessing)
|
|
{
|
|
FindWindowsMenu();
|
|
bProcessing=true;
|
|
if (msg->wParam==MSG_TOGGLE || (msg->wParam==MSG_OPEN && !CMenuContainer::IsMenuOpened()))
|
|
{
|
|
const TaskbarInfo *taskBar=GetDefaultTaskbarInfo();
|
|
ToggleStartMenu(taskBar->taskbarId,true);
|
|
}
|
|
else if (msg->wParam==MSG_TOGGLENEW)
|
|
{
|
|
PostMessage(g_ProgWin,WM_SYSCOMMAND,SC_TASKLIST,'WSMK');
|
|
}
|
|
else if (msg->wParam==MSG_SETTINGS)
|
|
{
|
|
if (GetSettingBool(L"EnableSettings"))
|
|
EditSettings(false,0);
|
|
}
|
|
else if (msg->wParam==MSG_SHIFTWIN)
|
|
{
|
|
const TaskbarInfo *taskBar=GetDefaultTaskbarInfo();
|
|
int control=GetSettingInt(L"ShiftWin");
|
|
if (control==OPEN_BOTH)
|
|
{
|
|
if (GetWinVersion()>=WIN_VER_WIN10)
|
|
control=GetWin10TabletMode()?OPEN_WINDOWS:OPEN_CLASSIC;
|
|
else
|
|
control=GetMetroMode(MonitorFromPoint(CPoint(GetMessagePos()),MONITOR_DEFAULTTONEAREST))?OPEN_WINDOWS:OPEN_CLASSIC;
|
|
}
|
|
if (control==OPEN_CLASSIC)
|
|
ToggleStartMenu(taskBar->taskbarId,true);
|
|
else if (control==OPEN_WINDOWS)
|
|
PostMessage(g_ProgWin,WM_SYSCOMMAND,SC_TASKLIST,'WSMK');
|
|
else if (control==OPEN_CORTANA)
|
|
OpenCortana();
|
|
else if (control==OPEN_CUSTOM)
|
|
{
|
|
CString commandText=GetSettingString(L"ShiftWinCommand");
|
|
if (!commandText.IsEmpty())
|
|
{
|
|
wchar_t expandedCommand[_MAX_PATH]{};
|
|
::ExpandEnvironmentStrings(commandText, expandedCommand, _countof(expandedCommand));
|
|
ShellExecute(NULL,NULL,expandedCommand,NULL,NULL,SW_SHOWNORMAL);
|
|
}
|
|
}
|
|
}
|
|
else if (msg->wParam==MSG_DRAG || msg->wParam==MSG_SHIFTDRAG)
|
|
{
|
|
const TaskbarInfo *taskBar=GetTaskbarInfo((int)msg->lParam);
|
|
if (taskBar)
|
|
{
|
|
int control=GetSettingInt((msg->wParam==MSG_DRAG)?L"MouseClick":L"ShiftClick");
|
|
if (control==OPEN_BOTH && GetWinVersion()>=WIN_VER_WIN10)
|
|
control=GetWin10TabletMode()?OPEN_WINDOWS:OPEN_CLASSIC;
|
|
if (control==OPEN_CLASSIC || (control==OPEN_WINDOWS && GetWinVersion()>=WIN_VER_WIN8))
|
|
ToggleStartMenu(taskBar->taskbarId,true);
|
|
else if (control==OPEN_WINDOWS)
|
|
PostMessage(g_ProgWin,WM_SYSCOMMAND,SC_TASKLIST,'WSMM');
|
|
}
|
|
}
|
|
else if (msg->wParam==MSG_EXIT && CMenuContainer::CanShowMenu())
|
|
{
|
|
LRESULT res=CallNextHookEx(NULL,code,wParam,lParam);
|
|
CleanStartMenuDLL();
|
|
return res; // we should exit as quickly as possible now. the DLL is about to be unloaded
|
|
}
|
|
else if (msg->wParam==MSG_HOTKEYS)
|
|
{
|
|
EnableHotkeys((THotkeys)msg->lParam);
|
|
}
|
|
else if (msg->wParam==MSG_NEWTASKBAR)
|
|
{
|
|
HWND child=(HWND)msg->lParam;
|
|
if (IsWindow(child))
|
|
{
|
|
wchar_t className[100];
|
|
GetClassName(child,className,_countof(className));
|
|
if (_wcsicmp(className,L"Shell_SecondaryTrayWnd")==0)
|
|
HandleSecondaryTaskbar((HWND)msg->lParam);
|
|
else if (_wcsicmp(className,L"ToolbarWindow32")==0)
|
|
{
|
|
HWND taskbar=GetAncestor(child,GA_ROOT);
|
|
TaskbarInfo *info=FindTaskBarInfoBar(taskbar);
|
|
if (info && !info->HasPart(child) && GetParent(child)==info->rebar)
|
|
{
|
|
SetWindowSubclass(child,SubclassTaskbarPartProc,'CLSH',info->taskbarId);
|
|
info->taskbarParts.push_back(child);
|
|
}
|
|
}
|
|
else if (_wcsicmp(className,L"TrayClockWClass")==0 || _wcsicmp(className,L"ClockButton")==0)
|
|
{
|
|
HWND taskbar=GetAncestor(child,GA_ROOT);
|
|
TaskbarInfo *info=FindTaskBarInfoBar(taskbar);
|
|
if (info && !info->HasPart(child))
|
|
{
|
|
SetWindowSubclass(child,SubclassTaskbarPartProc,'CLSH',info->taskbarId);
|
|
info->taskbarParts.push_back(child);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (msg->wParam==MSG_REDRAWTASKBAR)
|
|
{
|
|
if (msg->lParam)
|
|
InvalidateRect((HWND)msg->lParam,NULL,TRUE);
|
|
else
|
|
RedrawTaskbars();
|
|
}
|
|
else if (msg->wParam==MSG_RELOADSETTINGS)
|
|
{
|
|
LoadSettings();
|
|
UpdateTaskBars(TASKBAR_RECREATE_BUTTONS);
|
|
UpdateTaskBars(TASKBAR_UPDATE_TEXTURE);
|
|
ResetHotCorners();
|
|
RedrawTaskbars();
|
|
}
|
|
bProcessing=false;
|
|
}
|
|
}
|
|
if (!g_bTrimHooks)
|
|
{
|
|
if (msg->message==WM_HOTKEY && msg->hwnd==g_TaskBar)
|
|
{
|
|
if (msg->wParam==g_HotkeyShiftID)
|
|
PostMessage(g_TaskBar,g_StartMenuMsg,MSG_SHIFTWIN,0);
|
|
else if (msg->wParam==g_HotkeyCSMID)
|
|
{
|
|
msg->message=WM_NULL;
|
|
const TaskbarInfo *taskBar=GetDefaultTaskbarInfo();
|
|
if (taskBar->startButton)
|
|
SetForegroundWindow(taskBar->startButton);
|
|
ToggleStartMenu(taskBar->taskbarId,true);
|
|
}
|
|
else if (msg->wParam==g_HotkeyWSMID)
|
|
PostMessage(g_ProgWin,WM_SYSCOMMAND,SC_TASKLIST,'WSMK');
|
|
}
|
|
|
|
if (msg->message==WM_KEYDOWN && msg->hwnd==g_TaskBar && (msg->wParam==VK_SPACE || msg->wParam==VK_RETURN))
|
|
{
|
|
GUITHREADINFO info={sizeof(info)};
|
|
if (!GetGUIThreadInfo(GetCurrentThreadId(),&info) || !(info.flags&GUI_INMENUMODE))
|
|
{
|
|
FindWindowsMenu();
|
|
int control=GetSettingInt(L"WinKey");
|
|
if (control==OPEN_BOTH)
|
|
{
|
|
if (GetWinVersion()>=WIN_VER_WIN10)
|
|
control=GetWin10TabletMode()?OPEN_WINDOWS:OPEN_CLASSIC;
|
|
else
|
|
control=GetMetroMode(MonitorFromWindow(g_TaskBar,MONITOR_DEFAULTTONEAREST))?OPEN_WINDOWS:OPEN_CLASSIC;
|
|
}
|
|
if (control==OPEN_CLASSIC)
|
|
{
|
|
msg->message=WM_NULL;
|
|
const TaskbarInfo *taskBar=FindTaskBarInfoBar(g_TaskBar);
|
|
if (taskBar->startButton)
|
|
SetForegroundWindow(taskBar->startButton);
|
|
ToggleStartMenu(taskBar->taskbarId,true);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (msg->message==WM_KEYDOWN && msg->wParam==VK_TAB && CMenuContainer::IsMenuWindow(msg->hwnd))
|
|
{
|
|
// the taskbar steals the Tab key. we need to forward it to the menu instead
|
|
SendMessage(msg->hwnd,msg->message,msg->wParam,msg->lParam);
|
|
msg->message=WM_NULL;
|
|
}
|
|
|
|
if (msg->message==WM_SYSKEYDOWN && msg->wParam==VK_RETURN && CMenuContainer::IsMenuWindow(msg->hwnd))
|
|
{
|
|
// the taskbar steals the Alt+Enter key. we need to forward it to the menu instead
|
|
SendMessage(msg->hwnd,msg->message,msg->wParam,msg->lParam);
|
|
msg->message=WM_NULL;
|
|
}
|
|
}
|
|
bool bClick=(msg->message==WM_LBUTTONDOWN || msg->message==WM_LBUTTONDBLCLK || msg->message==WM_MBUTTONDOWN || msg->message==WM_MBUTTONDBLCLK);
|
|
bool bNcClick=(msg->message==WM_NCLBUTTONDOWN || msg->message==WM_NCLBUTTONDBLCLK || msg->message==WM_NCMBUTTONDOWN || msg->message==WM_NCMBUTTONDBLCLK);
|
|
bool bMiddle=(msg->message==WM_NCMBUTTONDOWN || msg->message==WM_MBUTTONDOWN || msg->message==WM_NCMBUTTONDBLCLK || msg->message==WM_MBUTTONDBLCLK);
|
|
if (bClick || bNcClick)
|
|
{
|
|
const TaskbarInfo *taskBar=NULL;
|
|
if (bClick)
|
|
taskBar=FindTaskBarInfoButton(msg->hwnd); // click on start button
|
|
if (!taskBar)
|
|
{
|
|
taskBar=FindTaskBarInfoBar(msg->hwnd); // click on taskbar
|
|
if (taskBar && !PointAroundStartButton(taskBar->taskbarId))
|
|
taskBar=NULL;
|
|
}
|
|
if (taskBar)
|
|
{
|
|
if (msg->message==WM_LBUTTONDOWN && GetWinVersion()==WIN_VER_WIN7 && msg->hwnd==taskBar->startButton)
|
|
{
|
|
// on Win7 ignore the click if the mouse is not over the start button (clicks on the context menu are sent to the start button)
|
|
CPoint pt(GetMessagePos());
|
|
if (WindowFromPoint(pt)!=msg->hwnd)
|
|
{
|
|
return CallNextHookEx(NULL,code,wParam,lParam);
|
|
}
|
|
}
|
|
// left or middle click on start button
|
|
FindWindowsMenu();
|
|
const wchar_t *name;
|
|
const wchar_t *command;
|
|
if (bMiddle)
|
|
{
|
|
name=L"MiddleClick";
|
|
command=L"MiddleClickCommand";
|
|
}
|
|
else if (GetKeyState(VK_SHIFT)<0)
|
|
{
|
|
name=L"ShiftClick";
|
|
command=L"ShiftClickCommand";
|
|
}
|
|
else
|
|
{
|
|
name=L"MouseClick";
|
|
command=L"MouseClickCommand";
|
|
}
|
|
|
|
int control=GetSettingInt(name);
|
|
if (control==OPEN_BOTH && GetWinVersion()>=WIN_VER_WIN10)
|
|
control=GetWin10TabletMode()?OPEN_WINDOWS:OPEN_CLASSIC;
|
|
if (control==OPEN_CLASSIC)
|
|
{
|
|
// click on the start button - toggle the menu
|
|
DWORD keyboard;
|
|
SystemParametersInfo(SPI_GETKEYBOARDCUES,NULL,&keyboard,0);
|
|
ToggleStartMenu(taskBar->taskbarId,keyboard!=0);
|
|
}
|
|
else if (control==OPEN_WINDOWS)
|
|
PostMessage(g_ProgWin,WM_SYSCOMMAND,SC_TASKLIST,'WSMM');
|
|
else if (control==OPEN_CORTANA)
|
|
OpenCortana();
|
|
else if (control==OPEN_CUSTOM)
|
|
{
|
|
CString commandText=GetSettingString(command);
|
|
if (!commandText.IsEmpty())
|
|
{
|
|
wchar_t expandedCommand[_MAX_PATH]{};
|
|
::ExpandEnvironmentStrings(commandText, expandedCommand, _countof(expandedCommand));
|
|
ShellExecute(NULL,NULL,expandedCommand,NULL,NULL,SW_SHOWNORMAL);
|
|
}
|
|
}
|
|
msg->message=WM_NULL;
|
|
}
|
|
}
|
|
|
|
if (msg->message==WM_LBUTTONUP)
|
|
{
|
|
// ignore button up on the win81 start button
|
|
const TaskbarInfo *taskBar=FindTaskBarInfoButton(msg->hwnd);
|
|
if (taskBar && taskBar->oldButton==msg->hwnd)
|
|
msg->message=WM_NULL;
|
|
}
|
|
if (!g_bTrimHooks)
|
|
{
|
|
if (msg->message==WM_TIMER && FindTaskBarInfoBar(msg->hwnd) && CMenuContainer::IgnoreTaskbarTimers())
|
|
{
|
|
// stop the taskbar timer messages. prevents the auto-hide taskbar from closing
|
|
msg->message=WM_NULL;
|
|
}
|
|
|
|
if (msg->message==WM_MOUSEMOVE && g_ProgramsButton && msg->hwnd==g_ProgramsButton && GetSettingBool(L"CascadeAll") && !(msg->wParam&MK_SHIFT))
|
|
{
|
|
DWORD pos=GetMessagePos();
|
|
if (pos!=g_LastHoverPos && !g_bAllProgramsTimer)
|
|
{
|
|
g_bAllProgramsTimer=true;
|
|
bool bDef;
|
|
DWORD time=GetSettingInt(L"AllProgramsDelay",bDef);
|
|
if (bDef)
|
|
SystemParametersInfo(SPI_GETMENUSHOWDELAY,NULL,&time,0);
|
|
SetTimer(g_ProgramsButton,'CLSM',time,NULL);
|
|
}
|
|
g_LastHoverPos=pos;
|
|
}
|
|
if (msg->message==WM_TIMER && msg->wParam=='CLSM' && g_ProgramsButton && msg->hwnd==g_ProgramsButton)
|
|
{
|
|
g_bAllProgramsTimer=false;
|
|
KillTimer(g_ProgramsButton,'CLSM');
|
|
DWORD pos=GetMessagePos();
|
|
if (pos==g_LastHoverPos)
|
|
PostMessage(g_AllPrograms,WM_COMMAND,IDOK,(LPARAM)g_ProgramsButton);
|
|
msg->message=WM_NULL;
|
|
}
|
|
if (msg->message==WM_MOUSELEAVE && g_ProgramsButton && msg->hwnd==g_ProgramsButton)
|
|
{
|
|
g_bAllProgramsTimer=false;
|
|
KillTimer(g_ProgramsButton,'CLSM');
|
|
}
|
|
|
|
// handle hover
|
|
if (msg->message==WM_MOUSEMOVE)
|
|
{
|
|
TaskbarInfo *taskBar=FindTaskBarInfoButton(msg->hwnd);
|
|
if (taskBar && !CMenuContainer::IsMenuOpened() && !WindowsMenuOpened())
|
|
{
|
|
if (GetSettingInt(L"Hover") && !taskBar->bTimer)
|
|
{
|
|
taskBar->bTimer=true;
|
|
int time=GetSettingInt(L"StartHoverDelay");
|
|
SetTimer(msg->hwnd,'CLSM',time,NULL);
|
|
}
|
|
if (msg->hwnd==taskBar->oldButton)
|
|
{
|
|
APPBARDATA appbar={sizeof(appbar)};
|
|
if (SHAppBarMessage(ABM_GETSTATE,&appbar)&ABS_AUTOHIDE)
|
|
SendMessage(taskBar->taskBar,WM_NCHITTEST,0,GetMessagePos());
|
|
}
|
|
}
|
|
}
|
|
if (msg->message==WM_MOUSELEAVE)
|
|
{
|
|
TaskbarInfo *taskBar=FindTaskBarInfoButton(msg->hwnd);
|
|
if (taskBar)
|
|
{
|
|
taskBar->bTimer=false;
|
|
KillTimer(msg->hwnd,'CLSM');
|
|
if (taskBar->oldButton==msg->hwnd)
|
|
{
|
|
RECT rc;
|
|
GetWindowRect(taskBar->oldButton,&rc);
|
|
CPoint pt(GetMessagePos());
|
|
if (PtInRect(&rc,pt))
|
|
{
|
|
wchar_t className[256]={0};
|
|
GetClassName(WindowFromPoint(pt),className,_countof(className));
|
|
if (wcscmp(className,L"ImmersiveSwitchList")==0 || wcscmp(className,L"EdgeUiInputWndClass")==0)
|
|
{
|
|
msg->message=WM_NULL;
|
|
TRACKMOUSEEVENT track={sizeof(track),TME_LEAVE,msg->hwnd,0};
|
|
TrackMouseEvent(&track);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ((msg->message==WM_NCMOUSEMOVE || msg->message==WM_NCMOUSELEAVE) && (msg->wParam==HTCAPTION || !IsAppThemed()) && GetSettingInt(L"Hover")) // HACK: in Classic mode the start menu can show up even if wParam is not HTCAPTION (most likely a bug in Windows)
|
|
{
|
|
TaskbarInfo *taskBar=FindTaskBarInfoBar(msg->hwnd);
|
|
if (taskBar)
|
|
{
|
|
if (!CMenuContainer::IsMenuOpened() && !WindowsMenuOpened() && PointAroundStartButton(taskBar->taskbarId))
|
|
{
|
|
if (!taskBar->bTimer)
|
|
{
|
|
taskBar->bTimer=true;
|
|
int time=GetSettingInt(L"StartHoverDelay");
|
|
SetTimer(taskBar->startButton,'CLSM',time,NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (taskBar->bTimer)
|
|
{
|
|
taskBar->bTimer=false;
|
|
KillTimer(taskBar->startButton,'CLSM');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (msg->message==WM_TIMER && msg->wParam=='CLSM' && CMenuContainer::CanShowMenu())
|
|
{
|
|
TaskbarInfo *taskBar=FindTaskBarInfoButton(msg->hwnd);
|
|
if (taskBar)
|
|
{
|
|
KillTimer(msg->hwnd,'CLSM');
|
|
msg->message=WM_NULL;
|
|
if (taskBar->bTimer && !CMenuContainer::IsMenuOpened() && !WindowsMenuOpened())
|
|
{
|
|
CPoint pt(GetMessagePos());
|
|
if (WindowFromPoint(pt)==msg->hwnd || PointAroundStartButton(taskBar->taskbarId))
|
|
{
|
|
int control=GetSettingInt(L"Hover");
|
|
if (control==OPEN_CLASSIC)
|
|
{
|
|
PostMessage(g_ProgWin,WM_SYSCOMMAND,SC_TASKLIST,'CSM');
|
|
}
|
|
else if (control==OPEN_WINDOWS)
|
|
{
|
|
FindWindowsMenu();
|
|
PostMessage(g_ProgWin,WM_SYSCOMMAND,SC_TASKLIST,'WSMM');
|
|
}
|
|
else if (control==OPEN_CUSTOM)
|
|
{
|
|
CString commandText=GetSettingString(L"HoverCommand");
|
|
if (!commandText.IsEmpty())
|
|
{
|
|
wchar_t expandedCommand[_MAX_PATH]{};
|
|
::ExpandEnvironmentStrings(commandText, expandedCommand, _countof(expandedCommand));
|
|
ShellExecute(NULL,NULL,expandedCommand,NULL,NULL,SW_SHOWNORMAL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
taskBar->bTimer=false;
|
|
}
|
|
}
|
|
}
|
|
// context menu
|
|
if (msg->message==WM_NCRBUTTONUP || msg->message==WM_RBUTTONUP)
|
|
{
|
|
TaskbarInfo *taskBar=FindTaskBarInfoButton(msg->hwnd);
|
|
DWORD winVer=GetWinVersion();
|
|
if (!taskBar && winVer>=WIN_VER_WIN8)
|
|
{
|
|
taskBar=FindTaskBarInfoBar(msg->hwnd);
|
|
if (taskBar && !PointAroundStartButton(taskBar->taskbarId))
|
|
taskBar=NULL;
|
|
}
|
|
if (taskBar)
|
|
{
|
|
CPoint pt0(GetMessagePos());
|
|
if (msg->message==WM_RBUTTONUP && msg->hwnd==taskBar->startButton && msg->lParam==MAKELPARAM(-1,-1))
|
|
{
|
|
RECT rc;
|
|
GetWindowRect(msg->hwnd,&rc);
|
|
pt0.x=(rc.left+rc.right)/2;
|
|
pt0.y=(rc.top+rc.bottom)/2;
|
|
}
|
|
bool bShowCSMenu=false, bShowWinX=false, bShowWin7=false;
|
|
if (msg->hwnd==taskBar->taskBar && taskBar->bReplaceButton)
|
|
bShowWinX=true;
|
|
else
|
|
{
|
|
bShowCSMenu=(GetSettingBool(L"ShiftRight")==(GetKeyState(VK_SHIFT)<0));
|
|
bShowWinX=winVer>=WIN_VER_WIN8 && !bShowCSMenu;
|
|
}
|
|
bShowWin7=!bShowCSMenu && g_WinStartButton && msg->hwnd!=g_WinStartButton;
|
|
|
|
if (bShowCSMenu || bShowWinX || bShowWin7)
|
|
{
|
|
msg->message=WM_NULL;
|
|
if (CMenuContainer::IsMenuOpened())
|
|
CMenuContainer::CloseStartMenu();
|
|
}
|
|
if (bShowCSMenu)
|
|
{
|
|
// additional commands for the context menu
|
|
enum
|
|
{
|
|
CMD_SETTINGS=1,
|
|
CMD_HELP,
|
|
CMD_EXIT,
|
|
CMD_OPEN,
|
|
CMD_OPEN_ALL,
|
|
CMD_EXPLORER,
|
|
CMD_OPEN_PINNED,
|
|
};
|
|
|
|
// right-click on the start button - open the context menu (Settings, Help, Exit)
|
|
HMENU menu=CreatePopupMenu();
|
|
CString titleFmt=LoadStringEx(IDS_MENU_TITLE);
|
|
if (!titleFmt.IsEmpty())
|
|
{
|
|
CString title;
|
|
DWORD ver=GetVersionEx(g_Instance);
|
|
title.Format(titleFmt,ver>>24,(ver>>16)&0xFF,ver&0xFFFF);
|
|
|
|
AppendMenu(menu,MF_STRING,0,title);
|
|
EnableMenuItem(menu,0,MF_BYPOSITION|MF_DISABLED);
|
|
SetMenuDefaultItem(menu,0,TRUE);
|
|
AppendMenu(menu,MF_SEPARATOR,0,0);
|
|
}
|
|
int count0=GetMenuItemCount(menu);
|
|
if (GetSettingBool(L"EnableExplorer"))
|
|
{
|
|
if (!GetSettingString(L"ExplorerPath").IsEmpty())
|
|
AppendMenu(menu,MF_STRING,CMD_EXPLORER,FindTranslation(L"Menu.Explorer",L"Windows Explorer"));
|
|
AppendMenu(menu,MF_STRING,CMD_OPEN,FindTranslation(L"Menu.Open",L"&Open"));
|
|
if (!SHRestricted(REST_NOCOMMONGROUPS))
|
|
AppendMenu(menu,MF_STRING,CMD_OPEN_ALL,FindTranslation(L"Menu.OpenAll",L"O&pen All Users"));
|
|
if (GetSettingInt(L"PinnedPrograms")==PINNED_PROGRAMS_PINNED)
|
|
AppendMenu(menu,MF_STRING,CMD_OPEN_PINNED,FindTranslation(L"Menu.OpenPinned",L"O&pen Pinned"));
|
|
AppendMenu(menu,MF_SEPARATOR,0,0);
|
|
}
|
|
if (GetSettingBool(L"EnableSettings"))
|
|
AppendMenu(menu,MF_STRING,CMD_SETTINGS,FindTranslation(L"Menu.MenuSettings",L"Settings"));
|
|
if (HasHelp())
|
|
AppendMenu(menu,MF_STRING,CMD_HELP,FindTranslation(L"Menu.MenuHelp",L"Help"));
|
|
if (GetSettingBool(L"EnableExit"))
|
|
{
|
|
AppendMenu(menu,MF_STRING,CMD_EXIT,FindTranslation(L"Menu.MenuExit",L"Exit"));
|
|
if (!CMenuContainer::CanShowMenu())
|
|
EnableMenuItem(menu,CMD_EXIT,MF_BYCOMMAND|MF_DISABLED);
|
|
}
|
|
if (GetMenuItemCount(menu)>count0)
|
|
{
|
|
MENUITEMINFO mii={sizeof(mii)};
|
|
mii.fMask=MIIM_BITMAP;
|
|
mii.hbmpItem=HBMMENU_POPUP_CLOSE;
|
|
SetMenuItemInfo(menu,CMD_EXIT,FALSE,&mii);
|
|
MENUINFO info={sizeof(info),MIM_STYLE,MNS_CHECKORBMP};
|
|
SetMenuInfo(menu,&info);
|
|
g_bInMenu=true;
|
|
SetForegroundWindow(msg->hwnd);
|
|
int res=TrackPopupMenu(menu,TPM_RIGHTBUTTON|TPM_RETURNCMD|(IsLanguageRTL()?TPM_LAYOUTRTL:0),pt0.x,pt0.y,0,msg->hwnd,NULL);
|
|
DestroyMenu(menu);
|
|
g_bInMenu=false;
|
|
if (res==CMD_SETTINGS)
|
|
{
|
|
EditSettings(false,0);
|
|
}
|
|
if (res==CMD_HELP)
|
|
{
|
|
ShowHelp();
|
|
return TRUE;
|
|
}
|
|
if (res==CMD_EXIT)
|
|
{
|
|
LRESULT res=CallNextHookEx(NULL,code,wParam,lParam);
|
|
CleanStartMenuDLL();
|
|
return res; // we should exit as quickly as possible now. the DLL is about to be unloaded
|
|
}
|
|
if (res==CMD_OPEN || res==CMD_OPEN_ALL)
|
|
{
|
|
CComString pPath;
|
|
if (SUCCEEDED(ShGetKnownFolderPath((res==CMD_OPEN)?FOLDERID_StartMenu:FOLDERID_CommonStartMenu,&pPath)))
|
|
ShellExecute(NULL,L"open",pPath,NULL,NULL,SW_SHOWNORMAL);
|
|
}
|
|
if (res==CMD_OPEN_PINNED) // open pinned folder
|
|
{
|
|
SHELLEXECUTEINFO execute={sizeof(execute)};
|
|
CString path=GetSettingString(L"PinnedItemsPath");
|
|
execute.lpVerb=L"open";
|
|
execute.lpFile=path;
|
|
execute.nShow=SW_SHOWNORMAL;
|
|
execute.fMask=SEE_MASK_DOENVSUBST;
|
|
ShellExecuteEx(&execute);
|
|
}
|
|
if (res==CMD_EXPLORER)
|
|
{
|
|
CString path=GetSettingString(L"ExplorerPath");
|
|
ITEMIDLIST blank={0};
|
|
SHELLEXECUTEINFO execute={sizeof(execute)};
|
|
execute.lpVerb=L"open";
|
|
execute.lpFile=path;
|
|
execute.nShow=SW_SHOWNORMAL;
|
|
if (_wcsicmp(path,L"computer")==0)
|
|
execute.lpFile=L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}";
|
|
else if (_wcsicmp(path,L"libraries")==0)
|
|
execute.lpFile=L"::{031E4825-7B94-4DC3-B131-E946B44C8DD5}";
|
|
else if (_wcsicmp(path,L"desktop")==0)
|
|
{
|
|
execute.fMask=SEE_MASK_IDLIST;
|
|
execute.lpIDList=␣
|
|
execute.lpFile=NULL;
|
|
}
|
|
else
|
|
{
|
|
execute.fMask=SEE_MASK_DOENVSUBST;
|
|
}
|
|
ShellExecuteEx(&execute);
|
|
}
|
|
}
|
|
}
|
|
else if (bShowWinX)
|
|
{
|
|
ShowWinX();
|
|
}
|
|
else if (bShowWin7)
|
|
{
|
|
CPoint pt(GetMessagePos());
|
|
ScreenToClient(g_WinStartButton,&pt);
|
|
PostMessage(g_WinStartButton,WM_RBUTTONUP,wParam,MAKELONG(pt.x,pt.y));
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
return CallNextHookEx(NULL,code,wParam,lParam);
|
|
}
|
|
|
|
HBITMAP GetStartScreenIcon( int size )
|
|
{
|
|
// for sizes >=64, use image directly
|
|
// for sizes>=32, get 64x64 and scale down
|
|
// for sizes<32 use the system background color
|
|
StartScreenThumbInfo info={{size<64?64:size}};
|
|
info.size.cy=info.size.cx;
|
|
if (size>=32 && g_AppManagerThread && GetWinVersion()==WIN_VER_WIN8)
|
|
{
|
|
info.event=CreateEvent(NULL,TRUE,FALSE,NULL);
|
|
PostThreadMessage(g_AppManagerThread,g_StartMenuMsg,MSG_METROTHUMBNAIL,(LPARAM)&info);
|
|
WaitForSingleObject(info.event,100); // if it takes more than 100ms, screw it
|
|
CloseHandle(info.event);
|
|
}
|
|
info.size.cy=info.size.cx*3/4;
|
|
|
|
BITMAPINFO bi={0};
|
|
bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
|
|
bi.bmiHeader.biWidth=bi.bmiHeader.biHeight=size;
|
|
bi.bmiHeader.biPlanes=1;
|
|
bi.bmiHeader.biBitCount=32;
|
|
|
|
HDC hDst=CreateCompatibleDC(NULL);
|
|
unsigned int *bits;
|
|
HBITMAP bitmap=CreateDIBSection(hDst,&bi,DIB_RGB_COLORS,(void**)&bits,NULL,0);
|
|
HGDIOBJ bmp0=SelectObject(hDst,bitmap);
|
|
RECT rc={0,size/8,size,size*7/8};
|
|
|
|
if (info.bitmap)
|
|
{
|
|
HDC hSrc=CreateCompatibleDC(hDst);
|
|
HGDIOBJ bmp02=SelectObject(hSrc,info.bitmap);
|
|
SetStretchBltMode(hDst,HALFTONE);
|
|
StretchBlt(hDst,rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,hSrc,0,0,info.size.cx,info.size.cy,SRCCOPY);
|
|
SelectObject(hSrc,bmp02);
|
|
DeleteDC(hSrc);
|
|
DeleteObject(info.bitmap);
|
|
}
|
|
else
|
|
{
|
|
typedef int (WINAPI *TGetImmersiveUserColorSetPreference)(bool bForceCheckRegistry, bool bSkipCheckOnFail);
|
|
typedef DWORD (WINAPI *TGetImmersiveColorFromColorSetEx)(UINT dwImmersiveColorSet, UINT dwImmersiveColorType, bool bIgnoreHighContrast, UINT dwHighContrastCacheMode);
|
|
typedef int (WINAPI *TGetImmersiveColorTypeFromName)(const wchar_t *name);
|
|
COLORREF color=0;
|
|
HMODULE hUxTheme=GetModuleHandle(L"uxtheme.dll");
|
|
if (hUxTheme)
|
|
{
|
|
TGetImmersiveUserColorSetPreference GetImmersiveUserColorSetPreference=(TGetImmersiveUserColorSetPreference)GetProcAddress(hUxTheme,MAKEINTRESOURCEA(98));
|
|
TGetImmersiveColorFromColorSetEx GetImmersiveColorFromColorSetEx=(TGetImmersiveColorFromColorSetEx)GetProcAddress(hUxTheme,MAKEINTRESOURCEA(95));
|
|
TGetImmersiveColorTypeFromName GetImmersiveColorTypeFromName=(TGetImmersiveColorTypeFromName)GetProcAddress(hUxTheme,MAKEINTRESOURCEA(96));
|
|
if (GetImmersiveUserColorSetPreference && GetImmersiveColorFromColorSetEx && GetImmersiveColorTypeFromName)
|
|
{
|
|
int type=GetImmersiveColorTypeFromName(L"ImmersiveStartBackground");
|
|
int set=GetImmersiveUserColorSetPreference(false,false);
|
|
color=GetImmersiveColorFromColorSetEx(set,type,false,0)&0xFFFFFF;
|
|
}
|
|
}
|
|
SetDCBrushColor(hDst,color);
|
|
FillRect(hDst,&rc,(HBRUSH)GetStockObject(DC_BRUSH));
|
|
HICON hIcon=(HICON)LoadImage(g_Instance,MAKEINTRESOURCE(GetWinVersion()>=WIN_VER_WIN10?IDI_START10:IDI_START),IMAGE_ICON,size,size,LR_DEFAULTCOLOR);
|
|
DrawIconEx(hDst,0,0,hIcon,size,size,0,NULL,DI_NORMAL);
|
|
DestroyIcon(hIcon);
|
|
}
|
|
SelectObject(hDst,bmp0);
|
|
DeleteDC(hDst);
|
|
|
|
int i=0;
|
|
int n=size*rc.top;
|
|
for (;i<n;i++)
|
|
bits[i]=0;
|
|
n=size*rc.bottom;
|
|
for (;i<n;i++)
|
|
bits[i]|=0xFF000000;
|
|
n=size*size;
|
|
for (;i<n;i++)
|
|
bits[i]=0;
|
|
|
|
return bitmap;
|
|
}
|
|
|
|
// WH_GETMESSAGE hook for the explorer's GUI thread. The start menu exe uses this hook to inject code into the explorer process
|
|
STARTMENUAPI LRESULT CALLBACK HookInject( int code, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
if (code==HC_ACTION && !g_TaskBar)
|
|
InitStartMenuDLL();
|
|
return CallNextHookEx(NULL,code,wParam,lParam);
|
|
}
|
|
|
|
STARTMENUAPI void InitManagers( bool bNohook )
|
|
{
|
|
InitializeSkinManager(bNohook);
|
|
g_ItemManager.Init(); // must be after skin manager because it uses the metro colors
|
|
g_SearchManager.Init();
|
|
}
|
|
|
|
STARTMENUAPI void CloseManagers( bool bNohook )
|
|
{
|
|
g_SearchManager.Close();
|
|
g_ItemManager.Close();
|
|
CloseSkinManager(bNohook);
|
|
}
|
|
|
|
STARTMENUAPI bool DllGetSettingBool( const wchar_t *name )
|
|
{
|
|
return GetSettingBool(name);
|
|
}
|
|
|
|
STARTMENUAPI int DllGetSettingInt( const wchar_t *name )
|
|
{
|
|
return GetSettingInt(name);
|
|
}
|
|
|
|
STARTMENUAPI void DllUpdateSettings( void )
|
|
{
|
|
CSettingsLockWrite lock;
|
|
UpdateSettings();
|
|
}
|
|
|
|
STARTMENUAPI CString DllLoadStringEx( int stringID )
|
|
{
|
|
return LoadStringEx(stringID);
|
|
}
|
|
|
|
STARTMENUAPI void DllLogToFile( const wchar_t *location, const wchar_t *message, ... )
|
|
{
|
|
va_list args;
|
|
va_start(args,message);
|
|
VLogToFile(location,message,args);
|
|
va_end(args);
|
|
}
|
|
|
|
#ifndef _WIN64
|
|
STARTMENUAPI bool DllSaveAdmx( TSettingsComponent component, const char *admxFile, const char *admlFile, const char *docFile )
|
|
{
|
|
return SaveAdmx(component,admxFile,admlFile,docFile);
|
|
}
|
|
|
|
STARTMENUAPI void DllLoadTranslationResources( HINSTANCE hLngInstance, int *pDialogs )
|
|
{
|
|
LoadTranslationResources(hLngInstance,pDialogs);
|
|
}
|
|
#endif
|
|
|
|
#ifdef TRACK_GDI_RESOURCES
|
|
STARTMENUAPI void DllDumpResourceLeaks( void )
|
|
{
|
|
DumpResourceLeaks();
|
|
}
|
|
#endif
|