#include "priv.h" #include "apithk.h" #include "mshtmhst.h" #include "basebar.h" #ifdef MAINWIN #include EXTERN_C MwPaintSpecialEOBorder( HWND hWnd, HDC hDC ); #endif #define DBM_ONPOSRECTCHANGE (WM_USER) //*** CBaseBar::IDeskBar::* { // /*---------------------------------------------------------- Purpose: IDeskBar::SetClient Usually the function that composes a bar/bandsite/band union is responsible for calling this method to inform the bar what the client (bandsite) is. */ HRESULT CBaseBar::SetClient(IUnknown *punkChild) { if (_punkChild != NULL) { // 4, 3, 2, 1 Release _hwndChild = NULL; if (_pDBC) { // This must happen first, before _pWEH becomes NULL so cleanup // notifications can still go thru _pDBC->SetDeskBarSite(NULL); } ATOMICRELEASE(_pDBC); ATOMICRELEASE(_pWEH); ATOMICRELEASE(_punkChild); } _punkChild = punkChild; HRESULT hr = S_OK; if (_punkChild != NULL) { // 1, 2, 3, 4 QI/AddRef/etc. _punkChild->AddRef(); if (!_hwnd) { _RegisterDeskBarClass(); _CreateDeskBarWindow(); if (!_hwnd) { return E_OUTOFMEMORY; } // can't do CBaseBar::_Initialize yet (haven't done SetSite yet) } hr = _punkChild->QueryInterface(IID_PPV_ARG(IWinEventHandler, &_pWEH)); if (SUCCEEDED(hr)) { hr = _punkChild->QueryInterface(IID_PPV_ARG(IDeskBarClient, &_pDBC)); if (SUCCEEDED(hr)) { // nothing to cache yet due to lazy CreateWindow hr = _pDBC->SetDeskBarSite(SAFECAST(this, IDeskBar*)); IUnknown_GetWindow(_punkChild, &_hwndChild); } } } return hr; } HRESULT CBaseBar::GetClient(IUnknown **ppunk) { *ppunk = _punkChild; if (_punkChild) _punkChild->AddRef(); return _punkChild ? S_OK : E_FAIL; } HRESULT CBaseBar::OnPosRectChangeDB(LPRECT prc) { _szChild.cx = RECTWIDTH(*prc); _szChild.cy = RECTHEIGHT(*prc); // We can't change our size right away because we haven't returned from processing // this WM_SIZE message. If we resize right now, USER gets confused... // // We cannot use PeekMessage to determine if there is already a pending // DBM_ONPOSRECTCHANGE because that allows incoming SendMessage's to // arrive, and then we can get into a bad recursive situation when there // are a lot of SHChangeNotify's arriving in rapid succession. // if (!_fPosRectChangePending) { _fPosRectChangePending = TRUE; PostMessage(_hwnd, DBM_ONPOSRECTCHANGE, 0, 0); } return S_OK; } // Derived classes are expected to implement this method and do something // interesting... void CBaseBar::_OnPostedPosRectChange() { } // } HRESULT CBaseBar::ShowDW(BOOL fShow) { fShow = BOOLIFY(fShow); if (BOOLIFY(_fShow) == fShow) return S_OK; _fShow = fShow; if (_pDBC) return _pDBC->UIActivateDBC(fShow ? DBC_SHOW : DBC_HIDE); else return E_UNEXPECTED; } void CBaseBar::_OnCreate() { SendMessage(_hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, 0), 0); } LRESULT CBaseBar::_OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT lres = 0; _CheckForwardWinEvent(uMsg, wParam, lParam, &lres); return lres; } /*** */ LRESULT CBaseBar::v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT lres = 0; switch (uMsg) { case WM_CREATE: _OnCreate(); break; case WM_COMMAND: return _OnCommand(uMsg, wParam, lParam); case WM_SIZE: _OnSize(); break; case WM_NOTIFY: return _OnNotify(uMsg, wParam, lParam); #if 0 // we'd like to set focus to the 1st band when somebody clicks in // 'dead space' on the bar (i.e. make it look like they TABed in). // however for some reason the below code has the bad effect of // de-selecting text in (e.g.) the addr edit control (it's as if // the control thinks we've clicked there 2x rather than 1x). case WM_SETFOCUS: if (IUnknown_HasFocusIO(_pDBC) == S_FALSE) IUnknown_UIActivateIO(_pDBC, TRUE, NULL); break; #endif case WM_SYSCOLORCHANGE: case WM_WININICHANGE: case WM_CONTEXTMENU: case WM_INITMENUPOPUP: case WM_MEASUREITEM: case WM_DRAWITEM: case WM_MENUCHAR: case WM_PALETTECHANGED: _CheckForwardWinEvent(uMsg, wParam, lParam, &lres); break; case DBM_ONPOSRECTCHANGE: _fPosRectChangePending = FALSE; _OnPostedPosRectChange(); break; #ifdef MAINWIN case WM_NCPAINTSPECIALFRAME: // In case of motif look the MwPaintBorder paints a Etched In // border if WM_NCPAINTSPECIALFRAME returns FALSE. We are handling // this message here and drawing the Etched Out frame explicitly. // wParam - HDC if (MwCurrentLook() == LOOK_MOTIF) { MwPaintSpecialEOBorder( hwnd, (HDC)wParam ); return TRUE; } #endif default: return DefWindowProcWrap(hwnd, uMsg, wParam, lParam); } return lres; } /*** */ CBaseBar::CBaseBar() : _cRef(1) { DllAddRef(); } /*** */ CBaseBar::~CBaseBar() { // see Release, where we call virtuals (which can't be called from dtor) DllRelease(); } /*** */ void CBaseBar::_RegisterDeskBarClass() { WNDCLASS wc = {0}; wc.style = _GetClassStyle(); wc.lpfnWndProc = s_WndProc; //wc.cbClsExtra = 0; wc.cbWndExtra = SIZEOF(CBaseBar*); wc.hInstance = HINST_THISDLL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) (COLOR_3DFACE+1); //wc.lpszMenuName = NULL; wc.lpszClassName = TEXT("BaseBar"); //wc.hIcon = NULL; SHRegisterClass(&wc); } DWORD CBaseBar::_GetExStyle() { return WS_EX_TOOLWINDOW; } DWORD CBaseBar::_GetClassStyle() { return CS_HREDRAW | CS_VREDRAW; } void CBaseBar::_CreateDeskBarWindow() { #ifndef UNIX // _hwnd is set in s_WndProc DWORD dwExStyle = _GetExStyle(); dwExStyle |= IS_BIDI_LOCALIZED_SYSTEM() ? dwExStyleRTLMirrorWnd : 0L; HWND hwndDummy = CreateWindowEx( dwExStyle, TEXT("BaseBar"), NULL, _hwndSite ? WS_CHILD | WS_CLIPCHILDREN : WS_POPUP | WS_CLIPCHILDREN, 0,0,100,100, _hwndSite, NULL, HINST_THISDLL, (LPVOID)SAFECAST(this, CImpWndProc*)); #else // This change removes a flash at the corner of the // screen. We create a small 1,1 window. HWND hwndDummy = CreateWindowEx( _GetExStyle(), TEXT("BaseBar"), NULL, _hwndSite ? WS_CHILD | WS_CLIPCHILDREN : WS_POPUP | WS_CLIPCHILDREN, -100,-100,1,1, _hwndSite, NULL, HINST_THISDLL, (LPVOID)SAFECAST(this, CImpWndProc*)); #endif } void CBaseBar::_OnSize(void) { RECT rc; if (!_hwndChild) return; GetClientRect(_hwnd, &rc); SetWindowPos(_hwndChild, 0, rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc), SWP_NOACTIVATE|SWP_NOZORDER); } void CBaseBar::_NotifyModeChange(DWORD dwMode) { if (_pDBC) { _dwMode = dwMode; // FEATURE: should we add an STBBIF_VIEWMODE_FLOAT? _pDBC->SetModeDBC(_dwMode); } } BOOL CBaseBar::_CheckForwardWinEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres) { HWND hwnd = NULL; *plres = 0; switch (uMsg) { case WM_CONTEXTMENU: case WM_INITMENUPOPUP: case WM_MEASUREITEM: case WM_DRAWITEM: case WM_MENUCHAR: hwnd = _hwndChild; break; case WM_NOTIFY: hwnd = ((LPNMHDR)lParam)->hwndFrom; break; case WM_COMMAND: hwnd = GET_WM_COMMAND_HWND(wParam, lParam); break; case WM_SYSCOLORCHANGE: case WM_WININICHANGE: case WM_PALETTECHANGED: hwnd = _hwndChild; break; } if (hwnd && _pWEH && _pWEH->IsWindowOwner(hwnd) == S_OK) { _pWEH->OnWinEvent(_hwnd, uMsg, wParam, lParam, plres); return TRUE; } return FALSE; } /*** */ LRESULT CBaseBar::_OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT lres = 0; _CheckForwardWinEvent(uMsg, wParam, lParam, &lres); return lres; } HRESULT CBaseBar::CloseDW(DWORD dwReserved) { SetClient(NULL); if (_hwnd) { DestroyWindow(_hwnd); _hwnd = NULL; } return S_OK; } HRESULT CBaseBar::QueryInterface(REFIID riid, LPVOID * ppvObj) { static const QITAB qit[] = { QITABENT(CBaseBar, IOleWindow), QITABENT(CBaseBar, IDeskBar), QITABENT(CBaseBar, IInputObject), QITABENT(CBaseBar, IInputObjectSite), QITABENT(CBaseBar, IServiceProvider), QITABENT(CBaseBar, IOleCommandTarget), { 0 }, }; return QISearch(this, (LPCQITAB)qit, riid, ppvObj); } ULONG CBaseBar::AddRef() { _cRef++; return _cRef; } ULONG CBaseBar::Release() { ASSERT(_cRef > 0); _cRef--; if (_cRef > 0) return _cRef; // 'virtual dtor' // gotta do virtual stuff here (not in dtor) because can't call // any virtuals in the dtor // CBaseBar::Destroy() { CloseDW(0); // } delete this; return 0; } //*** CBaseBar::IOleWindow::* { // HRESULT CBaseBar::GetWindow(HWND * lphwnd) { *lphwnd = _hwnd; return (_hwnd) ? S_OK : E_FAIL; } HRESULT CBaseBar::ContextSensitiveHelp(BOOL fEnterMode) { // FEATURE: Visit here later. return E_NOTIMPL; } // } // } // some helpers... { // What's the point of having // these empty implementations in the base class? // //*** CBaseBar::IServiceProvider::* // HRESULT CBaseBar::QueryService(REFGUID guidService, REFIID riid, void **ppvObj) { HRESULT hres = E_FAIL; *ppvObj = NULL; return hres; } //*** CBaseBar::IOleCommandTarget::* // HRESULT CBaseBar::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext) { return MayQSForward(_pDBC, OCTD_DOWN, pguidCmdGroup, cCmds, rgCmds, pcmdtext); } HRESULT CBaseBar::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut) { return MayExecForward(_pDBC, OCTD_DOWN, pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); } // } //*** CDeskBar::IInputObject::* { HRESULT CBaseBar::HasFocusIO() { HRESULT hres; hres = IUnknown_HasFocusIO(_pDBC); return hres; } HRESULT CBaseBar::TranslateAcceleratorIO(LPMSG lpMsg) { HRESULT hres; hres = IUnknown_TranslateAcceleratorIO(_pDBC, lpMsg); return hres; } HRESULT CBaseBar::UIActivateIO(BOOL fActivate, LPMSG lpMsg) { HRESULT hres; hres = IUnknown_UIActivateIO(_pDBC, fActivate, lpMsg); return hres; } // } //*** CDeskBar::IInputObjectSite::* { HRESULT CBaseBar::OnFocusChangeIS(IUnknown *punk, BOOL fSetFocus) { return NOERROR; } // }