TweetFollow Us on Twitter

Sprocket
Volume Number:10
Issue Number:10
Column Tag:Foundation Technology
Related Topics: Window Manager Process Manager

Sprocket: A Small 7.5-Adept Framework

Introducing the MacTech Magazine tiny application framework!

By Dave Falkenburg, Apple Computer, Inc.

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

This month we bring you yet another framework. This one, though, offers a little less than you’re probably used to. That’s right, less. It’s just about as small a framework as you can have and still have some interesting features. This one, written by Apple’s Dave Falkenburg, has support for many of the more recent Apple system features, yet comes in well under 33K for a 68K executable.

We plan to use Sprocket as the basis for many of the articles in the coming months. This will allow us to focus on what’s being taught (the new code) rather than what you’ve seen before.

In addition, Dave plans to continue development of Sprocket, so we hope to see more articles detailing how he’s making things work, as well as covering new framework features.

We don’t have room in this issue to list all of the code, so we’re only listing what fits. The complete set of sources will be available on the source code disk and our online sites (see page 2 for info).

Let us hear what you think of this. Do you like the way Sprocket is implemented? Do you have a better way to do something? Is something unclear? Did you find a bug? Is there something you’d like to see added? Let us know; we’re aiming to serve your needs - Ed stb

1994 Isn’t 1984

With the advent of Apple’s System 7.5 release, many of the system extensions developed over the last few years will actually be delivered to the customer in a form they can understand: a single box.

AppleGuide, a faster disk cache, QuickTime 2.0, PC Exchange with Macintosh Easy Open, Macintosh Drag & Drop, and the Thread Manager are some of the enhancements which come along for free with 7.5. Unsuspecting customers also receive a copy of PowerTalk 1.1 and QuickDraw GX 1.01 which they can also install.

It’s probably about time to think about adding support for these new features in your own applications. To help you along, here’s Sprocket.

Sprocket sports a minimalist design, with just enough to crank out small applications which do their work inside windows. It has plenty of hooks to aid in supporting new Apple technologies, and in many cases has all the necessary support code. It isn’t a full-blown class library. In fact, it’s only use of C++ objects is to do a very standard Macintosh thing: managing windows.

No! No! No! The Journey is the Journey -
The Reward is the Reward.

People not interested in the folklore of how Sprocket came to be can skip ahead to the next section.

Sprocket is the outgrowth of one programmer trying to make sense of all the interesting new things that have been added to Macintosh OS in the past few years. It leverages heavily on the ideas presented in recent develop magazine articles by Dean Yu, Steve Falkenburg, and Dave Hershey, as well as insights provided by SmartFriends™ all over.

After a dissatisfying experience with C++ and bulky application frameworks, I decided that there was something wrong with creating superfluous objects for things that wouldn’t get reused - all it seemed to do was make code less readable to the average programmer, and make things tougher on the compiler.

Like many other folks, I had decided that my application skeleton couldn’t be written in C++. Most of my motivation was slow compile times, and the bloated code which came out of CFront at the time. Still wanting flexibility, a decided to use ad hoc “object-oriented C” for my application skeleton. This meant making big structs full of function pointers that get jammed into the refCon of windows, etc. Lots of explicit initialization, and lots of opportunity to type in bugs.

Thankfully, Symantec finally shipped a real C++ compiler and I decided to bite the bullet. C++ was going to be the language I would use.

As it turns out, I just happened to be overhauling my Macintosh skeleton application about the time Dean Yu was working on his first develop article about making floating windows without defiling the Window Manager. As a result, I took an early version of his floating window code and “methodized” it. Similarly, Dean’s ideas about smartzooming on comp.sys.mac.programmer were incorporated into my skeleton. After a while, I shelved the project, because I was off to Apple to lend a hand on the PowerMac System Software project.

Maybe it was seeing developers porting their applications to PowerPC, or maybe it was the need to write new code instead of hacking other peoples code, but around the end of the 7.1.2 project I began hacking on my application at home after work. At the time (and until very recently) Icalled it App. You’ll see references to it all through the code (and maybe even here and there in this article).

Around the same time, some folks around here were talking about some Canadian company with PowerPC development tools in their pocket. It turned out that the rumors were true, and that a little 12 person startup had decided to do what two Fortune 500 companies seemingly deemed “impossible”.

Metrowerks Code Warrior is an excellent, rapid turnaround environment for building both 68K and PowerPC applications for Macintosh - and it’s a hell of a lot cheaper than buying an RS/6000 and trying to weasel an unreleased C compiler from the local Big Blue rep. With new tools in hand, I started adding Mixed Mode Universal ProcPtrs everywhere I needed them, and got it to run on a friend’s 6100/60.

About the time I was getting ready to add support for PowerTalk mail and QuickDraw GX, Scott gave me a call and convinced me that this would be a cool thing to share with the rest of the world, especially as a framework for other articles to use as a default basis for what they're teaching.

Dealing with Macintosh Windows - A Few Techniques

Folks familiar with C++ Macintosh programming can skip ahead to the section about the design philosophy employed while writing Sprocket.

A very common technique used by Macintosh programmers is to use the refCon field of the WindowRecord to indicate which routines to call when handling activate, update, mouse clicks, and other events.

One popular technique is to use the windowKind field as an indicator of what routine to call for each possible thing you need to do for a window:


/* 1 */
void
MyHandleUpdateEvent(WindowPeek theWindowToUpdate)
 { 
 GetPort(&oldPort);
 SetPort(theWindowToUpdate);
 BeginUpdate(theWindowToUpdate);

 kindOfWindow = theWindowToUpdate->windowKind;
 switch (kindOfWindow)
 { 
 case kDocumentWindow:
 MyDrawingWindowDrawProc();
 break;

 case kDrawingToolsPaletteWindow:
 MyDrawingToolsDrawProc();
 break;

 //... even more explicit window types follow
 } 
 EndUpdate(aWindow);
 SetPort(oldPort);
 } 

One drawback is the need to maintain a ton of switch statements everywhere in your code. Another less obvious one is that a new type of window cannot be added to the application without recompiling the application. Wouldn’t it be nice to let plug-in modules put up their own “first class” windows?

To avoid the problems here, clever programmers have begun to use the refCon field of the WindowRecord to store a table of function pointers. Programs that use this technique include NewsWatcher and CollaboDraw. In this way, all the switch statements can be removed, potentially saving code throughout the file:


/* 2 */
void
MyHandleUpdateEvent(WindowPtr theWindowToUpdate)
 { 
 GrafPtroldPort;
 WindowProcs*procTable =(WindowProcs*)GetWindowRefCon(theWindow);

 GetPort(&oldPort);
 SetPort(theWindowToUpdate);
 BeginUpdate(theWindowToUpdate);
 if (procTable->UpdateProc != NULL)// call the proc if it
 (*(procTable->DrawProc)());// isn’t null.
 EndUpdate(aWindow);
 SetPort(oldPort);
 } 

This is flexible, but leads to the need to initialize and maintain these procTables manually, which means a lot of initialization routines like:


/* 3 */
WindowPtr
MakeMyWindow()
 { 
 WindowProcs *myProcTable = NewHandleClear(sizeof(WindowProcs));
 myProcTable->DrawProc = MyDrawingWindowDrawProc;
 // ... and many more things you need to type in.
 } 

Once you’ve seen the light, and switch over to using ProcPtrs like this, you’ve started down the road to object oriented programming in C - object weenies call this stuff “polymorphism”. Your event loop only needs to know how to deal with generic windows - no switch statements anywhere. Any new type of window with a different set of WindowProcs can be thought of as a subclass of the base window.

Why Do I Need To Type All This Stuff In?

I don’t know about you, but I hate typing. Cut and paste can help here, but it also seems like that’s where a lot of bugs get introduced in large programs. Just when you might say: “Gee I can write a tool to automatically generate the initialization code for the window proc tables”, you’ll notice that there is no need. A C++ compiler can do that for you.

It’s simple to create a C++ object whose pointer can be stored in a window’s refCon. Other than the “function pointer magic” that the compiler does for you, this method leads to very similar coding as used with the function pointer case:


/* 4 */
void  HandleUpdate(EventRecord * anEvent)
 { 
 GrafPtroldPort;
 WindowPtraWindow = (WindowPtr) anEvent->message;  
 TWindow *wobj;
 
 GetPort(&oldPort);
 SetPort(aWindow);
 BeginUpdate(aWindow);
 if ((wobj = GetWindowObject(aWindow)) != nil)
 wobj->Draw();
 EndUpdate(aWindow);
 SetPort(oldPort);
 } 

Besides the desire to dispatch events to windows in a fast and flexible manner, there are other things which “good” Macintosh programs should do. Smart zooming, and patchless floating windows are two of these things.

Both of these things involve overriding the normal behavior of Macintosh windows, and hence are natural for rolling into the the base window methods. If you look at the source, you can see that Dean Yu’s advice in develop 15 and 17 has been taken to heart. (It’s a good thing he wrote those articles before starting to forget about all this Macintosh OS stuff)

Philosophy

The basic approaches used in developing Sprocket were:

• Use C++ objects instead of initializing tables of function pointers. Let the tools do the work - I spent many days debugging stupid “cut and paste” errors in my older code. Now that stable C++ compilers exist for Macintosh, many “nuisance” reasons to avoid C++ are gone. In many environments C++ code compiles just in the same amount of time as C code. There are at least 5 compilers I’ve used in the last year - MPW C++, Symantec C++, Metrowerks, PPCC, and xlC under AIX on an RS/6000.

• Ignore System 6. If you have a friend with a Macintosh Classic, SE, LC, etc. get them to buy a PowerMac - they’ll like it. It isn’t that hard to add support back into Sprocket, but it probably isn’t worth the added hassles.

