Rev 15168 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** R : A Computer Language for Statistical Data Analysis* File R_Event.c* Copyright (C) 1998-1999 Ross Ihaka* 2000-2001 Stefano M. Iacus the R core team** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*** This file is adapted from the public demos coming with the Waste library* distribution: WASTE Text Engine © 1993-2000 Marco Piovanelli.** This file was originally written by: Wing Kwong (Tiki), WAN 3/2/99* Updated to last version of WasteLib library: Stefano M. Iacus, 2001** Original file was:** WASTE Demo Project:* Dialog Utilities** Copyright © 1993-1998 Marco Piovanelli* All Rights Reserved** C port by John C. Daub*//*R_Eventby wing kwong (Tiki), WAN 3/2/99DescriptionThis file is based on the WASTE and WASTE demo, I had do somemodification to make it function as the way R want. The routine inhere is used to handle event (high or low level event.)*/#include <AppleEvents.h>#ifndef __AEREGISTRY__#include <AERegistry.h>#endif#ifndef __DISKINIT__#include <DiskInit.h>#endif#ifndef __TEXTSERVICES__#include <TextServices.h>#endif#ifndef __WEDEMOAPP__#include "RIntf.h"#endif#ifdef HAVE_CONFIG_H#include <config.h>#endif#include "Defn.h"#include "Graphics.h"#include "Startup.h" /* Jago */#include <Rdevices.h>Boolean EventsInit = false;SEXP R_LoadFromFile(FILE*, int);UInt32 sSleepTime = 0; // sleep time for WaitNextEvent()RgnHandle sMouseRgn = nil; // mouse region for WaitNextEvent()PicHandle WinPic;Boolean fstart = true;SInt16 Help_Window = 1;WindowPtr Help_Windows[MAX_NUM_H_WIN + 1];AEIdleUPP gAEIdleUPP;EventRecord gERecord;Boolean gQuit, gInBackground;#define kResumeMask 1 /* bit of message field for resume vs. suspend */extern Graphic_Ref gGReference[MAX_NUM_G_WIN + 1];extern SInt16 gExpose;extern Boolean gfinishedInput,finished;extern WindowPtr Console_Window;extern SInt16 Edit_Window;extern WindowPtr Edit_Windows[MAX_NUM_E_WIN + 1];extern SInt32 gChangeAble, gbuflen;extern char* gbuf;extern int isGraphicWindow (WindowPtr);extern void doActivate(EventRecord*);extern WindowPtr Working_Window;extern char InitFile[256];extern SInt16 gTextSize;extern RGBColor gTypeColour;#define kCMDEventClass 'DCMD' /* Event class command for MacZip */#define kCMDEvent 'DCMD' /* Event command */void DoGenKeyDown ( const EventRecord *event, Boolean Console);extern pascal OSErr FSpGetFullPath (const FSSpec*, short*, Handle*);extern int R_SetOptionWidth(int w);extern int R_ChooseFile(int isNewFile, char *fileBuf, int buflen);extern OSErr OpenSelection (FSSpecPtr theDoc);pascal Boolean idleProc(EventRecord *eventIn, long *sleep, RgnHandle *mouseRgn);/* AdjustCursor routine :Description :Used to adjust Cursor*/void AdjustCursor ( Point mouseLoc, RgnHandle mouseRgn ){Cursor arrow ;WindowRef window ;// by default, set mouseRgn to the whole QuickDraw coordinate plane,// so that we never get mouse moved eventsSetRectRgn ( mouseRgn, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF ) ;#if ! TARGET_API_MAC_CARBON// give text services a chance to set the cursor shape// (this call is not needed for Carbon clients)if ( SetTSMCursor( mouseLoc ) ){return ;}#endif// if there is a window open, give WEAdjustCursor an opportunity to set the cursor// WEAdjustCursor intersects mouseRgn (if supplied) with a region within which// the cursor is to retain its shape// (if the cursor is outside the view region, this is subtracted from mouseRgn )if ( ( window = FrontWindow ( ) ) != nil ){if ( WEAdjustCursor ( mouseLoc, mouseRgn, GetWindowWE ( window ) ) ){return ;}}// set the cursor to the arrow cursorSetCursor( GetQDGlobalsArrow ( & arrow ) ) ;}/* DoMouseDown routine :Description :Used to dispatch the mouse down event*/void DoPathSelect ( WindowRef window );OSStatus SwitchToFinder ( );OSStatus FindProcess(OSType,OSType,ProcessSerialNumber *);OSStatus FindProcess(OSType inProcessType,OSType inProcessSignature,ProcessSerialNumber * outPSN){ProcessSerialNumber psn ;ProcessInfoRec info ;// start at beginning of process listpsn . lowLongOfPSN = kNoProcess ;psn . highLongOfPSN = kNoProcess ;// init process info recordBlockZero ( & info, sizeof ( info ) ) ;info . processInfoLength = sizeof ( info ) ;// walk the process list, looking for the given creatorwhile ( ( GetNextProcess ( & psn ) == noErr ) &&( GetProcessInformation ( & psn, & info ) == noErr ) ){if ( info . processSignature == inProcessSignature ){if ( ( inProcessType == typeWildCard ) || ( inProcessType == info . processType ) ){if ( outPSN ){* outPSN = psn ;}return noErr ;}}}return procNotFound ;}OSStatus SwitchToFinder ( ){ProcessSerialNumber finderPSN ;OSStatus err ;// get Finder PSNif ( ( err = FindProcess ( FOUR_CHAR_CODE ( 'FNDR' ), FOUR_CHAR_CODE ( 'MACS' ), & finderPSN ) ) != noErr ){goto cleanup ;}// make it the frontmost processerr = SetFrontProcess ( & finderPSN ) ;cleanup :// return result codereturn err ;}void DoPathSelect ( WindowRef window ){SInt32 menuChoice = 0 ;if ( ( WindowPathSelect ( window, nil, & menuChoice ) == noErr ) &&( ( menuChoice & 0x0000FFFF ) > 1 ) ){// bring the Finder to the foregroundSwitchToFinder ( ) ;}}void DoMouseDown ( const EventRecord * event ){//WindowRef we;WEReference we;WindowPtr window ;SInt16 partCode ;SInt32 selStart, selEnd;// find out where this click when down inpartCode = FindWindow ( event -> where, & window ) ;SelectWindow(window);// dispatch on partCodeswitch ( partCode ){case inMenuBar :PrepareMenus ( ) ;DoMenuChoice ( MenuSelect ( event -> where ), event -> modifiers , window) ;break;case inContent :DoContent ( event -> where, event, window );SelectWindow ( window ) ;we = GetWindowWE(window);if(window == Console_Window){WEGetSelection ( & selStart, & selEnd, we );if(selStart == selEnd)WESetSelection(WEGetTextLength(we), WEGetTextLength(we), we);}break;case inDrag :{if ( window != FrontWindow ( ) ){if ( ( event->modifiers & cmdKey ) == 0 ){SelectWindow ( window ) ;}}else if ( IsWindowPathSelectClick ( window, ( EventRecord * ) event ) ){DoPathSelect ( window ) ;break ;}DoDrag ( event -> where, window ) ;break;}case inGrow :{DoGrow ( event -> where, window ) ;break;}case inGoAway :{if (FrontWindow() == Console_Window)DoQuit( savingAsk );if ( TrackGoAway ( window, event -> where ) ){if(!finished)DoClose ( closingWindow /*kNavSaveChangesClosingDocument*/, savingYes, window ) ;elseDoClose ( closingWindow /*kNavSaveChangesClosingDocument*/, savingAsk, window ) ;}break ;}case inZoomIn :case inZoomOut :{if ( TrackBox ( window, event -> where, partCode ) ){DoZoom ( partCode, window ) ;}break ;}case inProxyIcon:{// in order to start a proxy icon drag, the window must be active// and the proxy icon must be enabledif ( window == FrontWindow ( ) ){if ( ! IsWindowModified ( window ) ){// if the mouse isn't held down on the proxy icon for a certain delay,// this gesture should be interpreted as an attempt to drag the windowif ( TrackWindowProxyDrag ( window, event->where ) != errUserWantsToDragWindow ){break ;}}}else{// clicking the proxy icon of an inactive window should select// the window unless the command key is held downif ( ( event->modifiers & cmdKey ) == 0 ){SelectWindow ( window ) ;}}DoDrag ( event->where, window ) ;break ;}#if !TARGET_API_MAC_CARBONcase inSysWindow :{SystemClick ( event, window ) ;break ;}#endif} // switch}/* DoKeyDown routine :Description :*/void DoKeyDown ( const EventRecord *event ){WEReference we ;SInt32 StartPos1, EndPos1, StartPos2, EndPos2;if (FrontWindow() == Console_Window){we = GetWindowWE ( Console_Window ) ;WEGetSelection ( &StartPos1, &EndPos1, we );DoGenKeyDown ( event, false);WEGetSelection(&StartPos2, &EndPos2, we);Change_Color_Range(StartPos1, StartPos2, gTypeColour.red,gTypeColour.green, gTypeColour.blue, we);WESetSelection ( StartPos2, EndPos2, we );}elseDoGenKeyDown ( event, false);}/* DoGenKeyDown routine :Description :It will be called by the DoKeyDown event, and sometime we need todirectly insert a "\r" event of the console window.*/void DoGenKeyDown ( const EventRecord *event, Boolean Console){SInt16 key;Boolean isCmdKey ;pascal Handle TextHdl=NULL;SInt32 textLength;WEReference we ;Ptr TextPtr;SInt32 selStart, selEnd ;Point where = {-1, -1};char cha;char testbuf[256];// extract character code from event messageif (Console){we = GetWindowWE ( Console_Window);}else{we = GetWindowWE ( FrontWindow());}key = ( event -> message & charCodeMask );// is this a command+key combo?isCmdKey = ( ( event -> modifiers & cmdKey ) != 0 );// map function keys to the equivalent command+key combos// note that all fuction keys generate the same code, i.e. 0x10if ( key == 0x10 ){isCmdKey = true ;switch ( ( event -> message & keyCodeMask ) >> 8 ){case keyF1:{// R_ShowFile("Macintosh HD:Desktop Folder:R copy 3:R:Projects:R help", "Happy");key = 'c';break ;}case keyF2:{RnWrite(testbuf, R_ChooseFile(true, testbuf, 256));// key = 0 ;//key = 'v';break ;}case keyF3:{RnWrite(testbuf ,R_ChooseFile(false, testbuf, 256));key = 0;break ;}case keyF4:{ErrorDia("No warning is the best");key = 0 ;break ;}default:{key = 0 ;break ;}} // switch} // if// command + printable character combos are routed to MenuKey( )// but be sure to pass command + arrow key combos to WEKey( )if ( isCmdKey && (key >= 0x20 ) ){PrepareMenus ( );DoMenuChoice ( MenuKey ( key ), event -> modifiers ,FrontWindow()) ;}else{if ((FrontWindow () == Console_Window) || (Console)){WEGetSelection ( & selStart, & selEnd, we );if ((selEnd < gChangeAble) && (key >=0x20))SysBeep(10);else{if(key == kDel){if (selEnd < gChangeAble)SysBeep(10);elseDoKey ( key, event ) ;}elseif(key == kBs){if (selEnd <= gChangeAble)SysBeep(10);elseDoKey ( key, event ) ;}else{if ((key == 0x1E) && ( gChangeAble <= selStart))do_Down_Array();else{if ((key == 0x1F) && ( gChangeAble <= selStart))do_Up_Array();else{if(key == kReturn) WESetSelection ( WEGetTextLength(we), WEGetTextLength(we), we );DoKey ( key, event ) ;}}if(key == kReturn){TextHdl = WEGetText(we);HLock(TextHdl);TextPtr = *TextHdl;TextPtr = TextPtr + gChangeAble;strncpy(gbuf, TextPtr,gbuflen);HUnlock(TextHdl);textLength = WEGetTextLength(we) - gChangeAble;if (gbuflen < textLength)gbuf = gbuf + gbuflen;elsegbuf = gbuf + textLength;*gbuf = '\0';gfinishedInput = !gfinishedInput;}}}}if ((isEditWindow(FrontWindow()) != 0) || (isHelpWindow(FrontWindow()) != 0)){DoKey ( key, event ) ;}}}/* DoDiskEvent routine :Description :Handle Disk event*/void DoDiskEvent ( const EventRecord * event ){#if !TARGET_API_MAC_CARBONPoint dialogCorner ;if ( ( event -> message >> 16 ) != noErr ){SetPt ( & dialogCorner, 112, 80 ) ;DIBadMount ( dialogCorner, event -> message ) ;}#else#pragma unused ( event )#endif}/* DoOSEvent routine :Description :Handle OS event*/void DoOSEvent ( const EventRecord * event ){SInt16 osMessage ;WindowPtr window ;// extract the OS message field from the event recordosMessage = ( event -> message & osEvtMessageMask ) >> 24 ;// dispatch on osMessageswitch ( osMessage ){case suspendResumeMessage:{if ( ( window = FrontWindow( ) ) != nil ){DoActivate( (event->message & resumeFlag) != 0, window );}break;}case mouseMovedMessage:{// nothingbreak;}}}/* DoHighLevelEvent routine :Description :Handle High Level event*/void DoHighLevelEvent( const EventRecord *event ){AEProcessAppleEvent( event );}void DoNullEvent( const EventRecord *event ){#pragma unused (event)WindowPtr window;if ( ( window = FrontWindow( ) ) != nil ){WEIdle( &sSleepTime, GetWindowWE(window) );}else{sSleepTime = LONG_MAX;}}/* DoWindowEvent routine :Description :Handle High Level window event*/void DoWindowEvent( const EventRecord *event ){WindowPtr window;// the message field of the event record contains the window referencewindow = (WindowPtr) event->message;// make sure this window is an application window; check the windowKind fieldif ( GetWindowKind( window ) != userKind )return;switch ( event->what ){case updateEvt:{DoUpdate( window );break;}case activateEvt:{DoActivate( ( event->modifiers & activeFlag) != 0, window );break;}}}/* ProcessEvent routine :Desciption :It is used in the Event loop, when you call Process Event, it willcapture the next event that available, and dispatch it to thecorresponding routine.*/void ProcessEvent( void ){EventRecord event;Boolean gotEvent, haveResize = false;WindowPtr windowPtr;DevDesc *dd;SInt16 Console_Width, NumofChar;GrafPtr savePort;RgnHandle cursorRgn;Rect portRect ;CGrafPtr thePort;gotEvent = WaitNextEvent( everyEvent, &event, sSleepTime, sMouseRgn );#if ! TARGET_API_MAC_CARBON// give text services a chance to intercept this event// if TSMEvent( ) handles the event, it will set event.what to nullEvent// this call is not needed for Carbon clientsTSMEvent ( & event ) ;#endifif (gExpose) {dd = (DevDesc*)gGReference[gExpose].devdesc;dd-> dp.resize(dd);playDisplayList(dd);haveResize = true;gExpose = false;}if (fstart) {GetPortBounds ( GetWindowPort(Console_Window), & portRect ) ;Console_Width = portRect.right - portRect.left ;GetPort(&savePort);#if TARGET_API_MAC_CARBONSetPortWindowPort(Console_Window);#elseSetPort(Console_Window);#endifTextFont(4);TextSize(gTextSize);NumofChar = (int)(((Console_Width - 15) / CharWidth('M')) -0.5) ;R_SetOptionWidth(NumofChar);SetPort(savePort);fstart = false;}// adjust cursor shape and set mouse region// (we assume event.where is the current mouse position in global coordinates// if event.what <= osEvt; high-level events store the event ID there)if ( event.what <= osEvt ) {AdjustCursor( event.where, sMouseRgn );}// dispatch on event.whatswitch( event.what ) {case nullEvent:DoNullEvent( &event );break;case mouseDown:DoMouseDown( &event);break;case keyDown:case autoKey:DoKeyDown( &event );break;case updateEvt:windowPtr = (WindowPtr) (&event)->message;if (isGraphicWindow(windowPtr)) {CGrafPtr thePort;thePort = GetWindowPort(windowPtr);/* flush the entire port */QDFlushPortBuffer(thePort, NULL);}if (!haveResize)DoWindowEvent(&event);break;case activateEvt:windowPtr = (WindowPtr) (&event)->message;if (isGraphicWindow(windowPtr)) {doActivate(&event);}DoWindowEvent(&event);break;case diskEvt:DoDiskEvent( &event );break;case osEvt:DoOSEvent( &event );break;case kHighLevelEvent:DoHighLevelEvent( &event );break;} // switchif (gotEvent) {sSleepTime = 0; // force early idle after non-idle event}}/* My IdleProc for AESend */pascal Boolean idleProc(EventRecord *eventIn, long *sleep, RgnHandle *mouseRgn){switch (eventIn->what) {case nullEvent:/* no nul processing in this sample */*sleep = 0;mouseRgn = nil;break;case updateEvt:case activateEvt://DrawMain((WindowPtr)eventIn->message); /* draw whatever window needs an update */break;case app4Evt:switch ((gERecord.message >> 24) & 0x0FF) { /* high byte of message */case suspendResumeMessage: /* suspend/resume is also an activate/deactivate */gInBackground = (gERecord.message & kResumeMask) == 0;break;}break;}return(false); /* I'll wait forever */}/* GotRequiredParams routine :*/OSErr GotRequiredParams( const AppleEvent *ae ){DescType actualType;Size actualSize;OSErr err;err = AEGetAttributePtr( ae, keyMissedKeywordAttr, typeWildCard, &actualType, nil, 0, &actualSize );return ( err == errAEDescNotFound ) ? noErr :( err == noErr ) ? errAEParamMissed : err;}extern OSErr SourceFile(FSSpec *myfss);extern char *mac_getenv(const char *name);/* HandleOpenDocument routine :Description :This Event will be generated when you click on a R file icon.This event can only be depatched by the ProcessEvent routine.Thus, even you click on the file icon of R to start R, this eventwill not be catch until the R_readConsole start.*/static pascal OSErr HandleOpenDocument( const AppleEvent *ae,AppleEvent *reply, SInt32 refCon ){#pragma unused ( reply, refCon )AEDescList docList;AEKeyword keyword;DescType actualType;Size actualSize;SInt32 numberOfDocuments, i;FSSpec fileSpec;OSErr err;FInfo fileInfo;SInt16 pathLen;Handle pathName=NULL;FILE *fp;SEXP img, lst;docList.descriptorType = typeNull;docList.dataHandle = nil;// extract direct parameter from the Apple eventif ( ( err = AEGetParamDesc( ae, keyDirectObject, typeAEList, &docList ) ) != noErr )goto cleanup;// perform the recommended check for additional required parametersif ( ( err = GotRequiredParams( ae ) ) != noErr )goto cleanup;i = 1;if ( ( err = AEGetNthPtr( &docList, i, typeFSS, &keyword, &actualType,&fileSpec, sizeof( fileSpec ), &actualSize ) ) != noErr )goto cleanup;err = FSpGetFInfo(&fileSpec, &fileInfo);if (err != noErr) goto cleanup;if (fileInfo.fdType == 'PICT'){error("No Picture Can be load in this version of R\n");}if (fileInfo.fdType == 'TEXT'){if( strncmp("TRUE",mac_getenv("OnOpenSource"),4) == 0)SourceFile(&fileSpec);else {DoNew( false);RemWinMenuItem();ReadTextFile ( &fileSpec, GetWindowWE ( Edit_Windows[Edit_Window-1] ) );UniqueWinTitle();}}elseif ((fileInfo.fdType == 'BINA')||(fileInfo.fdType == 'ROBJ')){FSpGetFullPath(&fileSpec, &pathLen, &pathName);HLock((Handle) pathName);strncpy(InitFile, *pathName, pathLen);InitFile[pathLen] = '\0';HUnlock((Handle) pathName);if(!(fp = fopen(InitFile, "rb"))) { /* binary file */RWrite("File cannot be opened !");/* warning here perhaps */return;}PROTECT(img = R_LoadFromFile(fp, 1));switch (TYPEOF(img)) {case LISTSXP:while (img != R_NilValue) {defineVar(TAG(img), CAR(img), R_GlobalEnv);img = CDR(img);}break;case VECSXP:for (i = 0; i < LENGTH(img); i++) {lst = VECTOR_ELT(img,i);while (lst != R_NilValue) {defineVar(TAG(lst), CAR(lst), R_GlobalEnv);lst = CDR(lst);}}break;}UNPROTECT(1);}cleanup:return err;}/* HandleQuitApplication routine :Description :This event will be execute when the applcation exit normally*/static pascal OSErr HandleQuitApplication( const AppleEvent *ae,AppleEvent *reply, SInt32 refCon ){#pragma unused (reply, refCon)AEKeyword optKey;DescType actualType;Size actualSize;SavingOption saving;OSErr err;// default saving option is savingAsk;saving = savingAsk;// extract optional save optionsif ( ( err = AEGetParamPtr( ae, keyAESaveOptions, typeEnumerated, &actualType, &optKey, sizeof( optKey ), &actualSize ) ) == noErr ){if ( optKey == kAEYes ){saving = savingYes;}else if (optKey == kAENo ){saving = savingNo;}else if ( optKey != kAEAsk ){err = paramErr; // for want of a better codegoto cleanup;}}// perform the recommended check for additional required parametersif ( ( err = GotRequiredParams( ae ) ) != noErr )goto cleanup;// actually do the quit stufferr = DoQuit( saving );cleanup:return err;}/* InitializeEvents: modified to let R interact with other processessuch as UnZip tools, Browsers, etc.AppleEvents handlers are now installed only ifthe System allow this (i.e. System v. > 7.0)Stefano M.Iacus, 2/2/2001*/OSErr InitializeEvents( void ){OSErr err;long aLong = 0;// allocate space for the mouse regionsMouseRgn = NewRgn( );if ( ( err = AEInstallEventHandler( kCoreEventClass, kAEOpenDocuments, NewAEEventHandlerUPP( HandleOpenDocument ), kDoOpen, false ) ) != noErr )goto cleanup;if ( ( err = AEInstallEventHandler( kCoreEventClass, kAEPrintDocuments, NewAEEventHandlerUPP( HandleOpenDocument ), kDoPrint, false ) ) != noErr )goto cleanup;if ( ( err = AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP( HandleQuitApplication ), 0, false ) ) != noErr )goto cleanup;// install Apple event handlers for a subset of the Core suiteif ( ( err = InstallCoreHandlers( ) ) != noErr )goto cleanup;// install Apple event handlers for inline inputif ( ( err = WEInstallTSMHandlers( ) ) != noErr )goto cleanup;gAEIdleUPP = NewAEIdleUPP(idleProc);cleanup:if(err == noErr)EventsInit = true;return err;}void R_startBrowser(char *fileName){FSSpec HelpFile;Str255 name;name[0] = strlen(fileName);strncpy((char *)(&name[1]), fileName, name[0]);FSMakeFSSpec(0,0,name,&HelpFile);OpenSelection(&HelpFile);}