/* 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-upTickswhere.h - downSpot.h; int dy = event->where.v - downSpot.v; if (ABS(dx)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,'¤')) { *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,¶m); } 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>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 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;iprefSize; 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;idbodyPTE); 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;iinUse) 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,¶m); } 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()-TypingTickswhat==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<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,©Types)) { // 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