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;
 }
 }
 }







  
 
AAPL
$524.94
Apple Inc.
+5.93
MSFT
$40.01
Microsoft Corpora
-0.39
GOOG
$536.10
Google Inc.
-20.44

MacTech Search:
Community Search:

Software Updates via MacUpdate

VMware Fusion 6.0.3 - Run Windows apps a...
VMware Fusion allows you to create a Virtual Machine on your Mac and run Windows (including Windows 8.1) and Windows software on your Mac. Run your favorite Windows applications alongside Mac... Read more
Tweetbot 1.5.1 - Popular iOS twitter cli...
Tweetbot is a full-featured OS X Twitter client with a lot of personality. Whether it's the meticulously-crafted interface, sounds and animation, or features like multiple timelines and column views... Read more
Mac DVDRipper Pro 4.1.7 - Copy, backup,...
Mac DVDRipper Pro is the DVD backup solution that lets you protect your DVDs from scratches, save your batteries by reading your movies from your hard disk, manage your collection with just a few... Read more
PDFpenPro 6.2 - Advanced PDF toolkit for...
PDFpenPro allows users to edit PDF's easily. Add text, images and signatures. Fill out PDF forms. Merge or split PDF documents. Reorder and delete pages. Even correct text and edit graphics! Create... Read more
PDFpen 6.2 - Edit and annotate PDFs with...
PDFpen allows users to easily edit PDF's. Add text, images and signatures. Fill out PDF forms. Merge or split PDF documents. Reorder and delete pages. Even correct text and edit graphics! Features... Read more
Monolingual 1.5.9 - Remove unwanted OS X...
Monolingual is a program for removing unnecesary language resources from OS X, in order to reclaim several hundred megabytes of disk space. It requires a 64-bit capable Intel-based Mac and at least... Read more
Maya 2015 - Professional 3D modeling and...
Maya is an award-winning software and powerful, integrated 3D modeling, animation, visual effects, and rendering solution. Because Maya is based on an open architecture, all your work can be scripted... Read more
Starcraft II: Wings of Liberty 1.1.1.180...
Download the patch by launching the Starcraft II game and downloading it through the Battle.net connection within the app. Starcraft II: Wings of Liberty is a strategy game played in real-time. You... Read more
Sibelius 7.5.0 - Music notation solution...
Sibelius is the world's best-selling music notation software for Mac. It is as intuitive to use as a pen, yet so powerful that it does most things in less than the blink of an eye. The demo includes... Read more
Typinator 5.9 - Speedy and reliable text...
Typinator turbo-charges your typing productivity. Type a little. Typinator does the rest. We've all faced projects that require repetitive typing tasks. With Typinator, you can store commonly used... Read more

Latest Forum Discussions

See All

Have a Special Dead Trigger 2 Easter Bas...
Have a Special Dead Trigger 2 Easter Basket Full of Goodies, Courtesy of Madfinger Games Posted by Rob Rich on April 18th, 2014 [ permalink ] Dead Trigger 2 | Read more »
Almost All of Playdek’s Library is on Sa...
Almost All of Playdek’s Library is on Sale Right Now, and You Should Check it Out Posted by Rob Rich on April 18th, 2014 [ permalink ] Playdek has released quite a few great iOS ports of board and card games over the years, and now most of them... | Read more »
Zynga Launches Brand New Farmville Exper...
Zynga Launches Brand New Farmville Experience with Farmville 2: Country Escape Posted by Tre Lawrence on April 18th, 2014 [ permalink ] | Read more »
David. Review
David. Review By Cata Modorcea on April 18th, 2014 Our Rating: :: MINIMALISTIC IN A DIFFERENT WAYUniversal App - Designed for iPhone and iPad David is a minimalistic game wrapped inside of a soothing atmosphere in which the hero... | Read more »
Eyefi Unveils New Eyefi Cloud Service Th...
Eyefi Unveils New Eyefi Cloud Service That Allows Users to Share Media Across Personal Devices Posted by Tre Lawrence on April 18th, 2014 [ permalink ] | Read more »
Tales from the Dragon Mountain: The Lair...
Tales from the Dragon Mountain: The Lair Review By Jennifer Allen on April 18th, 2014 Our Rating: :: STEADY ADVENTURINGiPad Only App - Designed for the iPad Treading a safe path, Tales from the Dragon Mountain: The Lair is a... | Read more »
Yahoo Updates Flickr App with Advanced E...
Yahoo Updates Flickr App with Advanced Editing Features and More Posted by Tre Lawrence on April 18th, 2014 [ permalink ] | Read more »
My Incredible Body - A Kid's App to...
My Incredible Body - A Kid's App to Learn about the Human Body 1.1.00 Device: iOS Universal Category: Education Price: $2.99, Version: 1.1.00 (iTunes) Description: Wouldn’t it be cool to look inside yourself and see what was going on... | Read more »
Trials Frontier Review
Trials Frontier Review By Carter Dotson on April 18th, 2014 Our Rating: :: A ROUGH LANDINGUniversal App - Designed for iPhone and iPad Trials Frontier finally brings the famed stunt racing franchise to mobile, but how much does its... | Read more »
Evernote Business Notebook by Moleskin I...
Evernote Business Notebook by Moleskin Introduced – Support Available in Evernote for iOS Posted by Tre Lawrence on April 18th, 2014 [ permalink ] | Read more »

