mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1542 lines
40 KiB
1542 lines
40 KiB
/***
|
|
*mcdsptst.cpp
|
|
*
|
|
* Copyright (C) 1992, Microsoft Corporation. All Rights Reserved.
|
|
* Information Contained Herein Is Proprietary and Confidential.
|
|
*
|
|
*Purpose:
|
|
* UNDONE
|
|
*
|
|
*
|
|
*Revision History:
|
|
*
|
|
* [00] 28-Apr-93 bradlo: Created from TESample.c.
|
|
*
|
|
*Implementation Notes:
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
|
|
#include "sdisptst.h"
|
|
#include "macmain.h"
|
|
#include "resource.h"
|
|
|
|
ASSERTDATA
|
|
|
|
|
|
#if HC_MPW
|
|
extern "C" void _DataInit(void);
|
|
#endif
|
|
|
|
extern "C" CDECL_(void) DbPrintf(char *szFormat, ...);
|
|
|
|
|
|
/* A Doc struct contains the WindowRecord for one of our document
|
|
windows, as well as the TEHandle for the text we are editing. Other
|
|
document fields can be added to this record as needed. For a similar
|
|
example, see how the Window Manager and Dialog Manager add fields
|
|
after the GrafPort. */
|
|
typedef struct {
|
|
WindowRecord docWindow;
|
|
TEHandle docTE;
|
|
ControlHandle docVScroll;
|
|
ControlHandle docHScroll;
|
|
ProcPtr docClik;
|
|
} Doc;
|
|
|
|
|
|
SysEnvRec g_sysenv;
|
|
Boolean g_fInitOle = false;
|
|
Boolean g_fInBackground = false;
|
|
Boolean g_fLibrariesLoaded = false;
|
|
|
|
short g_cNumDocs = 0;
|
|
|
|
|
|
|
|
/* Define HIWRD and LOWRD macros for efficiency. */
|
|
#define HIWRD(aLong) (((aLong) >> 16) & 0xFFFF)
|
|
#define LOWRD(aLong) ((aLong) & 0xFFFF)
|
|
|
|
/* Define TOPLEFT and BOTRIGHT macros for convenience. Notice the implicit
|
|
dependency on the ordering of fields within a Rect */
|
|
#define TOPLEFT(aRect) (*(Point*)&(aRect).top)
|
|
#define BOTRIGHT(aRect) (*(Point*)&(aRect).bottom)
|
|
|
|
|
|
void
|
|
Exit()
|
|
{
|
|
if(g_fInitOle)
|
|
UninitOle();
|
|
#ifndef _PPCMAC
|
|
if(g_fLibrariesLoaded)
|
|
UninitOleManager(); // clean up applet
|
|
#endif
|
|
ExitToShell();
|
|
}
|
|
|
|
/* display fatal error alert, and exit */
|
|
void
|
|
Fatal(char *msg)
|
|
{
|
|
static const unsigned char pnil[2] = {0,0};
|
|
unsigned char buf[128];
|
|
|
|
SetCursor(&qd.arrow);
|
|
|
|
buf[0] = (unsigned char)strlen(msg);
|
|
memcpy(&buf[1], msg, buf[0]+1);
|
|
|
|
ParamText(buf, pnil, pnil, pnil);
|
|
Alert(rUserAlert, nil);
|
|
Exit();
|
|
}
|
|
|
|
extern "C" int
|
|
main()
|
|
{
|
|
Init();
|
|
|
|
long l = OleBuildVersion();
|
|
DbPrintf("OleBuildVersion = %d.%d\n", (int)HIWRD(l), (int)LOWRD(l));
|
|
|
|
EventLoop();
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Get events forever, and handle them by calling DoEvent.
|
|
Also call AdjustCursor each time through the loop. */
|
|
void
|
|
EventLoop()
|
|
{
|
|
Point mouse;
|
|
Boolean gotEvent;
|
|
EventRecord event;
|
|
RgnHandle cursorRgn;
|
|
|
|
cursorRgn = NewRgn(); /* we'll pass WNE an empty region the 1st time thru */
|
|
do{
|
|
GetGlobalMouse(&mouse);
|
|
AdjustCursor(mouse, cursorRgn);
|
|
gotEvent = WaitNextEvent(everyEvent, &event, GetSleep(), cursorRgn);
|
|
if(gotEvent){
|
|
/* make sure we have the right cursor before handling the event */
|
|
AdjustCursor(event.where, cursorRgn);
|
|
DoEvent(&event);
|
|
}else{
|
|
DoIdle(); /* perform idle tasks when it's not our event */
|
|
}
|
|
|
|
}while(true);
|
|
}
|
|
|
|
|
|
/* Do the right thing for an event. Determine what kind of event it is,
|
|
and call the appropriate routines. */
|
|
void
|
|
DoEvent(EventRecord *pevent)
|
|
{
|
|
char key;
|
|
short part;
|
|
WindowPtr window;
|
|
|
|
switch(pevent->what){
|
|
case nullEvent:
|
|
// we idle for null/mouse moved events ands for events which
|
|
// aren't ours (see EventLoop)
|
|
DoIdle();
|
|
break;
|
|
|
|
case mouseDown:
|
|
part = FindWindow(pevent->where, &window);
|
|
switch(part){
|
|
case inMenuBar: /* process a mouse menu command (if any) */
|
|
AdjustMenus(); /* bring 'em up-to-date */
|
|
DoMenuCommand(MenuSelect(pevent->where));
|
|
break;
|
|
|
|
case inSysWindow: /* let the system handle the mouseDown */
|
|
SystemClick(pevent, window);
|
|
break;
|
|
|
|
case inContent:
|
|
if(window != FrontWindow()){
|
|
SelectWindow(window);
|
|
}else{
|
|
DoContentClick(window, pevent);
|
|
}
|
|
break;
|
|
|
|
case inDrag: /* pass screenBits.bounds to get all gDevices */
|
|
DragWindow(window, pevent->where, &qd.screenBits.bounds);
|
|
break;
|
|
|
|
case inGoAway:
|
|
if(TrackGoAway(window, pevent->where))
|
|
DoCloseWindow(window); /* we don't care if the user cancelled */
|
|
break;
|
|
|
|
case inGrow:
|
|
DoGrowWindow(window, pevent);
|
|
break;
|
|
|
|
case inZoomIn:
|
|
case inZoomOut:
|
|
if(TrackBox(window, pevent->where, part))
|
|
DoZoomWindow(window, part);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case keyDown:
|
|
case autoKey: /* check for menukey equivalents */
|
|
key = (char)(pevent->message & charCodeMask);
|
|
if(pevent->modifiers & cmdKey){/* Command key down */
|
|
if(pevent->what == keyDown){
|
|
AdjustMenus(); /* enable/disable/check menu items properly */
|
|
DoMenuCommand(MenuKey(key));
|
|
}
|
|
}else{
|
|
DoKeyDown(pevent);
|
|
}
|
|
break;
|
|
|
|
case activateEvt:
|
|
DoActivate(
|
|
(WindowPtr)pevent->message,
|
|
(Boolean)((pevent->modifiers & activeFlag) != 0));
|
|
break;
|
|
|
|
case updateEvt:
|
|
DoUpdate((WindowPtr) pevent->message);
|
|
break;
|
|
|
|
case kOSEvent:
|
|
switch((pevent->message >> 24) & 0x0FF){ /* high byte of message */
|
|
case kMouseMovedMessage:
|
|
DoIdle(); /* mouse-moved is also an idle event */
|
|
break;
|
|
|
|
case kSuspendResumeMessage:
|
|
/* suspend/resume is also an activate/deactivate */
|
|
g_fInBackground = (pevent->message & kResumeMask) == 0;
|
|
DoActivate(FrontWindow(), (Boolean)!g_fInBackground);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case kHighLevelEvent:
|
|
AEProcessAppleEvent(pevent);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Change the cursor's shape, depending on its position. */
|
|
void
|
|
AdjustCursor(Point mouse, RgnHandle region)
|
|
{
|
|
Rect iBeamRect;
|
|
WindowPtr window;
|
|
RgnHandle arrowRgn;
|
|
RgnHandle iBeamRgn;
|
|
|
|
/* we only adjust the cursor when we are in front */
|
|
window = FrontWindow();
|
|
|
|
if((!g_fInBackground) && (!IsDAWindow(window))){
|
|
/* calculate regions for different cursor shapes */
|
|
arrowRgn = NewRgn();
|
|
iBeamRgn = NewRgn();
|
|
|
|
/* start arrowRgn wide open */
|
|
SetRectRgn(arrowRgn, kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos);
|
|
|
|
/* calculate iBeamRgn */
|
|
if(IsAppWindow(window)){
|
|
iBeamRect = (*((Doc*)window)->docTE)->viewRect;
|
|
SetPort(window); /* make a global version of the viewRect */
|
|
LocalToGlobal(&TOPLEFT(iBeamRect));
|
|
LocalToGlobal(&BOTRIGHT(iBeamRect));
|
|
RectRgn(iBeamRgn, &iBeamRect);
|
|
/* we temporarily change the port's origin to "globalfy" the visRgn */
|
|
SetOrigin(
|
|
(short)-window->portBits.bounds.left,
|
|
(short)-window->portBits.bounds.top);
|
|
SectRgn(iBeamRgn, window->visRgn, iBeamRgn);
|
|
SetOrigin((short)0, (short)0);
|
|
}
|
|
|
|
/* subtract other regions from arrowRgn */
|
|
DiffRgn(arrowRgn, iBeamRgn, arrowRgn);
|
|
|
|
/* change the cursor and the region parameter */
|
|
if(PtInRgn(mouse, iBeamRgn)){
|
|
SetCursor(*GetCursor(iBeamCursor));
|
|
CopyRgn(iBeamRgn, region);
|
|
}else{
|
|
SetCursor(&qd.arrow);
|
|
CopyRgn(arrowRgn, region);
|
|
}
|
|
DisposeRgn(arrowRgn);
|
|
DisposeRgn(iBeamRgn);
|
|
}
|
|
}
|
|
|
|
/* Get the global coordinates of the mouse. When you call OSEventAvail
|
|
it will return either a pending event or a null event. In either case,
|
|
the where field of the event record will contain the current position
|
|
of the mouse in global coordinates and the modifiers field will reflect
|
|
the current state of the modifiers. Another way to get the global
|
|
coordinates is to call GetMouse and LocalToGlobal, but that requires
|
|
being sure that thePort is set to a valid port. */
|
|
void
|
|
GetGlobalMouse(Point *mouse)
|
|
{
|
|
EventRecord event;
|
|
|
|
/* we aren't interested in any events */
|
|
OSEventAvail(kNoEvents, &event);
|
|
|
|
/* just the mouse position */
|
|
*mouse = event.where;
|
|
}
|
|
|
|
/* Called when a mouseDown occurs in the grow box of an active window.
|
|
In order to eliminate any 'flicker', we want to invalidate only what
|
|
is necessary. Since ResizeWindow invalidates the whole portRect, we
|
|
save the old TE viewRect, intersect it with the new TE viewRect, and
|
|
remove the result from the update region. However, we must make sure
|
|
that any old update region that might have been around gets put back. */
|
|
void
|
|
DoGrowWindow(WindowPtr window, EventRecord *event)
|
|
{
|
|
Rect tempRect;
|
|
long growResult;
|
|
Doc* doc;
|
|
RgnHandle tempRgn;
|
|
|
|
tempRect = qd.screenBits.bounds; /* set up limiting values */
|
|
tempRect.left = kMinDocDim;
|
|
tempRect.top = kMinDocDim;
|
|
growResult = GrowWindow(window, event->where, &tempRect);
|
|
|
|
/* see if it really changed size */
|
|
if(growResult != 0){
|
|
doc = (Doc*)window;
|
|
/* save old text box */
|
|
tempRect = (*doc->docTE)->viewRect;
|
|
tempRgn = NewRgn();
|
|
/* get localized update region */
|
|
GetLocalUpdateRgn(window, tempRgn);
|
|
SizeWindow(window, (short)LOWRD(growResult), (short)HIWRD(growResult), (Boolean)true);
|
|
ResizeWindow(window);
|
|
|
|
/* calculate & validate the region that hasn't changed so
|
|
it won't get redrawn */
|
|
SectRect(&tempRect, &(*doc->docTE)->viewRect, &tempRect);
|
|
ValidRect(&tempRect); /* take it out of update */
|
|
InvalRgn(tempRgn); /* put back any prior update */
|
|
DisposeRgn(tempRgn);
|
|
}
|
|
}
|
|
|
|
/* Called when a mouseClick occurs in the zoom box of an active window.
|
|
Everything has to get re-drawn here, so we don't mind that
|
|
ResizeWindow invalidates the whole portRect. */
|
|
void DoZoomWindow(WindowPtr window, short part)
|
|
{
|
|
EraseRect(&window->portRect);
|
|
ZoomWindow(window, part, (Boolean)(window == FrontWindow()));
|
|
ResizeWindow(window);
|
|
}
|
|
|
|
/* Called when the window has been resized to fix up the controls and
|
|
content. */
|
|
void ResizeWindow(WindowPtr window)
|
|
{
|
|
AdjustScrollbars(window, true);
|
|
AdjustTE(window);
|
|
InvalRect(&window->portRect);
|
|
}
|
|
|
|
/* Returns the update region in local coordinates */
|
|
void GetLocalUpdateRgn(WindowPtr window, RgnHandle localRgn)
|
|
{
|
|
/* save old update region */
|
|
CopyRgn(((WindowPeek) window)->updateRgn, localRgn);
|
|
|
|
OffsetRgn(
|
|
localRgn,
|
|
window->portBits.bounds.left,
|
|
window->portBits.bounds.top);
|
|
}
|
|
|
|
void
|
|
DoUpdate(WindowPtr window)
|
|
{
|
|
if(IsAppWindow(window)){
|
|
/* this sets up the visRgn */
|
|
BeginUpdate(window);
|
|
/* draw if updating needs to be done */
|
|
if(!EmptyRgn(window->visRgn))
|
|
DrawWindow(window);
|
|
EndUpdate(window);
|
|
}
|
|
}
|
|
|
|
/* This is called when a window is activated or deactivated.
|
|
It calls TextEdit to deal with the selection. */
|
|
void
|
|
DoActivate(WindowPtr window, Boolean becomingActive)
|
|
{
|
|
Rect growRect;
|
|
Doc* doc;
|
|
RgnHandle tempRgn, clipRgn;
|
|
|
|
if(IsAppWindow(window)){
|
|
doc = (Doc*)window;
|
|
if(becomingActive){
|
|
/* since we don't want TEActivate to draw a selection in an
|
|
area where we're going to erase and redraw, we'll clip
|
|
out the update region before calling it. */
|
|
tempRgn = NewRgn();
|
|
clipRgn = NewRgn();
|
|
/* get localized update region */
|
|
GetLocalUpdateRgn(window, tempRgn);
|
|
GetClip(clipRgn);
|
|
/* subtract updateRgn from clipRgn */
|
|
DiffRgn(clipRgn, tempRgn, tempRgn);
|
|
SetClip(tempRgn);
|
|
TEActivate(doc->docTE);
|
|
/* restore the full-blown clipRgn */
|
|
SetClip(clipRgn);
|
|
DisposeRgn(tempRgn);
|
|
DisposeRgn(clipRgn);
|
|
|
|
/* the controls must be redrawn on activation: */
|
|
(*doc->docVScroll)->contrlVis = kControlVisible;
|
|
(*doc->docHScroll)->contrlVis = kControlVisible;
|
|
InvalRect(&(*doc->docVScroll)->contrlRect);
|
|
InvalRect(&(*doc->docHScroll)->contrlRect);
|
|
/* the growbox needs to be redrawn on activation: */
|
|
growRect = window->portRect;
|
|
/* adjust for the scrollbars */
|
|
growRect.top = growRect.bottom - kScrollbarAdjust;
|
|
growRect.left = growRect.right - kScrollbarAdjust;
|
|
InvalRect(&growRect);
|
|
}else{
|
|
TEDeactivate(doc->docTE);
|
|
/* the controls must be hidden on deactivation: */
|
|
HideControl(doc->docVScroll);
|
|
HideControl(doc->docHScroll);
|
|
/* the growbox should be changed immediately on deactivation: */
|
|
DrawGrowIcon(window);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* This is called when a mouseDown occurs in the content of a window. */
|
|
void
|
|
DoContentClick(WindowPtr window, EventRecord *event)
|
|
{
|
|
Rect teRect;
|
|
Point mouse;
|
|
Doc* doc;
|
|
short part, value;
|
|
Boolean shiftDown;
|
|
ControlHandle control;
|
|
|
|
if(IsAppWindow(window)){
|
|
SetPort(window);
|
|
mouse = event->where; /* get the click position */
|
|
GlobalToLocal(&mouse);
|
|
doc = (Doc*)window;
|
|
/* see if we are in the viewRect. if so, we won't check the controls */
|
|
GetTERect(window, &teRect);
|
|
if(PtInRect(mouse, &teRect)){
|
|
/* see if we need to extend the selection - extend if Shift is down */
|
|
shiftDown = (event->modifiers & shiftKey) != 0;
|
|
TEClick(mouse, shiftDown, doc->docTE);
|
|
PascalClikLoop();
|
|
}else{
|
|
part = FindControl(mouse, window, &control);
|
|
switch(part){
|
|
case 0: /* do nothing for viewRect case */
|
|
break;
|
|
case inThumb:
|
|
value = GetCtlValue(control);
|
|
part = TrackControl(control, mouse, nil);
|
|
if(part != 0){
|
|
value -= GetCtlValue(control);
|
|
/* value now has CHANGE in value; if value changed, scroll */
|
|
if(value != 0){
|
|
if(control == doc->docVScroll){
|
|
TEScroll(
|
|
(short)0,
|
|
(short)(value * (*doc->docTE)->lineHeight),
|
|
doc->docTE);
|
|
}else{
|
|
TEScroll((short)value, (short)0, doc->docTE);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default: /* they clicked in an arrow, so track & scroll */
|
|
if(control == doc->docVScroll)
|
|
#ifdef _PPCMAC
|
|
value = TrackControl(control, mouse, (ControlActionUPP)VActionProc);
|
|
else
|
|
value = TrackControl(control, mouse, (ControlActionUPP)HActionProc);
|
|
#else
|
|
value = TrackControl(control, mouse, (ProcPtr)VActionProc);
|
|
else
|
|
value = TrackControl(control, mouse, (ProcPtr)HActionProc);
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* This is called for any keyDown or autoKey events, except when the
|
|
Command key is held down. It looks at the frontmost window to decide what
|
|
to do with the key typed. */
|
|
void
|
|
DoKeyDown(EventRecord *event)
|
|
{
|
|
char key;
|
|
TEHandle te;
|
|
WindowPtr window;
|
|
|
|
window = FrontWindow();
|
|
if(IsAppWindow(window)){
|
|
te = ((Doc*) window)->docTE;
|
|
key = (char)(event->message & charCodeMask);
|
|
/* we have a char. for our window; see if we are still below TextEditÕs
|
|
limit for the number of characters (but deletes are always rad) */
|
|
if(key == kDelChar
|
|
|| (*te)->teLength - ((*te)->selEnd - (*te)->selStart)+1 < kMaxTELength)
|
|
{
|
|
TEKey(key, te);
|
|
AdjustScrollbars(window, false);
|
|
AdjustTE(window);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Common algorithm for pinning the value of a control. It returns
|
|
the actual amount the value of the control changed. Note the
|
|
pinning is done for the sake of returning the amount the control
|
|
value changed. */
|
|
void
|
|
CommonAction(ControlHandle control, short *amount)
|
|
{
|
|
short value, max;
|
|
|
|
value = GetCtlValue(control); /* get current value */
|
|
max = GetCtlMax(control); /* and maximum value */
|
|
*amount = value - *amount;
|
|
if(*amount < 0)
|
|
*amount = 0;
|
|
else if(*amount > max)
|
|
*amount = max;
|
|
SetCtlValue(control, *amount);
|
|
*amount = value - *amount; /* calculate the real change */
|
|
}
|
|
|
|
/* Determines how much to change the value of the vertical scrollbar
|
|
by and how much to scroll the TE record. */
|
|
extern "C"
|
|
PASCAL_(void)
|
|
VActionProc(ControlHandle control, short part)
|
|
{
|
|
TEPtr te;
|
|
short amount;
|
|
WindowPtr window;
|
|
|
|
if(part != 0){ /* if it was actually in the control */
|
|
window = (*control)->contrlOwner;
|
|
te = *((Doc*) window)->docTE;
|
|
switch(part){
|
|
case inUpButton:
|
|
case inDownButton: /* one line */
|
|
amount = 1;
|
|
break;
|
|
case inPageUp: /* one page */
|
|
case inPageDown:
|
|
amount = (te->viewRect.bottom - te->viewRect.top) / te->lineHeight;
|
|
break;
|
|
}
|
|
if((part == inDownButton) || (part == inPageDown))
|
|
amount = -amount; /* reverse direction for a downer */
|
|
CommonAction(control, &amount);
|
|
if(amount != 0){
|
|
TEScroll((short)0,
|
|
(short)(amount * te->lineHeight),
|
|
((Doc*)window)->docTE);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Determines how much to change the value of the horizontal scrollbar
|
|
by and how much to scroll the TE record. */
|
|
extern "C"
|
|
PASCAL_(void)
|
|
HActionProc(ControlHandle control, short part)
|
|
{
|
|
TEPtr te;
|
|
short amount;
|
|
WindowPtr window;
|
|
|
|
if(part != 0){
|
|
window = (*control)->contrlOwner;
|
|
te = *((Doc*) window)->docTE;
|
|
switch(part){
|
|
case inUpButton:
|
|
case inDownButton: /* a few pixels */
|
|
amount = kButtonScroll;
|
|
break;
|
|
case inPageUp: /* a page */
|
|
case inPageDown:
|
|
amount = te->viewRect.right - te->viewRect.left;
|
|
break;
|
|
}
|
|
if((part == inDownButton) || (part == inPageDown))
|
|
amount = -amount; /* reverse direction */
|
|
CommonAction(control, &amount);
|
|
if(amount != 0)
|
|
TEScroll(amount, 0, ((Doc*) window)->docTE);
|
|
}
|
|
}
|
|
|
|
/* This is called whenever we get a null event et al. It takes care
|
|
of necessary periodic actions. For this program, it calls TEIdle. */
|
|
void
|
|
DoIdle()
|
|
{
|
|
WindowPtr window;
|
|
|
|
window = FrontWindow();
|
|
if(IsAppWindow(window))
|
|
TEIdle(((Doc*)window)->docTE);
|
|
}
|
|
|
|
/* Draw the contents of an application window. */
|
|
void DrawWindow(WindowPtr window)
|
|
{
|
|
SetPort(window);
|
|
EraseRect(&window->portRect);
|
|
DrawControls(window);
|
|
DrawGrowIcon(window);
|
|
TEUpdate(&window->portRect, ((Doc*)window)->docTE);
|
|
}
|
|
|
|
/* Enable and disable menus based on the current state. */
|
|
|
|
void DoEnableItem(MenuHandle hmenu, short sItem) {
|
|
EnableItem(hmenu, sItem);
|
|
}
|
|
|
|
void DoDisableItem(MenuHandle hmenu, short sItem) {
|
|
DisableItem(hmenu, sItem);
|
|
}
|
|
|
|
/* Enable and disable menus based on the current state. */
|
|
void
|
|
AdjustMenus()
|
|
{
|
|
long offset;
|
|
TEHandle hte;
|
|
MenuHandle menu;
|
|
WindowPtr window;
|
|
Boolean undo;
|
|
Boolean paste;
|
|
Boolean cutCopyClear;
|
|
void (*pfnEnable)(MenuHandle, short);
|
|
|
|
#if 0
|
|
File
|
|
New
|
|
Close
|
|
|
|
Edit
|
|
Undo
|
|
Cut
|
|
Copy
|
|
Clear
|
|
Paste
|
|
#endif
|
|
|
|
window = FrontWindow();
|
|
|
|
menu = GetMHandle(mFile);
|
|
|
|
pfnEnable = ((g_cNumDocs < kMaxOpenDocs) ? DoEnableItem : DoDisableItem);
|
|
pfnEnable(menu, iNew);
|
|
|
|
pfnEnable = ((window != nil) ? DoEnableItem : DoDisableItem);
|
|
pfnEnable(menu, iClose);
|
|
|
|
menu = GetMHandle(mEdit);
|
|
undo = false;
|
|
paste = false;
|
|
cutCopyClear = false;
|
|
|
|
if(IsDAWindow(window)){
|
|
undo = true; /* all editing is enabled for DA windows */
|
|
cutCopyClear = true;
|
|
paste = true;
|
|
}else if(IsAppWindow(window)){
|
|
hte = ((Doc*) window)->docTE;
|
|
if((*hte)->selStart < (*hte)->selEnd){
|
|
/* Cut, Copy, and Clear is enabled for app. windows with selections */
|
|
cutCopyClear = true;
|
|
}
|
|
if(GetScrap(nil, 'TEXT', &offset) > 0){
|
|
/* if there's any text in the clipboard, paste is enabled */
|
|
paste = true;
|
|
}
|
|
}
|
|
|
|
pfnEnable = (undo) ? DoEnableItem : DoDisableItem;
|
|
pfnEnable(menu, iUndo);
|
|
|
|
pfnEnable = (cutCopyClear) ? DoEnableItem : DoDisableItem;
|
|
pfnEnable(menu, iCut);
|
|
pfnEnable(menu, iCopy);
|
|
pfnEnable(menu, iClear);
|
|
|
|
pfnEnable = (paste) ? DoEnableItem : DoDisableItem;
|
|
pfnEnable(menu, iPaste);
|
|
}
|
|
|
|
|
|
/* This is called when an item is chosen from the menu bar (after calling
|
|
MenuSelect or MenuKey). It does the right thing for each command. */
|
|
void
|
|
DoMenuCommand(long menuResult)
|
|
{
|
|
TEHandle te;
|
|
Str255 daName;
|
|
OSErr saveErr;
|
|
Handle aHandle;
|
|
WindowPtr window;
|
|
long oldSize, newSize, total, contig;
|
|
short menuID, menuItem, itemHit, daRefNum;
|
|
|
|
window = FrontWindow();
|
|
|
|
menuID = (short)HIWRD(menuResult);
|
|
menuItem = (short)LOWRD(menuResult);
|
|
|
|
/* get menu item number and menu number */
|
|
switch(menuID){
|
|
case mApple:
|
|
switch(menuItem){
|
|
case iAbout: /* bring up alert for About */
|
|
itemHit = Alert(rAboutAlert, nil);
|
|
break;
|
|
default: /* all non-About items in this menu are DAs et al */
|
|
/* type Str255 is an array in MPW 3 */
|
|
GetMenuItemText(GetMHandle(mApple), menuItem, daName);
|
|
daRefNum = OpenDeskAcc(daName);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case mFile:
|
|
switch(menuItem){
|
|
case iNew:
|
|
DoNew();
|
|
break;
|
|
case iClose:
|
|
DoCloseWindow(FrontWindow()); /* ignore the result */
|
|
break;
|
|
case iQuit:
|
|
Terminate();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case mEdit: /* call SystemEdit for DA editing & MultiFinder */
|
|
if(!SystemEdit((short)(menuItem-1))){
|
|
te = ((Doc*)FrontWindow())->docTE;
|
|
switch(menuItem){
|
|
case iCut:
|
|
if(ZeroScrap() == noErr){
|
|
PurgeSpace(&total, &contig);
|
|
if((*te)->selEnd - (*te)->selStart + kTESlop > contig){
|
|
AlertUser(eNoSpaceCut);
|
|
}else{
|
|
TECut(te);
|
|
if(TEToScrap() != noErr){
|
|
AlertUser(eNoCut);
|
|
ZeroScrap();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case iCopy:
|
|
if(ZeroScrap() == noErr){
|
|
TECopy(te); /* after copying, export the TE scrap */
|
|
if(TEToScrap() != noErr){
|
|
AlertUser(eNoCopy);
|
|
ZeroScrap();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case iPaste: /* import the TE scrap before pasting */
|
|
if(TEFromScrap() == noErr){
|
|
if(TEGetScrapLen() + ((*te)->teLength -
|
|
((*te)->selEnd - (*te)->selStart)) > kMaxTELength){
|
|
AlertUser(eExceedPaste);
|
|
}else{
|
|
aHandle = (Handle)TEGetText(te);
|
|
oldSize = GetHandleSize(aHandle);
|
|
newSize = oldSize + TEGetScrapLen() + kTESlop;
|
|
SetHandleSize(aHandle, newSize);
|
|
saveErr = MemError();
|
|
SetHandleSize(aHandle, oldSize);
|
|
if(saveErr != noErr)
|
|
AlertUser(eNoSpacePaste);
|
|
else
|
|
TEPaste(te);
|
|
}
|
|
}else{
|
|
AlertUser(eNoPaste);
|
|
}
|
|
break;
|
|
|
|
case iClear:
|
|
TEDelete(te);
|
|
break;
|
|
}
|
|
AdjustScrollbars(window, false);
|
|
AdjustTE(window);
|
|
}
|
|
break;
|
|
|
|
case mOptions:
|
|
switch(menuItem){
|
|
case iClearAll:
|
|
te = ((Doc*)FrontWindow())->docTE;
|
|
TESetSelect(0, 32767, te);
|
|
TEDelete(te);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
HiliteMenu(0); /* unhighlight what MenuSelect (or MenuKey) hilited */
|
|
}
|
|
|
|
/* Create a new document and window. */
|
|
void
|
|
DoNew()
|
|
{
|
|
Ptr storage;
|
|
Boolean good;
|
|
Doc* doc;
|
|
WindowPtr window;
|
|
Rect destRect, viewRect;
|
|
|
|
storage = NewPtr(sizeof(Doc));
|
|
if(storage != nil){
|
|
window = GetNewWindow(rDocWindow, storage, (WindowPtr) -1);
|
|
if(window != nil){
|
|
/* this will be decremented when we call DoCloseWindow */
|
|
good = false;
|
|
g_cNumDocs += 1;
|
|
SetPort(window);
|
|
|
|
short font;
|
|
GetFNum((const unsigned char*)"\006Monaco", &font);
|
|
TextFont(font);
|
|
TextSize(9);
|
|
|
|
doc = (Doc*)window;
|
|
GetTERect(window, &viewRect);
|
|
destRect = viewRect;
|
|
destRect.right = destRect.left + kMaxDocWidth;
|
|
doc->docTE = TENew(&destRect, &viewRect);
|
|
|
|
/* if TENew succeeded, we have a good document */
|
|
good = doc->docTE != nil;
|
|
if(good){
|
|
AdjustViewRect(doc->docTE);
|
|
TEAutoView(true, doc->docTE);
|
|
}
|
|
|
|
if(good){
|
|
doc->docVScroll = GetNewControl(rVScroll, window);
|
|
good = (doc->docVScroll != nil);
|
|
}
|
|
|
|
if(good){
|
|
doc->docHScroll = GetNewControl(rHScroll, window);
|
|
good = (doc->docHScroll != nil);
|
|
}
|
|
|
|
if(good){ /* good? adjust & draw the controls, draw the window */
|
|
/* false to AdjustScrollValues means musn't redraw;
|
|
technically, of course, the window is hidden so
|
|
it wouldn't matter whether we called ShowControl
|
|
or not. */
|
|
AdjustScrollValues(window, false);
|
|
ShowWindow(window);
|
|
}else{
|
|
/* otherwise regret we ever created it... */
|
|
DoCloseWindow(window);
|
|
AlertUser(eNoWindow);
|
|
}
|
|
}else{
|
|
/* get rid of the storage if it is never used */
|
|
DisposPtr(storage);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Close a window. This handles desk accessory and application windows. */
|
|
/* 1.01 - At this point, if there was a document associated with a
|
|
window, you could do any document saving processing if it is 'dirty'.
|
|
DoCloseWindow would return true if the window actually closed, i.e.,
|
|
the user didn't cancel from a save dialog. This result is handy when
|
|
the user quits an application, but then cancels the save of a document
|
|
associated with a window. */
|
|
Boolean
|
|
DoCloseWindow(WindowPtr window)
|
|
{
|
|
TEHandle te;
|
|
|
|
if(IsDAWindow(window)){
|
|
CloseDeskAcc(((WindowPeek) window)->windowKind);
|
|
}else if(IsAppWindow(window)){
|
|
te = ((Doc*)window)->docTE;
|
|
if(te != nil){
|
|
/* dispose the TEHandle if we got far enough to make one */
|
|
TEDispose(te);
|
|
}
|
|
CloseWindow(window);
|
|
DisposPtr((Ptr)window);
|
|
g_cNumDocs -= 1;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/* Clean up the application and exit. We close all of the windows
|
|
so that they can update their documents, if any. */
|
|
void
|
|
Terminate()
|
|
{
|
|
Boolean closed;
|
|
WindowPtr aWindow;
|
|
|
|
closed = true;
|
|
do{
|
|
aWindow = FrontWindow(); /* get the current front window */
|
|
if(aWindow != nil)
|
|
closed = DoCloseWindow(aWindow); /* close this window */
|
|
} while (closed && (aWindow != nil));
|
|
|
|
if(closed)
|
|
Exit(); /* exit if no cancellation */
|
|
}
|
|
|
|
/* Return a rectangle that is inset from the portRect by the
|
|
size of the scrollbars and a little extra margin. */
|
|
void
|
|
GetTERect(WindowPtr window, Rect *teRect)
|
|
{
|
|
*teRect = window->portRect;
|
|
InsetRect(teRect, kTextMargin, kTextMargin);/* adjust for margin */
|
|
teRect->bottom = teRect->bottom - 15; /* and for the scrollbars */
|
|
teRect->right = teRect->right - 15;
|
|
}
|
|
|
|
/* Update the TERec's view rect so that it is the greatest multiple
|
|
of the lineHeight that still fits in the old viewRect. */
|
|
void
|
|
AdjustViewRect(TEHandle docTE)
|
|
{
|
|
TEPtr te;
|
|
|
|
te = *docTE;
|
|
te->viewRect.bottom = (((te->viewRect.bottom - te->viewRect.top) / te->lineHeight) * te->lineHeight) + te->viewRect.top;
|
|
}
|
|
|
|
/* Scroll the TERec around to match up to the potentially updated
|
|
scrollbar values. This is really useful when the window has been
|
|
resized such that the scrollbars became inactive but the TERec
|
|
was already scrolled. */
|
|
void
|
|
AdjustTE(WindowPtr window)
|
|
{
|
|
TEPtr te;
|
|
|
|
te = *((Doc*)window)->docTE;
|
|
|
|
TEScroll(
|
|
(short)((te->viewRect.left - te->destRect.left) -
|
|
GetCtlValue(((Doc*)window)->docHScroll)),
|
|
(short)((te->viewRect.top - te->destRect.top) -
|
|
(GetCtlValue(((Doc*)window)->docVScroll) * te->lineHeight)),
|
|
((Doc*)window)->docTE);
|
|
}
|
|
|
|
|
|
/* Calculate the new control maximum value and current value, whether
|
|
it is the horizontal or vertical scrollbar. The vertical max is
|
|
calculated by comparing the number of lines to the vertical size
|
|
of the viewRect. The horizontal max is calculated by comparing the
|
|
maximum document width to the width of the viewRect. The current
|
|
values are set by comparing the offset between the view and
|
|
destination rects. If necessary and we canRedraw, have the control
|
|
be re-drawn by calling ShowControl. */
|
|
void
|
|
AdjustHV(
|
|
Boolean isVert,
|
|
ControlHandle control,
|
|
TEHandle docTE,
|
|
Boolean canRedraw)
|
|
{
|
|
TEPtr te;
|
|
short value, lines, max, oldValue, oldMax;
|
|
|
|
oldValue = GetCtlValue(control);
|
|
oldMax = GetCtlMax(control);
|
|
te = *docTE; /* point to TERec for convenience */
|
|
|
|
if(isVert){
|
|
lines = te->nLines;
|
|
/* since nLines isn't right if the last character is a return,
|
|
check for that case */
|
|
if(*(*te->hText + te->teLength - 1) == kCrChar)
|
|
lines += 1;
|
|
max = lines - ((te->viewRect.bottom - te->viewRect.top) / te->lineHeight);
|
|
}else{
|
|
max = kMaxDocWidth - (te->viewRect.right - te->viewRect.left);
|
|
}
|
|
|
|
if ( max < 0 ) max = 0;
|
|
SetCtlMax(control, max);
|
|
|
|
/* Must deref. after SetCtlMax since, technically, it could
|
|
draw and therefore move memory. This is why we don't just
|
|
do it once at the beginning. */
|
|
te = *docTE;
|
|
if(isVert)
|
|
value = (te->viewRect.top - te->destRect.top) / te->lineHeight;
|
|
else
|
|
value = te->viewRect.left - te->destRect.left;
|
|
|
|
if(value < 0)
|
|
value = 0;
|
|
else if(value > max)
|
|
value = max;
|
|
|
|
SetCtlValue(control, value);
|
|
/* now redraw the control if it needs to be and can be */
|
|
if(canRedraw || (max != oldMax) || (value != oldValue))
|
|
ShowControl(control);
|
|
}
|
|
|
|
/* Simply call the common adjust routine for the vertical and
|
|
horizontal scrollbars. */
|
|
void
|
|
AdjustScrollValues(WindowPtr window, Boolean canRedraw)
|
|
{
|
|
Doc* doc;
|
|
|
|
doc = (Doc*)window;
|
|
AdjustHV(true, doc->docVScroll, doc->docTE, canRedraw);
|
|
AdjustHV(false, doc->docHScroll, doc->docTE, canRedraw);
|
|
}
|
|
|
|
/* Re-calculate the position and size of the viewRect and the
|
|
scrollbars. kScrollTweek compensates for off-by-one requirements
|
|
of the scrollbars to have borders coincide with the growbox. */
|
|
void
|
|
AdjustScrollSizes(WindowPtr window)
|
|
{
|
|
Rect teRect;
|
|
Doc* doc;
|
|
|
|
doc = (Doc*) window;
|
|
GetTERect(window, &teRect); /* start with TERect */
|
|
(*doc->docTE)->viewRect = teRect;
|
|
AdjustViewRect(doc->docTE); /* snap to nearest line */
|
|
|
|
MoveControl(
|
|
doc->docVScroll,
|
|
(short)(window->portRect.right - kScrollbarAdjust),
|
|
(short)-1);
|
|
SizeControl(
|
|
doc->docVScroll,
|
|
(short)kScrollbarWidth,
|
|
(short)((window->portRect.bottom - window->portRect.top) -
|
|
(kScrollbarAdjust - kScrollTweek)));
|
|
|
|
MoveControl(
|
|
doc->docHScroll,
|
|
(short)-1,
|
|
(short)(window->portRect.bottom - kScrollbarAdjust));
|
|
SizeControl(
|
|
doc->docHScroll,
|
|
(short)((window->portRect.right - window->portRect.left) -
|
|
(kScrollbarAdjust - kScrollTweek)),
|
|
(short)kScrollbarWidth);
|
|
}
|
|
|
|
/* Turn off the controls by jamming a zero into their contrlVis
|
|
fields (HideControl erases them and we don't want that). If the
|
|
controls are to be resized as well, call the procedure to do that,
|
|
then call the procedure to adjust the maximum and current values.
|
|
Finally re-enable the controls by jamming a $FF in their contrlVis
|
|
fields. */
|
|
void
|
|
AdjustScrollbars(WindowPtr window, Boolean needsResize)
|
|
{
|
|
Doc* doc;
|
|
|
|
doc = (Doc*) window;
|
|
/* First, turn visibility of scrollbars off so we won't get
|
|
unwanted redrawing */
|
|
(*doc->docVScroll)->contrlVis = kControlInvisible; /* turn them off */
|
|
(*doc->docHScroll)->contrlVis = kControlInvisible;
|
|
if(needsResize) /* move & size as needed */
|
|
AdjustScrollSizes(window);
|
|
/* fool with max and current value */
|
|
AdjustScrollValues(window, needsResize);
|
|
/* Now, restore visibility in case we never had to ShowControl
|
|
during adjustment */
|
|
(*doc->docVScroll)->contrlVis = kControlVisible; /* turn them on */
|
|
(*doc->docHScroll)->contrlVis = kControlVisible;
|
|
}
|
|
|
|
/* Gets called from our assembly language routine, AsmClikLoop,
|
|
which is in turn called by the TEClick toolbox routine. Saves
|
|
the windows clip region, sets it to the portRect, adjusts the
|
|
scrollbar values to match the TE scroll amount, then restores
|
|
the clip region. */
|
|
PASCAL_(Boolean)
|
|
PascalClikLoop()
|
|
{
|
|
WindowPtr window;
|
|
RgnHandle region;
|
|
|
|
window = FrontWindow();
|
|
|
|
region = NewRgn();
|
|
GetClip(region); /* save clip */
|
|
ClipRect(&window->portRect);
|
|
AdjustScrollValues(window, true); /* pass true for canRedraw */
|
|
SetClip(region); /* restore clip */
|
|
DisposeRgn(region);
|
|
|
|
return true;
|
|
}
|
|
|
|
Boolean
|
|
IsAppWindow(WindowPtr window)
|
|
{
|
|
return (window == nil)
|
|
? false : (((WindowPeek)window)->windowKind == userKind);
|
|
}
|
|
|
|
/* Check to see if a window belongs to a desk accessory. */
|
|
Boolean IsDAWindow(WindowPtr window)
|
|
{
|
|
/* DA windows have negative windowKinds */
|
|
return (window == nil)
|
|
? false : (((WindowPeek)window)->windowKind < 0);
|
|
}
|
|
|
|
void
|
|
AlertUser(short error)
|
|
{
|
|
short itemHit;
|
|
Str255 message, tmp;
|
|
|
|
SetCursor(&qd.arrow);
|
|
GetIndString(message, kErrStrings, error);
|
|
tmp[0] = '\0';
|
|
ParamText(message, tmp, tmp, tmp);
|
|
itemHit = Alert(rUserAlert, nil);
|
|
}
|
|
|
|
PASCAL_(OSErr)
|
|
RemoteLowLevelEvt(
|
|
AppleEvent theAppEvt,
|
|
AppleEvent reply,
|
|
long HandlerRefCon)
|
|
{
|
|
long cb;
|
|
OSErr err;
|
|
DescType descType;
|
|
EventRecord event;
|
|
|
|
UNUSED(reply);
|
|
UNUSED(HandlerRefCon);
|
|
|
|
err = AEGetKeyPtr(
|
|
&theAppEvt,
|
|
keyDirectObject,
|
|
typeWildCard,
|
|
&descType,
|
|
(Ptr)&event,
|
|
sizeof(event),
|
|
&cb);
|
|
|
|
if(err != noErr){
|
|
ASSERT(0);
|
|
return err;
|
|
}
|
|
|
|
DoEvent(&event);
|
|
|
|
return noErr;
|
|
}
|
|
|
|
void
|
|
InitAppleEvents()
|
|
{
|
|
OSErr err;
|
|
|
|
err = AEInstallEventHandler(
|
|
'OLE2', 'EVNT', (EventHandlerProcPtr)RemoteLowLevelEvt, 0, false);
|
|
ASSERT(err == noErr);
|
|
}
|
|
|
|
|
|
void
|
|
Init()
|
|
{
|
|
short count;
|
|
Handle menuBar;
|
|
long total, contig;
|
|
EventRecord event;
|
|
|
|
g_fInBackground = false;
|
|
|
|
MoreMasters();
|
|
MaxApplZone();
|
|
|
|
InitGraf((Ptr)&qd.thePort);
|
|
InitFonts();
|
|
InitWindows();
|
|
InitMenus();
|
|
TEInit();
|
|
InitDialogs(nil);
|
|
InitCursor();
|
|
FlushEvents(everyEvent, 0);
|
|
InitCursor();
|
|
|
|
#if HC_MPW
|
|
UnloadSeg((ProcPtr)_DataInit);
|
|
#endif
|
|
|
|
// REVIEW: move this above load of Ole?
|
|
SysEnvirons(kSysEnvironsVersion, &g_sysenv);
|
|
if (g_sysenv.machineType < 0
|
|
|| g_sysenv.systemVersion < 0x0600
|
|
|| g_sysenv.hasColorQD == false
|
|
|| TrapExists(_WaitNextEvent) == false)
|
|
{
|
|
Fatal("System is too whimpy");
|
|
}
|
|
|
|
/* get MultiFinder started */
|
|
for(count = 1; count <= 3; count++)
|
|
EventAvail(everyEvent, &event);
|
|
|
|
/* make sure we have enough memory to run */
|
|
if((long)GetApplLimit() - (long)ApplicZone() < kMinHeap)
|
|
Fatal("Not enough memory to run");
|
|
PurgeSpace(&total, &contig);
|
|
if(total < kMinSpace)
|
|
Fatal("Not enough memory after purge");
|
|
|
|
menuBar = GetNewMBar(rMenuBar); /* read menus into menu bar */
|
|
if(menuBar == nil)
|
|
Fatal("Unable to load menu bar");
|
|
SetMenuBar(menuBar);
|
|
DisposHandle(menuBar);
|
|
AddResMenu(GetMHandle(mApple), 'DRVR'); /* add DA names to Apple menu */
|
|
DrawMenuBar();
|
|
|
|
DoNew();
|
|
|
|
#ifndef _PPCMAC
|
|
DbPrintf("InitLibraryManager\n");
|
|
if (InitOleManager(0) != NOERROR)
|
|
Fatal("Could not initialize LibraryManager");
|
|
g_fLibrariesLoaded = true;
|
|
#endif
|
|
|
|
DbPrintf("OleInitialize\n");
|
|
if(InitOle() != NOERROR)
|
|
Fatal("Unable to Initialize Ole");
|
|
g_fInitOle = true;
|
|
|
|
InitAppleEvents();
|
|
}
|
|
|
|
/* Calculate a sleep value for WaitNextEvent. This takes into
|
|
account the things that DoIdle does with idle time. */
|
|
unsigned long
|
|
GetSleep()
|
|
{
|
|
long sleep;
|
|
TEHandle te;
|
|
WindowPtr window;
|
|
|
|
sleep = MAXLONG; /* default value for sleep */
|
|
if(!g_fInBackground){
|
|
window = FrontWindow(); /* and the front window is ours... */
|
|
if(IsAppWindow(window)){
|
|
/* and the selection is an insertion point... */
|
|
te = ((Doc*)window)->docTE;
|
|
if((*te)->selStart == (*te)->selEnd){
|
|
/* blink time for the insertion point */
|
|
sleep = GetCaretTime();
|
|
}
|
|
}
|
|
}
|
|
return sleep;
|
|
}
|
|
|
|
/* Check the bits of a trap number to determine its type. If bit 11
|
|
is set, its a Toolbox trap, otherwise its an OS trap. */
|
|
TrapType
|
|
GetTrapType(short theTrap)
|
|
{
|
|
return ((theTrap & 0x0800) == 0) ? OSTrap : ToolTrap;
|
|
}
|
|
|
|
/* Find the size of the Toolbox trap table. This can be either 0x0200
|
|
or 0x0400 bytes, depending on which Macintosh we are running on. We
|
|
determine the size by taking advantage of an anomaly of the smaller
|
|
trap table: any entries that fall beyond the end of the table are
|
|
mirrored back down into the lower part. For example, on a large table,
|
|
trap numbers A86E and AA6E correspond to different routines. However,
|
|
on a small table, they correspond to the same routine. By checking
|
|
the address of these routines, we can determine the size of the
|
|
table. */
|
|
short
|
|
NumToolboxTraps()
|
|
{
|
|
return
|
|
(NGetTrapAddress((short)0xA86E, ToolTrap) ==
|
|
NGetTrapAddress((short)0xAA6E, ToolTrap)) ? 0x0200 : 0x0400;
|
|
}
|
|
|
|
/* Check to see if a given trap is implemented */
|
|
Boolean
|
|
TrapExists(short theTrap)
|
|
{
|
|
TrapType theTrapType;
|
|
|
|
theTrapType = GetTrapType(theTrap);
|
|
if((theTrapType == ToolTrap)
|
|
&& ((theTrap & 0x07FF) >= NumToolboxTraps()))
|
|
return false;
|
|
return (NGetTrapAddress((short)_Unimplemented, ToolTrap) !=
|
|
NGetTrapAddress(theTrap, theTrapType));
|
|
}
|
|
|
|
STDAPI_(void)
|
|
OutputDebugString(const char *sz)
|
|
{
|
|
long len;
|
|
TEHandle hTE;
|
|
WindowPtr window;
|
|
|
|
len = strlen(sz);
|
|
|
|
window = FrontWindow();
|
|
if(window == nil)
|
|
return;
|
|
|
|
hTE = ((Doc*)window)->docTE;
|
|
if(hTE == nil || *hTE == nil)
|
|
return;
|
|
|
|
// if this insertion will cause us to overflow the TextEdit
|
|
// buffer, then delete enough from the beginning of the buffer
|
|
// to make room
|
|
|
|
if(((long)(*hTE)->teLength + len) > 30000){
|
|
TESetSelect(0, 15000, hTE);
|
|
TEDelete(hTE);
|
|
TESetSelect(30000, 30000, hTE);
|
|
}
|
|
|
|
TEInsert(sz, len, hTE);
|
|
TESelView(hTE);
|
|
}
|
|
|
|
struct regentry{
|
|
char *szKey;
|
|
char *szValue;
|
|
} g_rgregentry[] = {
|
|
|
|
{ "CLSID\\{00020468-0000-0000-C000-000000000046}\\LocalServer", "SDSP" }
|
|
|
|
, { "CLSID\\{00020468-0000-0000-C000-000000000046}\\ProgID",
|
|
"sdisptst.application" }
|
|
|
|
, { "CLSID\\{00020468-0000-0000-C000-000000000046}\\InprocHandler",
|
|
"OLE2:Def$DefFSet" }
|
|
|
|
, { "SDSP", "{00020468-0000-0000-C000-000000000046}" }
|
|
|
|
, { "sdisptst.application\\CLSID",
|
|
"{00020468-0000-0000-C000-000000000046}" }
|
|
|
|
// -- CDisptst
|
|
|
|
, { "CLSID\\{00020460-0000-0000-C000-000000000046}\\LocalServer", "SDSP" }
|
|
|
|
, { "CLSID\\{00020460-0000-0000-C000-000000000046}\\ProgID",
|
|
"sdisptst.cdisptst" }
|
|
|
|
, { "CLSID\\{00020460-0000-0000-C000-000000000046}\\InprocHandler",
|
|
"OLE2:Def$DefFSet" }
|
|
|
|
, { "SDSP", "{00020460-0000-0000-C000-000000000046}" }
|
|
|
|
, { "sdisptst.cdisptst\\CLSID",
|
|
"{00020460-0000-0000-C000-000000000046}" }
|
|
|
|
// -- CSarray
|
|
|
|
, { "CLSID\\{00020461-0000-0000-C000-000000000046}\\LocalServer", "SDSP" }
|
|
|
|
, { "CLSID\\{00020461-0000-0000-C000-000000000046}\\ProgID",
|
|
"sdisptst.csarray" }
|
|
|
|
, { "CLSID\\{00020461-0000-0000-C000-000000000046}\\InprocHandler",
|
|
"OLE2:Def$DefFSet" }
|
|
|
|
, { "SDSP", "{00020461-0000-0000-C000-000000000046}" }
|
|
|
|
, { "sdisptst.csarray\\CLSID",
|
|
"{00020461-0000-0000-C000-000000000046}" }
|
|
|
|
// -- CExcepinfo
|
|
|
|
, { "CLSID\\{00020466-0000-0000-C000-000000000046}\\LocalServer", "SDSP" }
|
|
|
|
, { "CLSID\\{00020466-0000-0000-C000-000000000046}\\ProgID",
|
|
"sdisptst.cexcepinfo" }
|
|
|
|
, { "CLSID\\{00020466-0000-0000-C000-000000000046}\\InprocHandler",
|
|
"OLE2:Def$DefFSet" }
|
|
|
|
, { "SDSP", "{00020466-0000-0000-C000-000000000046}" }
|
|
|
|
, { "sdisptst.cexcepinfo\\CLSID",
|
|
"{00020466-0000-0000-C000-000000000046}" }
|
|
|
|
// -- CProp
|
|
|
|
, { "CLSID\\{00020471-0000-0000-C000-000000000046}\\LocalServer", "SDSP" }
|
|
|
|
, { "CLSID\\{00020471-0000-0000-C000-000000000046}\\ProgID",
|
|
"sdisptst.cprop" }
|
|
|
|
, { "CLSID\\{00020471-0000-0000-C000-000000000046}\\InprocHandler",
|
|
"OLE2:Def$DefFSet" }
|
|
|
|
, { "SDSP", "{00020471-0000-0000-C000-000000000046}" }
|
|
|
|
, { "sdisptst.cprop\\CLSID",
|
|
"{00020471-0000-0000-C000-000000000046}" }
|
|
|
|
/*
|
|
* NOTE: The following is temporary for MacOle Beta 1
|
|
*
|
|
*/
|
|
|
|
, { "Interface\\{00020400-0000-0000-C000-000000000046}",
|
|
"IDispatch" }
|
|
|
|
, { "Interface\\{00020400-0000-0000-C000-000000000046}\\ProxyStubClsid",
|
|
"{00020420-0000-0000-C000-000000000046}" }
|
|
|
|
, { "Interface\\{00020404-0000-0000-C000-000000000046}",
|
|
"IEnumVARIANT" }
|
|
|
|
, { "Interface\\{00020404-0000-0000-C000-000000000046}\\ProxyStubClsid",
|
|
"{00020421-0000-0000-C000-000000000046}" }
|
|
|
|
, { "Interface\\{00020401-0000-0000-C000-000000000046}",
|
|
"ITypeInfo" }
|
|
|
|
, { "Interface\\{00020401-0000-0000-C000-000000000046}\\ProxyStubClsid",
|
|
"{00020422-0000-0000-C000-000000000046}" }
|
|
|
|
, { "Interface\\{00020402-0000-0000-C000-000000000046}",
|
|
"ITypeLib" }
|
|
|
|
, { "Interface\\{00020403-0000-0000-C000-000000000046}",
|
|
"ITypeComp" }
|
|
|
|
, { "Interface\\{00020405-0000-0000-C000-000000000046}",
|
|
"ICreateTypeInfo" }
|
|
|
|
, { "Interface\\{00020406-0000-0000-C000-000000000046}",
|
|
"ICreateTypeLib" }
|
|
|
|
, { "CLSID\\{00020420-0000-0000-C000-000000000046}",
|
|
"PSDispatch" }
|
|
|
|
#ifdef _PPCMAC
|
|
#define szAutomationDll "MicrosoftOLE2AutomationLib"
|
|
#else //_PPCMAC
|
|
#define szAutomationDll "OLE2:DISP$DispFSet"
|
|
#endif //_PPCMAC
|
|
|
|
, { "CLSID\\{00020420-0000-0000-C000-000000000046}\\InprocServer",
|
|
szAutomationDll }
|
|
|
|
, { "CLSID\\{00020422-0000-0000-C000-000000000046}",
|
|
"PSTypeInfo" }
|
|
|
|
, { "CLSID\\{00020422-0000-0000-C000-000000000046}\\InprocServer",
|
|
szAutomationDll }
|
|
|
|
, { "CLSID\\{00020421-0000-0000-C000-000000000046}",
|
|
"PSEnumVARIANT" }
|
|
|
|
, { "CLSID\\{00020421-0000-0000-C000-000000000046}\\InprocServer",
|
|
szAutomationDll }
|
|
|
|
};
|
|
|
|
HRESULT
|
|
EnsureRegistration()
|
|
{
|
|
HKEY hkey;
|
|
|
|
if(RegOpenKey(HKEY_CLASSES_ROOT, "SDSP", &hkey) == NOERROR){
|
|
RegCloseKey(hkey);
|
|
return NOERROR;
|
|
}
|
|
|
|
for(int i = 0; i < DIM(g_rgregentry); ++i){
|
|
if(RegSetValue(HKEY_CLASSES_ROOT, g_rgregentry[i].szKey, REG_SZ, g_rgregentry[i].szValue, 0) != ERROR_SUCCESS)
|
|
return ResultFromScode(E_FAIL);
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|