TweetFollow Us on Twitter

MACINTOSH C CARBON
MACINTOSH C CARBON: A Hobbyist's Guide To Programming the Macintosh in C
Version 1.0
2001 K. J. Bricknell
Go to Contents Go to Program Listing

CHAPTER 20

CARBON SCRAP

The Carbon Scrap Manager and the Scrap

Introduction

The inclusion of the word "Carbon" in the title of this chapter is quite deliberate, reflecting the fact that, in Carbon, the original Scrap Manager has been redesigned to fully support the needs of the preemptively scheduled Mac OS X.

Applications which support cut, copy, and paste operations write data to, and read data from, the scrap. The scrap is a storage area, maintained by the Scrap Manager, which holds the last text, graphics, sounds, etc., cut or copied by the user.

The various data formats in which data may be written to, and read from, the scrap are called scrap flavours. A scrap flavour is a self-contained, self-describing stream of bytes which represent a discreet object such as a picture or text selection. Each scrap flavour has a scrap flavour type and a set of scrap flavour flags. The scrap may contain data in one or more flavours, each flavour being a different representation of the same object.

Your application specifies the scrap flavour, or flavours, to be read from, and written to, the scrap. The ultimate aim is to allow the user to copy and paste documents:

  • Within a document created by your application.

  • Between different documents created by your application.

  • Between documents created by your application and documents created by other applications.

Location of the Scrap

On Mac OS 8/9, space is allocated for the scrap in each application's heap. The system software stores a handle to the scrap of the current process in the system global variable ScrapHandle. When an application is launched, data is copied to the newly activated application's heap from the previously active application's heap. If the scrap is too large to fit in the application's heap, the scrap is copied to disk. In this event, the handle to the scrap is set to NULL to indicate that the scrap is on disk.

On Mac OS X, the scrap is held by the pasteboard server.

Scrap Reference

A scrap is referred to by a scrap reference. The data type ScrapRef is defined as a pointer to a scrap reference:

     typedef struct OpaqueScrapRef *ScrapRef;

Note that, although there is only one scrap, there may be multiple ScrapRef values. A ScrapRef value is valid only until the scrap is cleared.

Scrap Flavours

Standard Scrap Flavours

Your application should be capable of writing at least one of the following standard scrap flavours to the scrap and should be capable of reading both:

  • 'TEXT' (that is, a series of ASCII characters).

  • 'PICT' (a QuickDraw picture).

Optional Flavours

Your application may also choose to support the following optional scrap format types:

  • 'styl' (a series of bytes which have the same format as a TextEdit 'styl' resource, and which describe styled text data).

  • 'movv' (a series of bytes which define a movie, and which have the same format as a 'movv' resource).

Private Flavours

It is also possible for your application to use its own private flavour, or flavours, but this should be in addition to at least one of the standard flavours.

Preferred Flavour

Recall that each flavour in the scrap (assuming there is more than one) is simply a different representation of the same object.

Your application should have a preferred scrap flavour. When reading data from the scrap, your application should request its preferred flavour first and only request its next preferred flavour if the preferred flavour does not exist in the scrap. When writing data to the scrap, your application should write its preferred flavour first. Any additional flavours should be written in the preferred order.

Implementing Edit Menu Commands

You use the Edit menu Cut, Copy, and Paste commands to implement cutting, copying, and pasting of data within or between documents. The following are the actions your application should perform to support these three commands:

Edit Command

Actions Performed by Your Application

Cut

If there is a current selection range, copy the data in the selection range to the desk scrap and remove the data from the document.

Copy

If there is a current selection range, copy the data in the selection range to the desk scrap.

Paste

Read the desk scrap and insert the data (if any) at the insertion point, replacing any current selection.

The insertion point in a text document is represented by the blinking vertical bar known as the caret. There is a close relationship between the selection range and the insertion point in that the insertion point is, in effect, an empty selection range.

If your application implements a Clear command, it should remove the data in the current selection range but should not save the data to the desk scrap.

Cut and Copy - Putting Data in the Scrap

