eudora-mac/main.c

1 line
77 KiB
C
Executable File
Raw Permalink Blame History

/* Copyright (c) 2017, Computer History Museum
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted (subject to
the limitations in the disclaimer below) provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Computer History Museum nor the names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE
COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE. */
#include "main.h"
#define FILE_NUM 22
/* Copyright (c) 1990-1992 by the University of Illinois Board of Trustees */
#pragma segment Main
#define TICKS2MINS 3600
void HouseKeeping(long activeTicks);
void DoKeyDown(WindowPtr topWinWP,EventRecord *event);
void DoMouseDown(WindowPtr topWinWP,EventRecord *event);
Boolean DoUpdate(WindowPtr topWin,EventRecord *event);
Boolean DoActivate(WindowPtr topWin,EventRecord *event);
Boolean DoApp1(WindowPtr topWinWP,EventRecord *event);
void DoContentClick(WindowPtr topWinWP,WindowPtr winWP,EventRecord *event);
Boolean DoDisk(long message);
long CloseUnused(void);
void SetYesterday(void);
long NickDrain(void);
#ifdef DRAG_GETOSEVT
void UpdateAWindow(void);
#endif
#if defined(EXPIRE) || defined(DEMO)
void ExpireWarning(void);
#endif
void AutoSave(void);
void ConfigureIfNeeded(void);
void UnloadSegments(void);
Boolean MyIsShowContextualMenuClick(EventRecord *event);
void ActiveUserIdleTasks(void);
static void SetupEventHandlers(void);
static pascal OSStatus WheelHandlerProc (EventHandlerCallRef nextHandler,EventRef event,void *data);
static pascal OSStatus ServicesHandlerProc (EventHandlerCallRef nextHandler,EventRef event,void *data);
static void AppendOSTypeToCFArray(CFMutableArrayRef arrayRef,OSType type);
pascal void __start(void);
pascal void SimpleStart(void);
pascal void SimpleStart(void)
{
#ifdef DEBUG
SLInit();
#endif
__start();
}
void main()
{
EventRecord theEvent;
Boolean active=True;
long houseTicks=0;
Boolean lock = False;
long activeTicks;
Boolean keyHit;
//uLong startTicks = 0;
ActiveTicks = activeTicks = TickCount();
SyncRW = True; // protect from RAM Doubler
/*
* perform set-up, including initializing mac managers
*/
#if __profile__
ProfilerInit(collectDetailed,bestTimeBase,20000,2000);
ProfilerSetStatus(True);
#endif
Initialize();
SetYesterday();
SeeIfWeShouldPreloadNav ();
CHECK_EXPIRE;
CHECK_DEMO;
#if defined(EXPIRE) || defined(DEMO)
ExpireWarning();
#endif
SetCursorByLocation();
ConfigureIfNeeded();
CheckForDefaultMailClient ();
SetupEventHandlers();
/*
* run the event loop
*/
#if __profile__
//ProfilerSetStatus(True);
#endif
while (!EjectBuckaroo && !Done)
{
//if (!startTicks) startTicks = TickCount();
//if (TickCount()-startTicks > 3600) break;
//ProfilerSetStatus(ActiveSearchCount > 0);
#ifdef DEBUG
if (BUG3 && !FrontWindow_())
{
Str63 s;
long grow, newFree;
static long oldFree=1L<<30;
(void) MaxMem(&grow);
DisposeHandle(NewHandle(400 K));
newFree = FreeMem();
if (oldFree>newFree)
{
DebugStr(ComposeString(s,"\p#%d;ht;g",oldFree-newFree));
AlertStr(OK_ALRT,Stop,ComposeString(s,
"\pLeak? was %d, now %d (%d)",oldFree,newFree,oldFree-newFree));
}
oldFree = newFree;
}
#endif
CommandPeriod = NoInitialCheck = False;
/*
* handle any events we might come across
*/
if (!Typing) PurgeSpace(&LastTotalSpace,&LastContigSpace);
//ProfilerSetStatus(False);
active = GrabEvent(&theEvent) ? HandleEvent(&theEvent) : False;
CurPers = PersList; // make darn sure.
// Did the user tell us to quit?
if (PleaseQuit)
{
PleaseQuit = False;
DoQuit(false);
}
if (Done) break;
keyHit = (theEvent.what==autoKey || theEvent.what==keyDown) && !(theEvent.modifiers&cmdKey);
if (DragTOCFrom) FinishBoxDrag();
Dragging = 0;
DragSequence++;
#if __profile__
//ProfilerSetStatus(Typing);
#endif
if (ProgressIsOpen()) CloseProgress();
if (keyHit || theEvent.what==mouseDown || theEvent.what==keyDown || theEvent.what==app1Evt) ActiveTicks = TickCount();
if (Typing) active = True;
if (active) activeTicks = TickCount();
if (!Typing && IsMyWindow(FrontWindow_()) && GetWindowKind(FrontWindow_())==TASKS_WIN)
ActiveTicks = activeTicks = 0; // if progress window up, user is idle
TendNotificationManager(active);
Typing = Typing || !HaveTheDiseaseCalledOSX() && OSEventAvail(keyDownMask,&theEvent) && !(theEvent.modifiers&cmdKey);
if (!Typing)
{
WindowPtr winWP = FrontWindow_();
if (IsMyWindow(winWP) && !InBG)
{
if (GetWindowKind(winWP)==CBOX_WIN || GetWindowKind(winWP)==MBOX_WIN)
RedoTOC((TOCHandle)GetWindowPrivateData(winWP));
else
{
MyWindowPtr win = GetWindowMyWindowPtr (winWP);
if (!win || (win && !win->isActive)) ActivateMyWindow(winWP,true);
// UpdateMyWindow(winWP);
}
}
if (SFWTC) SetCursorByLocation();
// See if any plug-ins need some idle time
ETLIdle(
((TickCount()-ActiveTicks<120)||(ModalWindow && !AreAllModalsPlugwindows()) ? EMSFIDLE_QUICK : (InBG ? 0:EMSFIDLE_UI_ALLOWED)) |
(Offline ? EMSFIDLE_OFFLINE : 0) |
(GetNumBackgroundThreads() ? EMSFIDLE_TRANSFERRING : 0));
if (!active && !TypingRecently)
{
URLScan();
QuoteScan();
#ifdef WINTERTREE
if (HasFeature (featureSpellChecking) && !PrefIsSet(PREF_NO_WINTERTREE)) SpellScan();
#endif
if (ActiveSearchCount) SearchAllIdle();
}
if (TickCount()-houseTicks > 30)
{
HouseKeeping(TickCount()-activeTicks);
houseTicks = TickCount();
}
// if (QTMoviesInited)
// This can cause movies to draw in the wrong place so don't use it
// MoviesTask(nil,50);
GraphicDownloadIdle(); // See if any graphic downloads need any processing
PlaySoundIdle(); // Give time to any sounds that might be playing
#ifdef TWO
/*
* tickle Frontier
*/
if (active) CheckSharedMenus(HIER_MENU_LIMIT);
#endif
#ifndef SLOW_CLOSE
/*
* destroy defunct streams
*/
TcpFastFlush(False);
#endif
/*
* write dirty toc's
*/
if (!active) RedoTOCs();
if (!active && !PrefIsSet(PREF_CORVAIR)) FlushTOCs(False,True);
/*
* cursor & help
*/
if (SFWTC) SetCursorByLocation();
if (theEvent.what==nullEvent && HasHelp && !InBG && HMGetBalloons())
DoHelp(FrontWindow_());
ASSERT(CurResFile()==SettingsRefN);
UseResFile(SettingsRefN);
ASSERT(Count1Resources(TOC_TYPE)==0);
#ifdef TWO
/*
* toolbar
*/
ToolbarBack();
#endif
/*
* all windows are fair game
*/
NotUsingAllWindows();
/*
* menu bar
*/
if (active) EnableMenus(MyFrontWindow(),False);
NoMenus = false;
/*
* check?
*/
if (!active && CheckNow)
{
if (AutoCheckOKWithDBRead(false)) // make sure we're really allowed to do an automatic check
XferMail(True,PrefIsSet(PREF_SEND_CHECK),False,False,True,0);
CheckNow = False;
}
}
/*
* clear gworld, personality stack
*/
ASSERT(StackPop(nil,GWStack)==fnfErr);
while (!StackPop(nil,GWStack));
ASSERT(!PersStack || StackPop(nil,PersStack)==fnfErr);
while (PersStack && !StackPop(nil,PersStack));
CurPers = PersList;
ASSERT(CurThreadGlobals==&ThreadGlobals);
if (EjectBuckaroo) DoQuit(false);
}
#ifdef IMAP
ZapAllIMAPConnections(true); // abort all IMAP connections
#endif
TcpFastFlush(True); //abort open streams
CheckSLIP(); //kill macslip
#ifdef USE_NETWORK_SETUP
CloseNetworkSetup();
#endif
// archive the junk mailbox
if (JunkPrefBoxArchive() && JunkTrimOK()) ArchiveJunk(GetJunkTOC());
#ifdef IMAP
// empty only the local trash. The IMAP trash was taken care of before network was closed down.
if (PrefIsSet(PREF_AUTO_EMPTY)) EmptyTrash(true,false,false);
#else
if (PrefIsSet(PREF_AUTO_EMPTY)) EmptyTrash();
#endif
FlushTOCs(True,False);
Cleanup();
#if __profile__
ProfilerSetStatus(False);
ProfilerDump("\peudora-profile");
ProfilerTerm();
#endif
}
void ConfigureIfNeeded(void)
{
Str255 pop;
if (!*GetPOPPref(pop) && PrefIsSet(PREF_ACAP)) ACAPLoad(True);
if (!*GetPOPPref(pop) || pop[1]=='@') // ACAP helped?
{
// ask the user if they'd like to import mail from another account ...
if (gImportersAvailable && ComposeStdAlert(Note,IMPORT_ON_STARTUP)==1)
{
DoMailImport();
}
else
{
DoSettings(0);
}
}
}
#if defined(EXPIRE) || defined(DEMO)
/************************************************************************
* ExpireWarning - warn the user that Eudora will expire in the next 7 days
* This routine works with an EXPIRE version AND a DEMO version.
************************************************************************/
void ExpireWarning(void)
{
Str255 date;
DateTimeRec dtr;
uLong expireSecs;
#ifdef EXPIRE
Zero(dtr);
dtr.year = EXP_YEAR;
dtr.month = EXP_MONTH+1;
dtr.day = 1;
Date2Secs(&dtr,&expireSecs);
if (expireSecs - LocalDateTime() < 3600L*24*7)
{
DateString(expireSecs,longDate,date,nil);
if (ComposeStdAlert(Caution,WILL_EXPIRE,date)==kAlertStdAlertOKButton)
OpenAdwareURL(GetNagState(), UPDATE_SITE, actionUpdate, updateQuery, nil);
}
#endif
#ifdef DEMO
if (gTimeBombData.days != TB_DISARMED) //only warn if the timebomb is not disarmed,
{
long expiresOn = gTimeBombData.date + (gTimeBombData.days * NUMBER_OF_SECS_DAY);
Secs2Date(expiresOn,&dtr);
Date2Secs(&dtr,&expireSecs);
if (expireSecs - LocalDateTime() < 3600L*24*7)
{
SetMyCursor(arrowCursor);
DateString(expireSecs,longDate,date,nil);
MyParamText(date,0,0,0);
if (Alert(WILL_EXPIRE_ALRT,nil) == BUY_NOW_BUTTON_WILL_EXPIRE)
PurchaseEudora();
}
}
#endif
}
#endif
/************************************************************************
* HouseKeeping - periodic cleanup functions
************************************************************************/
void HouseKeeping(long activeTicks)
{
static long flushTicks=0;
uLong checkTicks;
static long AutoSaveTicks;
long autoSecs;
static long spoolCleaned;
if (activeTicks>10)
{
long ticks;
WindowPtr winWP;
MyWindowPtr win;
static long lastBadgeTOCDirty = -1;
CurPers = PersList; // make darn sure
EnableMenus(MyFrontWindow(),False);
/*
* warn the user if we're growing low (get it) on memory
*/
MonitorGrow(True);
if (!InBG && TickCount()%20==0) FloatingWinIdle();
if (FixServers)
{
RedoTOCs();
FixMessServerAreas();
FixServers = False;
}
/*
* When was yesterday?
*/
SetYesterday();
if (PrefBadgeDo() && lastBadgeTOCDirty != AnyTOCDirty)
{
lastBadgeTOCDirty = AnyTOCDirty;
BadgeTheSupidDock(GlobalUnreadCount(),nil,AttentionNeeded || MyNMRec);
}
/*
* Do we need to switch modes?
*/
if (NewClientModePlusOne) AutoSwitchClientMode();
//
// Update the emo turd cache
EmoTurdCache = EmoLitterInternetWithTurds();
/*
* Do we need to nag the user?
*/
if (PlaylistNagCount)
{
short i;
Handle res;
for (i=1;res=GetIndResource(NAG_REQUEST_TYPE,i);i++)
{
short id;
OSType tipe;
GetResInfo(res,&id,&tipe,GlobalTemp);
DoPlaylistNag(id);
}
PlaylistNagCount = 0;
}
/*
* Register?
*/
#ifndef NAG
if (!ModalWindow) AutoRegister();
#endif
//if ((win=FrontWindow_()) && IsMyWindow(win) && win->qWindow.windowKind==MESS_WIN)
//GenerateReceipt(Win2MessH(win),MDN_DISPLAYED,True);
#ifdef THREADING_ON
/*
* report fatal thread errors
*/
if (CheckThreadError)
{
WarnUser(THREAD_CANT_CHECK,CheckThreadError);
CheckThreadError = noErr;
}
if (SendThreadError)
{
WarnUser(THREAD_CANT_SEND,SendThreadError);
SendThreadError = noErr;
}
#endif
if ((autoSecs = GetRLong(AUTOSAVE_INTERVAL)) && TickCount()-AutoSaveTicks>autoSecs*60)
{
AutoSaveTicks = TickCount();
AutoSave();
}
if (NewError && !GetNumBackgroundThreads())
{
WindowPtr mywin;
if (!IsTPIdleControlVisible() || PrefIsSet(PREF_TASK_PROGRESS_AUTO))
OpenTasksWinErrors();
else
if ((mywin=FrontWindow_()) && GetWindowKind(mywin)==TASKS_WIN)
{
if (!InBG)
SysBeep(1);
NewError = false;
}
}
/*
* save window state if need be
*/
if (WashMe && DiskSpunUp()) RememberOpenWindows();
/*
* save the mid list
*/
OutgoingMIDListSave();
/*
* check mail?
*/
#ifdef THREADING_ON
// for now, don't start thread if modal window up. this may change...
if (((!PrefIsSet(PREF_THREADING_OFF) && ThreadsAvailable() && activeTicks>120) || (activeTicks > GetRLong(IDLE_SECS)*60)) && (!ModalWindow || AreAllModalsPlugwindows()) && !CheckThreadRunning && !(PrefIsSet(PREF_POP_SEND) && SendThreadRunning))
#else
if (activeTicks > GetRLong(IDLE_SECS)*60 && (!ModalWindow || AreAllModalsPlugwindows()))
#endif
{
if (CheckOnIdle)
{
XferMail((CheckOnIdle&kCheck)!=0,(CheckOnIdle&kSend)!=0,False,True,True,0);
CheckOnIdle = 0;
return;
}
if (checkTicks = PersCheckTicks())
{
if (TickCount() > checkTicks)
{
if (!Offline && !(CurrentModifiers()&shiftKey))
{
// skip this check if we're not online. Be anal and slow about checking the connection.
if (AutoCheckOKWithDBRead(true))
{
XferMail(True,PrefIsSet(PREF_SEND_CHECK),False,False,True,0);
return;
}
}
}
}
if (ForceSend && ForceSend <= GMTDateTime() && AutoCheckOK()) {XferMail(False,True,False,False,True,0);return;}
}
#ifdef THREADING_ON
/* if a send thread couldn't be spawned, try it now */
if (SendImmediately && !SendThreadRunning)
{
XferMail(False,True,False,False,True,0);
return;
}
#endif
if (OpenAddrErrs && !AmQuitting && !ModalWindow && activeTicks > GetRLong(SHORT_MODAL_IDLE_SECS)*60)
{
// Recently sent one or more messages with addressing errors. Open 'em.
TOCHandle outTocH;
short sumNum;
if (outTocH = GetOutTOC())
for (sumNum=(*outTocH)->count-1; sumNum>=0; sumNum--)
if ((*outTocH)->sums[sumNum].flags&FLAG_ADDRERR)
{
(*outTocH)->sums[sumNum].flags &= ~FLAG_ADDRERR;
if (!GetAMessage(outTocH,sumNum,nil,nil,True)) break;
}
OpenAddrErrs = false;
}
/*
* close unneeded TOC's
*/
if (activeTicks > GetRLong(TOC_SMALLDIRTY))
{
TOCHandle tocH;
for (tocH=TOCList;tocH;tocH=(*tocH)->next)
(*tocH)->reallyDirty = TOCIsDirty(tocH) || (*tocH)->reallyDirty;
}
FlushTOCs(True,True);
/*
* just for good measure
*/
if (TickCount()-flushTicks > 60*GetRLong(FLUSH_SECS) && DiskSpunUp())
{
FlushVol(nil,MailRoot.vRef);
flushTicks = TickCount();
}
/*
* close speller, if idle for a while
*/
#ifdef WINTERTREE
if (HasFeature (featureSpellChecking))
SpellClose(false);
#endif //WINTERTREE
/*
* Wander over to the speaker and make sure he or she is happy
*/
#ifdef SPEECH_ENABLED
(void) SpeechIdle ();
#endif
/*
* Save the personalities
*/
if (HasFeature (featureMultiplePersonalities))
PersSaveAll();
/*
* The resolver may have left us little poodle bombs...
*/
FlushHIQ();
/*
* and logging...
*/
#ifdef THREADING_ON
if (!GetNumBackgroundThreads ())
#endif
if (!(LogLevel&LOG_EVENT)) CloseLog();
/*
* and that pesky settings file
*/
MyUpdateResFile(SettingsRefN);
#ifdef TWO
/*
* stop MacSLIP?
*/
CheckSLIP();
#endif
/*
* close unused IMAP connections
*/
CheckIMAPConnections();
/*
* display any pending IMAP warnings
*/
IMAPWarnings();
/*
* Remind the user about marked links, if we're online.
*/
if (activeTicks > GetRLong(OFFLINE_LINK_NAG_TIME)) RemindNag();
#ifdef NEVER
if (RunType!=Production)
{
Str255 item,item2;
short i;
MenuHandle mh;
*item2 = 0;
for (i=NEW_TO_HIER_MENU;i<=INSERT_TO_HIER_MENU;i++)
{
if (mh=GetMHandle(i))
{
GetItem(mh,1,item);
if (*item2 && !StringSame(item,item2))
{
PSCat(item,"\p<->");
PSCat(item,item2);
DebugStr(item);
break;
}
PCopy(item2,item);
}
}
}
#endif
/*
* fcc?
*/
//Folder Carbon Copy - light does not support the FCC feature
if (HasFeature (featureFcc))
FccFlop(GetWindowMyWindowPtr(FrontWindow_()));
/*
* Link History Aging
*/
if (HasFeature(featureLink)) AgeLinks();
/*
* idle routines
*/
ticks = TickCount();
for (winWP = GetWindowList(); winWP && TickCount() - ticks < 10; winWP = GetNextWindow (winWP)) {
win = GetWindowMyWindowPtr (winWP);
if (IsKnownWindowMyWindow(winWP) && win && win->idle && ticks-win->lastIdle>win->idleInterval)
{
SetPort_(GetWindowPort (winWP));
win->idle(win);
// (jp) Handle idle processing for intelligent nick fields
if (win->pte && HasNickScanCapability (win->pte))
NicknameWatcherIdle (win->pte);
win->lastIdle = TickCount();
}
}
#ifdef THREADING_ON
#ifndef BATCH_DELIVERY_ON
if (!ModalWindow || AreAllModalsPlugwindows()) // no modal window uppermost
if ((NeedToFilterIn && !CheckThreadRunning) || (NeedToFilterOut && !SendThreadRunning)) // we might plausibly have some messages
if (InBG || ((TickCount()-ActiveTicks) > GetRLong(MODAL_IDLE_SECS)*60)) // the user is not busy in Eudora
FilterXferMessages ();
#else
if (NeedToFilterIn||NeedToFilterOut||NeedToNotify||NeedToFilterIMAP) // there might be something there
if (!ModalWindow || AreAllModalsPlugwindows()) // no modal window uppermost
if (TickCount()-ActiveTicks > GetRLong(SHORT_MODAL_IDLE_SECS)*60) // user is not busy in Eudora
FilterXferMessages();
#endif
#endif
if ((!ModalWindow || AreAllModalsPlugwindows()) && TickCount()-ActiveTicks > GetRLong(SHORT_MODAL_IDLE_SECS)*60 && NoNewMailMe)
{
NoNewMailMe = false;
NotifyNewMail(0,false,nil,nil);
}
#ifdef IMAP
// update any IMAP message windows that need it
UpdateIMAPWindows();
// do New Mail alert if an IMAP check recently completed
if ((!ModalWindow || AreAllModalsPlugwindows()) && TickCount()-ActiveTicks > GetRLong(SHORT_MODAL_IDLE_SECS)*60 && !CheckThreadRunning && !IMAPCheckThreadRunning && gNewMessages)
{
NotifyNewMail(0,false,nil,nil);
gNewMessages = 0;
}
#endif
}
/*
* toolbar?
*/
if (TBarHasChanged)
{
TBarHasChanged = False;
if (PrefIsSet(PREF_TOOLBAR) != ToolbarShowing()) OpenToolbar();
else if (ToolbarShowing()) {OpenToolbar();OpenToolbar();}
}
if (!InBG) ShowToolbar();
/*
* run the text analyzer
*/
if (!TypingRecently && BeingAnal()) AnalScan();
// and the emoticon scanner
if (!TypingRecently && HasFeature(featureEmo) && EmoDo()) EmoScan();
/*
* do idle tasks that matter only for active users
*/
ActiveUserIdleTasks();
AdWinIdle();
StatsIdle();
if (gScreenChange && !InBG) // change in screen size (resolution)
{
gScreenChange = false;
ScreenChange();
}
/*
* Really obno stuff
*/
if (InBG || activeTicks > GetRLong(LONGTERM_IDLE)*60)
{
// perform any scheduled AddressBook Sync
OSXAddressBookScheduledSync();
/*
* clean up the spool folder
*/
if (GetPrefLong(PREF_SPOOL_DESTROY) && GMTDateTime()-spoolCleaned > 4*3600)
if (!CleanSpoolFolder(GetPrefLong(PREF_SPOOL_DESTROY))) spoolCleaned = GMTDateTime();
// perform IMAP auto expunge.
IMAPAutoExpunge();
// any mailboxes need compaction?
if (!GetNumBackgroundThreads()) // don't compact if threads running; might lead to conflicts
{
FSSpec spec;
if (!StackPop(&spec,CompactStack))
{
CompactMailbox(&spec,false);
if (GetHandleSize(CompactStack)/(*CompactStack)->elSize - (*CompactStack)->elCount > 20)
StackCompact(CompactStack);
return;
}
}
}
}
/************************************************************************
* ActiveUserIdleTasks - do idle tasks we do if the user is active
************************************************************************/
void ActiveUserIdleTasks(void)
{
static uLong stampTicks;
static uLong netTicks;
// if the user has been idle for a minute or more, stop doing these things
if (!UserIdle(ALMOST(TICKS2MINS)))
{
/*
* Check on our Network Connection every minute or so
*/
if (TickCount() - netTicks > TICKS2MINS)
{
// update the cached network status
TCPWillDial(true);
netTicks = TickCount();
}
/*
* Timestamp and flush the audit log once every two minutes
*/
if (!stampTicks) stampTicks=TickCount();
else if (FMBMain && (TickCount()-stampTicks > 2 * TICKS2MINS))
{
long faceTime, rearTime, connectTime, totalTime;
FaceMeasureReport(FMBMain,&faceTime, &rearTime, &connectTime, &totalTime);
AuditTimestamp(faceTime, rearTime, connectTime, totalTime);
stampTicks = TickCount();
}
}
}
/************************************************************************
* AutoSave - save open windows
************************************************************************/
void AutoSave(void)
{
WindowPtr winWP;
MyWindowPtr win;
Boolean saveMe;
for (winWP = FrontWindow_(); winWP; winWP = GetNextWindow (winWP)) {
win = GetWindowMyWindowPtr (winWP);
if (IsKnownWindowMyWindow(winWP) && win && IsDirtyWindow(win))
{
saveMe = false;
switch(GetWindowKind (winWP))
{
case ALIAS_WIN:
case TEXT_WIN:
case COMP_WIN:
case FILT_WIN:
saveMe = true;
break;
case MESS_WIN:
saveMe = MessOptIsSet(Win2MessH(win),OPT_WRITE);
break;
}
if (saveMe) DoMenu2(winWP,FILE_MENU,FILE_SAVE_ITEM,0);
}
}
}
/**********************************************************************
* CheckSLIP - check SLIP and PPP, hangup if need be
**********************************************************************/
void CheckSLIP(void)
{
if (gActiveConnections==0 && !gConnecting && !gStayConnected && !AdWinNeedsNetwork())
{
if (gUseOT)
{
extern MyOTPPPInfoStruct MyOTPPPInfo;
if (gHasOTPPP && !pendingCloses && MyOTPPPInfo.weConnectedPPP)
OTPPPDisconnect(false, true);
}
}
}
/**********************************************************************
* FccFlop - change the transfer menu for Fcc
**********************************************************************/
void FccFlop(MyWindowPtr win)
{
WindowPtr winWP = GetMyWindowWindowPtr (win);
Str255 s;
MenuHandle mh;
static short curName=0;
short shdName;
PETEHandle pte;
//Folder Carbon Copy - Light does not support the FCC feature
if (!HasFeature (featureFcc))
return;
if (win &&
IsWindowVisible(winWP) &&
GetWindowKind(winWP)==COMP_WIN &&
SumOf(Win2MessH(win))->state!=SENT &&
(pte = (*Win2MessH(win))->bodyPTE) &&
BCC_HEAD==CompHeadCurrent(pte))
{
shdName = FCC_NAME;
UseFeature (featureFcc);
}
else
shdName = TRANSFER_MNAME;
if (shdName!=curName && (mh = GetMHandle(TRANSFER_MENU)))
{
MySetMenuTitle(mh,GetRString(s,shdName));
DrawMenuBar();
curName = shdName;
TransferMenuHelp(shdName==FCC_NAME ? FCC_HMNU:TFER_HMNU);
}
}
/************************************************************************
* TransferMenuHelp - copy the correct hmnu into our settings file
************************************************************************/
void TransferMenuHelp(short id)
{
Handle h;
Zap1Resource('hmnu',TRANSFER_MENU);
ResourceCpy(SettingsRefN,HelpResFile,'hmnu',id);
{
if (h=Get1Resource('hmnu',id))
{
HNoPurge(h);
SetResInfo(h,TRANSFER_MENU,"");
}
}
}
/**********************************************************************
* SetYesterday - set our idea of when today begins
**********************************************************************/
void SetYesterday(void)
{
DateTimeRec dtr;
static long ticks;
static long lastYesterday;
if (TickCount()-ticks>TICKS2MINS || !ticks)
{
long secs = LocalDateTime();
ticks = TickCount();
#ifdef DEMO
today = secs;
#endif
SecondsToDate(secs,&dtr);
dtr.hour = dtr.minute = dtr.second = 0;
DateToSeconds(&dtr,&secs);
if (secs!=lastYesterday)
{
lastYesterday = secs;
RedoAllTOCs();
}
Yesterday = LocalDateTime()-secs;
}
}
/**********************************************************************
* HandleEvent - handle an event
**********************************************************************/
Boolean HandleEvent(EventRecord *event)
{
WindowPtr topWinWP = MyFrontWindow(); /* in case we need to know */
Boolean active=False;
MainEvent = *event; /* copy it into an accessible place */
#ifdef GX_PRINTING
if (!isGXDialog && MyIsDialogEvent(event))
#else //GX_PRINTING
if (MyIsDialogEvent(event))
#endif //GX_PRINTING
{
DialogPtr dlgPtr = GetDialogFromWindow(Event2Window(event));
if (!dlgPtr)
dlgPtr=GetDialogFromWindow(topWinWP);
if (IsMyWindow(GetDialogWindow(dlgPtr)))
DoModelessEvent(dlgPtr,event);
SetPort(InsurancePort);
return(True);
}
if (topWinWP)
{
SetPort_(GetWindowPort(topWinWP));
UsingWindow(topWinWP);
}
else
SetPort_(InsurancePort);
#ifdef USECMM
//check for contextual menu event
if( gHasCMM && MyIsShowContextualMenuClick( event ) )
{
HandleContextualMenuClick( topWinWP, event );
return(active);
}
#endif
/*
* slog through all the events...
*/
switch (event->what)
{
case keyDown:
case autoKey:
#ifdef FLOAT_WIN
if (keyFocusedFloater) topWinWP = GetMyWindowWindowPtr(keyFocusedFloater); //FLOAT_WIN
#endif //FLOAT_WIN
/*if (HasHelp && HMIsBalloon()) HMRemoveBalloon();*/
UsingWindow(topWinWP);
DoKeyDown(topWinWP,event);
active = True;
break;
case mouseUp:
case mouseDown:
/*if (HasHelp && HMIsBalloon()) HMRemoveBalloon();*/
DoMouseDown(topWinWP,event);
active = True;
break;
case updateEvt:
UsingWindow(topWinWP);
DoUpdate(topWinWP,event);
break;
case activateEvt:
if (!InBG) DoActivate(topWinWP,event);
break;
case app4Evt:
active = DoApp4(topWinWP,event);
break;
case app1Evt:
UsingWindow(topWinWP);
active = DoApp1(topWinWP,event);
break;
case kHighLevelEvent:
(void) AEProcessAppleEvent(event);
break;
}
SetPort(InsurancePort);
if (!ForceSend) SetSendQueue(); /* a message from beyond */
return(active);
}
/************************************************************************
* MyIsShowContextualMenuClick - is this a context menu event?
************************************************************************/
Boolean MyIsShowContextualMenuClick(EventRecord *event)
{
uLong opts = GetPrefLong(PREF_DRAG_OPTIONS);
if ((!(opts&2) || !(event->modifiers&controlKey)) && IsShowContextualMenuClick(event)) return(true);
return(false);
}
/**********************************************************************
* DoApp4 - handle an app4 event; suspend/resume/mouse
**********************************************************************/
Boolean DoApp4(WindowPtr topWinWP,EventRecord *event)
{
WindowPtr winWP;
MyWindowPtr topWin;
if (((event->message>>24)&0xff) == 0xfa)
{
SFWTC = True;
}
else
{
ClickType = Single; // no longer double-clicking if suspend/resume
if (((event->message)>>24)&1 == 1)
{
InBG = (event->message&1)==0;
if (!InBG)
SFWTC = True;
topWinWP = FrontWindow_();
#ifdef CTB
if (CnH) CMResume(CnH,!InBG);
#endif
InBG = (event->message&1)==0;
if (InBG)
{
MyHMHideTag();
HiliteMenu(0);
}
else
{
#ifdef REFRESH_LABELS_MENU
RefreshLabelsMenu();
#endif // REFRESH_LABELS_MENU
#ifdef GX_PRINTING
if (gGXIsPresent) UpdateGXPageSetup();
#endif //GX_PRINTING
}
topWin = GetWindowMyWindowPtr (topWinWP);
if (topWinWP && IsMyWindow(topWinWP) && InBG==topWin->isActive)
ActivateMyWindow(topWinWP,!InBG);
// Show/hide floating/docked windows
for (winWP = GetWindowList(); winWP; winWP = GetNextWindow (winWP))
if (IsFloating(winWP))
{
topWin = GetWindowMyWindowPtr (winWP);
if (InBG) StashStructure(topWin);
ShowHide(winWP,!InBG);
if (!InBG) StashStructure(topWin);
}
if (!InBG)
{
EventRecord mouseDownEvent;
// Make sure docked windows are still appropriately docked
// in case user changed screen resolution while Eudora
// was in background
PositionDockedWindows();
// Make sure pending mouse downs don't hit a floating
// window that has just been made visible
if (OSEventAvail(mDownMask,&mouseDownEvent))
if (FindWindow_(event->where,&winWP) >= inContent)
if (IsFloating(winWP))
// Remove mousedown event for click in this floating window
GetNextEvent(mDownMask,&mouseDownEvent);
}
}
}
return(False);
}
/**********************************************************************
* RefreshLabelsMenu - get a new copy of the Finder's label strings
**********************************************************************/
void RefreshLabelsMenu(void)
{
MenuHandle mh = GetMHandle(LABEL_HIER_MENU);
if (mh)
{
TrashMenu(mh,3);
AddFinderItems(mh);
SetItemMark(mh,1,noMark);
EnableItem(mh,0);
EnableItem(mh,1); // For some reason OS X may leave this disabled
}
}
/************************************************************************
* SetSendQueue - preload the SendQueue global with the number of queued
* messages.
************************************************************************/
void SetSendQueue(void)
{
TOCHandle tocH;
int sumNum;
uLong gmtSecs = GMTDateTime();
PersHandle pers;
// if (InAThread())
// return;
SendQueue = 0;
ForceSend = 0xffffffff;
if (!(tocH=GetRealOutTOC())) return;
for (pers=PersList;pers;pers=(*pers)->next) (*pers)->sendQueue = 0;
for (sumNum=0; sumNum<(*tocH)->count; sumNum++)
{
if ((*tocH)->sums[sumNum].messH) continue; // skip open messages
if ((*tocH)->sums[sumNum].state == TIMED)
{
if ((*tocH)->sums[sumNum].seconds &&
(*tocH)->sums[sumNum].seconds < ForceSend)
ForceSend = (*tocH)->sums[sumNum].seconds;
if ((*tocH)->sums[sumNum].seconds <= gmtSecs)
SetState(tocH,sumNum,QUEUED);
}
if ((*tocH)->sums[sumNum].state == QUEUED)
{
SendQueue++;
pers = TS_TO_PERS(tocH,sumNum);
if (!pers)
{
pers = PersList;
(*tocH)->sums[sumNum].persId = 0;
TOCSetDirty(tocH,true);
}
(*pers)->sendQueue++;
}
}
}
/**********************************************************************
* DoApp1 - handle an app1 event; scrolling by saratoga keys
**********************************************************************/
Boolean DoApp1(WindowPtr topWinWP,EventRecord *event)
{
if (topWinWP && IsMyWindow(topWinWP))
{
MyWindowPtr topWin = GetWindowMyWindowPtr (topWinWP);
if (topWin->app1 && (*topWin->app1)(topWin,event))
;
else if (topWin->pte)
{
event->what = keyDown;
PeteEdit(topWin,topWin->pte,peeEvent,(void*)event);
}
else
return DoApp1NoPTE(topWin,event);
}
return(True);
}
/**********************************************************************
* DoApp1NoPTE - handle an app1 event but ignore window & pte handlers
**********************************************************************/
Boolean DoApp1NoPTE(MyWindowPtr topWin,EventRecord *event)
{
if (topWin->vBar)
switch(event->message & charCodeMask)
{
case homeChar:
ScrollIt(topWin,REAL_BIG,REAL_BIG);
break;
case endChar:
ScrollIt(topWin,0,-REAL_BIG);
break;
case pageUpChar:
ScrollIt(topWin,0,
RoundDiv(topWin->contR.bottom-topWin->contR.top,topWin->vPitch)-1);
break;
case pageDownChar:
ScrollIt(topWin,0,
RoundDiv(topWin->contR.top-topWin->contR.bottom,topWin->vPitch)+1);
break;
}
return true;
}
/**********************************************************************
* DoKeyDown - handle a keystroke aimed at a window
**********************************************************************/
void DoKeyDown(WindowPtr topWinWP,EventRecord *event)
{
long select;
short c = UnadornMessage(event)&0xff;
OSErr err=errAEEventNotHandled;
Boolean done;
// (jp) Check for cmd-period while speaking
#ifdef SPEECH_ENABLED
if (event->what==keyDown && event->modifiers&cmdKey && IsCmdChar(event,'.') || // command-period
(event->message&charCodeMask)==escChar) //esc
if (CancelSpeech ()) {
FlushEvents (keyDownMask|keyUpMask|mDownMask|mUpMask,0); /* kill events on cmd-period */
return;
}
#endif
ClickType = Single; // can't keydown during a double-click
if (IsMyWindow(topWinWP))
{
MyWindowPtr topWin = GetWindowMyWindowPtr(topWinWP);
SetPort_(GetWindowPort (topWinWP));
// (jp) If the field supports nick stuff, handle the keystroke
done = false;
if (HasNickScanCapability (topWin->pte)) {
if (!(done = NicknameWatcherKey (topWin->pte, event)))
if (topWin->key) {
if ((*topWin->key)(topWin,event))
done = true;
}
else
if (!(event->modifiers & cmdKey)) {
(void) PeteEdit (topWin, topWin->pte, peeEvent, (void*) event); // (jp) Just in case no key function is defined (dialogs)
done = true;
}
NicknameWatcherKeyFollowup (topWin->pte);
// if (IsWazoo (topWin))
// ValidRect (PeteRect (topWin->pte, &r)); // (jp) Lame, I know... but we have a flicker problem. :|
// The problem is caused because the nickname watching
// code invalidates the field. Okay, fair enough...
// But, if the nickname window is wazooed, WazooPreUpdate
// is called which calls Draw1Control on the tab -- which
// erases the text we just finished drawing. Boo. Hiss.
// We con't have this problem in either composition windows
// or in windows that not wazooed. A more general solution
// should eventually replace this hackery.
}
if (!done) {
short charCode = event->message&charCodeMask;
if (!topWin->pte && charCode==backSpace && event->modifiers==cmdKey)
DoMenu(topWinWP,(EDIT_MENU<<16)|EDIT_CLEAR_ITEM,0);
else if (topWin->key && (*topWin->key)(topWin,event))
;
else if (event->modifiers&cmdKey)
{
if (IsMyWindow(topWinWP) && topWin && topWin->pte)
err = PeteEdit(topWin,topWin->pte,peeEvent,(void*)event);
if (err==errAEEventNotHandled)
if (select=MyMenuKey(event)) DoMenu(topWinWP,select,event->modifiers);
else SysBeep(20L);
return;
}
else if (topWin->pte)
PeteKey(topWin,topWin->pte,event);
}
}
else if (event->modifiers&cmdKey)
{
if (select=MyMenuKey(event))
DoMenu(topWinWP,select,event->modifiers);
else
SysBeep(20L);
}
else
SysBeep(20L);
}
pascal void Hook(void)
{
if (RunType != Production && CurrentModifiers()&controlKey)
{
Handle fkey3;
if (fkey3 = GetResource_('FKEY',3))
{
(*(ProcPtr)LDRef(fkey3))();
UL(fkey3);
}
else SysBeep(10);
}
}
/**********************************************************************
* DoMouseDown - handle a mouse-down event, goodness knows where
**********************************************************************/
void DoMouseDown(WindowPtr topWinWP,EventRecord *event)
{
static Point downSpot; /* Point of previous mouseDown */
static long upTicks; /* time of previous mouseUp */
long dblTime; /* double-click time from PRAM */
long wPart; /* window part where click occurred */
MyWindowPtr topWin;
WindowPtr winWP;
MyWindowPtr win;
short tolerance;
long mSelect;
topWin = GetWindowMyWindowPtr (topWinWP);
if (event->what==mouseUp)
{
upTicks = event->when;
if (IsMyWindow(topWinWP) && topWin && topWin->pte) PeteEdit(topWin,topWin->pte,peeEvent,event);
return;
}
dblTime = GetDblTime();
tolerance = GetRLong(DOUBLE_TOLERANCE);
/*
* figure out whether this is a double or triple click,
* and update double and triple click times
*/
if (event->when-upTicks<dblTime)
{
int dx = event->where.h - downSpot.h;
int dy = event->where.v - downSpot.v;
if (ABS(dx)<tolerance && ABS(dy)<tolerance && !(event->modifiers&cmdKey))
{
/* upgrade the click */
ClickType++;
if (ClickType > Triple) ClickType = Single;
}
else
ClickType = Single;
}
else
ClickType = Single;
upTicks = event->when;
downSpot = event->where;
SFWTC = True;
/*
* where was the click?
*/
wPart = FindWindow_(event->where,&winWP);
win = GetWindowMyWindowPtr (winWP);
UsingWindow(winWP);
#ifdef CTB
if (CnH && winWP && (long)CnH==GetWindowPrivateData(winWP))
CMEvent(CnH,event);
else
#endif
if (ModalWindow && winWP && winWP!=ModalWindow)
SysBeep(20L);
else
switch (wPart)
{
case inMenuBar:
EnableMenuItems(False);
SetMyCursor(arrowCursor); SFWTC = True;
SetMenuTexts(event->modifiers,False);
mSelect = MenuSelect(event->where);
DoMenu(topWinWP,mSelect,event->modifiers);
break;
case inProxyIcon:
if (win && win->proxy)
{
win->proxy(win,event);
break;
}
// fall-through is deliberate
case inDrag:
#ifdef FLOAT_WIN
if (!InBG && event->modifiers & cmdKey && IsTopNonFloater(winWP) && (IsBoxWindow(winWP) || IsMessWindow(winWP)))
#else //FLOAT_WIN
if (!InBG && event->modifiers & cmdKey && winWP==topWinWP && (IsBoxWindow(winWP) || IsMessWindow(winWP)))
#endif //FLOAT_WIN
PopupMailboxPath(win,nil,0,downSpot);
else
{
DragMyWindow(winWP,event->where);
#ifdef TWO
if (IsMessWindow(winWP) && ClickType==Double)
{
MyWindowPtr messTocWin = (*(*Win2MessH(win))->tocH)->win;
WindowPtr messTocWinWP = GetMyWindowWindowPtr(messTocWin);
ShowMyWindow(messTocWinWP);
UserSelectWindow(messTocWinWP);
SelectMessage((*Win2MessH(win))->tocH,(*Win2MessH(win))->sumNum);
if (event->modifiers&optionKey) BoxSelectSame((*Win2MessH(win))->tocH,SORT_SUBJECT_ITEM,(*Win2MessH(win))->sumNum);
}
#endif
}
break;
case inZoomIn:
case inZoomOut:
if (IsMyWindow(winWP)) win->saveSize = True;
ZoomMyWindow(winWP,event->where,wPart);
break;
case inGrow:
if (!(GetWindowKind(winWP)==dialogKind ||
IsMyWindow(winWP) && win && win->isRunt))
{
GrowMyWindow(win,event);
break;
}
/* fall-through is deliberate */
case inContent:
DoContentClick(topWinWP,winWP,event);
break;
case inGoAway:
if (event->modifiers & optionKey)
CloseAll(False);
else
GoAwayMyWindow(winWP,event->where);
break;
}
}
/**********************************************************************
* DoContentClick - handle a click in the content region of a window
**********************************************************************/
void DoContentClick(WindowPtr topWinWP,WindowPtr winWP,EventRecord *event)
{
MyWindowPtr win = GetWindowMyWindowPtr (winWP);
PETEHandle pte;
Point pt;
// (jp) Ignore clicks if for some reason we don't have a MyWindowPtr
if (!win)
return;
#ifdef FLOAT_WIN
if (IsMyWindow(winWP) && IsFloating(winWP))
SetKeyFocusedFloater(win);
else
{
SetKeyFocusedFloater(nil);
#endif //FLOAT_WIN
if (winWP != topWinWP)
{
SetPort_(GetWindowPort(winWP));
if (IsMyWindow(winWP) && WinBGDrag(win,event))
; // leave it alone
else if (IsMyWindow(winWP) && win->bgClick)
(*win->bgClick)(win,event);
else
SelectWindow_(winWP);
return;
}
#ifdef FLOAT_WIN
}
#endif //FLOAT_WIN
SetPort_(GetWindowPort(winWP));
pt = event->where;
GlobalToLocal(&pt);
if (!win->dontControl && HandleControl(pt,win))
;
else if (IsMyWindow(winWP))
{
if (!ClickWazoo(win,event,pt,nil))
if (!ClickSponsorAd(win,event,pt))
{
if (win->click)
(*win->click)(win,event);
else {
// (jp) Figure out which PETE actually received the click
for (pte = win->pteList; pte; pte = PeteNext (pte))
if (PtInPETE (pt, pte))
break;
if (PeteIsValid(pte)) {
if (pte != win->pte)
PeteSelect (win, win->pte, 0, 0);
PeteEditWFocus (win, pte, peeEvent, (void *) event, nil);
}
}
}
}
}
/**********************************************************************
*
**********************************************************************/
Boolean WinBGDrag(MyWindowPtr win,EventRecord *event)
{
WindowPtr winWP = GetMyWindowWindowPtr (win);
PETEHandle pte;
Point where;
Boolean result=False;
PushGWorld();
SetPort_(GetWindowPort(winWP));
where = event->where;
GlobalToLocal(&where);
if (IsWazoo(winWP) && ClickWazoo(win,event,where,&result) && result)
; // bg wazoo drag; all done now
else
{
for (pte=win->pteList;pte;pte=PeteNext(pte))
{
if (PtInPETE(where,pte))
{
if (tsmDocNotActiveErr!=PeteEdit(win,pte,peeEvent,event))
result = True;
break;
}
}
}
PopGWorld();
return(result);
}
/************************************************************************
* HandleControl
************************************************************************/
Boolean HandleControl(Point pt, MyWindowPtr win)
{
WindowPtr winWP = GetMyWindowWindowPtr (win);
int part;
int oldValue, difference;
ControlHandle cntl;
if (part = FindControl(pt,winWP,&cntl))
{
// Not in scrollbar thumb
if (part != kControlIndicatorPart)
{
part = TrackControl(cntl, pt, (ControlActionUPP)(-1));
ScrollAction(cntl,0); // reset scroll throttle when mouse goes up
}
// Live scroll
else if (GetControlVariant(cntl) != 0)
{
gLastCtlValue = GetControlValue(cntl);
part = TrackControl(cntl, pt, NewControlActionUPP(AMLiveScrollAction));
}
// Regular scroll
else
{
oldValue = GetControlValue(cntl);
part = TrackControl(cntl, pt, nil);
difference = oldValue - GetControlValue(cntl);
if (difference)
{
if (ScrollIsH(cntl))
ScrollMyWindow(win,difference,0);
else
ScrollMyWindow(win,0,difference);
UpdateMyWindow(winWP);
}
}
if (part && win->button)
(*win->button)(win,cntl,CurrentModifiers(),part);
return(True);
}
return(False);
}
/**********************************************************************
* DoUpdate - handle an update event
**********************************************************************/
Boolean DoUpdate(WindowPtr topWin,EventRecord *event)
{
#pragma unused(topWin)
WindowPtr theWindow;
if (theWindow = Event2Window(event))
{
#ifdef CTB
if (CnH && GetWindowPrivateData(theWindow)==(long)CnH)
{
CMEvent(CnH,event);
return(False);
}
#endif
if (IsMyWindow(theWindow))
{
UpdateMyWindow(theWindow);
return(False);
}
}
return(True); /* somebody else better do this one */
}
StackHandle ContextStack;
typedef struct {GrafPtr port; short curResFile;} SwitchContext;
/**********************************************************************
* MightSwitch - protect from the vagaries of other apps
**********************************************************************/
void MightSwitch(void)
{
SwitchContext context;
GetPort(&context.port);
context.curResFile = CurResFile();
if (!ContextStack) StackInit(sizeof(context),&ContextStack);
if (!ContextStack) return;
StackPush(&context,ContextStack);
SetPort(InsurancePort);
}
/**********************************************************************
* AfterSwitch - restore things after a switch back in
**********************************************************************/
void AfterSwitch(void)
{
SwitchContext context;
if (!ContextStack) return;
if (!StackPop(&context,ContextStack))
{
SetPort(context.port);
UseResFile(context.curResFile);
}
}
/**********************************************************************
* DoActivate - handle an activate event (and a prior deactivate, to boot)
**********************************************************************/
Boolean DoActivate(WindowPtr topWin,EventRecord *event)
{
#pragma unused(topWin)
WindowPtr theWindow;
Boolean active = !InBG && (event->modifiers&activeFlag)!=0;
Boolean yours = False;
if (theWindow = Event2Window(event))
{
UsingWindow(theWindow);
#ifdef CTB
if (CnH && (long)CnH==GetWindowPrivateData(theWindow))
CMActivate(CnH,active);
else
#endif
if (IsMyWindow(theWindow))
{
if (!CorrectlyActivated(theWindow))
ActivateMyWindow(theWindow,active!=0);//(event->modifiers&activeFlag)!=0);
}
else
yours=True;
}
SFWTC=True;
return(yours);
}
/**********************************************************************
* WarnUser - tell the user that something bad is happening
**********************************************************************/
int WU(AlertType type,int errorStr,int errorNum,int file,int line)
{
Str255 message;
Str255 explanation;
Str63 techStuff;
AlertStdAlertParamRec param;
UPtr sec;
extern ModalFilterUPP DlgFilterUPP;
short realSettingsRef = SettingsRefN;
if (errorNum!=userCancelled)
{
SettingsRefN = GetMainGlobalSettingsRefN();
GetRString(message,errorStr);
if (sec=PIndex(message,'<EFBFBD>'))
{
*explanation = *message - (sec-message);
BMD(sec+1,explanation+1,*explanation);
*message -= *explanation+1;
}
else if (errorNum==-108 && errorStr!=MEM_ERR)
GetRString(explanation,MEM_ERR);
else
*explanation = 0;
if (errorNum) ComposeRString(techStuff,WU_FMT,errorNum,file,line);
else ComposeRString(techStuff,WU_NOERR_FMT,file,line);
PCat(explanation,techStuff);
SettingsRefN = realSettingsRef;
Zero(param);
param.movable = True;
param.filterProc = DlgFilterUPP;
param.defaultButton = kAlertStdAlertOKButton;
param.position = kWindowDefaultPosition;
ReallyStandardAlert(type,message,explanation,&param);
}
return(errorNum);
}
/**********************************************************************
* DieWithError - die with the given error message
**********************************************************************/
void DWE(int errorStr,int errorNum,int file,int line)
{
Str255 fatal;
Str255 message;
Str255 number;
Str255 debugStr;
GetRString(fatal,FATAL);
GetRString(message,errorStr);
NumToString((long)errorNum,number);
ComposeRString(debugStr,FILE_LINE_FMT,file,line);
MyParamText(fatal,message,number,debugStr);
if (gAppearanceIsLoaded)
ComposeStdAlert(kAlertStopAlert,ERR_ASTR+ALRTStringsStrn,P1,P2,P3,P4);
else
StopAlert(NON_AM_ERR_ALRT, nil);
Cleanup();
ExitToShell();
}
/**********************************************************************
* DumpData - put up an alert that shows some data.
**********************************************************************/
void DumpData(UPtr description, UPtr data,int length)
{
Str255 asAscii;
Str255 asHex;
static char hex[]="0123456789abcdef";
char *ac, *hx;
char *from;
if (length > 255/2) length = 255/2;
/*
* prepare display strings
*/
*asAscii = 2*length;
*asHex = 2*length;
ac=asAscii+1;
hx=asHex+1;
for (from=data; from<data+length;from++)
{
*ac++ = optSpace;
if (*from==' ')
*ac++ = optSpace;
else if (*from<' ')
*ac++='.';
else
*ac++ = *from;
*hx++ = hex[((*from)>>4)&0xf];
*hx++ = hex[(*from)&0xf];
}
SetDialogFont(kFontIDMonaco);
MyParamText(description,asAscii,asHex,"");
switch (Alert(DUMP_ALRT,nil))
{
case DEBUG_BUTTON: Debugger(); break;
case EXIT_BUTTON: Cleanup(); ExitToShell(); break;
}
SetDialogFont(applFont);
}
/**********************************************************************
* monitor the heap situation
**********************************************************************/
long MonitorGrow(Boolean report)
{
static long memLeft = NSpare*SPARE_SIZE;
long roomLeft;
long roomAvailable;
short i;
long deficit=0;
if (!DoMonitor) return(0);
roomLeft = 0;
for (i=0;i<NSpare;i++)
if (SpareSpace[i]) roomLeft += GetHandleSize_(SpareSpace[i]);
if (roomLeft < memLeft)
{
#ifdef LDAP_ENABLED
MonitorLDAPCodeGrow(true);
#endif
if (report && (memLeft==NSpare*SPARE_SIZE || roomLeft+10 K<memLeft || roomLeft<MEM_CRITICAL))
MemoryWarning();
}
if (roomLeft < NSpare*SPARE_SIZE)
{
memLeft = roomLeft;
#ifdef LDAP_ENABLED
MonitorLDAPCodeGrow(true);
#endif
for (i=0;i<sizeof(SpareSpace)/sizeof(Handle);i++)
{
ZapHandle(SpareSpace[i]);
roomAvailable = CompactMem(SPARE_SIZE);
if (roomAvailable < SPARE_SIZE) roomAvailable = MaxMem(&roomLeft);
if (roomAvailable > SPARE_SIZE) roomAvailable = SPARE_SIZE;
MakeGrow(roomAvailable,i);
if (SpareSpace[i]) deficit += SPARE_SIZE-GetHandleSize_(SpareSpace[i]);
else deficit += SPARE_SIZE;
}
}
#ifdef LDAP_ENABLED
MonitorLDAPCodeGrow(false);
#endif
if (MemLastFailed || deficit)
{
long total;
PurgeSpace(&total,&MemLastFailed);
}
return(deficit);
}
/************************************************************************
* MemoryWarning - warn the user about how much memory is left.
************************************************************************/
void MemoryWarning(void)
{
Str255 partitionString;
long currentSize, estSize, spareSize;
short i;
#ifdef THREADING_ON
/* just cancel what you're doing and set error flag */
if (InAThread())
{
TaskKindEnum taskKind = GetCurrentTaskKind();
CommandPeriod=True;
if (taskKind==CheckingTask)
CheckThreadError = memFullErr;
else
if (taskKind==SendingTask)
SendThreadError = memFullErr;
return;
}
#endif
currentSize = CurrentSize();
estSize = EstimatePartitionSize(false);
spareSize = 0;
for (i=0;i<NSpare;i++)
if (SpareSpace[i]) spareSize += GetHandleSize_(SpareSpace[i]);
estSize = MAX(estSize,NSpare*SPARE_SIZE-spareSize+currentSize);
(void) ComposeRString(partitionString,MEM_PARTITION,currentSize/(1 K),
estSize/(1 K));
if (ComposeStdAlert(Stop,MEMORY_ALRT,MEM_LOW,MEM_EXPLANATION,partitionString)==MEMORY_QUIT) CommandPeriod=EjectBuckaroo=True;
}
/************************************************************************
* CurrentSize - how big is our partition?
************************************************************************/
uLong CurrentSize(void)
{
ProcessInfoRec pi;
ProcessSerialNumber psn;
uLong size=0;
pi.processInfoLength = sizeof(pi);
pi.processName = nil;
pi.processAppSpec = nil;
if (!GetProcessInformation(CurrentPSN(&psn),&pi))
{
return(pi.processSize-44 K); /* dunno where finder gets 44K, but... */
}
else return(DefaultSize());
}
/************************************************************************
* DefaultSize - how big is Eudora's normal partition?
************************************************************************/
uLong DefaultSize(void)
{
SizeHandle sizeH;
uLong size=0;
if (sizeH = GetResource_('SIZE',-1))
{
size = (*sizeH)->prefSize;
ReleaseResource_(sizeH);
}
return(size);
}
/************************************************************************
* EstimatePartitionSize - estimate the "right" size for Eudora
************************************************************************/
uLong EstimatePartitionSize(Boolean log)
{
Str31 suffix;
uLong drain = 0;
static short strids[] = {IN,OUT,TRASH};
short id;
MyWindowPtr win;
WindowPtr winWP;
uLong dFork = 0;
uLong size;
FSSpec spec;
short tocFactor = PrefIsSet(PREF_NO_RF_TOC_BACKUP) ? 1 : 2;
#ifdef DEBUG
uLong oldDrain;
#endif
GetRString(suffix,TOC_SUFFIX);
spec.vRefNum = MailRoot.vRef;
spec.parID = MailRoot.dirId;
for (id=0;id<sizeof(strids)/sizeof(short);id++)
{
GetRString(spec.name,strids[id]);
if (!PrefIsSet(PREF_NEW_TOC) || !(size=FSpRFSize(&spec)))
{
PSCat(spec.name,suffix);
size = tocFactor*FSpDFSize(&spec);
}
drain += size/tocFactor;
#ifdef DEBUG
if (log) ComposeLogS(-1,nil,"\pMailbox: %p: %d",spec.name,size/tocFactor);
#endif
}
/*
* nicknames
*/
drain += NickDrain() + ETLDrain();
#ifdef DEBUG
if (log) ComposeLogS(-1,nil,"\pNicknames: %d",NickDrain());
if (log) ComposeLogS(-1,nil,"\pEMSAPI: %d",ETLDrain());
#endif
for (winWP=FrontWindow_();winWP;winWP=GetNextWindow(winWP))
{
win = GetWindowMyWindowPtr (winWP);
#ifdef DEBUG
oldDrain = drain;
#endif
drain += sizeof(MyWindow) + 1 K + 5 K; // 5K seems to cover appearance requirements, give or take
switch (GetWindowKind(winWP))
{
case COMP_WIN:
case MESS_WIN:
drain += PETEGetMemInfo(PETE,(*Win2MessH(win))->bodyPTE);
drain += (*Win2MessH(win))->extras.offset;
drain += 7 K; // lots of controls in those windows
break;
case TEXT_WIN:
drain += PETEGetMemInfo(PETE,win->pte);
break;
case MBOX_WIN:
case CBOX_WIN:
if (!(*(TOCHandle)GetMyWindowPrivateData(win))->which)
drain += GetHandleSize_((TOCHandle)GetMyWindowPrivateData(win));
break;
default:
drain += 5 K;
}
#ifdef DEBUG
if (log)
{
Str255 title;
GetWTitle(winWP,title);
ComposeLogS(-1,nil,"\pMailbox: %p: %d",title,drain-oldDrain);
}
#endif
}
if (IsPowerNoVM())
{
FSSpec appSpec;
if (!GetFileByRef(AppResFile,&appSpec))
{
dFork = FSpDFSize(&appSpec);
// Hack! Hack! Hack!
// Fat version is way big, and ppc is about 5/9 of it.
// The proper way to calculate this is to walk the cfrg resource,
// but that looks more complicated than it's worth. SD
if (dFork > 3 K K)
#if TARGET_CPU_PPC
dFork = (dFork*5)/9;
#else
dFork = (dFork*4)/9;
#endif
}
}
#ifdef NEVER
if (RunType!=Production) drain += 2000 K;
#endif
drain = MAX(0,drain - 1500 K);
return(DefaultSize()+drain+dFork);
}
/**********************************************************************
* NickDrain - compute drain due to nicknames
**********************************************************************/
long NickDrain(void)
{
Str31 name;
FSSpec folderSpec;
CInfoPBRec hfi;
FSSpec spec;
long drain = 0;
/*
* add the Eudora Nicknames file
*/
FSMakeFSSpec(Root.vRef,Root.dirId,GetRString(name,ALIAS_FILE),&spec);
drain += FSpRFSize(&spec);
#ifdef TWO
/*
* add the Eudora Nicknames Cache file
*/
FSMakeFSSpec(Root.vRef,Root.dirId,GetRString(name,CACHE_ALIAS_FILE),&spec);
drain += FSpRFSize(&spec);
#ifdef VCARD
/*
* add the Personal Nicknames file
*/
if (HasFeature (featureVCard)) {
FSMakeFSSpec(Root.vRef,Root.dirId,GetRString(name,PERSONAL_ALIAS_FILE),&spec);
drain += FSpRFSize(&spec);
}
#endif
/*
* is there a nicknames folder?
*/
if (!SubFolderSpec(NICK_FOLDER,&folderSpec))
{
/*
* iterate through all the files, adding them to the list
*/
hfi.hFileInfo.ioNamePtr = name;
hfi.hFileInfo.ioFDirIndex = 0;
while (!DirIterate(folderSpec.vRefNum,folderSpec.parID,&hfi))
{
SimpleMakeFSSpec(folderSpec.vRefNum,folderSpec.parID,name,&spec);
drain += FSpRFSize(&spec);
}
}
#endif
return(drain);
}
/**********************************************************************
* create some space for the grow zone function
**********************************************************************/
void MakeGrow(long howMuch,short which)
{
Boolean oldMonitor = DoMonitor;
DoMonitor = False;
if (SpareSpace[which] = NuHandle(howMuch)) **(long **)SpareSpace[which] = 'SPAR';
DoMonitor = oldMonitor;
}
/**********************************************************************
* grow that zone...
**********************************************************************/
pascal long MyGrowZone(unsigned long needed)
{
long roomLeft;
long freed=0;
long theA5=SetCurrentA5();
Handle dontMove = (Handle)GZSaveHnd();
short resFile = CurResFile();
short i;
MemLastFailed = 1 K;
if (SettingsRefN) UseResFile(SettingsRefN);
if (!MemCanFail)
{
for (i=0;i<NSpare;i++)
if (dontMove!=(Handle)SpareSpace[i] && (roomLeft = InlineGetHandleSize((Handle)SpareSpace[i])))
{
freed = needed <= roomLeft ? needed : roomLeft;
SetHandleSize(SpareSpace[i],roomLeft - freed);
}
if (!freed && DamagedTOC && DamagedTOC != (TOCHandle)dontMove)
{
freed = InlineGetHandleSize((Handle)DamagedTOC);
ZapHandle(DamagedTOC);
}
}
UseResFile(resFile);
(void) SetA5(theA5);
return(freed);
}
/************************************************************************
* CloseUnused - close unused windows
************************************************************************/
long CloseUnused(void)
{
static short kinds[] = {MB_WIN,PH_WIN,TEXT_WIN,ALIAS_WIN,MESS_WIN,COMP_WIN,FILT_WIN,PICT_WIN,PERS_WIN,SIG_WIN,STA_WIN,LINK_WIN};
WindowPtr winWP,deadWinWP=nil;
MyWindowPtr win;
short kind;
for (kind=0;kind<sizeof(kinds)/sizeof(short);kind++)
{
for (winWP=FrontWindow();winWP;winWP=GetNextWindow(winWP))
{
win = GetWindowMyWindowPtr (winWP);
if (GetWindowKind(winWP)==kinds[kind] && win && !IsDirtyWindow (win) && !win->inUse)
if (kinds[kind]!=MESS_WIN || win->pte!=(*Win2MessH(win))->subPTE) deadWinWP = winWP;
}
if (deadWinWP)
{
if (!CloseMyWindow(deadWinWP))
{
UsingWindow(deadWinWP); /* couldn't close it ??? */
deadWinWP = nil;
kind--; /* try again with this kind */
}
else
{
return(1);
}
}
}
return(0);
}
/**********************************************************************
* FileSystemError - report an error regarding the file system
**********************************************************************/
int FSE(int context, UPtr name, int realErr, int file,int line)
{
Str255 text;
Str255 contextStr;
Str63 debugStr;
int offset = 0;
AlertStdAlertParamRec param;
extern ModalFilterUPP DlgFilterUPP;
OSErr err = realErr;
short realSettingsRef = SettingsRefN;
if (err!=userCancelled && err!=userCanceledErr)
{
SettingsRefN = GetMainGlobalSettingsRefN();
ComposeRString(text,FSE_NAME_ERR,name,err);
if (err < wrPermErr) offset += wrPermErr-dirNFErr-1;
if (err < volGoneErr) offset += volGoneErr+128;
err += offset;
err = dirFulErr - err + 2;
if (err > 37) err = 37;
GetRString(contextStr,FILE_STRN+err);
PCat(text,contextStr);
ComposeRString(debugStr,FILE_LINE_FMT,file,line);
PCat(text,debugStr);
GetRString(contextStr,context);
SettingsRefN = realSettingsRef;
Zero(param);
param.movable = True;
param.filterProc = DlgFilterUPP;
param.defaultButton = kAlertStdAlertOKButton;
param.position = kWindowDefaultPosition;
ReallyStandardAlert(kAlertCautionAlert,contextStr,text,&param);
}
return(realErr);
}
/************************************************************************
* MiniMainLoop - handle only a limited set of events. returns the event
* if someone else needs to handle it
************************************************************************/
Boolean MiniMainLoopLo(EventRecord *event);
Boolean MiniMainLoop(EventRecord *event)
{
Boolean result;
PushGWorld();
result = MiniMainLoopLo(event);
PopGWorld();
return(result);
}
Boolean MiniMainLoopLo(EventRecord *event)
{
WindowPtr topWinWP=FrontWindow_();
switch (event->what)
{
#ifndef NO_KEYUP
case keyUp:
#endif
case keyDown:
if ((event->modifiers&cmdKey) && IsCmdChar(event,'.') ||
((event->message&charCodeMask)==escChar) &&
(((event->message&keyCodeMask)>>8)==escKey))
{
FlushEvents(keyDownMask,0); /* kill all downs if we have a command-period */
#ifdef SPEECH_ENABLED
if (CancelSpeech ())
return (false);
#endif
CommandPeriod = True;
if (ProgressIsTop()) PressStop();
return(True);
}
break;
case app4Evt:
if (((event->message)>>24)&1 == 1)
DoApp4(topWinWP,event);
return(False);
case updateEvt:
DoUpdate(topWinWP,event);
return(False);
break;
case activateEvt:
DoActivate(topWinWP,event);
return(False);
break;
case mouseDown:
if (ModalWindow && ModalWindow==FrontWindow_()) DoMouseDown(ModalWindow,event);
break;
}
#ifdef CTB
if (CnH && topWinWP && GetWindowPrivateData(topWinWP)==(long)CnH)
{
CMEvent(CnH,event);
return(False);
}
#endif
#ifdef NO_KEYUP
if (HasCommandPeriod()) return(True);
#endif
return(False);
}
/**********************************************************************
*
**********************************************************************/
Boolean HasCommandPeriod(void)
{
if (InAThread()) return false;
if (!InBG)
{
if (CheckEventQueueForUserCancel())
{
FlushEvents(keyDownMask|keyUpMask|mDownMask|mUpMask,0); /* kill events on cmd-period */
if (CancelSpeech ()) return false;
CommandPeriod = True;
if (ProgressIsTop()) PressStop();
return true;
}
}
return false;
}
/************************************************************************
*
************************************************************************/
void FlushHIQ(void)
{
HostInfoQHandle hiq, nextHIQ;
for (hiq=HIQ;hiq;hiq=nextHIQ)
{
nextHIQ = (*hiq)->next;
if ((*hiq)->done && !(*hiq)->inUse)
{
LL_Remove(HIQ,hiq,(HostInfoQHandle));
ZapHandle(hiq);
}
}
}
/************************************************************************
* TendNotificationManager - see if an NM rec is active, and if it should
* be taken down
************************************************************************/
void TendNotificationManager(Boolean isActive)
{
if (MyNMRec)
{
long ticksSince = TickCount()-MyNMRec->nmRefCon;
if (isActive && ticksSince>10)
{
NMRemove(MyNMRec);
if (MyNMRec->nmIcon) DisposeIconSuite(MyNMRec->nmIcon,True);
ZapPtr(MyNMRec->nmStr);
ZapPtr(MyNMRec);
}
}
if (isActive) AttentionNeeded = false;
}
/**********************************************************************
* NuHandle - allocate a handle
**********************************************************************/
void *NuHandle(long size)
{
void *h;
RANDOM_FAILURE;
#ifdef NEVER
if (h = GetResource(POPD_TYPE,POPD_ID))
ASSERT(!(GetResAttrs(h)&resChanged) ||!(HGetState(h)&0x40));
#endif
#ifdef NEVER
if (MonitorGrow(False)>0)
{
#ifdef DEBUG
if (RunType!=Production) {SysBeep(10); DebugStr("\p;sc;g");}
#endif
#ifdef DEBUG
if (RunType==Debugging || size>100)
#endif
{
LMSetMemErr(-108);
return(nil);
}
}
#endif
MemCanFail = True;
h = NewHandle(size);
MemCanFail = False;
if (!h && MemLastFailed == 1 K || MemLastFailed > size) MemLastFailed = MIN(size,1 K);
return(h);
}
/**********************************************************************
* NuPtr - allocate a pointer
**********************************************************************/
void *NuPtr(long size)
{
void *h;
RANDOM_FAILURE;
MemCanFail = True;
MonitorGrow(False);
h = NewPtr(size);
MemCanFail = False;
if (!h && MemLastFailed == 1 K || MemLastFailed > size) MemLastFailed = MIN(size,1 K);
return(h);
}
/**********************************************************************
* NuPtrClear - allocate a zeroed pointer
**********************************************************************/
void *NuPtrClear(long size)
{
void *h;
RANDOM_FAILURE;
MemCanFail = True;
MonitorGrow(False);
h = NewPtrClear(size);
MemCanFail = False;
return(h);
}
/**********************************************************************
* get an event, giving time to system tasks as necessary
**********************************************************************/
Boolean GrabEvent(EventRecord *theEvent)
{
Boolean result;
/*
* get the event
*/
#ifndef NO_KEYUP
FlushEvents(keyUpMask,0);
#endif
DragFxxkOff = False;
result = WNE(everyEvent,theEvent,InBG ? 300L : ((Typing||ActiveSearchCount)?0:10L));
DragFxxkOff = theEvent->what!=nullEvent;
// make sure the rest of Eudora knows if we're typing
if ((theEvent->what==autoKey || theEvent->what==keyDown))
if (theEvent->modifiers&cmdKey)
TypingTicks = 0;
else
TypingTicks = TickCount();
Typing = TickCount()-TypingTicks<GetRLong(TYPING_THRESH);
TypingRecently = Typing || TickCount()-TypingTicks<GetRLong(TYPING_RECENTLY_THRESH);
/*
* handle special keys
*/
if (theEvent->what==keyDown || theEvent->what==autoKey)
SpecialKeys(theEvent);
/*
* global type-2-select buffer
*/
Type2Select(theEvent);
/*
* gd dialog manager
*/
if (!result && MyIsDialogEvent(theEvent))
{
Typing = False;
DoModelessEvent(GetDialogFromWindow(FrontWindow_()),theEvent);
}
return(result);
}
/**********************************************************************
* PantyTrack - handle drags
**********************************************************************/
pascal OSErr PantyTrack(DragTrackingMessage message, WindowPtr qWinWP, Ptr handlerRfCon, DragReference drag)
{
OSErr err=dragNotAcceptedErr;
MyWindowPtr qWin = GetWindowMyWindowPtr(qWinWP);
if (DragFxxkOff) return(dragNotAcceptedErr);
Dragging++;
if (IsMyWindow(qWinWP))
{
if (!DraggingWazoo(qWin,message,drag,&err))
if (qWin->drag) err = (*qWin->drag)(qWin,message,drag);
if (err==dragNotAcceptedErr) err = PeteDrag(qWin,message,drag);
else if (!qWin->butch) PeteDrag(nil,message,drag);
}
else if (IsPlugwindow(qWinWP))
err = PlugwindowDrag(qWinWP,message,drag);
else err = PeteDrag(nil,message,drag);
Dragging--;
return(err==kAcceptableGraphicDrag ? noErr : err);
}
pascal OSErr PantyReceive(WindowPtr qWin, Ptr handlerRfCon, DragReference drag)
{
OSErr err;
DECLARE_UPP(PantyTrack,DragTrackingHandler);
INIT_UPP(PantyTrack,DragTrackingHandler);
Dragging++;
err = PantyTrack(0x0fff,qWin,handlerRfCon,drag);
Dragging--;
return(err==kAcceptableGraphicDrag ? noErr : err);
}
/************************************************************************
* WNE - call WaitNextEvent. Make sure not to call from thread.
************************************************************************/
Boolean WNE(short eventMask,EventRecord *event,long sleep)
{
EventRecord localEvt;
Boolean result;
#ifdef THREADING_ON
static Boolean lastResult;
#endif
#ifdef THREADING_ON
if (InAThread ())
{
MyYieldToAnyThread();
return false;
}
else
if (!lastResult && !Typing)
MyYieldToAnyThread ();
#endif
#ifdef THREADING_ON
result = WNELo(eventMask,&localEvt,GetNumBackgroundThreads() ? 0 : sleep);
#else
result = WNELo(eventMask,&localEvt,sleep);
#endif
#ifdef THREADING_ON
lastResult = result;
#endif
ThreadYieldTicks = TickCount();
result = FMBEventFilter(&localEvt,result);
if (ToolbarShowing()) result = TBEventFilter(&localEvt,result);
if (PETE) PETEEventFilter(PETE,&localEvt);
if (!PlugwindowEventFilter(&localEvt)) return(false);
#ifdef TWO // frontier
if (localEvt.what==keyDown && localEvt.modifiers&cmdKey &&
(localEvt.message&charCodeMask)=='.' && SharedScriptRunning())
{
CancelSharedScript();
return(False);
}
#endif
if (event) *event=localEvt;
return(result);
}
/************************************************************************
* WNELo - call WaitNextEvent and do low-level processing
************************************************************************/
Boolean WNELo(short eventMask,EventRecord *event,long sleep)
{
EventRecord localEvt;
Boolean result;
ProcessSerialNumber me, him;
static Boolean mask;
Boolean foreground;
#if __profile__
//short profilerWas = ProfilerGetStatus();
#endif
static short oldmods;
if (eventMask && event && !sleep) sleep = 4;
#if __profile__
//ProfilerSetStatus(False);
#endif
MightSwitch();
#ifndef DRAG_GETOSEVT
if (Dragging)
{
result = False;
Zero(localEvt);
localEvt.what = nullEvent;
localEvt.when = TickCount();
}
#else
if (Dragging)
{
result = GetNextEvent(eventMask,&localEvt);
if (!result) UpdateAWindow();
}
#endif
else
result = WaitNextEvent(eventMask,&localEvt,sleep,MousePen);
if (localEvt.what!=nullEvent) NonNullTicks = TickCount();
#define HaveGetLastActivity ((GestaltBits(gestaltPowerMgrAttr)&(1<<gestaltPMgrDispatchExists))!=0)
#ifdef HAVE_GETLASTACTIVITY
if (localEvt.what==mouseDown || localEvt.what==keyDown || localEvt.what==keyUp || localEvt.what==autoKey)
{
if (HaveGetLastActivity) GlobalIdleTicks = 0;
}
else
{
ActivityInfo info;
OSErr err;
if (HaveGetLastActivity)
{
info.ActivityTime = 0;
info.ActivityType = UsrActivity;
if (!(err=GetLastActivity(&info)))
GlobalIdleTicks = TickCount()-info.ActivityTime;
}
}
#endif //HAVE_GETLASTACTIVITY
//if (RunType!=Production && localEvt.what) Dprintf("\p%d %x %x;g",localEvt.what,localEvt.message,localEvt.modifiers);
#if __profile__
//ProfilerSetStatus(profilerWas);
#endif
AfterSwitch();
YieldTicks = TickCount();
if (oldmods!=localEvt.modifiers)
{
oldmods = localEvt.modifiers;
SFWTC = True;
NonNullTicks = TickCount();
}
GetCurrentProcess(&me);
GetFrontProcess(&him);
SameProcess(&me,&him,&foreground);
InBG = !foreground;
NoInitialCheck = NoInitialCheck || (localEvt.what!=keyDown && !InBG && (oldmods&shiftKey)!=0);
#ifndef NO_KEYUP
if (!InBG && !mask)
{
mask = True;
SetEventMask(LMGetSysEvtMask()|keyUpMask);
}
#endif
if (event) *event=localEvt;
return(result);
}
/**********************************************************************
* NeedYield
**********************************************************************/
Boolean NeedYield(void)
{
short numThreads = GetNumBackgroundThreads();
long elapsedTicks = TickCount() - ThreadYieldTicks;
long vFactor = (InBG ? 1 : ((VicomIs && VicomFactor>0) ? VicomFactor : 1));
long yieldInterval = (InBG ? BgYieldInterval : FgYieldInterval) / ((numThreads ? numThreads : 1) * vFactor);
#ifdef HAVE_GETLASTACTIVITY
if (GlobalIdleTicks<60) yieldInterval = 0;
else if (GlobalIdleTicks<120) yieldInterval /= 2;
#endif //HAVE_GETLASTACTIVITY
// ASSERT(InBG ? (elapsedTicks < 120) : 1); // are we hogging time somewhere?
if (numThreads && !Typing) ToolbarIdleControls();
if (EventPending() || (elapsedTicks > yieldInterval))
return true;
return false;
}
#ifdef DRAG_GETOSEVT
/************************************************************************
* UpdateAWindow - update a window
************************************************************************/
void UpdateAWindow(void)
{
WindowPtr theWindow;
for (theWindow=FrontWindow();theWindow;theWindow=GetNextWindow(theWindow))
{
if (IsKnownWindowMyWindow(theWindow) && HasUpdateRgn(theWindow))
{
UpdateMyWindow(theWindow);
break;
}
}
}
#endif
#ifdef DEBUG
#define MemCorrupt(map,offset,string) MemCorruptLo(map,offset,string,__LINE__)
void MemCorruptLo(UHandle map,long offset,PStr msg,short line);
#define AtOffset(map,offset,type) *(type*)(*map+offset)
/**********************************************************************
* CheckHandle - check a handle for validity
**********************************************************************/
void CheckHandle(UHandle map,long offset,long size,THz hz,PStr string)
{
Handle h = *(Handle *)(*map+offset);
OSErr err = noErr;
/*
* in range?
*/
if (offset+3>GetHandleSize(map)) {MemCorrupt(map,offset,string);return;}
if (!h) return; /* nil ok */
/*
* handle a multiple of four?
*/
if ((uLong)h%4) {MemCorrupt(map,offset,string); return;}
/*
* handle in the zone?
*/
if ((uLong)h<(uLong)&hz->heapData || (uLong)h>(uLong)hz->bkLim) {MemCorrupt(map,offset,string); return;}
if (!*h) return; /* purged ok */
/*
* pointer a mult of four?
*/
if ((uLong)*h%4) {MemCorrupt(map,offset,string); return;}
/*
* pointer in the zone?
*/
if ((uLong)*h<(uLong)&hz->heapData || (uLong)*h>(uLong)hz->bkLim) {MemCorrupt(map,offset,string); return;}
/*
* size correct?
*/
if (size>=0 && GetHandleSize(h)!=size) {MemCorrupt(map,offset,string);return;}
/*
* handle looks ok to me
*/
return;
}
/**********************************************************************
*
**********************************************************************/
void MemCorruptLo(UHandle map,long offset,PStr msg,short line)
{
Str255 db;
Str255 scratch;
/*
* turn on logging
*/
DebugStr("\p;log MemCorrupt;g");
/*
* display line # & message
*/
NumToString(line,scratch);
PCopy(db,scratch);
PCatC(db,' ');
PCat(db,msg);
PCat(db,"\p;");
/*
* display area around the offending data
*/
PCat(db,"\pdm #");
NumToString((uLong)*map+offset,scratch);
PCat(db,scratch);
PCat(db,"\p-20 40;#");
/*
* print the address itself
*/
NumToString((uLong)*map+offset,scratch);
PCat(db,scratch);
/*
* turn off logging
*/
PCat(db,"\p;log");
/*
* now do it
*/
DebugStr(db);
}
#endif
/**********************************************************************
* SetupEventHandlers - setup carbon event handlers
**********************************************************************/
static void SetupEventHandlers(void)
{
// Scroll wheel support
EventTypeSpec wheelEventSpec =
{ kEventClassMouse,kEventMouseWheelMoved };
// Services menu support
EventTypeSpec servicesEventSpec[] =
{
{ kEventClassService, kEventServiceCopy },
{ kEventClassService, kEventServicePaste },
{ kEventClassService, kEventServiceGetTypes }
};
// Application target
EventTargetRef appTarget = GetApplicationEventTarget();
// Scroll wheel handler
InstallEventHandler(appTarget,NewEventHandlerUPP(WheelHandlerProc),sizeof(wheelEventSpec)/sizeof(EventTypeSpec),&wheelEventSpec,nil,nil);
// Services menu handler
if (!PrefIsSet(PREF_NO_SERVICES)) InstallEventHandler(appTarget,NewEventHandlerUPP(ServicesHandlerProc),sizeof(servicesEventSpec)/sizeof(EventTypeSpec),&servicesEventSpec,nil,nil);
}
/**********************************************************************
* WheelHandlerProc - carbon event handler for scroll wheel
**********************************************************************/
static pascal OSStatus WheelHandlerProc (EventHandlerCallRef nextHandler,EventRef event,void *data)
{
#pragma unused(nextHandler,data)
if ( ++gEnterWheelHandlerCount == 1 ) {
EventMouseWheelAxis axis;
SInt32 deltaH=0,deltaV=0;
WindowPtr winWP;
MyWindowPtr win;
Boolean vertical;
short lines;
PETEHandle pte;
HIPoint hiPt;
Point pt;
// Find window mouse is over
GetEventParameter(event,kEventParamMouseLocation,typeHIPoint,nil,sizeof(hiPt),nil,&hiPt);
pt.h = hiPt.x;
pt.v = hiPt.y;
FindWindow(pt,&winWP);
win = GetWindowMyWindowPtr(winWP);
if (win)
{
GetEventParameter(event,kEventParamMouseWheelAxis,typeMouseWheelAxis,nil,sizeof(axis),nil,&axis);
vertical = axis==kEventMouseWheelAxisY;
GetEventParameter(event,kEventParamMouseWheelDelta,typeLongInteger,nil,sizeof(deltaH), nil,
vertical ? &deltaV : &deltaH);
lines = GetRLong(SCROLL_WHEEL_LINES);
if (lines > 0 && lines <= 100)
{
deltaH *= lines;
deltaV *= lines;
}
// See if mouse is over a pte
SetPort(GetWindowPort(winWP));
GlobalToLocal(&pt);
for (pte=win->pteList;pte;pte=PeteNext(pte))
{
Rect rPTE;
PeteRect(pte,&rPTE);
if (PtInRect(pt,&rPTE))
break; // Found one!
}
if (pte)
{
short n,i;
n = deltaV >= 0 ? deltaV : -deltaV;
for(i=n;i--;)
PeteScroll(pte,0,deltaV>0?pseLineUp:pseLineDn);
if (IsBoxWindow(winWP))
{
TOCHandle tocH = Win2TOC(win);
if (pte==(*tocH)->previewPTE && PreviewReadFocus) BeenThereDoneThat(tocH,-1);
}
}
else if (win->pView && deltaV && PtInRect(pt,&win->pView->bounds))
LVScroll(win->pView,deltaV);
else if (win->scrollWheel && (win->scrollWheel)(win,pt,deltaH,deltaV))
;
else
ScrollIt(win,deltaH,deltaV);
}
}
gEnterWheelHandlerCount--;
return noErr;
}
/**********************************************************************
* AppendOSTypeToCFArray - add data type to CF array as CF string
**********************************************************************/
static void AppendOSTypeToCFArray(CFMutableArrayRef arrayRef,OSType type)
{
CFStringRef typeString = CreateTypeStringWithOSType(type);
if (typeString)
{
CFArrayAppendValue (arrayRef,typeString);
CFRelease (typeString);
}
}
/**********************************************************************
* ServicesHandlerProc - carbon event handler for Services menu
**********************************************************************/
static pascal OSStatus ServicesHandlerProc (EventHandlerCallRef nextHandler,EventRef event,void *data)
{
#pragma unused(nextHandler,data)
WindowPtr winWP = FrontWindow_();
MyWindowPtr win = GetWindowMyWindowPtr(winWP);
OSStatus err = noErr;
if (win && win->pte)
{
UInt32 eventKind = GetEventKind(event);
long start,stop;
Boolean selection;
CFMutableArrayRef copyTypes, pasteTypes;
ScrapRef serviceScrap;
selection = !PeteGetTextAndSelection(win->pte,nil,&start,&stop) && stop!=start;
switch (eventKind)
{
case kEventServiceGetTypes:
// Add the data types that we support to the copy/paste data-type arrays
if (selection)
{
// Do copy only if something is selected
if (!GetEventParameter(event,kEventParamServiceCopyTypes,typeCFMutableArrayRef,
NULL,sizeof (CFMutableArrayRef),NULL,&copyTypes))
{
// We copy only text
AppendOSTypeToCFArray(copyTypes,kScrapFlavorTypeText);
}
}
if (!GetEventParameter(event,kEventParamServicePasteTypes,typeCFMutableArrayRef,
NULL,sizeof (CFMutableArrayRef),NULL,&pasteTypes))
{
// We paste text, styl, or PICT
AppendOSTypeToCFArray(pasteTypes,kScrapFlavorTypeText);
AppendOSTypeToCFArray(pasteTypes,kScrapFlavorTypeTextStyle);
AppendOSTypeToCFArray(pasteTypes,kScrapFlavorTypePicture);
AppendOSTypeToCFArray(pasteTypes,'RTF ');
AppendOSTypeToCFArray(pasteTypes,'TIFF');
}
break;
case kEventServiceCopy:
if (!selection)
// Nothing to copy
break;
// Fall through
case kEventServicePaste:
// Get the service scrap
if (!GetEventParameter(event,kEventParamScrapRef,typeScrapRef,
NULL,sizeof(ScrapRef),NULL,&serviceScrap))
{
PETEUseScrap(PETE,serviceScrap);
// Make sure it's not locked. We allow text services to change
// read-only messages.
if (eventKind==kEventServicePaste) PeteLock(win->pte,kPETECurrentSelection,kPETECurrentSelection,peNoLock);
err = PeteEdit(win,win->pte,eventKind==kEventServiceCopy?peeCopy:peePaste,&MainEvent);
PETEUseScrap(PETE,nil);
}
break;
}
}
return err;
}
#pragma segment MacOS
#pragma segment StdC
#pragma segment Hesiod
#pragma segment MiscLibs
#pragma segment ICGlue