• Keep the RAM footprint small for the base functionality so that we don’t have to worry about heap fragmentation in the future or possible VM thrashing.

• Fold code snippets used by several subroutines into reusable chunks. Once again - reuse code where it makes sense to keep the code size down. This also tends to improve locality of reference for instruction cache accesses.

• Keep use of C++ objects down to only areas where there will typically be a lot of shared code or reuse. MacApp’s Nothing application used to be 300K! We don’t have a TApplication - there’s usually only ONE application anyway, why carry around base-class code you might not use just because C++ insists on creating references to it in the __vtbls?

• Sprocket is not a class library full of everything you ever had to do in CS101: If you want one of those, go buy it - it’ll have code written by genuine computer scientists that know more about algorithms than the average programmer. Lots of folks like the Booch class libraries.

• Use the Thread Manager in lieu of lots of IdleProcs. We still have Idle handlers for windows, but they really aren’t needed if the application can rely on using the Thread Manager.

A Quick Look At The Sources

The source directory is broken down into three folders:

:Interfaces: Definitions for Sprocket-supplied objects and

utility functions.

:Lib: Implementation of Sprocket’s core routines and objects.

:AppSpecific: Example code for building your own application using Sprocket.

As a rule of thumb, you shouldn’t need to change things inside :Interfaces: or :Lib:, while :AppSpecific: contains code designed for tweaking/replacement.