A typical approach to implementing the Cut and Copy commands is as follows:

  • Determine whether the frontmost window is a document window or a dialog.

  • If the frontmost window is a document window:

    • Call ClearCurrentScrap to purge the current contents of the scrap.

    • Call GetCurrentScrap to obtain a reference to the current scrap.

    • Determine whether the current selection contains text or a picture.

    • If the current selection is text, get a pointer to the selected text and get the size of the selection. If the current selection is a picture, get a pointer to the picture structure and get the size of that structure.

    • Call PutScrapFlavor to write the data to the scrap, passing the appropriate flavour type in the flavorType parameter.

    • If the command was the Cut command, delete the selection from the current document.
    
    

  • If the frontmost window is a dialog, use the Dialog Manager functions DialogCut or DialogCopy, as appropriate, to write the selected data to the scrap.

Paste - Getting Data From the Scrap

When you read the data from the scrap, your application should request the data in the application's preferred flavour type. If your application determines that that flavour does not exist in the scrap, it should then request the data in another flavour. If your application does not have a preferred flavour type, it should read each flavour type that your application supports.

If you request a scrap format that is not in the scrap, the Scrap Manager uses the Translation Manager to convert any one of the scrap flavour types currently in the scrap into the scrap flavour requested by your application. The Translation Manager looks for a translator that can perform one of these translations. If such a translator is available, the Translation Manager uses the translator to translate the data in the scrap into the requested flavour.

A typical approach to an implementation of the Paste command, for an application that prefers a flavour type of 'TEXT' as its first preference, is as follows:

  • Determine whether the frontmost window is a document window or a dialog.

  • If the frontmost window is a document window:

    • Call GetCurrentScrap to obtain a reference to the current scrap.

    • Call GetScrapFlavorFlags to determine whether the preferred flavour exists in the scrap.

    • If the preferred flavour type ('TEXT') does exist, call GetScrapFlavorSize to get the size of the text data, allocate a relocatable block of that size, and call GetScrapFlavorData to read the data into that block. Copy the data in the relocatable block to the current document at the insertion point.

    • If the preferred flavour type does not exist, call GetScrapFlavorFlags again to determine whether the next preferred flavour (say, 'PICT') exists in the scrap. If it does, call GetScrapFlavorSize to get the size of the picture data, allocate a relocatable block of that size, and call GetScrapFlavorData to read the data into that block. Call DrawPicture to draw the picture described by the data in the relocatable block in the current document at the insertion point.

  • If the frontmost window is a dialog, use the Dialog Manager function DialogPaste to paste the text from the scrap in the dialog.

Enabling the Paste Menu Item

Your application can determine whether to enable the Paste item in the Edit menu by calling GetScrapFlavorFlags to determine whether the scrap contains data of the flavour type specified in that call. GetScrapFlavorFlags returns noErr if the specified flavour exists.

Example

Fig 1 illustrates two cases, both of which deal with a user copying a picture consisting of text from a source document created by one application to a destination document created by another application.

In the first case, the source application has chosen to write only the 'PICT' flavour to the scrap, and the destination application has pasted the data, in that flavour, to its document.

In the second case, the source application has chosen to write both the 'TEXT' and 'PICT' flavours to the scrap, and the destination application has chosen the 'TEXT' flavour as the preferred flavour for the paste. The data is thus inserted into the document as editable text.

Clipboard Windows

Your application can provide a Show Clipboard command in the Edit menu which, when chosen, shows a window which displays the current contents of the scrap. Such a window is known as a Clipboard window. The Show Clipboard command should be toggled with a Hide Clipboard command to allow the user to hide the Clipboard window when required.

Although the scrap may contain multiple scrap flavours, your Clipboard window should ordinarily display the data in the application's preferred flavour only.

If the user has chosen to open the Clipboard window, your application should hide the window on receipt of a suspend event and show it when a resume event is received. This is necessary because the contents of the scrap could change while the application is in the background.

Transferring the Desk Scrap to Disk - Mac OS 8/9

