Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
Snapshot.c
/* |
File: Snapshot.c |
Contains: This application demonstrates how to quickly and |
efficiently capture the main device's desktop into |
a window. The program basically reads the image |
stored in the the main device's pixmap then copies |
it to a custom pixmap. The custom pixmap is de- |
fined at the same depth of the main device and |
contains an identical copy of that device's color- |
table. This is done to provide the fastest |
performance possible when copying from an offscreen |
to onscreen pixmap. By making sure the pixel values |
map to the exact same colors in both colortables, |
copybits will do a direct transfer of bits without |
wasting time remapping the colors. Also the ctSeed |
field for each colortable should be the same. Finally, |
since the main device's bounding rect is different |
than that of the offscreen's, the copying performance |
for the device to the offscreen is slightly affected |
because of the scaling required. However, the copying |
performance for the offscreen to the window is the |
best possible since the bounding rects for each are |
identical. |
Written by: EL |
Copyright: Copyright © 1991-1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source code" after having made |
changes. If you're going to re-distribute the source, we require that you make |
it clear in the source that the code was descended from Apple sample source |
code, but that you've made changes. |
Change History (most recent first): |
08/2000 JM Major revisions made. In addition to being "carbonized" |
added: multiple windows, refreshing, saving, conditional |
menu bar for OS X and 9, Apple Event Quit support, |
updated about box....(bunch of extra things) |
11/6/1999 GGS Updated to work with modern (1999) Mac OS. |
Fixed a PixMap disposing bug. Updated casts |
and headers. |
7/14/1999 KG Updated for Metrowerks Codewarror Pro 2.1 |
*/ |
#include "Snapshot.h" |
// Different picture scaling constants |
const int FULL_SIZE = 1; |
const float HALF_SIZE = 1.41; // square root of 2, roughly |
const int QUARTER_SIZE = 2; |
/* Global Variable Definitions */ |
Rect gBounds; // System resolution, effectively |
Boolean gDone = false; // Application termination global |
Boolean gDoingTrick = false; // "Trick" flag |
float gScale = 2.0; // QUARTER_SIZE; // Scaling the window, relative to resolution (default of 1/2 width and height) |
Rect gMinWindowSize; // The minimum window size |
const unsigned char* fileName = "\pDesktop Pic"; // Generic filename |
const unsigned char* defaultName = "\pSnapshot"; // Default Save File Name |
unsigned long resizingDelay = 0; |
int main() |
{ |
initMac(); |
setUp(); |
doNewSnapshot(); |
adjustMenus(); |
doEventLoop(); |
destroyAllWindows(); |
} |
// Tests to see if we are running on Mac OS X. |
Boolean onOSX() |
{ |
long response; |
OSErr anErr = noErr; |
anErr = Gestalt(gestaltSystemVersion, &response); |
return response >= 0x01000 && (anErr == noErr); |
} |
void destroyAllWindows() |
{ |
WindowPtr theWindow = FrontWindow(); |
while(FrontWindow() != NULL) { |
disposeWindow(theWindow); |
theWindow = FrontWindow(); |
} |
} |
void initMac() |
{ |
// the only "init" calls needed in carbon |
InitCursor(); |
FlushEvents( 0, everyEvent ); |
} |
void setUp() |
{ |
Handle menuBar; |
OSErr anErr = noErr; |
long response; |
// Carbon Porting guidelines say provide alternate menu bar/menu scheme for OS X |
// This is just one way of doing a different menu for 9 and X, which is pretty static |
if (onOSX()) |
menuBar = GetNewMBar(MENU_BAR_IDX); //if we are running on X, need menu without a File->Quit |
else |
menuBar = GetNewMBar(MENU_BAR_ID); //default menu bar |
anErr = ResError(); |
if ( menuBar == nil || anErr != noErr ) |
ExitToShell(); |
SetMenuBar(menuBar); |
DisposeHandle(menuBar); |
DrawMenuBar(); |
// Install 'quit' event handler |
// This "handler" is called when a user selects Application->Quit on OS X. |
if ((Gestalt(gestaltAppleEventsAttr, &response) == noErr)) { |
anErr = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, |
NewAEEventHandlerUPP(AEQuitHandler), 0, false); |
if (anErr != noErr) |
ExitToShell(); |
} |
} |
void doNewSnapshot() |
{ |
WindowPtr newWindow = nil; |
PixMapHandle pixHandle = nil; |
// Snapshots consist of a window and a PixMap, could have chosen |
// to use only pictures instead, but the existing code dealt with |
// PixMaps, so I kept the existing "concept" |
pixHandle = createScreenPixMap(); |
newWindow = createWindow(); |
// Window's refCon is its handle to a PixMap |
SetWRefCon(newWindow, (long)pixHandle); |
drawImage( newWindow ); |
ShowWindow( newWindow ); |
} |
WindowPtr createWindow() |
{ |
Rect wBounds; |
BitMap bitMap; |
int top, left, width, height; |
WindowPtr newWindow; |
// Centering the window is a good thing.... |
GetQDGlobalsScreenBits(&bitMap); |
width = ((bitMap.bounds.right - bitMap.bounds.left) / gScale); |
height = ((bitMap.bounds.bottom - bitMap.bounds.top) / gScale); |
left = (((bitMap.bounds.right - bitMap.bounds.left) - width) / 2); |
top = (((bitMap.bounds.bottom - bitMap.bounds.top) - height) / 2); |
// if scale is same size or bigger than the screen |
if (gScale <= FULL_SIZE) |
top = left = GetMBarHeight() * 3; //arbitrary position.... |
// Create a window to display the final offscreen image. |
SetRect( &wBounds, left, top, left + width, top + height ); |
newWindow = NewCWindow( 0L, &wBounds, "\pSuper Snapshot!", false, kWindowFullZoomGrowDocumentProc, |
(WindowPtr)-1L, true, 0L ); |
// The refcon of the windows are going to be used to store the PixMapHandle |
// from a screen capture. 0 means no associated PixMapHandle while non-zero |
// means the value is a handle to a PixMap. A windows refcon should always be |
// a value in this program |
SetWRefCon(newWindow, 0L); |
return newWindow; |
} |
void disposeWindow(WindowPtr dieWindow) |
{ |
PixMapHandle pixHandle; |
if (dieWindow == NULL || !IsValidWindowPtr(dieWindow)) |
return; |
// Free up the baseAddr pointer field, the PixMap itself, |
// and the window |
pixHandle = (PixMapHandle)GetWRefCon(dieWindow); |
if (pixHandle != nil) { |
LockPixels(pixHandle); |
DisposePtr((*pixHandle)->baseAddr); |
DisposeCTable((*pixHandle)->pmTable); |
// set the color table to nil since this was a "custom" |
// pixmap, otherwise DisposePixMap will not deallocate the memory |
(*pixHandle)->pmTable = nil; |
UnlockPixels(pixHandle); |
DisposePixMap(pixHandle); |
} |
DisposeWindow(dieWindow); |
} |
void calculateSystemBounds() |
{ |
BitMap bitMap; |
// Get the resolution of the screen, save it in a global Rectangle and |
// use the info to calculate the min/max window size |
GetQDGlobalsScreenBits(&bitMap); |
SetRect( &gBounds, 0, 0, bitMap.bounds.right, bitMap.bounds.bottom); |
SetRect(&gMinWindowSize, bitMap.bounds.right / 4, bitMap.bounds.bottom / 4, bitMap.bounds.right, bitMap.bounds.bottom); |
} |
PixMapHandle createScreenPixMap() |
{ |
GDHandle mainDevice; |
CTabHandle cTable; |
short depth; |
Ptr offBaseAddr; /* Pointer to the off-screen pixel image */ |
short bytesPerRow; |
PixMapHandle pixHandle = nil; |
pixHandle = NewPixMap(); |
/* Get a handle to the main device. */ |
mainDevice = GetMainDevice(); |
/* Store its current pixel depth. */ |
depth = (**(**mainDevice).gdPMap).pixelSize; |
/* Make an identical copy of its pixmap's colortable. */ |
cTable = (**(**mainDevice).gdPMap).pmTable; |
(void) HandToHand( (Handle*)&cTable ); |
// Get Resolution of screen |
calculateSystemBounds(); |
// Fill in a few of the PixMap's fields... |
// NewPixMap() is good for default initialization, simply modify |
// the new PixMap |
(*pixHandle)->pmTable = cTable; |
(*pixHandle)->bounds = gBounds; |
(*pixHandle)->pixelSize = depth; |
bytesPerRow = ((gBounds.right - gBounds.left) * depth) / 8; |
offBaseAddr = NewPtr((unsigned long) bytesPerRow * (gBounds.bottom - gBounds.top)); |
(*pixHandle)->baseAddr = offBaseAddr; // Point to image |
(*pixHandle)->rowBytes = bytesPerRow | 0x8000; // MSB set for PixMap |
LockPixels(pixHandle); |
CopyBits( (BitMap *)*(**mainDevice).gdPMap, (BitMap *) *pixHandle, |
&(**(**mainDevice).gdPMap).bounds, &(*pixHandle)->bounds, srcCopy, 0l ); |
UnlockPixels(pixHandle); |
return pixHandle; |
} |
void drawImage(WindowPtr theWindow) |
{ |
Rect tempRect1; |
PixMapHandle pixHandle = (PixMapHandle) GetWRefCon(theWindow); |
GrafPtr oldPort; |
GetPort(&oldPort); |
SetPortWindowPort(theWindow); |
if (theWindow == NULL || !IsValidWindowPtr(theWindow)) |
return; |
if (pixHandle == NULL) |
return; |
else |
LockPixels(pixHandle); |
// Copy the offscreen image back onto the window. |
CopyBits( (BitMap *) *pixHandle, |
GetPortBitMapForCopyBits(GetWindowPort(theWindow)), |
&(*pixHandle)->bounds, |
GetPortBounds(GetWindowPort(theWindow),&tempRect1), |
srcCopy, 0L); |
UnlockPixels(pixHandle); |
SetPort(oldPort); |
} |
void saveToPICTFile(WindowPtr theWindow) |
{ |
PicHandle picHandle; |
OSErr anErr = noErr; |
NavReplyRecord reply; |
NavDialogOptions dialogOptions; |
FSSpec documentFSSpec; |
OSType fileTypeToSave = 'PICT'; |
OSType creatorType = 'ogle'; // PictureViewer |
AEKeyword theKeyword; |
DescType actualType; |
Size actualSize; |
Rect tempRect1; |
PixMapHandle pixHandle; |
// This is a very basic NavServices file-saving example |
// added logic for this program specifically |
if (theWindow == NULL || !IsValidWindowPtr(theWindow)) |
return; |
pixHandle = (PixMapHandle) GetWRefCon(theWindow); |
LockPixels(pixHandle); |
SetPortWindowPort(theWindow); |
GetPortBounds(GetWindowPort(theWindow), &tempRect1); |
picHandle = OpenPicture(&tempRect1); |
CopyBits((BitMap*) *pixHandle, GetPortBitMapForCopyBits(GetWindowPort(theWindow)), &(*pixHandle)->bounds, |
&tempRect1, srcCopy, 0L); |
ClosePicture(); |
anErr = NavGetDefaultDialogOptions(&dialogOptions); |
dialogOptions.dialogOptionFlags |= kNavSelectDefaultLocation; |
// Set default name for a saved snapshot |
PLstrcpy(dialogOptions.savedFileName, defaultName); |
anErr = NavPutFile( nil, |
&reply, |
&dialogOptions, |
nil, |
fileTypeToSave, |
creatorType, |
nil ); |
if (anErr == noErr && reply.validRecord) { |
anErr = AEGetNthPtr(&(reply.selection), 1, typeFSS, |
&theKeyword, &actualType, |
&documentFSSpec, sizeof(documentFSSpec), |
&actualSize ); |
if (anErr == noErr) { |
writePictToFile(&documentFSSpec, picHandle); |
} |
reply.translationNeeded = false; |
anErr = NavCompleteSave(&reply, kNavTranslateInPlace); |
NavDisposeReply(&reply); |
} |
KillPicture(picHandle); |
UnlockPixels(pixHandle); |
} |
void writePictToFile(FSSpec *fspec, PicHandle picHandle) |
{ |
OSErr anErr = noErr; |
long inOutCount; |
short refNum; |
OSType fileTypeToSave = 'PICT'; |
OSType creatorType = 'ogle'; // PictureViewer |
int count; |
unsigned char header[512]; |
// Pict files have to have 512 bytes of "zero" data at the front. |
for (count = 0; count < 512; count++) |
header[count] = 0x00; |
anErr = FSpCreate(fspec, creatorType, fileTypeToSave, smSystemScript); |
if (anErr == dupFNErr) { |
anErr = FSpDelete(fspec); //delete file if already exists |
anErr = FSpCreate(fspec, creatorType, fileTypeToSave, smSystemScript); |
} |
// write the file |
FSpOpenDF(fspec, fsRdWrPerm, &refNum ); |
inOutCount = 512; |
anErr = FSWrite(refNum, &inOutCount, header); // write the header |
if (anErr == noErr) { |
inOutCount = GetHandleSize((Handle)picHandle); |
anErr = FSWrite(refNum,&inOutCount,*picHandle); |
} |
FSClose( refNum ); |
} |
void doTrickEventLoop() |
{ |
EventRecord anEvent; |
WindowPtr evtWind = NULL; |
// Event loop while doing the "full screen" trick |
while (!gDone) { |
if (WaitNextEvent( everyEvent, &anEvent, 2, nil )) { |
if (anEvent.what == updateEvt) { |
evtWind = (WindowPtr)anEvent.message; |
SetPortWindowPort(evtWind); |
BeginUpdate(evtWind); |
drawImage(evtWind); |
EndUpdate(evtWind); |
} |
else if (anEvent.what == autoKey || anEvent.what == keyDown) |
handleKeyPress(&anEvent); |
else if (anEvent.what == kHighLevelEvent) |
AEProcessAppleEvent(&anEvent); |
} |
} |
gDone = false; |
} |
void doConfusion() |
{ |
GDHandle mainDevice; |
PicHandle picHandle; |
FSSpec fspec; |
PixMapHandle pixHandle; |
WindowPtr theWindow; |
float oldScale = gScale; |
OSErr anErr = noErr; |
AEDesc desc; |
Ptr oldState = NULL; |
WindowPtr bigWindow; |
RgnHandle rgnHandle = NewRgn(); |
Rect tempRect1; |
gScale = 1; |
mainDevice = GetMainDevice(); |
pixHandle = createScreenPixMap(); |
LockPixels(pixHandle); |
if (!onOSX()) { |
// used a window for debugging purposes |
theWindow = createWindow(); |
SetPortWindowPort(theWindow); |
SetWRefCon(theWindow, (long) pixHandle); |
picHandle = OpenPicture(&gBounds); |
drawImage(theWindow); |
ClosePicture(); |
//ShowWindow(theWindow); |
// write pict to file |
FSMakeFSSpec(0, 0, fileName, &fspec); |
writePictToFile(&fspec, picHandle); |
// set desktop pict :-) |
anErr = OHMakeAliasDescFromFSSpec(&fspec, &desc); |
if (anErr == noErr) { |
SetDesktopPict(&desc, 1); |
AEDisposeDesc(&desc); |
} |
KillPicture(picHandle); |
DisposeWindow(theWindow); |
gDone = true; |
} |
else { |
// since OS X does not use the Appearance manager for the desktop background |
// we will drop into full screen mode instead |
gDoingTrick = true; |
BeginFullScreen(&oldState, nil, 0, 0, &bigWindow, 0, fullScreenAllowEvents); |
SetWRefCon(bigWindow, (long)pixHandle); |
SetPortWindowPort(bigWindow); |
CopyBits( (BitMap *) *pixHandle, |
GetPortBitMapForCopyBits(GetWindowPort(bigWindow)), |
&(*pixHandle)->bounds, |
GetPortBounds(GetWindowPort(bigWindow),&tempRect1), |
srcCopy, 0L); |
QDFlushPortBuffer(GetWindowPort(bigWindow), GetPortVisibleRegion(GetWindowPort(bigWindow), rgnHandle)); |
doTrickEventLoop(); |
EndFullScreen(oldState, nil); |
gDoingTrick = false; |
} |
// clean up |
DisposePtr((*pixHandle)->baseAddr); |
DisposeCTable((*pixHandle)->pmTable); |
UnlockPixels(pixHandle); |
DisposePixMap(pixHandle); |
DisposeRgn(rgnHandle); |
gScale = oldScale; |
} |
void adjustMenus() |
{ |
// Function simply recalculates menus based on app state |
// Apps should do better menu handling, this is quick and dirty :-) |
MenuHandle menuHandle = GetMenuHandle(SIZE_MENU); |
int counter; |
for (counter = 1; counter <= NUMBER_OF_SIZES; counter++) |
CheckMenuItem(menuHandle, counter, false); |
if (gScale == QUARTER_SIZE) |
CheckMenuItem(menuHandle, SIZE_QUARTER_SCALE, true); |
else if (gScale == HALF_SIZE) |
CheckMenuItem(menuHandle, SIZE_HALF_SCALE, true); |
else if (gScale == FULL_SIZE) |
CheckMenuItem(menuHandle, SIZE_FULL_SCALE, true); |
menuHandle = GetMenuHandle(onOSX() ? FILE_MENUX : FILE_MENU); |
for (counter = 2; counter <= NUMBER_OF_FILE_MENU_ITEMS; counter++) |
FrontWindow() != NULL ? EnableMenuItem(menuHandle, counter) : DisableMenuItem(menuHandle, counter); |
} |
void resizeWindow(WindowPtr theWindow) |
{ |
PixMapHandle pixHandle; |
Rect originalLoc, newLoc; |
Boolean wasCollapsed; |
RgnHandle rgnHandle = NewRgn(); |
// Resize the window.... |
if (theWindow == NULL || !IsValidWindowPtr(theWindow)) |
return; |
wasCollapsed = IsWindowCollapsed(theWindow); |
if (wasCollapsed) { |
HideWindow(theWindow); |
CollapseWindow(theWindow, false); |
} |
pixHandle = (PixMapHandle)GetWRefCon(theWindow); |
GetWindowBounds(theWindow, kWindowContentRgn, &originalLoc); |
SetRect( &newLoc, |
originalLoc.left, originalLoc.top, |
gBounds.right / gScale + originalLoc.left, |
gBounds.bottom / gScale + originalLoc.top); |
SetWindowBounds(theWindow, kWindowContentRgn, &newLoc); |
drawImage(theWindow); |
QDFlushPortBuffer( GetWindowPort(theWindow), |
GetPortVisibleRegion(GetWindowPort(theWindow), rgnHandle)); |
if (wasCollapsed) { |
CollapseWindow(theWindow, wasCollapsed); |
ShowWindow(theWindow); |
} |
DisposeRgn(rgnHandle); |
} |
void handleMenuSelection(long result) |
{ |
int menuID, menuItem; |
RgnHandle rgnHandle = NewRgn(); |
DialogPtr theDialog = NULL; |
short itemHit; |
PixMapHandle pixHandle; |
menuID = HiWord(result); |
menuItem = LoWord(result); |
HiliteMenu(0); |
// File Menu |
if (menuID == FILE_MENU || menuID == FILE_MENUX) { |
if (menuItem == FILE_SAVE) |
saveToPICTFile(FrontWindow()); |
else if (menuItem == FILE_QUIT) |
gDone = true; |
else if (menuItem == FILE_CLOSE) { |
if (gDoingTrick) |
gDone = true; |
else if (FrontWindow() != NULL) |
disposeWindow(FrontWindow()); |
} |
else if (menuItem == FILE_NEW) { |
doNewSnapshot(); |
} |
else if (menuItem == FILE_REFRESH) { |
if (FrontWindow() == NULL) { |
HiliteMenu(0); |
return; |
} |
pixHandle = (PixMapHandle)GetWRefCon(FrontWindow()); |
DisposePtr((**pixHandle).baseAddr); |
DisposePixMap(pixHandle); |
pixHandle = createScreenPixMap(); |
SetWRefCon(FrontWindow(), (long)pixHandle); |
drawImage(FrontWindow()); |
QDFlushPortBuffer(GetWindowPort(FrontWindow()), GetPortVisibleRegion(GetWindowPort(FrontWindow()), rgnHandle)); |
} |
} |
else if (menuID == ABOUT_MENU) { //about menu handling |
if (menuItem == ABOUT) { |
theDialog = GetNewDialog ( ABOUTDLG, nil, (WindowPtr)-1 ); |
do { |
ModalDialog ( nil, &itemHit ); |
} while( itemHit != ok ) ; |
DisposeDialog ( theDialog ); |
} |
} |
else if (menuID == SIZE_MENU) { //size menu |
switch (menuItem) { |
case SIZE_QUARTER_SCALE: |
gScale = QUARTER_SIZE; |
break; |
case SIZE_HALF_SCALE: |
gScale = HALF_SIZE; |
break; |
case SIZE_FULL_SCALE: |
gScale = FULL_SIZE; |
break; |
} |
resizeWindow(FrontWindow()); |
} |
else if (menuID == SPECIAL_MENU || menuID == SPECIAL_MENUX) { // "special" because depends on OS 9 or X |
switch (menuItem) { |
case SPECIAL_CONFUSING: |
doConfusion(); |
break; |
} |
} |
adjustMenus(); |
DisposeRgn(rgnHandle); |
} |
void handleKeyPress(EventRecord *event) |
{ |
char key; |
key = event->message & charCodeMask; |
// just check to see if the command key is down, if so |
// process it as menu selection |
if ( event->modifiers & cmdKey ) |
handleMenuSelection(MenuKey(key)); |
} |
// Apple Event - "Quit" Handler |
pascal OSErr AEQuitHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn) |
{ |
#pragma unused (messagein,refIn,reply) |
// Do not call ExitToShell() in an AE Handler.... |
gDone = true; |
return noErr; |
} |
void doDynamicResizing(WindowPtr theWindow) |
{ |
Point currentLoc; |
Rect windowBounds; |
long time; |
int offsetX, offsetY; |
int windowWidth, windowHeight; |
RgnHandle rgnHandle = NewRgn(); |
EventRecord anEvent; |
// I could not find any code that would handle dynamic resizing using the "classic" |
// or traditional event model....so I wrote my own implementation |
GetWindowBounds(theWindow, kWindowStructureRgn, &windowBounds); |
GetMouse(¤tLoc); |
LocalToGlobal(¤tLoc); |
// calculate where mouse is in relation to edge of the window |
offsetX = windowBounds.right - currentLoc.h; |
offsetY = windowBounds.bottom - currentLoc.v; |
time = TickCount(); |
while (Button()) { |
GetMouse(¤tLoc); |
LocalToGlobal(¤tLoc); |
GetWindowBounds(theWindow, kWindowStructureRgn, &windowBounds); |
windowBounds.bottom = currentLoc.v + offsetX; |
windowBounds.right = currentLoc.h + offsetY; |
windowWidth = windowBounds.right - windowBounds.left; |
windowHeight = windowBounds.bottom - windowBounds.top; |
// Error check the window rectangle |
if (windowWidth < gMinWindowSize.left) |
windowBounds.right = windowBounds.left + gMinWindowSize.left; |
if (windowHeight < gMinWindowSize.top) |
windowBounds.bottom = windowBounds.top + gMinWindowSize.top; |
SetWindowBounds(theWindow, kWindowStructureRgn, &windowBounds); |
// Draws every "resizingDelay" miliseconds, can easily change the interval |
// I've set the interval to 0 for instantaneous drawing, but different apps may want to |
// change the delay (maybe the drawing is quite complex....) or change it during execution |
if (TickCount() - time >= resizingDelay) { |
drawImage(theWindow); |
QDFlushPortBuffer(GetWindowPort(theWindow), GetPortVisibleRegion(GetWindowPort(theWindow), rgnHandle)); |
time = TickCount(); |
} |
WaitNextEvent( everyEvent, &anEvent, 0, nil ); |
processEvent(&anEvent); |
// User may have decided to quit or close the window |
if (gDone || !IsValidWindowPtr(theWindow)) |
break; |
} |
DisposeRgn(rgnHandle); |
// Update the window when all is done |
PostEvent(updateEvt, (long)theWindow); |
} |
void processEvent(EventRecord *anEvent) |
{ |
WindowPtr evtWind; |
short clickArea; |
Rect screenRect; |
RgnHandle rgnHandle = NewRgn(); |
// Pretty standard event processing, save the couple checks for the |
// "trick" flag being set |
if (anEvent->what == mouseDown) |
{ |
clickArea = FindWindow( anEvent->where, &evtWind ); |
if (clickArea == inMenuBar) |
handleMenuSelection(MenuSelect(anEvent->where)); |
else if (clickArea == inDrag) |
{ |
GetRegionBounds(GetGrayRgn(), &screenRect); |
DragWindow( evtWind, anEvent->where, &screenRect ); |
} |
else if (clickArea == inContent) |
{ |
if (evtWind != FrontWindow()) |
SelectWindow( evtWind ); |
} |
else if (clickArea == inGoAway) { |
if (TrackGoAway( evtWind , anEvent->where )) { |
disposeWindow(evtWind); |
adjustMenus(); |
} |
} |
else if (clickArea == inGrow) { |
doDynamicResizing(evtWind); |
} |
else if (clickArea == inZoomIn || clickArea == inZoomOut) { |
if (TrackBox (evtWind, anEvent->where, clickArea == inZoomOut ? inZoomOut : inZoomIn)) { |
ZoomWindow (evtWind, clickArea == inZoomOut ? inZoomOut : inZoomIn, true); |
drawImage(evtWind); |
QDFlushPortBuffer(GetWindowPort(evtWind), GetPortVisibleRegion(GetWindowPort(evtWind), rgnHandle)); |
} |
} |
} |
else if (anEvent->what == updateEvt) |
{ |
evtWind = (WindowPtr)anEvent->message; |
SetPortWindowPort(evtWind); |
BeginUpdate(evtWind); |
drawImage(evtWind); |
EndUpdate(evtWind); |
} |
else if (anEvent->what == autoKey || anEvent->what == keyDown) |
handleKeyPress(anEvent); |
else if (anEvent->what == kHighLevelEvent) |
AEProcessAppleEvent(anEvent); |
DisposeRgn(rgnHandle); |
} |
void doEventLoop() |
{ |
EventRecord anEvent; |
while (!gDone) |
if (WaitNextEvent( everyEvent, &anEvent, 10, nil)) |
processEvent(&anEvent); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-10-10