diff options
author | kbr@google.com <kbr@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-19 21:58:47 +0000 |
---|---|---|
committer | kbr@google.com <kbr@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-19 21:58:47 +0000 |
commit | 82fa5dd3894c873f8cf852a7921c5f8dea70477a (patch) | |
tree | 10e637e1885c50ae8470f4ecb6b7b5ffdcf9995d /o3d/plugin/mac | |
parent | b560bed97395fec57d5c91f26433504bcf8c6d90 (diff) | |
download | chromium_src-82fa5dd3894c873f8cf852a7921c5f8dea70477a.zip chromium_src-82fa5dd3894c873f8cf852a7921c5f8dea70477a.tar.gz chromium_src-82fa5dd3894c873f8cf852a7921c5f8dea70477a.tar.bz2 |
Refactored full-screen code under FullscreenWindowMac base class and
overlay window code into OverlayWindowMac class. This is an
intermediate step toward a Cocoa and CGL implementation.
Verified that mouse and key events continue to work in full-screen
mode with full-screen sample and a modified render-mode.html in
Firefox 3.6.3 on Mac OS X, where O3D continues to use the Quickdraw
drawing model.
BUG=http://code.google.com/p/o3d/issues/detail?id=221
TEST=none
Review URL: http://codereview.chromium.org/2129015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@47733 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d/plugin/mac')
-rw-r--r-- | o3d/plugin/mac/fullscreen_window_mac.h | 82 | ||||
-rw-r--r-- | o3d/plugin/mac/fullscreen_window_mac.mm | 388 | ||||
-rw-r--r-- | o3d/plugin/mac/main_mac.mm | 15 | ||||
-rw-r--r-- | o3d/plugin/mac/overlay_window_mac.h | 62 | ||||
-rw-r--r-- | o3d/plugin/mac/overlay_window_mac.mm | 286 | ||||
-rw-r--r-- | o3d/plugin/mac/plugin_mac.h | 3 | ||||
-rw-r--r-- | o3d/plugin/mac/plugin_mac.mm | 537 |
7 files changed, 837 insertions, 536 deletions
diff --git a/o3d/plugin/mac/fullscreen_window_mac.h b/o3d/plugin/mac/fullscreen_window_mac.h new file mode 100644 index 0000000..693150d --- /dev/null +++ b/o3d/plugin/mac/fullscreen_window_mac.h @@ -0,0 +1,82 @@ +/* + * 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. + */ + +#ifndef O3D_PLUGIN_MAC_FULLSCREEN_WINDOW_MAC_H_ +#define O3D_PLUGIN_MAC_FULLSCREEN_WINDOW_MAC_H_ + +#include <OpenGL/OpenGL.h> + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" + +#include "plugin/mac/overlay_window_mac.h" + +// Abstract base class for the full-screen window. Provides the +// ability to easily choose between Carbon and Cocoa implementations. + +namespace glue { +namespace _o3d { +class PluginObject; +} // namespace _o3d +} // namespace glue + +namespace o3d { + +class FullscreenWindowMac { + public: + static FullscreenWindowMac* Create(glue::_o3d::PluginObject* obj, + int target_width, + int target_height); + virtual ~FullscreenWindowMac(); + + virtual bool Initialize(int target_width, + int target_height); + virtual void IdleCallback(); + virtual bool Shutdown(const GLint* last_buffer_rect); + + virtual CGRect GetWindowBounds() const = 0; + virtual bool IsActive() const = 0; + + protected: + FullscreenWindowMac() {} + + private: +#ifdef O3D_PLUGIN_ENABLE_FULLSCREEN_MSG + scoped_ptr<OverlayWindowMac> overlay_window_; +#endif + + DISALLOW_COPY_AND_ASSIGN(FullscreenWindowMac); +}; + +} // namespace o3d + +#endif // O3D_PLUGIN_MAC_FULLSCREEN_WINDOW_MAC_H_ + diff --git a/o3d/plugin/mac/fullscreen_window_mac.mm b/o3d/plugin/mac/fullscreen_window_mac.mm new file mode 100644 index 0000000..6824894 --- /dev/null +++ b/o3d/plugin/mac/fullscreen_window_mac.mm @@ -0,0 +1,388 @@ +/* + * 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 "fullscreen_window_mac.h" + +#include <QuickTime/QuickTime.h> + +#import "graphics_utils_mac.h" +#import "overlay_window_mac.h" +#import "plugin_mac.h" +#import "core/cross/display_mode.h" +#import "plugin/cross/o3d_glue.h" +#import "plugin/mac/graphics_utils_mac.h" + +using glue::_o3d::PluginObject; + +namespace o3d { + +//---------------------------------------------------------------------- +// Carbon full-screen implementation. +// + +// Convenience function for fetching SInt32 parameters from Carbon EventRefs. +static SInt32 GetIntEventParam(EventRef inEvent, EventParamName inName) { + SInt32 value = 0; + return (GetEventParameter(inEvent, inName, typeSInt32, NULL, sizeof(value), + NULL, &value) == noErr) ? value : 0; +} + + +// Maps the MacOS button numbers to the constants used by our +// event mechanism. Not quite as obvious as you might think, as the Mac +// thinks the numbering should go left, right, middle and our W3C-influenced +// system goes left, middle, right. +// Defaults to left-button if passed a strange value. Pass Cocoa mouse button +// codes as-is (they start at 0), pass Carbon button codes - 1. +o3d::Event::Button MacOSMouseButtonNumberToO3DButton(int inButton) { + + switch(inButton) { + case 0: + return o3d::Event::BUTTON_LEFT; + case 1: + return o3d::Event::BUTTON_RIGHT; + case 2: + return o3d::Event::BUTTON_MIDDLE; + case 3: + return o3d::Event::BUTTON_4; + case 4: + return o3d::Event::BUTTON_5; + } + + return o3d::Event::BUTTON_LEFT; +} + + +// Handles the CarbonEvents that we get sent for the fullscreen mode window. +// Most of these can be converted to EventRecord events and handled by the +// HandleMacEvent() function in main_mac.mm, but some have no equivalent in +// that space, scroll-wheel events for example, and so must be handled here. +static OSStatus HandleFullscreenWindow(EventHandlerCallRef inHandlerCallRef, + EventRef inEvent, + void *inUserData) { + OSType event_class = GetEventClass(inEvent); + OSType event_kind = GetEventKind(inEvent); + NPP instance = (NPP)inUserData; + PluginObject* obj = (PluginObject*)(instance->pdata); + HIPoint mouse_loc = { 0.0, 0.0 }; + bool is_scroll_event = event_class == kEventClassMouse && + (event_kind == kEventMouseScroll || + event_kind == kEventMouseWheelMoved); + + // If it's any kind of mouse event, get the global mouse loc. + if (event_class == kEventClassMouse) { + GetEventParameter(inEvent, kEventParamMouseLocation, + typeHIPoint, NULL, + sizeof(mouse_loc), NULL, + &mouse_loc); + } + + // Handle the two kinds of scroll message we understand. + if (is_scroll_event) { + SInt32 x_scroll = 0; + SInt32 y_scroll = 0; + EventMouseWheelAxis axis = kEventMouseWheelAxisY; + + switch (event_kind) { + // The newer kind of scroll event, as sent when two-finger + // dragging on a touchpad. + case kEventMouseScroll: + x_scroll = GetIntEventParam(inEvent, + kEventParamMouseWheelSmoothHorizontalDelta); + y_scroll = GetIntEventParam(inEvent, + kEventParamMouseWheelSmoothVerticalDelta); + + // only pass x or y value - pass whichever is larger + if (x_scroll && y_scroll) { + if (abs(x_scroll) > abs(y_scroll)) + y_scroll = 0; + else + x_scroll = 0; + } + break; + // The older kind of scroll event, as sent when using the wheel on + // a third-party mouse. + case kEventMouseWheelMoved: + GetEventParameter(inEvent, kEventParamMouseWheelAxis, + typeMouseWheelAxis, NULL, + sizeof(axis), NULL, + &axis); + + if (axis == kEventMouseWheelAxisY) { + y_scroll = GetIntEventParam(inEvent, + kEventParamMouseWheelDelta); + } else { + x_scroll = GetIntEventParam(inEvent, + kEventParamMouseWheelDelta); + } + break; + } + + // Dispatch the event now that we have all the data. + if (x_scroll || y_scroll) { + o3d::Event event(o3d::Event::TYPE_WHEEL); + event.set_delta(x_scroll, y_scroll); + // Global and local locs are the same, in this case, + // as we have a fullscreen window at 0,0. + event.set_position(mouse_loc.x, mouse_loc.y, + mouse_loc.x, mouse_loc.y, true); + obj->client()->AddEventToQueue(event); + } + return noErr; + } else if (event_class == kEventClassMouse && + (event_kind == kEventMouseDown || event_kind == kEventMouseUp)) { + + o3d::Event::Type type = (event_kind == kEventMouseDown) ? + o3d::Event::TYPE_MOUSEDOWN : + o3d::Event::TYPE_MOUSEUP; + o3d::Event event(type); + event.set_position(mouse_loc.x, mouse_loc.y, + mouse_loc.x, mouse_loc.y, true); + + EventMouseButton button = 0; + GetEventParameter(inEvent, kEventParamMouseButton, + typeMouseButton, NULL, + sizeof(button), NULL, + &button); + // Carbon mouse button numbers start at 1, so subtract 1 here - + // Cocoa mouse buttons, by contrast, start at 0). + event.set_button(MacOSMouseButtonNumberToO3DButton(button - 1)); + + // add the modifiers to the event, if any + UInt32 carbonMods = GetIntEventParam(inEvent, + kEventParamKeyModifiers); + if (carbonMods) { + int modifier_state = 0; + if (carbonMods & controlKey) { + modifier_state |= o3d::Event::MODIFIER_CTRL; + } + if (carbonMods & shiftKey) { + modifier_state |= o3d::Event::MODIFIER_SHIFT; + } + if (carbonMods & optionKey) { + modifier_state |= o3d::Event::MODIFIER_ALT; + } + if (carbonMods & cmdKey) { + modifier_state |= o3d::Event::MODIFIER_META; + } + + event.set_modifier_state(modifier_state); + } + + obj->client()->AddEventToQueue(event); + } else { // not a scroll event or a click + + // All other events are currently handled by being converted to an + // old-style EventRecord as passed by the classic NPAPI interface + // and dispatched through our common routine. + EventRecord eventRecord; + + if (ConvertEventRefToEventRecord(inEvent, &eventRecord)) { + HandleMacEvent(&eventRecord, (NPP)inUserData); + return noErr; + } else { + return eventNotHandledErr; + } + } + return noErr; +} + + +static WindowRef CreateFullscreenWindow(WindowRef window, + PluginObject *obj) { + Rect bounds = CGRect2Rect(CGDisplayBounds(CGMainDisplayID())); + OSStatus err = noErr; + EventTypeSpec eventTypes[] = { + {kEventClassKeyboard, kEventRawKeyDown}, + {kEventClassKeyboard, kEventRawKeyRepeat}, + {kEventClassKeyboard, kEventRawKeyUp}, + {kEventClassMouse, kEventMouseDown}, + {kEventClassMouse, kEventMouseUp}, + {kEventClassMouse, kEventMouseMoved}, + {kEventClassMouse, kEventMouseDragged}, + {kEventClassMouse, kEventMouseScroll}, + {kEventClassMouse, kEventMouseWheelMoved} + }; + + if (window == NULL) + err = CreateNewWindow(kSimpleWindowClass, + kWindowStandardHandlerAttribute, + &bounds, + &window); + if (err) + return NULL; + + SetWindowLevel(window, CGShieldingWindowLevel() + 1); + + InstallEventHandler(GetWindowEventTarget(window), HandleFullscreenWindow, + sizeof(eventTypes)/sizeof(eventTypes[0]), eventTypes, + obj->npp(), NULL); + ShowWindow(window); + return window; +} + +class CarbonFullscreenWindowMac : public FullscreenWindowMac { + public: + CarbonFullscreenWindowMac(PluginObject* obj); + virtual ~CarbonFullscreenWindowMac(); + + virtual bool Initialize(int target_width, int target_height); + virtual bool Shutdown(const GLint* last_buffer_rect); + virtual CGRect GetWindowBounds() const; + virtual bool IsActive() const; + + private: + PluginObject* obj_; + WindowRef fullscreen_window_; + Ptr fullscreen_state_; + + DISALLOW_COPY_AND_ASSIGN(CarbonFullscreenWindowMac); +}; + +CarbonFullscreenWindowMac::CarbonFullscreenWindowMac(PluginObject* obj) + : obj_(obj), + fullscreen_window_(NULL), + fullscreen_state_(NULL) { +} + +CarbonFullscreenWindowMac::~CarbonFullscreenWindowMac() { +} + +bool CarbonFullscreenWindowMac::Initialize(int target_width, + int target_height) { + // check which mode we are in now + o3d::DisplayMode current_mode; + GetCurrentDisplayMode(¤t_mode); + + WindowRef temp_window = NULL; + + // Determine if screen mode switching is actually required. + if (target_width != 0 && + target_height != 0 && + target_width != current_mode.width() && + target_height != current_mode.height()) { + short short_target_width = target_width; + short short_target_height = target_height; + BeginFullScreen(&fullscreen_state_, + nil, // Value of nil selects the main screen. + &short_target_width, + &short_target_height, + &temp_window, + NULL, + fullScreenCaptureAllDisplays); + } else { + SetSystemUIMode(kUIModeAllSuppressed, kUIOptionAutoShowMenuBar); + fullscreen_state_ = NULL; + } + + fullscreen_window_ = CreateFullscreenWindow(NULL, obj_); + SetWindowForAGLContext(obj_->GetMacAGLContext(), fullscreen_window_); + aglDisable(obj_->GetMacAGLContext(), AGL_BUFFER_RECT); + // This must be done after all of the above setup in order for the + // overlay window to appear on top. + FullscreenWindowMac::Initialize(target_width, target_height); + return true; +} + +bool CarbonFullscreenWindowMac::Shutdown(const GLint* last_buffer_rect) { + FullscreenWindowMac::Shutdown(last_buffer_rect); + SetWindowForAGLContext(obj_->GetMacAGLContext(), obj_->GetMacWindow()); + aglSetInteger(obj_->GetMacAGLContext(), AGL_BUFFER_RECT, last_buffer_rect); + aglEnable(obj_->GetMacAGLContext(), AGL_BUFFER_RECT); + if (fullscreen_window_) { + HideWindow(fullscreen_window_); + ReleaseWindowGroup(GetWindowGroup(fullscreen_window_)); + DisposeWindow(fullscreen_window_); + fullscreen_window_ = NULL; + } + if (fullscreen_state_) { + EndFullScreen(fullscreen_state_, 0); + fullscreen_state_ = NULL; + } else { + SetSystemUIMode(kUIModeNormal, 0); + } + return true; +} + +CGRect CarbonFullscreenWindowMac::GetWindowBounds() const { + Rect bounds = {0,0,0,0}; + ::GetWindowBounds(fullscreen_window_, kWindowContentRgn, &bounds); + return Rect2CGRect(bounds); +} + +bool CarbonFullscreenWindowMac::IsActive() const { + return fullscreen_window_ == ActiveNonFloatingWindow(); +} + +//---------------------------------------------------------------------- +// FullscreenWindowMac implementation. +// + +FullscreenWindowMac* FullscreenWindowMac::Create( + glue::_o3d::PluginObject* obj, + int target_width, + int target_height) { + FullscreenWindowMac* window = new CarbonFullscreenWindowMac(obj); + if (!window->Initialize(target_width, target_height)) { + delete window; + return NULL; + } + + return window; +} + +FullscreenWindowMac::~FullscreenWindowMac() { +} + +bool FullscreenWindowMac::Initialize(int target_width, int target_height) { +#ifdef O3D_PLUGIN_ENABLE_FULLSCREEN_MSG + overlay_window_.reset(new OverlayWindowMac()); +#endif + return true; +} + +void FullscreenWindowMac::IdleCallback() { +#ifdef O3D_PLUGIN_ENABLE_FULLSCREEN_MSG + if (overlay_window_.get()) { + overlay_window_->IdleCallback(); + } +#endif +} + +bool FullscreenWindowMac::Shutdown(const GLint* last_buffer_rect) { +#ifdef O3D_PLUGIN_ENABLE_FULLSCREEN_MSG + overlay_window_.reset(); +#endif + return true; +} + +} // namespace o3d + diff --git a/o3d/plugin/mac/main_mac.mm b/o3d/plugin/mac/main_mac.mm index 617c906..86ae0de 100644 --- a/o3d/plugin/mac/main_mac.mm +++ b/o3d/plugin/mac/main_mac.mm @@ -56,6 +56,7 @@ #include "plugin/cross/whitelist.h" #include "plugin/mac/plugin_mac.h" #include "plugin/mac/graphics_utils_mac.h" +#include "plugin/mac/fullscreen_window_mac.h" #import "plugin/mac/o3d_layer.h" @@ -69,6 +70,7 @@ using glue::StreamManager; using o3d::Bitmap; using o3d::DisplayWindowMac; using o3d::Event; +using o3d::FullscreenWindowMac; using o3d::Renderer; namespace { @@ -305,9 +307,8 @@ void HandleMouseEvent(PluginObject* obj, int x, y; // now make x and y plugin relative coords if (obj->GetFullscreenMacWindow()) { - Rect wBounds; - GetWindowBounds(obj->GetFullscreenMacWindow(), kWindowGlobalPortRgn, - &wBounds); + Rect wBounds = o3d::CGRect2Rect( + obj->GetFullscreenMacWindow()->GetWindowBounds()); x = screen_x - wBounds.left; y = screen_y - wBounds.top; in_plugin = true; @@ -470,7 +471,7 @@ EventModifiers CocoaToEventRecordModifiers(NSUInteger inMods) { // This API will also be required for a carbon-free 64 bit version for 10.6. bool HandleCocoaEvent(NPP instance, NPCocoaEvent* the_event) { PluginObject* obj = static_cast<PluginObject*>(instance->pdata); - WindowRef fullscreen_window = obj->GetFullscreenMacWindow(); + FullscreenWindowMac* fullscreen_window = obj->GetFullscreenMacWindow(); bool handled = false; if (g_logger) g_logger->UpdateLogging(); @@ -552,7 +553,7 @@ bool HandleCocoaEvent(NPP instance, NPCocoaEvent* the_event) { // because another app has been called to the front. // TODO: We'll have problems with this when dealing with e.g. // Japanese text input IME windows. - if (fullscreen_window && fullscreen_window != ActiveNonFloatingWindow()) { + if (fullscreen_window && !fullscreen_window->IsActive()) { obj->CancelFullscreenDisplay(); } @@ -846,7 +847,7 @@ NPError PlatformNPPGetValue(NPP instance, NPPVariable variable, void *value) { bool HandleMacEvent(EventRecord* the_event, NPP instance) { PluginObject* obj = static_cast<PluginObject*>(instance->pdata); bool handled = false; - WindowRef fullscreen_window = obj->GetFullscreenMacWindow(); + FullscreenWindowMac* fullscreen_window = obj->GetFullscreenMacWindow(); if (g_logger) g_logger->UpdateLogging(); @@ -877,7 +878,7 @@ bool HandleMacEvent(EventRecord* the_event, NPP instance) { // of the fullscreen window and we need to exit fullscreen mode. // This can happen because another browser window has come forward, or // because another app has been called to the front. - if (fullscreen_window && fullscreen_window != ActiveNonFloatingWindow()) { + if (fullscreen_window && !fullscreen_window->IsActive()) { obj->CancelFullscreenDisplay(); } diff --git a/o3d/plugin/mac/overlay_window_mac.h b/o3d/plugin/mac/overlay_window_mac.h new file mode 100644 index 0000000..f848b8b --- /dev/null +++ b/o3d/plugin/mac/overlay_window_mac.h @@ -0,0 +1,62 @@ +/* + * 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. + */ + +#ifndef O3D_PLUGIN_MAC_OVERLAY_WINDOW_MAC_H_ +#define O3D_PLUGIN_MAC_OVERLAY_WINDOW_MAC_H_ + +#include <Carbon/Carbon.h> + +#include "base/basictypes.h" + +// Draws the text indicating how to get out of full-screen mode. + +namespace o3d { + +class OverlayWindowMac { + public: + OverlayWindowMac(); + ~OverlayWindowMac(); + + // Runs the idle callback for this overlay window, which just + // transitions the window on to and off of the screen. + void IdleCallback(); + + private: + WindowRef overlay_window_; + double time_to_hide_overlay_; + + DISALLOW_COPY_AND_ASSIGN(OverlayWindowMac); +}; + +} // namespace o3d + +#endif // O3D_PLUGIN_MAC_OVERLAY_WINDOW_MAC_H_ + diff --git a/o3d/plugin/mac/overlay_window_mac.mm b/o3d/plugin/mac/overlay_window_mac.mm new file mode 100644 index 0000000..ea3af06 --- /dev/null +++ b/o3d/plugin/mac/overlay_window_mac.mm @@ -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 diff --git a/o3d/plugin/mac/plugin_mac.h b/o3d/plugin/mac/plugin_mac.h index 7f3faa0..ebf9c3a 100644 --- a/o3d/plugin/mac/plugin_mac.h +++ b/o3d/plugin/mac/plugin_mac.h @@ -43,6 +43,8 @@ namespace o3d { +class DisplayMode; + // RenderTimer maintains an animation timer (nominally running at 60fps) // // Keeps track of the current NPP instances running in the browser and then @@ -83,6 +85,7 @@ void ReleaseSafariBrowserWindow(void* browserWindow); // Some miscellaneous helper functions... +void GetCurrentDisplayMode(DisplayMode *mode); void CFReleaseIfNotNull(CFTypeRef cf); diff --git a/o3d/plugin/mac/plugin_mac.mm b/o3d/plugin/mac/plugin_mac.mm index 4ab3127..057d43d 100644 --- a/o3d/plugin/mac/plugin_mac.mm +++ b/o3d/plugin/mac/plugin_mac.mm @@ -252,11 +252,9 @@ void RenderTimer::TimerCallback(CFRunLoopTimerRef timer, void* info) { bool in_fullscreen = obj->GetFullscreenMacWindow(); -#ifdef O3D_PLUGIN_ENABLE_FULLSCREEN_MSG if (in_fullscreen) { - obj->FullscreenIdle(); + obj->GetFullscreenMacWindow()->IdleCallback(); } -#endif // We're visible if (a) we are in fullscreen mode, (b) our cliprect // height and width are both a sensible size, ie > 1 pixel, or (c) if @@ -370,458 +368,6 @@ char* CreatePosixFilePathFromHFSFilePath(const char* hfsPath) { -// Convenience function for fetching SInt32 parameters from Carbon EventRefs. -static SInt32 GetIntEventParam(EventRef inEvent, EventParamName inName) { - SInt32 value = 0; - return (GetEventParameter(inEvent, inName, typeSInt32, NULL, sizeof(value), - NULL, &value) == noErr) ? value : 0; -} - - -#pragma mark ____OVERLAY_WINDOW - -#ifdef O3D_PLUGIN_ENABLE_FULLSCREEN_MSG - -// 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); - ShowWindow(window); - - return window; -} - -#endif // O3D_PLUGIN_ENABLE_FULLSCREEN_MSG - - -// Maps the MacOS button numbers to the constants used by our -// event mechanism. Not quite as obvious as you might think, as the Mac -// thinks the numbering should go left, right, middle and our W3C-influenced -// system goes left, middle, right. -// Defaults to left-button if passed a strange value. Pass Cocoa mouse button -// codes as-is (they start at 0), pass Carbon button codes - 1. -o3d::Event::Button MacOSMouseButtonNumberToO3DButton(int inButton) { - - switch(inButton) { - case 0: - return o3d::Event::BUTTON_LEFT; - case 1: - return o3d::Event::BUTTON_RIGHT; - case 2: - return o3d::Event::BUTTON_MIDDLE; - case 3: - return o3d::Event::BUTTON_4; - case 4: - return o3d::Event::BUTTON_5; - } - - return o3d::Event::BUTTON_LEFT; -} - - -#pragma mark ____FULLSCREEN_WINDOW - - -// Handles the CarbonEvents that we get sent for the fullscreen mode window. -// Most of these can be converted to EventRecord events and handled by the -// HandleMacEvent() function in main_mac.mm, but some have no equivalent in -// that space, scroll-wheel events for example, and so must be handled here. -static OSStatus HandleFullscreenWindow(EventHandlerCallRef inHandlerCallRef, - EventRef inEvent, - void *inUserData) { - OSType event_class = GetEventClass(inEvent); - OSType event_kind = GetEventKind(inEvent); - NPP instance = (NPP)inUserData; - PluginObject* obj = (PluginObject*)(instance->pdata); - HIPoint mouse_loc = { 0.0, 0.0 }; - bool is_scroll_event = event_class == kEventClassMouse && - (event_kind == kEventMouseScroll || - event_kind == kEventMouseWheelMoved); - - // If it's any kind of mouse event, get the global mouse loc. - if (event_class == kEventClassMouse) { - GetEventParameter(inEvent, kEventParamMouseLocation, - typeHIPoint, NULL, - sizeof(mouse_loc), NULL, - &mouse_loc); - } - - // Handle the two kinds of scroll message we understand. - if (is_scroll_event) { - SInt32 x_scroll = 0; - SInt32 y_scroll = 0; - EventMouseWheelAxis axis = kEventMouseWheelAxisY; - - switch (event_kind) { - // The newer kind of scroll event, as sent when two-finger - // dragging on a touchpad. - case kEventMouseScroll: - x_scroll = GetIntEventParam(inEvent, - kEventParamMouseWheelSmoothHorizontalDelta); - y_scroll = GetIntEventParam(inEvent, - kEventParamMouseWheelSmoothVerticalDelta); - - // only pass x or y value - pass whichever is larger - if (x_scroll && y_scroll) { - if (abs(x_scroll) > abs(y_scroll)) - y_scroll = 0; - else - x_scroll = 0; - } - break; - // The older kind of scroll event, as sent when using the wheel on - // a third-party mouse. - case kEventMouseWheelMoved: - GetEventParameter(inEvent, kEventParamMouseWheelAxis, - typeMouseWheelAxis, NULL, - sizeof(axis), NULL, - &axis); - - if (axis == kEventMouseWheelAxisY) { - y_scroll = GetIntEventParam(inEvent, - kEventParamMouseWheelDelta); - } else { - x_scroll = GetIntEventParam(inEvent, - kEventParamMouseWheelDelta); - } - break; - } - - // Dispatch the event now that we have all the data. - if (x_scroll || y_scroll) { - o3d::Event event(o3d::Event::TYPE_WHEEL); - event.set_delta(x_scroll, y_scroll); - // Global and local locs are the same, in this case, - // as we have a fullscreen window at 0,0. - event.set_position(mouse_loc.x, mouse_loc.y, - mouse_loc.x, mouse_loc.y, true); - obj->client()->AddEventToQueue(event); - } - return noErr; - } else if (event_class == kEventClassMouse && - (event_kind == kEventMouseDown || event_kind == kEventMouseUp)) { - - o3d::Event::Type type = (event_kind == kEventMouseDown) ? - o3d::Event::TYPE_MOUSEDOWN : - o3d::Event::TYPE_MOUSEUP; - o3d::Event event(type); - event.set_position(mouse_loc.x, mouse_loc.y, - mouse_loc.x, mouse_loc.y, true); - - EventMouseButton button = 0; - GetEventParameter(inEvent, kEventParamMouseButton, - typeMouseButton, NULL, - sizeof(button), NULL, - &button); - // Carbon mouse button numbers start at 1, so subtract 1 here - - // Cocoa mouse buttons, by contrast, start at 0). - event.set_button(MacOSMouseButtonNumberToO3DButton(button - 1)); - - // add the modifiers to the event, if any - UInt32 carbonMods = GetIntEventParam(inEvent, - kEventParamKeyModifiers); - if (carbonMods) { - int modifier_state = 0; - if (carbonMods & controlKey) { - modifier_state |= o3d::Event::MODIFIER_CTRL; - } - if (carbonMods & shiftKey) { - modifier_state |= o3d::Event::MODIFIER_SHIFT; - } - if (carbonMods & optionKey) { - modifier_state |= o3d::Event::MODIFIER_ALT; - } - if (carbonMods & cmdKey) { - modifier_state |= o3d::Event::MODIFIER_META; - } - - event.set_modifier_state(modifier_state); - } - - obj->client()->AddEventToQueue(event); - } else { // not a scroll event or a click - - // All other events are currently handled by being converted to an - // old-style EventRecord as passed by the classic NPAPI interface - // and dispatched through our common routine. - EventRecord eventRecord; - - if (ConvertEventRefToEventRecord(inEvent, &eventRecord)) { - HandleMacEvent(&eventRecord, (NPP)inUserData); - return noErr; - } else { - return eventNotHandledErr; - } - } - return noErr; -} - - -static WindowRef CreateFullscreenWindow(WindowRef window, - PluginObject *obj, - int mode_id) { - Rect bounds = CGRect2Rect(CGDisplayBounds(CGMainDisplayID())); - OSStatus err = noErr; - EventTypeSpec eventTypes[] = { - {kEventClassKeyboard, kEventRawKeyDown}, - {kEventClassKeyboard, kEventRawKeyRepeat}, - {kEventClassKeyboard, kEventRawKeyUp}, - {kEventClassMouse, kEventMouseDown}, - {kEventClassMouse, kEventMouseUp}, - {kEventClassMouse, kEventMouseMoved}, - {kEventClassMouse, kEventMouseDragged}, - {kEventClassMouse, kEventMouseScroll}, - {kEventClassMouse, kEventMouseWheelMoved} - }; - - if (window == NULL) - err = CreateNewWindow(kSimpleWindowClass, - kWindowStandardHandlerAttribute, - &bounds, - &window); - if (err) - return NULL; - - SetWindowLevel(window, CGShieldingWindowLevel() + 1); - - InstallEventHandler(GetWindowEventTarget(window), HandleFullscreenWindow, - sizeof(eventTypes)/sizeof(eventTypes[0]), eventTypes, - obj->npp(), NULL); - ShowWindow(window); - return window; -} - -void CleanupFullscreenWindow(PluginObject *obj) { - WindowRef fs_window = obj->GetFullscreenMacWindow(); -#ifdef O3D_PLUGIN_ENABLE_FULLSCREEN_MSG - WindowRef fs_o_window = obj->GetFullscreenOverlayMacWindow(); -#endif - - obj->SetFullscreenMacWindow(NULL); -#ifdef O3D_PLUGIN_ENABLE_FULLSCREEN_MSG - obj->SetFullscreenOverlayMacWindow(NULL); -#endif - - if (fs_window) { - HideWindow(fs_window); - ReleaseWindowGroup(GetWindowGroup(fs_window)); - DisposeWindow(fs_window); - } - -#ifdef O3D_PLUGIN_ENABLE_FULLSCREEN_MSG - if(fs_o_window) { - HideWindow(fs_o_window); - ReleaseWindowGroup(GetWindowGroup(fs_o_window)); - DisposeWindow(fs_o_window); - } -#endif -} - #pragma mark ____SCREEN_RESOLUTION_MANAGEMENT @@ -889,7 +435,7 @@ static int GetCGDisplayModeID(NSDictionary* mode_dict) { } // Returns DisplayMode data for the current state of the main display. -static void GetCurrentDisplayMode(o3d::DisplayMode *mode) { +void GetCurrentDisplayMode(o3d::DisplayMode *mode) { int width = 0; int height = 0; int refresh_rate = 0; @@ -962,8 +508,6 @@ void PluginObject::GetDisplayModes(std::vector<o3d::DisplayMode> *modes) { #pragma mark ____FULLSCREEN_SWITCHING -#define kTransitionTime 1.0 - namespace glue { namespace _o3d { @@ -984,57 +528,17 @@ bool PluginObject::RequestFullscreenDisplay() { } } - // check which mode we are in now - o3d::DisplayMode current_mode; - GetCurrentDisplayMode(¤t_mode); - - WindowRef fullscreen_window = NULL; - - // Determine if screen mode switching is actually required. - if (target_width != 0 && - target_height != 0 && - target_width != current_mode.width() && - target_height != current_mode.height()) { - short short_target_width = target_width; - short short_target_height = target_height; - BeginFullScreen(&mac_fullscreen_state_, - nil, // Value of nil selects the main screen. - &short_target_width, - &short_target_height, - &fullscreen_window, - NULL, - fullScreenCaptureAllDisplays); - } else { - SetSystemUIMode(kUIModeAllSuppressed, kUIOptionAutoShowMenuBar); - mac_fullscreen_state_ = NULL; - } - - SetFullscreenMacWindow(o3d::CreateFullscreenWindow( - NULL, - this, - fullscreen_region_mode_id_)); - Rect bounds = {0,0,0,0}; - GetWindowBounds(GetFullscreenMacWindow(), kWindowContentRgn, &bounds); + FullscreenWindowMac* fullscreen_window = + FullscreenWindowMac::Create(this, target_width, target_height); + SetFullscreenMacWindow(fullscreen_window); + Rect bounds = o3d::CGRect2Rect(fullscreen_window->GetWindowBounds()); - o3d::SetWindowForAGLContext(mac_agl_context_, GetFullscreenMacWindow()); - aglDisable(mac_agl_context_, AGL_BUFFER_RECT); renderer()->SetClientOriginOffset(0, 0); renderer_->Resize(bounds.right - bounds.left, bounds.bottom - bounds.top); fullscreen_ = true; client()->SendResizeEvent(renderer_->width(), renderer_->height(), true); -#ifdef O3D_PLUGIN_ENABLE_FULLSCREEN_MSG - SetFullscreenOverlayMacWindow(o3d::CreateOverlayWindow()); - ShowWindow(mac_fullscreen_overlay_window_); - o3d::SlideWindowToRect(mac_fullscreen_overlay_window_, - o3d::Rect2CGRect(o3d::GetOverlayWindowRect(true)), - kTransitionTime); - - // Hide the overlay text 4 seconds from now. - time_to_hide_overlay_ = [NSDate timeIntervalSinceReferenceDate] + 4.0; -#endif - return true; } @@ -1043,24 +547,12 @@ void PluginObject::CancelFullscreenDisplay() { if (!GetFullscreenMacWindow()) return; - o3d::SetWindowForAGLContext(mac_agl_context_, mac_window_); - - o3d::CleanupFullscreenWindow(this); - + GetFullscreenMacWindow()->Shutdown(last_buffer_rect_); + SetFullscreenMacWindow(NULL); renderer_->Resize(prev_width_, prev_height_); - aglSetInteger(mac_agl_context_, AGL_BUFFER_RECT, last_buffer_rect_); - aglEnable(mac_agl_context_, AGL_BUFFER_RECT); - - if (mac_fullscreen_state_) { - EndFullScreen(mac_fullscreen_state_, 0); - mac_fullscreen_state_ = NULL; - } else { - SetSystemUIMode(kUIModeNormal, 0); - } fullscreen_ = false; client()->SendResizeEvent(prev_width_, prev_height_, false); - // Somehow the browser window does not automatically activate again // when we close the fullscreen window, so explicitly reactivate it. if (mac_cocoa_window_) { @@ -1071,18 +563,5 @@ void PluginObject::CancelFullscreenDisplay() { } } -#ifdef O3D_PLUGIN_ENABLE_FULLSCREEN_MSG -void PluginObject::FullscreenIdle() { - if ((mac_fullscreen_overlay_window_ != NULL) && - (time_to_hide_overlay_ != 0.0) && - (time_to_hide_overlay_ < [NSDate timeIntervalSinceReferenceDate])) { - time_to_hide_overlay_ = 0.0; - o3d::SlideWindowToRect(mac_fullscreen_overlay_window_, - o3d::Rect2CGRect(o3d::GetOverlayWindowRect(false)), - kTransitionTime); - } -} -#endif - } // namespace glue } // namespace o3d |