Although, on Mac OS 8/9, the scrap is usually located in memory, your application can write the contents of the scrap in memory to a scrap file using UnloadScrap. You should do this only if memory is not large enough to hold the data you need to write to the scrap. After writing the contents of the scrap to disk, UnloadScrap releases the memory previously occupied by the scrap. Thereafter, any operations your application performs on data in the scrap affect the scrap as stored in the scrap file on disk. You can use LoadScrap to read the contents of the scrap file back into memory.

On Mac OS X, calls to LoadScrap and UnloadScrap are ignored.

Main Carbon Scrap Manager Functions

The main Carbon Scrap Manager functions are as follows:

Function

Description

GetCurrentScrap

Gets a reference to the current scrap. (Note that this reference will become invalid and unusable after the scrap is cleared.)

GetScrapFlavorFlags

Determines whether the scrap contains data for a particular flavour and provides information about that flavour if it exists. (Amongst other things, this function is useful for deciding whether to enable the Paste item in your Edit menu.)

GetScrapFlavorSize

Gets the size of the data of the specified flavour from the specified scrap.

GetScrapFlavorData

Gets the data of the specified flavour from the specified scrap.

ClearCurrentScrap

Clears the current scrap. This function should be called immediately the user requests a Copy or Cut operation.

PutScrapFlavor

Puts data on the scrap. Also promises data to the specified scrap (see below).

Associated Constants and Data Types

The following constants and data types are associated with the main Scrap Manager functions:

Scrap Flavour Type Constants

Constant

Flavour Type

Description

kScrapFlavorTypePicture 'PICT'

Picture

kScrapFlavorTypeText 'TEXT'

Text

kScrapFlavorTypeTextStyle 'styl'

Text style

kScrapFlavorTypeMovie 'moov'

Movie

Scrap Flavour Flag Constants

In the following, the first two constants may be passed in the flavorFlags parameter in calls to PutScrapFlavour, and the third is received in the flavorFlags parameter in calls to GetScrapFlavorFlags:

Constant

Meaning

kScrapFlavorMaskNone

No flags required.

kScrapFlavorMaskSenderOnly

Only the process which puts the flavour on the scrap can see it.

If another process puts a flavour with this flag on the scrap,your process will never see the flavour. Accordingly, there is no point in testing for this flag.

This flag is typically used to save a private flavour to the scrap so that other promised (see below) public flavours can be derived from it on demand.

kScrapFlavorMaskTranslated

The flavour was translated, by the Translation Manager, from some other flavour in the scrap. (Most callers should not care about this flag.) (Most callers should not care about this flag.)

ScrapFlavorInfo Data Type

The ScrapFlavorInfo data type describes a single flavour within a scrap and is used by those functions which get information about the current scrap (GetScrapFlavorFlags, GetScrapFlavorSize, and GetScrapFlavorData):
     struct ScrapFlavorInfo 
     {
       ScrapFlavorType  flavorType;
       ScrapFlavorFlags flavorFlags;
     };
     typedef struct ScrapFlavorInfo ScrapFlavorInfo;

Private Scrap

As an alternative to writing to and reading from the scrap whenever the user cuts, copies and pastes data, your application can choose to use its own private scrap. An application which uses a private scrap copies data to its private scrap when the user chooses the Cut or Copy command and pastes data from the private scrap when the user chooses the Paste command.

Additional Actions - Old Scrap Manager

In the old pre-Carbon Scrap Manager, an application which used a private scrap had to take the following additional actions whenever it received suspend and resume events:

  • Suspend Event. On receipt of a suspend event, the application had to copy data from the private scrap to the scrap.

  • Resume Event. On receipt of a resume event, the application had to first examine the convertClipboardFlag bit in the message field of the resume event structure to determine if the data in the scrap had changed since the previous suspend event. If the data in the scrap had changed, the application had to copy the data from the scrap to its private scrap. The application's menu adjustment function enabled the Paste item if the data copied to the private scrap was of the preferred, or other acceptable, type.

The process is illustrated at Fig 2.

Additional Actions - Carbon Scrap Manager

