TweetFollow Us on Twitter

Rhapsody In Purple

Volume Number: 14 (1998)
Issue Number: 3
Column Tag: Rhapsody

Rhapsody in Purple

by Karl Kraft

An overview of the several ways to patch applications in Rhapsody, with various levels of bravery

Overview

Rhapsody may have an OS 8 look and feel, but under the hood it is running a completely different engine. While this new engine may sweep away some of our most beloved Mac items, like loadable "system" code in the form of INITs and CDEVs, their Rhapsody equivalents are by no means non-existent, or even difficult to implement. In fact modifications to the system and to applications under Rhapsody can be done in a clean and safe manner using high level constructs.

This article seeks to explain how a Rhapsody application comes to have a particular look and feel, and ultimately how to modify the look and feel of not only your applications, but all applications on the system. The overall effect of the source in the article is to change the background color of windows to an awful shade of purple.

How Programs Launch in Rhapsody

When a user thinks of an application, he usually thinks of a single software package, such as "ClarisWorks", which is actually a collection of templates, fonts, applications, help files, and other miscellaneous items.

When most developers thinks of an application, the target is more specific, usually a single binary image that contains executable code. Under Mac OS, this executable would also have a resource fork with various resources bound to the application.

Under Rhapsody, an application consists of many more parts, each of which is either executed or interpreted by the system as a whole. The most basic parts are:

  1. The executable file, which includes loading instructions for individual processor families, and basic information such as the application's icon. Under Rhapsody, this comes in a format called "mach-o".
  2. Resources in the form of images, property-lists, string files, and others.
  3. NeXT Interface Builder or "nib" files, that define the layout and connection of objects in the interface.
  4. Various frameworks and dynamic libraries supplied by Apple Computer, such as AppKit, Foundation and System.
  5. The Window Server, a separate program that handles all the drawing and PostScript imaging.
  6. The many utility and server programs that run on the machine such as AKServer (short for AppKit Server), a program that helps handle the pasteboard.
  7. The mach kernel and underlying operating system.

Together these pieces offer you, the Macintosh hacker, dozens of places where a patch can be applied both for your projects, and applications delivered in a compiled form.

Simple Non-Code Patches

Even if you aren't a programmer, you shouldn't have much trouble figuring out how to use interface builder to modify an application. This can be useful when a sysadmin type desires to remove functionality from an application, or perform interface butchery.

Using Viewer, the Rhapsody equivalent to Finder, select an application such as Terminal.app. For this example, pretend that you have have been ordered to prevent users from changing their preferences in this application. Note: Defaults can be changed in ways besides the preferences panel, but the type of people who would try this stunt would seldom think out the total impact of their interface butchery.

Start by making a copy of Terminal.app, and storing it in a safe place. You might need it to recover from your actions.

Terminal.app is actually a folder that contains the various resources and executable pieces of the Terminal application. Through the magic of Viewer, folders with the .app extension appear as single files. You can invoke stronger magic by selecting Terminal.app, and then picking "Open As Folder" from Viewer's File menu. This should reveal a folder with three items, a file called Terminal, which is the actual executable image, a folder with a header file for communicating with Terminal, and a folder called Resources. The Resources folder contains all the resources for the application, such as images, nib files, string files, and property lists.

Descending into the Resources folder, you should find a folder titled English.lproj. The lproj extension indicates a language project, which contains all the localizable items for this application. This is often just about every resource in the application. Even images are localizable, because the concept they represent can be conveyed differently in each language. An image of a dollar sign might be localized to a Yen symbol for the Japanese language project.

Inside English.lproj you strike paydirt, a nib file that is cleverly named Terminal.nib. You can open this nib file in interface builder by double clicking on the nib file icon.

Note: Terminal.app and all the resources grouped with it are not modifiable by a regular user. You need to be either logged in as root, or working on a copy of Terminal.app that belongs to you.

Using Interface Builder, you can navigate through the Terminal menu structure until you find the Preferences menu item. Since nib files contain not only interface objects but also their connections, you can discover what method is called when this menu item is clicked. Using the Inspector, and selecting connections, you should discover that it is connected to the File's Owner object, and calls the method preferences:.

