ResKnife/Carbon/Classes/Application.cpp

1146 lines
31 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();
}
#if TARGET_API_MAC_CARBON
// 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);
}
#endif
#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);
}
#endif
#if __profile__
ProfilerDump("\pResKnife profile");
ProfilerTerm();
#endif
#if !TARGET_API_MAC_CARBON
QuitResKnife();
#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() != NULL);
// 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 retrieved 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);
if(error) return error;
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 >= kMacOS8)
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;
}