Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
CarbonTransparentWindow.c
/* |
* File: CarbonTransparentWindow.c of CarbonTransparentWindow |
* |
* Contains: 2 Carbon transparent windows. |
* |
* Version: 1.0 |
* |
* Created: 6/20/05 |
* |
* Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
* ("Apple") in consideration of your agreement to the following terms, and your |
* use, installation, modification or redistribution of this Apple software |
* constitutes acceptance of these terms. If you do not agree with these terms, |
* please do not use, install, modify or redistribute this Apple software. |
* |
* In consideration of your agreement to abide by the following terms, and subject |
* to these terms, Apple grants you a personal, non-exclusive license, under AppleÍs |
* copyrights in this original Apple software (the "Apple Software"), to use, |
* reproduce, modify and redistribute the Apple Software, with or without |
* modifications, in source and/or binary forms; provided that if you redistribute |
* the Apple Software in its entirety and without modifications, you must retain |
* this notice and the following text and disclaimers in all such redistributions of |
* the Apple Software. Neither the name, trademarks, service marks or logos of |
* Apple Computer, Inc. may be used to endorse or promote products derived from the |
* Apple Software without specific prior written permission from Apple. Except as |
* expressly stated in this notice, no other rights or licenses, express or implied, |
* are granted by Apple herein, including but not limited to any patent rights that |
* may be infringed by your derivative works or by other works in which the Apple |
* Software may be incorporated. |
* |
* The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
* WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
* WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
* PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
* COMBINATION WITH YOUR PRODUCTS. |
* |
* IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
* OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
* (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
* |
* Copyright: Copyright © 2005 Apple Computer, Inc, All Rights Reserved |
*/ |
//**************************************************** |
//**************************************************** |
#pragma mark * compilation directives * |
//**************************************************** |
#pragma mark - |
#pragma mark * includes & imports * |
#include "CarbonTransparentWindow.h" |
//**************************************************** |
#pragma mark - |
#pragma mark * typedef's, struct's, enums, defines, etc. * |
//**************************************************** |
#pragma mark - |
#pragma mark * local (static) function prototypes * |
static pascal OSStatus UserPaneCompDraw(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData); |
static pascal OSStatus UserPaneNonCompDraw(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData); |
static OSStatus MakeWindowTransparent(WindowRef aWindowRef); |
static pascal OSStatus TransparentWindowHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData); |
//**************************************************** |
#pragma mark - |
#pragma mark * exported globals * |
//**************************************************** |
#pragma mark - |
#pragma mark * local (static) globals * |
//**************************************************** |
#pragma mark - |
#pragma mark * exported function implementations * |
// the code for Do_NewCompositingWindow and Do_NewNonCompositingWindow is |
// actually the same except for the name of the nib resource (CompWindow vs. NonCompWindow) |
// and the user pane draw handler which uses QuickDraw in the Non-Compositing window and |
// Quartz in the Compositing window |
// in the nib, both windows are also the same except that one has the compositing attribute |
// and the other one has not. |
/***************************************************** |
* |
* Do_NewCompositingWindow() |
* |
* Purpose: Create a compositing transparent window |
* |
* Inputs: none |
* |
* Returns: OSStatus - error code (0 == no error) |
*/ |
OSStatus Do_NewCompositingWindow() |
{ |
WindowRef aWindowRef = NULL; |
OSStatus status; |
// create a Nib reference passing the name of the nib file (without the .nib extension) |
// CreateNibReference only searches into the application bundle. |
IBNibRef anIBNibRef; |
status = CreateNibReference(CFSTR("main"), &anIBNibRef); |
require_noerr(status, CantGetNibRef); |
// create a window. "CompWindow" is the name of the window object. This name is set in |
// InterfaceBuilder when the nib is created. |
status = CreateWindowFromNib(anIBNibRef, CFSTR("CompWindow"), &aWindowRef); |
require_noerr(status, CantCreateWindow); |
require(aWindowRef != NULL, CantCreateWindow); |
// we no longer need the nib reference |
DisposeNibReference(anIBNibRef); |
// looking for our user pane |
HIViewID userPaneID = { 'UsrP', 100 }; |
HIViewRef userPane; |
status = HIViewFindByID(HIViewGetRoot(aWindowRef), userPaneID, &userPane); |
require_noerr(status, CantCreateWindow); |
require(userPane != NULL, CantCreateWindow); |
// so that we can install its custom drawing handler |
EventTypeSpec eventCD = { kEventClassControl, kEventControlDraw }; |
status = InstallControlEventHandler(userPane, UserPaneCompDraw, 1, &eventCD, userPane, NULL); |
require_noerr(status, CantCreateWindow); |
// make this window transparent |
status = MakeWindowTransparent(aWindowRef); |
require_noerr(status, MakeWindowTransparent); |
ShowWindow(aWindowRef); |
MakeWindowTransparent: |
CantCreateWindow: |
CantGetNibRef: |
return status; |
} // Do_NewCompositingWindow |
/***************************************************** |
* |
* Do_NewNonCompositingWindow() |
* |
* Purpose: Create a non-compositing transparent window |
* |
* Inputs: none |
* |
* Returns: OSStatus - error code (0 == no error) |
*/ |
OSStatus Do_NewNonCompositingWindow() |
{ |
WindowRef aWindowRef = NULL; |
OSStatus status; |
// create a Nib reference passing the name of the nib file (without the .nib extension) |
// CreateNibReference only searches into the application bundle. |
IBNibRef anIBNibRef; |
status = CreateNibReference(CFSTR("main"), &anIBNibRef); |
require_noerr(status, CantGetNibRef); |
// create a window. "NonCompWindow" is the name of the window object. This name is set in |
// InterfaceBuilder when the nib is created. |
status = CreateWindowFromNib(anIBNibRef, CFSTR("NonCompWindow"), &aWindowRef); |
require_noerr(status, CantCreateWindow); |
require(aWindowRef != NULL, CantCreateWindow); |
// we no longer need the nib reference |
DisposeNibReference(anIBNibRef); |
// looking for our user pane |
HIViewID userPaneID = { 'UsrP', 100 }; |
HIViewRef userPane; |
status = HIViewFindByID(HIViewGetRoot(aWindowRef), userPaneID, &userPane); |
require_noerr(status, CantCreateWindow); |
require(userPane != NULL, CantCreateWindow); |
// so that we can install its custom drawing handler |
EventTypeSpec eventCD = { kEventClassControl, kEventControlDraw }; |
status = InstallControlEventHandler(userPane, UserPaneNonCompDraw, 1, &eventCD, userPane, NULL); |
require_noerr(status, CantCreateWindow); |
// make this window transparent |
status = MakeWindowTransparent(aWindowRef); |
require_noerr(status, MakeWindowTransparent); |
ShowWindow(aWindowRef); |
MakeWindowTransparent: |
CantCreateWindow: |
CantGetNibRef: |
return status; |
} // Do_NewNonCompositingWindow |
//**************************************************** |
#pragma mark - |
#pragma mark * local (static) function implementations * |
/***************************************************** |
* |
* UserPaneCompDraw(inHandlerCallRef, inEvent, inUserData) |
* |
* Purpose: The draw handler for our user pane in the Compositing window, we just paint 2 rectangles in 2 different transparent colors with Quartz |
* |
* Inputs: inHandlerCallRef - reference to the current handler call chain |
* inEvent - the event |
* inUserData - app-specified data you passed in the call to InstallEventHandler |
* |
* Returns: OSStatus - error code (0 == no error) |
*/ |
static pascal OSStatus UserPaneCompDraw(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData) |
{ |
OSStatus status; |
CGContextRef context; |
status = GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef, NULL, sizeof(context), NULL, &context); |
require_noerr(status, GetEventParameter); |
HIRect bounds; |
status = HIViewGetBounds((HIViewRef)inUserData, &bounds); |
require_noerr(status, HIViewGetBounds); |
CGContextSetRGBFillColor(context, 1, 0, 0, 0.5); |
CGContextFillRect(context, bounds); |
CGContextSetRGBFillColor(context, 1, 1, 0, 0.5); |
bounds = CGRectInset(bounds, 30, 30); |
CGContextFillRect(context, bounds); |
GetEventParameter: |
HIViewGetBounds: |
return status; |
} // UserPaneCompDraw |
/***************************************************** |
* |
* UserPaneNonCompDraw(inHandlerCallRef, inEvent, inUserData) |
* |
* Purpose: The draw handler for our user pane in the Non-Compositing window, we just paint 2 rectangles in 2 different colors with QuickDraw |
* |
* Inputs: inHandlerCallRef - reference to the current handler call chain |
* inEvent - the event |
* inUserData - app-specified data you passed in the call to InstallEventHandler |
* |
* Returns: OSStatus - error code (0 == no error) |
*/ |
static pascal OSStatus UserPaneNonCompDraw(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData) |
{ |
OSStatus status = noErr; |
Rect bounds; |
GetControlBounds((HIViewRef)inUserData, &bounds); |
RGBColor redColor = { 65535, 0, 0 }; |
RGBForeColor(&redColor); |
PaintRect(&bounds); |
RGBColor yellowColor = { 65535, 65535, 0 }; |
RGBForeColor(&yellowColor); |
InsetRect(&bounds, 30, 30); |
PaintRect(&bounds); |
return status; |
} // UserPaneNonCompDraw |
/***************************************************** |
* |
* MakeWindowTransparent(aWindowRef) |
* |
* Purpose: Makes a window (Non-Compositing or Compositing) transparent using custom handlers |
* |
* Inputs: aWindowRef - the window to make transparent |
* |
* Returns: OSStatus - error code (0 == no error) |
*/ |
static OSStatus MakeWindowTransparent(WindowRef aWindowRef) |
{ |
OSStatus status = paramErr; |
require(aWindowRef != NULL, paramErr); |
// is the window compositing or not? |
WindowAttributes attributes; |
status = GetWindowAttributes(aWindowRef, &attributes); |
require_noerr(status, GetWindowAttributes); |
if (attributes & kWindowCompositingAttribute) |
{ |
// it is compositing so we intercept the kEventWindowGetRegion event to be able to specify an empty opaque region |
EventTypeSpec wCompositingEvents = { kEventClassWindow, kEventWindowGetRegion }; |
status = InstallWindowEventHandler(aWindowRef, TransparentWindowHandler, 1, &wCompositingEvents, aWindowRef, NULL); |
require_noerr(status, InstallWindowEventHandler); |
HIViewRef contentView; |
status = HIViewFindByID(HIViewGetRoot(aWindowRef), kHIViewWindowContentID, &contentView); |
require_noerr(status, HIViewFindByID); |
// and we intercept the kEventControlDraw event of our content view so that we can make it transparent |
EventTypeSpec cCompositingEvents = { kEventClassControl, kEventControlDraw }; |
status = InstallControlEventHandler(contentView, TransparentWindowHandler, 1, &cCompositingEvents, contentView, NULL); |
require_noerr(status, InstallControlEventHandler); |
} |
else |
{ |
// it is non-compositing so we intercept the kEventWindowGetRegion event to be able to specify an empty opaque region |
// and we intercept the kEventWindowDrawContent event of our window so that we can make it transparent |
EventTypeSpec wNonCompositingEvents[] = |
{ |
{ kEventClassWindow, kEventWindowGetRegion }, |
{ kEventClassWindow, kEventWindowDrawContent } |
}; |
status = InstallWindowEventHandler(aWindowRef, TransparentWindowHandler, GetEventTypeCount(wNonCompositingEvents), wNonCompositingEvents, aWindowRef, NULL); |
require_noerr(status, InstallWindowEventHandler); |
} |
// telling the HIToolbox that our window is not opaque so that we will be asked for the opaque region |
UInt32 features; |
status = GetWindowFeatures(aWindowRef, &features); |
require_noerr(status, GetWindowFeatures); |
if ( ( features & kWindowIsOpaque ) != 0 ) |
{ |
status = HIWindowChangeFeatures(aWindowRef, 0, kWindowIsOpaque); |
require_noerr(status, HIWindowChangeFeatures); |
} |
// force opaque shape to be recalculated |
status = ReshapeCustomWindow(aWindowRef); |
require_noerr(status, ReshapeCustomWindow); |
// ensure that HIToolbox doesn't use standard shadow style, which defeats custom opaque shape |
status = SetWindowAlpha(aWindowRef, 0.999); |
require_noerr(status, SetWindowAlpha); |
SetWindowAlpha: |
ReshapeCustomWindow: |
HIWindowChangeFeatures: |
GetWindowFeatures: |
InstallControlEventHandler: |
HIViewFindByID: |
InstallWindowEventHandler: |
GetWindowAttributes: |
paramErr: |
return status; |
} // MakeWindowTransparent |
/***************************************************** |
* |
* TransparentWindowHandler(inHandlerCallRef, inEvent, inUserData) |
* |
* Purpose: The handlers for the 3 events that we intercept in MakeWindowTransparent |
* |
* Inputs: inHandlerCallRef - reference to the current handler call chain |
* inEvent - the event |
* inUserData - app-specified data you passed in the call to InstallEventHandler |
* |
* Returns: OSStatus - error code (0 == no error) |
*/ |
static pascal OSStatus TransparentWindowHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData) |
{ |
OSStatus status = eventNotHandledErr; |
switch(GetEventKind(inEvent)) |
{ |
case kEventWindowGetRegion: |
{ |
WindowRegionCode code; |
RgnHandle rgn; |
// which region code is being queried? |
GetEventParameter(inEvent, kEventParamWindowRegionCode, typeWindowRegionCode, NULL, sizeof(code), NULL, &code); |
// if it is the opaque region code then set the region to Empty and return noErr to stop the propagation |
if (code == kWindowOpaqueRgn) |
{ |
GetEventParameter(inEvent, kEventParamRgnHandle, typeQDRgnHandle, NULL, sizeof(rgn), NULL, &rgn); |
SetEmptyRgn(rgn); |
status = noErr; |
} |
break; |
} |
case kEventWindowDrawContent: |
{ |
GrafPtr port; |
CGContextRef context; |
Rect portBounds; |
HIRect bounds; |
GetPort(&port); |
GetPortBounds(port, &portBounds); |
// we need a Quartz context so that we can use transparency |
QDBeginCGContext(port, &context); |
// make the whole content transparent |
bounds = CGRectMake(0, 0, portBounds.right, portBounds.bottom); |
CGContextClearRect(context, bounds); |
QDEndCGContext(port, &context); |
// we need to let the HIToolbox and the regular kEventWindowDrawContent handler do their work, |
// mainly draw the subviews, so we return eventNotHandledErr to propagate. |
status = eventNotHandledErr; |
break; |
} |
case kEventControlDraw: |
{ |
CGContextRef context; |
HIRect bounds; |
GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef, NULL, sizeof(context), NULL, &context); |
HIViewGetBounds((HIViewRef)inUserData, &bounds); |
// make the whole content transparent |
CGContextClearRect(context, bounds); |
// we must not let the default draw handler of the content view be called (it would draw the default opaque theme) |
// so we return noErr to stop the propagation. |
status = noErr; |
break; |
} |
} |
return status; |
} // TransparentWindowHandler |
Copyright © 2005 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2005-08-10