Simply picking disconnect from the connections inspector will render this item impotent, leaving a boring menu item that does nothing. Perhaps a dash of purple will help spice up things . Using Interface Builder, you can add a panel to the application, with some nice purple text, that says "This item is disabled". You can see a sample of my panel in Figure 1.

Figure 1.

Hold down the control key, and drag a line from the Preferences menu item to the title bar of the newly created panel, and the connection inspector will appear. Set the connection to makeKeyAndOrderFront:.

Now save all your mischief and give it a try. If you did it right, picking Preferences should bring up your new preferences panel, and frighten the user from every picking an un-authorized menu item again.

You can edit just about any resource in this manner. Images, property lists, and other resources can be modified by simply using the appropriate editor. You can also use this technique to localize an application that has not been localized to a desired language by the developer. Simply copy English.lproj to Esperanto.lproj, and edit away. The changes you make in Esperanto.lproj will be seen by any user whose default language choice is set to Esperanto before English.

Color Me Purple All Over

What if you desire a more drastic change? What if you want all the windows in your application to have a purple background? One option would be to carefully check every time a window is created, and set its background color to purple.

In a small application that might work. A few windows means a few lines of code. However, I know of several OPENSTEP applications that have on the order of several hundred nib files, and hundreds of windows that can be created on the fly. Such a manual technique would be troublesome, because you would eventually miss a window, and its gray background would just look atrocious compared to all the glorious purple windows spread across the screen.

There is a better way, and in this example, you will convert TextEdit to produce purple panels and windows. While you read this next section, grab a copy of the source to TextEdit from /NextDeveloper/Examples/AppKit/ from the Rhapsody Developer Release, and start the project building.

One of the great advantages of Objective-C is the ability to completely override a class by a technique known as posing. In posing, a class (ie: PurpleWindow) assumes the identity of its superclass, such as NSWindow. In Figure 2 a simple class tree shows where NSPanel and PurpleWindow are both subclasses of NSWindow. After PurpleWindow begins posing as NSWindow, the class tree is changed to that of Figure 3.

Figure 2.

Figure 3.

By using this technique, you can not only subclass an existing class, but make the implementation of your class the default implementation for the super class and all it's subclasses. This saves you from the trouble and difficulty of having to write a separate subclass for NSWindow, NSPanel, and other windows that you may not even know exist.

To see this in action, use ProjectBuilder to create a new class called PurpleWindow. ProjectBuilder will create two files for you, an .m file (methods) and an .h file (headers). A quick look at the header shows that ProjectBuilder thinks PurpleWindow is a subclass of NSObject rather than NSWindow. Edit the header file to read:

#import <AppKit/AppKit.h>
implementation PurpleWindow:NSWindow
@end

Now the question is, how do you get PurpleWindows to have a purple background? If you think that the compiler should just figure it out from the prefix of "Purple", you are going to be sorely disappointed. You need to pick some method of NSWindow, override it, and then call a method to set the purple color. For starters, write the method that sets the background color to purple.

-(void)becomePurple;
{
  [self setBackgroundColor:[NSColor purpleColor]];
}

Now all that is left is to call becomePurple sometime early in the creation of a window, before it is displayed. A particularly tempting target is makeKeyAndOrderFront:. This method is called to put a window on screen, and make it the key window (the window which accepts keyboard events). So you should dutifully write:

-(void) makeKeyAndOrderFront:sender;
{
  [self becomePurple];
  [super makeKeyAndOrderFront:sender];
}

Now whenever a PurpleWindow receives the makeKeyAndOrderFront: message it should change its background color to purple, and then have NSWindow actually put the window on screen.

Note: makeKeyAndOrderFront: probably isn't the best place to actually make this patch. I picked it as an example because it is well known, quick and easy for developers to understand.

If you typed everything correctly, you should be able to compile your new modified TextEdit, and give it a test. The change should have absolutely no effect at this point. Simply creating a subclass of NSWindow does not make it automatically pose as NSWindow, nor does it cause all windows to become PurpleWindows. At this point, the only way you will get a PurpleWindow, is if you create one in InterfaceBuilder, or programmitcally.

To start the actual posing takes a single line:

