| Index: plugin/mac/overlay_window_mac.mm
|
| ===================================================================
|
| --- plugin/mac/overlay_window_mac.mm (revision 0)
|
| +++ plugin/mac/overlay_window_mac.mm (revision 0)
|
| @@ -0,0 +1,286 @@
|
| +/*
|
| + * Copyright 2010, Google Inc.
|
| + * All rights reserved.
|
| + *
|
| + * Redistribution and use in source and binary forms, with or without
|
| + * modification, are permitted provided that the following conditions are
|
| + * met:
|
| + *
|
| + * * Redistributions of source code must retain the above copyright
|
| + * notice, this list of conditions and the following disclaimer.
|
| + * * Redistributions in binary form must reproduce the above
|
| + * copyright notice, this list of conditions and the following disclaimer
|
| + * in the documentation and/or other materials provided with the
|
| + * distribution.
|
| + * * Neither the name of Google Inc. nor the names of its
|
| + * contributors may be used to endorse or promote products derived from
|
| + * this software without specific prior written permission.
|
| + *
|
| + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| + */
|
| +
|
| +#import "overlay_window_mac.h"
|
| +
|
| +#import "plugin/mac/graphics_utils_mac.h"
|
| +
|
| +#ifdef O3D_PLUGIN_ENABLE_FULLSCREEN_MSG
|
| +
|
| +#define kTransitionTime 1.0
|
| +
|
| +namespace o3d {
|
| +
|
| +// A little wrapper for ATSUSetAttributes to make calling it with one attribute
|
| +// less annoying.
|
| +static void MySetAttribute(ATSUStyle style,
|
| + ATSUAttributeTag tag,
|
| + ByteCount size,
|
| + ATSUAttributeValuePtr value) {
|
| +
|
| + ATSUAttributeTag tags[2] = {tag, 0};
|
| + ByteCount sizes[2] = {size, 0};
|
| + ATSUAttributeValuePtr values[2] = {value, 0};
|
| +
|
| + ATSUSetAttributes(style, 1, tags, sizes, values);
|
| +}
|
| +
|
| +// A little wrapper for ATSUSetLayoutControls to make calling it with one
|
| +// attribute less annoying.
|
| +static void MySetLayoutControl(ATSUTextLayout layout,
|
| + ATSUAttributeTag tag,
|
| + ByteCount size,
|
| + ATSUAttributeValuePtr value) {
|
| +
|
| + ATSUAttributeTag tags[2] = {tag, 0};
|
| + ByteCount sizes[2] = {size, 0};
|
| + ATSUAttributeValuePtr values[2] = {value, 0};
|
| +
|
| + ATSUSetLayoutControls(layout, 1, tags, sizes, values);
|
| +}
|
| +
|
| +// Returns the unicode 16 chars that we need to display as the fullscreen
|
| +// message. Should be disposed with free() after use.
|
| +static UniChar * GetFullscreenDisplayText(int *returned_length) {
|
| + // TODO this will need to be a localized string.
|
| + NSString* ns_display_text = @"Press ESC to exit fullscreen";
|
| + int count = [ns_display_text length];
|
| + UniChar* display_text_16 = (UniChar*) calloc(count, sizeof(UniChar));
|
| +
|
| + [ns_display_text getCharacters:display_text_16];
|
| + *returned_length = count;
|
| + return display_text_16;
|
| +}
|
| +
|
| +
|
| +static void DrawToOverlayWindow(WindowRef overlayWindow) {
|
| + CGContextRef overlayContext = NULL;
|
| + CGFloat kWhiteOpaque[] = {1.0, 1.0, 1.0, 1.0};
|
| + CGFloat kBlackNotOpaque[] = {0.0, 0.0, 0.0, 0.5};
|
| + Rect bounds = {0, 0, 0, 0};
|
| + const char* kOverlayWindowFontName = "Arial";
|
| + const int kPointSize = 22;
|
| + const float kShadowRadius = 5.0;
|
| + const float kRoundRectRadius = 9.0;
|
| + const float kTextLeftMargin = 15.0;
|
| + const float kTextBottomMargin = 22.0;
|
| +
|
| + QDBeginCGContext(GetWindowPort(overlayWindow), &overlayContext);
|
| + GetWindowBounds(overlayWindow, kWindowContentRgn, &bounds);
|
| +
|
| + // Make the global rect local.
|
| + bounds.right -= bounds.left;
|
| + bounds.left = 0;
|
| + bounds.bottom -= bounds.top;
|
| + bounds.top = 0;
|
| +
|
| + CGRect cgTotalRect = Rect2CGRect(bounds);
|
| + CGContextSetShouldSmoothFonts(overlayContext, true);
|
| + CGContextClearRect(overlayContext, cgTotalRect);
|
| +
|
| + CGColorSpaceRef myColorSpace = CGColorSpaceCreateDeviceRGB();
|
| + CGColorRef shadow = CGColorCreate(myColorSpace, kBlackNotOpaque);
|
| + CGColorRef roundRectBackColor = CGColorCreate(myColorSpace, kBlackNotOpaque);
|
| + CGSize shadowOffset = {0.0,0.0};
|
| +
|
| + CGContextSetFillColor(overlayContext, kWhiteOpaque);
|
| + CGContextSetStrokeColor(overlayContext, kWhiteOpaque);
|
| +
|
| + // Draw the round rect background.
|
| + CGContextSaveGState(overlayContext);
|
| + CGContextSetFillColorWithColor(overlayContext, roundRectBackColor);
|
| + CGRect cg_rounded_area =
|
| + CGRectMake(// Offset from left and bottom to give shadow its space.
|
| + kShadowRadius, kShadowRadius,
|
| + // Increase width and height so rounded corners
|
| + // will be clipped out, except at bottom left.
|
| + (bounds.right - bounds.left) + 30,
|
| + (bounds.bottom - bounds.top) + 30);
|
| + // Save state before applying shadow.
|
| + CGContextSetShadowWithColor(overlayContext, shadowOffset,
|
| + kShadowRadius, shadow);
|
| + PaintRoundedCGRect(overlayContext, cg_rounded_area, kRoundRectRadius, true);
|
| + // Restore graphics state to remove shadow.
|
| + CGContextRestoreGState(overlayContext);
|
| +
|
| + // Draw the text.
|
| + int text_length = 0;
|
| + UniChar* display_text = GetFullscreenDisplayText(&text_length);
|
| +
|
| + if ((text_length > 0) && (display_text != NULL)) {
|
| + ATSUStyle style;
|
| + ATSUTextLayout layout;
|
| + ATSUFontID font;
|
| + Fixed pointSize = Long2Fix(kPointSize);
|
| + Boolean is_bold = true;
|
| +
|
| + ATSUCreateStyle(&style);
|
| + ATSUFindFontFromName(kOverlayWindowFontName, strlen(kOverlayWindowFontName),
|
| + kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
|
| + kFontNoLanguageCode, &font);
|
| +
|
| + MySetAttribute(style, kATSUFontTag, sizeof(font), &font);
|
| + MySetAttribute(style, kATSUSizeTag, sizeof(pointSize), &pointSize);
|
| + MySetAttribute(style, kATSUQDBoldfaceTag, sizeof(Boolean), &is_bold);
|
| +
|
| +
|
| + ATSUCreateTextLayout(&layout);
|
| + ATSUSetTextPointerLocation(layout, display_text,
|
| + kATSUFromTextBeginning, kATSUToTextEnd,
|
| + text_length);
|
| + ATSUSetRunStyle(layout, style, kATSUFromTextBeginning, kATSUToTextEnd);
|
| +
|
| + MySetLayoutControl(layout, kATSUCGContextTag,
|
| + sizeof(CGContextRef), &overlayContext);
|
| +
|
| + // Need to enable this for languages like Japanese to draw as something
|
| + // other than a series of squares.
|
| + ATSUSetTransientFontMatching(layout, true);
|
| +
|
| +
|
| + CGContextSetFillColor(overlayContext, kWhiteOpaque);
|
| + ATSUDrawText(layout, kATSUFromTextBeginning, kATSUToTextEnd,
|
| + X2Fix(kShadowRadius + kTextLeftMargin),
|
| + X2Fix(kShadowRadius + kTextBottomMargin));
|
| + ATSUDisposeStyle(style);
|
| + ATSUDisposeTextLayout(layout);
|
| + free(display_text);
|
| + }
|
| +
|
| + CGColorRelease(roundRectBackColor);
|
| + CGColorRelease(shadow);
|
| + CGColorSpaceRelease (myColorSpace);
|
| +
|
| + QDEndCGContext(GetWindowPort(overlayWindow), &overlayContext);
|
| +}
|
| +
|
| +static OSStatus HandleOverlayWindow(EventHandlerCallRef inHandlerCallRef,
|
| + EventRef inEvent,
|
| + void *inUserData) {
|
| + OSType event_class = GetEventClass(inEvent);
|
| + OSType event_kind = GetEventKind(inEvent);
|
| +
|
| + if (event_class == kEventClassWindow &&
|
| + event_kind == kEventWindowPaint) {
|
| + WindowRef theWindow = NULL;
|
| + GetEventParameter(inEvent, kEventParamDirectObject,
|
| + typeWindowRef, NULL,
|
| + sizeof(theWindow), NULL,
|
| + &theWindow);
|
| + if (theWindow) {
|
| + CallNextEventHandler(inHandlerCallRef, inEvent);
|
| + DrawToOverlayWindow(theWindow);
|
| + }
|
| + }
|
| +
|
| + return noErr;
|
| +}
|
| +
|
| +
|
| +
|
| +static Rect GetOverlayWindowRect(bool visible) {
|
| +#define kOverlayHeight 60
|
| +#define kOverlayWidth 340
|
| + Rect screen_bounds = CGRect2Rect(CGDisplayBounds(CGMainDisplayID()));
|
| + Rect hidden_window_bounds = {screen_bounds.top - kOverlayHeight,
|
| + screen_bounds.right - kOverlayWidth,
|
| + screen_bounds.top,
|
| + screen_bounds.right};
|
| + Rect visible_window_bounds = {screen_bounds.top,
|
| + screen_bounds.right - kOverlayWidth,
|
| + screen_bounds.top + kOverlayHeight,
|
| + screen_bounds.right};
|
| +
|
| + return (visible) ? visible_window_bounds : hidden_window_bounds;
|
| +}
|
| +
|
| +
|
| +static WindowRef CreateOverlayWindow(void) {
|
| + Rect window_bounds = GetOverlayWindowRect(false);
|
| + WindowClass wClass = kOverlayWindowClass;
|
| + WindowRef window = NULL;
|
| + OSStatus err = noErr;
|
| + WindowAttributes overlayAttributes = kWindowNoShadowAttribute |
|
| + kWindowIgnoreClicksAttribute |
|
| + kWindowNoActivatesAttribute |
|
| + kWindowStandardHandlerAttribute;
|
| + EventTypeSpec eventTypes[] = {
|
| + {kEventClassWindow, kEventWindowPaint},
|
| + {kEventClassWindow, kEventWindowShown}
|
| + };
|
| +
|
| + err = CreateNewWindow(wClass,
|
| + overlayAttributes,
|
| + &window_bounds,
|
| + &window);
|
| + if (err)
|
| + return NULL;
|
| +
|
| + SetWindowLevel(window, CGShieldingWindowLevel() + 1);
|
| + InstallEventHandler(GetWindowEventTarget(window), HandleOverlayWindow,
|
| + sizeof(eventTypes)/sizeof(eventTypes[0]), eventTypes,
|
| + NULL, NULL);
|
| + return window;
|
| +}
|
| +
|
| +OverlayWindowMac::OverlayWindowMac()
|
| + : overlay_window_(NULL),
|
| + time_to_hide_overlay_(0.0) {
|
| + overlay_window_ = CreateOverlayWindow();
|
| + ShowWindow(overlay_window_);
|
| + o3d::SlideWindowToRect(overlay_window_,
|
| + Rect2CGRect(GetOverlayWindowRect(true)),
|
| + kTransitionTime);
|
| +
|
| + // Hide the overlay text 4 seconds from now.
|
| + time_to_hide_overlay_ = [NSDate timeIntervalSinceReferenceDate] + 4.0;
|
| +}
|
| +
|
| +OverlayWindowMac::~OverlayWindowMac() {
|
| + HideWindow(overlay_window_);
|
| + ReleaseWindowGroup(GetWindowGroup(overlay_window_));
|
| + DisposeWindow(overlay_window_);
|
| +}
|
| +
|
| +void OverlayWindowMac::IdleCallback() {
|
| + if ((overlay_window_ != NULL) &&
|
| + (time_to_hide_overlay_ != 0.0) &&
|
| + (time_to_hide_overlay_ < [NSDate timeIntervalSinceReferenceDate])) {
|
| + time_to_hide_overlay_ = 0.0;
|
| + SlideWindowToRect(overlay_window_,
|
| + Rect2CGRect(GetOverlayWindowRect(false)),
|
| + kTransitionTime);
|
| + }
|
| +}
|
| +
|
| +} // namespace o3d
|
| +
|
| +#endif // O3D_PLUGIN_ENABLE_FULLSCREEN_MSG
|
|
|
| Property changes on: plugin/mac/overlay_window_mac.mm
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|