ResKnife/Carbon/Classes/Application.cpp

1133 lines
32 KiB
C++
Raw Blame History

#include "Application.h"
#include "Asynchronous.h" // for initing, idling, and disposing
#include "Errors.h"
#include "Files.h" // for open & save etc.
#include "FileWindow.h" // no particuar reason
#include "ResourceObject.h"
#include "Utility.h"
// set up prefs and globals
globals g;
prefs p;
/*** MAIN ***/
int main( int argc, char* argv[] )
{
#pragma unused( argc, argv )
// get system version
OSStatus error = Gestalt( gestaltSystemVersion, &g.systemVersion ); // this loads HIToolbox.framework on OS X
if( error ) return error;
// initalise application
error = InitToolbox();
if( error ) return error;
error = InitMenubar();
if( error ) return error;
error = InitAppleEvents();
if( error ) return error;
error = InitCarbonEvents();
if( error ) return error;
error = InitGlobals();
if( error ) return error;
InitCursor();
// check system version is at least 7.1
if( g.systemVersion < kMacOS71 )
{
DisplayError( kStringOSNotGoodEnough, kExplanationOSNotGoodEnough );
QuitResKnife();
}
// check carbon version is at least 1.1
error = Gestalt( gestaltCarbonVersion, &g.carbonVersion );
if( g.carbonVersion < kCarbonLib11 || error )
{
DisplayError( kStringMinimumCarbonLib, kExplanationMinimumCarbonLib );
QuitResKnife();
}
else if( g.carbonVersion < kCarbonLib131 )
{
DisplayError( kStringRecommendedCarbonLib, kExplanationRecommendedCarbonLib );
}
#if __profile__
error = ProfilerInit( collectDetailed, bestTimeBase, 400, 40 );
if( error ) DebugStr( "\pProfiler initalisation failed" ); // profiler failed
#endif
#if TARGET_API_MAC_CARBON
// run event loop
RunApplicationEventLoop();
#else
EventRecord theEvent;
while( !g.quitting )
{
WaitNextEvent( everyEvent, &theEvent, 20, null );
if( IsDialogEvent( &theEvent ) )
ParseDialogEvents( null, &theEvent, null );
else ParseEvents( &theEvent );
}
QuitResKnife();
#endif
#if __profile__
ProfilerDump( "\pResKnife profile" );
ProfilerTerm();
#endif
return error;
}
/*** INIT TOOLBOX ***/
OSStatus InitToolbox( void )
{
#if !TARGET_API_MAC_CARBON
InitGraf( &qd.thePort );
InitFonts();
FlushEvents( everyEvent, 0 );
InitWindows();
InitMenus();
TEInit();
InitDialogs( 0L );
#endif
return noErr;
}
/*** INITALIZE MENUBAR ***/
OSStatus InitMenubar( void )
{
OSStatus error = noErr;
#if USE_NIBS
IBNibRef nibRef = null;
// create a nib reference (only searches the application bundle)
error = CreateNibReference( CFSTR("ResKnife"), &nibRef );
if( error != noErr )
{
DisplayError( "\pThe nib file reference could not be obtained." );
return error;
}
// get menu bar
error = SetMenuBarFromNib( nibRef, CFSTR("Menubar") );
if( error != noErr )
{
DisplayError( "\pMenus could not be obtained from nib file." );
return error;
}
// dispose of nib ref
DisposeNibReference( nibRef );
#else /* ! USE_NIBS */
Handle menuList = GetNewMBar( kClassicMenuBar );
SetMenuBar( menuList );
ReleaseResource( menuList );
// delete quit and prefs on OS X
long result;
error = Gestalt( gestaltMenuMgrAttr, &result );
if( !error && (result & gestaltMenuMgrAquaLayoutMask) )
{
MenuRef fileMenu = GetMenuRef( kFileMenu );
MenuRef editMenu = GetMenuRef( kEditMenu );
DeleteMenuItem( fileMenu, kFileMenuQuitItem );
DeleteMenuItem( fileMenu, kFileMenuQuitItem -1 );
DeleteMenuItem( editMenu, kEditMenuPreferencesItem );
DeleteMenuItem( editMenu, kEditMenuPreferencesItem -1 );
}
// set delete item character to the delete glyph
MenuRef editMenu = GetMenuRef( kEditMenu );
SetMenuItemKeyGlyph( editMenu, kEditMenuClearItem, kMenuDeleteLeftGlyph );
#if TARGET_API_MAC_CARBON
MenuRef windowMenu;
CreateStandardWindowMenu( 0, &windowMenu );
InsertMenu( windowMenu, kWindowMenu );
#else
AppendResMenu( GetMenuRef( kAppleMenu ), 'DRVR' );
#endif /* TARGET_CARBON */
DrawMenuBar();
#endif /* USE_NIBS */
return error;
}
/*** INIT APPLE EVENTS ***/
OSStatus InitAppleEvents( void )
{
AEEventHandlerUPP appleEventParser = NewAEEventHandlerUPP( ParseAppleEvents );
AEInstallEventHandler( kCoreEventClass, kAEOpenApplication, appleEventParser, 0, false );
AEInstallEventHandler( kCoreEventClass, kAEReopenApplication, appleEventParser, 0, false );
AEInstallEventHandler( kCoreEventClass, kAEOpenDocuments, appleEventParser, 0, false );
AEInstallEventHandler( kCoreEventClass, kAEPrintDocuments, appleEventParser, 0, false );
AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, appleEventParser, 0, false );
return noErr;
}
/*** INIT CARBON EVENTS ***/
OSStatus InitCarbonEvents( void )
{
#if TARGET_API_MAC_CARBON
EventHandlerUPP handler = null;
EventHandlerRef ref = null;
EventTypeSpec update = { kEventClassMenu, kEventMenuEnableItems };
EventTypeSpec process = { kEventClassCommand, kEventCommandProcess };
// install menu adjust handler
handler = NewEventHandlerUPP( CarbonEventUpdateMenus );
InstallApplicationEventHandler( handler, 1, &update, null, &ref );
// install menu selection handler
handler = NewEventHandlerUPP( CarbonEventParseMenuSelection );
InstallApplicationEventHandler( handler, 1, &process, null, &ref );
// install default idle timer <20> 200 millisecond interval - bug: this should be in a seperate thread and the cursor blink time
EventLoopTimerUPP timerUPP = NewEventLoopTimerUPP( DefaultIdleTimer );
OSStatus error = InstallEventLoopTimer( GetMainEventLoop(), kEventDurationNoWait, kEventDurationMillisecond * 200, timerUPP, null, &g.idleTimer );
return error;
#else
return noErr;
#endif
}
/*** INITALIZE GLOBALS ***/
OSStatus InitGlobals( void )
{
OSStatus error = noErr;
// general app globals
g.quitting = false;
g.cancelQuit = false;
g.frontApp = true;
g.appResFile = CurResFile();
g.asyncSound = !(Boolean) SHInitSoundHelper( &g.callSH, kSHDefChannels );
g.emergencyMemory = NewHandleClear( kEmergencyMemory );
// files
g.tempCount = 0;
// debugging
g.debug = false;
g.surpressErrors = false;
g.useAppleEvents = true;
g.useSheets = (g.carbonVersion >= kCarbonLib11)? true:false;
// prefs dialog
g.prefsDialog = null;
p.warnOnDelete = true;
// colours
SetColour( &g.white, 0xFFFF, 0xFFFF, 0xFFFF );
SetColour( &g.bgColour, 0xEEEE, 0xEEEE, 0xEEEE );
SetColour( &g.sortColour, 0xDDDD, 0xDDDD, 0xDDDD );
SetColour( &g.bevelColour, 0xAAAA, 0xAAAA, 0xAAAA );
SetColour( &g.textColour, 0x7777, 0x7777, 0x7777 );
SetColour( &g.frameColour, 0x5555, 0x5555, 0x5555 );
SetColour( &g.black, 0x0000, 0x0000, 0x0000 );
#if TARGET_API_MAC_CARBON
// window manager
g.windowMgrAvailable = true;
g.extendedWindowAttr = true;
// drag manager
g.dragAvailable = true;
g.translucentDrag = true;
// appearance manager
g.appearanceAvailable = true;
g.useAppearance = g.appearanceAvailable; // assume if user has Appearence, s/he wants to use it
if( g.useAppearance ) RegisterAppearanceClient(); // register such with the OS
// nav services
g.navAvailable = true;
g.useNavServices = g.navAvailable; // assume if user has NavServices, s/he wants to use them
if( g.navAvailable ) NavLoad(); // preload for efficiency - ignored on OS X (always loaded)
#else
// check for drag manager presence/attributes
SInt32 result = null;
error = Gestalt( gestaltDragMgrAttr, &result );
if( !error ) {
g.dragAvailable = (Boolean) (result & (1 << gestaltDragMgrPresent));
g.translucentDrag = (Boolean) (result & (1 << gestaltDragMgrHasImageSupport)); }
else {
g.dragAvailable = false;
g.translucentDrag = false; }
// check appearance availablilty
result = null;
error = Gestalt( gestaltAppearanceAttr, &result );
if( !error ) {
g.appearanceAvailable = (Boolean) (result & (1 << gestaltAppearanceExists));
g.useAppearance = g.appearanceAvailable; } // assume if user has Appearence, s/he wants to use it
else {
g.appearanceAvailable = false;
g.useAppearance = false; }
if( g.useAppearance ) RegisterAppearanceClient(); // register such with the OS
// check nav services availablilty
g.navAvailable = (Boolean) NavServicesAvailable();
g.useNavServices = g.navAvailable; // assume if user has NavServices, s/he wants to use them
if( g.navAvailable ) NavLoad(); // preload for efficiency
// check for MacOS 8.5's window manager (also in CarbonLib 1.0 - backported to 8.1)
result = null;
error = Gestalt( gestaltWindowMgrAttr, &result );
if( !error ) {
g.windowMgrAvailable = (Boolean) (result & (1 << gestaltWindowMgrPresentBit));
g.extendedWindowAttr = (Boolean) (result & (1 << gestaltExtendedWindowAttributes)); }
else {
g.windowMgrAvailable = false;
g.extendedWindowAttr = false; }
UpdateMenus( null );
#endif
return error;
}
#if !TARGET_API_MAC_CARBON
/*** PARSE EVENTS ***/
OSStatus ParseEvents( EventRecord *event )
{
OSStatus error = eventNotHandledErr;
switch( event->what )
{
case nullEvent:
IdleEvent();
break;
case mouseDown:
error = MouseDownEventOccoured( event );
break;
case mouseUp:
error = MouseUpEventOccoured( event );
break;
case keyDown:
error = KeyDownEventOccoured( event );
break;
case autoKey:
error = KeyRepeatEventOccoured( event );
break;
case keyUp:
error = KeyUpEventOccoured( event );
break;
case updateEvt:
error = UpdateEventOccoured( event );
break;
case activateEvt:
error = ActivateEventOccoured( event );
break;
case osEvt:
error = ParseOSEvents( event );
break;
case kHighLevelEvent:
error = AEProcessAppleEvent( event );
break;
}
return error;
}
/*** PARSE DIALOG EVENTS ***/
pascal Boolean ParseDialogEvents( DialogPtr dialog, EventRecord *event, DialogItemIndex *itemHit )
{
#pragma unused( dialog, event, itemHit )
/* OSStatus error = eventNotHandledErr;
if( dialog == null && itemHit == null );
*/ return false;
}
/*** PARSE OS EVENTS ***/
OSStatus ParseOSEvents( EventRecord *event )
{
#pragma unused( event )
OSStatus error = eventNotHandledErr;
SInt8 eventType = event->message >> 24; // high byte of message field
if( eventType & mouseMovedMessage )
{
// mouse moved event
}
else if( eventType & suspendResumeMessage ) // suspend/resume event
{
g.frontApp = ( event->message & resumeFlag ); // true on resume
if( FrontWindow() ) // only de/activate front window (if present)
{
WindowObjectPtr winObj = (WindowObjectPtr) GetWindowRefCon( FrontWindow() );
error = winObj->Activate( g.frontApp );
}
if( event->message & convertClipboardFlag )
{
// convert clipboard to private scrap
}
}
else error = paramErr;
return error;
}
#endif
/*** PARSE APPLE EVENTS ***/
pascal OSErr ParseAppleEvents( const AppleEvent *event, AppleEvent *reply, SInt32 refCon )
{
#pragma unused( reply, refCon )
OSErr error;
Size actualSize;
DescType actualType;
DescType eventClass, eventID;
error = AEGetAttributePtr( (AppleEvent *) event, keyEventClassAttr, typeType, &actualType, (Ptr) &eventClass, sizeof(eventClass), &actualSize );
if( error ) return errAEEventNotHandled;
error = AEGetAttributePtr( (AppleEvent *) event, keyEventIDAttr, typeType, &actualType, (Ptr) &eventID, sizeof(eventID), &actualSize );
if( error ) return errAEEventNotHandled;
switch( eventClass )
{
case kCoreEventClass:
switch( eventID )
{
case kAEOpenApplication: // sent when app opened directly (ie not file opened)
#if TARGET_API_MAC_CARBON
DisplayOpenDialog();
#else
if( g.useNavServices ) DisplayOpenDialog();
else DisplayStandardFileOpenDialog();
#endif
break;
case kAEReopenApplication: // sent when app is double-clicked on, but is already open
if( FrontWindow() == null )
{
AEDescList list = {};
#if TARGET_API_MAC_CARBON
AppleEventSendSelf( kCoreEventClass, kAEOpenApplication, list );
#else
if( g.useAppleEvents ) AppleEventSendSelf( kCoreEventClass, kAEOpenApplication, list );
else if( g.useNavServices ) DisplayOpenDialog();
else DisplayStandardFileOpenDialog();
#endif
}
break;
case kAEOpenDocuments: // sent when file is double-clicked on in finder,
AppleEventOpen( event ); // or open is chosen in the file menu and g.useAppleEvents is true
break;
case kAEPrintDocuments: // sent when document is dragged onto printer
AppleEventPrint( event );
break;
case kAEQuitApplication: // sent from many locations (eg after restart command)
QuitResKnife();
break;
}
break;
/* case kAECoreSuite: // i'm not even registering for these yet
switch( eventID )
{
case kAECut:
case kAECopy:
case kAEPaste:
case kAEDelete:
DisplayErrorDialog( "\pSorry, but cut, copy, paste and clear via Apple Events arn't yet supported." );
error = errAEEventNotHandled;
break;
}
break;
*/ }
return error;
}
/******************/
/* EVENT HANDLING */
/******************/
#if !TARGET_API_MAC_CARBON
/*** MOUSE DOWN EVENT OCCOURED ***/
OSStatus MouseDownEventOccoured( EventRecord *event )
{
// get the window
OSStatus error = eventNotHandledErr;
WindowRef window;
SInt16 windowPart = FindWindow( event->where, &window );
WindowObjectPtr winObj = (WindowObjectPtr) GetWindowRefCon( window );
// find out where the click occoured
if( !windowPart ) return error;
else switch( windowPart )
{
case inMenuBar:
error = UpdateMenus( FrontWindow() ); // error ignored at the moment
UInt32 menuChoice = MenuSelect( event->where );
UInt16 menu = HiWord( menuChoice );
UInt16 item = LoWord( menuChoice );
error = ParseMenuSelection( menu, item ); // error ignored at the moment
HiliteMenu( 0 );
break;
case inSysWindow:
SystemClick( event, window );
break;
case inContent:
SelectWindow( window );
winObj->Click( event->where, event->modifiers );
break;
case inDrag:
DragWindow( window, event->where, &qdb );
winObj->BoundsChanged( null );
break;
case inGrow:
Rect bounds; // minimum and maximum bounds of window
SetRect( &bounds, 128, 128, 1024, 1024 );
SInt32 result = GrowWindow( window, event->where, &bounds );
if( result )
{
SInt16 newWidth = LoWord( result );
SInt16 newHeight = HiWord( result );
SizeWindow( window, newWidth, newHeight, false );
winObj->BoundsChanged( null );
}
break;
case inGoAway:
if( TrackGoAway( window, event->where ) )
winObj->Close();
break;
case inZoomIn:
case inZoomOut:
if( TrackBox( window, event->where, windowPart ) )
{
ZoomWindow( window, windowPart, window == FrontWindow() ); // I think the last param *might* need to be "g.frontApp"
winObj->BoundsChanged( null );
}
break;
case inCollapseBox:
case inProxyIcon:
break;
}
return error;
}
/*** MOUSE UP EVENT OCCOURED ***/
OSStatus MouseUpEventOccoured( EventRecord *event )
{
#pragma unused( event )
OSStatus error = eventNotHandledErr;
return error;
}
/*** KEY DOWN EVENT OCCOURED ***/
OSStatus KeyDownEventOccoured( EventRecord *event )
{
OSStatus error = eventNotHandledErr;
char key = (char)( event->message & charCodeMask ); // get the key pressed
if( event->modifiers & cmdKey ) // was it a menu shortcut?
{
UpdateMenus( FrontWindow() );
UInt32 menuChoice = MenuKey( key );
UInt16 menu = HiWord( menuChoice );
UInt16 item = LoWord( menuChoice );
if( menu && item )
error = ParseMenuSelection( menu, item );
}
return error;
}
/*** KEY REPEAT EVENT OCCOURED ***/
OSStatus KeyRepeatEventOccoured( EventRecord *event )
{
OSStatus error = KeyDownEventOccoured( event );
return error;
}
/*** KEY UP EVENT OCCOURED ***/
OSStatus KeyUpEventOccoured( EventRecord *event )
{
#pragma unused( event )
OSStatus error = eventNotHandledErr;
return error;
}
/*** UPDATE EVENT OCCOURED ***/
OSStatus UpdateEventOccoured( EventRecord *event )
{
OSStatus error = eventNotHandledErr;
GrafPtr oldPort;
WindowRef window = (WindowRef) event->message;
// send update events to window
GetPort( &oldPort );
SetPortWindowPort( window );
BeginUpdate( window ); // this sets up the visRgn
{
RgnHandle updateRgn = NewRgn();
WindowObjectPtr winObj = (WindowObjectPtr) GetWindowRefCon( window );
GetPortVisibleRegion( GetWindowPort( window ), updateRgn );
if( winObj ) error = winObj->Update( updateRgn );
DisposeRgn( updateRgn );
}
EndUpdate( window );
SetPort( oldPort );
return error;
}
/*** ACTIVATE EVENT OCCOURED ***/
OSStatus ActivateEventOccoured( EventRecord *event )
{
OSStatus error = eventNotHandledErr;
WindowObjectPtr winObj = (WindowObjectPtr) GetWindowRefCon( (WindowRef) event->message );
if( winObj ) error = winObj->Activate( (Boolean) (event->modifiers & activeFlag) );
return error;
}
/*** IDLE EVENT ***/
OSStatus IdleEvent( void )
{
// call sound idle routine
if( g.asyncSound ) SHIdle();
// compact all memory
/* SInt32 total, contig;
PurgeMem( kEmergencyMemory );
CompactMem( kEmergencyMemory );
PurgeSpace( &total, &contig );
// deal with emergency memory
if( total < kMinimumFreeMemory && g.emergencyMemory )
{
DisposeHandle( g.emergencyMemory ); // release emergence memory
DisplayError( "\pMemory is running low, please close some windows." );
}
else if( !g.emergencyMemory && contig > kEmergencyMemory ) // try to recover handle if possible
g.emergencyMemory = NewHandleClear( kEmergencyMemory );
*/ return noErr;
}
#endif
/*** QUIT RES KNIFE ***/
void QuitResKnife( void )
{
// save all open files
WindowRef window = FrontNonFloatingWindow(), nextWindow;
while( window )
{
nextWindow = GetNextWindow( window );
SInt32 kind = GetWindowKind( window );
if( kind == kFileWindowKind )
{
#if TARGET_API_MAC_CARBON
EventRef event;
CreateEvent( null, kEventClassWindow, kEventWindowClose, kEventDurationNoWait, kEventAttributeNone, &event );
SendEventToWindow( event, window );
ReleaseEvent( event );
#else
// bug: this is totally the wrong thing to do here, but will have to do for now
DisposeWindow( window ); // bug: windows don't close when sent a WindowClose event!
#endif
}
window = nextWindow;
}
if( !g.cancelQuit )
{
if( g.asyncSound ) SHKillSoundHelper();
if( g.navAvailable ) NavUnload();
#if TARGET_API_MAC_CARBON
QuitApplicationEventLoop();
#else
g.quitting = true;
#endif
}
}
/*******************/
/* MENU SELECTIONS */
/*******************/
#if TARGET_API_MAC_CARBON
/*** CARBON EVENT UPDATE MENUS ***/
pascal OSStatus CarbonEventUpdateMenus( EventHandlerCallRef callRef, EventRef event, void *userData )
{
#pragma unused( callRef, event, userData )
OSStatus error = eventNotHandledErr;
Boolean fileOpen = (Boolean) FrontNonFloatingWindow();
// application menu (passing null causes all menus to be searched)
EnableCommand( null, kMenuCommandAbout, true );
EnableCommand( null, kHICommandPreferences, true );
// file menu
EnableCommand( null, kMenuCommandNewFile, true );
EnableCommand( null, kMenuCommandOpenFile, true );
EnableCommand( null, kMenuCommandCloseWindow, fileOpen );
EnableCommand( null, kMenuCommandCloseFile, fileOpen );
EnableCommand( null, kMenuCommandSaveFile, fileOpen ); // bug: shoud be disabled if file is unmodified
EnableCommand( null, kMenuCommandSaveFileAs, fileOpen );
EnableCommand( null, kMenuCommandRevertFile, fileOpen );
EnableCommand( null, kMenuCommandPageSetup, fileOpen );
EnableCommand( null, kMenuCommandPrint, fileOpen );
/* if( fileOpen )
{
// edit window
EnableCommand( null, kHICommandUndo, false );
EnableCommand( null, kHICommandRedo, false );
EnableCommand( null, kHICommandCut, false );
EnableCommand( null, kHICommandCopy, false );
EnableCommand( null, kHICommandPaste, false );
EnableCommand( null, kHICommandClear, false );
EnableCommand( null, kHICommandSelectAll, false );
EnableCommand( null, kMenuCommandFind, false );
EnableCommand( null, kMenuCommandFindAgain, false );
// resource menu
EnableCommand( null, kMenuCommandNewResource, false );
EnableCommand( null, kMenuCommandOpenHex, false );
EnableCommand( null, kMenuCommandOpenDefault, false );
EnableCommand( null, kMenuCommandOpenTemplate, false );
EnableCommand( null, kMenuCommandOpenSpecific, false );
EnableCommand( null, kMenuCommandRevertResource, false );
EnableCommand( null, kMenuCommandPlaySound, false );
}
*/
// debug menu
EnableCommand( null, kMenuCommandDebug, true );
EnableCommand( null, kMenuCommandAppleEvents, false );
EnableCommand( null, kMenuCommandAppearance, false );
EnableCommand( null, kMenuCommandNavServices, false );
EnableCommand( null, kMenuCommandSheets, g.carbonVersion >= kCarbonLib11 );
SetMenuCommandMark( null, kMenuCommandDebug, g.debug? kMenuCheckmarkGlyph : kMenuNullGlyph );
SetMenuCommandMark( null, kMenuCommandSurpressErrors, g.surpressErrors? kMenuCheckmarkGlyph : kMenuNullGlyph );
SetMenuCommandMark( null, kMenuCommandAppleEvents, g.useAppleEvents? kMenuCheckmarkGlyph : kMenuNullGlyph ); // these three should always be true in Carbon
SetMenuCommandMark( null, kMenuCommandAppearance, g.useAppearance? kMenuCheckmarkGlyph : kMenuNullGlyph );
SetMenuCommandMark( null, kMenuCommandNavServices, g.useNavServices? kMenuCheckmarkGlyph : kMenuNullGlyph );
SetMenuCommandMark( null, kMenuCommandSheets, g.useSheets? kMenuCheckmarkGlyph : kMenuNullGlyph );
return error;
}
/*** CARBON EVENT PARSE MENU SELECTION ***/
pascal OSStatus CarbonEventParseMenuSelection( EventHandlerCallRef callRef, EventRef event, void *userData )
{
#pragma unused( callRef, userData )
// get menu command
HICommand menuCommand;
OSStatus error = GetEventParameter( event, kEventParamDirectObject, typeHICommand, null, sizeof(HICommand), null, &menuCommand );
if( error ) return eventNotHandledErr;
switch( menuCommand.commandID )
{
// application menu
case kMenuCommandAbout:
ShowAboutBox();
break;
case kHICommandPreferences:
ShowPrefsWindow();
break;
// file menu
case kMenuCommandNewFile:
new FileWindow;
break;
case kMenuCommandOpenFile:
if( g.useSheets ) error = DisplayModelessGetFileDialog();
else error = DisplayOpenDialog();
break;
// debug menu
case kMenuCommandDebug:
g.debug = !g.debug;
break;
case kMenuCommandSurpressErrors:
g.surpressErrors = !g.surpressErrors;
break;
case kMenuCommandAppleEvents:
g.useAppleEvents = !g.useAppleEvents;
break;
case kMenuCommandAppearance:
g.useAppearance = !g.useAppearance;
break;
case kMenuCommandNavServices:
g.useNavServices = !g.useNavServices;
break;
case kMenuCommandSheets:
g.useSheets = !g.useSheets;
break;
default:
return eventNotHandledErr; // pass all other events
}
return error; // event handled here, so terminate.
}
/*** DEFAULT IDLE TIMER ***/
pascal void DefaultIdleTimer( EventLoopTimerRef timer, void *data )
{
#pragma unused( timer, data )
// idle controls (allow cursor blinking)
IdleControls( GetUserFocusWindow() ); // bug: apple should have the control install it's own timer
// call sound idle routine
if( g.asyncSound && g.callSH ) SHIdle();
}
#else
/*** UPDATE MENUS ***/
OSStatus UpdateMenus( WindowRef window )
{
#pragma unused( window )
OSStatus error = noErr;
// disable/checkmark items in the debug menu
MenuRef debugMenu = GetMenuRef( kDebugMenu );
MenuItemEnable( debugMenu, kDebugMenuAppearanceItem, g.appearanceAvailable );
MenuItemEnable( debugMenu, kDebugMenuNavServicesItem, g.navAvailable );
MenuItemEnable( debugMenu, kDebugMenuSheetsItem, false );
CheckMenuItem( debugMenu, kDebugMenuDebugItem, g.debug );
CheckMenuItem( debugMenu, kDebugMenuSurpressErrorsItem, g.surpressErrors );
CheckMenuItem( debugMenu, kDebugMenuAppleEventsItem, g.useAppleEvents );
CheckMenuItem( debugMenu, kDebugMenuAppearanceItem, g.useAppearance );
CheckMenuItem( debugMenu, kDebugMenuNavServicesItem, g.useNavServices );
return error;
}
/*** PARSE MENU SELECTION ***/
OSStatus ParseMenuSelection( UInt16 menu, UInt16 item )
{
// get the frontmost window, in all it's various forms
OSStatus error = eventNotHandledErr;
WindowRef window = FrontWindow();
WindowObjectPtr winObj = null;
FileWindowPtr file = null;
if( window )
{
winObj = (WindowObjectPtr) GetWindowRefCon( window );
if( GetWindowKind( window ) == kFileWindowKind )
file = (FileWindowPtr) winObj;
}
// do the menu function
if( menu && item )
{
switch( menu )
{
case kAppleMenu:
switch( item )
{
case kAppleMenuAboutItem:
ShowAboutBox();
break;
default: // something from "apple menu items" folder
Str255 itemName;
MenuHandle appleMenu = GetMenuHandle( kAppleMenu );
GetMenuItemText( appleMenu, item, itemName );
OpenDeskAcc( itemName );
break;
}
break;
case kFileMenu:
switch( item )
{
case kFileMenuNewFileItem:
new FileWindow;
break;
case kFileMenuOpenFileItem:
if( g.useNavServices ) DisplayOpenDialog();
else DisplayStandardFileOpenDialog();
break;
case kFileMenuCloseWindowItem:
if( winObj ) winObj->Close();
break;
case kFileMenuQuitItem:
AEDescList list = {};
error = AppleEventSendSelf( kCoreEventClass, kAEQuitApplication, list );
if( error ) QuitResKnife();
break;
}
break;
case kEditMenu:
/* switch( item )
{
case :
break;
}
*/ break;
case kResourceMenu:
switch( item )
{
case kResourceMenuNewResource:
if( file ) file->DisplayNewResourceDialog();
break;
}
break;
case kDebugMenu:
switch( item )
{
case kDebugMenuDebugItem:
g.debug = !g.debug;
break;
case kDebugMenuSurpressErrorsItem:
g.surpressErrors = !g.surpressErrors;
break;
case kDebugMenuAppleEventsItem:
g.useAppleEvents = !g.useAppleEvents;
break;
case kDebugMenuAppearanceItem:
g.useAppearance = !g.useAppearance;
break;
case kDebugMenuNavServicesItem:
g.useNavServices = !g.useNavServices;
break;
}
break;
}
error = UpdateMenus( FrontWindow() );
}
return error;
}
#endif
/****************/
/* APPLE EVENTS */
/****************/
/*** SEND MYSELF AN APPLE EVENT ***/
OSStatus AppleEventSendSelf( DescType eventClass, DescType eventID, AEDescList list )
{
OSStatus error;
AEAddressDesc myAddress; // all of these are really of type AEDesc
AppleEvent noReply;
AppleEvent event;
myAddress.descriptorType = typeNull;
myAddress.dataHandle = null;
noReply.descriptorType = typeNull;
noReply.dataHandle = null;
ProcessSerialNumber psn;
error = GetCurrentProcess( &psn );
if( error ) return error;
error = AECreateDesc( typeProcessSerialNumber, &psn, sizeof(ProcessSerialNumber), &myAddress );
if( error ) return error;
error = AECreateAppleEvent( eventClass, eventID, &myAddress, kAutoGenerateReturnID, kAnyTransactionID, &event );
if( error ) return error;
error = AEPutParamDesc( &event, keyDirectObject, &list );
if( error ) return error;
error = AESend( &event, &noReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, null, null );
return error;
}
/*** GOT REQUIRED PARAMS ***/
Boolean GotRequiredParams( const AppleEvent *event )
{
OSStatus error = noErr;
DescType actualType;
Size actualSize;
// check if we have retreived the required parameters
error = AEGetAttributePtr( event, keyMissedKeywordAttr, typeWildCard, &actualType, null, 0, &actualSize );
return error == errAEDescNotFound;
}
/*** OPEN ***/
OSStatus AppleEventOpen( const AppleEvent *event )
{
OSStatus error = noErr;
// get the list of objects to open
AEDescList list;
AEKeyword aeKeyword;
aeKeyword = keyDirectObject;
error = AEGetParamDesc( event, aeKeyword, typeAEList, &list );
if( !GotRequiredParams( event ) || error ) return errAEEventNotHandled;
// count how many we have
SInt32 itemCount;
error = AECountItems( &list, &itemCount );
if( error ) return errAEEventNotHandled;
// open each one
FSSpec fileSpec;
DescType actualType;
Size actualSize;
for( SInt32 n = 1; n <= itemCount; n++ )
{
error = AEGetNthPtr( &list, n, typeFSS, &aeKeyword, &actualType, (Ptr) &fileSpec, sizeof(FSSpec), &actualSize );
if( actualType == typeFSS && !error ) new FileWindow( &fileSpec );
}
AEDisposeDesc( &list );
return error;
}
/*** PRINT ***/
OSStatus AppleEventPrint( const AppleEvent *event )
{
#pragma unused( event )
return errAEEventNotHandled;
}
/************************/
/* NIB WINDOW MANAGMENT */
/************************/
/*** SHOW ABOUT BOX ***/
OSStatus ShowAboutBox( void )
{
#if TARGET_API_MAC_CARBON
#if USE_NIBS
// create a nib reference (only searches the application bundle)
IBNibRef nibRef = null;
OSStatus error = CreateNibReference( CFSTR("ResKnife"), &nibRef );
if( error != noErr || nibRef == null )
{
DisplayError( "\pThe nib file reference could not be obtained." );
return error;
}
// create window
WindowRef window;
error = CreateWindowFromNib( nibRef, CFSTR("About Box"), &window );
if( error != noErr || window == null )
{
DisplayError( "\pThe about box could not be obtained from the nib file." );
return error;
}
// dispose of nib ref
DisposeNibReference( nibRef );
// show window
ShowWindow( window );
#else
Rect creationBounds;
WindowRef window;
SetRect( &creationBounds, 0, 0, 300, 300 );
OffsetRect( &creationBounds, 50, 50 );
OSStatus error = CreateNewWindow( kDocumentWindowClass, kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute | kWindowInWindowMenuAttribute, &creationBounds, &window );
ControlRef picControl;
ControlButtonContentInfo content;
/* content.contentType = kControlContentPictHandle;
content.u.picture = GetPicture( 128 );
if( content.u.picture == null ) DebugStr("\ppicture == null");
*/ content.contentType = kControlContentPictRes;
content.u.resID = 128;
CreatePictureControl( window, &creationBounds, &content, true, &picControl );
// SetControlData( picControl, kControlPicturePart, kControlPictureHandleTag, sizeof(content.u.picture), content.u.picture );
#endif
#else
WindowRef window = null;
if( g.useAppearance && g.systemVersion >= kMacOSEight )
window = GetNewCWindow( kFileWindow8, null, kFirstWindowOfClass );
else
window = GetNewCWindow( kFileWindow7, null, kFirstWindowOfClass );
if( window == null ) return paramErr;
PicHandle picture = (PicHandle) GetPicture( 128 );
SetWindowPic( window, picture );
#endif
ShowWindow( window );
return noErr;
}
/*** SHOW PREFERENCES WINDOW ***/
OSStatus ShowPrefsWindow( void )
{
#if USE_NIBS
// create a nib reference (only searches the application bundle)
IBNibRef nibRef = null;
OSStatus error = CreateNibReference( CFSTR("ResKnife"), &nibRef );
if( error != noErr || nibRef == null )
{
DisplayError( "\pThe nib file reference could not be obtained." );
return error;
}
// create window
WindowRef window;
error = CreateWindowFromNib( nibRef, CFSTR("Preferences"), &window );
if( error != noErr || window == null )
{
DisplayError( "\pThe preferences window could not be obtained from the nib file." );
return error;
}
// dispose of nib ref
DisposeNibReference( nibRef );
// install tabs handler
ControlRef control;
ControlID id = { 'tabs', 1 };
GetControlByID( window, &id, &control );
EventTypeSpec event = { kEventClassControl, kEventControlHit };
InstallEventHandler( GetControlEventTarget(control), NewEventHandlerUPP( PrefsTabEventHandler ), 1, &event, &control, null );
// show window
ShowWindow( window );
#endif
return noErr;
}
/*** PREFS TAB EVENT HANDLER ***/
pascal OSStatus PrefsTabEventHandler( EventHandlerCallRef handlerRef, EventRef event, void* userData )
{
#pragma unused( handlerRef, event )
// get tabs control
OSStatus error = noErr;
ControlRef control = (ControlRef) userData;
SInt16 selectedTab = GetControlValue( control );
WindowRef window = GetControlOwner( control );
// select correct tab
ControlRef currentTab;
ControlID id = { 'pane', 1 };
GetControlByID( window, &id, &currentTab );
SetControlVisibility( currentTab, selectedTab == id.id, true );
id.id = 2;
GetControlByID( window, &id, &currentTab );
SetControlVisibility( currentTab, selectedTab == id.id, true );
return error;
}