In the preemptively scheduled Mac OS X, this rather straightforward approach is no longer feasible. Consider the following scenario on Mac OS X:

  • Application B, which has a private scrap, is the frontmost application. The user clicks in a window belonging to application A to make application A the frontmost application. Application B receives a suspend event and begins to convert its private scrap.

  • While application B is still converting its private scrap, application A has become the frontmost application, and the user clicks in its menu bar. Application A, needing to decide whether to enable the Paste item in its Edit menu, looks at the scrap to determine what flavours it contains. Because application B has not finished converting its private scrap, and thus has not put anything onto the scrap, application A finds nothing it wants on the scrap and, accordingly, disables the Paste item.

The situation in which application A finds itself with regard to the Paste item is not acceptable in terms of human interface. The user cannot be expected to know that application B is still converting its scrap and that application As Paste item will be enabled in due course.

Making Promises

The Carbon Scrap Manager eliminates this problem using the concept of promised flavours. If, in the above example, application B calls PutScrapFlavor with NULL passed in the flavorData parameter whenever the user chooses Cut or Copy, a promise is made that data of the flavour specified in the flavorType parameter will later be placed on the scrap. On checking the scrap, application A will see the promise and can thus enable its Paste item in the expectation that the actual data will eventually appear in the scrap. The actual data can then be provided by application B through a subsequent call to PutScrapFlavor during the execution of a scrap promise keeper (callback) function. (Scrap promise keeper callback functions are called by the Carbon Scrap Manager as required to keep an earlier promise of a particular scrap flavour.)

In the first (promise-making) call to PutScrapFlavor, passing a non-zero size in the flavorSize parameter is optional; however, providing the size is advisable because callers of GetScrapFlavorSize will then be able to avoid blocking. If the size is provided, the subsequent call to PutScrapFlavor must provide the same amount of data as was promised. If the size is unknown at the time of the promise, your application should pass kScrapFlavorSizeUnknown in the flavorSize parameter.

Note that the promise-making PutScrapFlavor call cannot be made when your application receives a suspend event. This is because of the fundamental difference between the receipt of suspend events in Carbon applications as compared with Classic applications (see Chapter 2). Making the promise each time the user chooses Cut or Copy involves very little overhead, since only the promise, not the data, is being placed on the scrap.

Calling In Promises

In applications that use the Classic event model, your application should invariably call CallInScrapPromises on exit to cater for the possibility that it may have made promises that, after it quits, it cannot possibly honour. CallInScrapPromises forces all promises to be kept. On Mac OS X, this action is necessary even if your application has itself made no promises, the reason being that it is possible that, unbeknown to the application, promises could have been made on its behalf. For example, when you copy TEXT data (which has ASCII 13 for line endings) onto the scrap, the Carbon Scrap Manager promises other flavours which have different line endings and/or text encodings so that Cocoa applications can paste.

Calling CallInScrapPromises is not necessary in applications which use the Carbon event model model because the call will be made automatically in that case.

TextEdit, Dialogs, and Scrap

TextEdit and Scrap

TextEdit is a collection of functions and data structures which you can use to provide your application with basic text editing capabilities.

If your application uses TextEdit in its windows, be aware that TextEdit maintains its own private scrap. Accordingly:

  • PutScrap is not used and the special TextEdit functions TECut, TECopy, and TEToScrap are used in the processes of cutting text from the document and copying text to the TextEdit private scrap and to the desk scrap.

  • GetScrap is not used and the special TextEdit functions TEPaste, TEStylePaste, and TEFromScrap are used in the processes of pasting text from the TextEdit private scrap and copying text from the desk scrap to the TextEdit private scrap.

Chapter 21 describes TextEdit, including the TextEdit private scrap and the TextEdit scrap-related functions.

Dialogs and Scrap

Dialogs may contain edit text items, and the Dialog Manager uses TextEdit to perform the editing operations within those items.

You can use the Dialog Manager to handle most editing operations within dialogs. The Dialog Manager functions DialogCut, DialogCopy, and DialogPaste may be used to implement Cut, Copy and Paste commands within edit text items in dialogs. (See the demonstration program at Chapter 8.)

TextEdit's private scrap facilitates the copying and pasting of data between dialogs. However, your application itself must ensure that the user can copy and paste data between your application's dialogs and its document windows. If your application uses TextEdit for all editing operations within its document windows, this is easily achieved because TextEdit's TECut, TECopy, TEPaste, and TEStylePaste functions and the Dialog Manager's DialogCut, DialogCopy, and DialogPaste functions all use TextEdit's private scrap.

