Something went wrong. Try again.
Reactos
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300/* * ReactOS Explorer * * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#include "precomp.h"#include <commoncontrols.h>#include <regstr.h>#include <shlwapi_undoc.h>
/* Set DUMP_TASKS to 1 to enable a dump of the tasks and task groups every 5 seconds */#define DUMP_TASKS 0#define DEBUG_SHELL_HOOK 0
#define MAX_TASKS_COUNT (0x7FFF)#define TASK_ITEM_ARRAY_ALLOC 64
//************************************************************************// Fullscreen windows (a.k.a. rude apps) checker
#define TIMER_ID_VALIDATE_RUDE_APP 5#define VALIDATE_RUDE_INTERVAL 1000#define VALIDATE_RUDE_MAX_COUNT 5
static BOOLSHELL_GetMonitorRect( _In_opt_ HMONITOR hMonitor, _Out_opt_ PRECT prcDest, _In_ BOOL bWorkAreaOnly){ MONITORINFO mi = { sizeof(mi) }; if (!hMonitor || !::GetMonitorInfoW(hMonitor, &mi)) { if (!prcDest) return FALSE;
if (bWorkAreaOnly) ::SystemParametersInfoW(SPI_GETWORKAREA, 0, prcDest, 0); else ::SetRect(prcDest, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
return FALSE; }
if (prcDest) *prcDest = (bWorkAreaOnly ? mi.rcWork : mi.rcMonitor); return TRUE;}
static BOOLSHELL_IsParentOwnerOrSelf(_In_ HWND hwndTarget, _In_ HWND hWnd){ for (; hWnd; hWnd = ::GetParent(hWnd)) { if (hWnd == hwndTarget) return TRUE; } return FALSE;}
static BOOLSHELL_IsRudeWindowActive(_In_ HWND hWnd){ HWND hwndFore = ::GetForegroundWindow(); DWORD dwThreadId = ::GetWindowThreadProcessId(hWnd, NULL); return dwThreadId == ::GetWindowThreadProcessId(hwndFore, NULL) || SHELL_IsParentOwnerOrSelf(hWnd, hwndFore);}
static BOOLSHELL_IsRudeWindow(_In_opt_ HMONITOR hMonitor, _In_ HWND hWnd, _In_ BOOL bDontCheckActive){ if (!::IsWindowVisible(hWnd) || hWnd == ::GetDesktopWindow()) return FALSE;
RECT rcMonitor; SHELL_GetMonitorRect(hMonitor, &rcMonitor, FALSE);
DWORD style = ::GetWindowLongPtrW(hWnd, GWL_STYLE);
RECT rcWnd; enum { CHECK_STYLE = WS_THICKFRAME | WS_DLGFRAME | WS_BORDER }; if ((style & CHECK_STYLE) == CHECK_STYLE) { ::GetClientRect(hWnd, &rcWnd); // Ignore frame ::MapWindowPoints(hWnd, NULL, (PPOINT)&rcWnd, sizeof(RECT) / sizeof(POINT)); } else { ::GetWindowRect(hWnd, &rcWnd); }
RECT rcUnion; ::UnionRect(&rcUnion, &rcWnd, &rcMonitor);
return ::EqualRect(&rcUnion, &rcWnd) && (bDontCheckActive || SHELL_IsRudeWindowActive(hWnd));}
////////////////////////////////////////////////////////////////
const WCHAR szTaskSwitchWndClass[] = L"MSTaskSwWClass";const WCHAR szRunningApps[] = L"Running Applications";
#if DEBUG_SHELL_HOOKconst struct { INT msg; LPCWSTR msg_name;} hshell_msg [] = { { HSHELL_WINDOWCREATED, L"HSHELL_WINDOWCREATED" }, { HSHELL_WINDOWDESTROYED, L"HSHELL_WINDOWDESTROYED" }, { HSHELL_ACTIVATESHELLWINDOW, L"HSHELL_ACTIVATESHELLWINDOW" }, { HSHELL_WINDOWACTIVATED, L"HSHELL_WINDOWACTIVATED" }, { HSHELL_GETMINRECT, L"HSHELL_GETMINRECT" }, { HSHELL_REDRAW, L"HSHELL_REDRAW" }, { HSHELL_TASKMAN, L"HSHELL_TASKMAN" }, { HSHELL_LANGUAGE, L"HSHELL_LANGUAGE" }, { HSHELL_SYSMENU, L"HSHELL_SYSMENU" }, { HSHELL_ENDTASK, L"HSHELL_ENDTASK" }, { HSHELL_ACCESSIBILITYSTATE, L"HSHELL_ACCESSIBILITYSTATE" }, { HSHELL_APPCOMMAND, L"HSHELL_APPCOMMAND" }, { HSHELL_WINDOWREPLACED, L"HSHELL_WINDOWREPLACED" }, { HSHELL_WINDOWREPLACING, L"HSHELL_WINDOWREPLACING" }, { HSHELL_RUDEAPPACTIVATED, L"HSHELL_RUDEAPPACTIVATED" },};#endif
typedef struct _TASK_GROUP{ /* We have to use a linked list instead of an array so we don't have to update all pointers to groups in the task item array when removing groups. */ struct _TASK_GROUP *Next;
DWORD dwTaskCount; DWORD dwProcessId; INT Index; union { DWORD dwFlags; struct {
DWORD IsCollapsed : 1; }; };} TASK_GROUP, *PTASK_GROUP;
typedef struct _TASK_ITEM{ HWND hWnd; PTASK_GROUP Group; INT Index; INT IconIndex;
union { DWORD dwFlags; struct {
/* IsFlashing is TRUE when the task bar item should be flashing. */ DWORD IsFlashing : 1;
/* RenderFlashed is only TRUE if the task bar item should be drawn with a flash. */ DWORD RenderFlashed : 1; }; };} TASK_ITEM, *PTASK_ITEM;
class CHardErrorThread{ DWORD m_ThreadId; HANDLE m_hThread; LONG m_bThreadRunning; DWORD m_Status; DWORD m_dwType; CStringW m_Title; CStringW m_Text;public:
CHardErrorThread(): m_ThreadId(0), m_hThread(NULL), m_bThreadRunning(FALSE), m_Status(NULL), m_dwType(NULL) { }
~CHardErrorThread() { if (m_bThreadRunning) { /* Try to unstuck Show */ PostThreadMessage(m_ThreadId, WM_QUIT, 0, 0); DWORD ret = WaitForSingleObject(m_hThread, 3*1000); if (ret == WAIT_TIMEOUT) TerminateThread(m_hThread, 0); CloseHandle(m_hThread); } }
HRESULT ThreadProc() { HRESULT hr; CComPtr<IUserNotification> pnotification;
hr = OleInitialize(NULL); if (FAILED_UNEXPECTEDLY(hr)) return hr;
hr = CoCreateInstance(CLSID_UserNotification, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IUserNotification, &pnotification)); if (FAILED_UNEXPECTEDLY(hr)) return hr;
hr = pnotification->SetBalloonInfo(m_Title, m_Text, NIIF_WARNING); if (FAILED_UNEXPECTEDLY(hr)) return hr;
hr = pnotification->SetIconInfo(NULL, NULL); if (FAILED_UNEXPECTEDLY(hr)) return hr;
/* Show will block until the balloon closes */ hr = pnotification->Show(NULL, 0); if (FAILED_UNEXPECTEDLY(hr)) return hr;
return S_OK; }
static DWORD CALLBACK s_HardErrorThreadProc(IN OUT LPVOID lpParameter) { CHardErrorThread* pThis = reinterpret_cast<CHardErrorThread*>(lpParameter); pThis->ThreadProc(); CloseHandle(pThis->m_hThread); OleUninitialize(); InterlockedExchange(&pThis->m_bThreadRunning, FALSE); return 0; }
void StartThread(PBALLOON_HARD_ERROR_DATA pData) { BOOL bIsRunning = InterlockedExchange(&m_bThreadRunning, TRUE);
/* Ignore the new message if we are already showing one */ if (bIsRunning) return;
m_Status = pData->Status; m_dwType = pData->dwType; m_Title = (PWCHAR)((ULONG_PTR)pData + pData->TitleOffset); m_Text = (PWCHAR)((ULONG_PTR)pData + pData->MessageOffset); m_hThread = CreateThread(NULL, 0, s_HardErrorThreadProc, this, 0, &m_ThreadId); if (!m_hThread) { m_bThreadRunning = FALSE; } }};
class CTaskToolbar : public CWindowImplBaseT< CToolbar<TASK_ITEM>, CControlWinTraits >{public: INT UpdateTbButtonSpacing(IN BOOL bHorizontal, IN BOOL bThemed, IN UINT uiRows = 0, IN UINT uiBtnsPerLine = 0) { TBMETRICS tbm;
tbm.cbSize = sizeof(tbm); tbm.dwMask = TBMF_BARPAD | TBMF_BUTTONSPACING;
tbm.cxBarPad = tbm.cyBarPad = 0;
if (bThemed) { tbm.cxButtonSpacing = 0; tbm.cyButtonSpacing = 0; } else { if (bHorizontal || uiBtnsPerLine > 1) tbm.cxButtonSpacing = (3 * GetSystemMetrics(SM_CXEDGE) / 2); else tbm.cxButtonSpacing = 0;
if (!bHorizontal || uiRows > 1) tbm.cyButtonSpacing = (3 * GetSystemMetrics(SM_CYEDGE) / 2); else tbm.cyButtonSpacing = 0; }
SetMetrics(&tbm);
return tbm.cxButtonSpacing; }
VOID BeginUpdate() { SetRedraw(FALSE); }
VOID EndUpdate() { SendMessageW(WM_SETREDRAW, TRUE); InvalidateRect(NULL, TRUE); }
BOOL SetButtonCommandId(IN INT iButtonIndex, IN INT iCommandId) { TBBUTTONINFO tbbi;
tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND; tbbi.idCommand = iCommandId;
return SetButtonInfo(iButtonIndex, &tbbi) != 0; }
LRESULT OnNcHitTestToolbar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { POINT pt;
/* See if the mouse is on a button */ pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); ScreenToClient(&pt);
INT index = HitTest(&pt); if (index < 0) { /* Make the control appear to be transparent outside of any buttons */ return HTTRANSPARENT; }
bHandled = FALSE; return 0; }
public: BEGIN_MSG_MAP(CNotifyToolbar) MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTestToolbar) END_MSG_MAP()
BOOL Initialize(HWND hWndParent) { DWORD styles = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE | TBSTYLE_LIST | TBSTYLE_TRANSPARENT | CCS_TOP | CCS_NORESIZE | CCS_NODIVIDER;
// HACK & FIXME: CORE-18016 HWND toolbar = CToolbar::Create(hWndParent, styles); m_hWnd = NULL; return SubclassWindow(toolbar); }};
class CTaskSwitchWnd : public CComCoClass<CTaskSwitchWnd>, public CComObjectRootEx<CComMultiThreadModelNoCS>, public CWindowImpl < CTaskSwitchWnd, CWindow, CControlWinTraits >, public IOleWindow{ CTaskToolbar m_TaskBar;
CComPtr<ITrayWindow> m_Tray;
UINT m_ShellHookMsg;
WORD m_TaskItemCount; WORD m_AllocatedTaskItems;
PTASK_GROUP m_TaskGroups; PTASK_ITEM m_TaskItems; PTASK_ITEM m_ActiveTaskItem;
HTHEME m_Theme; UINT m_ButtonsPerLine; WORD m_ButtonCount;
HIMAGELIST m_ImageList;
BOOL m_IsGroupingEnabled; BOOL m_IsDestroying;
INT m_nRudeAppValidationCounter;
SIZE m_ButtonSize;
UINT m_uHardErrorMsg; CHardErrorThread m_HardErrorThread;
public: CTaskSwitchWnd() : m_ShellHookMsg(NULL), m_TaskItemCount(0), m_AllocatedTaskItems(0), m_TaskGroups(NULL), m_TaskItems(NULL), m_ActiveTaskItem(NULL), m_Theme(NULL), m_ButtonsPerLine(0), m_ButtonCount(0), m_ImageList(NULL), m_IsGroupingEnabled(FALSE), m_IsDestroying(FALSE), m_nRudeAppValidationCounter(0) { ZeroMemory(&m_ButtonSize, sizeof(m_ButtonSize)); m_uHardErrorMsg = RegisterWindowMessageW(L"HardError"); } virtual ~CTaskSwitchWnd() { }
INT GetWndTextFromTaskItem(IN PTASK_ITEM TaskItem, LPWSTR szBuf, DWORD cchBuf) { /* Get the window text without sending a message so we don't hang if an application isn't responding! */ return InternalGetWindowText(TaskItem->hWnd, szBuf, cchBuf); }
#if DUMP_TASKS != 0 VOID DumpTasks() { PTASK_GROUP CurrentGroup; PTASK_ITEM CurrentTaskItem, LastTaskItem;
TRACE("Tasks dump:\n"); if (m_IsGroupingEnabled) { CurrentGroup = m_TaskGroups; while (CurrentGroup != NULL) { TRACE("- Group PID: 0x%p Tasks: %d Index: %d\n", CurrentGroup->dwProcessId, CurrentGroup->dwTaskCount, CurrentGroup->Index);
CurrentTaskItem = m_TaskItems; LastTaskItem = CurrentTaskItem + m_TaskItemCount; while (CurrentTaskItem != LastTaskItem) { if (CurrentTaskItem->Group == CurrentGroup) { TRACE(" + Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index); } CurrentTaskItem++; }
CurrentGroup = CurrentGroup->Next; }
CurrentTaskItem = m_TaskItems; LastTaskItem = CurrentTaskItem + m_TaskItemCount; while (CurrentTaskItem != LastTaskItem) { if (CurrentTaskItem->Group == NULL) { TRACE("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index); } CurrentTaskItem++; } } else { CurrentTaskItem = m_TaskItems; LastTaskItem = CurrentTaskItem + m_TaskItemCount; while (CurrentTaskItem != LastTaskItem) { TRACE("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index); CurrentTaskItem++; } } }#endif
VOID UpdateIndexesAfter(IN INT iIndex, BOOL bInserted) { PTASK_GROUP CurrentGroup; PTASK_ITEM CurrentTaskItem, LastTaskItem; INT NewIndex;
int offset = bInserted ? +1 : -1;
if (m_IsGroupingEnabled) { /* Update all affected groups */ CurrentGroup = m_TaskGroups; while (CurrentGroup != NULL) { if (CurrentGroup->IsCollapsed && CurrentGroup->Index >= iIndex) { /* Update the toolbar buttons */ NewIndex = CurrentGroup->Index + offset; if (m_TaskBar.SetButtonCommandId(CurrentGroup->Index + offset, NewIndex)) { CurrentGroup->Index = NewIndex; } else CurrentGroup->Index = -1; }
CurrentGroup = CurrentGroup->Next; } }
/* Update all affected task items */ CurrentTaskItem = m_TaskItems; LastTaskItem = CurrentTaskItem + m_TaskItemCount; while (CurrentTaskItem != LastTaskItem) { CurrentGroup = CurrentTaskItem->Group; if (CurrentGroup != NULL) { if (!CurrentGroup->IsCollapsed && CurrentTaskItem->Index >= iIndex) { goto UpdateTaskItemBtn; } } else if (CurrentTaskItem->Index >= iIndex) { UpdateTaskItemBtn: /* Update the toolbar buttons */ NewIndex = CurrentTaskItem->Index + offset; if (m_TaskBar.SetButtonCommandId(CurrentTaskItem->Index + offset, NewIndex)) { CurrentTaskItem->Index = NewIndex; } else CurrentTaskItem->Index = -1; }
CurrentTaskItem++; } }
INT UpdateTaskGroupButton(IN PTASK_GROUP TaskGroup) { ASSERT(TaskGroup->Index >= 0);
/* FIXME: Implement */
return TaskGroup->Index; }
VOID ExpandTaskGroup(IN PTASK_GROUP TaskGroup) { ASSERT(TaskGroup->dwTaskCount > 0); ASSERT(TaskGroup->IsCollapsed); ASSERT(TaskGroup->Index >= 0);
/* FIXME: Implement */ }
HICON GetWndIcon(HWND hwnd) { HICON hIcon = NULL;
/* Retrieve icon by sending a message */#define GET_ICON(type) \ SendMessageTimeout(hwnd, WM_GETICON, (type), 0, SMTO_NOTIMEOUTIFNOTHUNG, 100, (PDWORD_PTR)&hIcon)
LRESULT bAlive = GET_ICON(g_TaskbarSettings.bSmallIcons ? ICON_SMALL2 : ICON_BIG); if (hIcon) return hIcon;
if (bAlive) { bAlive = GET_ICON(ICON_SMALL); if (hIcon) return hIcon; }
if (bAlive) { GET_ICON(g_TaskbarSettings.bSmallIcons ? ICON_BIG : ICON_SMALL2); if (hIcon) return hIcon; }#undef GET_ICON
/* If we failed, retrieve icon from the window class */ hIcon = (HICON)GetClassLongPtr(hwnd, g_TaskbarSettings.bSmallIcons ? GCLP_HICONSM : GCLP_HICON); if (hIcon) return hIcon;
return (HICON)GetClassLongPtr(hwnd, g_TaskbarSettings.bSmallIcons ? GCLP_HICON : GCLP_HICONSM); }
INT UpdateTaskItemButton(IN PTASK_ITEM TaskItem) { TBBUTTONINFO tbbi = { 0 }; HICON icon; WCHAR windowText[255];
ASSERT(TaskItem->Index >= 0);
tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_BYINDEX | TBIF_STATE | TBIF_TEXT | TBIF_IMAGE; tbbi.fsState = TBSTATE_ENABLED; if (m_ActiveTaskItem == TaskItem) tbbi.fsState |= TBSTATE_CHECKED;
if (TaskItem->RenderFlashed) tbbi.fsState |= TBSTATE_MARKED;
/* Check if we're updating a button that is the last one in the line. If so, we need to set the TBSTATE_WRAP flag! */ if (!m_Tray->IsHorizontal() || (m_ButtonsPerLine != 0 && (TaskItem->Index + 1) % m_ButtonsPerLine == 0)) { tbbi.fsState |= TBSTATE_WRAP; }
if (GetWndTextFromTaskItem(TaskItem, windowText, _countof(windowText)) > 0) { tbbi.pszText = windowText; }
icon = GetWndIcon(TaskItem->hWnd); if (!icon) icon = static_cast<HICON>(LoadImageW(NULL, MAKEINTRESOURCEW(OIC_SAMPLE), IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE)); TaskItem->IconIndex = ImageList_ReplaceIcon(m_ImageList, TaskItem->IconIndex, icon); tbbi.iImage = TaskItem->IconIndex;
if (!m_TaskBar.SetButtonInfo(TaskItem->Index, &tbbi)) { TaskItem->Index = -1; return -1; }
TRACE("Updated button %d for hwnd 0x%p\n", TaskItem->Index, TaskItem->hWnd); return TaskItem->Index; }
VOID RemoveIcon(IN PTASK_ITEM TaskItem) { TBBUTTONINFO tbbi; PTASK_ITEM currentTaskItem, LastItem;
if (TaskItem->IconIndex == -1) return;
tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_IMAGE;
currentTaskItem = m_TaskItems; LastItem = currentTaskItem + m_TaskItemCount; while (currentTaskItem != LastItem) { if (currentTaskItem->IconIndex > TaskItem->IconIndex) { currentTaskItem->IconIndex--; tbbi.iImage = currentTaskItem->IconIndex;
m_TaskBar.SetButtonInfo(currentTaskItem->Index, &tbbi); } currentTaskItem++; }
ImageList_Remove(m_ImageList, TaskItem->IconIndex); }
PTASK_ITEM FindLastTaskItemOfGroup( IN PTASK_GROUP TaskGroup OPTIONAL, IN PTASK_ITEM NewTaskItem OPTIONAL) { PTASK_ITEM TaskItem, LastTaskItem, FoundTaskItem = NULL; DWORD dwTaskCount;
ASSERT(m_IsGroupingEnabled);
TaskItem = m_TaskItems; LastTaskItem = TaskItem + m_TaskItemCount;
dwTaskCount = (TaskGroup != NULL ? TaskGroup->dwTaskCount : MAX_TASKS_COUNT);
ASSERT(dwTaskCount > 0);
while (TaskItem != LastTaskItem) { if (TaskItem->Group == TaskGroup) { if ((NewTaskItem != NULL && TaskItem != NewTaskItem) || NewTaskItem == NULL) { FoundTaskItem = TaskItem; }
if (--dwTaskCount == 0) { /* We found the last task item in the group! */ break; } }
TaskItem++; }
return FoundTaskItem; }
INT CalculateTaskItemNewButtonIndex(IN PTASK_ITEM TaskItem) { PTASK_GROUP TaskGroup; PTASK_ITEM LastTaskItem;
/* NOTE: This routine assumes that the group is *not* collapsed! */
TaskGroup = TaskItem->Group; if (m_IsGroupingEnabled) { if (TaskGroup != NULL) { ASSERT(TaskGroup->Index < 0); ASSERT(!TaskGroup->IsCollapsed);
if (TaskGroup->dwTaskCount > 1) { LastTaskItem = FindLastTaskItemOfGroup(TaskGroup, TaskItem); if (LastTaskItem != NULL) { /* Since the group is expanded the task items must have an index */ ASSERT(LastTaskItem->Index >= 0);
return LastTaskItem->Index + 1; } } } else { /* Find the last NULL group button. NULL groups are added at the end of the task item list when grouping is enabled */ LastTaskItem = FindLastTaskItemOfGroup(NULL, TaskItem); if (LastTaskItem != NULL) { ASSERT(LastTaskItem->Index >= 0);
return LastTaskItem->Index + 1; } } }
return m_ButtonCount; }
INT AddTaskItemButton(IN OUT PTASK_ITEM TaskItem) { WCHAR windowText[255]; TBBUTTON tbBtn = { 0 }; INT iIndex; HICON icon;
if (TaskItem->Index >= 0) { return UpdateTaskItemButton(TaskItem); }
if (TaskItem->Group != NULL && TaskItem->Group->IsCollapsed) { /* The task group is collapsed, we only need to update the group button */ return UpdateTaskGroupButton(TaskItem->Group); }
icon = GetWndIcon(TaskItem->hWnd); if (!icon) icon = static_cast<HICON>(LoadImageW(NULL, MAKEINTRESOURCEW(OIC_SAMPLE), IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE)); TaskItem->IconIndex = ImageList_ReplaceIcon(m_ImageList, -1, icon);
tbBtn.iBitmap = TaskItem->IconIndex; tbBtn.fsState = TBSTATE_ENABLED | TBSTATE_ELLIPSES; tbBtn.fsStyle = BTNS_CHECK | BTNS_NOPREFIX | BTNS_SHOWTEXT; tbBtn.dwData = TaskItem->Index;
if (GetWndTextFromTaskItem(TaskItem, windowText, _countof(windowText)) > 0) { tbBtn.iString = (DWORD_PTR) windowText; }
/* Find out where to insert the new button */ iIndex = CalculateTaskItemNewButtonIndex(TaskItem); ASSERT(iIndex >= 0); tbBtn.idCommand = iIndex;
m_TaskBar.BeginUpdate();
if (m_TaskBar.InsertButton(iIndex, &tbBtn)) { UpdateIndexesAfter(iIndex, TRUE);
TRACE("Added button %d for hwnd 0x%p\n", iIndex, TaskItem->hWnd);
TaskItem->Index = iIndex; m_ButtonCount++;
/* Update button sizes and fix the button wrapping */ UpdateButtonsSize(TRUE); return iIndex; }
m_TaskBar.EndUpdate();
return -1; }
BOOL DeleteTaskItemButton(IN OUT PTASK_ITEM TaskItem) { PTASK_GROUP TaskGroup; INT iIndex;
TaskGroup = TaskItem->Group;
if (TaskItem->Index >= 0) { if ((TaskGroup != NULL && !TaskGroup->IsCollapsed) || TaskGroup == NULL) { m_TaskBar.BeginUpdate();
RemoveIcon(TaskItem); iIndex = TaskItem->Index; if (m_TaskBar.DeleteButton(iIndex)) { TaskItem->Index = -1; m_ButtonCount--;
UpdateIndexesAfter(iIndex, FALSE);
/* Update button sizes and fix the button wrapping */ UpdateButtonsSize(TRUE); return TRUE; }
m_TaskBar.EndUpdate(); } }
return FALSE; }
PTASK_GROUP AddToTaskGroup(IN HWND hWnd) { DWORD dwProcessId; PTASK_GROUP TaskGroup, *PrevLink;
if (!GetWindowThreadProcessId(hWnd, &dwProcessId)) { TRACE("Cannot get process id of hwnd 0x%p\n", hWnd); return NULL; }
/* Try to find an existing task group */ TaskGroup = m_TaskGroups; PrevLink = &m_TaskGroups; while (TaskGroup != NULL) { if (TaskGroup->dwProcessId == dwProcessId) { TaskGroup->dwTaskCount++; return TaskGroup; }
PrevLink = &TaskGroup->Next; TaskGroup = TaskGroup->Next; }
/* Allocate a new task group */ TaskGroup = (PTASK_GROUP) HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(*TaskGroup)); if (TaskGroup != NULL) { TaskGroup->dwTaskCount = 1; TaskGroup->dwProcessId = dwProcessId; TaskGroup->Index = -1;
/* Add the task group to the list */ *PrevLink = TaskGroup; }
return TaskGroup; }
VOID RemoveTaskFromTaskGroup(IN OUT PTASK_ITEM TaskItem) { PTASK_GROUP TaskGroup, CurrentGroup, *PrevLink;
TaskGroup = TaskItem->Group; if (TaskGroup != NULL) { DWORD dwNewTaskCount = --TaskGroup->dwTaskCount; if (dwNewTaskCount == 0) { /* Find the previous pointer in the chain */ CurrentGroup = m_TaskGroups; PrevLink = &m_TaskGroups; while (CurrentGroup != TaskGroup) { PrevLink = &CurrentGroup->Next; CurrentGroup = CurrentGroup->Next; }
/* Remove the group from the list */ ASSERT(TaskGroup == CurrentGroup); *PrevLink = TaskGroup->Next;
/* Free the task group */ HeapFree(hProcessHeap, 0, TaskGroup); } else if (TaskGroup->IsCollapsed && TaskGroup->Index >= 0) { if (dwNewTaskCount > 1) { /* FIXME: Check if we should expand the group */ /* Update the task group button */ UpdateTaskGroupButton(TaskGroup); } else { /* Expand the group of one task button to a task button */ ExpandTaskGroup(TaskGroup); } } } }
PTASK_ITEM FindTaskItem(IN HWND hWnd) { PTASK_ITEM TaskItem, LastItem;
TaskItem = m_TaskItems; LastItem = TaskItem + m_TaskItemCount; while (TaskItem != LastItem) { if (TaskItem->hWnd == hWnd) return TaskItem;
TaskItem++; }
return NULL; }
PTASK_ITEM FindOtherTaskItem(IN HWND hWnd) { PTASK_ITEM LastItem, TaskItem; PTASK_GROUP TaskGroup; DWORD dwProcessId;
if (!GetWindowThreadProcessId(hWnd, &dwProcessId)) { return NULL; }
/* Try to find another task that belongs to the same process as the given window */ TaskItem = m_TaskItems; LastItem = TaskItem + m_TaskItemCount; while (TaskItem != LastItem) { TaskGroup = TaskItem->Group; if (TaskGroup != NULL) { if (TaskGroup->dwProcessId == dwProcessId) return TaskItem; } else { DWORD dwProcessIdTask;
if (GetWindowThreadProcessId(TaskItem->hWnd, &dwProcessIdTask) && dwProcessIdTask == dwProcessId) { return TaskItem; } }
TaskItem++; }
return NULL; }
PTASK_ITEM AllocTaskItem() { if (m_TaskItemCount >= MAX_TASKS_COUNT) { /* We need the most significant bit in 16 bit command IDs to indicate whether it is a task group or task item. WM_COMMAND limits command IDs to 16 bits! */ return NULL; }
ASSERT(m_AllocatedTaskItems >= m_TaskItemCount);
if (m_TaskItemCount == 0) { m_TaskItems = (PTASK_ITEM) HeapAlloc(hProcessHeap, 0, TASK_ITEM_ARRAY_ALLOC * sizeof(*m_TaskItems)); if (m_TaskItems != NULL) { m_AllocatedTaskItems = TASK_ITEM_ARRAY_ALLOC; } else return NULL; } else if (m_TaskItemCount >= m_AllocatedTaskItems) { PTASK_ITEM NewArray; SIZE_T NewArrayLength, ActiveTaskItemIndex;
NewArrayLength = m_AllocatedTaskItems + TASK_ITEM_ARRAY_ALLOC;
NewArray = (PTASK_ITEM) HeapReAlloc(hProcessHeap, 0, m_TaskItems, NewArrayLength * sizeof(*m_TaskItems)); if (NewArray != NULL) { if (m_ActiveTaskItem != NULL) { /* Fixup the ActiveTaskItem pointer */ ActiveTaskItemIndex = m_ActiveTaskItem - m_TaskItems; m_ActiveTaskItem = NewArray + ActiveTaskItemIndex; } m_AllocatedTaskItems = (WORD) NewArrayLength; m_TaskItems = NewArray; } else return NULL; }
return m_TaskItems + m_TaskItemCount++; }
VOID FreeTaskItem(IN OUT PTASK_ITEM TaskItem) { WORD wIndex;
if (TaskItem == m_ActiveTaskItem) m_ActiveTaskItem = NULL;
wIndex = (WORD) (TaskItem - m_TaskItems); if (wIndex + 1 < m_TaskItemCount) { MoveMemory(TaskItem, TaskItem + 1, (m_TaskItemCount - wIndex - 1) * sizeof(*TaskItem)); }
m_TaskItemCount--; }
VOID DeleteTaskItem(IN OUT PTASK_ITEM TaskItem) { if (!m_IsDestroying) { /* Delete the task button from the toolbar */ DeleteTaskItemButton(TaskItem); }
/* Remove the task from it's group */ RemoveTaskFromTaskGroup(TaskItem);
/* Free the task item */ FreeTaskItem(TaskItem); }
VOID CheckActivateTaskItem(IN OUT PTASK_ITEM TaskItem) { PTASK_ITEM CurrentTaskItem; PTASK_GROUP TaskGroup = NULL;
CurrentTaskItem = m_ActiveTaskItem;
if (TaskItem != NULL) TaskGroup = TaskItem->Group;
if (m_IsGroupingEnabled && TaskGroup != NULL && TaskGroup->IsCollapsed) { /* FIXME */ return; }
if (CurrentTaskItem != NULL) { PTASK_GROUP CurrentTaskGroup;
if (CurrentTaskItem == TaskItem) return;
CurrentTaskGroup = CurrentTaskItem->Group;
if (m_IsGroupingEnabled && CurrentTaskGroup != NULL && CurrentTaskGroup->IsCollapsed) { if (CurrentTaskGroup == TaskGroup) return;
/* FIXME */ } else { m_ActiveTaskItem = NULL; if (CurrentTaskItem->Index >= 0) { UpdateTaskItemButton(CurrentTaskItem); } } }
m_ActiveTaskItem = TaskItem;
if (TaskItem != NULL && TaskItem->Index >= 0) { UpdateTaskItemButton(TaskItem); } else if (TaskItem == NULL) { TRACE("Active TaskItem now NULL\n"); } }
PTASK_ITEM FindTaskItemByIndex(IN INT Index) { PTASK_ITEM TaskItem, LastItem;
TaskItem = m_TaskItems; LastItem = TaskItem + m_TaskItemCount; while (TaskItem != LastItem) { if (TaskItem->Index == Index) return TaskItem;
TaskItem++; }
return NULL; }
PTASK_GROUP FindTaskGroupByIndex(IN INT Index) { PTASK_GROUP CurrentGroup;
CurrentGroup = m_TaskGroups; while (CurrentGroup != NULL) { if (CurrentGroup->Index == Index) break;
CurrentGroup = CurrentGroup->Next; }
return CurrentGroup; }
BOOL AddTask(IN HWND hWnd) { PTASK_ITEM TaskItem;
if (!::IsWindow(hWnd) || m_Tray->IsSpecialHWND(hWnd)) return FALSE;
TaskItem = FindTaskItem(hWnd); if (TaskItem == NULL) { TRACE("Add window 0x%p\n", hWnd); TaskItem = AllocTaskItem(); if (TaskItem != NULL) { ZeroMemory(TaskItem, sizeof(*TaskItem)); TaskItem->hWnd = hWnd; TaskItem->Index = -1; TaskItem->Group = AddToTaskGroup(hWnd);
if (!m_IsDestroying) { AddTaskItemButton(TaskItem); } } }
return TaskItem != NULL; }
BOOL ActivateTaskItem(IN OUT PTASK_ITEM TaskItem OPTIONAL) { if (TaskItem != NULL) { TRACE("Activate window 0x%p on button %d\n", TaskItem->hWnd, TaskItem->Index); }
CheckActivateTaskItem(TaskItem); return FALSE; }
BOOL ActivateTask(IN HWND hWnd) { PTASK_ITEM TaskItem;
if (!hWnd) { return ActivateTaskItem(NULL); }
TaskItem = FindTaskItem(hWnd); if (TaskItem == NULL) { TaskItem = FindOtherTaskItem(hWnd); }
if (TaskItem == NULL) { WARN("Activate window 0x%p, could not find task\n", hWnd); RefreshWindowList(); }
return ActivateTaskItem(TaskItem); }
BOOL DeleteTask(IN HWND hWnd) { PTASK_ITEM TaskItem;
TaskItem = FindTaskItem(hWnd); if (TaskItem != NULL) { TRACE("Delete window 0x%p on button %d\n", hWnd, TaskItem->Index); DeleteTaskItem(TaskItem); return TRUE; } //else //TRACE("Failed to delete window 0x%p\n", hWnd);
return FALSE; }
VOID DeleteAllTasks() { PTASK_ITEM CurrentTask;
if (m_TaskItemCount > 0) { CurrentTask = m_TaskItems + m_TaskItemCount; do { DeleteTaskItem(--CurrentTask); } while (CurrentTask != m_TaskItems); } }
VOID FlashTaskItem(IN OUT PTASK_ITEM TaskItem) { TaskItem->RenderFlashed = 1; UpdateTaskItemButton(TaskItem); }
BOOL FlashTask(IN HWND hWnd) { PTASK_ITEM TaskItem;
TaskItem = FindTaskItem(hWnd); if (TaskItem != NULL) { TRACE("Flashing window 0x%p on button %d\n", hWnd, TaskItem->Index); FlashTaskItem(TaskItem); return TRUE; }
return FALSE; }
VOID RedrawTaskItem(IN OUT PTASK_ITEM TaskItem) { PTASK_GROUP TaskGroup;
TaskGroup = TaskItem->Group; if (m_IsGroupingEnabled && TaskGroup != NULL) { if (TaskGroup->IsCollapsed && TaskGroup->Index >= 0) { UpdateTaskGroupButton(TaskGroup); } else if (TaskItem->Index >= 0) { goto UpdateTaskItem; } } else if (TaskItem->Index >= 0) { UpdateTaskItem: TaskItem->RenderFlashed = 0; UpdateTaskItemButton(TaskItem); } }
BOOL RedrawTask(IN HWND hWnd) { PTASK_ITEM TaskItem;
TaskItem = FindTaskItem(hWnd); if (TaskItem != NULL) { RedrawTaskItem(TaskItem); return TRUE; }
return FALSE; }
VOID UpdateButtonsSize(IN BOOL bRedrawDisabled) { RECT rcClient; UINT uiRows, uiMax, uiMin, uiBtnsPerLine, ui; LONG NewBtnSize; BOOL Horizontal;
/* Update the size of the image list if needed */ int cx, cy; ImageList_GetIconSize(m_ImageList, &cx, &cy); if (cx != GetSystemMetrics(g_TaskbarSettings.bSmallIcons ? SM_CXSMICON : SM_CXICON) || cy != GetSystemMetrics(g_TaskbarSettings.bSmallIcons ? SM_CYSMICON : SM_CYICON)) { ImageList_SetIconSize(m_ImageList, GetSystemMetrics(g_TaskbarSettings.bSmallIcons ? SM_CXSMICON : SM_CXICON), GetSystemMetrics(g_TaskbarSettings.bSmallIcons ? SM_CYSMICON : SM_CYICON));
/* SetIconSize removes all icons so we have to reinsert them */ PTASK_ITEM TaskItem = m_TaskItems; PTASK_ITEM LastTaskItem = m_TaskItems + m_TaskItemCount; while (TaskItem != LastTaskItem) { TaskItem->IconIndex = -1; UpdateTaskItemButton(TaskItem);
TaskItem++; } m_TaskBar.SetImageList(m_ImageList); }
if (GetClientRect(&rcClient) && !IsRectEmpty(&rcClient)) { if (m_ButtonCount > 0) { Horizontal = m_Tray->IsHorizontal();
if (Horizontal) { TBMETRICS tbm = { 0 }; tbm.cbSize = sizeof(tbm); tbm.dwMask = TBMF_BUTTONSPACING; m_TaskBar.GetMetrics(&tbm);
if (m_ButtonSize.cy + tbm.cyButtonSpacing != 0) uiRows = (rcClient.bottom + tbm.cyButtonSpacing) / (m_ButtonSize.cy + tbm.cyButtonSpacing); else uiRows = 1;
if (uiRows == 0) uiRows = 1;
uiBtnsPerLine = (m_ButtonCount + uiRows - 1) / uiRows; } else { uiBtnsPerLine = 1; uiRows = m_ButtonCount; }
if (!bRedrawDisabled) m_TaskBar.BeginUpdate();
/* We might need to update the button spacing */ int cxButtonSpacing = m_TaskBar.UpdateTbButtonSpacing( Horizontal, m_Theme != NULL, uiRows, uiBtnsPerLine);
/* Determine the minimum and maximum width of a button */ uiMin = GetSystemMetrics(SM_CXSIZE) + (2 * GetSystemMetrics(SM_CXEDGE)); if (Horizontal) { uiMax = GetSystemMetrics(SM_CXMINIMIZED);
/* Calculate the ideal width and make sure it's within the allowed range */ NewBtnSize = (rcClient.right - (uiBtnsPerLine * cxButtonSpacing)) / uiBtnsPerLine;
if (NewBtnSize < (LONG) uiMin) NewBtnSize = uiMin; if (NewBtnSize >(LONG)uiMax) NewBtnSize = uiMax;
/* Recalculate how many buttons actually fit into one line */ uiBtnsPerLine = rcClient.right / (NewBtnSize + cxButtonSpacing); if (uiBtnsPerLine == 0) uiBtnsPerLine++; } else { NewBtnSize = uiMax = rcClient.right; }
m_ButtonSize.cx = NewBtnSize;
m_ButtonsPerLine = uiBtnsPerLine;
for (ui = 0; ui != m_ButtonCount; ui++) { TBBUTTONINFOW tbbi = { 0 }; tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_BYINDEX | TBIF_SIZE | TBIF_STATE; tbbi.cx = (INT) NewBtnSize; tbbi.fsState = TBSTATE_ENABLED;
/* Check if we're updating a button that is the last one in the line. If so, we need to set the TBSTATE_WRAP flag! */ if (Horizontal) { if ((ui + 1) % uiBtnsPerLine == 0) tbbi.fsState |= TBSTATE_WRAP; } else { tbbi.fsState |= TBSTATE_WRAP; }
if (m_ActiveTaskItem != NULL && m_ActiveTaskItem->Index == (INT)ui) { tbbi.fsState |= TBSTATE_CHECKED; }
m_TaskBar.SetButtonInfo(ui, &tbbi); } } else { m_ButtonsPerLine = 0; m_ButtonSize.cx = 0; } }
// FIXME: This seems to be enabling redraws prematurely, but moving it to its right place doesn't work! m_TaskBar.EndUpdate(); }
BOOL CALLBACK EnumWindowsProc(IN HWND hWnd) { if (m_Tray->IsTaskWnd(hWnd)) { TRACE("Adding task for %p...\n", hWnd); AddTask(hWnd); } return TRUE; }
static BOOL CALLBACK s_EnumWindowsProc(IN HWND hWnd, IN LPARAM lParam) { CTaskSwitchWnd * This = (CTaskSwitchWnd *) lParam;
return This->EnumWindowsProc(hWnd); }
BOOL RefreshWindowList() { TRACE("Refreshing window list...\n"); /* Add all windows to the toolbar */ return EnumWindows(s_EnumWindowsProc, (LPARAM)this); }
LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { TRACE("OmThemeChanged\n");
if (m_Theme) CloseThemeData(m_Theme);
if (IsThemeActive()) m_Theme = OpenThemeData(m_hWnd, L"TaskBand"); else m_Theme = NULL;
return TRUE; }
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (!m_TaskBar.Initialize(m_hWnd)) return FALSE;
SetWindowTheme(m_TaskBar.m_hWnd, L"TaskBand", NULL);
m_ImageList = ImageList_Create(GetSystemMetrics(g_TaskbarSettings.bSmallIcons ? SM_CXSMICON : SM_CXICON), GetSystemMetrics(g_TaskbarSettings.bSmallIcons ? SM_CYSMICON : SM_CYICON), ILC_COLOR32 | ILC_MASK, 0, 1000); m_TaskBar.SetImageList(m_ImageList);
/* Set proper spacing between buttons */ m_TaskBar.UpdateTbButtonSpacing(m_Tray->IsHorizontal(), m_Theme != NULL);
/* Register the shell hook */ m_ShellHookMsg = RegisterWindowMessageW(L"SHELLHOOK");
TRACE("ShellHookMsg got assigned number %d\n", m_ShellHookMsg);
RegisterShellHook(m_hWnd, 3); /* 1 if no NT! We're targeting NT so we don't care! */
RefreshWindowList();
/* Recalculate the button size */ UpdateButtonsSize(FALSE);
#if DUMP_TASKS != 0 SetTimer(hwnd, 1, 5000, NULL);#endif return TRUE; }
LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { m_IsDestroying = TRUE;
KillTimer(TIMER_ID_VALIDATE_RUDE_APP);
/* Unregister the shell hook */ RegisterShellHook(m_hWnd, FALSE);
CloseThemeData(m_Theme); DeleteAllTasks();
if (m_ImageList) { ImageList_Destroy(m_ImageList); m_ImageList = NULL; }
return TRUE; }
static BOOL InvokeRegistryAppKeyCommand(UINT uAppCmd) { BOOL bResult = FALSE; WCHAR szBuf[MAX_PATH * 2]; wsprintfW(szBuf, L"%s\\AppKey\\%u", REGSTR_PATH_EXPLORER, uAppCmd); HUSKEY hKey; if (SHRegOpenUSKeyW(szBuf, KEY_READ, NULL, &hKey, FALSE) != ERROR_SUCCESS) return bResult;
DWORD cb = sizeof(szBuf); if (!bResult && SHRegQueryUSValueW(hKey, L"ShellExecute", NULL, szBuf, &cb, FALSE, NULL, 0) == ERROR_SUCCESS) { bResult = TRUE; } cb = sizeof(szBuf); if (!bResult && SHRegQueryUSValueW(hKey, L"Association", NULL, szBuf, &cb, FALSE, NULL, 0) == ERROR_SUCCESS) { bResult = TRUE; cb = _countof(szBuf); if (AssocQueryString(ASSOCF_NOTRUNCATE, ASSOCSTR_EXECUTABLE, szBuf, NULL, szBuf, &cb) != S_OK) *szBuf = UNICODE_NULL; } cb = sizeof(szBuf); if (!bResult && SHRegQueryUSValueW(hKey, L"RegisteredApp", NULL, szBuf, &cb, FALSE, NULL, 0) == ERROR_SUCCESS) { bResult = TRUE; SHRunIndirectRegClientCommand(NULL, szBuf); *szBuf = UNICODE_NULL; // Don't execute again } SHRegCloseUSKey(hKey);
// Note: Tweak UI uses an empty string for its "Do nothing" option. if (bResult && *szBuf) ShellExec_RunDLLW(NULL, NULL, szBuf, SW_SHOW); return bResult; }
BOOL HandleAppCommand(IN WPARAM wParam, IN LPARAM lParam) { const UINT uAppCmd = GET_APPCOMMAND_LPARAM(lParam); if (InvokeRegistryAppKeyCommand(uAppCmd)) return TRUE; switch (uAppCmd) { case APPCOMMAND_VOLUME_MUTE: case APPCOMMAND_VOLUME_DOWN: case APPCOMMAND_VOLUME_UP: // TODO: Try IMMDeviceEnumerator::GetDefaultAudioEndpoint first and then fall back to mixer. FIXME("Call the mixer API to change the global volume\n"); return TRUE; case APPCOMMAND_BROWSER_SEARCH: return SHFindFiles(NULL, NULL); } return FALSE; }
LRESULT OnShellHook(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { BOOL Ret = FALSE;
/* In case the shell hook wasn't registered properly, ignore WM_NULLs*/ if (uMsg == 0) { bHandled = FALSE; return 0; }
TRACE("Received shell hook message: wParam=%08lx, lParam=%08lx\n", wParam, lParam);
switch ((INT) wParam) { case HSHELL_APPCOMMAND: Ret = HandleAppCommand(0, lParam); break;
case HSHELL_WINDOWCREATED: AddTask((HWND) lParam); break;
case HSHELL_WINDOWDESTROYED: /* The window still exists! Delay destroying it a bit */ OnWindowDestroyed((HWND)lParam); DeleteTask((HWND)lParam); break;
case HSHELL_RUDEAPPACTIVATED: case HSHELL_WINDOWACTIVATED: OnWindowActivated((HWND)lParam); ActivateTask((HWND)lParam); break;
case HSHELL_FLASH: FlashTask((HWND) lParam); break;
case HSHELL_REDRAW: RedrawTask((HWND) lParam); break;
case HSHELL_TASKMAN: ::PostMessage(m_Tray->GetHWND(), TWM_OPENSTARTMENU, 0, 0); break;
case HSHELL_ACTIVATESHELLWINDOW: ::SwitchToThisWindow(m_Tray->GetHWND(), TRUE); ::SetForegroundWindow(m_Tray->GetHWND()); break;
case HSHELL_LANGUAGE: case HSHELL_SYSMENU: case HSHELL_ENDTASK: case HSHELL_ACCESSIBILITYSTATE: case HSHELL_WINDOWREPLACED: case HSHELL_WINDOWREPLACING:
case HSHELL_GETMINRECT: default: {#if DEBUG_SHELL_HOOK int i, found; for (i = 0, found = 0; i != _countof(hshell_msg); i++) { if (hshell_msg[i].msg == (INT) wParam) { TRACE("Shell message %ws unhandled (lParam = 0x%p)!\n", hshell_msg[i].msg_name, lParam); found = 1; break; } } if (found) break;#endif TRACE("Shell message %d unhandled (lParam = 0x%p)!\n", (INT) wParam, lParam); break; } }
return Ret; }
VOID HandleTaskItemClick(IN OUT PTASK_ITEM TaskItem) { BOOL bIsMinimized; BOOL bIsActive;
if (::IsWindow(TaskItem->hWnd)) { bIsMinimized = ::IsIconic(TaskItem->hWnd); bIsActive = (TaskItem == m_ActiveTaskItem);
TRACE("Active TaskItem %p, selected TaskItem %p\n", m_ActiveTaskItem, TaskItem); if (m_ActiveTaskItem) TRACE("Active TaskItem hWnd=%p, TaskItem hWnd %p\n", m_ActiveTaskItem->hWnd, TaskItem->hWnd);
TRACE("Valid button clicked. HWND=%p, IsMinimized=%s, IsActive=%s...\n", TaskItem->hWnd, bIsMinimized ? "Yes" : "No", bIsActive ? "Yes" : "No");
if (!bIsMinimized && bIsActive) { if (!::IsHungAppWindow(TaskItem->hWnd)) ::ShowWindowAsync(TaskItem->hWnd, SW_MINIMIZE); TRACE("Valid button clicked. App window Minimized.\n"); } else { ::SwitchToThisWindow(TaskItem->hWnd, TRUE);
TRACE("Valid button clicked. App window Restored.\n"); } } }
VOID HandleTaskGroupClick(IN OUT PTASK_GROUP TaskGroup) { /* TODO: Show task group menu */ }
BOOL HandleButtonClick(IN WORD wIndex) { PTASK_ITEM TaskItem; PTASK_GROUP TaskGroup;
if (m_IsGroupingEnabled) { TaskGroup = FindTaskGroupByIndex((INT) wIndex); if (TaskGroup != NULL && TaskGroup->IsCollapsed) { HandleTaskGroupClick(TaskGroup); return TRUE; } }
TaskItem = FindTaskItemByIndex((INT) wIndex); if (TaskItem != NULL) { HandleTaskItemClick(TaskItem); return TRUE; }
return FALSE; }
static VOID CALLBACK SendAsyncProc(HWND hwnd, UINT uMsg, DWORD_PTR dwData, LRESULT lResult) { ::PostMessageW(hwnd, WM_NULL, 0, 0); }
VOID HandleTaskItemRightClick(IN OUT PTASK_ITEM TaskItem) { POINT pt; GetCursorPos(&pt);
SetForegroundWindow(TaskItem->hWnd);
ActivateTask(TaskItem->hWnd);
if (GetForegroundWindow() != TaskItem->hWnd) ERR("HandleTaskItemRightClick detected the window did not become foreground\n");
::SendMessageCallbackW(TaskItem->hWnd, WM_POPUPSYSTEMMENU, 0, MAKELPARAM(pt.x, pt.y), SendAsyncProc, (ULONG_PTR)TaskItem); }
VOID HandleTaskGroupRightClick(IN OUT PTASK_GROUP TaskGroup) { /* TODO: Show task group right click menu */ }
BOOL HandleButtonRightClick(IN WORD wIndex) { PTASK_ITEM TaskItem; PTASK_GROUP TaskGroup; if (m_IsGroupingEnabled) { TaskGroup = FindTaskGroupByIndex((INT) wIndex); if (TaskGroup != NULL && TaskGroup->IsCollapsed) { HandleTaskGroupRightClick(TaskGroup); return TRUE; } }
TaskItem = FindTaskItemByIndex((INT) wIndex);
if (TaskItem != NULL) { HandleTaskItemRightClick(TaskItem); return TRUE; }
return FALSE; }
LRESULT HandleItemPaint(IN OUT NMTBCUSTOMDRAW *nmtbcd) { LRESULT Ret = CDRF_DODEFAULT; PTASK_GROUP TaskGroup; PTASK_ITEM TaskItem;
TaskItem = FindTaskItemByIndex((INT) nmtbcd->nmcd.dwItemSpec); TaskGroup = FindTaskGroupByIndex((INT) nmtbcd->nmcd.dwItemSpec); if (TaskGroup == NULL && TaskItem != NULL) { ASSERT(TaskItem != NULL);
if (TaskItem != NULL && ::IsWindow(TaskItem->hWnd)) { /* Make the entire button flashing if necessary */ if (nmtbcd->nmcd.uItemState & CDIS_MARKED) { Ret = TBCDRF_NOBACKGROUND; if (!m_Theme) { SelectObject(nmtbcd->nmcd.hdc, GetSysColorBrush(COLOR_HIGHLIGHT)); Rectangle(nmtbcd->nmcd.hdc, nmtbcd->nmcd.rc.left, nmtbcd->nmcd.rc.top, nmtbcd->nmcd.rc.right, nmtbcd->nmcd.rc.bottom); } else { DrawThemeBackground(m_Theme, nmtbcd->nmcd.hdc, TDP_FLASHBUTTON, 0, &nmtbcd->nmcd.rc, 0); } nmtbcd->clrText = GetSysColor(COLOR_HIGHLIGHTTEXT); return Ret; } } } else if (TaskGroup != NULL) { /* FIXME: Implement painting for task groups */ } return Ret; }
LRESULT HandleToolbarNotification(IN const NMHDR *nmh) { LRESULT Ret = 0;
switch (nmh->code) { case NM_CUSTOMDRAW: { LPNMTBCUSTOMDRAW nmtbcd = (LPNMTBCUSTOMDRAW) nmh;
switch (nmtbcd->nmcd.dwDrawStage) {
case CDDS_ITEMPREPAINT: Ret = HandleItemPaint(nmtbcd); break;
case CDDS_PREPAINT: Ret = CDRF_NOTIFYITEMDRAW; break;
default: Ret = CDRF_DODEFAULT; break; } break; } }
return Ret; }
// Internal structure for IsRudeEnumProc typedef struct tagRUDEAPPDATA { HMONITOR hTargetMonitor; HWND hwndFound; HWND hwndFirstCheck; } RUDEAPPDATA, *PRUDEAPPDATA;
// Find any rude app static BOOL CALLBACK IsRudeEnumProc(_In_ HWND hwnd, _In_ LPARAM lParam) { PRUDEAPPDATA pData = (PRUDEAPPDATA)lParam;
HMONITOR hMon = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); if (!hMon || (pData->hTargetMonitor && pData->hTargetMonitor != hMon) || !SHELL_IsRudeWindow(hMon, hwnd, (hwnd == pData->hwndFirstCheck))) { return TRUE; // Continue }
pData->hwndFound = hwnd; return FALSE; // Finish }
// Internal structure for FullScreenEnumProc typedef struct tagFULLSCREENDATA { const RECT *pRect; HMONITOR hTargetMonitor; ITrayWindow *pTray; } FULLSCREENDATA, *PFULLSCREENDATA;
// Notify ABN_FULLSCREENAPP for each monitor static BOOL CALLBACK FullScreenEnumProc(_In_ HMONITOR hMonitor, _In_opt_ HDC hDC, _In_ LPRECT prc, _In_ LPARAM lParam) { PFULLSCREENDATA pData = (PFULLSCREENDATA)lParam;
BOOL bFullOpening = (pData->hTargetMonitor == hMonitor); if (!bFullOpening && pData->pRect) { RECT rc, rcMon; SHELL_GetMonitorRect(hMonitor, &rcMon, FALSE); ::IntersectRect(&rc, &rcMon, pData->pRect); bFullOpening = ::EqualRect(&rc, &rcMon); }
// Notify ABN_FULLSCREENAPP to appbars pData->pTray->NotifyFullScreenToAppBars(hMonitor, bFullOpening); return TRUE; }
void HandleFullScreenApp(_In_opt_ HWND hwndRude) { // Notify ABN_FULLSCREENAPP for every monitor RECT rc; FULLSCREENDATA Data = { NULL, NULL, NULL }; if (hwndRude && ::GetWindowRect(hwndRude, &rc)) { Data.pRect = &rc; Data.hTargetMonitor = ::MonitorFromWindow(hwndRude, MONITOR_DEFAULTTONULL); } Data.pTray = m_Tray; ::EnumDisplayMonitors(NULL, NULL, FullScreenEnumProc, (LPARAM)&Data);
if (hwndRude) { // Make the taskbar bottom UINT uFlags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER; HWND hwndTray = m_Tray->GetHWND(); ::SetWindowPos(hwndTray, HWND_BOTTOM, 0, 0, 0, 0, uFlags);
// Switch to the rude app if necessary DWORD exstyle = (DWORD)::GetWindowLongPtrW(hwndRude, GWL_EXSTYLE); if (!(exstyle & WS_EX_TOPMOST) && !SHELL_IsRudeWindowActive(hwndRude)) ::SwitchToThisWindow(hwndRude, TRUE); } }
HWND FindRudeApp(_In_opt_ HWND hwndFirstCheck) { // Quick check HMONITOR hMon = MonitorFromWindow(hwndFirstCheck, MONITOR_DEFAULTTONEAREST); RUDEAPPDATA data = { hMon, NULL, hwndFirstCheck }; if (::IsWindow(hwndFirstCheck) && !IsRudeEnumProc(hwndFirstCheck, (LPARAM)&data)) return hwndFirstCheck;
// Slow check ::EnumWindows(IsRudeEnumProc, (LPARAM)&data);
return data.hwndFound; }
// WM_WINDOWPOSCHANGED LRESULT OnWindowPosChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { // Re-start rude app validation KillTimer(TIMER_ID_VALIDATE_RUDE_APP); SetTimer(TIMER_ID_VALIDATE_RUDE_APP, VALIDATE_RUDE_INTERVAL, NULL); m_nRudeAppValidationCounter = 0; bHandled = FALSE; return 0; }
// HSHELL_WINDOWACTIVATED, HSHELL_RUDEAPPACTIVATED void OnWindowActivated(_In_ HWND hwndTarget) { // Re-start rude app validation KillTimer(TIMER_ID_VALIDATE_RUDE_APP); SetTimer(TIMER_ID_VALIDATE_RUDE_APP, VALIDATE_RUDE_INTERVAL, NULL); m_nRudeAppValidationCounter = 0; }
// HSHELL_WINDOWDESTROYED void OnWindowDestroyed(_In_ HWND hwndTarget) { if (!FindTaskItem(hwndTarget)) return; HWND hwndRude = FindRudeApp(hwndTarget); HandleFullScreenApp(hwndRude); }
LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { HDC hdc = (HDC) wParam;
if (!IsAppThemed()) { bHandled = FALSE; return 0; }
RECT rect; GetClientRect(&rect); DrawThemeParentBackground(m_hWnd, hdc, &rect);
return TRUE; }
LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { SIZE szClient;
szClient.cx = LOWORD(lParam); szClient.cy = HIWORD(lParam); if (m_TaskBar.m_hWnd != NULL) { m_TaskBar.SetWindowPos(NULL, 0, 0, szClient.cx, szClient.cy, SWP_NOZORDER);
UpdateButtonsSize(FALSE); } return TRUE; }
LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { LRESULT Ret = TRUE; /* We want the tray window to be draggable everywhere, so make the control appear transparent */ Ret = DefWindowProc(uMsg, wParam, lParam); if (Ret != HTVSCROLL && Ret != HTHSCROLL) Ret = HTTRANSPARENT; return Ret; }
LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { LRESULT Ret = TRUE; if (lParam != 0 && (HWND) lParam == m_TaskBar.m_hWnd) { HandleButtonClick(LOWORD(wParam)); } return Ret; }
LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { LRESULT Ret = TRUE; const NMHDR *nmh = (const NMHDR *) lParam;
if (nmh->hwndFrom == m_TaskBar.m_hWnd) { Ret = HandleToolbarNotification(nmh); } return Ret; }
LRESULT OnUpdateTaskbarPos(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { /* Update the button spacing */ m_TaskBar.UpdateTbButtonSpacing(m_Tray->IsHorizontal(), m_Theme != NULL); return TRUE; }
LRESULT OnTaskbarSettingsChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { BOOL bSettingsChanged = FALSE; TaskbarSettings* newSettings = (TaskbarSettings*)lParam;
if (newSettings->bGroupButtons != g_TaskbarSettings.bGroupButtons) { bSettingsChanged = TRUE; g_TaskbarSettings.bGroupButtons = newSettings->bGroupButtons; m_IsGroupingEnabled = g_TaskbarSettings.bGroupButtons; }
if (newSettings->bSmallIcons != g_TaskbarSettings.bSmallIcons) { bSettingsChanged = TRUE; g_TaskbarSettings.bSmallIcons = newSettings->bSmallIcons; }
if (bSettingsChanged) { /* Refresh each task item view */ RefreshWindowList(); UpdateButtonsSize(FALSE); }
return 0; }
LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { LRESULT Ret = 0; INT_PTR iBtn = -1;
if (m_TaskBar.m_hWnd != NULL) { POINT pt;
pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam);
::ScreenToClient(m_TaskBar.m_hWnd, &pt);
iBtn = m_TaskBar.HitTest(&pt); if (iBtn >= 0) { HandleButtonRightClick(iBtn); } } if (iBtn < 0) { /* Not on a taskbar button, so forward message to tray */ Ret = SendMessage(m_Tray->GetHWND(), uMsg, wParam, lParam); } return Ret; }
LRESULT OnKludgeItemRect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { PTASK_ITEM TaskItem = FindTaskItem((HWND) wParam); if (TaskItem) { RECT* prcMinRect = (RECT*) lParam; RECT rcItem, rcToolbar; m_TaskBar.GetItemRect(TaskItem->Index, &rcItem); m_TaskBar.GetWindowRect(&rcToolbar);
OffsetRect(&rcItem, rcToolbar.left, rcToolbar.top);
*prcMinRect = rcItem; return TRUE; } return FALSE; }
LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return MA_NOACTIVATE; }
LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { switch (wParam) {#if DUMP_TASKS != 0 case 1: DumpTasks(); break;#endif case TIMER_ID_VALIDATE_RUDE_APP: { // Real activation of rude app might take some time after HSHELL_...ACTIVATED. // Wait up to 5 seconds with validating the rude app at each second. HWND hwndRude = FindRudeApp(NULL); HandleFullScreenApp(hwndRude);
KillTimer(wParam); ++m_nRudeAppValidationCounter; if (m_nRudeAppValidationCounter < VALIDATE_RUDE_MAX_COUNT && !hwndRude) SetTimer(wParam, VALIDATE_RUDE_INTERVAL, NULL); break; } default: { WARN("Unknown timer ID: %p\n", wParam); break; } } return TRUE; }
LRESULT OnSetFont(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return m_TaskBar.SendMessageW(uMsg, wParam, lParam); }
LRESULT OnSettingChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (wParam == SPI_SETNONCLIENTMETRICS) { /* Don't update the font, this will be done when we get a WM_SETFONT from our parent */ UpdateButtonsSize(FALSE); }
return 0; }
LRESULT OnCopyData(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { PCOPYDATASTRUCT cpData = (PCOPYDATASTRUCT)lParam; if (cpData->dwData == m_uHardErrorMsg) { /* A hard error balloon message */ PBALLOON_HARD_ERROR_DATA pData = (PBALLOON_HARD_ERROR_DATA)cpData->lpData; ERR("Got balloon data 0x%x, 0x%x, '%S', '%S'\n", pData->Status, pData->dwType, (WCHAR*)((ULONG_PTR)pData + pData->TitleOffset), (WCHAR*)((ULONG_PTR)pData + pData->MessageOffset)); if (pData->cbHeaderSize == sizeof(BALLOON_HARD_ERROR_DATA)) m_HardErrorThread.StartThread(pData); return TRUE; }
return FALSE; }
HRESULT Initialize(IN HWND hWndParent, IN OUT ITrayWindow *tray) { m_Tray = tray; m_IsGroupingEnabled = g_TaskbarSettings.bGroupButtons; Create(hWndParent, 0, szRunningApps, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP); if (!m_hWnd) return E_FAIL; return S_OK; }
// *** IOleWindow methods ***
STDMETHODIMP GetWindow(HWND* phwnd) override { if (!phwnd) return E_INVALIDARG; *phwnd = m_hWnd; return S_OK; }
STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode) override { return E_NOTIMPL; }
DECLARE_WND_CLASS_EX(szTaskSwitchWndClass, CS_DBLCLKS, COLOR_3DFACE)
BEGIN_MSG_MAP(CTaskSwitchWnd) MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest) MESSAGE_HANDLER(WM_COMMAND, OnCommand) MESSAGE_HANDLER(WM_NOTIFY, OnNotify) MESSAGE_HANDLER(TSWM_UPDATETASKBARPOS, OnUpdateTaskbarPos) MESSAGE_HANDLER(TWM_SETTINGSCHANGED, OnTaskbarSettingsChanged) MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu) MESSAGE_HANDLER(WM_TIMER, OnTimer) MESSAGE_HANDLER(WM_SETFONT, OnSetFont) MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChanged) MESSAGE_HANDLER(m_ShellHookMsg, OnShellHook) MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate) MESSAGE_HANDLER(WM_KLUDGEMINRECT, OnKludgeItemRect) MESSAGE_HANDLER(WM_COPYDATA, OnCopyData) MESSAGE_HANDLER(WM_WINDOWPOSCHANGED, OnWindowPosChanged) END_MSG_MAP()
DECLARE_NOT_AGGREGATABLE(CTaskSwitchWnd)
DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(CTaskSwitchWnd) COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow) END_COM_MAP()};
HRESULT CTaskSwitchWnd_CreateInstance(IN HWND hWndParent, IN OUT ITrayWindow *Tray, REFIID riid, void **ppv){ return ShellObjectCreatorInit<CTaskSwitchWnd>(hWndParent, Tray, riid, ppv);}