TweetFollow Us on Twitter

Jan 98 Factory Floor

Volume Number: 14 (1998)
Issue Number: 1
Column Tag: From The Factory Floor

CodeWarrior Latitude: Porting Your Apps to Rhapsody

by Dave Mark, ©1997 by Metrowerks, Inc., all rights reserved.

The June, 1997 Factory Floor column contained an interview with David Hempling, CodeWarrior Latitude engineering lead. You can find the interview at: http://www.metrowerks.com/products/cw/latitude/index.html.

For those who missed the interview, CodeWarrior Latitude is essentially a porting library that greatly simplifies the process of porting MacOS applications to Rhapsody. Latitude is an implementation of the Macintosh System 7 application programming interfaces (APIs) that allows source code for a Macintosh application to be compiled with little modification on a Rhapsody platform, resulting in a native Rhapsody application. Latitude maps the Mac API requests to native Unix system calls. An application built with Latitude attains the look and feel of the new native platform. In this column we'll explore the process of using Latitude to port applications to Rhapsody.

A Simple Example

Let's start off with a simple example, straight from the pages of the Mac Primer, Volume II. ColorTutor allows you to play with the various Color Quickdraw drawing modes. Written in C, ColorTutor consists of a project file, a C source file, and a resource file containing MENU & WIND resources.

The first task in porting an application to Rhapsody is to physically get the application's files to the Rhaposdy platform. There are several ways to do this. For the source code itself, any means of transferring text files from one computer to another will do. If we had a collection of sources, we could tar them up with a tar tool on the Mac, ftp the tar file to Rhapsody with something like Fetch, and untar the image on the other side. This method cannot be used to transfer Mac resource data.

Another method would be to use one of several available UNIX/Mac file sharing systems such as MacNFS, NFS/Share, IPT uShare, Helios EtherShare, or Xinet K-AShare. Latitude's File Manager understands the various formats that these systems use so they are also good for transferring Mac resource data.

Before copying over the resource file, however, we must ensure that a BNDL resource is present in the application's resource data. Latitude requires the signature value in an application's BNDL resource in order to maintain its own "desktop database". ColorTutor.rsrc does not have a BNDL resource so we'll add one, using ResEdit, on the Mac. We'll make ColorTutor's signature 'CTTR'. That done, we'll build ColorTutor on the Mac, ensuring that all of the application's resources are collected into the application's executable.

For this example, we use NFS/Share to transfer the ColorTutor executable to our target platform. NFS/Share uses AppleDouble format, so the file will be split into two pieces when it is transferred, namely ColorTutor and %ColorTutor.

Once we've successfully transferred the file to our Rhapsody file system, we place %ColorTutor in a directory named:

$LATITUDE_ROOT/Latitude.MacFiles/Applications/ColorTutor/

$LATITUDE_ROOT is where Latitude was installed on our Rhapsody system. We place ColorTutor.c in the directory:

$LATITUDE_ROOT/Latitude.MacFiles/Applications/ColorTutor/Sources/

We can now prepare the ColorTutor.c file for compilation. Latitude includes a tool called prepare_sources that traverses your source files and replaces non-ANSI Mac-isms in your sources (such as pascal strings, eight-bit characters, and four character constants) with macros that conditionally expand to either the Macintosh or the ANSI styles, depending on where the build takes place. It also creates a Makefile usable with gnu make that can be used to build your application.

prepare_sources wants to know the name of the application we're creating and the type of system includes it is using:

% prepare_sources ColorTutor universal
Creating Latitude.manifest...
Converting source files to Latitude files.
mac2unix: processing ./ColorTutor.c
Writing default Makefile...
Conversion complete.

ColorTutor.c is copied to ColorTutor.c.bak, preserving the original code, and three files are created: the modified source ColorTutor.c, a Makefile, and Latitude.Manifest, which is a list of the source files used to create the application.

Looking at ColorTutor.c, we can see that prepare_sources replaced all "\p..." strings with PSTRINGCONST("...") macros. It also replaced four-character constants like 'DRVR' with the QUADCONST('D','R','V','R') macro. Even though some non-Mac compilers will handle a four character constant, the order of the characters in the resulting long can be flipped. By using QUADCONST(), we ensure that the proper ordering is achieved.

