338153 Frontport bug 332579 to trunk, consolidating the native event improvements made on the 1.8 branch (332579) and trunk (326273). r=josh sr=darin

This commit is contained in:
mark%moxienet.com 2006-05-17 19:07:05 +00:00
parent 0277af7788
commit a46bfe2646
14 changed files with 266 additions and 1353 deletions

View File

@ -70,11 +70,5 @@ EXPORTS = \
nsThemeConstants.h \
$(NULL)
ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
EXPORTS += \
nsRepeater.h \
$(NULL)
endif
include $(topsrcdir)/config/rules.mk

View File

@ -1,82 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsRepeater_h___
#define nsRepeater_h___
#include "nscore.h"
#include "widgetCore.h"
class EventRecord;
class NS_WIDGET Repeater
{
public:
Repeater();
virtual ~Repeater();
virtual void RepeatAction(const EventRecord &aMacEvent) {}
virtual void IdleAction(const EventRecord &aMacEvent) {}
void StartRepeating();
void StopRepeating();
void StartIdling();
void StopIdling();
static void DoRepeaters(const EventRecord &aMacEvent);
static void DoIdlers(const EventRecord &aMacEvent);
protected:
void AddToRepeatList();
void RemoveFromRepeatList();
void AddToIdleList();
void RemoveFromIdleList();
static Repeater* sRepeaters;
static Repeater* sIdlers;
bool mRepeating;
bool mIdling;
Repeater* mPrevRptr;
Repeater* mNextRptr;
Repeater* mPrevIdlr;
Repeater* mNextIdlr;
};
#endif

View File

@ -1,172 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* to build this, build mozilla/widget/macbuild/_WidgetSupport.mcp
* I hope I'm the last person to waste 30 minutes looking for the project that builds this file */
#pragma export on
#include "nsRepeater.h"
Repeater* Repeater::sRepeaters = NULL;
Repeater* Repeater::sIdlers = NULL;
Repeater::Repeater()
: mRepeating(false)
, mIdling(false)
, mPrevRptr(NULL)
, mNextRptr(NULL)
, mPrevIdlr(NULL)
, mNextIdlr(NULL)
{
}
Repeater::~Repeater()
{
if (mRepeating) RemoveFromRepeatList();
if (mIdling) RemoveFromIdleList();
}
// protected helper functs
//----------------------------------------------------------------------------
void Repeater::AddToRepeatList()
{
if (sRepeaters)
{
sRepeaters->mPrevRptr = this;
mNextRptr = sRepeaters;
}
sRepeaters = this;
}
//----------------------------------------------------------------------------
void Repeater::RemoveFromRepeatList()
{
if (sRepeaters == this) sRepeaters = mNextRptr;
if (mPrevRptr) mPrevRptr->mNextRptr = mNextRptr;
if (mNextRptr) mNextRptr->mPrevRptr = mPrevRptr;
mPrevRptr = NULL;
mNextRptr = NULL;
}
//----------------------------------------------------------------------------
void Repeater::AddToIdleList()
{
if (sIdlers)
{
sIdlers->mPrevIdlr = this;
mNextIdlr = sIdlers;
}
sIdlers = this;
}
//----------------------------------------------------------------------------
void Repeater::RemoveFromIdleList()
{
if (sIdlers == this) sIdlers = mNextIdlr;
if (mPrevIdlr) mPrevIdlr->mNextIdlr = mNextIdlr;
if (mNextIdlr) mNextIdlr->mPrevIdlr = mPrevIdlr;
mPrevIdlr = NULL;
mNextIdlr = NULL;
}
// repeater methods
//----------------------------------------------------------------------------
void Repeater::StartRepeating()
{
if (!mRepeating)
{
AddToRepeatList();
mRepeating = true;
}
}
void Repeater::StopRepeating()
{
if (mRepeating)
{
RemoveFromRepeatList();
mRepeating = false;
}
}
void Repeater::DoRepeaters(const EventRecord &aMacEvent)
{
Repeater* theRepeater = sRepeaters;
while (theRepeater)
{
Repeater* nextRepeater = theRepeater->mNextRptr;
theRepeater->RepeatAction(aMacEvent);
theRepeater = nextRepeater;
}
}
// idler methods
void Repeater::StartIdling()
{
if (!mIdling)
{
AddToIdleList();
mIdling = true;
}
}
void Repeater::StopIdling()
{
if (mIdling)
{
RemoveFromIdleList();
mIdling = false;
}
}
void Repeater::DoIdlers(const EventRecord &aMacEvent)
{
Repeater* theIdler = sIdlers;
while (theIdler)
{
Repeater* nextIdler = theIdler->mNextIdlr;
theIdler->IdleAction(aMacEvent);
theIdler = nextIdler;
}
}
#pragma export off

View File

@ -83,10 +83,6 @@ REQUIRES += glitz glitzagl
endif
endif
GFX_LCPPSRCS = \
nsRepeater.cpp \
$(NULL)
CPPSRCS = nsAppShell.cpp \
nsBidiKeyboard.cpp \
nsChildWindow.cpp \
@ -123,7 +119,6 @@ CPPSRCS = nsAppShell.cpp \
nsPrintOptionsX.cpp \
nsPrintSettingsX.cpp \
nsPrintSessionX.cpp \
$(GFX_LCPPSRCS) \
$(NULL)
XPIDLSRCS += \
@ -148,16 +143,11 @@ ifdef MOZ_ENABLE_CAIRO_GFX
EXTRA_DSO_LDOPTS += -lthebes
endif
GARBAGE += $(GFX_LCPPSRCS)
include $(topsrcdir)/config/rules.mk
RESOURCE = libwidget.rsrc
RES_SRC = $(srcdir)/nsMacWidget.r
export:: $(addprefix $(topsrcdir)/gfx/src/mac/,$(GFX_LCPPSRCS))
$(INSTALL) $^ .
$(RESOURCE): $(RES_SRC)
/Developer/Tools/Rez -i /Developer/Headers/FlatCarbon -useDF $< -o $@

View File

