Install a VBL task to animate the watch cursor when we are away from the event loop for more that 3/4 of a second. r=sfraser, bug#52108.

This commit is contained in:
pinkerton%netscape.com 2000-09-12 22:51:16 +00:00
Родитель edea9b6d1e
Коммит aca176bb6c
2 изменённых файлов: 168 добавлений и 6 удалений

Просмотреть файл

@ -64,6 +64,7 @@
#include "nsISocketTransportService.h"
#include "nsIFileTransportService.h"
#ifndef topLeft
#define topLeft(r) (((Point *) &(r))[0])
#endif
@ -89,6 +90,11 @@ extern nsIRollupListener * gRollupListener;
extern nsIWidget * gRollupWidget;
// A class encapsulating our VBL task to spin the watch cursor if we're
// away from WNE for too long
WatchTask gWatchTask;
//======================================================================================
// PROFILE
//======================================================================================
@ -131,6 +137,7 @@ extern nsIWidget * gRollupWidget;
#endif //PROFILE
#endif //DEBUG
//======================================================================================
static Boolean KeyDown(const UInt8 theKey)
@ -327,6 +334,8 @@ PRBool nsMacMessagePump::GetEvent(EventRecord &theEvent)
haveEvent = PR_FALSE;
#endif
gWatchTask.EventLoopReached();
return haveEvent;
}
@ -419,8 +428,11 @@ void nsMacMessagePump::DispatchEvent(PRBool aRealEvent, EventRecord *anEvent)
// DoUpdate
//
//-------------------------------------------------------------------------
//#include "ProfilerUtils.h"
void nsMacMessagePump::DoUpdate(EventRecord &anEvent)
{
//INST_TRACE("nsMacMessagePump:DoUpdate");
WindowPtr whichWindow = reinterpret_cast<WindowPtr>(anEvent.message);
StPortSetter portSetter(whichWindow);
@ -429,6 +441,7 @@ void nsMacMessagePump::DoUpdate(EventRecord &anEvent)
// The app can do its own updates here
DispatchOSEventToRaptor(anEvent, whichWindow);
::EndUpdate(whichWindow);
}
@ -463,13 +476,16 @@ void nsMacMessagePump::DoMouseDown(EventRecord &anEvent)
}
else
{
gWatchTask.Suspend();
long menuResult = ::MenuSelect(anEvent.where);
gWatchTask.Resume();
if (HiWord(menuResult) != 0)
{
menuResult = ConvertOSMenuResultToPPMenuResult(menuResult);
DoMenu(anEvent, menuResult);
}
}
break;
}
@ -493,8 +509,10 @@ void nsMacMessagePump::DoMouseDown(EventRecord &anEvent)
// grrr... DragWindow calls SelectWindow, no way to stop it. For now,
// we'll just let it come to the front and then push it back if necessary.
Rect screenRect;
gWatchTask.Suspend();
::GetRegionBounds(::GetGrayRgn(), &screenRect);
::DragWindow(whichWindow, anEvent.where, &screenRect);
gWatchTask.Resume();
// only activate if the command key is not down
if (!(anEvent.modifiers & cmdKey))
@ -584,7 +602,9 @@ void nsMacMessagePump::DoMouseDown(EventRecord &anEvent)
sizeRect.top = kMinWindowHeight;
sizeRect.left = kMinWindowWidth;
gWatchTask.Suspend();
long newSize = ::GrowWindow(whichWindow, anEvent.where, &sizeRect);
gWatchTask.Resume();
if (newSize != 0)
::SizeWindow(whichWindow, newSize & 0x0FFFF, (newSize >> 16) & 0x0FFFF, true);
::DrawGrowIcon(whichWindow);
@ -600,14 +620,19 @@ void nsMacMessagePump::DoMouseDown(EventRecord &anEvent)
case inGoAway:
{
gWatchTask.Suspend();
::SetPortWindowPort(whichWindow);
if (::TrackGoAway(whichWindow, anEvent.where))
if (::TrackGoAway(whichWindow, anEvent.where)) {
gWatchTask.Resume();
DispatchOSEventToRaptor(anEvent, whichWindow);
}
gWatchTask.Resume();
break;
}
case inZoomIn:
case inZoomOut:
gWatchTask.Suspend();
if (::TrackBox(whichWindow, anEvent.where, partCode)) {
GrafPtr savePort;
GDHandle gdNthDevice;
@ -619,6 +644,8 @@ void nsMacMessagePump::DoMouseDown(EventRecord &anEvent)
long sectArea, greatestArea = 0;
Boolean sectFlag;
gWatchTask.Resume();
GetPort(&savePort);
::SetPortWindowPort(whichWindow);
Rect windRect;
@ -663,6 +690,7 @@ void nsMacMessagePump::DoMouseDown(EventRecord &anEvent)
tempRect.bottom - 3);
::SetWindowStandardState ( whichWindow, &zoomRect );
}
gWatchTask.Resume();
SetPort(savePort);
@ -839,6 +867,8 @@ extern const PRInt16 kAppleMenuID; // Danger Will Robinson!!! - this currently r
//-------------------------------------------------------------------------
void nsMacMessagePump::DoActivate(EventRecord &anEvent)
{
//INST_TRACE("nsMacMessagePump:DoActivate");
WindowPtr whichWindow = (WindowPtr)anEvent.message;
::SetPortWindowPort(whichWindow);
if (anEvent.modifiers & activeFlag)
@ -917,3 +947,87 @@ PRBool nsMacMessagePump::DispatchMenuCommandToRaptor(
return handled;
}
#pragma mark -
WatchTask :: WatchTask ( )
: mChecksum('mozz'), mSelf(this), mTicks(::TickCount()), mBusy(PR_FALSE), mSuspended(PR_FALSE),
mInstallSucceeded(PR_FALSE), mAnimation(0)
{
// setup the task
mTask.qType = vType;
mTask.vblAddr = NewVBLProc((VBLProcPtr)DoWatchTask);
mTask.vblCount = kRepeatInterval;
mTask.vblPhase = 0;
// install it
mInstallSucceeded = ::VInstall((QElemPtr)&mTask) == noErr;
}
WatchTask :: ~WatchTask ( )
{
if ( mInstallSucceeded )
::VRemove ( (QElemPtr)&mTask );
InitCursor();
}
//
// DoWatchTask
//
// Called at vertical retrace. If we haven't been to the event loop for
// |kTicksToShowWatch| ticks, animate the cursor.
//
// Note: assumes that the VBLTask, mTask, is the first member variable, so
// that we can piggy-back off the pointer to get to the rest of our data.
//
// (Do we still need the check for LMGetCrsrBusy()? It's not in carbon...)
//
pascal void
WatchTask :: DoWatchTask ( WatchTask* inSelf )
{
if ( inSelf->mChecksum == 'mozz' ) {
if ( !inSelf->mSuspended ) {
if ( !inSelf->mBusy && !LMGetCrsrBusy() ) {
if ( ::TickCount() - inSelf->mTicks > kTicksToShowWatch ) {
::SetAnimatedThemeCursor(kThemeWatchCursor, inSelf->mAnimation);
inSelf->mBusy = PR_TRUE;
}
}
else
::SetAnimatedThemeCursor(kThemeWatchCursor, inSelf->mAnimation);
// next frame in cursor animation
++inSelf->mAnimation;
}
// reset the task to fire again
inSelf->mTask.vblCount = kRepeatInterval;
} // if valid checksum
} // DoWatchTask
//
// EventLoopReached
//
// Called every time we reach the event loop (or an event loop), this tickles
// our internal tick count to reset the time since our last visit to WNE and
// if we were busy, we're not any more.
//
void
WatchTask :: EventLoopReached ( )
{
// reset the cursor if we were animating it
if ( mBusy )
::InitCursor();
mBusy = PR_FALSE;
mTicks = ::TickCount();
mAnimation = 0;
}

Просмотреть файл

@ -38,6 +38,9 @@
#ifndef nsMacMessagePump_h__
#define nsMacMessagePump_h__
#include <Retrace.h>
#include <Events.h>
#include "prtypes.h"
#include "nsIEventQueueService.h"
@ -46,6 +49,52 @@ class nsToolkit;
class nsMacMessageSink;
class nsMacTSMMessagePump;
//
// class WatchTask
//
// A nice little class that installs/removes a VBL to set the cursor to
// the watch if we're away from the event loop for a while. Will also
// animate the watch cursor.
//
class WatchTask
{
public:
WatchTask ( ) ;
~WatchTask ( ) ;
// call from the main event loop
void EventLoopReached ( ) ;
// turn off when we know we're going into an area where it's ok
// that WNE is not called (eg, the menu code)
void Suspend ( ) { mSuspended = PR_TRUE; };
void Resume ( ) { mSuspended = PR_FALSE; };
private:
enum {
kRepeatInterval = 10, // check every 1/6 of a second if we should show watch (10/60)
kTicksToShowWatch = 45, // show watch if haven't seen WNE for 3/4 second (45/60)
kStepsInAnimation = 12
};
// the VBL task
static pascal void DoWatchTask(WatchTask* theTaskPtr) ;
VBLTask mTask; // this must be first!!
long mChecksum; // 'mozz' to validate we have real data at interrupt time (not needed?)
void* mSelf; // so we can get back to |this| from the static routine
long mTicks; // last time the event loop was hit
PRPackedBool mBusy; // are we currently spinning the cursor?
PRPackedBool mSuspended; // set if we've temporarily suspended operation
PRPackedBool mInstallSucceeded; // did we succeed in installing the task? (used in dtor)
short mAnimation; // stage of animation
};
//================================================
// Macintosh Message Pump Class
@ -97,11 +146,10 @@ private:
public:
static void SetWindowlessMenuEventHandler(nsWindowlessMenuEventHandler func)
{gWindowlessMenuEventHandler = func;}
};
#endif // nsMacMessagePump_h__