//-------------------------------------------------------------------
// OWL Extensions (OWLEXT) Class Library
// Copyright(c) 1996 by Manic Software.
// All rights reserved.
//
// This file implements the TBusyCursor class.
//
// Original code by Don Griffin; used with permission.
//-------------------------------------------------------------------
#include <owlext\pch.h>
#pragma hdrstop
#include <owlext/busy.h>
#include <owl/statusba.h>
#include <owlext/enumwnd.h>
#include <owlext/util.h>
using namespace owl;
namespace OwlExt {
#ifdef _DEBUG
/*
static owl::tstring WndText (HWND hWnd){
char text [33];
::GetWindowText (hWnd, text, sizeof text);
return owl::tstring(text);
}
static owl::tstring WndClass (HWND hWnd)
{
char className [80];
::GetClassName (hWnd, className, sizeof className);
return owl::tstring (className);
}
*/
#endif
static bool FilterWindow (HWND hWnd)
{
bool filter = !::IsWindowEnabled (hWnd) || !::IsWindowVisible (hWnd);
return filter;
}
//--------------------------------------------------------------------------
class TCountWindows : public OwlExt::TEnumWindows{
public:
TCountWindows () { mCount = 0; }
uint Count () const { return mCount; }
protected:
uint mCount;
virtual bool OnEnumWindow (HWND hWnd);
};
bool
TCountWindows::OnEnumWindow (HWND hWnd)
{
if(!FilterWindow (hWnd))
++mCount;
return true;
}
//--------------------------------------------------------------------------
struct TWindowSubclass{
HWND hWnd;
WNDPROC fnPrevWndProc;
};
class TSubclassWindows : public OwlExt::TEnumWindows {
public:
TSubclassWindows (WNDPROC fnSubclass, TWindowSubclass * wnd)
: mFnSubclass (LONG_PTR(fnSubclass)), mWnd (wnd) { }
protected:
TWindowSubclass* mWnd;
LONG_PTR mFnSubclass;
virtual bool OnEnumWindow (HWND hWnd);
};
bool TSubclassWindows::OnEnumWindow (HWND hWnd)
{
if (!FilterWindow (hWnd)){
mWnd->hWnd = hWnd;
mWnd->fnPrevWndProc = (WNDPROC)::SetWindowLongPtr(hWnd, GWLP_WNDPROC, mFnSubclass);
++mWnd;
}
return true;
}
//------------------------------------------------------------------------------
enum{
WM_NCMOUSEFIRST = WM_NCMOUSEMOVE,
WM_NCMOUSELAST = WM_NCMBUTTONDBLCLK
};
class TBusyHook{
public:
TBusyHook ();
~TBusyHook ();
private:
TAPointer<TWindowSubclass> mSubclass;
HCURSOR mBusyCursor;
uint mCount;
uint mHideCaretCount;
LRESULT BusyWndMethod (HWND, UINT, WPARAM, LPARAM);
static LRESULT CALLBACK BusyWndProc (HWND, UINT, WPARAM, LPARAM);
LRESULT DefWndProc (HWND, UINT, WPARAM, LPARAM);
};
static TBusyHook* sHook;
TBusyHook::TBusyHook()
{
TCountWindows counter;
counter.EnumWindows (OwlExt::TEnumWindows::emAllWindows);
mCount = counter.Count();
mSubclass = new TWindowSubclass [mCount];
TSubclassWindows subclass (BusyWndProc, mSubclass);
subclass.EnumWindows (OwlExt::TEnumWindows::emAllWindows);
HideCaret (0);
mHideCaretCount = 1;
mBusyCursor = ::LoadCursor (0, IDC_WAIT);
}
TBusyHook::~TBusyHook ()
{
for (int n = 0; n < (int)mCount; ++n)
::SetWindowLongPtr(mSubclass[n].hWnd, GWLP_WNDPROC, (LONG_PTR)mSubclass[n].fnPrevWndProc);
while (mHideCaretCount--)
ShowCaret (0);
UpdateCursor();
}
LRESULT CALLBACK
TBusyHook::BusyWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return sHook->BusyWndMethod (hWnd, uMsg, wParam, lParam);
}
LRESULT
TBusyHook::BusyWndMethod (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HWND hTopMostWindow;
switch (uMsg){
case WM_SETCURSOR:
::SetCursor (mBusyCursor);
return TRUE;
case WM_MOUSEACTIVATE:
hTopMostWindow = (HWND) wParam;
if (hTopMostWindow == hWnd)
return MA_ACTIVATEANDEAT;
return ::DefWindowProc (hWnd, uMsg, wParam, lParam);
case WM_SETFOCUS:
DefWndProc (hWnd, uMsg, wParam, lParam);
HideCaret (0);
++mHideCaretCount;
return 0;
}
if ((uMsg >= WM_KEYFIRST && uMsg <= WM_KEYLAST) ||
(uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST) ||
(uMsg >= WM_NCMOUSEFIRST && uMsg <= WM_NCMOUSELAST))
{
return 0; // ::DefWindowProc (hWnd, uMsg, wParam, lParam);
}
return DefWndProc (hWnd, uMsg, wParam, lParam);
}
LRESULT TBusyHook::DefWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int n;
for (n = 0; n < (int)mCount; ++n)
if (mSubclass[n].hWnd == hWnd)
return CallWindowProc(mSubclass[n].fnPrevWndProc, hWnd, uMsg, wParam, lParam);
PRECONDITION (0);
return 0;
}
//--------------------------------------------------------------------------
TBusyCursor* TBusyCursor::sTop;
TBusyCursor::TBusyCursor (owl::tstring message)
:
mMessage (message)
{
Init();
}
TBusyCursor::TBusyCursor ()
{
Init();
}
void TBusyCursor::Init ()
{
mNext = sTop;
sTop = this;
mActive = true;
mBusyCursor = ::LoadCursor (0, IDC_WAIT);
Activate ();
}
TBusyCursor::~TBusyCursor ()
{
const bool ok = sTop == this; // Must be destructed in reverse order.
WARN(!ok, _T("TBusyCursor::~TBusyCursor: Terminating due to failed precondition."));
if (!ok) std::terminate();
Active(mNext ? mNext->mActive : false); // update active state
sTop = mNext;
}
////////////////////////////////////////////////////////////////////////////
// This method activates or deactivates the busy state.
//
void TBusyCursor::Active (bool active)
{
if (active == mActive)
// Already active
return;
mActive = active;
if (sTop != this)
return; // we're not top-most, so we don't control the global state
if (mActive)
Activate();
else
Deactivate();
}
////////////////////////////////////////////////////////////////////////////
// This method activates the busy state.
//
void TBusyCursor::Activate ()
{
::SetCursor (mBusyCursor);
PRECONDITION(sHook == 0);
sHook = new TBusyHook;
UpdateMessage (mMessage.c_str());
}
////////////////////////////////////////////////////////////////////////////
// This method deactivates the busy state.
//
void TBusyCursor::Deactivate ()
{
PRECONDITION (sHook != 0);
delete sHook;
sHook = 0;
UpdateMessage (0);
}
////////////////////////////////////////////////////////////////////////////
// This method sets the message for the status bar.
//
void TBusyCursor::Message (owl::tstring message)
{
mMessage = message;
if (sTop == this && Active())
UpdateMessage (mMessage);
}
////////////////////////////////////////////////////////////////////////////
// This method flushes the message to the status bar.
//
void TBusyCursor::UpdateMessage(LPCTSTR message)
{
//TApplication* app = GetApplicationObject();
TStatusBar* bar = 0;
if (bar){
bar->SetText (message);
bar->UpdateWindow();
}
}
} // OwlExt namespace
//==============================================================================
↑ V547 Expression 'bar' is always false.
↑ V813 Decreased performance. The 'message' argument should probably be rendered as a constant reference.
↑ V820 The 'message' variable is not used after copying. Copying can be replaced with move/swap for optimization.