diff options
author | maf@google.com <maf@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-10 01:15:35 +0000 |
---|---|---|
committer | maf@google.com <maf@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-10 01:15:35 +0000 |
commit | 59813099e93f2a9165870f42b7eb5ab39304c8bd (patch) | |
tree | 9e547f7d1d2635104b389bccfe1b7b811d49161a /o3d | |
parent | 461ce4745fc15a6f434699d5a7dcc0591ce952cd (diff) | |
download | chromium_src-59813099e93f2a9165870f42b7eb5ab39304c8bd.zip chromium_src-59813099e93f2a9165870f42b7eb5ab39304c8bd.tar.gz chromium_src-59813099e93f2a9165870f42b7eb5ab39304c8bd.tar.bz2 |
Make O3D fullscreen mode support resolution switching on Mac.
First cut - a bit glitchy when leaving fullscreen currently as we get unwanted browser window resizing when the resolution requested is lower than the current window size.
Review URL: http://codereview.chromium.org/118471
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18013 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
-rw-r--r-- | o3d/plugin/build.scons | 1 | ||||
-rw-r--r-- | o3d/plugin/cross/o3d_glue.cc | 5 | ||||
-rw-r--r-- | o3d/plugin/cross/o3d_glue.h | 1 | ||||
-rw-r--r-- | o3d/plugin/mac/main_mac.mm | 49 | ||||
-rw-r--r-- | o3d/plugin/mac/plugin_mac.mm | 239 |
5 files changed, 250 insertions, 45 deletions
diff --git a/o3d/plugin/build.scons b/o3d/plugin/build.scons index 3ff6a97..40c8719 100644 --- a/o3d/plugin/build.scons +++ b/o3d/plugin/build.scons @@ -140,6 +140,7 @@ if env.Bit('mac'): 'Breakpad', 'Cocoa', 'IOKit', + 'QuickTime', ], CCFLAGS = ['-F$MAC_BREAKPAD_DIR', '-F$CG_DIR'], diff --git a/o3d/plugin/cross/o3d_glue.cc b/o3d/plugin/cross/o3d_glue.cc index 0a7ddd4..f760e1b 100644 --- a/o3d/plugin/cross/o3d_glue.cc +++ b/o3d/plugin/cross/o3d_glue.cc @@ -114,6 +114,7 @@ PluginObject::PluginObject(NPP npp) painted_once_(false), #endif #ifdef OS_MACOSX + mac_fullscreen_state_(NULL), renderer_is_software_(false), scroll_is_in_progress_(false), drawing_model_(NPDrawingModelQuickDraw), @@ -668,6 +669,9 @@ int PluginObject::height() const { return 0; } + +// On Mac there is a different implementation in plugin_mac.mm. +#ifndef OS_MACOSX void PluginObject::GetDisplayModes(std::vector<o3d::DisplayMode> *modes) { if (renderer()) { renderer()->GetDisplayModes(modes); @@ -675,6 +679,7 @@ void PluginObject::GetDisplayModes(std::vector<o3d::DisplayMode> *modes) { modes->clear(); } } +#endif void PluginObject::RedirectToFile(const char *url) { char cmd[] = "window.location = 'file:///%s';"; diff --git a/o3d/plugin/cross/o3d_glue.h b/o3d/plugin/cross/o3d_glue.h index 019488a..ebe2a44 100644 --- a/o3d/plugin/cross/o3d_glue.h +++ b/o3d/plugin/cross/o3d_glue.h @@ -218,6 +218,7 @@ class PluginObject: public NPObject { bool SetRendererIsSoftware(bool state) {renderer_is_software_ = state;} bool renderer_is_software_; + Ptr mac_fullscreen_state_; NPDrawingModel drawing_model_; NPEventModel event_model_; WindowRef mac_window_; // may be NULL in the Chrome case diff --git a/o3d/plugin/mac/main_mac.mm b/o3d/plugin/mac/main_mac.mm index 30f750c..17f1039 100644 --- a/o3d/plugin/mac/main_mac.mm +++ b/o3d/plugin/mac/main_mac.mm @@ -93,6 +93,17 @@ void RenderOnDemandCallbackHandler::Run() { obj_->SetWantsRedraw(true); } +static unsigned char GetMacEventKeyChar(const EventRecord *the_event) { + unsigned char the_char = the_event->message & charCodeMask; + return the_char; +} + +static unsigned char GetMacEventKeyCode(const EventRecord *the_event) { + unsigned char the_key_code = (the_event->message & keyCodeMask) >> 8; + return the_key_code; +} + + // Cocoa key events for things like arrow key presses can have strange unicode // values in the 0xF700-0xF747 range, eg NSUpArrowFunctionKey is 0xF700. // These values are defined in NSEvent.h. @@ -201,12 +212,10 @@ static void DispatchKeyboardEvent(PluginObject* obj, // Javascript. static void DispatchMacKeyboardEvent(PluginObject* obj, EventRecord* the_event) { - unsigned char theKeyCode = (the_event->message & keyCodeMask) >> 8; - DispatchKeyboardEvent(obj, the_event->what, - the_event->message & charCodeMask, - theKeyCode, + GetMacEventKeyChar(the_event), + GetMacEventKeyCode(the_event), the_event->modifiers); } @@ -561,8 +570,7 @@ bool HandleMacEvent(EventRecord* the_event, NPP instance) { break; case keyDown: // Hard-coded trapdoor to get out of fullscreen mode if user hits escape. - unsigned char theChar = the_event->message & charCodeMask; - if (theChar == '\e' && fullscreen_window) { + if ((GetMacEventKeyChar(the_event) == '\e') && fullscreen_window) { obj->CancelFullscreenDisplay(); break; } // otherwise fall through @@ -840,6 +848,9 @@ extern "C" { assert(window != NULL); + if (window->window == NULL) + return NPERR_NO_ERROR; + obj->last_plugin_loc_.h = window->x; obj->last_plugin_loc_.v = window->y; @@ -857,14 +868,17 @@ extern "C" { break; } case NPDrawingModelCoreGraphics: { - NP_CGContext* np_cg = reinterpret_cast<NP_CGContext*>(window->window); - if (obj->event_model_ == NPEventModelCocoa) { - NSWindow * ns_window = reinterpret_cast<NSWindow*>(np_cg->window); - new_window = reinterpret_cast<WindowRef>([ns_window windowRef]); - } else { - new_window = np_cg->window; + // Safari 4 sets window->window to NULL when in Cocoa event mode. + if (window->window != NULL) { + NP_CGContext* np_cg = reinterpret_cast<NP_CGContext*>(window->window); + if (obj->event_model_ == NPEventModelCocoa) { + NSWindow * ns_window = reinterpret_cast<NSWindow*>(np_cg->window); + new_window = reinterpret_cast<WindowRef>([ns_window windowRef]); + } else { + new_window = np_cg->window; + } + obj->mac_2d_context_ = np_cg->context; } - obj->mac_2d_context_ = np_cg->context; break; } case NPDrawingModelQuickDraw: { @@ -1048,8 +1062,13 @@ extern "C" { obj->last_buffer_rect_[3] = clipHeight; obj->mac_surface_hidden_ = false; + // If in fullscreen, just remember the desired change in geometry so + // we restore to the right rectangle. + if (obj->GetFullscreenMacWindow() != NULL) + return NPERR_NO_ERROR; + aglSetInteger(obj->mac_agl_context_, AGL_BUFFER_RECT, - obj->last_buffer_rect_); + obj->last_buffer_rect_); aglEnable(obj->mac_agl_context_, AGL_BUFFER_RECT); } @@ -1082,8 +1101,6 @@ extern "C" { obj->client()->SetRenderOnDemandCallback( new RenderOnDemandCallbackHandler(obj)); - - obj->renderer()->SetClientOriginOffset(gl_x_origin, gl_y_origin); obj->Resize(window->width, window->height); diff --git a/o3d/plugin/mac/plugin_mac.mm b/o3d/plugin/mac/plugin_mac.mm index f245f3e..94327b4 100644 --- a/o3d/plugin/mac/plugin_mac.mm +++ b/o3d/plugin/mac/plugin_mac.mm @@ -34,6 +34,7 @@ #include "plugin_mac.h" #include <Breakpad/Breakpad.h> #include <Cocoa/Cocoa.h> +#include <QuickTime/QuickTime.h> #include "plugin/cross/o3d_glue.h" #include "plugin/cross/main.h" #include "core/mac/display_window_mac.h" @@ -525,6 +526,14 @@ static void DrawToOverlayWindow(WindowRef overlayWindow) { } +static void SetWindowLevel(WindowRef window, int level) { + WindowGroupRef wGroup = NULL; + WindowGroupAttributes attrs = 0; + CreateWindowGroup(attrs, &wGroup); + SetWindowGroupLevel(wGroup, level); + SetWindowGroup(window, wGroup); +} + static WindowRef CreateOverlayWindow(void) { Rect bounds = CGRect2Rect(CGDisplayBounds(CGMainDisplayID())); WindowClass wClass = kOverlayWindowClass; @@ -539,7 +548,6 @@ static WindowRef CreateOverlayWindow(void) { kEventClassWindow, kEventWindowShown }; - err = CreateNewWindow(wClass, overlayAttributes, &bounds, @@ -547,10 +555,12 @@ static WindowRef CreateOverlayWindow(void) { if (err) return NULL; - ShowWindow(window); + SetWindowLevel(window, CGShieldingWindowLevel() + 1); InstallEventHandler(GetWindowEventTarget(window), HandleOverlayWindow, sizeof(eventTypes)/sizeof(eventTypes[0]), eventTypes, NULL, NULL); + ShowWindow(window); + return window; } @@ -717,10 +727,11 @@ static OSStatus HandleFullscreenWindow(EventHandlerCallRef inHandlerCallRef, } } -static WindowRef CreateFullscreenWindow(PluginObject *obj, + +static WindowRef CreateFullscreenWindow(WindowRef window, + PluginObject *obj, int mode_id) { Rect bounds = CGRect2Rect(CGDisplayBounds(CGMainDisplayID())); - WindowRef window = NULL; OSStatus err = noErr; EventTypeSpec eventTypes[] = { kEventClassKeyboard, kEventRawKeyDown, @@ -734,13 +745,16 @@ static WindowRef CreateFullscreenWindow(PluginObject *obj, kEventClassMouse, kEventMouseWheelMoved }; - err = CreateNewWindow(kSimpleWindowClass, - kWindowStandardHandlerAttribute, - &bounds, - &window); + 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); @@ -749,28 +763,191 @@ static WindowRef CreateFullscreenWindow(PluginObject *obj, } void CleanupFullscreenWindow(PluginObject *obj) { - if (obj->GetFullscreenMacWindow()) { - DisposeWindow(obj->GetFullscreenMacWindow()); - obj->SetFullscreenMacWindow(NULL); + WindowRef fs_window = obj->GetFullscreenMacWindow(); + WindowRef fs_o_window = obj->GetFullscreenOverlayMacWindow(); + + obj->SetFullscreenMacWindow(NULL); + obj->SetFullscreenOverlayMacWindow(NULL); + + if (fs_window) { + ReleaseWindowGroup(GetWindowGroup(fs_window)); + DisposeWindow(fs_window); + } + + if(fs_o_window) { + ReleaseWindowGroup(GetWindowGroup(fs_o_window)); + DisposeWindow(fs_o_window); + } +} + +#pragma mark ____SCREEN_RESOLUTION_MANAGEMENT + + +// Constant kO3D_MODE_OFFSET is added to the position in the array returned by +// CGDisplayAvailableModes to make it an ID. This makes IDs distinguishable from +// array positions when debugging, and also means that ID 0 can have a special +// meaning (current mode) rather than meaning the first resolution in the list. +const int kO3D_MODE_OFFSET = 100; + +// Extracts data from the Core Graphics screen mode data passed in. +// Returns false if the mode is an undesirable one, ie if it is not safe for +// the current screen hardware, is stretched, or is interlaced. +// Returns various information about the mode in the var parameters passed. +static bool ExtractDisplayModeData(NSDictionary *mode_dict, + int *width, + int *height, + int *refresh_rate, + int *bits_per_pixel) { + + *width = [[mode_dict objectForKey:(id)kCGDisplayWidth] intValue]; + *height = [[mode_dict objectForKey:(id)kCGDisplayHeight] intValue]; + *refresh_rate = [[mode_dict objectForKey:(id)kCGDisplayRefreshRate] intValue]; + *bits_per_pixel = + [[mode_dict objectForKey:(id)kCGDisplayBitsPerPixel] intValue]; + + if (![mode_dict objectForKey:(id)kCGDisplayModeIsSafeForHardware]) + return false; + + if ([mode_dict objectForKey:(id)kCGDisplayModeIsStretched]) + return false; + + if ([mode_dict objectForKey:(id)kCGDisplayModeIsInterlaced]) + return false; + + return true; +} + +void PluginObject::GetDisplayModes(std::vector<o3d::DisplayMode> *modes) { + NSArray* mac_modes = (NSArray*)CGDisplayAvailableModes(CGMainDisplayID()); + int num_modes = [mac_modes count]; + std::vector<o3d::DisplayMode> modes_found; + + for (int i = 0; i < num_modes; ++i) { + int width = 0; + int height = 0; + int refresh_rate = 0; + int bpp = 0; + + if (ExtractDisplayModeData([mac_modes objectAtIndex:i], + &width, + &height, + &refresh_rate, + &bpp) && bpp == 32) + modes_found.push_back(o3d::DisplayMode(width, height, refresh_rate, + i + kO3D_MODE_OFFSET)); + } + + modes->swap(modes_found); +} + + +// Returns information on a display mode, which is mode n - kO3D_MODE_OFFSET +// in the raw list returned by CGDisplayAvailableModes on the main screen, +// with kO3D_MODE_OFFSET + 0 being the first entry in the array. +static bool GetDisplayMode(int id, o3d::DisplayMode *mode) { + NSArray *mac_modes = (NSArray*) CGDisplayAvailableModes(CGMainDisplayID()); + int num_modes = [mac_modes count]; + int array_offset = id - kO3D_MODE_OFFSET; + + if (array_offset >= 0 && array_offset < num_modes) { + int width = 0; + int height = 0; + int refresh_rate = 0; + int bpp = 0; + + ExtractDisplayModeData([mac_modes objectAtIndex:array_offset], + &width, &height, &refresh_rate, &bpp); + mode->Set(width, height, refresh_rate, id); + return true; } - if (obj->GetFullscreenOverlayMacWindow()) { - DisposeWindow(obj->GetFullscreenOverlayMacWindow()); - obj->SetFullscreenOverlayMacWindow(NULL); + return false; +} + +static int GetCGDisplayModeID(NSDictionary* mode_dict) { + return [[mode_dict valueForKey:@"Mode"] intValue]; +} + +// Returns DisplayMode data for the current state of the main display. +static void GetCurrentDisplayMode(o3d::DisplayMode *mode) { + int width = 0; + int height = 0; + int refresh_rate = 0; + int bpp = 0; + int mode_id = 0; + + NSDictionary* current_mode = + (NSDictionary*)CGDisplayCurrentMode(CGMainDisplayID()); + + // To get the O3D mode id of the current mode, we need to find it in the list + // of all modes, since the id we use is it's index + kO3D_MODE_OFFSET. + + // Get the CG id of current mode so that we will recognize it. + int current_cg_id = GetCGDisplayModeID(current_mode); + + // Get list of all modes. + NSArray *modes = (NSArray*)CGDisplayAvailableModes(CGMainDisplayID()); + int num_modes = [modes count]; + + // Find current mode in that list, and compute the O3D id for it. + for (int x = 0 ; x < num_modes ; x++) { + if (GetCGDisplayModeID([modes objectAtIndex:x]) == current_cg_id) { + mode_id = x + kO3D_MODE_OFFSET; + break; + } } + + ExtractDisplayModeData(current_mode, &width, &height, &refresh_rate, &bpp); + mode->Set(width, height, refresh_rate, mode_id); } +#pragma mark ____FULLSCREEN_SWITCHING + bool PluginObject::RequestFullscreenDisplay() { -#ifndef NDEBUG // TODO: Remove after all security is in. // If already in fullscreen mode, do nothing. if (GetFullscreenMacWindow()) return false; - SetSystemUIMode(kUIModeAllSuppressed, kUIOptionAutoShowMenuBar); - SetFullscreenMacWindow( - CreateFullscreenWindow(this, fullscreen_region_mode_id_)); + int target_width = 0; + int target_height = 0; + if (fullscreen_region_valid_) { + o3d::DisplayMode the_mode; + if (GetDisplayMode(fullscreen_region_mode_id_, &the_mode)) { + target_width = the_mode.width(); + target_height = the_mode.height(); + } + } + + // 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_, + GetMainDevice(), + &short_target_width, + &short_target_height, + &fullscreen_window, + NULL, + fullScreenCaptureAllDisplays); + } else { + SetSystemUIMode(kUIModeAllSuppressed, kUIOptionAutoShowMenuBar); + mac_fullscreen_state_ = NULL; + } + + SetFullscreenMacWindow(CreateFullscreenWindow(NULL, + this, + fullscreen_region_mode_id_)); Rect bounds = {0,0,0,0}; GetWindowBounds(GetFullscreenMacWindow(), kWindowContentRgn, &bounds); @@ -779,33 +956,40 @@ bool PluginObject::RequestFullscreenDisplay() { renderer()->SetClientOriginOffset(0, 0); renderer_->Resize(bounds.right - bounds.left, bounds.bottom - bounds.top); + const double kFadeOutTime = 3.0; SetFullscreenOverlayMacWindow(CreateOverlayWindow()); + DrawToOverlayWindow(GetFullscreenOverlayMacWindow()); TransitionWindowOptions options = {0, kFadeOutTime, NULL, NULL}; TransitionWindowWithOptions(GetFullscreenOverlayMacWindow(), kWindowFadeTransitionEffect, kWindowHideTransitionAction, NULL, true, &options); + return true; -#else - return false; -#endif } void PluginObject::CancelFullscreenDisplay() { -#ifndef NDEBUG // TODO: Remove after user-prompt feature goes in. - // if not in fullscreen mode, do nothing if (!GetFullscreenMacWindow()) return; - //fullscreen_ = false; SetWindowForAGLContext(mac_agl_context_, mac_window_); + + CleanupFullscreenWindow(this); + + renderer_->Resize(prev_width_, prev_height_); aglSetInteger(mac_agl_context_, AGL_BUFFER_RECT, last_buffer_rect_); aglEnable(mac_agl_context_, AGL_BUFFER_RECT); - renderer_->Resize(prev_width_, prev_height_); - CleanupFullscreenWindow(this); + + if (mac_fullscreen_state_) { + EndFullScreen(mac_fullscreen_state_, 0); + mac_fullscreen_state_ = NULL; + } else { + SetSystemUIMode(kUIModeNormal, 0); + } + // Somehow the browser window does not automatically activate again // when we close the fullscreen window, so explicitly reactivate it. @@ -815,8 +999,5 @@ void PluginObject::CancelFullscreenDisplay() { } else { SelectWindow(mac_window_); } - - SetSystemUIMode(kUIModeNormal, 0); -#endif } |