Main Carbon Scrap Manager Data Types and Functions

Constants

Scrap Flavour Types

kScrapFlavorTypePicture    = FOUR_CHAR_CODE('PICT')  // Picture
kScrapFlavorTypeText       = FOUR_CHAR_CODE('TEXT')  // Text
kScrapFlavorTypeTextStyle  = FOUR_CHAR_CODE('styl')  // Text style
kScrapFlavorTypeMovie      = FOUR_CHAR_CODE('moov')  // Movie
kScrapFlavorTypeSound      = FOUR_CHAR_CODE('snd ')  // Sound

Scrap Flavour Flags

kScrapFlavorMaskNone       = 0x00000000
kScrapFlavorMaskSenderOnly = 0x00000001
kScrapFlavorMaskTranslated = 0x00000002

Promising Flavours

kScrapFlavorSizeUnknown    = -1

Result Codes

internalScrapErr            = -4988
duplicateScrapFlavorErr     = -4989
badScrapRefErr              = -4990
processStateIncorrectErr    = -4991
scrapPromiseNotKeptErr      = -4992
noScrapPromiseKeeperErr     = -4993
nilScrapFlavorDataErr       = -4994
scrapFlavorFlagsMismatchErr = -4995
scrapFlavorSizeMismatchErr  = -4996
illegalScrapFlavorFlagsErr  = -4997
illegalScrapFlavorTypeErr   = -4998
illegalScrapFlavorSizeErr   = -4999
scrapFlavorNotFoundErr      = -102
needClearScrapErr           = -100

Data Types

typedef struct OpaqueScrapRef *ScrapRef;
typedef FourCharCode               ScrapFlavorType;
typedef UInt32                     ScrapFlavorFlags;

ScrapFlavorInfo

struct ScrapFlavorInfo 
{
 ScrapFlavorType  flavorType;
 ScrapFlavorFlags flavorFlags;
};
typedef struct ScrapFlavorInfo ScrapFlavorInfo;

Functions

Obtaining a Reference to the Current Scrap

OSStatus  GetCurrentScrap(ScrapRef *scrap);

Obtaining Information About a Specific Scrap Flavour

OSStatus  GetScrapFlavorFlags(ScrapRef scrap,ScrapFlavorType flavorType,
          ScrapFlavorFlags *flavorFlags);

Obtaining the Size of Data of a Specified Scrap Flavour

OSStatus  GetScrapFlavorSize(ScrapRef scrap,ScrapFlavorType flavorType,
          Size *byteCount);

Obtaining the Data of a Specified Scrap Flavour

OSStatus  GetScrapFlavorData(ScrapRef scrap,ScrapFlavorType flavorType,
          Size *byteCount,void *destination);

Writing Data to the Scrap and Clearing the Scrap

OSStatus  PutScrapFlavor(ScrapRef scrap,ScrapFlavorType flavorType,
          ScrapFlavorFlags  flavorFlags,Size flavorSize,const void *flavorData);
OSStatus  ClearCurrentScrap(void);

Scrap Promise Keeping

ScrapPromiseKeeperUPP  NewScrapPromiseKeeperUPP(ScrapPromiseKeeperProcPtr userRoutine);
void      DisposeScrapPromiseKeeperUPP(ScrapPromiseKeeperUPP userUPP);
OSStatus  SetScrapPromiseKeeper(ScrapRef scrap,ScrapPromiseKeeperUPP upp,
          const void *userData);
OSStatus  CallInScrapPromises(void);

Application-Defined (Callback) Function

OSStatus myScrapPromiseKeeperFunction(ScrapRef scrap,ScrapFlavorType flavorType,
         void *userData);

Transferring the Scrap Between Memory and Disk (Mac OS 8/9)

