netscape-revival
sun-java/awt.bad/macos/MToolkit.cp
//##############################################################################
//##############################################################################
//
// File: MToolkit.cp
// Author: Dan Clifford
//
// Copyright © 1995-1996, Netscape Communications Corporation
//
//##############################################################################
//##############################################################################
#include "MToolkit.h"
#include <LPane.h>
#include <PP_Messages.h>
#include "MTextAreaPeer.h"
#include <UDesktop.h>
extern "C" {
#include "mdmacmem.h"
#include <stdlib.h>
#include "native.h"
#include "typedefs_md.h"
#include "java_awt_Color.h"
#include "java_awt_Font.h"
#include "sun_awt_macos_MToolkit.h"
#include "sun_awt_macos_MComponentPeer.h"
#include "java_awt_Component.h"
#include "interpreter.h"
#include "exceptions.h"
#include "prlog.h"
#include "prgc.h"
#include "swkern.h"
#undef __cplusplus
#define IMPLEMENT_netscape_applet_MozillaAppletContext
#include "n_applet_MozillaAppletContext.h"
#include "java.h"
#include "jri.h"
#include "lj.h"
extern void FreeClassArenas(void);
};
#include "fredmem.h"
enum {
kTimeBetweenStationaryMouseMovedEvents = 20,
kMacJavaAppletMaxHistorySize = 1
};
#ifndef CAFFEINE
#include "earlmgr.h"
#endif
extern "C" {
#include "uapp.h"
#include "lj.h"
}
#include <Quickdraw.h>
#include <UDesktop.h>
#include "MCanvasPeer.h"
#include "MFramePeer.h"
enum {
kDefaultColorTableResID = 2048
};
Boolean gHasScreenResolution = false;
Rect gMainScreenBounds;
long gTotalClickCount = 0;
Hsun_awt_macos_MComponentPeer *gCurrentJavaTarget;
void GetScreenResolution(void)
{
if (!gHasScreenResolution) {
GDHandle mainScreenDevice;
mainScreenDevice = GetMainDevice();
gMainScreenBounds = (**mainScreenDevice).gdRect;
gHasScreenResolution = true;
}
}
UInt32 MToolkitExecutJavaDynamicMethod(void *obj, char *method_name, char *signature, ...)
{
UInt32 returnValue;
va_list args;
va_start(args, signature);
returnValue = (UInt32)do_execute_java_method_vararg(EE(), obj, method_name, signature,
0, (bool_t)FALSE, args, 0, (bool_t)FALSE);
va_end(args);
if (exceptionOccurred(EE())) {
exceptionDescribe(EE());
}
return returnValue;
}
UInt32 MToolkitExecutJavaStaticMethod(ClassClass *classObject, char *method_name, char *signature, ...)
{
UInt32 returnValue;
struct methodblock *mb = NULL;
Int32 i;
va_list args;
va_start(args, signature);
/* XXX Why are we doing this?? do_execute_java_method_vararg will throw an exception
* if the method is not found. */
/* Lookup the method */
mb = cbMethods(classObject);
for (i = classObject->methods_count; --i >= 0; mb++) {
if ((strcmp(fieldname(&mb->fb), method_name) == 0) &&
(strcmp(fieldsig(&mb->fb), signature) == 0)) {
break;
}
}
if (mb == NULL) {
#if DEBUG
DebugStr("\pJava: MToolkitExecutJavaStaticMethod called with illegal function");
#endif
return 0;
}
returnValue = (UInt32)do_execute_java_method_vararg(EE(), classObject, method_name, signature, 0, (bool_t)TRUE, args, 0, (bool_t)FALSE);
va_end(args);
if (exceptionOccurred(EE())) {
exceptionDescribe(EE());
}
return returnValue;
}
LWindow *
GetContainerWindow(LPane *currentPane)
{
LView *currentContainer,
*parentView;
currentContainer = currentPane->GetSuperView();
if (currentContainer == NULL) {
if (currentPane->GetPaneID() == MFramePeer::class_ID)
return (LWindow *)currentPane;
else
return NULL;
}
while (1) {
parentView = currentContainer->GetSuperView();
if (parentView == NULL)
break;
currentContainer = parentView;
}
if (currentContainer->GetPaneID() == 'java')
return NULL;
else
return (LWindow *)currentContainer;
}
enum {
kEventHistoryLength = 32
};
EventRecord gEventRecordHistory[kEventHistoryLength];
UInt32 gEventRecordHistoryNextItem = 0;
Hsun_awt_macos_MComponentPeer *gCurrentMouseTargetPeer = NULL;
extern "C" jint
LJ_GetTotalApplets(); // FIX ME
unsigned char JavaAppletHistoryFlusher(size_t bytesNeeded)
{
SInt32 totalApplets,
appletsToTrim,
appletsWeDidTrim;
static Boolean alreadyInFlusher = false;
DebugStr("\pLJ_GetTotalApplets"); // FIX ME
if (alreadyInFlusher)
{
#if DEBUG
DebugStr("\pJavaAppletHistoryFlusher has been called re-intrantly");
#endif
return false;
}
alreadyInFlusher = true;
// Make sure that we can't pre-empt during this cache flusher
DeactivateTimer();
if ((EE())->exceptionKind == EXCKIND_YIELD)
(EE())->exceptionKind = EXCKIND_NONE;
// Trim half of the applets that we have.
totalApplets = LJ_GetTotalApplets();
appletsToTrim = totalApplets / 2;
// First try to trim the inactive applets. If that doesn't
// get us anywhere, kill the LRU active applet.
appletsWeDidTrim = LJ_TrimApplets(appletsToTrim, true);
if (appletsWeDidTrim == 0)
appletsWeDidTrim = LJ_TrimApplets(1, false);
ActivateTimer();
alreadyInFlusher = false;
return (appletsWeDidTrim != 0);
}
MToolkit::
MToolkit():LAttachment(msg_Event, true)
{
mLastNullPoint.h = 0;
mLastNullPoint.v = 0;
mFrameList = new LList(sizeof(LPane *));
if (mFrameList == NULL)
SignalError(0, JAVAPKG "OutOfMemoryError", 0);
}
void
MToolkit::AddFrame(LPane *frame)
{
if (mFrameList->FetchIndexOf(&frame) == 0)
mFrameList->InsertItemsAt(1, 1, &frame);
}
void
MToolkit::RemoveFrame(LPane *frame)
{
mFrameList->Remove(&frame);
}
Hsun_awt_macos_MComponentPeer *
MToolkit::LocatePointInFrame(LPane *currentPane, Point &incomingPoint)
{
Hsun_awt_macos_MComponentPeer *currentPeer = NULL;
Rect localRect;
Point incomingPointCopy = incomingPoint;
if (!currentPane->IsVisible())
return NULL;
currentPane->CalcLocalFrameRect(localRect);
currentPane->GlobalToPortPoint(incomingPointCopy);
currentPane->PortToLocalPoint(incomingPointCopy);
if (!PtInRect(incomingPointCopy, &localRect))
return NULL;
currentPeer = PaneToPeer(currentPane);
if (currentPeer == NULL)
return NULL;
// The point must not be in the obscured region as well.
if (unhand(currentPeer)->mObscuredRgn == NULL)
return NULL;
if (PtInRgn(incomingPointCopy, (RgnHandle)(unhand(currentPeer)->mObscuredRgn)))
return NULL;
// If the pane is a container, check all of the sub
// views to see if they contain the point.
if (unhand(currentPeer)->mIsContainer) {
LView *currentPaneAsView = (LView *)currentPane;
LListIterator iterator(currentPaneAsView->GetSubPanes(), iterate_FromStart);
LPane *theSub;
Hsun_awt_macos_MComponentPeer *childPeer;
while (iterator.Next(&theSub)) {
childPeer = LocatePointInFrame(theSub, incomingPoint);
if (childPeer != NULL)
return childPeer;
}
}
// Check to make sure that the point is actually visible.
currentPane->FocusDraw();
static RgnHandle tempRegion = NULL;
if (tempRegion == NULL)
tempRegion = ::NewRgn();
if (tempRegion == NULL) {
SignalError(0, JAVAPKG "OutOfMemoryError", 0);
return NULL;
}
::GetClip(tempRegion);
if (::PtInRgn(incomingPointCopy, tempRegion)) {
incomingPoint = incomingPointCopy;
return currentPeer;
}
else {
return NULL;
}
}
Hsun_awt_macos_MComponentPeer *
MToolkit::LocatePoint(Point &incomingPoint)
{
Hsun_awt_macos_MComponentPeer *currentPeer = NULL;
LListIterator iterator(*mFrameList, iterate_FromStart);
LPane *theSub;
LWindow *frontRegularWindow = LWindow::FetchWindowObject(FrontWindow());
while (iterator.Next(&theSub)) {
LWindow *ourWindowObject = GetContainerWindow(theSub);
if (ourWindowObject != frontRegularWindow)
continue;
currentPeer = LocatePointInFrame(theSub, incomingPoint);
if (currentPeer != NULL)
return currentPeer;
}
return NULL;
}
void
MToolkit::ExecuteSelf(MessageT inMessage, void *ioParam)
{
Hsun_awt_macos_MComponentPeer *targetPeer;
EventRecord *incomingEvent = (EventRecord *)ioParam;
Point translatedPoint = incomingEvent->where;
Boolean executeInHost = true;
static UInt32 gNextTimeToSendStationaryEvent = 0;
UInt32 currentTime = TickCount();
Boolean memoryIsReallyLow = false;
Boolean timeToTrimApplet = false;
Boolean eventToRemember = false;
gEventRecordHistory[gEventRecordHistoryNextItem] = *incomingEvent;
FreeClassArenas();
// Only send events to the front window.
WindowRef eventWindow;
::FindWindow(translatedPoint, &eventWindow);
if (eventWindow == ::FrontWindow()) {
switch (incomingEvent->what) {
case nullEvent:
// Only send mouse moved events when the mouse actually moves.
if ((incomingEvent->where.h != mLastNullPoint.h) ||
(incomingEvent->where.v != mLastNullPoint.v) ||
(gNextTimeToSendStationaryEvent < TickCount())) {
targetPeer = LocatePoint(translatedPoint);
// if (PeerToPane(targetPeer)->GetPaneID() != MCanvasPeer::class_ID)
// break;
gNextTimeToSendStationaryEvent = TickCount() + kTimeBetweenStationaryMouseMovedEvents;
mLastNullPoint = incomingEvent->where;
// Take care of the mouse moved event.
if (targetPeer != NULL) {
// If the target is not a canvas, then don't send
// mouse events... This is a really terrible
// inconsistency in AWT.
if (StillDown()) {
MToolkitExecutJavaDynamicMethod(targetPeer, "handleMouseMoved",
"(IIIZ)V", translatedPoint.h, translatedPoint.v,
incomingEvent->modifiers, true);
} else
MToolkitExecutJavaDynamicMethod(targetPeer, "handleMouseMoved",
"(IIIZ)V", translatedPoint.h, translatedPoint.v,
incomingEvent->modifiers, false);
executeInHost = false;
}
// And the exit/enter events as well.
if (targetPeer != gCurrentMouseTargetPeer) {
if (gCurrentMouseTargetPeer != NULL)
MToolkitExecutJavaDynamicMethod(gCurrentMouseTargetPeer, "handleMouseExit",
"(III)V", translatedPoint.h, translatedPoint.v, incomingEvent->modifiers);
if (targetPeer != NULL)
MToolkitExecutJavaDynamicMethod(targetPeer, "handleMouseEnter",
"(III)V", translatedPoint.h, translatedPoint.v, incomingEvent->modifiers);
gCurrentMouseTargetPeer = targetPeer;
}
}
break;
case mouseDown:
targetPeer = LocatePoint(translatedPoint);
LPane *targetPane = PeerToPane(targetPeer);
if (targetPeer != NULL) {
// If the target is not a canvas, then don't send
// mouse events... This is a really terrible
// inconsistency in AWT.
if (targetPane->GetPaneID() == MCanvasPeer::class_ID) {
LCommander::SwitchTarget((MCanvasPeer *)targetPane);
} else
break;
if (targetPeer != gCurrentJavaTarget)
gTotalClickCount = 0;
MToolkitExecutJavaDynamicMethod(targetPeer, "handleMouseChanged",
"(IIIIZI)V", translatedPoint.h, translatedPoint.v,
incomingEvent->modifiers, ++gTotalClickCount, true, gEventRecordHistoryNextItem);
executeInHost = false;
}
eventToRemember = true;
break;
case mouseUp:
targetPeer = LocatePoint(translatedPoint);
if (targetPeer != NULL) {
MToolkitExecutJavaDynamicMethod(targetPeer, "handleMouseChanged",
"(IIIIZI)V", translatedPoint.h, translatedPoint.v,
incomingEvent->modifiers, 0, false, gEventRecordHistoryNextItem);
executeInHost = false;
}
eventToRemember = true;
break;
case keyDown:
case autoKey:
// If there is a modal dialog up, then don't
// grab key strokes... they are meant for the dialog.
if (UDesktop::FrontWindowIsModal())
break;
if ((GetJavaTarget() != NULL) && ((incomingEvent->modifiers & cmdKey) == 0)) {
Int16 theKey = incomingEvent->message & charCodeMask;
if (theKey == '\r')
theKey = '\n';
MToolkitExecutJavaDynamicMethod(GetJavaTarget(), "handleKeyEvent",
"(IIIIZI)V", incomingEvent->where.h, incomingEvent->where.v, theKey,
incomingEvent->modifiers, true, gEventRecordHistoryNextItem);
executeInHost = false;
}
eventToRemember = true;
break;
case keyUp:
if (GetJavaTarget() != NULL) {
Int16 theKey = incomingEvent->message & charCodeMask;
MToolkitExecutJavaDynamicMethod(GetJavaTarget(), "handleKeyEvent",
"(IIIIZI)V", incomingEvent->where.h, incomingEvent->where.v, theKey,
incomingEvent->modifiers, false, gEventRecordHistoryNextItem);
executeInHost = false;
}
eventToRemember = true;
break;
default:
break;
}
}
if (eventToRemember) {
gEventRecordHistoryNextItem++;
if (gEventRecordHistoryNextItem >= kEventHistoryLength)
gEventRecordHistoryNextItem = 0;
}
PR_SetThreadPriority(PR_CurrentThread(), 0);
mExecuteHost = executeInHost;
}
MToolkit *gMToolkit = NULL;
MToolkit *
MToolkit::GetMToolkit()
{
// If there is no toolkit already, then call java AWT to
// fetch the Toolkit, which will force our MToolkit to
// initialize
if (gMToolkit == NULL) {
ClassClass *toolkitClass;
toolkitClass = FindClass(EE(), "java/awt/Toolkit", TRUE);
if (toolkitClass != NULL)
MToolkitExecutJavaStaticMethod(toolkitClass, "getDefaultToolkit", "()Ljava/awt/Toolkit;");
}
return gMToolkit;
}
void sun_awt_macos_MToolkit_init(struct Hsun_awt_macos_MToolkit *toolkit)
{
gMToolkit = new MToolkit();
if (gMToolkit == NULL) {
SignalError(0, JAVAPKG "OutOfMemoryError", 0);
return;
}
(CFrontApp::GetApplication())->AddAttachment(gMToolkit);
URegistrar::RegisterClass(MTextAreaPeer::class_ID, (ClassCreatorFunc)MTextAreaPeer::CreateMTextAreaPeerStream);
URegistrar::RegisterClass(MTextEditPeer::class_ID, (ClassCreatorFunc)MTextEditPeer::CreateMTextEditPeerStream);
}
Hjava_awt_image_ColorModel *gStandard8BitColorModel = NULL;
struct Hjava_awt_image_ColorModel *sun_awt_macos_MToolkit_makeColorModel(struct Hsun_awt_macos_MToolkit *toolkit)
{
struct Hjava_awt_image_ColorModel *awt_colormodel;
CTabHandle defaultColorTable;
ColorSpec *currentColorSpec;
defaultColorTable = (CTabHandle)GetResource('clut', kDefaultColorTableResID);
if (defaultColorTable == NULL) {
SignalError(0, JAVAPKG "OutOfMemoryError", 0);
return NULL;
}
// Get the system 8-bit color lookup table. This will be the
// the colors we use to create the default color model.
// By making the arrays volatile, we ensure that the GC wonÕt
// get rid of our arrays.
volatile HArrayOfByte *redComponent = (HArrayOfByte *) ArrayAlloc(T_BYTE, 256);
volatile HArrayOfByte *greenComponent = (HArrayOfByte *) ArrayAlloc(T_BYTE, 256);
volatile HArrayOfByte *blueComponent = (HArrayOfByte *) ArrayAlloc(T_BYTE, 256);
char *currentRed = unhand(redComponent)->body;
char *currentBlue = unhand(blueComponent)->body;
char *currentGreen = unhand(greenComponent)->body;
if ((redComponent == NULL) || (greenComponent == NULL) || (blueComponent == NULL)) {
SignalError(0, JAVAPKG "OutOfMemoryError", 0);
return NULL;
}
// Fill in the red, green and blue component arrays.
currentColorSpec = (**defaultColorTable).ctTable;
for (UInt32 currentItem = 0; currentItem < 256; currentItem++) {
*currentRed++ = currentColorSpec->rgb.red >> 8;
*currentBlue++ = currentColorSpec->rgb.blue >> 8;
*currentGreen++ = currentColorSpec->rgb.green >> 8;
}
// We are finished with the color table. Reselase it.
ReleaseResource((Handle)defaultColorTable);
// Execute the constructor for the color model object.
awt_colormodel = (Hjava_awt_image_ColorModel *)execute_java_constructor(EE(), "java/awt/image/IndexColorModel", 0,
"(II[B[B[B)", 8, 256, redComponent, greenComponent, greenComponent);
gStandard8BitColorModel = awt_colormodel;
return awt_colormodel;
}
long sun_awt_macos_MToolkit_getScreenResolution(struct Hsun_awt_macos_MToolkit *toolkit)
{
// Even though multi-sync monitors make this untrue, for now
// return the classic Macintosh 72 dpi.
return 72;
}
long sun_awt_macos_MToolkit_getScreenWidth(struct Hsun_awt_macos_MToolkit *toolkit)
{
GetScreenResolution();
return gMainScreenBounds.right - gMainScreenBounds.left;
}
long sun_awt_macos_MToolkit_getScreenHeight(struct Hsun_awt_macos_MToolkit *toolkit)
{
GetScreenResolution();
return gMainScreenBounds.bottom - gMainScreenBounds.top;
}
void sun_awt_macos_MToolkit_sync(struct Hsun_awt_macos_MToolkit *toolkit)
{
// On the macintosh, this does nothing (up to nowÉ)
}