When compiled on the Mac, ColorTutor.c relied on the MacHeaders pre-compiled headers. Since we don't have pre-compiled headers on our non-Mac platform (yet), we must explicitly include MacHeaders in our source. A copy of the standard MacHeaders is included in $LATITUDE_ROOT/utilities, so we'll copy it to our ColorTutor/Sources and #include it at the top of ColorTutor.c

ColorTutor.c uses qd. to access Quickdraw low memory globals like thePort, screenBits, etc. CodeWarrior Latitude supports these globals but does not keep them in a qd structure. We can use a macro to remove qd. when it is used. At the top of ColorTutor.c, we add the following:

#ifdef _LATITUDE_
#define QD(x)   x
#else
#define QD(x)   qd.x
#endif

We now go through ColorTutor.c and replace instances of qd. with the use of the QD() macro. So

InitGraf( &qd.thePort );

becomes

InitGraf(&QD(thePort));

There are a few other instances in the file which we'll replace as well.

Before we build ColorTutor, we must insert code to initialize Latitude. The lg_latitude_init() call does several things. It sets up Latitude's trap table, initializes various toolbox managers, and opens Latitude's System file and the application's resource file. lg_latitude_init() also allows settings that affect how the application looks and behaves. For ColorTutor, only the bare minimum is required.

Currently, main() starts out like this:

