< Previous PageNext Page > Hide TOC

HICocoaView: Using Cocoa Views in Carbon Windows

Cocoa provides views that are either not currently available in HIToolbox or are available without full support. These include views such as WebView, PDFView, QTMovieView, and NSTokenField. In addition, the Cocoa and Carbon control hierarchies are incompatible, so it has been difficult or impossible to have views from both frameworks embedded within the same window.

A new type of HIView called HICocoaView solves these problems. In Mac OS X v10.5 and later, you can embed a Cocoa view (any subclass of NSView) inside the HIView control hierarchy in a Carbon window. This is accomplished by associating the Cocoa view with a Carbon wrapper view called HICocoaView, a subclass of HIView. You can use standard HIView functions to manipulate the wrapper view, and you can use Cocoa methods to manipulate the associated Cocoa view.

Note: HICocoaView is supported only in Carbon windows with compositing enabled. For more information about compositing windows, see HIView Programming Guide.

Figure 1 shows how HICocoaView fits into the HIObject class hierarchy.


Figure 1  HICocoaView class hierarchy

HICocoaView class hierarchy

Because HICocoaView is a subclass of HIView, you can use HIView functions to manipulate a wrapper view. For example, you can use HIViewFindByID to find the view in a window’s view hierarchy. If the view needs to be made visible, you can call HIViewSetVisible. If it needs to be redrawn, you can call HIViewSetNeedsDisplay. If you need more control over your view, you can also intercept any of the Carbon control events and implement them yourself. Note that you don’t need to handle the kEventControlDraw event; the wrapper view takes care of drawing its Cocoa view.

There are no restrictions on the type of Cocoa view you can wrap. A wrapped Cocoa view may also contain other Cocoa views. To gain access to the functionality of a wrapped Cocoa view, you can use any of its methods. To invoke these methods, you will need to use Objective-C to create and send messages to the Cocoa view. For example, if you want a PDFView object associated with a Carbon wrapper view to advance to the next page, you need to send the message goToNextPage: to the object.

When you modify the state of a Carbon wrapper view, adjustments are automatically made to the state of the associated Cocoa view. This is a one-way process, however—messages sent to the Cocoa view do not necessarily change the state of the wrapper view. For example, sending the setFrame: message to the Cocoa view does not reposition the wrapper view within its parent view.

When you embed a wrapper view inside a window, there are some limitations:

The next section describes how to incorporate HICocoaView into your application.

Contents:

Using HICocoaView
Using a Nib-Based Cocoa User Interface


Using HICocoaView

The HICocoaView API is easy to understand and use. There are three functions:

HICocoaViewCreate

Creates a Carbon view that serves as a wrapper for a Cocoa view.

HICocoaViewSetView

Associates a Cocoa view with a Carbon wrapper view.

HICocoaViewGetView

Returns the Cocoa view associated with a Carbon wrapper view.

This section explains when and how to use these functions.

Preparing your Carbon Project to use Cocoa

Before you can use the HICocoaView feature, you need to take the following steps to prepare your Carbon project to use Objective-C and Cocoa:

Creating a Wrapper View

To create a Carbon wrapper view and add it to the view hierarchy of a Carbon window, you use one of two approaches:

Using HICocoaViewCreate

The following code example shows how to use HICocoaViewCreate to create a wrapped Cocoa view that can be embedded inside the content view of a Carbon window:

NSView *myCocoaView = [[SomeNSView alloc] init];
HIViewRef myHICocoaView;
HICocoaViewCreate (myCocoaView, 0, &myHICocoaView);
[myCocoaView release];

Using Interface Builder

If you’re using Interface Builder, the first step is to add an HIView to your Carbon window by dragging an HIView object from the Carbon Objects palette into the window. If you like, resize the view to fill a larger area of the window. Now select the view and use the Inspector window to assign the class ID "com.apple.HICocoaView" to the view. You also need to assign a control signature and ID; you’ll use these values to find the view at runtime.

Figure 2 shows how a nib-based Carbon window that contains a wrapper view might look in Interface Builder.


Figure 2  A Carbon wrapper view in Interface Builder

A Carbon wrapper view in Interface Builder

Associating a Cocoa View with a Wrapper View