SInt32 UnloadScrap(void); // Does nothing when called on Mac OS X
SInt32 LoadScrap(void);   // Does nothing when called on Mac OS X

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Scrivener 3.0 - Project management and w...
Scrivener is a project management and writing tool for writers of all kinds that stays with you from that first unformed idea all the way through to the first - or even final - draft. Outline and... Read more
SuperDuper! 3.0.1 - Advanced disk clonin...
SuperDuper! is an advanced, yet easy to use disk copying program. It can, of course, make a straight copy, or "clone" -- useful when you want to move all your data from one machine to another, or do... Read more
Parallels Desktop 13.2.0 - Run Windows a...
Parallels allows you to run Windows and Mac applications side by side. Choose your view to make Windows invisible while still using its applications, or keep the familiar Windows background and... Read more
VueScan 9.5.92 - Scanner software with a...
VueScan is a scanning program that works with most high-quality flatbed and film scanners to produce scans that have excellent color fidelity and color balance. VueScan is easy to use, and has... Read more
iFinance 4.3.4 - Comprehensively manage...
iFinance allows you to keep track of your income and spending -- from your lunchbreak coffee to your new car -- in the most convenient and fastest way. Clearly arranged transaction lists of all your... Read more
jAlbum Pro 15.0 - Organize your digital...
jAlbum Pro has all the features you love in jAlbum, but comes with a commercial license. You can create gorgeous custom photo galleries for the Web without writing a line of code! Beginner-friendly... Read more
jAlbum 15.0 - Create custom photo galler...
With jAlbum, you can create gorgeous custom photo galleries for the Web without writing a line of code! Beginner-friendly, with pro results - Simply drag and drop photos into groups, choose a design... Read more
Duet 1.6.9.3 - Use your iPad as an exter...
Duet is the first app that allows you to use your iDevice as an extra display for your Mac using the Lightning or 30-pin cable. Note: This app requires a $14.99 iOS companion app. Version 1.6.9.3:... Read more
Duet 1.6.9.3 - Use your iPad as an exter...
Duet is the first app that allows you to use your iDevice as an extra display for your Mac using the Lightning or 30-pin cable. Note: This app requires a $14.99 iOS companion app. Version 1.6.9.3:... Read more
iExplorer 4.1.10 - View and transfer fil...
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

Latest Forum Discussions

See All

The mobile gamer's guide to Black F...
We're starting to catch wind of some exciting deals in the mobile gaming space for Black Friday. There are big discounts on mobile phones and accessories cropping up already, so you might want to get a move on things ahead of the big day. It's... | Read more »
The best pre-Black Friday deals - Novemb...
Black Friday will soon be upon us, but online retailers are already getting a headstart on the steep discounts. Don't wait until Friday—you'll find some pretty good deals all over the internet without waiting in lines or competing with other... | Read more »
Mighty Battles guide - how to build a so...
Mighty Battles, the latest title from Hothead Games, is set to take the App Store by storm. The game puts a welcome twist on lane battlers, adding FPS elements to spice things up a bit. You'll collect cards to put your own military unit to gether,... | Read more »
Rules of Survival guide - how to be the...
The PUBG craze makes its way to mobile, with more and more battle royale games debuting on iOS and Android. Rules of Survival joins the ranks of mobile PUBG-likes, offering a classic battle royale experiences that doesn't vary too much from its... | Read more »
The best new games we played this week -...
The weekend is upon us friends, and it's time to take a look back and reflect on all of the wonderful games we've played over the past few days. This week was jam packed with new releases. There were some big, long awaited launches, some fun... | Read more »
Lineage II: Revolution guide - tips and...
At long last, Lineage II: Revolution has now come to western shores, bring Netmarble's sweeping MMORPG to mobile devices. It's an addictive, epic experience, but some of the systems in the game can be a bit overwhelming. Here are a few tips to help... | Read more »
A Boy and His Blob (Games)
A Boy and His Blob 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: | Read more »
Fight terrible monsters and collect epic...
Released on Western markets early last month, Dragon Project, created by Japanese developer COLOPL, brings epic monster hunting action to mobile for the very first time. Collect a huge array of weapons and armor, and join up with friends to fight... | Read more »
I Am The Hero (Games)
I Am The Hero 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: I Am The Hero is a pixel art, beat 'em up, fighting game that tells the story of a "Hero" with a glorious but mysterious past.... | Read more »
Kauldron (Music)
Kauldron 1.0 Device: iOS Universal Category: Music Price: $3.99, Version: 1.0 (iTunes) Description: Kauldron is our warmest sounding, punchiest synth yet! A completely new modeling technology, combined with carefully designed... | Read more »