The code has been successfully built using Metrowerks CodeWarrior 4 and tested on a Macintosh IIsi. It is in the process of being run through even more compilers - I had some trouble using PPCC, so there could be something wrong with the code [we'll be grateful for any corrections you readers send in - Ed stb].

The coding conventions are based on MacApp and the unofficial C++ style guide published in an early develop article. I haven’t gone crazy with const parameters and the like, because like most of us, I’m still learning things about Bjarne’s creation. The indented braces are a habit of mine, since the Process Manager (and Finder) were typed this way.

Now on to the files themselves - first the core Sprocket sources:

:Interfaces:AppConditionals.h

Conditional compilation flags kept in a header. MPW and Unix folk tend to keep these things in Makefiles, but that really means that you have to use make. In this manner, we can potentially build Sprocket in both Unix/MPW and THINK/MW environments. If you do source code control, it’s also handy to keep conditionals in a source file.

:Interfaces:StandardMenus.h

Constants defining some standard MENU IDs. It would be nice to rip out menu IDs and item numbers from application code to abstract menu choices from the position in the menu bar. Just about every other framework does. We may do that eventually.

:Interfaces:AppLib.h

Function prototypes and declarations for all the utility functions and useful global variables provided in the less object oriented parts of Sprocket.

:Lib:AppLib.cp

main() lives in here. The heart of the Macintosh application. Routines include toolbox initialization, the main event loop, and cleanup routines. Points of interest include the use of dynamic run and sleep values inside the main event loop.

:Interfaces:AppleEventHandling.h
:Lib:AppleEventHandling.cp

Code for handling the required Apple event suite (kAEOpenApplication, kAEOpenDocuments, kAEPrintDocuments, and kAEQuitApplication). Support for opening AOCE letters is also supported. Once we add OSA scripting support, expect this file to grow by leaps and bounds.

:Interfaces:DialogUtils.h
:Lib:DialogUtils.cp

Useful utility functions for using modal dialogs and alerts in the System 7 world. Contains an auto-resized error alert mechanism and lots of FilterProcs needed to prevent update events from blocking background applications. For more information about why we do all these things see the Macintosh Technote: Pending Update Perils. Support for calling the Thread Manager YieldToAnyThread inside the filterProcs is also provided.

:Lib:Preferences.cp

Routines for dealing opening and/or creating a preferences file. [Am I the only one who thought that develop article on preferences files was a bit of overkill? - drf ]

:Interfaces:Window.h
:Lib:Window.cp

These are especially interesting, and are listed at the end of the article for your reading enjoyment.

Our favorite C++ object (so far). TWindow is the base class for defining a Macintosh window. Every window created directly by Sprocket is built using this object. When a Macintosh window is created, the pointer to a corresponding C++ object is stashed in the refCon.

I’ve taken care to make creating windows from application code as simple as:

TWhizbangWindow * myWindow = new TWhizbangWindow(<WhizzyParameters>);

Creating new kinds of windows is as easy as overriding the MakeNewWindow method, and providing unique drawing & event handling methods.

Right now, both floating and normal windows are supported. Modal windows (e.g., windows that come above floaters and cause them to be deactivated) are next on the list for implementation.

Weird C++ ALERT: This isn’t as easy as it looks because C++ has a habit of not letting you call virtual methods in an inherited class from within a constructor. From within the bottom-most derived window class, we call back to an inherited method, CreateWindow, to do common window creation, instead of creating the window from within TWindow::TWindow().

:Interfaces:DialogWindow.h
:Lib:DialogWindow.cp

A class called TDialogWindow which allows for the trivial creation of Dialog Manager-based windows. It’s kinda skanky right now because it temporarily patches FrontWindow in order to fool IsDialogEvent and DialogSelect into working with Dean’s floater technique.

:Interfaces:SplashWindow.h
:Lib:SplashWindow.cp

Object-based implementation of the splash screen. Mostly gratuitous, but a fun example of subclassing TWindow.

Application Specific Stuff

:AppSpecific:App.cp

Recipe code for the application-specific things. It implements the following required functions, as well as an about box dialog:

OSErr   SetupApplication(void);
OSErr   TearDownApplication(void);
void    HandleMenu(TWindow * topWindowObj,long menuCode);
void    ConvertClipboard(void);
OSErr   OpenNewDocument(void);
OSErr   OpenDocument(LetterDescriptor *,void *);
OSErr   PrintDocument(LetterDescriptor *,void *);
Boolean QuitApplication(void);

:AppSpecific:DocWindow.cp
:AppSpecific:DocWindow.h

A window which spins arrows using threads and draws a grow box.

:AppSpecific:PreferencesDialogWindow.cp
:AppSpecific:PreferencesDialogWindow.h

A totally bogus example showing how to override TDialogWindow. Preferences dialogs that look like this are less than nice to the novice user. Cool applications derive default preferences from the user’s use of the application, not from clever imitations of the System 6 Control Panel.

:AppSpecific:ToolWindow.cp
:AppSpecific:ToolWindow.h

An empty floating tool palette. Eventually it’d be nice to define tool palette template resources, but for now we use the parameter as a WIND resource id.

Nothing against my brother or anything, but I just can’t read the code in CollaboDraw without getting hives. Here’s my first attempt at building some C++ window classes for dealing with AOCE:

:Unfinished AOCE Stuff:MailableWindow.h
:Unfinished AOCE Stuff:MailableWindow.cp

A base class for an AOCE mailable window. Intended to be placed within :Lib: once all the mailer commands and Undo support have been added to Sprocket.

:Unfinished AOCE Stuff:MailableDocWindow.cp
:Unfinished AOCE Stuff:MailableDocWindow.h

A simple subclass of TMailableWindow intended to be added to :AppSpecific: when it is more complete.

Have fun reading through the code. There should be a couple of even less obvious tips and tricks in there that I’ve since forgotten about that might be useful. Like I said, Sprocket has picked up a lot of ideas from other sample code through the years.

Speaking of other code, remember that Sprocket is not the be-all, end-all Macintosh framework. It’s really a minimalist shell that makes it easy to demonstrate cool things in the magazine or building little hacks.

Other Frameworks

There are a ton of other Macintosh specific and/or cross platform frameworks that can be of great help. We’ll be focusing on Sprocket for articles here in the magazine, but these other frameworks have a lot to offer for full-fledged applications. A number of them are advertised right here in the magazine. Here are a few more (in no particular order):

MacApp - The first framework for building applications supplied by Apple. It had it’s beginnings as Object Pascal framework, but has been converted C++ over the last few years, and can now be used to build Power Macintosh applications. MacApp 3.x started integrating System 7 functionality and began to embrace C++.

TCL - A THINK C Objects based framework. Since Symantec didn’t have “real C++” until a few years ago, the most popular compiler used by Mac developers was essentially locked out of MacApp. TCL is still a popular framework, and the 2.0 version has been ported to the PowerPC.

AppsToGo - Eric Soldan of Apple DTS has a C-based application framework. This framework is heavily built upon being able to dynamically instantiate user interface elements from templates. Because it sprang forth out of the DTS.Lib effort in the early 90’s, lots of utility functions for doing “useful things” in MacOS are also included. Some things built using AppsToGo include ClickBook and Kibitz, as well as a bunch of other commercial applications. You can find it at ftp://ftp.apple.com/dts/mac/sc/apps.to.go

QuickApp - Another MacApp-flavored application framework. This is probably a lot like Sprocket, but is probably better tested, and leverages off more experiences. Apps can be as small as 50K. $149, e-mail emergent@aol.com.

MetroWerks PowerPlant - A C++ class library for building Macintosh Applications. There is a lot of very cool stuff inside PowerPlant, including support for floating windows, resource-based user interfaces, robust exception handling, AppleEvent Object model support, and lots of very useful classes for using the Thread Manager. Uses multiple inheritance to get more code reuse. Also has it’s own coding conventions similar to the MacApp-style, but also containing hints for whether or not the object “pulls in lots of other stuff”, or it's a lightweight, reusable “L”ibrary class. Greg Dow, the original author of TCL, is the principal force behind PowerPlant.

Visual C++, MFC - Microsoft’s cross platform development strategy - don’t write Mac software, just write Windows code. Probably a good choice for people porting vertical market applications from Windows to Mac on a very tight schedule.

OpenDoc - A whole new way of building applications. Stop thinking about applications - parts is parts. The idea here is that you essentially write a C++ object that can be embedded inside any document. It is important to note that OpenDoc isn’t really a framework in the sense of providing default “do the right thing” methods for parts. Instead it provides the class hierarchy alone. A cross-platform parts framework (OPF, the OpenDoc Parts Framework, descended from BedRock) is also under development.

OLE - Microsoft’s component software strategy. Instead of eliminating the application altogether, this is kind of a super-plug in that lets Microsoft use your code within their Office Suite, and other OLE-enabled applications.

Taligent - Some really cool C++ stuff, but few details have yet been disclosed in a public forum.

What to expect in the future:

• Making Sprocket more robust with a clean, ARM-inspired exception model.

• More support for AppleScript, and hence more studly AppleGuide abilities.

• Adding QuickDraw GX-aware Printing, and possibly GX window classes.

• Changes to transparently adapt to new stuff coming from Apple.

• And, of course, cool demos and new articles based on Sprocket.

And now to a few selected listings. We’ll show Window.h, Window.cp, and AppLib.h. They’re especially interesting, and they filled up all of our available space for this month. To see the rest of the files, check out this month’s source disk or the online sites (see p. 2 for details).

Window.h

/*  Contains:  Definition of TWindow, a base class which provides a framework 
for building way-cool windows which even John Sullivan would be happy 
with. Floating windows and “smart zooming” algorithms are based on code 
samples provided by Dean Yu.  Written by: Dave Falkenburg, Dean Yu
Copyright:© 1993-94 by Dave Falkenburg, all rights reserved. */

/* 5 */
#ifndef _WINDOW_
#define _WINDOW_

#ifndef __TYPES__
#include<Types.h>
#endif
#ifndef __WINDOWS__
#include<Windows.h>
#endif
#ifndef __EVENTS__
#include<Events.h>
#endif
#ifndef __DRAG__
#include<Drag.h>
#endif

typedef short  WindowTemplateID;

class TWindow
 {
public:
 enum WindowType
 {
 kNormalWindow = 0,
 kFloatingWindow,
 kModalWindow
 };
 TWindow();
 virtual~TWindow();

 //Event routing methods
 virtualBoolean  EventFilter(EventRecord * theEvent);
 
 Methods you shouldn’t need to override, but might need to

 virtual void    CreateWindow(WindowType typeOfWindowToCreate 
 = kNormalWindow);
 virtualvoidSelect(void);
 virtualvoidDrag(Point startPoint);
 virtual void    Nudge( short horizontalDistance, 
 short verticalDistance);
 virtual void    Grow(Point startPoint);
 virtual void    Zoom(short zoomState);
 virtualvoidShowHide(Boolean showFlag);

 Methods which MUST be overridden:

 virtual WindowPtr MakeNewWindow(WindowPtr behindWindow) = 0;

 Methods which probably should be overridden

 virtualvoidAdjustCursor(EventRecord * anEvent);
 virtual void    Idle(EventRecord * anEvent);
 virtual void    Activate(Boolean activating);
 virtual void    Draw(void);
 virtual void    Click(EventRecord * anEvent);
 virtualvoidKeyDown(EventRecord * anEvent);
 virtual void    GetPerfectWindowSize(Rect * perfectSize);
 virtualvoidGetWindowSizeLimits(Rect * limits);
 virtual void    AdjustForNewWindowSize(     Rect * oldRect,
 Rect * newRect);
 //Window property accessor methods 
 // watch for new ones when we add scripting support     
 
 virtualBoolean  IsVisible(void);
 virtualBoolean  CanClose(void);   
 virtualBoolean  Close(void);
 virtualBoolean  DeleteAfterClose(void);
 virtualvoidDoEditMenu(short item);

 //Methods for use with the Drag Manager
 
 virtualOSErr  HandleDrag(DragTrackingMessage dragMessage, 
 DragReference theDrag);
 virtualOSErr    DragEnterWindow(DragReference theDrag);
 virtualOSErr    DragInWindow(DragReference theDrag);
 virtualOSErr    DragLeaveWindow(DragReference theDrag);
 virtualOSErr    HandleDrop(DragReference theDragRef);

protected:
 WindowPtrfWindow;
 WindowType fWindowType;

 BooleanfIsVisible;
 };

Utility Functions:
// Don’t you just wish you didn’t have to do this?
pascal WindowPtr GetNewColorOrBlackAndWhiteWindow(
 short windowID, void *wStorage, WindowPtr behind);
pascal WindowPtr NewColorOrBlackAndWhiteWindow(
 void *wStorage, const Rect *boundsRect,
 ConstStr255Param title, Boolean visible, 
 short theProc, WindowPtr behind, 
 Boolean goAwayFlag, long refCon);

TWindow * GetWindowObject(WindowPtr aWindow);
WindowPtr FrontModalWindow(void);
WindowPtr LastModalWindow(void);
WindowPtr FrontFloatingWindow(void);
WindowPtr LastFloatingWindow(void);
WindowPtr FrontNonFloatingWindow(void);
void    HiliteAndActivateWindow( WindowPtr aWindow,
 Boolean active);
void    SuspendResumeWindows(Boolean resuming);
void    HiliteWindowsForModalDialog(Boolean hiliting);

pascal OSErrCallWindowDragTrackingHandler( 
 DragTrackingMessage message,
 WindowPtr theWindow,
 void *handlerRefCon,
 DragReference theDragRef);
pascal OSErrCallWindowDragReceiveHandler(
 WindowPtr theWindow, 
 void *handlerRefCon,
 DragReference theDragRef);
#endif

Window.cp


/* 6 */
/* Contains:Implementation of TWindow, a base class which provides a 
framework for building way-cool windows which even John Sullivan would 
be happy with. Floating windows and “smart zooming” algorithms are based 
on code samples provided by Dean Yu. Tim Craycroft, the guy making the 
window manager do all this work for you has also been a great help.
 
Written by: Dave Falkenburg
Copyright:© 1993-94 by Dave Falkenburg, all rights reserved.

To Do:  Make sure invisible windows can be created & managed
 Handle modal windows as another class of windows
 Fix activate bugs when showing and hiding windows
 Window positioning methods (getters and setters)
 Display Manager support
 Changes to support AEObject model
 */

#include <Types.h>
#include <Windows.h>
#include <Errors.h>
#include <Script.h>//for GetMBarHeight()
#include <LowMem.h>//for LMGetWindowList()

#include "AppLib.h"
#include "Window.h"

const short kFloatingWindowKind    = 1000;
const short kNormalWindowKind = 1001;
const WindowPtr  kNoFloatingWindows= (WindowPtr) -1;
const short kScreenEdgeSlop = 4;
const short kSpaceForFinderIcons = 64;
const short kMinimumTitleBarHeight = 21;
const short kMinimumWindowSize= 32;

static void HiliteShowHideFloatingWindows(
 Boolean hiliting,Boolean hiding);

static void FindScreenRectWithLargestPartOfWindow(
 WindowPtr aWindow, Rect *theBestScreenRect, 
 GDHandle * theBestDevice);
static pascal void CalculateWindowAreaOnDevice(
 short depth, short deviceFlags, GDHandle targetDevice,        
 long userData);

struct  CalcWindowAreaDeviceLoopUserData
 {
 GDHandle fScreenWithLargestPartOfWindow;
 long   fLargestArea;
 Rect   fWindowBounds;
 };

TWindow::TWindow()
 {
 }
TWindow::~TWindow()
 {
 }
TWindow::CreateWindow

void TWindow::CreateWindow( WindowType typeOfWindowToCreate 
/* = kNormalWindow */)
 {
 WindowPtrbehindWindow,oldFrontMostWindow;
 
 if (typeOfWindowToCreate == kModalWindow)
 {
 DebugStr("\pModal windows aren’t supported yet");
 fWindowType = kFloatingWindow;
 return;
 }
 else if (typeOfWindowToCreate == kFloatingWindow)
 {
 behindWindow = (WindowPtr) -1;
 oldFrontMostWindow = FrontWindow();

 fWindowType = kFloatingWindow;
 }
 else if (typeOfWindowToCreate == kNormalWindow)
 {
 behindWindow = LastFloatingWindow();

 fWindowType = kNormalWindow;
 
 if (behindWindow == kNoFloatingWindows)
 oldFrontMostWindow = nil;
 else
 oldFrontMostWindow = (WindowPtr) 
 ((WindowPeek) behindWindow)->nextWindow;
 }

 fWindow = this->MakeNewWindow(behindWindow);
 fIsVisible = ((WindowPeek) fWindow)->visible;

 if (fWindow)
 {
 SetWRefCon(fWindow,(long) this);

 if (typeOfWindowToCreate == kModalWindow)
 {
 DebugStr("\pCan’t create Modal windows yet");
 }
 else if (typeOfWindowToCreate == kFloatingWindow)
 {
 ((WindowPeek) fWindow)->windowKind = kFloatingWindowKind;
 
 //make sure the other window stays hilited
 if (oldFrontMostWindow)
 HiliteAndActivateWindow(oldFrontMostWindow,true);
 }
 else if (typeOfWindowToCreate == kNormalWindow)
 {
 ((WindowPeek) fWindow)->windowKind = kNormalWindowKind;

 //unhighlight the old front window
 if (oldFrontMostWindow)
 HiliteAndActivateWindow(oldFrontMostWindow,false);

 //hilite the new window 
 HiliteAndActivateWindow(fWindow,true);
 }
 }
 }
TWindow::AdjustCursor
void
TWindow::AdjustCursor(EventRecord * /* anEvent */)
 {
 }
TWindow::Idle
void
TWindow::Idle(EventRecord * /* anEvent */)
 {
 }
TWindow::Activate
void
TWindow::Activate(Boolean /* activating */)
 {
 }
TWindow::Draw
void
TWindow::Draw(void)
 {
 }
TWindow::Click
void
TWindow::Click(EventRecord * /* anEvent */)
 {
 }
 TWindow::KeyDown
void
TWindow::KeyDown(EventRecord * /* anEvent */)
 {
 }
TWindow::Select
void
TWindow::Select(void)
 {
 WindowPtrcurrentFrontWindow;
 
 if (fWindowType == kFloatingWindow)
 currentFrontWindow = FrontWindow();
 else if (fWindowType == kNormalWindow)
 currentFrontWindow = FrontNonFloatingWindow();
 else
 {
 }

 if (currentFrontWindow != fWindow)
 {
 if (fWindowType == kFloatingWindow)
 BringToFront(fWindow);
 else
 {
 WindowPtrlastFloater = LastFloatingWindow();

 //If there are no floating windows, just call SelectWindow like the 
good ol’ days
 if (lastFloater == kNoFloatingWindows)
 SelectWindow(fWindow);
 else
 {
 // Deactivate the window currently in front.
 HiliteAndActivateWindow(currentFrontWindow,false);
 
// Bring it behind the last floating window and activate it.  Note that 
Inside Mac 1
// states that you need to call PaintOne() and CalcVis() on a window 
if you are using 
// SendBehind() to bring it closer to the front.  With Sys 7, this is 
no longer necessary.
 SendBehind(fWindow,lastFloater);
 HiliteAndActivateWindow(fWindow,true);
 }
 }
 }
 }
TWindow::Drag
void
TWindow::Drag(Point startPoint)
 {
 GrafPtrsavePort;
 KeyMap theKeyMap;
 BooleancommandKeyDown = false;
 RgnHandledraggingRegion;
 long   dragResult;
 WindowPeek windowAsWindowPeek = (WindowPeek) fWindow;
 
 if (WaitMouseUp())//de-bounce?
 {
 // Set up the Window Manager port.
 GetPort(&savePort);
 SetPort(gWindowManagerPort);
 SetClip(GetGrayRgn());

 // Check to see if the command key is down.
 GetKeys(theKeyMap);
 commandKeyDown = ((theKeyMap[1] & 0x8000) != 0);
 
 if (commandKeyDown)
 {
 //We’re not going to change window ordering, so make sure that we don’t 

 //  drag in front of other windows which may be in front of ours.
 ClipAbove(windowAsWindowPeek);
 }
 else if (fWindowType != kFloatingWindow)
 {
 //We’re dragging a normal window, so make sure that we don’t drag in 

 //front of any floating windows.
 ClipAbove((WindowPeek) FrontNonFloatingWindow());
 }
 
 //Drag an outline of the window around the desktop.
 //NOTE: DragGrayRgn destroys the region passed in, so make a copy
 draggingRegion = NewRgn();
 CopyRgn(windowAsWindowPeek->strucRgn,draggingRegion);
 dragResult = DragGrayRgn(draggingRegion, startPoint,
 &gDeskRectangle, &gDeskRectangle, noConstraint, nil);
 DisposeRgn(draggingRegion);
 SetPort(savePort);//Get back to old port

 if ((dragResult != 0) && (dragResult != 0x80008000))
 {
 this->Nudge((dragResult & 0xFFFF),(dragResult >> 16));
 }
 }
 if (!commandKeyDown)
 Select();
 }
TWindow::Nudge
void
TWindow::Nudge(short horizontalDistance, short verticalDistance)
 {
 WindowPeek windowAsWindowPeek = (WindowPeek) fWindow;
 short  newHorizontalPosition,newVerticalPosition;
 
 newHorizontalPosition = (short) (**windowAsWindowPeek
 ->contRgn).rgnBBox.left + horizontalDistance;
 newVerticalPosition = (short) (**windowAsWindowPeek
 ->contRgn).rgnBBox.top + verticalDistance;
 MoveWindow(fWindow,newHorizontalPosition,
 newVerticalPosition, false);
 }
TWindow::Grow
void
TWindow::Grow(Point startPoint)
 {
 GrafPtroldPort;
 long newSize;
 Rect oldWindowRect,resizeLimits;
 
 GetPort(&oldPort);
 GetWindowSizeLimits(&resizeLimits);
 newSize = GrowWindow(fWindow,startPoint,&resizeLimits);
 if (newSize)
 {
 oldWindowRect = fWindow->portRect;
 SizeWindow(fWindow,(short) newSize,
 (short) (newSize >> 16),true);
 SetPort(fWindow);
 this->AdjustForNewWindowSize(&oldWindowRect,
 &fWindow->portRect);
 } 
 SetPort(oldPort);
 }
TWindow::Zoom
void
TWindow::Zoom(short zoomState)
 {
 GrafPtroldPort;
 FontInfo systemFontInfo;
 short  titleBarHeight;
 Rect   bestScreenRect,perfectWindowRect,scratchRect;
 short  amountOffscreen;
 WindowPeek windowAsWindowPeek = (WindowPeek) fWindow;
 GDHandle bestDevice;
 
 GetPort(&oldPort);

 //Figure out the height of the title bar so we can properly position
 //a window. The algorithm is stolen from the System 7.x 'WDEF' (0)
 //This probably isn’t the best thing to do: A better way might be 
 //to diff the structure and content region rectangles?
 SetPort(gWindowManagerPort);
 GetFontInfo(&systemFontInfo);
 titleBarHeight = (short) (systemFontInfo.ascent + 
 systemFontInfo.descent + 4);
 if ((titleBarHeight % 2) == 1)
 titleBarHeight--;
 if (titleBarHeight < kMinimumTitleBarHeight)
 titleBarHeight = kMinimumTitleBarHeight;

 //Only do the voodoo magic if we are really “zooming” the window.
 if (zoomState == inZoomOut)
 {
 FindScreenRectWithLargestPartOfWindow( 
 fWindow,&bestScreenRect,&bestDevice);
 bestScreenRect.top += titleBarHeight;

 this->GetPerfectWindowSize(&perfectWindowRect);
 OffsetRect(&perfectWindowRect,-perfectWindowRect.left,
 -perfectWindowRect.top);

 //Take the zero-pined perfect window size and move it to
 //the top left of the  window’s content region.
 OffsetRect(&perfectWindowRect,
 (**windowAsWindowPeek->contRgn).rgnBBox.left,
 (**windowAsWindowPeek->contRgn).rgnBBox.top);
 
 //Does perfectWindowRect fit completely on the best screen?
   SectRect(&perfectWindowRect,&bestScreenRect,&scratchRect);
 if (!EqualRect(&perfectWindowRect, &scratchRect))
 {
 //SectRect sez perfectWindowRect doesn’t completely fit on the screen, 

 //   so bump the window so that more of it fits.
 //Make sure that the left edge of perfectWindowRect is forced onto the 
best 
 //  screen.  This is in case we are bumping the window to the right.
 amountOffscreen = bestScreenRect.left 
 - perfectWindowRect.left;
 if (amountOffscreen > 0)
 {
 perfectWindowRect.left += amountOffscreen;
 perfectWindowRect.right += amountOffscreen;
 }

 //Make sure that the left edge of perfectWindowRect is forced
 //onto the best screen.  This is in case we are bumping
 //the window downward to a new screen.
 amountOffscreen = bestScreenRect.top 
 - perfectWindowRect.top;
 if (amountOffscreen > 0)
 {
 perfectWindowRect.top += amountOffscreen;
 perfectWindowRect.bottom += amountOffscreen;
 }

 //If right edge of window falls off the screen,
 //Move window to the left until the right edge IS on the screen
 //OR the left edge is at bestScreenRect.left
 amountOffscreen = perfectWindowRect.right 
 - bestScreenRect.right;
 if (amountOffscreen > 0)
 {
 //Are we going to push the left edge offscreen? If so, change the
 //offset so we move the window all the way over to the left.
 if ((perfectWindowRect.left - amountOffscreen) 
 < bestScreenRect.left)
 amountOffscreen = perfectWindowRect.left 
 - bestScreenRect.left;
 perfectWindowRect.left -= amountOffscreen;
 perfectWindowRect.right -= amountOffscreen;
 }

 //If bottom edge of window falls off the screen,
 //Move window to up until the bottom edge IS on the screen
 //OR the top edge is at bestScreenRect.top
 amountOffscreen = perfectWindowRect.bottom 
 - bestScreenRect.bottom;
 if (amountOffscreen > 0)
 {
 //Are we going to push the top edge offscreen? If so, change the
 //offset so we move the window just to the top.
 if ((perfectWindowRect.top - amountOffscreen) 
 < bestScreenRect.top)
 amountOffscreen = perfectWindowRect.top 
 - bestScreenRect.top;
 perfectWindowRect.top -= amountOffscreen;
 perfectWindowRect.bottom -= amountOffscreen;
 }
 SectRect(&perfectWindowRect, &bestScreenRect, 
 &scratchRect);
 if (!EqualRect(&perfectWindowRect, &scratchRect))
 {
 //The edges of the window still fall offscreen,
 //so make the window smaller until it fits.
 if (perfectWindowRect.bottom > bestScreenRect.bottom)
 perfectWindowRect.bottom = bestScreenRect.bottom;

 //If the right edge is still falling off,
 //save space for Finder’s disk icons as well.
 if (perfectWindowRect.right > bestScreenRect.right)
 {
 perfectWindowRect.right = bestScreenRect.right;
 
 //If we were on the main screen, leave room for Finder icons, too.
 if (bestDevice == GetMainDevice())
 perfectWindowRect.right -= kSpaceForFinderIcons;
 }
 }
 }
 //Stash our new rectangle inside of the Window’s dataHandle
 //so that ZoomWindow does the right thing.
 (**((WStateDataHandle)
 (windowAsWindowPeek->dataHandle))).stdState 
 = perfectWindowRect;
 }
 //Don’t forget to set the port to the window being zoomed
 //Why, you ask? Because IM-IV-50 says to; otherwise you die
 SetPort(fWindow);

 Rect oldWindowRect = fWindow->portRect;
 
 ZoomWindow(fWindow,zoomState,false);
 this->AdjustForNewWindowSize(&oldWindowRect,
 &fWindow->portRect);
 SetPort(oldPort);
 }
TWindow::ShowHide
void
TWindow::ShowHide(Boolean showFlag)
 {
 //Here we need the “::” in front of ShowHide to indicate we are calling
 //the global function, and not the method ShowHide. Unintended recursion
 //can do bad things to the unsuspecting programmer.
 //Some C++ programmers would always prepend the “::” on function calls.
 ::ShowHide(fWindow,showFlag);
 fIsVisible = showFlag;
 } 
TWindow::EventFilter
Boolean
TWindow::EventFilter(EventRecord * /* theEvent */)
 {
 return false;
 }
TWindow::GetPerfectWindowSize
void
TWindow::GetPerfectWindowSize(Rect *perfectSize)
 {
 *perfectSize = qd.screenBits.bounds;
 }
TWindow::GetWindowSizeLimits
void
TWindow::GetWindowSizeLimits(Rect *limits)
 {
 limits->top = limits->left = kMinimumWindowSize;
 limits->right = gDeskRectangle.right - gDeskRectangle.left;
 limits->bottom = gDeskRectangle.bottom 
 - gDeskRectangle.top;
 }
TWindow::AdjustForNewWindowSize
void
TWindow::AdjustForNewWindowSize( Rect * /* oldRect */, 
 Rect * /* newSize */)
 {
 }
TWindow::IsVisible
Boolean
TWindow::IsVisible(void)
 {
 return fIsVisible;
 }
TWindow::CanClose
Boolean
TWindow::CanClose(void)
 {
 return true;
 }
TWindow::Close
Boolean
TWindow::Close(void)
 {
 WindowPtrnewFrontWindow = nil;
 
 if (FrontNonFloatingWindow() == fWindow)
 newFrontWindow = (WindowPtr) ((WindowPeek) fWindow)
 ->nextWindow;
 DisposeWindow(fWindow);
 if (newFrontWindow)
 HiliteAndActivateWindow(newFrontWindow,true);
 return true;
 }
TWindow::DeleteAfterClose
Boolean
TWindow::DeleteAfterClose(void)
 {
 return true;
 }
TWindow::DoEditMenu
void
TWindow::DoEditMenu(short /* menuCode */)
 {
 }
TWindow::HandleDrag
OSErr
TWindow::HandleDrag(DragTrackingMessage dragMessage, 
 DragReference theDrag)
 {
 OSErr  result = dragNotAcceptedErr; 
 switch (dragMessage)
 {
 case dragTrackingEnterWindow:
 result = this->DragEnterWindow(theDrag);
 break; 
 case dragTrackingInWindow:
 result = this->DragInWindow(theDrag);
 break; 
 case dragTrackingLeaveWindow:
 result = this->DragLeaveWindow(theDrag);
 break; 
 default:
 break;
 }
 return result;
 }
TWindow::DragEnterWindow
OSErr
TWindow::DragEnterWindow(DragReference /* theDrag */)
 {
 return dragNotAcceptedErr;
 }
TWindow::DragInWindow
OSErr
TWindow::DragInWindow(DragReference /* theDrag */)
 {
 return dragNotAcceptedErr;
 }
TWindow::DragLeaveWindow
OSErr
TWindow::DragLeaveWindow(DragReference /* theDrag */)
 {
 return dragNotAcceptedErr;
 }
TWindow::HandleDrop
OSErr
TWindow::HandleDrop(DragReference /* theDrag */)
 {
 return dragNotAcceptedErr;
 }
 Utility Functions used for floating windows

GetWindowObject
TWindow *
GetWindowObject(WindowPtr aWindow)
 {
 short  wKind;
 
 if (aWindow != nil)
 {
 wKind = ((WindowPeek) aWindow)->windowKind;
 if (wKind >= userKind)
 {
 //All windowKinds >= userKind are based upon TWindow
 return (TWindow *) GetWRefCon(aWindow);
 }
 }
 return (TWindow *) nil;
 }
Utility functions

GetNewColorOrBlackAndWhiteWindow
pascal WindowPtr
GetNewColorOrBlackAndWhiteWindow(short windowID, 
 void *wStorage, WindowPtr behind)
 {
 if (gHasColorQuickdraw)
 return GetNewCWindow(windowID,wStorage,behind);
 else
 return GetNewWindow(windowID,wStorage,behind);
 }
NewColorOrBlackAndWhiteWindow
pascal WindowPtr
NewColorOrBlackAndWhiteWindow( void *wStorage, 
 const Rect *boundsRect, ConstStr255Param title, 
 Boolean visible, short theProc, WindowPtr behind, 
 Boolean goAwayFlag, long refCon)
 {
 if (gHasColorQuickdraw)
 return NewCWindow(wStorage, boundsRect, title, visible,
 theProc, behind, goAwayFlag, refCon);
 else
 return NewWindow(wStorage, boundsRect, title, visible,
  theProc, behind, goAwayFlag,refCon);
 }
LastFloatingWindow
WindowPtr
LastFloatingWindow(void)
 {
 WindowPeek aWindow = (WindowPeek) FrontWindow();
 WindowPtrlastFloater = (WindowPtr) kNoFloatingWindows;
 
 while (aWindow && (aWindow->windowKind 
 == kFloatingWindowKind))
 {
 if (aWindow->visible)
 lastFloater = (WindowPtr) aWindow;

 aWindow = (WindowPeek) aWindow->nextWindow;
 }
 return(lastFloater);
 }
FrontNonFloatingWindow
WindowPtr
FrontNonFloatingWindow(void)
 {
 WindowPeek aWindow = (WindowPeek) LMGetWindowList();

 //Skip over floating windows
 while (aWindow && (aWindow->windowKind 
 == kFloatingWindowKind))
 aWindow = (WindowPeek) aWindow->nextWindow;

 //Skip over invisible, but otherwise normal windows
 while (aWindow && (aWindow->visible == 0))
 aWindow = (WindowPeek) aWindow->nextWindow;
 
 return (WindowPtr) aWindow;
 }
HiliteAndActivateWindow
void
HiliteAndActivateWindow(WindowPtr aWindow,Boolean active)
 {
 GrafPtroldPort;
 TWindow* wobj = GetWindowObject(aWindow);
 
 if (aWindow)
 {
 HiliteWindow(aWindow,active);
 if (wobj != nil)
 {
 GetPort(&oldPort);
 SetPort(aWindow);
 wobj->Activate(active);
 SetPort(oldPort);
 } 
 }
 }
SuspendResumeWindows
void
SuspendResumeWindows(Boolean resuming)
 {
 //When we suspend/resume, hide/show all the visible floaters
 HiliteShowHideFloatingWindows(resuming,true);
 }
HiliteWindowsForModalDialog
void
HiliteWindowsForModalDialog(Boolean hiliting)
 {
 //When we display a modal dialog, we need to unhighlight
 //all visible floaters. We also need to re-hilite them afterwards.
 HiliteShowHideFloatingWindows(hiliting,false);
 }
HiliteShowHideFloatingWindows
void
HiliteShowHideFloatingWindows(Boolean hiliting,Boolean dohiding)
 {
 WindowPeek aWindow;
 TWindow *wobj;
 
 HiliteAndActivateWindow(FrontNonFloatingWindow(),hiliting);
 aWindow = LMGetWindowList();
 while (aWindow && aWindow->windowKind 
 == kFloatingWindowKind)
 {
 wobj = GetWindowObject((WindowPtr) aWindow);
 
 //If we are hiding or showing, only hide/show windows that were 
 //  visible to begin with.
 //NOTE:We use our copy of the visible flag so we can
 //automatically show floaters on a resume event.
 //NOTE:Since this isn’t a method of TWindow, we don’t really need the 
“::” 
 //     on ShowHide, but as long as we’re trying to avoid ambiguity 
 if (dohiding && (wobj != nil) && (wobj->IsVisible()))
 ::ShowHide((WindowPtr) aWindow,hiliting);
 
 //All floaters are hilited if any floater is hilited
 HiliteWindow((WindowPtr) aWindow,hiliting);
 aWindow = (WindowPeek) aWindow->nextWindow;
 }
 }
Routines used for dealing with windows and multiple screens

CalculateWindowAreaOnDevice
pascal void
CalculateWindowAreaOnDevice(short /* depth */,
 short /* deviceFlags */,GDHandle targetDevice,long userData)
 {
 CalcWindowAreaDeviceLoopUserData *deviceLoopDataPtr;
 long   windowAreaOnThisScreen;
 Rect   windowRectOnThisScreen;
 
 deviceLoopDataPtr = (CalcWindowAreaDeviceLoopUserData *)
 userData;

 SectRect(&deviceLoopDataPtr->fWindowBounds, 
 &(**targetDevice).gdRect,&windowRectOnThisScreen);
 OffsetRect(&windowRectOnThisScreen,
 -windowRectOnThisScreen.left,
 -windowRectOnThisScreen.top);
 windowAreaOnThisScreen = windowRectOnThisScreen.right 
 * windowRectOnThisScreen.bottom;
 if (windowAreaOnThisScreen > deviceLoopDataPtr->fLargestArea)
 {
 deviceLoopDataPtr->fLargestArea = windowAreaOnThisScreen;
 deviceLoopDataPtr->fScreenWithLargestPartOfWindow 
 = targetDevice;
 }
 }

DeviceLoopDrawingUPP CallCalcWindowAreaOnDevice = 
 NewDeviceLoopDrawingProc(&CalculateWindowAreaOnDevice);

FindScreenRectWithLargestPartOfWindow
void
FindScreenRectWithLargestPartOfWindow(WindowPtr aWindow,
 Rect *theBestScreenRect,GDHandle * theBestDevice)
 {
 RgnHandlecopyOfWindowStrucRgn;
 CalcWindowAreaDeviceLoopUserData  deviceLoopData;

 //Use DeviceLoop to find out what GDevice contains the largest
 //portion of the supplied window.
 //NOTE:Assumes thePort == the Window Manager Port because we using
 //the window strucRgn, not contRgn.
 deviceLoopData.fScreenWithLargestPartOfWindow = nil;
 deviceLoopData.fLargestArea = -1;
 deviceLoopData.fWindowBounds = (**(((WindowPeek) aWindow)
 ->contRgn)).rgnBBox;
 copyOfWindowStrucRgn = NewRgn();
 CopyRgn(((WindowPeek) aWindow)->strucRgn,copyOfWindowStrucRgn);

 DeviceLoop(copyOfWindowStrucRgn, 
 CallCalcWindowAreaOnDevice, 
 (long) &deviceLoopData,singleDevices);

 DisposeRgn(copyOfWindowStrucRgn);
 
 *theBestDevice = 
 deviceLoopData.fScreenWithLargestPartOfWindow;
 *theBestScreenRect = 
 (**(deviceLoopData.fScreenWithLargestPartOfWindow)).gdRect;

 //Leave some space around the edges of the screen so window look good, 
AND
 //if the best device is the main screen, leave space for the Menubar
 InsetRect(theBestScreenRect,kScreenEdgeSlop,kScreenEdgeSlop);
 if (GetMainDevice() 
 == deviceLoopData.fScreenWithLargestPartOfWindow)
 theBestScreenRect->top += GetMBarHeight();
 }
Drag Manager callback routines which dispatch to a window’s method

CallWindowDragTrackingHandler
pascal OSErr
CallWindowDragTrackingHandler(DragTrackingMessage dragMessage, 
 WindowPtr theWindow,void * /* refCon */,DragReference theDrag)
 {
 TWindow *wobj = GetWindowObject(theWindow);
 
 if (wobj)
 return(wobj->HandleDrag(dragMessage,theDrag));
 else
 return dragNotAcceptedErr;
 }
CallWindowDragReceiveHandler
pascal OSErr
CallWindowDragReceiveHandler(WindowPtr theWindow,
 void * /* refCon */,DragReference theDrag)
 {
 TWindow *wobj = GetWindowObject(theWindow);
 
 if (wobj)
 return(wobj->HandleDrop(theDrag));
 else
 return dragNotAcceptedErr;
 }


AppLib.h


/* 7 */
/* Contains:Prototypes for the “guts” of a Macintosh application.
Copyright:© 1993 by Dave Falkenburg, all rights reserved. */

#ifndef _APPLIB_
#define _APPLIB_

#include"AppConditionals.h"
#include"Preferences.h"
#include<Types.h>
#include<Windows.h>
#include<Dialogs.h>
#include<Menus.h>
#include<Files.h>
#include<AppleEvents.h>
#include<StandardFile.h>
#include<OCEStandardMail.h>
#include"Window.h"

#ifqUseQuickDrawGX
#include<FixMath.h>//make sure we don’t use GX lame #define of “fixed1”
#include<graphics types.h>
#endif
useful macros
#ifqDebug
#define DebugMessage(x) DebugStr(x)
#else
#define DebugMessage(x)
#endif
Resource IDs
#define kErrorAlertID128
#define kStandardCloseAlertID 129
#define kStandardCloseWithNewPubsAlertID     130
#define kCoreErrorStrings 128
#define kUnsupportedSystemSoftware 1
#define kNeedsThreadManager 2
#define kStandardCloseStrings 129
#define kQuittingStr 1
#define kClosingStr2
#define kPreferencesFileStrings    130
#define kPreferencesFileName1
#define kSplashPictureID  128

#ifqUseQuickDrawGX
// When using GX, we want to create a 300K graphics heap
// NOTE: I have no idea what to use as a number here!
#define kGraphicsHeapSize (300 * 1024)
#endif
Useful functions provided by App:

void    HandleEvent(EventRecord *anEvent);
void    HandleClose(WindowPtr aWindow);
short   StandardAlert(short alertID, short defaultItem=ok,
 short cancelItem= 0,
 ModalFilterUPP customFilterProc = nil);
void    ErrorAlert(short stringList,short whichString);
void    FatalErrorAlert(short stringList,short whichString);

extern ModalFilterUPPStandardDialogFilter;
extern ModalFilterYDUPP StandardDialogFilterYD;
extern  voidPseudoClickInDialogItem(DialogPtr theDialog,
  short itemToClick);
enum  StandardCloseResult
 {
 kSaveDocument = 1,
 kCancelSaveDocument = 2,
 kDontSaveDocument = 3
 };

StandardCloseResultStandardCloseDocument(
 const StringPtr documentType,StringPtr documentName,
 Boolean hasNewEditions, Boolean quitting);

OSErr CheckAppleEventForMissingParams(
 AppleEvent *theAppleEvent);

short OpenPreferencesResFile(void);

// AOCE “FrontWindow”-equivalent routine for the Standard Mail package
extern FrontWindowUPPFrontWindowProcForAOCEUPP;

Globals
extern  Boolean  gDone;
extern  Boolean  gMenuBarNeedsUpdate;
extern  Boolean  gHasColorQuickdraw;
extern  Boolean  gHasThreadManager;
extern  Boolean  gHasDragManager;
extern  Boolean  gHasAOCE;
extern  Boolean  gHasDisplayManager;

#ifqInlineInputAware
extern  Boolean  gHasTextServices;
extern  Boolean  gHasTSMTE;
#endif

#ifqUseQuickDrawGX
extern  Boolean  gHasQuickDrawGX;
extern  longgQuickDrawGXVersion;
extern  longgQuickDrawGXPrintingVersion;
extern  gxGraphicsClient  gQuickDrawGXClient;
#endif

extern  GrafPtr  gWindowManagerPort;
extern  RectgDeskRectangle;
extern  RgnHandlegMouseRegion;

extern  short    gPreferencesRsrcRefNum;

Routines that the application MUST supply:

extern  OSErr  SetupApplication(void);
extern  voidTearDownApplication(void);
extern  voidHandleMenu(TWindow * topWindowObj,long menuCode);
extern  voidConvertClipboard(void);

extern  OSErr  OpenNewDocument(void);
extern  OSErr  OpenDocument(LetterDescriptor *,void *);
extern  OSErr  PrintDocument(LetterDescriptor *,void *);
extern  Boolean  QuitApplication(void);

#endif

AppLib.cp


/* 8 */
/* Contains:The “guts” of a Macintosh application. Written by Dave and 
many other SmartFriends™  Copyright: © 1993-94 by Dave Falkenburg, all 
rights reserved. */
#ifdef  SystemSevenOrLater
#undef  SystemSevenOrLater
#endif
#define SystemSevenOrLater1

#include <limits.h>//For LONG_MAX

#include <Types.h>
#include <Quickdraw.h>
#include <Fonts.h>
#include <Menus.h>
#include <Windows.h>
#include <Dialogs.h>
#include <Desk.h>
#include <Events.h>
#include <AppleEvents.h>
#include <DiskInit.h>

#if qUseETO15Interfaces
#include <Gestalt.h>
#include <CodeFragments.h>
#include <Devices.h>
#else
#include <GestaltEqu.h>
#include <FragLoad.h>
#endif

#include <ToolUtils.h>
#include <Traps.h>
#include <LowMem.h>

#include <Threads.h>
#include <Drag.h>
#include <Editions.h>
#include <OCEStandardMail.h>

#ifqInlineInputAware
#include <TextServices.h>
#include <TSMTE.h>
#endif

#include "AppLib.h"
#include "StandardMenus.h"
#include "Window.h"
#include "SplashWindow.h"
#include "MailableWindow.h"
#include "AppleEventHandling.h"

#ifqUseQuickDrawGX
#include <graphics macintosh.h>
#include <graphics routines.h>
#include <PrintingManager.h>
#endif
Function Prototypes
void  main(void);
void  MainEventLoop(void);
void  HandleMouseDown(TWindow * topWindowObj, EventRecord * anEvent);
void  HandleUpdate(EventRecord * anEvent);
void  HandleClose(WindowPtr aWindow);

Globals
Boolean gDone = false;
Boolean gMenuBarNeedsUpdate = true;

Boolean gHasColorQuickdraw = false;
Boolean gHasThreadManager = false;
Boolean gHasDragManager = false;
Boolean gHasAppleScript = false;
Boolean gHasAOCE = false;
Boolean gHasDisplayManager = false;

GrafPtr gWindowManagerPort;
Rect    gDeskRectangle;
RgnHandle gMouseRegion = nil;

short   gPreferencesRsrcRefNum;

#ifqInlineInputAware
Boolean gHasTextServices = false;
Boolean gHasTSMTE = false;
#endif

#ifqUseQuickDrawGX
Boolean gHasQuickDrawGX = false;
long    gQuickDrawGXVersion = 0;
long    gQuickDrawGXPrintingVersion = 0;
gxGraphicsClient gQuickDrawGXClient;

// PrintingEventOverride is our generic event handler for QuickDrawGX.
// It alows us to handle events while the QuickDrawGX movable modal
// printing dialogs are displayed.
// ¿ Really should move to a GX-specific place ?
PrintingEventOverrideForGX
OSErr
PrintingEventOverrideForGX(EventRecord *anEvent, 
  Boolean filterEvent)
 {
 if (!filterEvent)
 switch (anEvent->what)
 {
 case mouseDown:
 case keyDown:
 case autoKey:
 break;
 default:
 HandleEvent(anEvent);
 }
 return noErr;
 }
#endif

// Values that can be adjusted by other application code to change
// the behavior of the MainEventLoop.
//
// Rules of thumb:
// Increase gXXXRunQuantum (and decrease gXXXSleepQuantum) when:
// The application has many threads running that need time
// Decrease gXXXRunQuantum when:
// Sending AppleEvents to other applications
// Launching other applications
// Running in the background

unsigned long  gForegroundRunQuantum = 0;
unsigned long  gForegroundSleepQuantum = GetCaretTime();
unsigned long  gBackgroundRunQuantum = 0;
unsigned long  gBackgroundSleepQuantum = LONG_MAX;

// Globals used to “tune” the performance of MainEventLoop
// (assume we’ll be starting in the foreground)

static  unsigned longgRunQuantum = gForegroundRunQuantum;
static  unsigned longgSleepQuantum = gForegroundSleepQuantum;

#ifdef  powerc
#ifndef __MWERKS__
QDGlobals qd;
#endif
#endif
main
void
main(void)
 {
 long   feature;

 MaxApplZone();
 MoreMasters(); MoreMasters(); MoreMasters(); MoreMasters();

 InitGraf(&qd.thePort); 
 InitFonts();
 InitWindows();
 InitMenus();
 TEInit();
 InitDialogs(nil);

 if (GetToolTrapAddress(_Unimplemented) 
 == GetOSTrapAddress(_Gestalt))
 FatalErrorAlert(kCoreErrorStrings,
 kUnsupportedSystemSoftware);

 if (Gestalt(gestaltQuickdrawFeatures,&feature) == noErr)
 gHasColorQuickdraw = ((feature & (1 << gestaltHasColor)) != 0);

 TSplashWindow * splashWindow = new TSplashWindow;
 
 if ((Gestalt(gestaltAppleEventsAttr,&feature) == noErr) 
 && (feature & (1 << gestaltAppleEventsPresent)))
 {
 //Figure out if we need to do AppleEvent recording
 gHasAppleScript = (feature & (1 << gestaltScriptingSupport));
 }
 else
 FatalErrorAlert(kCoreErrorStrings,
 kUnsupportedSystemSoftware);

#ifqInlineInputAware
 if ((Gestalt(gestaltTSMgrVersion,&feature) == noErr) 
  && (feature >= 1))
 {
 gHasTextServices = true;
 if (Gestalt(gestaltTSMTEAttr, &feature) == noErr)
 gHasTSMTE = (feature & (1 << gestaltTSMTEPresent));
 }
#endif

 if (Gestalt(gestaltThreadMgrAttr,&feature) == noErr)
 {
#ifdef  powerc
 //If running on a PowerPC, make sure that we not only have the 68K Thread
 //Manager, but also the PowerPC shared library, too.  Because of the 
wonders
 //of weak linking and out of memory errors we need to also check to 
make
 //sure that an entrypoint in the library is there, too. 
 if ((Ptr) NewThread != kUnresolvedSymbolAddress)
 gHasThreadManager = ((feature 
 & ((1 << gestaltThreadMgrPresent) 
  | (1 << gestaltThreadsLibraryPresent))) != 0);
#else
 gHasThreadManager = ((feature & (1 << gestaltThreadMgrPresent)) != 0);
#endif
 }
 
 //Check for and install Drag Manager callbacks
 if (Gestalt(gestaltDragMgrAttr,&feature) == noErr)
 {
#ifdef  powerc
 //If running on a PowerPC, make sure that we not only have the
 //68K Drag Manager, but also the PowerPC shared library, too.
 if ((Ptr) NewDrag != kUnresolvedSymbolAddress)
 gHasDragManager = ((feature 
 & ((1 << gestaltDragMgrPresent) 
  | (1 << gestaltPPCDragLibPresent))) != 0);
#else
 gHasDragManager = ((feature & (1<<gestaltDragMgrPresent))!=0);
#endif

 if (gHasDragManager)
 {
 InstallTrackingHandler(  NewDragTrackingHandlerProc
 (CallWindowDragTrackingHandler),
 (WindowPtr) nil,nil);
 InstallReceiveHandler( NewDragReceiveHandlerProc
 (CallWindowDragReceiveHandler), 
 (WindowPtr) nil,nil);
 }
 }
 //Check for Display Manager
 if (Gestalt(gestaltDisplayMgrAttr,&feature) == noErr)
 gHasDisplayManager 
 = ((feature & (1 << gestaltDisplayMgrPresent)) != 0);
 
 //Check for and initialize AOCE Standard Mail package if it exists
 if ((Gestalt(gestaltSMPMailerVersion,&feature) == noErr) 
 && (feature != 0))
 {
#ifdef  powerc
 if ((Ptr) SMPInitMailer != kUnresolvedSymbolAddress)
 gHasAOCE = (SMPInitMailer(kSMPVersion) == noErr);
#else
 gHasAOCE = (SMPInitMailer(kSMPVersion) == noErr);
#endif
 }

#ifqUseQuickDrawGX
 //Check for and initialize QuickDrawGX
 if (Gestalt(gestaltGXVersion, &gQuickDrawGXVersion)==noErr)
 if (Gestalt(gestaltGXPrintingMgrVersion,
 &gQuickDrawGXPrintingVersion) == noErr)
#ifdef  powerc
 if ((Ptr) GXEnterGraphics != kUnresolvedSymbolAddress)
 gHasQuickDrawGX = true;
#else
 gHasQuickDrawGX = true;
#endif

 if (gHasQuickDrawGX)
 {
// gQuickDrawGXClient = GXNewGraphicsClient(nil, kGraphicsHeapSize, 
// (gxClientAttribute) 0);
 GXEnterGraphics();
 GXInitPrinting();
 }
#endif
 
 InstallAppleEventHandlers(); // Install our AppleEvent Handlers

 //Setup desktop rectangle for dragging windows around         
 
 GetWMgrPort(&gWindowManagerPort);
 gDeskRectangle = (**GetGrayRgn()).rgnBBox;

 //Get the default menubar
 SetMenuBar(GetNewMBar(rMenuBar));
 AddResMenu(GetMHandle(mApple),'DRVR');
 
 gPreferencesRsrcRefNum = OpenPreferencesResFile();
 
 if (SetupApplication() == noErr)
 {
 delete splashWindow;// get rid of the splash screen
 MainEventLoop();
 TearDownApplication();
 }
 
#ifqUseQuickDrawGX
 if (gHasQuickDrawGX)// Tear down QuickDrawGX
 {
 GXExitPrinting();
// GXDisposeGraphicsClient(gQuickDrawGXClient);    //    Dies a horrible 
death for me?
 GXExitGraphics();
 }
#endif
 }
MainEventLoop
void
MainEventLoop(void)
 {
 EventRecordanEvent;
 unsigned long nextTimeToCheckForEvents = 0;
 
 while (!gDone)
 {
 if (gMenuBarNeedsUpdate)
 {
 gMenuBarNeedsUpdate = false;
 DrawMenuBar();
 }
 if ((gRunQuantum == 0) ||
 (TickCount() > nextTimeToCheckForEvents))
 {
 nextTimeToCheckForEvents = TickCount() + gRunQuantum;
 (void) WaitNextEvent(everyEvent,&anEvent,
 gSleepQuantum,gMouseRegion);
 HandleEvent(&anEvent);
 }
 if (gHasThreadManager)
 YieldToAnyThread();
 }
 }
HandleEvent
void
HandleEvent(EventRecord *anEvent)
 {
 TWindow* wobj;
 
 if (anEvent->what != updateEvt)
 wobj = GetWindowObject(FrontNonFloatingWindow());
 else
 wobj = GetWindowObject((WindowPtr) anEvent->message);
 if (wobj != nil)
 wobj->AdjustCursor(anEvent);
 if ((wobj != nil) && wobj->EventFilter(anEvent))
 return;
 else switch (anEvent->what)
 {
 case nullEvent:
 if (wobj != nil)
 wobj->Idle(anEvent);
 break;
 case mouseDown:
 HandleMouseDown(wobj,anEvent);
 break;
 case keyDown:
 case autoKey:
 if (anEvent->modifiers & cmdKey)
 HandleMenu(wobj,MenuKey((short) anEvent->message 
 & charCodeMask));
 else if (wobj != nil)
 wobj->KeyDown(anEvent);
 break;
 case updateEvt:
 HandleUpdate(anEvent);
 break;
 case diskEvt:
 if (anEvent->message >> 16)
 {
 static Point  where = {50,50};
 (void) DIBadMount(where,anEvent->message);
 }
 break;
 case osEvt:
 switch ((anEvent->message & osEvtMessageMask) >> 24)
 {
 case mouseMovedMessage:
 break;
 case suspendResumeMessage: 
 if (anEvent->message & resumeFlag)
 {
 gRunQuantum = gForegroundRunQuantum;
 gSleepQuantum = gForegroundSleepQuantum;
 }
 else
 {
 gRunQuantum = gBackgroundRunQuantum;
 gSleepQuantum = gBackgroundSleepQuantum;
 }
 SuspendResumeWindows(
 (anEvent->message & resumeFlag) != 0);
 if (anEvent->message & convertClipboardFlag)
 ConvertClipboard();
 break;
 }
 break;
 case kHighLevelEvent:
 (void) AEProcessAppleEvent(anEvent);
 break;
 default:
 break;
 }
 }
HandleMouseDown
void
HandleMouseDown(TWindow * topWindowObj,EventRecord *anEvent)
 {
 WindowPtraWindow;
 short  partCode;
 TWindow*wobj;

 partCode = FindWindow(anEvent->where,&aWindow);
 wobj = GetWindowObject(aWindow);
 switch(partCode)
 {
 case inMenuBar:
 HandleMenu(topWindowObj,MenuSelect(anEvent->where));
 break;
 case inSysWindow:
 SystemClick(anEvent,aWindow);
 break;
 case inContent:
 if (wobj)
 {
 GrafPtroldPort;
 
 GetPort(&oldPort);
 SetPort(aWindow);
 GlobalToLocal(&anEvent->where);
 wobj->Click(anEvent);
 SetPort(aWindow);
 }
 break;
 case inDrag:
 if (wobj)
 wobj->Drag(anEvent->where);
 break;
 case inGrow:
 if (wobj)
 wobj->Grow(anEvent->where);
 break;
 case inGoAway:
 if (TrackGoAway(aWindow,anEvent->where))
 HandleClose(aWindow);
 break;
 case inZoomIn:
      caseinZoomOut:
        if (TrackBox(aWindow,anEvent->where,partCode) && (wobj))
 wobj->Zoom(partCode);
        break;
 default:
 break;
 }
 }
HandleUpdate
void  HandleUpdate(EventRecord * anEvent)
 {
 GrafPtroldPort;
 WindowPtraWindow = (WindowPtr) anEvent->message;  
 TWindow* wobj;
 
 GetPort(&oldPort);
 SetPort(aWindow);
 BeginUpdate(aWindow);
 if ((wobj = GetWindowObject(aWindow)) != nil)
 wobj->Draw();
 EndUpdate(aWindow);
 SetPort(oldPort);
 }
HandleClose
void
HandleClose(WindowPtr aWindow)
 {
 short  windowKind;
 TWindow*wobj;
 
 if (aWindow)
 {
 windowKind = ((WindowPeek) aWindow)->windowKind;
 if (windowKind < 0)
 {
 CloseDeskAcc(((WindowPeek)aWindow)->windowKind);
 }
 else if ( ((wobj = GetWindowObject(aWindow)) != nil) &&
 wobj->CanClose() && wobj->Close() 
 && wobj->DeleteAfterClose())
 {
 delete wobj;
 }
 }
 }







  
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Google Drive 1.20 - File backup and shar...
Google Drive is a place where you can create, share, collaborate, and keep all of your stuff. Whether you're working with a friend on a joint research project, planning a wedding with your fiancé, or... Read more
Simon 4.0.3 - Monitor changes and crashe...
Simon monitors websites and alerts you of crashes and changes. Select pages to monitor, choose your alert options, and customize your settings. Simon does the rest. Keep a watchful eye on your... Read more
Vitamin-R 2.23 - Personal productivity t...
Vitamin-R creates the optimal conditions for your brain to work at its best by structuring your work into short bursts of distraction-free, highly focused activity alternating with opportunities for... Read more
iDefrag 5.0.0 - Disk defragmentation and...
iDefrag helps defragment and optimize your disk for improved performance. Features include: Supports HFS and HFS+ (Mac OS Extended). Supports case sensitive and journaled filesystems. Supports... Read more
PCalc 4.2 - Full-featured scientific cal...
PCalc is a full-featured, scriptable scientific calculator with support for hexadecimal, octal, and binary calculations, as well as an RPN mode, programmable functions, and an extensive set of unit... Read more
FileZilla 3.10.2 - Fast and reliable FTP...
FileZilla (ported from Windows) is a fast and reliable FTP client and server with lots of useful features and an intuitive interface. Version 3.10.2: Note: Now requires a 64-bit Intel processor.... Read more
The Hit List 1.1.11 - Advanced reminder...
The Hit List manages the daily chaos of your modern life. It's easy to learn - it's as easy as making lists. And it's powerful enough to let you plan, then forget, then act when the time is right.... Read more
Bartender 1.2.32 - Organize your menu ba...
Bartender lets you organize your menu bar apps. Features: Lets you tidy your menu bar apps how you want. See your menu bar apps when you want. Hide the apps you need to run, but do not need to... Read more
ClamXav 2.7.5 - Free virus checker, base...
ClamXav is a free virus checker for OS X. It uses the tried, tested, and very popular ClamAV open source antivirus engine as a back end. I hope you like and use ClamXav a lot and that it helps keep... Read more
xScope 4.1.2 - Onscreen graphic measurem...
xScope is powerful set of tools that are ideal for measuring, inspecting, and testing on-screen graphics and layouts. Its tools float above your desktop windows and can be accessed via a toolbar,... Read more

Dungeon Hunter 5 Coming on March 12
Gameloft has excitedly announced that Dungeon Hunter 5 is on its way! Once again, you will adventure across the land of Valenthia exploring dungeons and fighting monsters. The game will have a new asynchronous multiplayer mode called Strongholds... | Read more »
It Came From Canada: Jurojin: Immortal N...
At this point it’s pretty safe to say that no MOBA is going to dethrone Dota 2 and League of Legends anytime soon. After all, if Batman can’t do it, nobody can. However, with a genre as popular and profitable as this one, there’s still room for... | Read more »
Tiny Farm – Animals, Tractors and Advent...
Tiny Farm – Animals, Tractors and Adventures! Review By Amy Solomon on March 3rd, 2015 Our Rating: :: LIVELY LANDSCAPESUniversal App - Designed for iPhone and iPad Tiny Farm – Animals, Tractors and Adventures! includes farm-related... | Read more »
This Week at 148Apps: February 23-27, 20...
Final February Fun at 148Apps   How do you know what apps are worth your time and money? Just look to the review team at 148Apps. We sort through the chaos and find the apps you’re looking for. The ones we love become Editor’s Choice, standing out... | Read more »
GDC 2015 – Does Not Commute is Definitel...
GDC 2015 – Does Not Commute is Definitely a Game You Should Keep an Eye on Posted by Rob Rich on March 2nd, 2015 [ permalink ] We were teased about Mediocre Games’ (Smash Hit, | Read more »
F84 Games & POW! Announce Stan Lee V...
F84 Games has announced that it is working with legendary comic creator Stan Lee and POW! Entertainment to produce Stan Lee’s Hero Command. The game will be a action adventure of heroic proportions. | Read more »
Setlyst Keeps Your Set Straight So You C...
Setlyst Keeps Your Set Straight So You Can Focus On Rocking Out. Posted by Jessica Fisher on March 2nd, 2015 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Space is Vast, So Space Agency Has a Vas...
Space is Vast, So Space Agency Has a Vast New Update! Posted by Jessica Fisher on March 2nd, 2015 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Size DOES Matter Review
Size DOES Matter Review By Campbell Bird on March 2nd, 2015 Our Rating: :: HARD TO BEATUniversal App - Designed for iPhone and iPad This rhythm game has a unique control scheme and performance system that make it feel like a true... | Read more »
The first ever action 3D card battler Al...
On the other hand, you probably haven’t played an action 3D card battler – until now. Step forward, All Star Legion. All Star Legion is a 3D QTE-based action RPG card battler, but fear not – the game itself isn’t as convoluted as its description.... | Read more »

Price Scanner via MacPrices.net

Another Tranche Of IBM MobileFirst For iOS Ap...
IBM has announced the next expansion phase for  its IBM MobileFirst for iOS portfolio, with a troika of new apps to address key priorities for the Banking and Financial Services, Airline and Retail... Read more
Sale! 15-inch Retina MacBook Pros for up to $...
B&H Photo has the new 2014 15″ Retina MacBook Pros on sale for up to $250 off MSRP for a limited time. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.2GHz Retina MacBook Pro: $... Read more
WaterField Designs Introduces the Minimalist...
With Apple Pay gaining popularity, Android Pay coming in May 2015, and loyalty cards and receipts that can be accessed from smartphones, San Francisco’s WaterField Designs observes that it may be... Read more
Sale! 15-inch 2.2GHz Retina MacBook Pro for $...
 Best Buy has the 15″ 2.2GHz Retina MacBook Pro on sale for $1774.99 $1799.99, or $225 off MSRP. Choose free home shipping or free local store pickup (if available). Price valid for online orders... Read more
13-inch 2.5GHz MacBook Pro (refurbished) avai...
The Apple Store has Apple Certified Refurbished 13″ 2.5GHz MacBook Pros available for $170 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free: - 13″ 2.5GHz... Read more
13-inch 2.5GHz MacBook Pro on sale for $100 o...
B&H Photo has the 13″ 2.5GHz MacBook Pro on sale for $999.99 including free shipping plus NY sales tax only. Their price is $100 off MSRP. Read more
27-inch 3.5GHz 5K iMac in stock today and on...
 B&H Photo has the 27″ 3.5GHz 5K iMac in stock today and on sale for $2299 including free shipping plus NY sales tax only. Their price is $200 off MSRP, and it’s the lowest price available for... Read more
Apple Launches Free Web-Based Pages and Other...
Apple’s new Web-only access to iWork productivity apps is a free level of iCloud service available to anyone, including people who don’t own or use Apple devices. The service includes access to Apple... Read more
Survey Reveals Solid State Disk (SSD) Technol...
In a recent SSD technology use survey, Kroll Ontrack, a firm specializing in data recovery, found that while nearly 90 percent of respondents leverage the performance and reliability benefits of SSD... Read more
Save up to $600 with Apple refurbished Mac Pr...
The Apple Store is offering Apple Certified Refurbished Mac Pros for up to $600 off the cost of new models. An Apple one-year warranty is included with each Mac Pro, and shipping is free. The... Read more

Jobs Board

*Apple* Solutions Consultant - Retail Sales...
**Job Summary** As an Apple Solutions Consultant (ASC) you are the link between our customers and our products. Your role is to drive the Apple business in a retail Read more
*Apple* Pay Automation Engineer - iOS System...
**Job Summary** At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring passion and dedication to your job Read more
Sr. Technical Services Consultant, *Apple*...
**Job Summary** Apple Professional Services (APS) has an opening for a senior technical position that contributes to Apple 's efforts for strategic and transactional Read more
Event Director, *Apple* Retail Marketing -...
…This senior level position is responsible for leading and imagining the Apple Retail Team's global engagement strategy and team. Delivering an overarching brand Read more
*Apple* Pay - Site Reliability Engineer - Ap...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.