[PurpleWindow poseAsClass:[NSWindow class]];

Your decision at this point is where to insert this line in your project. After you start the posing, all calls to NSWindow methods will instead be sent to PurpleWindow. Because of this, the ideal circumstance is to perform the posing before any NSWindow objects are created. This will guarantee that all NSWindow objects in your application are actually PurpleWindow objects.

The earliest point in the execution of your application would be the function main(), found in the file Edit_main.m. By making this line the first line in main(), it will take place before any objects are created. Inserting this early in main() produces:

#import <AppKit/NSApplication.h>
#import "PurpleWindow.h"

int main(int argc, const char *argv[]) {
  [PurpleWindow poseAsClass:[NSWindow class]];
 return NSApplicationMain(argc, argv);
}

Build the project again, run and test. You should find that document windows have no noticeable change. At first this may disappoint you, but the reason is that the white background of the document window comes from the NSText object that completely covers the background. You will need to look at windows with some background visible, such as the Info panel, the Preferences panel, and the Find panel. These should look like Figure 4.

Figure 4.

Posing can be a valuable tool, and a dangerous weapon. Careless and unnecessary use can make programs difficult to debug and create strange effects. If all you need is some purple windows for your application, you would probably be better off with just using a subclass. Reserve the power of posing for patching class that you lack source for, such as the Appkit, and always keep the posing down to a minimum.

Posing in a Friendly Executable

If you can pose in your application, can you pose in an application where the source is not available? To pose, you need:

  1. Your class to be linked into the target application.
  2. A call relatively early on, where you can engage the actual posing action.

Some applications will make this task easy for you. These "friendly" applications support the loading and linking of dynamic code in the form of bundles. Examples include ProjectBuilder, InterfaceBuilder, Viewer, and Mail. All of these applications load bundles in one form or another.

For the next example, the goal is to make windows in the ProjectBuilder application use the same PurpleWindow as we used in TextEdit, but this time I'll assume you don't have the complete source to ProjectBuilder or Yellow Box.

The application ProjectBuilder, supports the ability to load Bundles of code and resources than can receive a notification when a project is opened, closed, an other various useful things.

A bundle is much like an INIT in that it offers a section of executable code and resources like images, all packaged as a single unit. The biggest difference between these two is that an INIT contains code to patch the Macintosh System on startup, and a bundle contains loadable code for a single application. Another difference is that the loading of INITs happens automatically, provided that they are in the proper place. Bundles are usually only loaded by applications that explicitly look for them.

Bundles are created using the same tools, and a process very similar to building applications. You start by creating a new Project in Project Builder, but pick the type Bundle instead of Application. You can then add and edit classes to your bundle, build, and test.

For the building of ProjectBuilder bundles, the task is made a little easier by a preference template that can be found at http://www.ensuing.com/~karl/RhapHack/RhapBundle.html. This template is a ProjectBuilder bundle ready for use in ProjectBuilder, with a default interface and class that only needs a small portion of work to be useable. To start, copy the template project to some place convenient, like your home directory, and then open it in ProjectBuilder. This type of project does not have nay interface, so all the work is done in ProjectBuilder.

You now need to edit the basic class. As you can see there are several methods already created for the template that perform the basic task of grabbing information from the ProjectBuilder application and setting up the notification center to call methods on certain events. One of these methods is called setup:. According to the documentation, this method is called when the PBBundleHost first loads the bundle. This looks like a good place to start your PurpleWindow posing as NSWindow. Insert this simple code snippet in the method builderStarted:

+(void)builderStarted;
{
 [PurpleWindow poseAsClass:[NSWindow class]];
}

You will also need to add PurpleWindow.h to the list of headers imported by the PBTemplate class. Add this line at the top of the file PBTemplate.m.

#import "PurpleWindow.h"

Don't forget to add PurpleWindow to the list of classes to be compiled into this Bundle. You can add it to the project by selecting the classes suitcase in the current project, and then dragging PurpleWindow.m from the Workspace, or the PupleWindow application, to the classes suitcase.

If everything was done correctly, you should be able to build the application with no warnings or errors. If it worked, use the options button in the build panel to change the build type from "bundle" to "install". This will copy the bundle to ~/Library/ProjectBuilder.

Now that the bundle has been installed you can add it to the list of bundles that PBBundleHost will load by selecting Bundles in the Preferences panel of Project Builder. It won't be loaded right away though, you need to quit ProjectBuilder and relaunch in order for the bundle to be loaded.

When you launch ProjectBuilder, you should be able to bring up the Find panel and it should have a purple window as shown in Figure 5. If not, something is wrong. Check to make sure that the project was built and installed correctly, and that all the source code changes have been made to the bundle.

Figure 5.

If you play with this new creation for a while, you will notice a few important things related to the goals stated in the very beginning of this journey:

The first is that it works. It is possible to write code that significantly modifies an application's framework even if you do not have source for the framework, or the application. We were able to patch at the level of the high-level framework, rather than at a low-level machine trap.

It is a clean patch. The code doesn't have to patch a half-dozen points to constantly detect windows and convert the background to purple. And the patch only applied to the application that loaded it. It is easy to see that if the bundle was bogus, it would only affect the single application that loaded it.

Application or Bundle, the code was identical. PurpleWindow wasn't modified in this example at all. You merely copied it from a previous project. This is part of what made it such a clean patch. You can design new classes to augment the AppKit in an application, and then apply these classes to other applications.

The patch fell short in two very important goals:

The patch only applies after the bundle is loaded. In the case of ProjectBuilder, this was before any windows were created. However an application like Preferences does not load the executable code from the bundle until it is actually needed. A system wide PurpleWindow patch is not going to do much good if the user has to push a button in every app to get it going.

The patch only applies to ProjectBuilder, which is a "cooperative" application. You still don't have a way to get the executable code of the bundle linked into just any running application. Even the actual API for how a bundle interacts with an application is different for each application, so the bundle you have created works only in ProjectBuilder.

Both of these problems can be easily solved if programmers would band together and create a common API, and agree to have a common directory where bundles could be located. Similarly, world peace could be easily achieved if you just get the leaders of the world to agree on a few things. There are more developers than world leaders.

An Exploitable Link

This article started with a list of what makes up an application, and indicated that each of these was a target point for modification. So far you have modified the resources, interface files, and the executable itself in source code form. While each of these points has advantages and can help in the overall goal, they don't deliver the ideal hoped for: a patch to all applications that run on the system. If there is a way to make patch every application, it must lay in the other items, such as the frameworks, window server, server programs, or the kernel.

The kernel has facilities to allow loadable code and drivers, similar to the way that Preferences allows you to load bundles, and since every program links to the kernel, it seems like the ideal place to find the abilities required for this venture. However, developing source code that dynamically loads into the kernel takes a great deal of discipline, and debugging takes a great deal of patience and usually two machines. Also since code running in the kernel space can do anything, a much greater chance exists to trash your operating system beyond repair.

Server programs like AKServer primarily serve in interprocess communication between applications and in providing system resources. They have no facility for loadable code, which results in a more difficult patch. They are not going to do much to bring us closer to the goal.

With a little work, functions can be sent to the WindowServer, however they must be written in PostScript, and they tend to be limited to affecting how the drawing or windows are presented, such as changing the shape or color of the cursor.

This leaves frameworks, which also have no provision for loading code. However, there is a weak point in how frameworks are loaded that can be exploited.

How Frameworks Work

In the final step of compiling any Rhapsody program, the linker is passed a list of frameworks that the program requires for execution. This list is then embedded within a portion of the executable file. When a file is passed to the operating system for execution, it finds the needed frameworks, dynamically links them to the executable, and then actually executes the program. If a common framework was replaced with a framework that loaded bundles, it should be possible to make any application behave as a cooperative application like ProjectBuilder.

To find out what Frameworks are common, you can examine various applications using the AppEdit application, or the command line tool "otool". Casual examination shows that three frameworks are used by every application. These three frameworks are called System, Foundation, and Appkit, and are all located in /NextLibrary/Frameworks.

The System framework encompasses all basic operating system calls, such as read() and write(). If this framework was modified, it would affect not only applications but every executable file including command line tools and startup procedures. Patching this framework is possible, but an error could be difficult to recover from. Without a valid System.framework, your computer can not even start up.

The next possible framework is Foundation. While not used by as many command line programs, it is used by some, and therefore has many of the same problems as System.framework.

That leaves AppKit.framework, which is a good choice overall. There are no boot programs depending on it, and if you totally destroy the framework, it is possible to repair the damage by booting into single-user mode. Appkit.framework also make sense, as most patches would be targeted towards applications' look and feel. It also has another benefit missing from Foundation and System. To patch applications. you need to load bundles at some point early in the application's life. One of the very first objects instantiated in an application is the NSApplication class, and this class lives in Appkit.framework. Of course, it is possible to make the patches in the System or Foundation frameworks, just with a greater risk.

It would be possible to patch the actual binary code of the Appkit framework, however, such a low level patch is not needed. Instead you can move the Appkit framework to a new location, and then create a new "patch" framework. If the "patch" framework is placed where the operating system looks for Appkit.framework, then launched applications will bind to the "patch" framework, if the patch Framework is compiled to depend on the new Appkit framework in its new location, both the patch framework, and the Appkit framework would be loaded whenever a new application is launched.

The Adventure Begins

This procedure is not for the weak, timid, tired, forgetful or easily worried. Don't try this on a system that has important data. You would be well advised to read this entire section from start to finish and understand it before placing your fingers on the keyboard. Also, between the time this was written and the time you read it, the layout of files may have changed drastically, check the Ensuing web site for any errata. Above all else, don't come complaining to me when you find your system no longer boots.

In this process you will end up with three frameworks:

  • OldKit. This is the original AppKit as supplied by Apple, modified to run as either AppKit or OldKit.
  • NewKit. This will be the new version of AppKit that you make using Project Builder.
  • AppKit. This is what the system thinks is the one true AppKit and can be toggled back and forth between OldKit and NewKit.

Moving the Appkit framework ( or any important framework) is a quick way to disable a system, but it is necessary to get things rolling. You will need to either login as root, or become root using the superuser command. As root, and using the command line, execute the following commands:

cd /NextLibrary/Frameworks

This will get your current working directory to be the place for the rest of these commands.

mkdir OldKit.framework

This creates a new folder called OldKit that will hold the original Appkit.

 (cd AppKit.framework; gnutar -cf - . ) | (cd OldKit.framework; gnutar -xf - ) 

This whopper of a command copies the contents of AppKit to OldKit, and preserves as much of the directory structure as possible. Frameworks tend to have a great deal of links, and using the copy command will use more than twice the disc space. This command may take several minutes depending on how speedy your hard drives are.

cd OldKit.framework

Change into the OldKit framework for the rest of the commands

ln -s Versions/B/OldKit OldKit

This creates an alias called OldKit in the current directory that links to where the actual copy of OldKit will reside.

cd Versions/B
cp AppKit OldKit

This copies the file AppKit to OldKit. This is done so that you can have a pristine copy of AppKit when AppKit.framework is linked to OldKit.framework.

At this point OldKit.framework would seem to be ready to go, however there is a small bit of binary editing that needs to be done first. When applications are compiled to use OldKit, the actual OldKit file you just created will be examined, and inside is a string that identifies the path to this framework, which is still set to AppKit. To see this string you can type the command

otool -L OldKit

You must change this string so that NewKit can successfully link to OldKit. To change the string use a hex editor like HexEdit or you can download a program called App2Old that specifically patches AppKit to OldKit at ftp://ftp.ensuing.com/xxxxxx. After you edit the file, use otool to make sure the change was made.

Now that this has been done, you have a new framework called OldKit that is functionally identical to AppKit, just with a different name. In the mean time, the original AppKit framework still exists, and applications launched at this point still use the AppKit.framework.

You now need to create a new AppKit framework that accomplishes two tasks.

  1. 1. Augment the Applications class to activate the posing.
  2. 2. Link to OldKit, so that original AppKit classes are available at runtime.

The framework is created in much the same way as an Application or bundle. From ProjectBuilder, create a new project, and select the type of Framework. You then need to edit several variables and configuration files to prepare the project for compiling. Add the OldKit framework by adding it to the frameworks suitcase. Edit the file Makefile.postamble and change the following lines, so that the versions of this kit match the original AppKit.

