802 lines
24 KiB
C++
802 lines
24 KiB
C++
#include "stdafx.h"
|
|
#include "sfthost.h"
|
|
#include "uxtheme.h"
|
|
#include "uxthemep.h"
|
|
#include "rcids.h"
|
|
|
|
// WARNING! Must be in sync with c_rgidmLegacy
|
|
|
|
#define NUM_TBBUTTON_IMAGES 3
|
|
static const TBBUTTON tbButtonsCreate [] =
|
|
{
|
|
{0, SMNLC_EJECT, TBSTATE_ENABLED, BTNS_SHOWTEXT|BTNS_AUTOSIZE, {0,0}, IDS_LOGOFF_TIP_EJECT, 0},
|
|
{1, SMNLC_LOGOFF, TBSTATE_ENABLED, BTNS_SHOWTEXT|BTNS_AUTOSIZE, {0,0}, IDS_LOGOFF_TIP_LOGOFF, 1},
|
|
{2, SMNLC_TURNOFF, TBSTATE_ENABLED, BTNS_SHOWTEXT|BTNS_AUTOSIZE, {0,0}, IDS_LOGOFF_TIP_SHUTDOWN, 2},
|
|
{2,SMNLC_DISCONNECT,TBSTATE_ENABLED, BTNS_SHOWTEXT|BTNS_AUTOSIZE, {0,0}, IDS_LOGOFF_TIP_DISCONNECT, 3},
|
|
};
|
|
|
|
// WARNING! Must be in sync with tbButtonsCreate
|
|
static const UINT c_rgidmLegacy[] =
|
|
{
|
|
IDM_EJECTPC,
|
|
IDM_LOGOFF,
|
|
IDM_EXITWIN,
|
|
IDM_MU_DISCONNECT,
|
|
};
|
|
|
|
class CLogoffPane
|
|
: public CUnknown
|
|
, public CAccessible
|
|
{
|
|
public:
|
|
|
|
// *** IUnknown ***
|
|
STDMETHODIMP QueryInterface(REFIID riid, void** ppvObj);
|
|
STDMETHODIMP_(ULONG) AddRef(void) { return CUnknown::AddRef(); }
|
|
STDMETHODIMP_(ULONG) Release(void) { return CUnknown::Release(); }
|
|
|
|
// *** IAccessible overridden methods ***
|
|
STDMETHODIMP get_accKeyboardShortcut(VARIANT varChild, BSTR *pszKeyboardShortcut);
|
|
STDMETHODIMP get_accDefaultAction(VARIANT varChild, BSTR *pszDefAction);
|
|
|
|
CLogoffPane::CLogoffPane();
|
|
CLogoffPane::~CLogoffPane();
|
|
|
|
static LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
LRESULT _OnCreate(LPARAM lParam);
|
|
void _OnDestroy();
|
|
LRESULT _OnNCCreate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
LRESULT _OnNCDestroy(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
LRESULT _OnNotify(NMHDR *pnm);
|
|
LRESULT _OnCommand(int id);
|
|
LRESULT _OnCustomDraw(NMTBCUSTOMDRAW *pnmcd);
|
|
LRESULT _OnSMNFindItem(PSMNDIALOGMESSAGE pdm);
|
|
LRESULT _OnSMNFindItemWorker(PSMNDIALOGMESSAGE pdm);
|
|
LRESULT _OnSysColorChange(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
LRESULT _OnDisplayChange(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
LRESULT _OnSettingChange(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
void _InitMetrics();
|
|
LRESULT _OnSize(int x, int y);
|
|
|
|
private:
|
|
HWND _hwnd;
|
|
HWND _hwndTB;
|
|
HWND _hwndTT; //Tooltip window.
|
|
COLORREF _clr;
|
|
int _colorHighlight;
|
|
int _colorHighlightText;
|
|
HTHEME _hTheme;
|
|
BOOL _fSettingHotItem;
|
|
MARGINS _margins;
|
|
|
|
// helper functions
|
|
int _GetCurButton();
|
|
LRESULT _NextVisibleButton(PSMNDIALOGMESSAGE pdm, int i, int direction);
|
|
BOOL _IsButtonHidden(int i);
|
|
TCHAR _GetButtonAccelerator(int i);
|
|
void _RightAlign();
|
|
void _ApplyOptions();
|
|
|
|
BOOL _SetTBButtons(int id, UINT iMsg);
|
|
BOOL _ThemedSetTBButtons(int iState, UINT iMsg);
|
|
|
|
friend BOOL CLogoffPane_RegisterClass();
|
|
};
|
|
|
|
CLogoffPane::CLogoffPane()
|
|
{
|
|
ASSERT(_hwndTB == NULL);
|
|
ASSERT(_hwndTT == NULL);
|
|
_clr = CLR_INVALID;
|
|
}
|
|
|
|
CLogoffPane::~CLogoffPane()
|
|
{
|
|
}
|
|
|
|
HRESULT CLogoffPane::QueryInterface(REFIID riid, void * *ppvOut)
|
|
{
|
|
static const QITAB qit[] = {
|
|
QITABENT(CLogoffPane, IAccessible),
|
|
QITABENT(CLogoffPane, IDispatch), // IAccessible derives from IDispatch
|
|
{ 0 },
|
|
};
|
|
return QISearch(this, qit, riid, ppvOut);
|
|
}
|
|
|
|
LRESULT CALLBACK CLogoffPane::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CLogoffPane *self = reinterpret_cast<CLogoffPane *>(GetWindowPtr0(hwnd));
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_NCCREATE:
|
|
return self->_OnNCCreate(hwnd, uMsg, wParam, lParam);
|
|
|
|
case WM_CREATE:
|
|
return self->_OnCreate(lParam);
|
|
|
|
case WM_DESTROY:
|
|
self->_OnDestroy();
|
|
break;
|
|
|
|
case WM_NCDESTROY:
|
|
return self->_OnNCDestroy(hwnd, uMsg, wParam, lParam);
|
|
|
|
case WM_ERASEBKGND:
|
|
{
|
|
RECT rc;
|
|
GetClientRect(hwnd, &rc);
|
|
if (self->_hTheme)
|
|
{
|
|
DrawThemeBackground(self->_hTheme, (HDC)wParam, SPP_LOGOFF, 0, &rc, 0);
|
|
}
|
|
else
|
|
{
|
|
SHFillRectClr((HDC)wParam, &rc, GetSysColor(COLOR_MENU));
|
|
DrawEdge((HDC)wParam, &rc, EDGE_ETCHED, BF_TOP);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
return self->_OnCommand(GET_WM_COMMAND_ID(wParam, lParam));
|
|
|
|
case WM_NOTIFY:
|
|
return self->_OnNotify((NMHDR*)(lParam));
|
|
|
|
case WM_SIZE:
|
|
return self->_OnSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
|
|
|
case WM_SYSCOLORCHANGE:
|
|
return self->_OnSysColorChange(hwnd, uMsg, wParam, lParam);
|
|
|
|
case WM_DISPLAYCHANGE:
|
|
return self->_OnDisplayChange(hwnd, uMsg, wParam, lParam);
|
|
|
|
case WM_SETTINGCHANGE:
|
|
return self->_OnSettingChange(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
LRESULT CLogoffPane::_OnNCCreate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
|
|
|
|
CLogoffPane *self = new CLogoffPane;
|
|
|
|
if (self)
|
|
{
|
|
SetWindowPtr0(hwnd, self);
|
|
|
|
self->_hwnd = hwnd;
|
|
|
|
return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
void AddBitmapToToolbar(HWND hwndTB, HBITMAP hBitmap, int cxTotal, int cy, UINT iMsg)
|
|
{
|
|
HIMAGELIST himl = ImageList_Create(cxTotal / NUM_TBBUTTON_IMAGES, cy, ILC_COLOR32, 0, NUM_TBBUTTON_IMAGES);
|
|
|
|
if (himl)
|
|
{
|
|
ImageList_Add(himl, hBitmap, NULL);
|
|
|
|
HIMAGELIST himlPrevious = (HIMAGELIST) SendMessage(hwndTB, iMsg, 0, (LPARAM)himl);
|
|
if (himlPrevious)
|
|
{
|
|
ImageList_Destroy(himlPrevious);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL CLogoffPane::_SetTBButtons(int id, UINT iMsg)
|
|
{
|
|
HBITMAP hBitmap = LoadBitmap(_Module.GetModuleInstance(), MAKEINTRESOURCE(id));
|
|
if (hBitmap)
|
|
{
|
|
BITMAP bm;
|
|
if (GetObject(hBitmap, sizeof(BITMAP), &bm))
|
|
{
|
|
AddBitmapToToolbar(_hwndTB, hBitmap, bm.bmWidth, bm.bmHeight, iMsg);
|
|
}
|
|
DeleteObject(hBitmap);
|
|
}
|
|
return BOOLIFY(hBitmap);
|
|
}
|
|
|
|
BOOL CLogoffPane::_ThemedSetTBButtons(int iState, UINT iMsg)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
HDC hdcScreen = GetDC(NULL);
|
|
HDC hdc = CreateCompatibleDC(hdcScreen);
|
|
if (hdc)
|
|
{
|
|
SIZE siz;
|
|
if (SUCCEEDED(GetThemePartSize(_hTheme, NULL, SPP_LOGOFFBUTTONS, iState,
|
|
NULL, TS_TRUE, &siz)))
|
|
{
|
|
void *pvDestBits;
|
|
BITMAPINFO bi = {0};
|
|
|
|
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
|
|
bi.bmiHeader.biWidth = siz.cx;
|
|
bi.bmiHeader.biHeight = siz.cy;
|
|
bi.bmiHeader.biPlanes = 1;
|
|
bi.bmiHeader.biBitCount = 32;
|
|
bi.bmiHeader.biCompression = BI_RGB;
|
|
|
|
// Create a DIB Section so we can force it to be 32 bits, and preserve the alpha channel.
|
|
HBITMAP hbm = CreateDIBSection(hdcScreen, &bi, DIB_RGB_COLORS, &pvDestBits, NULL, 0);
|
|
if (hbm)
|
|
{
|
|
HBITMAP hbmOld = (HBITMAP) SelectObject(hdc, hbm);
|
|
|
|
RECT rc={0,0,siz.cx,siz.cy};
|
|
|
|
// draws into the DC, which updates the bitmap
|
|
DTBGOPTS dtbg = {sizeof(DTBGOPTS), DTBG_DRAWSOLID, 0,}; // tell drawthemebackground to preserve the alpha channel
|
|
bRet = SUCCEEDED(DrawThemeBackgroundEx(_hTheme, hdc, SPP_LOGOFFBUTTONS, iState, &rc, &dtbg));
|
|
|
|
SelectObject(hdc, hbmOld); // unselect the bitmap, so we can use it
|
|
|
|
if (bRet)
|
|
AddBitmapToToolbar(_hwndTB, hbm, siz.cx, siz.cy, iMsg);
|
|
|
|
DeleteObject(hbm);
|
|
}
|
|
}
|
|
DeleteDC(hdc);
|
|
}
|
|
if (hdcScreen)
|
|
ReleaseDC(NULL, hdcScreen);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
void CLogoffPane::_OnDestroy()
|
|
{
|
|
if (IsWindow(_hwndTB))
|
|
{
|
|
HIMAGELIST himl = (HIMAGELIST) SendMessage(_hwndTB, TB_GETIMAGELIST, 0, 0);
|
|
|
|
if (himl)
|
|
{
|
|
ImageList_Destroy(himl);
|
|
}
|
|
|
|
himl = (HIMAGELIST) SendMessage(_hwndTB, TB_GETHOTIMAGELIST, 0, 0);
|
|
if (himl)
|
|
{
|
|
ImageList_Destroy(himl);
|
|
}
|
|
}
|
|
}
|
|
|
|
LRESULT CLogoffPane::_OnCreate(LPARAM lParam)
|
|
{
|
|
// Do not set WS_TABSTOP here; that's CLogoffPane's job
|
|
|
|
DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS|WS_VISIBLE | CCS_NORESIZE|CCS_NODIVIDER | TBSTYLE_FLAT|TBSTYLE_LIST|TBSTYLE_TOOLTIPS;
|
|
RECT rc;
|
|
|
|
_hTheme = (PaneDataFromCreateStruct(lParam))->hTheme;
|
|
|
|
if (_hTheme)
|
|
{
|
|
GetThemeColor(_hTheme, SPP_LOGOFF, 0, TMT_TEXTCOLOR, &_clr);
|
|
_colorHighlight = COLOR_MENUHILIGHT;
|
|
_colorHighlightText = COLOR_HIGHLIGHTTEXT;
|
|
|
|
GetThemeMargins(_hTheme, NULL, SPP_LOGOFF, 0, TMT_CONTENTMARGINS, NULL, &_margins);
|
|
}
|
|
else
|
|
{
|
|
_clr = GetSysColor(COLOR_MENUTEXT);
|
|
_colorHighlight = COLOR_HIGHLIGHT;
|
|
_colorHighlightText = COLOR_HIGHLIGHTTEXT;
|
|
|
|
_margins.cyTopHeight = _margins.cyBottomHeight = 2 * GetSystemMetrics(SM_CYEDGE);
|
|
ASSERT(_margins.cxLeftWidth == 0);
|
|
ASSERT(_margins.cxRightWidth == 0);
|
|
}
|
|
|
|
GetClientRect(_hwnd, &rc);
|
|
rc.left += _margins.cxLeftWidth;
|
|
rc.right -= _margins.cxRightWidth;
|
|
rc.top += _margins.cyTopHeight;
|
|
rc.bottom -= _margins.cyBottomHeight;
|
|
|
|
_hwndTB = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, dwStyle,
|
|
rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc), _hwnd,
|
|
NULL, NULL, NULL );
|
|
if (_hwndTB)
|
|
{
|
|
//
|
|
// Don't freak out if this fails. It just means that the accessibility
|
|
// stuff won't be perfect.
|
|
//
|
|
SetAccessibleSubclassWindow(_hwndTB);
|
|
|
|
// we do our own themed drawing...
|
|
SetWindowTheme(_hwndTB, L"", L"");
|
|
|
|
// Scale up on HIDPI
|
|
SendMessage(_hwndTB, CCM_DPISCALE, TRUE, 0);
|
|
|
|
SendMessage(_hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
|
|
|
|
if (!_hTheme ||
|
|
!_ThemedSetTBButtons(SPLS_NORMAL, TB_SETIMAGELIST) ||
|
|
!_ThemedSetTBButtons(SPLS_HOT, TB_SETHOTIMAGELIST) )
|
|
{
|
|
// if we don't have a theme, or failed at setting the images from the theme
|
|
// set buttons images from the rc file
|
|
_SetTBButtons(IDB_LOGOFF_NORMAL, TB_SETIMAGELIST);
|
|
_SetTBButtons(IDB_LOGOFF_HOT, TB_SETHOTIMAGELIST);
|
|
}
|
|
|
|
SendMessage(_hwndTB, TB_ADDBUTTONS, ARRAYSIZE(tbButtonsCreate), (LPARAM) tbButtonsCreate);
|
|
int idText = IsOS(OS_FRIENDLYLOGONUI) ? IDS_LOGOFF_TEXT_FRIENDLY : IDS_LOGOFF_TEXT_DOMAIN;
|
|
SendMessage(_hwndTB, TB_ADDSTRING, (WPARAM) _Module.GetModuleInstance(), (LPARAM) idText);
|
|
|
|
_ApplyOptions();
|
|
|
|
_hwndTT = (HWND)SendMessage(_hwndTB, TB_GETTOOLTIPS, 0, 0); //Get the tooltip window.
|
|
|
|
_InitMetrics();
|
|
|
|
return 0;
|
|
}
|
|
|
|
return -1; // no point in sticking around if we couldn't create the toolbar
|
|
}
|
|
|
|
BOOL CLogoffPane::_IsButtonHidden(int i)
|
|
{
|
|
TBBUTTON but;
|
|
SendMessage(_hwndTB, TB_GETBUTTON, i, (LPARAM) &but);
|
|
return but.fsState & TBSTATE_HIDDEN;
|
|
}
|
|
|
|
void CLogoffPane::_RightAlign()
|
|
{
|
|
int iWidthOfButtons=0;
|
|
|
|
// add up the width of all the non-hidden buttons
|
|
for(int i=0;i<ARRAYSIZE(tbButtonsCreate);i++)
|
|
{
|
|
if (!_IsButtonHidden(i))
|
|
{
|
|
RECT rc;
|
|
SendMessage(_hwndTB, TB_GETITEMRECT, i, (LPARAM) &rc);
|
|
iWidthOfButtons += RECTWIDTH(rc);
|
|
}
|
|
}
|
|
|
|
if (iWidthOfButtons)
|
|
{
|
|
RECT rc;
|
|
GetClientRect(_hwndTB, &rc);
|
|
|
|
int iIndent = RECTWIDTH(rc) - iWidthOfButtons - GetSystemMetrics(SM_CXEDGE);
|
|
|
|
if (iIndent < 0)
|
|
iIndent = 0;
|
|
SendMessage(_hwndTB, TB_SETINDENT, iIndent, 0);
|
|
}
|
|
}
|
|
|
|
LRESULT CLogoffPane::_OnSize(int x, int y)
|
|
{
|
|
if (_hwndTB)
|
|
{
|
|
SetWindowPos(_hwndTB, NULL, _margins.cxLeftWidth, _margins.cyTopHeight,
|
|
x-(_margins.cxRightWidth+_margins.cxLeftWidth), y-(_margins.cyBottomHeight+_margins.cyTopHeight),
|
|
SWP_NOACTIVATE | SWP_NOOWNERZORDER);
|
|
_RightAlign();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CLogoffPane::_OnNCDestroy(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// WARNING! "this" might be invalid (if WM_NCCREATE failed), so
|
|
// do not use any member variables!
|
|
LRESULT lres = DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
SetWindowPtr0(hwnd, 0);
|
|
if (this)
|
|
{
|
|
this->Release();
|
|
}
|
|
return lres;
|
|
}
|
|
|
|
void CLogoffPane::_ApplyOptions()
|
|
{
|
|
SMNFILTEROPTIONS nmopt;
|
|
nmopt.smnop = SMNOP_LOGOFF | SMNOP_TURNOFF | SMNOP_DISCONNECT | SMNOP_EJECT;
|
|
_SendNotify(_hwnd, SMN_FILTEROPTIONS, &nmopt.hdr);
|
|
|
|
SendMessage(_hwndTB, TB_HIDEBUTTON, SMNLC_EJECT, !(nmopt.smnop & SMNOP_EJECT));
|
|
SendMessage(_hwndTB, TB_HIDEBUTTON, SMNLC_LOGOFF, !(nmopt.smnop & SMNOP_LOGOFF));
|
|
SendMessage(_hwndTB, TB_HIDEBUTTON, SMNLC_TURNOFF, !(nmopt.smnop & SMNOP_TURNOFF));
|
|
SendMessage(_hwndTB, TB_HIDEBUTTON, SMNLC_DISCONNECT, !(nmopt.smnop & SMNOP_DISCONNECT));
|
|
|
|
_RightAlign();
|
|
}
|
|
|
|
|
|
LRESULT CLogoffPane::_OnNotify(NMHDR *pnm)
|
|
{
|
|
if (pnm->hwndFrom == _hwndTB)
|
|
{
|
|
switch (pnm->code)
|
|
{
|
|
case NM_CUSTOMDRAW:
|
|
return _OnCustomDraw((NMTBCUSTOMDRAW*)pnm);
|
|
case TBN_WRAPACCELERATOR:
|
|
return TRUE; // Disable wraparound; we want DeskHost to do navigation
|
|
case TBN_GETINFOTIP:
|
|
{
|
|
NMTBGETINFOTIP *ptbgit = (NMTBGETINFOTIP *)pnm;
|
|
ASSERT(ptbgit->lParam >= IDS_LOGOFF_TIP_EJECT && ptbgit->lParam <= IDS_LOGOFF_TIP_DISCONNECT);
|
|
LoadString(_Module.GetModuleInstance(), ptbgit->lParam, ptbgit->pszText, ptbgit->cchTextMax);
|
|
return TRUE;
|
|
}
|
|
case TBN_HOTITEMCHANGE:
|
|
{
|
|
// Disallow setting a hot item if we are not focus
|
|
// (unless it was specifically our idea in the first place)
|
|
// Otherwise we interfere with keyboard navigation
|
|
|
|
NMTBHOTITEM *phot = (NMTBHOTITEM*)pnm;
|
|
if (!(phot->dwFlags & HICF_LEAVING) &&
|
|
GetFocus() != pnm->hwndFrom &&
|
|
!_fSettingHotItem)
|
|
{
|
|
return TRUE; // deny hot item change
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
else // from host
|
|
{
|
|
switch (pnm->code)
|
|
{
|
|
case SMN_REFRESHLOGOFF:
|
|
_ApplyOptions();
|
|
return TRUE;
|
|
case SMN_FINDITEM:
|
|
return _OnSMNFindItem(CONTAINING_RECORD(pnm, SMNDIALOGMESSAGE, hdr));
|
|
case SMN_APPLYREGION:
|
|
return HandleApplyRegion(_hwnd, _hTheme, (SMNMAPPLYREGION *)pnm, SPP_LOGOFF, 0);
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
LRESULT CLogoffPane::_OnCommand(int id)
|
|
{
|
|
int i;
|
|
for (i = 0; i < ARRAYSIZE(tbButtonsCreate); i++)
|
|
{
|
|
if (tbButtonsCreate[i].idCommand == id)
|
|
{
|
|
if (!_IsButtonHidden(i))
|
|
{
|
|
PostMessage(v_hwndTray, WM_COMMAND, c_rgidmLegacy[i], 0);
|
|
SMNMCOMMANDINVOKED ci;
|
|
SendMessage(_hwndTB, TB_GETITEMRECT, i, (LPARAM)&ci.rcItem);
|
|
MapWindowRect(_hwndTB, NULL, &ci.rcItem);
|
|
_SendNotify(_hwnd, SMN_COMMANDINVOKED, &ci.hdr);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CLogoffPane::_OnCustomDraw(NMTBCUSTOMDRAW *pnmtbcd)
|
|
{
|
|
LRESULT lres;
|
|
|
|
switch (pnmtbcd->nmcd.dwDrawStage)
|
|
{
|
|
case CDDS_PREPAINT:
|
|
return CDRF_NOTIFYITEMDRAW;
|
|
|
|
case CDDS_ITEMPREPAINT:
|
|
#if 0 //Do we still need this?
|
|
pnmtbcd->nHLStringBkMode = TRANSPARENT; // needed to reduce flicker- bug in toolbar?
|
|
#endif
|
|
|
|
pnmtbcd->clrText = _clr;
|
|
pnmtbcd->clrTextHighlight = GetSysColor(_colorHighlightText);
|
|
pnmtbcd->clrHighlightHotTrack = GetSysColor(_colorHighlight);
|
|
|
|
lres = TBCDRF_NOEDGES | TBCDRF_HILITEHOTTRACK;
|
|
|
|
// todo - FIX TOOLBAR to respect clrTextHighlight when item is hot.
|
|
if (pnmtbcd->nmcd.uItemState == CDIS_HOT)
|
|
{
|
|
pnmtbcd->clrText = pnmtbcd->clrTextHighlight;
|
|
}
|
|
|
|
return lres;
|
|
}
|
|
return CDRF_DODEFAULT;
|
|
}
|
|
|
|
LRESULT CLogoffPane::_NextVisibleButton(PSMNDIALOGMESSAGE pdm, int i, int direction)
|
|
{
|
|
ASSERT(direction == +1 || direction == -1);
|
|
|
|
i += direction;
|
|
while (i >= 0 && i < ARRAYSIZE(tbButtonsCreate))
|
|
{
|
|
if (!_IsButtonHidden(i))
|
|
{
|
|
pdm->itemID = i;
|
|
return TRUE;
|
|
}
|
|
i += direction;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
int CLogoffPane::_GetCurButton()
|
|
{
|
|
return (int)SendMessage(_hwndTB, TB_GETHOTITEM, 0, 0);
|
|
}
|
|
|
|
LRESULT CLogoffPane::_OnSMNFindItem(PSMNDIALOGMESSAGE pdm)
|
|
{
|
|
LRESULT lres = _OnSMNFindItemWorker(pdm);
|
|
|
|
if (lres)
|
|
{
|
|
//
|
|
// If caller requested that the item also be selected, then do so.
|
|
//
|
|
if (pdm->flags & SMNDM_SELECT)
|
|
{
|
|
if (_GetCurButton() != pdm->itemID)
|
|
{
|
|
// Explicitly pop the tooltip so we don't have the problem
|
|
// of a "virtual" tooltip causing the infotip to appear
|
|
// the instant the mouse moves into the window.
|
|
if (_hwndTT)
|
|
{
|
|
SendMessage(_hwndTT, TTM_POP, 0, 0);
|
|
}
|
|
|
|
// _fSettingHotItem tells our WM_NOTIFY handler to
|
|
// allow this hot item change to go through
|
|
_fSettingHotItem = TRUE;
|
|
SendMessage(_hwndTB, TB_SETHOTITEM, pdm->itemID, 0);
|
|
_fSettingHotItem = FALSE;
|
|
|
|
// Do the SetFocus after setting the hot item to prevent
|
|
// toolbar from autoselecting the first button (which
|
|
// is what it does if you SetFocus when there is no hot
|
|
// item). SetFocus returns the previous focus window.
|
|
if (SetFocus(_hwndTB) != _hwndTB)
|
|
{
|
|
// Send the notify since we tricked toolbar into not sending it
|
|
// (Toolbar doesn't send a subobject focus notification
|
|
// on WM_SETFOCUS if the item was already hot when it gained focus)
|
|
NotifyWinEvent(EVENT_OBJECT_FOCUS, _hwndTB, OBJID_CLIENT, pdm->itemID + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If not found, then tell caller what our orientation is (horizontal)
|
|
// and where the currently-selected item is.
|
|
//
|
|
|
|
pdm->flags |= SMNDM_HORIZONTAL;
|
|
int i = _GetCurButton();
|
|
RECT rc;
|
|
if (i >= 0 && SendMessage(_hwndTB, TB_GETITEMRECT, i, (LPARAM)&rc))
|
|
{
|
|
pdm->pt.x = (rc.left + rc.right)/2;
|
|
pdm->pt.y = (rc.top + rc.bottom)/2;
|
|
}
|
|
else
|
|
{
|
|
pdm->pt.x = 0;
|
|
pdm->pt.y = 0;
|
|
}
|
|
|
|
}
|
|
return lres;
|
|
}
|
|
|
|
TCHAR CLogoffPane::_GetButtonAccelerator(int i)
|
|
{
|
|
TCHAR szText[MAX_PATH];
|
|
if (SendMessage(_hwndTB, TB_GETBUTTONTEXT, tbButtonsCreate[i].idCommand, (LPARAM)szText) > 0)
|
|
{
|
|
return CharUpperChar(SHFindMnemonic(szText));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Metrics changed -- update.
|
|
//
|
|
void CLogoffPane::_InitMetrics()
|
|
{
|
|
if (_hwndTT)
|
|
{
|
|
// Disable/enable infotips based on user preference
|
|
SendMessage(_hwndTT, TTM_ACTIVATE, ShowInfoTip(), 0);
|
|
|
|
// Toolbar control doesn't set the tooltip font so we have to do it ourselves
|
|
SetWindowFont(_hwndTT, GetWindowFont(_hwndTB), FALSE);
|
|
}
|
|
}
|
|
|
|
LRESULT CLogoffPane::_OnDisplayChange(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// Propagate first because _InitMetrics needs to talk to the updated toolbar
|
|
SHPropagateMessage(hwnd, uMsg, wParam, lParam, SPM_SEND | SPM_ONELEVEL);
|
|
_InitMetrics();
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CLogoffPane::_OnSettingChange(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// Propagate first because _InitMetrics needs to talk to the updated toolbar
|
|
SHPropagateMessage(hwnd, uMsg, wParam, lParam, SPM_SEND | SPM_ONELEVEL);
|
|
// _InitMetrics() is so cheap it's not worth getting too upset about
|
|
// calling it too many times.
|
|
_InitMetrics();
|
|
_RightAlign();
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CLogoffPane::_OnSysColorChange(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// update colors in classic mode
|
|
if (!_hTheme)
|
|
{
|
|
_clr = GetSysColor(COLOR_MENUTEXT);
|
|
}
|
|
|
|
SHPropagateMessage(hwnd, uMsg, wParam, lParam, SPM_SEND | SPM_ONELEVEL);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
LRESULT CLogoffPane::_OnSMNFindItemWorker(PSMNDIALOGMESSAGE pdm)
|
|
{
|
|
int i;
|
|
switch (pdm->flags & SMNDM_FINDMASK)
|
|
{
|
|
case SMNDM_FINDFIRST:
|
|
return _NextVisibleButton(pdm, -1, +1);
|
|
|
|
case SMNDM_FINDLAST:
|
|
return _NextVisibleButton(pdm, ARRAYSIZE(tbButtonsCreate), -1);
|
|
|
|
case SMNDM_FINDNEAREST:
|
|
// HACK! but we know that we are the only control in our group
|
|
// so this doesn't need to be implemented
|
|
return FALSE;
|
|
|
|
case SMNDM_HITTEST:
|
|
pdm->itemID = SendMessage(_hwndTB, TB_HITTEST, 0, (LPARAM)&pdm->pt);
|
|
return pdm->itemID >= 0;
|
|
|
|
case SMNDM_FINDFIRSTMATCH:
|
|
case SMNDM_FINDNEXTMATCH:
|
|
{
|
|
if ((pdm->flags & SMNDM_FINDMASK) == SMNDM_FINDFIRSTMATCH)
|
|
{
|
|
i = 0;
|
|
}
|
|
else
|
|
{
|
|
i = _GetCurButton() + 1;
|
|
}
|
|
|
|
TCHAR tch = CharUpperChar((TCHAR)pdm->pmsg->wParam);
|
|
for ( ; i < ARRAYSIZE(tbButtonsCreate); i++)
|
|
{
|
|
if (_IsButtonHidden(i))
|
|
continue; // skip hidden buttons
|
|
if (_GetButtonAccelerator(i) == tch)
|
|
{
|
|
pdm->itemID = i;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
break; // not found
|
|
|
|
case SMNDM_FINDNEXTARROW:
|
|
switch (pdm->pmsg->wParam)
|
|
{
|
|
case VK_LEFT:
|
|
case VK_UP:
|
|
return _NextVisibleButton(pdm, _GetCurButton(), -1);
|
|
|
|
case VK_RIGHT:
|
|
case VK_DOWN:
|
|
return _NextVisibleButton(pdm, _GetCurButton(), +1);
|
|
}
|
|
|
|
return FALSE; // not found
|
|
|
|
case SMNDM_INVOKECURRENTITEM:
|
|
i = _GetCurButton();
|
|
if (i >= 0 && i < ARRAYSIZE(tbButtonsCreate))
|
|
{
|
|
FORWARD_WM_COMMAND(_hwnd, tbButtonsCreate[i].idCommand, _hwndTB, BN_CLICKED, PostMessage);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
|
|
case SMNDM_OPENCASCADE:
|
|
return FALSE; // none of our items cascade
|
|
|
|
default:
|
|
ASSERT(!"Unknown SMNDM command");
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT CLogoffPane::get_accKeyboardShortcut(VARIANT varChild, BSTR *pszKeyboardShortcut)
|
|
{
|
|
if (varChild.lVal)
|
|
{
|
|
return CreateAcceleratorBSTR(_GetButtonAccelerator(varChild.lVal - 1), pszKeyboardShortcut);
|
|
}
|
|
return CAccessible::get_accKeyboardShortcut(varChild, pszKeyboardShortcut);
|
|
}
|
|
|
|
HRESULT CLogoffPane::get_accDefaultAction(VARIANT varChild, BSTR *pszDefAction)
|
|
{
|
|
if (varChild.lVal)
|
|
{
|
|
return GetRoleString(ACCSTR_EXECUTE, pszDefAction);
|
|
}
|
|
return CAccessible::get_accDefaultAction(varChild, pszDefAction);
|
|
}
|
|
|
|
|
|
BOOL WINAPI LogoffPane_RegisterClass()
|
|
{
|
|
WNDCLASSEX wc;
|
|
ZeroMemory( &wc, sizeof(wc) );
|
|
|
|
wc.cbSize = sizeof(wc);
|
|
wc.style = CS_GLOBALCLASS;
|
|
wc.cbWndExtra = sizeof(LPVOID);
|
|
wc.lpfnWndProc = CLogoffPane::WndProc;
|
|
wc.hInstance = _Module.GetModuleInstance();
|
|
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
|
|
wc.hbrBackground = (HBRUSH)(NULL);
|
|
wc.lpszClassName = TEXT("DesktopLogoffPane");
|
|
|
|
return RegisterClassEx( &wc );
|
|
|
|
}
|