@ -47,36 +47,12 @@
#include "nsToolkit.h"
#include "nsMacMessagePump.h"
// kWNETransitionEventList
//
// This list encompasses all Carbon events that can be converted into
// EventRecords. Not all will necessarily be called; not all will necessarily
// be handled. Some items here may be redundant in that handlers are already
// installed elsewhere. This may need a good audit.
//
static const EventTypeSpec kWNETransitionEventList[] = {
{ kEventClassMouse, kEventMouseDown },
{ kEventClassMouse, kEventMouseUp },
{ kEventClassMouse, kEventMouseMoved },
{ kEventClassMouse, kEventMouseDragged },
{ kEventClassKeyboard, kEventRawKeyDown },
{ kEventClassKeyboard, kEventRawKeyUp },
{ kEventClassKeyboard, kEventRawKeyRepeat },
{ kEventClassWindow, kEventWindowUpdate },
{ kEventClassWindow, kEventWindowActivated },
{ kEventClassWindow, kEventWindowDeactivated },
{ kEventClassWindow, kEventWindowCursorChange },
{ kEventClassApplication, kEventAppActivated },
{ kEventClassApplication, kEventAppDeactivated },
{ kEventClassAppleEvent, kEventAppleEvent },
{ kEventClassControl, kEventControlTrack },
};
#include <Carbon/Carbon.h>
// nsAppShell implementation
nsAppShell::nsAppShell()
: mWNETransitionEventHandler(NULL)
, mCFRunLoop(NULL)
: mCFRunLoop(NULL)
, mCFRunLoopSource(NULL)
, mRunningEventLoop(PR_FALSE)
{
@ -92,9 +68,6 @@ nsAppShell::~nsAppShell()
if (mCFRunLoop)
::CFRelease(mCFRunLoop);
if (mWNETransitionEventHandler)
::RemoveEventHandler(mWNETransitionEventHandler);
}
// Init
@ -114,18 +87,10 @@ nsAppShell::Init()
return rv;
nsIToolkit *toolkit = mToolkit.get();
mMacPump = new nsMacMessagePump(static_cast<nsToolkit*>(toolkit));
if (!mMacPump.get() || !nsMacMemoryCushion::EnsureMemoryCushion())
mMacPump = new nsMacMessagePump(NS_STATIC_CAST(nsToolkit*, toolkit));
if (!mMacPump.get())
return NS_ERROR_OUT_OF_MEMORY;
OSStatus err = ::InstallApplicationEventHandler(
::NewEventHandlerUPP(WNETransitionEventHandler),
GetEventTypeCount(kWNETransitionEventList),
kWNETransitionEventList,
(void*)this,
&mWNETransitionEventHandler);
NS_ENSURE_TRUE(err == noErr, NS_ERROR_UNEXPECTED);
// Add a CFRunLoopSource to the main native run loop. The source is
// responsible for interrupting the run loop when Gecko events are ready.
@ -227,29 +192,3 @@ nsAppShell::ProcessGeckoEvents(void* aInfo)
NS_RELEASE(self);
}
// WNETransitionEventHandler
//
// Transitional WaitNextEvent handler. Accepts Carbon events from
// kWNETransitionEventList, converts them into EventRecords, and
// dispatches them through the path they would have gone if they
// had been received as EventRecords from WaitNextEvent.
//
// protected static
pascal OSStatus
nsAppShell::WNETransitionEventHandler(EventHandlerCallRef aHandlerCallRef,
EventRef aEvent,
void* aUserData)
{
nsAppShell* self = NS_STATIC_CAST(nsAppShell*, aUserData);
EventRecord eventRecord;
::ConvertEventRefToEventRecord(aEvent, &eventRecord);
PRBool handled = self->mMacPump->DispatchEvent(PR_TRUE, &eventRecord);
if (handled)
return noErr;
return eventNotHandledErr;
}

View File

@ -45,7 +45,6 @@
#ifndef nsAppShell_h__
#define nsAppShell_h__
#include <Carbon/Carbon.h>
#include <CoreFoundation/CoreFoundation.h>
#include "nsBaseAppShell.h"
@ -69,17 +68,11 @@ protected:
virtual PRBool ProcessNextNativeEvent(PRBool aMayWait);
static void ProcessGeckoEvents(void* aInfo);
static pascal OSStatus WNETransitionEventHandler(
EventHandlerCallRef aHandlerCallRef,
EventRef aEvent,
void* aUserData);
protected:
nsCOMPtr<nsIToolkit> mToolkit;
nsAutoPtr<nsMacMessagePump> mMacPump;
EventHandlerRef mWNETransitionEventHandler;
CFRunLoopRef mCFRunLoop;
CFRunLoopSourceRef mCFRunLoopSource;

View File

