Index: plugin/mac/fullscreen_window_mac.mm |
=================================================================== |
--- plugin/mac/fullscreen_window_mac.mm (revision 0) |
+++ plugin/mac/fullscreen_window_mac.mm (revision 0) |
@@ -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 |
+ |
Property changes on: plugin/mac/fullscreen_window_mac.mm |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |