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
$95.60
Apple Inc.
-2.55
MSFT
$43.16
Microsoft Corpora
-0.42
GOOG
$571.60
Google Inc.
-15.82

MacTech Search:
Community Search:

Software Updates via MacUpdate

OneNote 15.2 - Free digital notebook fro...
OneNote is your very own digital notebook. With OneNote, you can capture that flash of genius, that moment of inspiration, or that list of errands that’s too important to forget. Whether you’re at... Read more
iStat Menus 4.22 - Monitor your system r...
iStat Menus lets you monitor your system right from the menubar. Included are 8 menu extras that let you monitor every aspect of your system. Some features: CPU -- Monitor cpu usage. 7 display... Read more
Ember 1.8 - Versatile digital scrapbook....
Ember (formerly LittleSnapper) is your digital scrapbook of things that inspire you: websites, photos, apps or other things. Just drag in images that you want to keep, organize them into relevant... Read more
OmniPlan 2.3.6 - Robust project manageme...
With OmniPlan, you can create logical, manageable project plans with Gantt charts, schedules, summaries, milestones, and critical paths. Break down the tasks needed to make your project a success,... Read more
Command-C 1.1.1 - Clipboard sharing tool...
Command-C is a revolutionary app which makes easy to share your clipboard between iOS and OS X using your local WiFi network, even if the app is not currently opened. Copy anything (text, pictures,... Read more
Knock 1.1.7 - Unlock your Mac by knockin...
Knock is a faster, safer way to sign in. You keep your iPhone with you all the time. Now you can use it as a password. You never have to open the app -- just knock on your phone twice, even when it's... Read more
Mellel 3.3.6 - Powerful word processor w...
Mellel is the leading word processor for OS X and has been widely considered the industry standard since its inception. Mellel focuses on writers and scholars for technical writing and multilingual... Read more
LibreOffice 4.3.0.4 - Free Open Source o...
LibreOffice is an office suite (word processor, spreadsheet, presentations, drawing tool) compatible with other major office suites. The Document Foundation is coordinating development and... Read more
Freeway Pro 7.0 - Drag-and-drop Web desi...
Freeway Pro lets you build websites with speed and precision... without writing a line of code! With it's user-oriented drag-and-drop interface, Freeway Pro helps you piece together the website of... Read more
Drive Genius 3.2.4 - Powerful system uti...
Drive Genius is an OS X utility designed to provide unsurpassed storage management. Featuring an easy-to-use interface, Drive Genius is packed with powerful tools such as a drive optimizer, a... Read more

Latest Forum Discussions

See All

Dawn of the Immortals Review
Dawn of the Immortals Review By Jennifer Allen on July 31st, 2014 Our Rating: :: RESPECTABLE EXPLORATIONUniversal App - Designed for iPhone and iPad Dawn of the Immortals might not re-invent the wheel, but it does tweak it a little... | Read more »
80 Days Review
80 Days Review By Jennifer Allen on July 31st, 2014 Our Rating: :: EPIC ADVENTUREUniversal App - Designed for iPhone and iPad A fantastic and fascinating re-envisioning of the classic novel by Jules Verne, 80 Days is a delightful... | Read more »
Battleheart Legacy Guide
The world of Battleheart Legacy is fun and deep; full of wizards, warriors, and witches. Here are some tips and tactics to help you get the most enjoyment out of this great game. | Read more »
Puzzle Roo Review
Puzzle Roo Review By Jennifer Allen on July 31st, 2014 Our Rating: :: PUZZLE-BASED TWISTUniversal App - Designed for iPhone and iPad A different take on the usual block dropping puzzle game, Puzzle Roo is quite pleasant.   | Read more »
Super Crossfire Re-Release Super Crossfi...
Super Crossfire Re-Release Super Crossfighter Coming Soon, Other Radiangames Titles Go 50% Off Posted by Ellis Spice on July 31st, 2014 [ | Read more »
Hexiled Review
Hexiled Review By Rob Thomas on July 31st, 2014 Our Rating: :: HEX SELLSUniversal App - Designed for iPhone and iPad In space, no one can hear you… spell? Hexiled is a neat concept for a word scramble puzzle, but it doesn’t go too... | Read more »
Summoners War: Sky Arena Passes 10 Milli...
Summoners War: Sky Arena Passes 10 Million Installs! Posted by Jessica Fisher on July 31st, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Deep Loot Review
Deep Loot Review By Jennifer Allen on July 31st, 2014 Our Rating: :: DIVE DEEPUniversal App - Designed for iPhone and iPad Dive deep in this fun explore-em-up that’s a little grind heavy but ultimately quite entertaining.   | Read more »
Despicable Me: Minion Rush is One Year O...
Despicable Me: Minion Rush is One Year Old, Gets its Biggest Update Yet Posted by Jennifer Allen on July 31st, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Fish & Shark Review
Fish & Shark Review By Jordan Minor on July 31st, 2014 Our Rating: :: FLAPPY FISHUniversal App - Designed for iPhone and iPad Fish & Shark’s beauty is only scale deep.   | Read more »

Price Scanner via MacPrices.net

Save up to $130 on an iPad mini with Apple re...
The Apple Store has Certified Refurbished 2nd generation iPad minis with Retina Displays available for up to $130 off the cost of new models, starting at $339. Apple’s one-year warranty is included... Read more
iPad Cannibalization Threat “Overblown”
Seeking Alpha’s Kevin Greenhalgh observes that while many commentators think Apple’s forthcoming 5.5-inch panel iPhone 6 will cannibalize iPad sales, in his estimation, these concerns are being... Read more
Primate Labs Releases July 2014 MacBook Pro P...
Primate Labs’ John Poole has posted Geekbench 3 results for most of the new MacBook Pro models that Apple released on Tuesday. Poole observes that overall performance improvements for the new MacBook... Read more
Apple Re-Releases Bugfixed MacBook Air EFI Fi...
Apple has posted a bugfixed version EFI Firmware Update 2.9 a for MacBook Air (Mid 2011) models. The update addresses an issue where systems may take longer to wake from sleep than expected, and... Read more
Save $50 on the 2.5GHz Mac mini, plus free sh...
B&H Photo has the 2.5GHz Mac mini on sale for $549.99 including free shipping. That’s $50 off MSRP, and B&H will also include a free copy of Parallels Desktop software. NY sales tax only. Read more
Save up to $140 on an iPad Air with Apple ref...
Apple is offering Certified Refurbished iPad Airs for up to $140 off MSRP. Apple’s one-year warranty is included with each model, and shipping is free. Stock tends to come and go with some of these... Read more
$250 price drop on leftover 15-inch Retina Ma...
B&H Photo has dropped prices on 2013 15″ Retina MacBook Pros by $250 off original MSRP. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.3GHz Retina MacBook Pro: $2249, $250 off... Read more
More iPad Upgrade Musings – The ‘Book Mystiqu...
Much discussed recently, what with Apple reporting iPad sales shrinkage over two consecutive quarters, is that it had apparently been widely assumed that tablet users would follow a two-year hardware... Read more
13-inch 2.5GHz MacBook Pro on sale for $999,...
Best Buy has the 13″ 2.5GHz MacBook Pro available for $999.99 on their online store. Choose free shipping or free instant local store pickup (if available). Their price is $100 off MSRP. Price is... Read more
Save up to $300 on an iMac with Apple refurbi...
The Apple Store has Apple Certified Refurbished iMacs available for up to $300 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free. These are the best prices on... Read more

Jobs Board

*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
Sr. Product Leader, *Apple* Store Apps - Ap...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
Sr Software Lead Engineer, *Apple* Online S...
Sr Software Lead Engineer, Apple Online Store Publishing Systems Keywords: Company: Apple Job Code: E3PCAK8MgYYkw Location (City or ZIP): Santa Clara Status: Full Read more
Sr Software Lead Engineer, *Apple* Online S...
Sr Software Lead Engineer, Apple Online Store Publishing Systems Keywords: Company: Apple Job Code: E3PCAK8MgYYkw Location (City or ZIP): Santa Clara Status: Full 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.