Price Scanner via MacPrices.net

Deal Alert! 13-inch MacBook Pro on sale for $...
Best Buy has the 13″ 2.5GHz MacBook Pro on sale for $999.99 on their online store. Choose free shipping or free instant local store pickup (if available). Their price is $200 off MSRP. Price is valid... Read more
Free HopTo 2.2 Helps Enhance Your Productivit...
The HopTo app helps you do more on your iPad by providing more and easier adaccess to files and documents. Version 2.2 adds Egnyte and HopTo’s Mac OSX File Connector. If you already have the hopTo... Read more
National Distracted Driving Awareness Month:...
As the country recognizes National Distracted Driving Awareness Month, Sprint is reminding wireless consumers to focus on driving while behind the wheel, to not text or email while driving, and to... Read more
13-inch 2.4GHz Retina MacBook Pro available f...
Abt has the 13″ 2.4GHz 128GB Retina MacBook Pro available for $1229 including free shipping. Their price is $70 off MSRP. Read more
iMacs on sale for up to $160 off MSRP this we...
Best Buy has iMacs on sale for up to $160 off MSRP for a limited time. Choose free home shipping or free instant local store pickup (if available). Prices are valid for online orders only, in-store... Read more
iPad Airs on sale this weekend for up to $100...
Best Buy has WiFi iPad Airs on sale for $50 off MSRP and WiFi + Cellular iPad Airs on sale for $100 off MSRP on their online store for a limited time, with prices now starting at $449. Choose free... Read more
Apple restocks refurbished Mac minis starting...
The Apple Store has restocked Apple Certified Refurbished Mac minis for up to $150 off the cost of new models. Apple’s one-year warranty is included with each mini, and shipping is free: - 2.5GHz Mac... Read more
Hyundai Brings Apple CarPlay To The 2015 Sona...
Hyundai Motor America has announced it will bring Apple CarPlay functionality to the 2015 Sonata. CarPlay is pitched as a smarter, safer and easier way to use iPhone in the car and gives iPhone users... Read more
Updated iPads Coming Sooner Than We Had Thoug...
MacRumors, cites KGI securities analyst Ming Chi Kuo, well-respected as an Apple product prognisticator, saying that Apple will introduce an upgraded iPad Air and iPad mini in 2014/Q3, meaning the... Read more
Toshiba Unveils New High And Low End Laptop M...
Toshiba has announced new laptop models covering both the high-end and low-end of the notebook computer spectrum. Toshiba 4K Ultra HD Laptop Toshiba’s new Satellite P55t features one of the world’s... Read more

Jobs Board

*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Inc. Research Data Specialist - Appl...
…of Worldwide Market Research & Intelligence. The team is responsible for conducting Apple branded consumer market research. It is also responsible for analyzing data Read more
*Apple* Automotive Parts Department position...
Apple Automotive is one of the fastest growing dealer…and it shows. Consider making the switch to the Apple Automotive Group today! At Apple Automotive, we Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Retail - Manager - Holyoke - Apple I...
Job Summary Keeping an Apple Store thriving requires a diverse set of leadership skills, and as a Manager, you’re a master of them all. In the store’s fast-paced, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.