Mozilla/mozilla/widget/src/mac/nsMacEventHandler.cpp
pierre%netscape.com 3e39d64a45 added nsDeleteObserver (#3147: crashes on mouseMoved or closeWindow)
git-svn-id: svn://10.0.0.236/trunk@21426 18797224-902f-48f8-a5cc-f745e15eee43
1999-02-21 02:10:36 +00:00

546 lines
15 KiB
C++
Raw Blame History

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include <LowMem.h>
#include "nsMacEventHandler.h"
#include "nsWindow.h"
#include "nsToolkit.h"
#include "prinrval.h"
// from MacHeaders.c
#ifndef topLeft
#define topLeft(r) (((Point *) &(r))[0])
#endif
#ifndef botRight
#define botRight(r) (((Point *) &(r))[1])
#endif
//-------------------------------------------------------------------------
//
// nsMacEventHandler constructor/destructor
//
//-------------------------------------------------------------------------
nsMacEventHandler::nsMacEventHandler(nsWindow* aTopLevelWidget)
{
mTopLevelWidget = aTopLevelWidget;
mLastWidgetHit = nsnull;
mLastWidgetPointed = nsnull;
}
nsMacEventHandler::~nsMacEventHandler()
{
if (mLastWidgetPointed)
mLastWidgetPointed->RemoveDeleteObserver(this);
if (mLastWidgetHit)
mLastWidgetHit->RemoveDeleteObserver(this);
}
void nsMacEventHandler::NotifyDelete(void* aDeletedObject)
{
if (mLastWidgetPointed == aDeletedObject)
mLastWidgetPointed = nsnull;
if (mLastWidgetHit == aDeletedObject)
mLastWidgetHit = nsnull;
}
#pragma mark -
//-------------------------------------------------------------------------
//
// HandleOSEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleOSEvent(
EventRecord& aOSEvent)
{
PRBool retVal = PR_FALSE;
switch (aOSEvent.what)
{
case keyUp:
case keyDown:
case autoKey:
retVal = HandleKeyEvent(aOSEvent);
break;
case activateEvt:
retVal = HandleActivateEvent(aOSEvent);
break;
case updateEvt:
retVal = HandleUpdateEvent(aOSEvent);
break;
case mouseDown:
retVal = HandleMouseDownEvent(aOSEvent);
break;
case mouseUp:
retVal = HandleMouseUpEvent(aOSEvent);
break;
case osEvt:
case nullEvent:
retVal = HandleMouseMoveEvent(aOSEvent);
break;
}
return retVal;
}
//-------------------------------------------------------------------------
//
// Handle Menu commands
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleMenuCommand(
EventRecord& aOSEvent,
long aMenuResult)
{
// get the focused widget
nsWindow* focusedWidget;
nsCOMPtr<nsToolkit> toolkit ( dont_AddRef((nsToolkit*)mTopLevelWidget->GetToolkit()) );
if (toolkit)
focusedWidget = toolkit->GetFocus();
if (focusedWidget == nsnull)
focusedWidget = mTopLevelWidget;
// nsEvent
nsMenuEvent menuEvent;
menuEvent.eventStructType = NS_MENU_EVENT;
menuEvent.message = NS_MENU_SELECTED;
menuEvent.point.x = aOSEvent.where.h;
menuEvent.point.y = aOSEvent.where.v;
menuEvent.time = PR_IntervalNow();
// nsGUIEvent
menuEvent.widget = focusedWidget;
menuEvent.nativeMsg = (void*)&aOSEvent;
// nsMenuEvent
menuEvent.mMenuItem = nsnull; //<2F>TODO: initialize mMenuItem
menuEvent.mCommand = aMenuResult;
// dispatch the menu event: if it is not processed by the focused widget,
// propagate the event through the different parents all the way up to the window
PRBool eventHandled = focusedWidget->DispatchWindowEvent(menuEvent);
if (! eventHandled)
{
nsCOMPtr<nsWindow> grandParent;
nsCOMPtr<nsWindow> parent ( dont_AddRef((nsWindow*)focusedWidget->GetParent()) );
while (parent)
{
menuEvent.widget = parent;
eventHandled = parent->DispatchWindowEvent(menuEvent);
if (eventHandled)
{
break;
}
else
{
grandParent = dont_AddRef((nsWindow*)parent->GetParent());
parent = grandParent;
}
}
}
return eventHandled;
}
#pragma mark -
//-------------------------------------------------------------------------
//
// HandleKeyEvent
//
//-------------------------------------------------------------------------
#define homeKey 0x01 /* ascii code for home key */
#define enterKey 0x03 /* ascii code for enter key */
#define endKey 0x04 /* ascii code for end key */
#define helpKey 0x05 /* ascii code for help key */
#define deleteKey 0x08 /* ascii code for delete/backspace */
#define tabKey 0x09 /* ascii code for tab key */
#define pageUpKey 0x0B /* ascii code for page up key */
#define pageDownKey 0x0C /* ascii code for page down key */
#define returnKey 0x0D /* ascii code for return key */
#define leftArrow 0x1C /* ascii code for left arrow key */
#define rightArrow 0x1D /* ascii code for right arrow key */
#define upArrow 0x1E /* ascii code for up arrow key */
#define downArrow 0x1F /* ascii code for down arrow key */
#define forwardDelKey 0x7F /* ascii code for forward delete key */
#define spaceKey 0x20 /* ascii code for a space */
#define escapeKeyCode 0x35 /* key code for escape key */
#define clearKeyCode 0x47 /* key code for clear key */
static PRUint32 ConvertMacToRaptorKeyCode(UInt32 eventMessage, UInt32 eventModifiers)
{
UInt8 charCode = (eventMessage & charCodeMask);
UInt8 keyCode = (eventMessage & keyCodeMask) >> 8;
PRUint32 raptorKeyCode;
// temporary hack until we figure out the key handling strategy (sfraser)
if (charCode >= ' ' && charCode <= '~') // ~ is 0x7E
{
raptorKeyCode = charCode;
}
else
{
switch (charCode)
{
case homeKey: raptorKeyCode = NS_VK_HOME; break;
case enterKey: raptorKeyCode = NS_VK_RETURN; break; // fix me!
case endKey: raptorKeyCode = NS_VK_END; break;
//case helpKey: raptorKeyCode = ; break;
case deleteKey: raptorKeyCode = NS_VK_DELETE; break;
case tabKey: raptorKeyCode = NS_VK_TAB; break;
case pageUpKey: raptorKeyCode = NS_VK_PAGE_UP; break;
case pageDownKey: raptorKeyCode = NS_VK_PAGE_DOWN; break;
case returnKey: raptorKeyCode = NS_VK_RETURN; break;
case leftArrow: raptorKeyCode = NS_VK_LEFT; break;
case rightArrow: raptorKeyCode = NS_VK_RIGHT; break;
case upArrow: raptorKeyCode = NS_VK_UP; break;
case downArrow: raptorKeyCode = NS_VK_DOWN; break;
case escapeKeyCode: raptorKeyCode = NS_VK_ESCAPE; break;
case clearKeyCode: raptorKeyCode = NS_VK_CLEAR; break;
}
}
return raptorKeyCode;
}
//-------------------------------------------------------------------------
//
// HandleKeyEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleKeyEvent(EventRecord& aOSEvent)
{
// get the focused widget
nsWindow* focusedWidget;
nsCOMPtr<nsToolkit> toolkit ( dont_AddRef((nsToolkit*)mTopLevelWidget->GetToolkit()) );
if (toolkit)
focusedWidget = toolkit->GetFocus();
if (focusedWidget == nsnull)
focusedWidget = mTopLevelWidget;
// nsEvent
nsKeyEvent keyEvent;
keyEvent.eventStructType = NS_KEY_EVENT;
switch (aOSEvent.what)
{
case keyUp: keyEvent.message = NS_KEY_UP; break;
case keyDown: keyEvent.message = NS_KEY_DOWN; break;
case autoKey: keyEvent.message = NS_KEY_DOWN; break;
}
keyEvent.point.x = 0;
keyEvent.point.y = 0;
keyEvent.time = PR_IntervalNow();
// nsGUIEvent
keyEvent.widget = focusedWidget;
keyEvent.nativeMsg = (void*)&aOSEvent;
// nsInputEvent
keyEvent.isShift = ((aOSEvent.modifiers & shiftKey) != 0);
keyEvent.isControl = ((aOSEvent.modifiers & controlKey) != 0);
keyEvent.isAlt = ((aOSEvent.modifiers & optionKey) != 0);
keyEvent.isCommand = ((aOSEvent.modifiers & cmdKey) != 0);
// nsKeyEvent
keyEvent.keyCode = ConvertMacToRaptorKeyCode(aOSEvent.message, aOSEvent.modifiers);
return(focusedWidget->DispatchWindowEvent(keyEvent));
}
//-------------------------------------------------------------------------
//
// HandleActivateEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleActivateEvent(EventRecord& aOSEvent)
{
nsCOMPtr<nsToolkit> toolkit ( dont_AddRef((nsToolkit*)mTopLevelWidget->GetToolkit()) );
if (toolkit)
{
Boolean isActive = ((aOSEvent.modifiers & activeFlag) != 0);
if (isActive)
{
//<2F>TODO: retrieve the focused widget for that window
nsWindow* focusedWidget = mTopLevelWidget;
toolkit->SetFocus(focusedWidget);
nsIMenuBar* menuBar = focusedWidget->GetMenuBar();
//<2F>TODO: if the focusedWidget doesn't have a menubar,
// look all the way up to the window
// until one of the parents has a menubar
//<2F>TODO: set the menu bar here
}
else
{
//<2F>TODO: save the focused widget for that window
toolkit->SetFocus(nsnull);
}
}
return PR_TRUE;
}
//-------------------------------------------------------------------------
//
// HandleUpdateEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleUpdateEvent(EventRecord& aOSEvent)
{
mTopLevelWidget->HandleUpdateEvent();
return PR_TRUE;
}
//-------------------------------------------------------------------------
//
// HandleMouseDownEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleMouseDownEvent(
EventRecord& aOSEvent)
{
PRBool retVal = PR_FALSE;
WindowPtr whichWindow;
short partCode = ::FindWindow(aOSEvent.where, &whichWindow);
switch (partCode)
{
case inDrag:
{
Point macPoint;
macPoint = topLeft(whichWindow->portRect);
::LocalToGlobal(&macPoint);
mTopLevelWidget->Move(macPoint.h, macPoint.v);
break;
}
case inGrow:
{
Rect macRect = whichWindow->portRect;
::LocalToGlobal(&topLeft(macRect));
::LocalToGlobal(&botRight(macRect));
mTopLevelWidget->Resize(macRect.right - macRect.left, macRect.bottom - macRect.top, PR_FALSE);
break;
}
case inGoAway:
{
mTopLevelWidget->Destroy();
break;
}
case inContent:
{
nsMouseEvent mouseEvent;
ConvertOSEventToMouseEvent(aOSEvent, mouseEvent, NS_MOUSE_LEFT_BUTTON_DOWN);
nsWindow* widgetHit = (nsWindow*)mouseEvent.widget;
if (widgetHit)
{
// set the focus on the widget hit
nsCOMPtr<nsToolkit> toolkit ( dont_AddRef((nsToolkit*)widgetHit->GetToolkit()) );
if (toolkit)
toolkit->SetFocus(widgetHit);
// dispatch the event
retVal = widgetHit->DispatchMouseEvent(mouseEvent);
}
if (mLastWidgetHit)
mLastWidgetHit->RemoveDeleteObserver(this);
mLastWidgetHit = widgetHit;
if (mLastWidgetHit)
mLastWidgetHit->AddDeleteObserver(this);
break;
}
}
return retVal;
}
//-------------------------------------------------------------------------
//
// HandleMouseUpEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleMouseUpEvent(
EventRecord& aOSEvent)
{
PRBool retVal = PR_FALSE;
nsMouseEvent mouseEvent;
ConvertOSEventToMouseEvent(aOSEvent, mouseEvent, NS_MOUSE_LEFT_BUTTON_UP);
nsWindow* widgetReleased = (nsWindow*)mouseEvent.widget;
if ((widgetReleased != nsnull) && (widgetReleased != mLastWidgetHit))
retVal |= widgetReleased->DispatchMouseEvent(mouseEvent);
if (mLastWidgetHit)
{
mLastWidgetHit->RemoveDeleteObserver(this);
retVal |= mLastWidgetHit->DispatchMouseEvent(mouseEvent);
mLastWidgetHit = nsnull;
}
return retVal;
}
//-------------------------------------------------------------------------
//
// HandleMouseMoveEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleMouseMoveEvent(
EventRecord& aOSEvent)
{
PRBool retVal = PR_FALSE;
nsMouseEvent mouseEvent;
ConvertOSEventToMouseEvent(aOSEvent, mouseEvent, NS_MOUSE_MOVE);
nsWindow* widgetPointed = (nsWindow*)mouseEvent.widget;
if (widgetPointed != mLastWidgetPointed)
{
if (mLastWidgetPointed != nsnull)
{
mLastWidgetPointed->RemoveDeleteObserver(this);
mouseEvent.widget = mLastWidgetPointed;
mouseEvent.message = NS_MOUSE_EXIT;
retVal |= mLastWidgetPointed->DispatchMouseEvent(mouseEvent);
mLastWidgetPointed = nsnull;
mouseEvent.widget = widgetPointed;
}
if (widgetPointed != nsnull)
{
widgetPointed->AddDeleteObserver(this);
mLastWidgetPointed = widgetPointed;
mouseEvent.message = NS_MOUSE_ENTER;
retVal |= widgetPointed->DispatchMouseEvent(mouseEvent);
}
}
else
{
if (widgetPointed != nsnull)
retVal |= widgetPointed->DispatchMouseEvent(mouseEvent);
}
return retVal;
}
#pragma mark -
//-------------------------------------------------------------------------
//
// ConvertOSEventToMouseEvent
//
//-------------------------------------------------------------------------
void nsMacEventHandler::ConvertOSEventToMouseEvent(
EventRecord& aOSEvent,
nsMouseEvent& aMouseEvent,
PRUint32 aMessage)
{
static long lastWhen = 0;
static Point lastWhere = {0, 0};
static short lastClickCount = 0;
// get the click count
if (((aOSEvent.when - lastWhen) < ::LMGetDoubleTime())
&& (abs(aOSEvent.where.h - lastWhere.h) < 5)
&& (abs(aOSEvent.where.v - lastWhere.v) < 5))
{
if (aOSEvent.what == mouseDown)
{
lastClickCount ++;
if (lastClickCount == 2)
aMessage = NS_MOUSE_LEFT_DOUBLECLICK;
}
}
else
{
if (! ::StillDown())
lastClickCount = 0;
}
lastWhen = aOSEvent.when;
lastWhere = aOSEvent.where;
// get the widget hit and its hit point
Point hitPoint = aOSEvent.where;
::SetPort(static_cast<GrafPort*>(mTopLevelWidget->GetNativeData(NS_NATIVE_DISPLAY)));
::SetOrigin(0, 0);
::GlobalToLocal(&hitPoint);
nsPoint widgetHitPoint(hitPoint.h, hitPoint.v);
nsWindow* widgetHit = mTopLevelWidget->FindWidgetHit(hitPoint);
if (widgetHit)
{
nsRect bounds;
widgetHit->GetBounds(bounds);
nsPoint widgetOrigin(bounds.x, bounds.y);
widgetHit->LocalToWindowCoordinate(widgetOrigin);
widgetHitPoint.MoveBy(-widgetOrigin.x, -widgetOrigin.y);
}
// nsEvent
aMouseEvent.eventStructType = NS_MOUSE_EVENT;
aMouseEvent.message = aMessage;
aMouseEvent.point = widgetHitPoint;
aMouseEvent.time = PR_IntervalNow();
// nsGUIEvent
aMouseEvent.widget = widgetHit;
aMouseEvent.nativeMsg = (void*)&aOSEvent;
// nsInputEvent
aMouseEvent.isShift = ((aOSEvent.modifiers & shiftKey) != 0);
aMouseEvent.isControl = ((aOSEvent.modifiers & controlKey) != 0);
aMouseEvent.isAlt = ((aOSEvent.modifiers & optionKey) != 0);
// nsMouseEvent
aMouseEvent.clickCount = lastClickCount;
}