Price Scanner via MacPrices.net

Save up to $180 with Apple Certified Refurbis...
Apple has Certified Refurbished 2017 13″ MacBook Airs available starting at $849. An Apple one-year warranty is included with each MacBook, and shipping is free: – 13″ 1.8GHz/8GB/128GB MacBook Air (... Read more
Black Friday deals on Apple Macs now live at...
Amazon has MacBook Pros, MacBook Airs, MacBooks, and iMacs on sale for up to $200 off MSRP for Black Friday week. Shipping is free. Note that stock of some Macs may come and go during the week, so... Read more
Black Friday pricing on Macs and iPads now av...
B&H Photo has lowered prices on many Macs, iPads, and iPad Pros as part of their Black Friday week sale. Save up to $200 on MacBooks and iMacs and up to $150 on iPads. B&H charges sales tax... Read more
Best Apple iPad deals this weekend, up to $80...
Apple resellers are offering 9.7″ iPads and 10.5″ iPad Pros for up to $80 off MSRP this weekend as part of their early Holiday and Black Friday sales: Adorama is offering new 2017 9.7″ 32GB WiFi... Read more
Early Black Friday sale: Apple iMacs for up t...
B&H Photo has 27-inch iMacs in stock and on sale for up $130-$150 off MSRP including free shipping. B&H charges sales tax in NY & NJ only: – 27″ 3.8GHz iMac (MNED2LL/A): $2149 $150 off... Read more
Apple restocks refurbished Mac minis starting...
Apple has restocked Certified Refurbished Mac minis starting at $419. Apple’s one-year warranty is included with each mini, and shipping is free: – 1.4GHz Mac mini: $419 $80 off MSRP – 2.6GHz Mac... Read more
Save on 12″ MacBooks, Apple refurbished model...
Apple has Certified Refurbished 2017 12″ Retina MacBooks available for $200-$240 off the cost of new models. Apple will include a standard one-year warranty with each MacBook, and shipping is free.... Read more
Early Holiday sale: 12″ iPad Pros for up to $...
B&H Photo has 12″ iPad Pros on sale today for up to $130 off MSRP. Shipping is free, and B&H collects no sales tax outside NY & NJ: – 12″ 64GB WiFi iPad Pro: $749, save $50 – 12″ 256GB... Read more
Holiday sale prices on Apple 13″ MacBook Pros...
B&H Photo has 2017 13″ MacBook Pros in stock today and on sale for $100-$150 off MSRP, each including free shipping plus NY & NJ sales tax only: – 13-inch 2.3GHz/128GB Space Gray MacBook Pro... Read more
Sale: 13″ MacBook Airs starting at $899, $100...
B&H Photo has 2017 13″ MacBook Airs on sale today for $100 off MSRP including free shipping. B&H charges NY & NJ sales tax only: – 13″ 1.8GHz/128GB MacBook Air (MQD32LL/A): $899, $100 off... Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Product Manager - *Apple* Pay on the *Appl...
Job Summary Apple is looking for a talented product manager to drive the expansion of Apple Pay on the Apple Online Store. This position includes a unique Read more
*Apple* Pro/Consumer Apps Support Engineer -...
…exemplify AppleCare's expert technical support paired with exceptional customer service for Apple 's software apps. This person is a problem solver, who understands Read more
Partner Marketing Manager, *Apple* Pay - Ap...
Job Summary The Apple Pay partner marketing team is looking for a Marketing Manager to develop and drive US programs. The right candidate will be passionate about Read more
*Apple* Solution Consultant - Apple (United...
# Apple Solution Consultant - Rochester, MN Job Number: 113037950 Rochester, MN, Minnesota, United States Posted: 19-Sep-2017 Weekly Hours: 40.00 **Job Summary** Are Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.