To associate a Cocoa view with an existing Carbon wrapper view, you use the HICocoaViewSetView function. There are two occasions for using this function:

The following code example shows how to find a wrapper view in a window’s content view hierarchy and associate a Cocoa web view with the wrapper view:

const HIViewID kMyHICocoaViewID = { 'Test', 1 };
HIViewRef myHICocoaView = NULL;
HIViewFindByID (HIViewGetRoot(myWindow), kMyHICocoaViewID, &myHICocoaView);
if (myHICocoaView != NULL) {
   WebView *myWebView = [[WebView alloc] init];
   HICocoaViewSetView (myHICocoaView, myWebView);
   [myWebView release];
}

Getting the Cocoa View from a Wrapper View

If you have a Carbon wrapper view with an associated Cocoa view, you can use the HICocoaViewGetView function to get a pointer to the Cocoa view. Typically, you use this function when you want to send a message to the Cocoa view.

The following code example shows how to obtain a Cocoa web view from an existing wrapper view and load a webpage:

NSString *urlText = @"http://developer.apple.com/referencelibrary/";
WebView *myWebView = (WebView*) HICocoaViewGetView (myHICocoaView);
if (myWebView != NULL)
   [[myWebView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlText]]];

Using a Nib-Based Cocoa User Interface

If you use a Cocoa nib file to specify a more complex user interface, your Carbon application needs to load the nib at runtime in order to embed the Cocoa user interface in an HICocoaView. One way to do this is to use a custom controller object to load the nib and access the UI. You can use the NSViewController class to simplify this task. NSViewController makes it easy to load a nib and get access to the NSView-based user interface inside. The approach described here is adapted from a working sample application called HIView-NSView. The sample uses a subclass of NSViewController called WebViewController to implement some features in the user interface.

Listing 1 shows how to implement a wrapper function that creates a nib-based Carbon window, creates a nib-based Cocoa view that contains the user interface for a simple web browser, and embeds the user interface in an HICocoaView. An explanation for each numbered line of code follows the listing.

Listing 1  Using a nib-based Cocoa user interface in a Carbon window

static OSStatus MyNewWindow (void)
{
    OSStatus status = noErr;
 
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; // 1
 
    status = CreateWindowFromNib (gMainNibRef, CFSTR("MainWindow"), &gWindow); // 2
    require_noerr(status, CantCreateWindow);
 
    WebViewController* controller =
        [[WebViewController alloc] initWithNibName:@"WebView" bundle:nil]; // 3
    SetWRefCon(gWindow, (SRefCon)controller); // 4
 
    HIViewRef carbonView;
    status = HIViewFindByID (HIViewGetRoot(window), kMyHICocoaViewID, &carbonView); // 5
    require_noerr(status, CantFindHICocoaView);
 
    NSView* cocoaView = [controller view]; // 6
    if (cocoaView != nil)
        status = HICocoaViewSetView (carbonView, cocoaView); // 7
 
    ShowWindow(gWindow); // 8
 
CantCreateWindow:
CantFindHICocoaView:
 
    [pool release]; // 9
    return status;
}

Here’s what the code does:

  1. Creates a local autorelease pool. This step is necessary because this function is not being called by the toolbox.

  2. Creates a nib-based Carbon window. In this example, global variables are used for both the main nib object and the new window object.

  3. Creates a Cocoa view controller to gain access to the nib-based Cocoa view and to implement the Cocoa view’s UI.

  4. Stores the Cocoa view controller as window data. This information is used later to release the controller when the window is closed.

  5. Finds the HICocoaView wrapper view in the Carbon window.

  6. Retrieves the Cocoa view from the view controller.

  7. Embeds the Cocoa view in the HICocoaView wrapper view.

  8. Makes the Carbon window visible.

  9. Drains and releases the local autorelease pool.

Figure 3 illustrates a simple Cocoa web browser view displayed inside a Carbon window.


Figure 3  Cocoa user interface inside a Carbon window

A Cocoa web browser view inside a Carbon window

To learn how to write an NSViewController subclass that implements the user interface in Figure 3, see the sample application HIView-NSView.



< Previous PageNext Page > Hide TOC


© 2002, 2007 Apple Inc. All Rights Reserved. (Last updated: 2007-10-31)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.