void  main( void )
{
    ToolboxInit();
    MenuBarInit();

We're going to change main() to accept arguments and pass those arguments to lg_latitude_init:

#ifndef _LATITUDE_
void  main( void )
{
#else
void  main( long argc, char **argv )
{
#ifdef _LATITUDE_
    LG_APP_INFO_BLOCK lblock;

    lblock.flags = LG_APP_INFO_SIGNATURE |
                LG_APP_INFO_CLASSNAME;
    lblock.signature = QUADCONST('C','T','T','R');
    lblock.classname = "Latitude";
    lg_latitude_init(argc,argv, &lblock);
#endif

            ToolboxInit();
            MenuBarInit();

We're now ready to build ColorTutor. Using the gcc 2.7.2 compiler, this code compiles without error. However, if you're using a different C compiler, you may find that the C++ style '//' comments at the top of ColorTutor.c are a problem. If so, simply replace them with C style '/* */' comments and rebuild. The first time we run ColorTutor, Latitude brings up a Get File Dialog asking us to locate the application's resource file. This is only done once. Latitude stores the location of the resource file in it's own desktop database located at:

user.MacFiles/System/Preferences/LatitudeApps

Once that is done, ColorTutor is off and running on our platform. Playing with the app's popup menus and seeing the proper results in the dialog shows that this application was ported successfully with very little effort. Additionally, we can take this source code back to the Mac, along with the LGLatitude.h file, and continue to use the same source to build both our Mac and non-Mac platform versions.

PowerPlant

Obviously, ColorTutor is a very simple application that doesn't contain any serious portability problems. It's ANSI C code, contains no private resource data that it uses itself, doesn't patch traps, doesn't have custom definition functions, etc. Lets move on to a more complex porting example and look at what's required to bring a PowerPlant app, like Muscle, over to Rhapsody using CodeWarrior Latitude.

The first thing to notice about PowerPlant is that it's written in C++ and that its source code is laid out hierarchically in a directory structure. It's easy to replicate this structure on our new platform. The prepare_sources script currently only recognizes file extensions for C (.c & .h). It is easy to modify the 'find' incantation in prepare_sources to recognize the C++ file naming convention used in PowerPlant. prepare_sources is also fairly naive about complex development environments. Depending on your own expertise with Makefiles, you may decide to build the development environment yourself. You do need to run the conversion script, mac2unix, over the code to take care of the pascal strings and four character constants, however.

Inside the PowerPlant code itself, there are a few modifications we need to make.

Template Instantiation

Template instantiation is not standardized across C++ platforms. When we brought PowerPlant away from the Metrowerks environment, we entered a world where multiple instantiations of C++ templates needed to be handled differently.

There are two classic approaches to solving the instantiation issue: the Cfront and Borland models. In Cfront all instantiations occur in a single well-known directory. The Borland model, on the other hand, instantiates each template in each translation unit with duplicates being removed by the linker. Both techniques have serious flaws and have led to other approaches. The gcc compiler that we're using on Rhapsody, in particular, eschews these and provides instead 3 different techniques. The details of the problems encountered with all of these approaches will be deferred for a future article. In short, the only approach that worked was to:

  • disable implicit instantiation (compiler option)
  • disable explicit instantiations in header files
  • explicitly instantiate each template in each translation unit in which the linker complained

This solution is not optimal because the burden for template instantiation is placed on the programmer. Change the code or how the translation units are combined and you may have to change where the explicit instantiations are placed. But it does work. We hope that better automatic approaches are found in the future that eliminates the need for any explicit instantiation statements.

For example, we had to turn off any explicit instantiation statements that occurred in .h files (really a bad idea to begin with):

Pane_Classes/LView.h

  #if !defined(MW__GCC_EXPLICIT_TEMPLATE_INSTANTIATION)
  template class TArray<LPane*>;
  #endif

and then to make sure that source files that required the instantiations had them:

Pane_Classes/LView.cpp

  #if defined(MW__GCC_EXPLICIT_TEMPLATE_INSTANTIATION)
  template class TArray<LPane*>;
  template class TArrayIterator<LPane*>;
  #endif

Scripting & AEObject Support

Latitude's Apple event implementation is not complete. While basic Apple event calls are in place, AEObject support is not. PowerPlant uses AEObjects to record user actions as well as trigger window management, such as taking a window down or allowing a window to be dragged. PowerPlant's AEObject code is centralized and it was clear where an event was dispatched and where it was picked up. We modified the code to perform the end result directly, without going through the AEObject dispatching mechanism.

For example, PowerPlant's LWindow::AttemptClose() function now looks like this:

void
LWindow::AttemptClose()
{
   // Get approval from SuperCommander
   if ((mSuperCommander == nil) 
      || mSuperCommander->AllowSubRemoval(this)) {
   
      // Send Close AE for recording only
#ifdef MW__LATITUDE_AE_OBJECT_SUPPORT
      DoClose();
#else
      SendSelfAE(kAECoreSuite, kAEClose, false);
      delete this;
#endif
   }
}

Long-Word Alignment

Mac resource data is kept in 680x0 alignment space, meaning long words can fall on short word boundaries. Reading in a 680x0 aligned resource on a platform in which long words are aligned on long word boundaries yields inaccessible data and even segmentation and bus errors, depending upon how the source code accesses the data. While some compilers have align pragmas that can keep structures in a specified alignment space, these pragmas are not common to all platforms, even with the same compiler. We recommend that these pragmas not be used since they don't ensure portability.

Latitude includes tools to pack and unpack Mac resources and file data. By using these tools, your app is assured to be portable to other platforms where CodeWarrior Latitude is supported. Additionally, Latitude's lg_align* tools will perform byte swapping once Latitude is made available for x86 platforms. In PowerPlant, the LWindow::MakeMacWindow() function sneaks a peek at a WIND resource before calling Mac Window Manager's GetNewWindow(). The code fragment looks like this:

SWINDREsourceH theWind = (SWINDResourceH) ::GetResource(QUADCONST('W','I','N','D'), inWINDid);

Int16 kind;

#ifdef _LATITUDE_
if (lg_align_unpack((Handle)theWIND, SWINDResource_align) != noErr)
{
   /* unpack failed! */
}
#endif
kind = (**theWIND).refcon;

The SWINDResource_align argument to lg_align_unpack is a LG_ALIGN token array containing a description of the elements of the WIND resource. Had we not done the lg_align_unpack, the kind variable would contain garbage since the refcon field of a WIND resource is not naturally long word aligned.

Floating Windows

Many Mac applications have floating windows and it seems that every Mac application accomplishes this feat differently. Some patch traps such as FrontWindow, SendBehind, and WaitNextEvent. Some modify the Window Manager's WindowList. Latitude is capable of supporting floating windows through many different methods. The best method, however, is to let Latitude float the windows without intervention.

Regardless of how your application floats windows, it is best to alert Latitude that a certain window is meant to float when the window is created. This way Latitude can make this communication to the gui layer and ensure that the window is created with a floating attribute.

In PowerPlant's UDesktop::NewDeskWindow() function, we want to inform Latitude that the window we're about to create is a floater. Just before the GetNewWindow() call at the bottom of this function, we insert the following:

#ifdef _LATITUDE_
   if (inWindow->HasAttribute(windAttr_Floating)) {
      LG_WMGR_WINDOW_BLOCK wblock;
      
      wblock.flags = LG_WMGR_WINDOW_FLOAT;
      wblock.floats = LG_WINDOW_IS_FLOATER;
      lg_latitude_next_window(&wblock);
   }
#endif

   if (UEnvironment::HasFeature(env_SupportsColor)) {
      macWindowP = ::GetNewCWindow(inWINDid, nil, inBehind);
   } else {
      macWindowP = ::GetNewWindow(inWINDid, nil, inBehind);
   }

CW Latitude has three settings for the floats attribute: LG_WINDOW_IS_FLOATER means that this window is to float above other windows that aren't specified to float. LG_WINDOW_HAS_FLOATERS is the default for regular windows. These windows allow others to float above them. Finally, LG_WINDOW_HAS_NO_FLOATERS specifies windows that must float above all else.

Controls As Drawings

On the Mac, standard controls are drawn in Quickdraw so the area they're rendered in, when scrolled, behaves as expected and the control scrolls with the area. This not the case with CW Latitude and the gui layers it supports. On systems like Motif, controls float above the window's canvas, so if drawings are scrolled across the window, the controls will not move by themselves. They must be explicitly moved.

PowerPlant's LPane::AdaptToSuperScroll() adjusts the control's rectangles but doesn't move the controls themselves. By overriding AdaptToSuperScroll for the LStdControl class and adding a Draw(nil) call, we can be sure that CW Latitude's gui layer will move the control for us.

Muscle

With as much PowerPlant as needed for Muscle ported, we can now begin looking at Muscle's source code. Since Muscle is almost entirely written in terms of PowerPlant, we have very little work to do.

In the ColorTutor example, we had to remove instances of qd. for CW Latitude. In C++ applications however, the QDGlobals type is a class of inline definitions tied to the Quickdraw low memory globals and the application must define it's own QDGlobals qd. So at the top of CMuscleApp.c, we add

#ifdef _LATITUDE_
QDGlobals qd;
#endif

We also add a lg_latitude_init() call similar to the one we added in ColorTutor.c. Muscle's signature is 'MePo'. We can also turn on CW Latitude's gui colorization so that windows have a default background color that matches the rest of their desktop.

void   main( long argc, char **argv )
{
#ifdef _LATITUDE_
   LG_APP_INFO_BLOCK   lblock;

   lblock.flags = LG_APP_INFO_SIGNATURE |                   LG_APP_INFO_CLASSNAME |
         LG_APP_INFO_WINDOW_GUI_COLOR;
   lblock.signature = QUADCONST( 'M','e','P','o' );
   lblock.classname = "Latitude";
   lblock.window_gui_color = 1;
   lg_latitude_init( argc, argv, &lblock );
#endif

Muscle contains a demonstration of PowerPlant's QuickTime support. Unfortunately, Rhapsody does not yet support QuickTime. Latitude will rely on Rhapsody's own QuickTime support once it becomes available. At this point, it is necessary for us to #ifdef out code involving QuickTime. This code is centralized in Muscle's CMuscleApp.cp file and is easy to spot. QuickTime initialization and destruction code in CMuscleApp::CMusleApp and CMuscleApp::~CMusleApp, QuickTime demo selection code in CMusleApp::ObeyCommand, and CMusleApp::FindCommandStatus can all be #ifdefed out.

Porting YOUR Application

As any seasoned Mac programmer will agree, there is a lot of lore in Mac programming. Having assisted many Mac porting projects using CodeWarrior Latitude since its beginnings, we have seen some porting efforts go smoothly and some go rough. Knowledge of Mac programming lore is key.

The make-up of the porting team makes all the difference in the world. The best team combines experience from both Mac and Rhapsody environments in addition to a strong understanding of the underlying Mac code base.

Less advantaged teams are made up entirely of either Mac programmers who aren't familiar with Rhapsody details or Rhapsody programmers who have no Mac programming experience and are not at all familiar with the code base being ported. Experience from both sides is necessary. Rhapsody and/or UNIX skills are needed to properly set up the development environment and address platform issues. Mac skills are needed to understand what exactly is being done in the application source code. By taking the time to put the right team together for the job, your porting project will be much smoother and easier.

We've touched on only a few aspects of the process of porting Mac applications to Rhapsody. Fortunately, PowerPlant and Muscle do not contain many of the imaginative coding techniques we've seen in other Mac applications. Many of these issues are discussed in the CodeWarrior Latitude Guide that accompanies the CodeWarrior Latitude software package.

We invite you to stop by Developer Central at MacWorld in San Francisco, January 6 - 9, 1998, and see Latitude in action. You can pick up the ColorTutor and other sample code at MacTech's web site. And don't forget to stop by http://www.metrowerks.com for up to the minute updates on CW Latitude and Metrowerks' other products.

 
AAPL
$118.31
Apple Inc.
+0.71
MSFT
$47.46
Microsoft Corpora
-0.01
GOOG
$539.90
Google Inc.
-1.18

MacTech Search:
Community Search:

Software Updates via MacUpdate

RapidWeaver 6.0.3 - Create template-base...
RapidWeaver is a next-generation Web design application to help you easily create professional-looking Web sites in minutes. No knowledge of complex code is required, RapidWeaver will take care of... Read more
iPhoto Library Manager 4.1.10 - Manage m...
iPhoto Library Manager lets you organize your photos into multiple iPhoto libraries. Separate your high school and college photos from your latest summer vacation pictures. Or keep some photo... Read more
iExplorer 3.5.1.9 - View and transfer al...
iExplorer is an iPhone browser for Mac lets you view the files on your iOS device. By using a drag and drop interface, you can quickly copy files and folders between your Mac and your iPhone or... Read more
MacUpdate Desktop 6.0.3 - Discover and i...
MacUpdate Desktop 6 brings seamless 1-click installs and version updates to your Mac. With a free MacUpdate account and MacUpdate Desktop 6, Mac users can now install almost any Mac app on macupdate.... Read more
SteerMouse 4.2.2 - Powerful third-party...
SteerMouse is an advanced driver for USB and Bluetooth mice. It also supports Apple Mighty Mouse very well. SteerMouse can assign various functions to buttons that Apple's software does not allow,... Read more
iMazing 1.1 - Complete iOS device manage...
iMazing (was DiskAid) is the ultimate iOS device manager with capabilities far beyond what iTunes offers. With iMazing and your iOS device (iPhone, iPad, or iPod), you can: Copy music to and from... Read more
PopChar X 7.0 - Floating window shows av...
PopChar X helps you get the most out of your font collection. With its crystal-clear interface, PopChar X provides a frustration-free way to access any font's special characters. Expanded... Read more
Carbon Copy Cloner 4.0.3 - Easy-to-use b...
Carbon Copy Cloner backups are better than ordinary backups. Suppose the unthinkable happens while you're under deadline to finish a project: your Mac is unresponsive and all you hear is an ominous,... Read more
ForeverSave 2.1.3 - Universal auto-save...
ForeverSave auto-saves all documents you're working on while simultaneously doing backup versioning in the background. Lost data can be quickly restored at any time. Losing data, caused by... Read more
Voila 3.8.1 - Capture, annotate, organiz...
Voila is a screen-capture, recording, and annotation tool that is a full-featured replacement for Mac's screen-capture and screen-recording capabilities. It has a large and robust set of editing,... Read more

Latest Forum Discussions

See All

Black Friday has Started Early – Lots an...
It’s almost turkey time! Which means lots and lots of food but also lots and lots of sales. Some sales have even started a few days early, which is why we’ve put together a list of iOS games that are currently discounted (sometimes by a lot).... | Read more »
Loose Leaf Review
Loose Leaf Review By Jennifer Allen on November 26th, 2014 Our Rating: :: SIMPLE SKETCHINGiPad Only App - Designed for the iPad Sketch out ideas with simple drawing tools, courtesy of Loose Leaf.   | Read more »
Screeny (Utilities)
Screeny 1.0 Device: iOS iPhone Category: Utilities Price: $.99, Version: 1.0 (iTunes) Description: Screeny is an utility app that helps you save space consumed by screenshots. It screens your camera roll and helps you to filter and... | Read more »
Tilt to Live Bundle Set to Arrive This T...
Tilt to Live Bundle Set to Arrive This Thanksgiving Posted by Ellis Spice on November 25th, 2014 [ permalink ] One Man Left has unveiled an upcoming Tilt to Live bundle, allowing players to get the series for a di | Read more »
BattleLore: Command (Entertainment)
BattleLore: Command 1.0 Device: iOS Universal Category: Entertainment Price: $9.99, Version: 1.0 (iTunes) Description: ***NOTE: Compatible with iPad 2/iPad mini, iPod touch 5 and up and iPhone 4S and up – WILL NOT RUN ON EARLIER... | Read more »
Weather Or Not Review
Weather Or Not Review By Jennifer Allen on November 25th, 2014 Our Rating: :: STYLISH WEATHER REPORTINGiPhone App - Designed for the iPhone, compatible with the iPad Check the weather quickly and conveniently with Weather or Not... | Read more »
The All-New Football Manager Handheld 20...
The All-New Football Manager Handheld 2015 is Available Now Posted by Jessica Fisher on November 25th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Six iOS Games to Get You Ready for Thank...
Image Source: Friends Wiki At this point in the month, you or at least a few people you know are probably getting ready to scramble around (or are already scrambling around) for Thanksgiving Dinner. It’s a hectic day of precise oven utilization, but... | Read more »
Call of Duty: Heroes: Tips, Tricks, and...
Hello Heroes: What’d we think of Call of Duty‘s take on Clash of Clans? Check out our Call of Duty: Heroes review to find out! Just downloaded Call of Duty: Heroes and need some handy tips and tricks on how to get ahead of the rest? As we often do,... | Read more »
Call of Duty: Heroes Review
Call of Duty: Heroes Review By Jennifer Allen on November 25th, 2014 Our Rating: :: CLASH OF FRANCHISESUniversal App - Designed for iPhone and iPad Mix Clash of Clans with Call of Duty, and this is what you get.   | Read more »

Price Scanner via MacPrices.net

Early Black Friday Mac Pro sale, 6-Core 3.5GH...
 B&H Photo has the 6-Core 3.5GHz Mac Pro on sale today for $3499 including free shipping plus NY sales tax. Their price is $500 off MSRP, and it’s the lowest price available for this model from... Read more
Early Black Friday sale price: 15-inch 2.2GHz...
 B&H Photo has the 2014 15″ 2.2GHz Retina MacBook Pro on sale today for $1699.99. Shipping is free, and B&H charges NY sales tax only. Their price is $300 off MSRP, equalling Best Buy’s price... Read more
13-inch 2.5GHz MacBook Pro (refurbished) avai...
The Apple Store has Apple Certified Refurbished 13″ 2.5GHz MacBook Pros available for $170 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free: - 13″ 2.5GHz... Read more
Early Black Friday iPad mini 3 sale: $75 off...
 Best Buy has iPad mini 3s on sale for $75 off MSRP on their online store for a limited time. Choose free shipping or free local store pickup (if available). Sale prices available for online orders... Read more
Early Black Friday MacBook Pro sale: 15-inch...
 Best Buy has posted early Black Friday prices on 15″ Retina MacBook Pros, with models on sale for $300 off MSRP on their online store for a limited time. Choose free local store pickup (if available... Read more
A9 Chips Already?
It’s barely more than a couple of months since Apple got the first A8 systems-on-chip into consumer hands, but rumor and news focus is already turning to the next-generation A9 SoC. Apple Daily... Read more
NewerTech Announces NuGuard KXs Impact X-Orbi...
NewerTech has announced updates to its family of Impact X-Orbing Screen Armor bringing military grade, triple layer protection to Apple’s new iPhone 6 and 6 Plus. Like all models in the NuGuard KXs... Read more
13-inch 1.4GHz MacBook Air on sale for $889,...
 B&H Photo has the 13″ 1.4GHz/128GB MacBook Air on sale for $889 including free shipping plus NY tax only. Their price is $110 off MSRP. B&H will also include free copies of Parallels Desktop... Read more
Save up to $300 on Macs and iPads with your A...
Purchase a new Mac or iPad at The Apple Store for Education and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free,... Read more
Apple refurbished Mac Pros available for up t...
The Apple Store is offering Apple Certified Refurbished Mac Pros for up to $600 off the cost of new models. An Apple one-year warranty is included with each Mac Pro, and shipping is free. The... Read more

Jobs Board

*Apple* Solutions Consultant (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
Senior Event Manager, *Apple* Retail Market...
…This senior level position is responsible for leading and imagining the Apple Retail Team's global event strategy. Delivering an overarching brand story; in-store, Read more
*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
*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* 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.