DEPLOY_WITH_VERSION_NAME = B
COMPATIBILITY_PROJECT_VERSION = 45
CURRENT_PROJECT_VERSION = 45

You now need to find a convenient place to start the posing. A framework does not have a main() function, so you need some Objective-C method called early in the life of the Application. The ideal choice is to make an initialize method for your posing category of Application.

While not the very first method called in the life of an application, it does happen very early, and usually before any nibs are loaded. Create a new class file called Application_Patch.m, and modify the header to be a category of Application. The add an implementation of the method initialize to the m file.

***Application_Patch.h***

@interface Application(Patch)
@end

***Application_Patch.m***
@implementation Application(Patch)
+(void)initialize;
{
  [PurpleWindow poseAsClass:[NSWindow clas s]];
}
@end

The final source for this project, is the familiar PurpleWindow class, which you can copy from the previous example used in ProjectBuilder. If you compile and install, you should find a new framework in ~/Library/Frameworks called AppKit.framework, this is the patched AppKit.framework. Using AppEdit or otool, you should be able to see that this framework relies on the OldKit framework.

You are now ready to install this new framework as the default AppKit framework. By running these commands you can put your machine in to a very unstable state. Since you will be removing the AppKit to a new location, the system will be unable to find any AppKit resources that it may need, such as an open, save or font panels. If you try to use any system resources in AppKit.framework that are not already loaded, you may find that you program hangs.

From the command line type the following as root:

cd /NextLibrary/Frameworks
cp -r ~/AppKit/AppKit.framework NewKit

This copies NewKit from your personal library to the system library.

mv AppKit.framework safety
This moves AppKit.framework to a folder named safety

ln -s NewKit AppKit.framework

This creates an alias for NewKit called AppKit.framework,

At this point you should be able to launch new applications and find that familiar, yet somewhat sickening shade of purple. If Applications won't launch any more, relink AppKit to OldKit, and then proceed to debug by checking the console for messages.

Don't play around too much. The system at this point is still very unstable. When the current running applications were launched, (like Viewer, ProjectBuilder, Terminal), they started using AppKit.framework to load system resources. Those resources are now in OldKit, and if you try to print, open or save files, or anything else that needs a system resource, you may be lucky to get an error message, more likely you will wedge things pretty bad.

It would seem therefore that if you logged out and logged in, or rebooted, your entire system would be patched and you would be done. However, some of the early login process requires resources in Appkit.framework, and they are not forgiving about the fact that the AppKit is not there. If you reboot at this point you will not be able to login.

That said, you can fix this minor problem by changing the Resources directory of NewKit to point to the Resources of OldKit.

cd /NextLibrary/Frameworks/NewKit
rm -rf Resources
ln -s ../OldKit/Resources Resources

After rebooting, everything should return to "normal", and you should have a very purple operating system to play with. Congratulations.

Closing

When I originally wrote this hack during MacHack '97, it actually worked a bit differently. Instead of the patches being part of the patched AppKit, they were loadable bundles in much the same way as ProjectBuilders loadable bundres. A front end called HackManager allowed the user to pick which patches were applied to which applications. While the overall design was more flexible, and enabled the user to turn off the patch (something missing from this example), it suffered a great deal from slow launching applications. Each time an application was loaded, several dozen bundles would have to be read into memory as well, and then applied to the running application.

Hopefully, Apple will develop some plan for dealing with system wide patches like the example given. However, their most recent FAQ on Rhapsody suggests that the entire idea of modifying the system as a whole is going to be avoided.


Karl Kraft, Karl_Kraft@ensuing.com, has written several applications for OPENSTEP, the operating system on which Rhapsody is based, and is currently working on The CodeBook, an interactive book for learning the Yellow Box framework.

 
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

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
Save up to $270 with Apple refurbished 13-inc...
The Apple Store has Apple Certified Refurbished October 2013 13″ Retina MacBook Pros available starting at $1099, with models up to $270 off MSRP. Apple’s one-year warranty is standard, and shipping... Read more

Jobs Board

*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
*Apple* Retail - Manager - Apple (United Sta...
Job SummaryKeeping 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, dynamic 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
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.