@ -92,6 +92,20 @@ nsMacEventDispatchHandler gEventDispatchHandler;
static void ConvertKeyEventToContextMenuEvent(const nsKeyEvent* inKeyEvent, nsMouseEvent* outCMEvent);
static inline PRBool IsContextMenuKey(const nsKeyEvent& inKeyEvent);
class StPackedBoolSetter {
public:
StPackedBoolSetter(PRPackedBool& aFlag): mFlag(aFlag) {
mFlag = PR_TRUE;
};
~StPackedBoolSetter() {
mFlag = PR_FALSE;
};
protected:
PRPackedBool& mFlag;
};
//-------------------------------------------------------------------------
//
@ -379,6 +393,7 @@ nsMacEventHandler::nsMacEventHandler(nsMacWindow* aTopLevelWidget)
mIMEIsComposing = PR_FALSE;
mIMECompositionStr = nsnull;
mHandlingKeyEvent = PR_FALSE;
}
@ -1030,6 +1045,12 @@ PRUint32 nsMacEventHandler::ConvertKeyEventToUnicode(EventRecord& aOSEvent)
PRBool nsMacEventHandler::HandleKeyEvent(EventRecord& aOSEvent)
{
// Avoid reentrancy
if (mHandlingKeyEvent)
return PR_FALSE;
StPackedBoolSetter handling(mHandlingKeyEvent);
nsresult result = NS_ERROR_UNEXPECTED;
nsWindow* checkFocusedWidget;
@ -1145,6 +1166,12 @@ IsContextMenuKey(const nsKeyEvent& inKeyEvent)
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleUKeyEvent(const PRUnichar* text, long charCount, EventRecord& aOSEvent)
{
// Avoid reentrancy
if (mHandlingKeyEvent)
return PR_FALSE;
StPackedBoolSetter handling(mHandlingKeyEvent);
nsresult result = NS_ERROR_UNEXPECTED;
// get the focused widget
nsWindow* focusedWidget = gEventDispatchHandler.GetActive();

View File

@ -170,8 +170,9 @@ protected:
RgnHandle mUpdateRgn;
TSMDocumentID mTSMDocument;
nsPoint mIMEPos;
PRBool mIMEIsComposing;
nsAutoString *mIMECompositionStr;
PRPackedBool mIMEIsComposing;
PRPackedBool mHandlingKeyEvent;
};
#endif // MacMacEventHandler_h__

View File

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mark Mentovai <mark@moxienet.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -35,454 +36,188 @@
*
* ***** END LICENSE BLOCK ***** */
//
// nsMacMessagePump
//
// This file contains the default implementation for the mac event loop. Events that
// pertain to the layout engine are routed there via a MessageSink that is passed in
// at creation time. Events not destined for layout are handled here (such as window
// moved).
//
// Clients may either use this implementation or write their own. Embedding applications
// will almost certainly write their own because they will want control of the event
// loop to do other processing. There is nothing in the architecture which forces the
// embedding app to use anything called a "message pump" so the event loop can actually
// live anywhere the app wants.
//
/*
* Dispatcher for a variety of application-scope events. The real event loop
* is in nsAppShell.
*/
#include "nsMacMessagePump.h"
#include "nsWidgetsCID.h"
#include "nsToolkit.h"
#include "nscore.h"
#include "nsRepeater.h"
#include "nsIServiceManager.h"
#include "prthread.h"
#include "nsMacTSMMessagePump.h"
#include "nsIRollupListener.h"
#include "nsIWidget.h"
#include "nsGfxUtils.h"
#include "nsMacWindow.h"
#include <MacWindows.h>
#include <ToolUtils.h>
#ifndef XP_MACOSX
#include <DiskInit.h>
#endif
#include <Devices.h>
#include <LowMem.h>
#include <Sound.h>
#include <Quickdraw.h>
#include "nsCarbonHelpers.h"
#include "nsIEventSink.h"
#include "nsIRollupListener.h"
#include "nsIWidget.h"
#include "nsPIWidgetMac.h"
#include "nsPIEventSinkStandalone.h"
//#include "nsISocketTransportService.h"
//include "nsIFileTransportService.h"
#include "nsGfxUtils.h"
#include "nsGUIEvent.h"
#include "nsMacTSMMessagePump.h"
#include "nsToolkit.h"
#if !XP_MACOSX
#include "MenuSharing.h"
#endif
#ifndef topLeft
#define topLeft(r) (((Point *) &(r))[0])
#endif
#include <Carbon/Carbon.h>
#ifndef botRight
#define botRight(r) (((Point *) &(r))[1])
#endif
#if DEBUG && !defined(XP_MACOSX)
#include <SIOUX.h>
#include "macstdlibextras.h"
#endif
#define DRAW_ON_RESIZE 0 // if 1, enable live-resize except when the command key is down
const short kMinWindowWidth = 125;
const short kMinWindowHeight = 150;
extern nsIRollupListener * gRollupListener;
extern nsIWidget * gRollupWidget;
//======================================================================================
// PROFILE
//======================================================================================
#ifdef DEBUG
// Important Notes:
// ----------------
//
// - To turn the profiler on, define "#pragma profile on" in IDE_Options.h
// then set $PROFILE to 1 in BuildNGLayoutDebug.pl and recompile everything.
//
// - You may need to turn the profiler off ("#pragma profile off")
// in NSPR.Debug.Prefix because of incompatiblity with NSPR threads.
// It usually isn't a problem but it may be one when profiling things like
// imap or network i/o.
//
// - The profiler utilities (ProfilerUtils.c) and the profiler
// shared library (ProfilerLib) sit in NSRuntime.mcp.
//
// Define this if you want to start profiling when the Caps Lock
// key is pressed. Press Caps Lock, start the command you want to
// profile, release Caps Lock when the command is done. It works
// for all the major commands: display a page, open a window, etc...
//
// If you want to profile the project, you must make sure that the
// global prefix file (IDE_Options.h) contains "#pragma profile on".
//#define PROFILE
// Define this if you want to let the profiler run while you're
// spending time in other apps. Usually you don't.
//#define PROFILE_WAITNEXTEVENT
#ifdef PROFILE
#include "ProfilerUtils.h"
#endif //PROFILE
#endif //DEBUG
#pragma mark -
#if !XP_MACOSX
#pragma mark MenuSharingToolkitSupport
//=================================================================
static pascal void ErrorDialog (Str255 s)
{
//ParamText (s, "\p", "\p", "\p");
//Alert (kMenuSharingAlertID, nil);
}
//=================================================================
static pascal void EventFilter (EventRecord *ev)
{
// Hrm, prolly should do _something_ here
}
#pragma mark -
#endif
//=================================================================
/* Constructor
* @update dc 08/31/98
* @param aToolkit -- The toolkit created by the application
* @return NONE
*/
nsMacMessagePump::nsMacMessagePump(nsToolkit *aToolkit)
: mToolkit(aToolkit), mTSMMessagePump(NULL)
: mToolkit(aToolkit)
, mMouseClickEventHandler(NULL)
, mWNETransitionEventHandler(NULL)
{
mRunning = PR_FALSE;
mMouseRgn = ::NewRgn();
NS_ASSERTION(mToolkit, "No toolkit");
// This list encompasses all Carbon events that can be converted into
// EventRecords. Not all will necessarily be called; not all will necessarily
// be handled. Some items here may be redundant in that handlers are already
// installed elsewhere. This may need a good audit.
const EventTypeSpec kWNETransitionEventList[] = {
{ kEventClassMouse, kEventMouseDown },
{ kEventClassMouse, kEventMouseUp },
{ kEventClassMouse, kEventMouseMoved },
{ kEventClassMouse, kEventMouseDragged },
{ kEventClassKeyboard, kEventRawKeyDown },
{ kEventClassKeyboard, kEventRawKeyUp },
{ kEventClassKeyboard, kEventRawKeyRepeat },
{ kEventClassWindow, kEventWindowUpdate },
{ kEventClassWindow, kEventWindowActivated },
{ kEventClassWindow, kEventWindowDeactivated },
{ kEventClassWindow, kEventWindowCursorChange },
{ kEventClassApplication, kEventAppActivated },
{ kEventClassApplication, kEventAppDeactivated },
{ kEventClassAppleEvent, kEventAppleEvent },
{ kEventClassControl, kEventControlTrack },
};
static EventHandlerUPP sWNETransitionEventHandlerUPP;
if (!sWNETransitionEventHandlerUPP)
sWNETransitionEventHandlerUPP =
::NewEventHandlerUPP(WNETransitionEventHandler);
OSStatus err =
::InstallApplicationEventHandler(sWNETransitionEventHandlerUPP,
GetEventTypeCount(kWNETransitionEventList),
kWNETransitionEventList,
NS_STATIC_CAST(void*, this),
&mWNETransitionEventHandler);
NS_ASSERTION(err == noErr, "Could not install WNETransitionEventHandler");
// For middle clicks. Install this handler second, because
// WNETransitionEventHandler swallows all events, and MouseClickEventHandler
// needs to be able to handle mouse-click events (punting non-middle-click
// ones).
const EventTypeSpec kMouseClickEventList[] = {
{ kEventClassMouse, kEventMouseDown },
{ kEventClassMouse, kEventMouseUp },
};
static EventHandlerUPP sMouseClickEventHandlerUPP;
if (!sMouseClickEventHandlerUPP)
sMouseClickEventHandlerUPP = ::NewEventHandlerUPP(MouseClickEventHandler);
err =
::InstallApplicationEventHandler(sMouseClickEventHandlerUPP,
GetEventTypeCount(kMouseClickEventList),
kMouseClickEventList,
NS_STATIC_CAST(void*, this),
&mMouseClickEventHandler);
NS_ASSERTION(err == noErr, "Could not install MouseClickEventHandler");
//
// create the TSM Message Pump
//
mTSMMessagePump = nsMacTSMMessagePump::GetSingleton();
NS_ASSERTION(mTSMMessagePump!=NULL,"nsMacMessagePump::nsMacMessagePump: Unable to create TSM Message Pump.");
#if !XP_MACOSX
// added to support Menu Sharing API. Initializes the Menu Sharing API.
InitSharedMenus (ErrorDialog, EventFilter);
#endif
// To handle middle-button clicks we must use Carbon Events
const EventTypeSpec eventTypes[] = {
{ kEventClassMouse, kEventMouseDown },
{ kEventClassMouse, kEventMouseUp }
};
EventHandlerUPP handlerUPP =
::NewEventHandlerUPP(nsMacMessagePump::CarbonMouseHandler);
::InstallApplicationEventHandler(handlerUPP, GetEventTypeCount(eventTypes),
eventTypes, (void*)this, NULL);
nsMacTSMMessagePump* tsmMessagePump = nsMacTSMMessagePump::GetSingleton();
NS_ASSERTION(tsmMessagePump, "Unable to create TSM Message Pump");
}
//=================================================================
/* Destructor
* @update dc 08/31/98
* @param NONE
* @return NONE
*/
nsMacMessagePump::~nsMacMessagePump()
{
if (mMouseRgn)
::DisposeRgn(mMouseRgn);
if (mMouseClickEventHandler)
::RemoveEventHandler(mMouseClickEventHandler);
//¥TODO? release the toolkits and sinks? not if we use COM_auto_ptr.
//
// release the TSM Message Pump
//
}
if (mWNETransitionEventHandler)
::RemoveEventHandler(mWNETransitionEventHandler);
//=================================================================
/* Return the frontmost window that is not the SIOUX console
*/
WindowPtr nsMacMessagePump::GetFrontApplicationWindow()
{
WindowPtr firstAppWindow = ::FrontWindow();
#if DEBUG && !defined(XP_MACOSX)
if (IsSIOUXWindow(firstAppWindow))
firstAppWindow = ::GetNextWindow(firstAppWindow);
#endif
return firstAppWindow;
}
//=================================================================
/* Runs the message pump for the macintosh
* @update dc 08/31/98
* @param NONE
*/
void nsMacMessagePump::DoMessagePump()
{
PRBool haveEvent;
EventRecord theEvent;
nsToolkit::AppInForeground();
while (mRunning)
{
#ifdef PROFILE
if (KeyDown(0x39)) // press [caps lock] to start the profile
ProfileStart();
else
ProfileStop();
#endif // PROFILE
#ifdef PROFILE
#ifndef PROFILE_WAITNEXTEVENT
ProfileSuspend();
#endif // PROFILE_WAITNEXTEVENT
#endif // PROFILE
haveEvent = GetEvent(theEvent, PR_TRUE);
#ifdef PROFILE
#ifndef PROFILE_WAITNEXTEVENT
ProfileResume();
#endif // PROFILE_WAITNEXTEVENT
#endif // PROFILE
DispatchEvent(haveEvent, &theEvent);
}
}
//static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID);
//static NS_DEFINE_CID(kFileTransportServiceCID, NS_FILETRANSPORTSERVICE_CID);
//#define BUSINESS_INDICATOR
#define kIdleHysterysisTicks 60
//=================================================================
/* Return TRUE if the program is busy, like doing network stuff.
*
*/
PRBool nsMacMessagePump::BrowserIsBusy()
{
// we avoid frenetic oscillations between busy and idle states by not going
// idle for a few ticks after we've detected idleness. This was added after
// observing rapid busy/idle oscillations during chrome loading.
static PRUint32 sNextIdleTicks = 0;
PRBool foundActivity = PR_TRUE;
do // convenience for breaking. We'll start by assuming that we're busy.
{
/*
* Don't count connections for now; mailnews holds server connections open,
* and that causes us to behave as busy even when we're not, which eats CPU
* time and makes machines run hot.
nsCOMPtr<nsISocketTransportService> socketTransport = do_GetService(kSocketTransportServiceCID);
if (socketTransport)
{
PRUint32 inUseTransports;
socketTransport->GetInUseTransportCount(&inUseTransports);
if (inUseTransports > 0)
break;
}
nsCOMPtr<nsIFileTransportService> fileTransport = do_GetService(kFileTransportServiceCID);
if (fileTransport)
{
PRUint32 inUseTransports;
fileTransport->GetInUseTransportCount(&inUseTransports);
if (inUseTransports > 0)
break;
}
*/
if (mToolkit->ToolkitBusy())
break;
foundActivity = PR_FALSE;
} while(0);
PRBool isBusy = foundActivity;
if (foundActivity)
sNextIdleTicks = ::TickCount() + kIdleHysterysisTicks;
else if (::TickCount() < sNextIdleTicks)
isBusy = PR_TRUE;
#ifdef BUSINESS_INDICATOR
static PRBool wasBusy;
if (isBusy != wasBusy)
{
printf("*** Message pump became %s at %ld (next idle %ld)\n", isBusy ? "busy" : "idle", ::TickCount(), sNextIdleTicks);
wasBusy = isBusy;
}
#endif
return isBusy;
}
//=================================================================
/* Fetch a single event
* @update dc 08/31/98
* @param NONE
* @return A boolean which states whether we have a real event
*/
PRBool nsMacMessagePump::GetEvent(EventRecord &theEvent, PRBool mayWait)
{
PRBool inForeground = nsToolkit::IsAppInForeground();
PRBool buttonDown = ::Button();
// when in the background, we don't want to chew up time processing mouse move
// events, so set the mouse region to null. If we're in the fg, however,
// we want every mouseMove event we can get our grubby little hands on, so set
// it to a 1x1 rect.
RgnHandle mouseRgn = inForeground ? mMouseRgn : nsnull;
// if the mouse is down, and we're in the foreground, then eat
// CPU so we respond quickly when scrolling etc.
SInt32 sleepTime = (!mayWait || (buttonDown && inForeground)) ? 0 : 5;
::SetEventMask(everyEvent); // we need keyUp events
PRBool haveEvent = ::WaitNextEvent(everyEvent, &theEvent, sleepTime, mouseRgn);
return haveEvent;
nsMacTSMMessagePump::Shutdown();
}
//=================================================================
/* Dispatch a single event
* @param theEvent - the event to dispatch
* @param anEvent - the event to dispatch
* @return A boolean which states whether we handled the event
*/
PRBool nsMacMessagePump::DispatchEvent(PRBool aRealEvent, EventRecord *anEvent)
PRBool nsMacMessagePump::DispatchEvent(EventRecord *anEvent)
{
PRBool handled = PR_FALSE;
if (aRealEvent == PR_TRUE)
{
#if DEBUG && !defined(XP_MACOSX)
if ((anEvent->what != kHighLevelEvent) && SIOUXHandleOneEvent(anEvent))
return PR_TRUE;
#endif
switch(anEvent->what) {
// diskEvt is gone in Carbon, and so is unhandled here.
switch(anEvent->what)
{
case keyUp:
case keyDown:
case autoKey:
handled = DoKey(*anEvent);
break;
case keyUp:
case keyDown:
case autoKey:
handled = DoKey(*anEvent);
break;
case mouseDown:
handled = DoMouseDown(*anEvent);
break;
case mouseDown:
handled = DoMouseDown(*anEvent);
break;
case mouseUp:
handled = DoMouseUp(*anEvent);
break;
case mouseUp:
handled = DoMouseUp(*anEvent);
break;
case updateEvt:
handled = DoUpdate(*anEvent);
break;
case updateEvt:
handled = DoUpdate(*anEvent);
break;
case activateEvt:
handled = DoActivate(*anEvent);
break;
case activateEvt:
handled = DoActivate(*anEvent);
break;
case diskEvt:
handled = DoDisk(*anEvent);
break;
case osEvt: {
unsigned char eventType = ((anEvent->message >> 24) & 0x00ff);
switch (eventType)
{
case suspendResumeMessage:
if (anEvent->message & resumeFlag)
nsToolkit::AppInForeground(); // resume message
else
nsToolkit::AppInBackground(); // suspend message
case osEvt:
{
unsigned char eventType = ((anEvent->message >> 24) & 0x00ff);
switch (eventType)
{
case suspendResumeMessage:
if ( anEvent->message & resumeFlag )
nsToolkit::AppInForeground(); // resume message
else
nsToolkit::AppInBackground(); // suspend message
handled = DoMouseMove(*anEvent);
break;
case mouseMovedMessage:
handled = DoMouseMove(*anEvent);
break;
}
}
break;
case kHighLevelEvent:
::AEProcessAppleEvent(anEvent);
handled = PR_TRUE;
break;
handled = DoMouseMove(*anEvent);
break;
case mouseMovedMessage:
handled = DoMouseMove(*anEvent);
break;
}
break;
}
case kHighLevelEvent:
::AEProcessAppleEvent(anEvent);
handled = PR_TRUE;
break;
}
else
{
DoIdle(*anEvent);
if (mRunning)
Repeater::DoIdlers(*anEvent);
// yield to other threads
::PR_Sleep(PR_INTERVAL_NO_WAIT);
handled = PR_FALSE;
}
if (mRunning)
Repeater::DoRepeaters(*anEvent);
NS_ASSERTION(ValidateDrawingState(), "Bad drawing state");
return handled;
}
#pragma mark -
//-------------------------------------------------------------------------
//
// DoUpdate
//
//-------------------------------------------------------------------------
//#include "ProfilerUtils.h"
PRBool nsMacMessagePump::DoUpdate(EventRecord &anEvent)
{
WindowPtr whichWindow = reinterpret_cast<WindowPtr>(anEvent.message);
StPortSetter portSetter(whichWindow);
@ -494,7 +229,6 @@ PRBool nsMacMessagePump::DoUpdate(EventRecord &anEvent)
return PR_TRUE;
}
//-------------------------------------------------------------------------
//
// DoMouseDown
@ -530,15 +264,8 @@ PRBool nsMacMessagePump::DoMouseDown(EventRecord &anEvent)
}
else
{
long menuResult = ::MenuSelect(anEvent.where);
::MenuSelect(anEvent.where);
handled = PR_TRUE;
#if USE_MENUSELECT
if (HiWord(menuResult) != 0)
{
menuResult = ConvertOSMenuResultToPPMenuResult(menuResult);
handled = DoMenu(anEvent, menuResult);
}
#endif
}
break;
@ -629,74 +356,21 @@ PRBool nsMacMessagePump::DoMouseDown(EventRecord &anEvent)
{
nsGraphicsUtils::SafeSetPortWindowPort(whichWindow);
// use the cmd-key to do the opposite of the DRAW_ON_RESIZE setting.
Boolean cmdKeyDown = (anEvent.modifiers & cmdKey) != 0;
Boolean drawOnResize = DRAW_ON_RESIZE ? !cmdKeyDown : cmdKeyDown;
if (drawOnResize)
{
Point oldPt = anEvent.where;
while (::WaitMouseUp())
{
Repeater::DoRepeaters(anEvent);
Rect sizeLimit;
sizeLimit.top = kMinWindowHeight;
sizeLimit.left = kMinWindowWidth;
sizeLimit.bottom = 0x7FFF;
sizeLimit.right = 0x7FFF;
Point origin = {0,0};
::LocalToGlobal(&origin);
Point newPt;
::GetMouse(&newPt);
::LocalToGlobal(&newPt);
if (::DeltaPoint(oldPt, newPt))
{
Rect portRect;
::GetWindowPortBounds(whichWindow, &portRect);
Rect newSize;
::ResizeWindow(whichWindow, anEvent.where, &sizeLimit, &newSize);
short width = newPt.h - origin.h;
short height = newPt.v - origin.v;
if (width < kMinWindowWidth)
width = kMinWindowWidth;
if (height < kMinWindowHeight)
height = kMinWindowHeight;
Point newPt = botRight(newSize);
::LocalToGlobal(&newPt);
newPt.h -= 8, newPt.v -= 8;
anEvent.where = newPt; // important!
handled = DispatchOSEventToRaptor(anEvent, whichWindow);
oldPt = newPt;
::SizeWindow(whichWindow, width, height, true);
// simulate a click in the grow icon
anEvent.where.h = width - 8; // on Aqua, clicking at (width, height) misses the grow icon. inset a bit.
anEvent.where.v = height - 8;
::LocalToGlobal(&anEvent.where);
DispatchOSEventToRaptor(anEvent, whichWindow);
Boolean haveEvent;
EventRecord updateEvent;
haveEvent = ::WaitNextEvent(updateMask, &updateEvent, 0, nil);
if (haveEvent)
DoUpdate(updateEvent);
}
}
handled = PR_TRUE;
}
else
{
Rect sizeRect;
::GetRegionBounds(::GetGrayRgn(), &sizeRect);
/* rjc sez (paraphrased) the maximum window size could also reasonably be
taken from the size of ::GetRegionBounds(::GetGrayRgn(),...) (not simply
the region bounds, but its width and height) or perhaps the size of the
screen to which the window mostly belongs. But why be so restrictive? */
sizeRect.top = kMinWindowHeight;
sizeRect.left = kMinWindowWidth;
sizeRect.bottom = 0x7FFF;
sizeRect.right = 0x7FFF;
long newSize = ::GrowWindow(whichWindow, anEvent.where, &sizeRect);
if (newSize != 0)
::SizeWindow(whichWindow, newSize & 0x0FFFF, (newSize >> 16) & 0x0FFFF, true);
Rect portRect;
Point newPt = botRight(*::GetWindowPortBounds(whichWindow, &portRect));
::LocalToGlobal(&newPt);
newPt.h -= 8, newPt.v -= 8;
anEvent.where = newPt; // important!
handled = DispatchOSEventToRaptor(anEvent, whichWindow);
}
break;
}
@ -739,7 +413,6 @@ PRBool nsMacMessagePump::DoMouseDown(EventRecord &anEvent)
return handled;
}
//-------------------------------------------------------------------------
//
// DoMouseUp
@ -757,7 +430,7 @@ PRBool nsMacMessagePump::DoMouseUp(EventRecord &anEvent)
// when the user clicks a widget, keeps the mouse button pressed and
// releases it outside the window, the event needs to be reported to
// the widget so that it can deactivate itself.
whichWindow = GetFrontApplicationWindow();
whichWindow = ::FrontWindow();
}
PRBool handled = DispatchOSEventToRaptor(anEvent, whichWindow);
@ -779,15 +452,9 @@ PRBool nsMacMessagePump::DoMouseMove(EventRecord &anEvent)
PRInt16 partCode;
PRBool handled = PR_FALSE;
if (mMouseRgn)
{
Point globalMouse = anEvent.where;
::SetRectRgn(mMouseRgn, globalMouse.h, globalMouse.v, globalMouse.h + 1, globalMouse.v + 1);
}
partCode = ::FindWindow(anEvent.where, &whichWindow);
if (whichWindow == nil)
whichWindow = GetFrontApplicationWindow();
whichWindow = ::FrontWindow();
/* Disable mouse moved events for windowshaded windows -- this prevents tooltips
from popping up in empty space.
@ -797,7 +464,6 @@ PRBool nsMacMessagePump::DoMouseMove(EventRecord &anEvent)
return handled;
}
//-------------------------------------------------------------------------
//
// DoKey
@ -808,82 +474,10 @@ PRBool nsMacMessagePump::DoMouseMove(EventRecord &anEvent)
PRBool nsMacMessagePump::DoKey(EventRecord &anEvent)
{
PRBool handled = PR_FALSE;
{
handled = DispatchOSEventToRaptor(anEvent, GetFrontApplicationWindow());
#if USE_MENUSELECT
/* we want to call this if cmdKey is pressed and no other modifier keys are pressed */
if((!handled) && (anEvent.what == keyDown) && (anEvent.modifiers == cmdKey) )
{
// do a menu key command
long menuResult = ::MenuKey(theChar);
if (HiWord(menuResult) != 0)
{
menuResult = ConvertOSMenuResultToPPMenuResult(menuResult);
DoMenu(anEvent, menuResult);
handled = PR_TRUE;
}
}
#endif
}
handled = DispatchOSEventToRaptor(anEvent, ::FrontWindow());
return handled;
}
//-------------------------------------------------------------------------
//
// DoDisk
//
//-------------------------------------------------------------------------
PRBool nsMacMessagePump::DoDisk(const EventRecord& anEvent)
{
return PR_FALSE;
}
//-------------------------------------------------------------------------
//
// DoMenu
//
//-------------------------------------------------------------------------
extern Boolean SIOUXIsAppWindow(WindowPtr window);
#if USE_MENUSELECT
PRBool nsMacMessagePump::DoMenu(EventRecord &anEvent, long menuResult)
{
// The app can handle its menu commands here or
// in the nsNativeBrowserWindow and nsNativeViewerApp
extern const PRInt16 kAppleMenuID; // Danger Will Robinson!!! - this currently requires
// APPLE_MENU_HACK to be defined in nsMenu.h
// One of these days it'll become a non-hack
// and things will be less convoluted
// See if it was the Apple Menu
if (HiWord(menuResult) == kAppleMenuID)
{
short theItem = LoWord(menuResult);
if (theItem > 2)
{
Str255 daName;
GrafPtr savePort;
::GetMenuItemText(::GetMenuHandle(kAppleMenuID), theItem, daName);
::GetPort(&savePort);
::OpenDeskAcc(daName);
::SetPort(savePort);
HiliteMenu(0);
return PR_TRUE;
}
}
// Note that we still give Raptor a shot at the event as it will eventually
// handle the About... selection
PRBool handled = DispatchMenuCommandToRaptor(anEvent, menuResult);
HiliteMenu(0);
return handled;
}
#endif
//-------------------------------------------------------------------------
//
// DoActivate
@ -918,40 +512,6 @@ PRBool nsMacMessagePump::DoActivate(EventRecord &anEvent)
return DispatchOSEventToRaptor(anEvent, whichWindow);
}
//-------------------------------------------------------------------------
//
// DoIdle
//
//-------------------------------------------------------------------------
void nsMacMessagePump::DoIdle(EventRecord &anEvent)
{
// send mouseMove event
static Point lastWhere = {0, 0};
#if !XP_MACOSX
if ( nsToolkit::IsAppInForeground() )
{
// Shared Menu support - note we hardcode first menu ID available as 31000
CheckSharedMenus(31000);
}
#endif
if (*(long*)&lastWhere == *(long*)&anEvent.where)
return;
EventRecord localEvent = anEvent;
localEvent.what = nullEvent;
lastWhere = localEvent.where;
if ( nsToolkit::IsAppInForeground() )
DoMouseMove(localEvent);
}
#pragma mark -
//-------------------------------------------------------------------------
//
// DispatchOSEventToRaptor
@ -969,71 +529,68 @@ PRBool nsMacMessagePump::DispatchOSEventToRaptor(
return handled;
}
#if USE_MENUSELECT
//-------------------------------------------------------------------------
//
// DispatchMenuCommandToRaptor
//
//-------------------------------------------------------------------------
PRBool nsMacMessagePump::DispatchMenuCommandToRaptor(
EventRecord &anEvent,
long menuResult)
{
PRBool handled = PR_FALSE;
WindowPtr theFrontWindow = GetFrontApplicationWindow();
nsCOMPtr<nsIEventSink> sink;
nsToolkit::GetWindowEventSink ( theFrontWindow, getter_AddRefs(sink) );
nsCOMPtr<nsPIEventSinkStandalone> menuSink ( do_QueryInterface(sink) );
if ( menuSink )
menuSink->DispatchMenuEvent ( &anEvent, menuResult, &handled );
return handled;
}
#endif // USE_MENUSELECT
//-------------------------------------------------------------------------
//
// CarbonMouseHandler
//
//-------------------------------------------------------------------------
pascal OSStatus nsMacMessagePump::CarbonMouseHandler(
EventHandlerCallRef nextHandler,
EventRef theEvent, void *userData)
pascal OSStatus
nsMacMessagePump::MouseClickEventHandler(EventHandlerCallRef aHandlerCallRef,
EventRef aEvent,
void* aUserData)
{
EventMouseButton button;
OSErr err = ::GetEventParameter(theEvent, kEventParamMouseButton,
OSErr err = ::GetEventParameter(aEvent, kEventParamMouseButton,
typeMouseButton, NULL,
sizeof(EventMouseButton), NULL, &button);
if (err != noErr)
// Only handle middle click events here. Let the rest fall through.
if (err != noErr || button != kEventMouseButtonTertiary)
return eventNotHandledErr;
// Only handle middle click events here. Let the rest fall through to
// WaitNextEvent().
if (button != kEventMouseButtonTertiary)
return eventNotHandledErr;
EventRecord theRecord;
if (!::ConvertEventRefToEventRecord(theEvent, &theRecord)) {
EventRecord eventRecord;
if (!::ConvertEventRefToEventRecord(aEvent, &eventRecord)) {
// This will return FALSE on a middle click event; that's to let us know
// it's giving us a nullEvent, which is expected since Classic events
// don't support the middle button normally.
//
// We know better, so let's restore the actual event kind.
UInt32 kind = ::GetEventKind(theEvent);
theRecord.what = (kind == kEventMouseDown) ? mouseDown : mouseUp;
UInt32 kind = ::GetEventKind(aEvent);
eventRecord.what = (kind == kEventMouseDown) ? mouseDown : mouseUp;
}
// Classic mouse events don't record the button specifier. The message
// parameter is unused in mouse click events, so let's stuff it there.
// We'll pick it up in nsMacEventHandler::HandleMouseDownEvent().
theRecord.message = (UInt32)button;
eventRecord.message = NS_STATIC_CAST(UInt32, button);
// Process the modified event internally
nsMacMessagePump *pump = (nsMacMessagePump*)userData;
PRBool handled = pump->DispatchEvent(PR_TRUE, &theRecord);
return handled ? noErr : eventNotHandledErr;
nsMacMessagePump* self = NS_STATIC_CAST(nsMacMessagePump*, aUserData);
PRBool handled = self->DispatchEvent(&eventRecord);
if (handled)
return noErr;
return eventNotHandledErr;
}
// WNETransitionEventHandler
//
// Transitional WaitNextEvent handler. Accepts Carbon events from
// kWNETransitionEventList, converts them into EventRecords, and
// dispatches them through the path they would have gone if they
// had been received as EventRecords from WaitNextEvent.
//
// protected static
pascal OSStatus
nsMacMessagePump::WNETransitionEventHandler(EventHandlerCallRef aHandlerCallRef,
EventRef aEvent,
void* aUserData)
{
nsMacMessagePump* self = NS_STATIC_CAST(nsMacMessagePump*, aUserData);
EventRecord eventRecord;
::ConvertEventRefToEventRecord(aEvent, &eventRecord);
PRBool handled = self->DispatchEvent(&eventRecord);
if (!handled)
return eventNotHandledErr;
return noErr;
}

View File

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mark Mentovai <mark@moxienet.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -35,89 +36,56 @@
*
* ***** END LICENSE BLOCK ***** */
//
// nsMacMessagePump
//
// This file contains the default implementation for the mac event loop. Events that
// pertain to the layout engine are routed there via a MessageSink that is passed in
// at creation time. Events not destined for layout are handled here (such as window
// moved).
//
// Clients may either use this implementation or write their own. Embedding applications
// will almost certainly write their own because they will want control of the event
// loop to do other processing. There is nothing in the architecture which forces the
// embedding app to use anything called a "message pump" so the event loop can actually
// live anywhere the app wants.
//
/*
* Dispatcher for a variety of application-scope events. The real event loop
* is in nsAppShell.
*/
#ifndef nsMacMessagePump_h__
#define nsMacMessagePump_h__
#include "prtypes.h"
#include <Events.h>
#include "prtypes.h"
class nsToolkit;
class nsMacTSMMessagePump;
class nsIEventSink;
class nsIWidget;
//================================================
// Macintosh Message Pump Class
class nsMacMessagePump
{
// CLASS MEMBERS
private:
PRBool mRunning;
Point mMousePoint; // keep track of where the mouse is at all times
RgnHandle mMouseRgn;
nsToolkit* mToolkit;
nsMacTSMMessagePump* mTSMMessagePump;
public:
nsMacMessagePump(nsToolkit *aToolKit);
virtual ~nsMacMessagePump();
// CLASS METHODS
public:
nsMacMessagePump(nsToolkit *aToolKit);
virtual ~nsMacMessagePump();
PRBool ProcessEvents(PRBool aProcessEvents);
void DoMessagePump();
PRBool GetEvent(EventRecord &theEvent, PRBool mayWait);
// returns true if handled
PRBool DispatchEvent(PRBool aRealEvent, EventRecord *anEvent);
void StartRunning() {mRunning = PR_TRUE;}
void StopRunning() {mRunning = PR_FALSE;}
// returns PR_TRUE if the event was handled
PRBool DispatchEvent(EventRecord *anEvent);
private:
protected:
// these all return PR_TRUE if the event was handled
PRBool DoMouseDown(EventRecord &anEvent);
PRBool DoMouseUp(EventRecord &anEvent);
PRBool DoMouseMove(EventRecord &anEvent);
PRBool DoUpdate(EventRecord &anEvent);
PRBool DoKey(EventRecord &anEvent);
PRBool DoActivate(EventRecord &anEvent);
// these all return PR_TRUE if the event was handled
PRBool DoMouseDown(EventRecord &anEvent);
PRBool DoMouseUp(EventRecord &anEvent);
PRBool DoMouseMove(EventRecord &anEvent);
PRBool DoUpdate(EventRecord &anEvent);
PRBool DoKey(EventRecord &anEvent);
#if USE_MENUSELECT
PRBool DoMenu(EventRecord &anEvent, long menuResult);
#endif
PRBool DoDisk(const EventRecord &anEvent);
PRBool DoActivate(EventRecord &anEvent);
void DoIdle(EventRecord &anEvent);
PRBool DispatchOSEventToRaptor(EventRecord &anEvent, WindowPtr aWindow);
PRBool DispatchOSEventToRaptor(EventRecord &anEvent, WindowPtr aWindow);
#if USE_MENUSELECT
PRBool DispatchMenuCommandToRaptor(EventRecord &anEvent, long menuResult);
#endif
static pascal OSStatus MouseClickEventHandler(
EventHandlerCallRef aHandlerCallRef,
EventRef aEvent,
void* aUserData);
static pascal OSStatus WNETransitionEventHandler(
EventHandlerCallRef aHandlerCallRef,
EventRef aEvent,
void* aUserData);
PRBool BrowserIsBusy();
WindowPtr GetFrontApplicationWindow();
static pascal OSStatus CarbonMouseHandler(EventHandlerCallRef nextHandler,
EventRef theEvent, void *userData);
protected:
nsToolkit* mToolkit;
nsMacTSMMessagePump* mTSMMessagePump;
EventHandlerRef mMouseClickEventHandler;
EventHandlerRef mWNETransitionEventHandler;
};
#endif // nsMacMessagePump_h__

View File

@ -83,26 +83,26 @@ nsMacTSMMessagePump::nsMacTSMMessagePump()
NS_ASSERTION(mPos2OffsetUPP!=NULL, "nsMacTSMMessagePump::InstallTSMAEHandlers: NewAEEventHandlerUPP[Pos2Pffset] failed");
err = AEInstallEventHandler(kTextServiceClass, kPos2Offset, mPos2OffsetUPP, (long)this, false);
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[Pos2Offset] failed");
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandler[Pos2Offset] failed");
err = AEInstallEventHandler(kTextServiceClass, kOffset2Pos, mOffset2PosUPP, (long)this, false);
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[Offset2Pos] failed");
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandler[Offset2Pos] failed");
err = AEInstallEventHandler(kTextServiceClass, kUpdateActiveInputArea, mUpdateUPP, (long)this, false);
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[Update] failed");
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandler[Update] failed");
if (tsmstrategy.UseUnicodeForKeyboard()) {
mKeyboardUPP = NewAEEventHandlerUPP(nsMacTSMMessagePump::UnicodeNotFromInputMethodHandler);
NS_ASSERTION(mKeyboardUPP!=NULL, "nsMacTSMMessagePump::InstallTSMAEHandlers: NewAEEventHandlerUPP[FromInputMethod] failed");
err = AEInstallEventHandler(kTextServiceClass, kUnicodeNotFromInputMethod, mKeyboardUPP, (long)this, false);
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[FromInputMethod] failed");
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandler[FromInputMethod] failed");
mGetSelectedTextUPP = NewAEEventHandlerUPP(nsMacTSMMessagePump::UnicodeGetSelectedTextHandler);
NS_ASSERTION(mGetSelectedTextUPP!=NULL, "nsMacTSMMessagePump::InstallTSMAEHandlers: NewAEEventHandlerUPP[GetSelectedText] failed");
err = AEInstallEventHandler(kTextServiceClass, kGetSelectedText, mGetSelectedTextUPP, (long)this, false);
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[GetSelectedText] failed");
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandler[GetSelectedText] failed");
}
@ -113,13 +113,13 @@ nsMacTSMMessagePump::~nsMacTSMMessagePump()
OSErr err;
err = AERemoveEventHandler(kTextServiceClass, kPos2Offset, mPos2OffsetUPP, false);
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[Pos2Offset] failed");
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::RemoveTSMAEHandlers: AERemoveEventHandler[Pos2Offset] failed");
err = AERemoveEventHandler(kTextServiceClass, kOffset2Pos, mOffset2PosUPP, false);
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[Offset2Pos] failed");
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::RemoveTSMAEHandlers: AERemoveEventHandler[Offset2Pos] failed");
err = AERemoveEventHandler(kTextServiceClass, kUpdateActiveInputArea, mUpdateUPP, false);
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[Update] failed");
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::RemoveTSMAEHandlers: AERemoveEventHandler[Update] failed");
::DisposeAEEventHandlerUPP(mPos2OffsetUPP);
::DisposeAEEventHandlerUPP(mOffset2PosUPP);
@ -128,11 +128,11 @@ nsMacTSMMessagePump::~nsMacTSMMessagePump()
nsTSMStrategy tsmstrategy;
if (tsmstrategy.UseUnicodeForKeyboard()) {
err = AERemoveEventHandler(kTextServiceClass, kUnicodeNotFromInputMethod, mKeyboardUPP, false);
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[FromInputMethod] failed");
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::RemoveTSMAEHandlers: AERemoveEventHandler[FromInputMethod] failed");
::DisposeAEEventHandlerUPP(mKeyboardUPP);
err = AERemoveEventHandler(kTextServiceClass, kGetSelectedText, mGetSelectedTextUPP, false);
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[GetSelectedText] failed");
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::RemoveTSMAEHandlers: AERemoveEventHandler[GetSelectedText] failed");
::DisposeAEEventHandlerUPP(mGetSelectedTextUPP);
}

View File

@ -57,7 +57,7 @@ public:
~nsMacTSMMessagePump();
static nsMacTSMMessagePump* GetSingleton();
void Shutdown();
static void Shutdown();
private:
static pascal OSErr PositionToOffsetHandler(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon);
@ -77,4 +77,4 @@ private:
};
#endif // NSMACTSMMESSAGEPUMP_h__
#endif // NSMACTSMMESSAGEPUMP_h__

View File

@ -36,93 +36,14 @@
* ***** END LICENSE BLOCK ***** */
#include "nsToolkit.h"
#include "nsIWidget.h"
#include "nsGUIEvent.h"
#include "nsWidgetAtoms.h"
#include "nsIEventSink.h"
#include "nsWidgetSupport.h"
#include <Gestalt.h>
#include <Movies.h>
#include "nsIEventSink.h"
#include "nsIServiceManager.h"
#include "nsThreadUtils.h"
#include "nsGfxCIID.h"
#include "nsIPref.h"
static nsMacNSPREventQueueHandler* gEventQueueHandler = nsnull;
//-------------------------------------------------------------------------
//
//-------------------------------------------------------------------------
nsMacNSPREventQueueHandler::nsMacNSPREventQueueHandler(): Repeater()
{
mRefCnt = 0;
}
//-------------------------------------------------------------------------
//
//-------------------------------------------------------------------------
nsMacNSPREventQueueHandler::~nsMacNSPREventQueueHandler()
{
StopRepeating();
}
//-------------------------------------------------------------------------
//
//-------------------------------------------------------------------------
void nsMacNSPREventQueueHandler::StartPumping()
{
++mRefCnt;
NS_LOG_ADDREF(this, mRefCnt, "nsMacNSPREventQueueHandler", sizeof(*this));
}
//-------------------------------------------------------------------------
//
//-------------------------------------------------------------------------
PRBool nsMacNSPREventQueueHandler::StopPumping()
{
if (mRefCnt > 0) {
--mRefCnt;
NS_LOG_RELEASE(this, mRefCnt, "nsMacNSPREventQueueHandler");
if (mRefCnt == 0) {
return PR_TRUE;
}
}
return PR_FALSE;
}
//-------------------------------------------------------------------------
//
//-------------------------------------------------------------------------
void nsMacNSPREventQueueHandler::RepeatAction(const EventRecord& inMacEvent)
{
ProcessPLEventQueue();
}
//-------------------------------------------------------------------------
//
//-------------------------------------------------------------------------
PRBool nsMacNSPREventQueueHandler::EventsArePending()
{
return NS_HasPendingEvents(NS_GetCurrentThread());
}
//-------------------------------------------------------------------------
//
//-------------------------------------------------------------------------
void nsMacNSPREventQueueHandler::ProcessPLEventQueue()
{
NS_ProcessPendingEvents(NS_GetCurrentThread());
}
#pragma mark -
// assume we begin as the fg app
@ -133,9 +54,6 @@ bool nsToolkit::sInForeground = true;
//-------------------------------------------------------------------------
nsToolkit::nsToolkit()
{
if (gEventQueueHandler == nsnull)
gEventQueueHandler = new nsMacNSPREventQueueHandler;
::EnterMovies(); // Required for nsSound to Work! -- fix for bug 194632
}
@ -144,17 +62,6 @@ nsToolkit::nsToolkit()
//-------------------------------------------------------------------------
nsToolkit::~nsToolkit()
{
/* StopPumping decrements a refcount on gEventQueueHandler; a prelude toward
stopping event handling. This is not something you want to do unless you've
bloody well started event handling and incremented the refcount. That's
done in the Init method, not the constructor, and that's what mInited is about.
*/
if (mInited && gEventQueueHandler) {
if (gEventQueueHandler->StopPumping()) {
delete gEventQueueHandler;
gEventQueueHandler = nsnull;
}
}
::ExitMovies(); // done with Movie Toolbox -- fix for bug 194632
}
@ -165,21 +72,9 @@ nsToolkit::~nsToolkit()
nsresult
nsToolkit::InitEventQueue(PRThread * aThread)
{
if (gEventQueueHandler)
gEventQueueHandler->StartPumping();
return NS_OK;
}
//-------------------------------------------------------------------------
//
//-------------------------------------------------------------------------
PRBool nsToolkit::ToolkitBusy()
{
return (gEventQueueHandler) ? gEventQueueHandler->EventsArePending() : PR_FALSE;
}
void
nsToolkit :: AppInForeground ( )
{
@ -266,116 +161,3 @@ nsToolkitBase* NS_CreateToolkitInstance()
{
return new nsToolkit();
}
#pragma mark -
Handle nsMacMemoryCushion::sMemoryReserve;
nsMacMemoryCushion::nsMacMemoryCushion()
: mBufferHandle(nsnull)
{
}
nsMacMemoryCushion::~nsMacMemoryCushion()
{
StopRepeating();
::SetGrowZone(nsnull);
NS_ASSERTION(sMemoryReserve, "Memory reserve was nil");
if (sMemoryReserve)
{
::DisposeHandle(sMemoryReserve);
sMemoryReserve = nil;
}
if (mBufferHandle)
::DisposeHandle(mBufferHandle);
}
OSErr nsMacMemoryCushion::Init(Size bufferSize, Size reserveSize)
{
sMemoryReserve = ::NewHandle(reserveSize);
if (sMemoryReserve == nsnull)
return ::MemError();
mBufferHandle = ::NewHandle(bufferSize);
if (mBufferHandle == nsnull)
return ::MemError();
// make this purgable
::HPurge(mBufferHandle);
return noErr;
}
void nsMacMemoryCushion::RepeatAction(const EventRecord &aMacEvent)
{
if (!RecoverMemoryReserve(kMemoryReserveSize))
{
// NS_ASSERTION(0, "Failed to recallocate memory reserve. Flushing caches");
nsMemory::HeapMinimize(PR_TRUE);
}
}
Boolean nsMacMemoryCushion::RecoverMemoryReserve(Size reserveSize)
{
if (!sMemoryReserve) return true; // not initted yet
if (*sMemoryReserve != nsnull) return true; // everything is OK
::ReallocateHandle(sMemoryReserve, reserveSize);
if (::MemError() != noErr || !*sMemoryReserve) return false;
return true;
}
Boolean nsMacMemoryCushion::RecoverMemoryBuffer(Size bufferSize)
{
if (!mBufferHandle) return true; // not initted yet
if (*mBufferHandle != nsnull) return true; // everything is OK
::ReallocateHandle(mBufferHandle, bufferSize);
if (::MemError() != noErr || !*mBufferHandle) return false;
// make this purgable
::HPurge(mBufferHandle);
return true;
}
pascal long nsMacMemoryCushion::GrowZoneProc(Size amountNeeded)
{
long freedMem = 0;
if (sMemoryReserve && *sMemoryReserve && sMemoryReserve != ::GZSaveHnd())
{
freedMem = ::GetHandleSize(sMemoryReserve);
::EmptyHandle(sMemoryReserve);
}
return freedMem;
}
std::auto_ptr<nsMacMemoryCushion> gMemoryCushion;
Boolean nsMacMemoryCushion::EnsureMemoryCushion()
{
if (!gMemoryCushion.get())
{
nsMacMemoryCushion* softFluffyCushion = new nsMacMemoryCushion();
if (!softFluffyCushion) return false;
OSErr err = softFluffyCushion->Init(nsMacMemoryCushion::kMemoryBufferSize, nsMacMemoryCushion::kMemoryReserveSize);
if (err != noErr)
{
delete softFluffyCushion;
return false;
}
gMemoryCushion.reset(softFluffyCushion);
softFluffyCushion->StartRepeating();
}
return true;
}

View File

@ -38,12 +38,7 @@
#ifndef TOOLKIT_H
#define TOOLKIT_H
#include <memory>
#include "nsToolkitBase.h"
#include "nsRepeater.h"
#include "nsCOMPtr.h"
/**
* The toolkit abstraction is necessary because the message pump must
@ -60,13 +55,7 @@
*
* All this has changed: the application now usually creates one copy of
* the nsToolkit per window and the special widgets had to be moved
* to the nsMacEventHandler. Also, to avoid creating several repeaters,
* the NSPR event queue has been moved to a global object of its own:
* the nsMacNSPREventQueueHandler declared below.
*
* If by any chance we support one day several threads for the UI
* on the Mac, will have to create one instance of the NSPR
* event queue per nsToolkit.
* to the nsMacEventHandler.
*/
#include <MacTypes.h>
@ -87,9 +76,6 @@ public:
nsToolkit();
virtual ~nsToolkit();
// are there pending events on the toolkit's event queue?
PRBool ToolkitBusy();
protected:
virtual nsresult InitEventQueue(PRThread * aThread);
@ -114,74 +100,4 @@ protected:
static bool sInForeground;
};
class nsMacNSPREventQueueHandler : public Repeater
{
public:
nsMacNSPREventQueueHandler();
virtual ~nsMacNSPREventQueueHandler();
virtual void StartPumping();
virtual PRBool StopPumping();
// Repeater interface
virtual void RepeatAction(const EventRecord& inMacEvent);
PRBool EventsArePending();
protected:
void ProcessPLEventQueue();
protected:
nsrefcnt mRefCnt;
};
// class for low memory detection and handling
class nsMacMemoryCushion : public Repeater
{
public:
enum {
kMemoryBufferSize = 64 * 1024, // 64k reserve, purgeable handle purged first
kMemoryReserveSize = 32 * 1024 // 32k memory reserve, freed by the GrowZoneProc
};
nsMacMemoryCushion();
~nsMacMemoryCushion();
OSErr Init(Size bufferSize, Size reserveSize);
void RepeatAction(const EventRecord &aMacEvent);
protected:
// reallocate the memory buffer. Returns true on success
Boolean RecoverMemoryBuffer(Size bufferSize);
// allocate or recover the memory reserve. Returns true on success
Boolean RecoverMemoryReserve(Size reserveSize);
static pascal long GrowZoneProc(Size amountNeeded);
public:
static Boolean EnsureMemoryCushion();
protected:
static Handle sMemoryReserve;
Handle mBufferHandle; // this is first to go
};
#endif // TOOLKIT_H