diff options
Diffstat (limited to 'o3d')
-rw-r--r-- | o3d/core/cross/gl/renderer_gl.cc | 22 | ||||
-rw-r--r-- | o3d/core/cross/gl/renderer_gl.h | 51 | ||||
-rw-r--r-- | o3d/core/cross/renderer.cc | 4 | ||||
-rw-r--r-- | o3d/core/cross/renderer.h | 33 | ||||
-rw-r--r-- | o3d/core/win/d3d9/renderer_d3d9.cc | 80 | ||||
-rw-r--r-- | o3d/core/win/d3d9/renderer_d3d9.h | 16 | ||||
-rw-r--r-- | o3d/plugin/cross/o3d_glue.cc | 6 | ||||
-rw-r--r-- | o3d/plugin/cross/o3d_glue.h | 32 | ||||
-rw-r--r-- | o3d/plugin/npapi_host_control/win/host_control.cc | 19 | ||||
-rw-r--r-- | o3d/plugin/npapi_host_control/win/host_control.h | 3 | ||||
-rw-r--r-- | o3d/plugin/npapi_host_control/win/np_plugin_proxy.cc | 13 | ||||
-rw-r--r-- | o3d/plugin/npapi_host_control/win/np_plugin_proxy.h | 5 | ||||
-rw-r--r-- | o3d/plugin/win/main_win.cc | 382 |
13 files changed, 353 insertions, 313 deletions
diff --git a/o3d/core/cross/gl/renderer_gl.cc b/o3d/core/cross/gl/renderer_gl.cc index b52e324..9f0955c 100644 --- a/o3d/core/cross/gl/renderer_gl.cc +++ b/o3d/core/cross/gl/renderer_gl.cc @@ -651,8 +651,6 @@ RendererGL::RendererGL(ServiceLocator* service_locator) new BlendEquationHandler(&blend_equation_[ALPHA])); } -RendererGL *RendererGL::current_renderer_ = NULL; - RendererGL::~RendererGL() { Destroy(); } @@ -1101,7 +1099,6 @@ void RendererGL::Destroy() { DestroyCommonGL(); if (display_) { ::glXMakeCurrent(display_, 0, 0); - current_renderer_ = NULL; if (context_) { ::glXDestroyContext(display_, context_); context_ = 0; @@ -1117,17 +1114,14 @@ bool RendererGL::MakeCurrent() { #ifdef OS_WIN if (!device_context_ || !gl_context_) return false; bool result = ::wglMakeCurrent(device_context_, gl_context_) != 0; - if (result) current_renderer_ = this; return result; #endif #ifdef OS_MACOSX if (mac_cgl_context_ != NULL) { ::CGLSetCurrentContext(mac_cgl_context_); - current_renderer_ = this; return true; } else if (mac_agl_context_ != NULL) { ::aglSetCurrentContext(mac_agl_context_); - current_renderer_ = this; return true; } else { return false; @@ -1136,7 +1130,6 @@ bool RendererGL::MakeCurrent() { #ifdef OS_LINUX if (context_ != NULL) { bool result = ::glXMakeCurrent(display_, window_, context_) == True; - if (result) current_renderer_ = this; return result; } else { return false; @@ -1219,12 +1212,15 @@ void RendererGL::Resize(int width, int height) { CHECK_GL_ERROR(); } -bool RendererGL::SetFullscreen(bool fullscreen, - const DisplayWindow& display, - int mode_id) { - if (fullscreen != fullscreen_) { - fullscreen_ = fullscreen; - } +bool RendererGL::GoFullscreen(const DisplayWindow& display, + int mode_id) { + fullscreen_ = true; + return true; +} + +bool RendererGL::CancelFullscreen(const DisplayWindow& display, + int width, int height) { + fullscreen_ = false; return true; } diff --git a/o3d/core/cross/gl/renderer_gl.h b/o3d/core/cross/gl/renderer_gl.h index 92aaca8..722e29e2 100644 --- a/o3d/core/cross/gl/renderer_gl.h +++ b/o3d/core/cross/gl/renderer_gl.h @@ -65,16 +65,13 @@ class RendererGL : public Renderer { // Released all hardware resources. virtual void Destroy(); - // Turns fullscreen display on or off. - // Parameters: - // fullscreen: true for fullscreen, false for in-browser display - // display: a platform-specific display identifier - // mode_id: a mode returned by GetDisplayModes, for fullscreen use. - // (Ignored in non-fullscreen mode.) - // Returns true on success, false on failure. - virtual bool SetFullscreen(bool fullscreen, - const DisplayWindow& display, - int mode_id); + // Overridden from Renderer. + virtual bool GoFullscreen(const DisplayWindow& display, + int mode_id); + + // Overridden from Renderer. + virtual bool CancelFullscreen(const DisplayWindow& display, + int width, int height); // Tells whether we're currently displayed fullscreen or not. virtual bool fullscreen() const { @@ -118,23 +115,35 @@ class RendererGL : public Renderer { // Makes this renderer active on the current thread if it is not active // already. void MakeCurrentLazy() { - if (!IsCurrent()) MakeCurrent(); + if (!IsCurrent()) + MakeCurrent(); } // Returns whether or not this renderer is active on the current thread. - // In the Mac case, also requires the correct GL context to be active. // Don't worry, the "get" calls are el cheapo. bool IsCurrent() { -#ifdef OS_MACOSX +#if defined(OS_MACOSX) if ((mac_agl_context_ != NULL) && - (mac_agl_context_ != aglGetCurrentContext())) { - return false; + (mac_agl_context_ == aglGetCurrentContext())) { + return true; } else if ((mac_cgl_context_ != NULL) && - (mac_cgl_context_ != CGLGetCurrentContext())) { - return false; + (mac_cgl_context_ == CGLGetCurrentContext())) { + return true; } +#elif defined(OS_WIN) + if ((gl_context_ != NULL) && + (gl_context_ == wglGetCurrentContext())) { + return true; + } +#elif defined(OS_LINUX) + if ((context_ != NULL) && + (context_ == glXGetCurrentContext())) { + return true; + } +#else + Error: must port RendererGL::IsCurrent() to your platform. #endif - return this == current_renderer_; + return false; } // Makes this renderer active on the current thread. @@ -221,12 +230,6 @@ class RendererGL : public Renderer { ServiceDependency<SemanticManager> semantic_manager_; - // Current renderer, tracking which renderer has last called wglMakeCurrent - // (or equivalent on other platforms). - // NOTE: this should really be thread-local, but since we don't handle - // multiple threads currently, this is enough. - static RendererGL *current_renderer_; - // Indicates we're rendering fullscreen rather than in the plugin region. bool fullscreen_; diff --git a/o3d/core/cross/renderer.cc b/o3d/core/cross/renderer.cc index ff640b7..1310376 100644 --- a/o3d/core/cross/renderer.cc +++ b/o3d/core/cross/renderer.cc @@ -127,7 +127,8 @@ Renderer::Renderer(ServiceLocator* service_locator) dest_x_offset_(0), dest_y_offset_(0), supports_npot_(false), - back_buffer_cleared_(false) { + back_buffer_cleared_(false), + presented_once_(false) { } Renderer::~Renderer() { @@ -321,6 +322,7 @@ void Renderer::Present() { DCHECK(!rendering_); DCHECK(!drawing_); PlatformSpecificPresent(); + presented_once_ = true; } void Renderer::Clear(const Float4 &color, diff --git a/o3d/core/cross/renderer.h b/o3d/core/cross/renderer.h index df5bbd2..c372bca 100644 --- a/o3d/core/cross/renderer.h +++ b/o3d/core/cross/renderer.h @@ -213,16 +213,27 @@ class Renderer { // Handles the plugin resize event. virtual void Resize(int width, int height) = 0; - // Turns fullscreen display on or off. + // Turns fullscreen display on. // Parameters: - // fullscreen: true for fullscreen, false for in-plugin display // display: a platform-specific display identifier - // mode_id: a mode returned by GetDisplayModes, for fullscreen use. Ignored - // in non-fullscreen mode. + // mode_id: a mode returned by GetDisplayModes // Returns true on success, false on failure. - // TODO: Make this pure virtual once it's implemented everywhere. - virtual bool SetFullscreen(bool fullscreen, const DisplayWindow& display, - int mode_id) { + // TODO(o3d): Make this pure virtual once it's implemented everywhere. + virtual bool GoFullscreen(const DisplayWindow& display, + int mode_id) { + return false; + } + + // Cancels fullscreen display. Restores rendering to windowed mode + // with the given width and height. + // Parameters: + // display: a platform-specific display identifier + // width: the width to which to restore windowed rendering + // height: the height to which to restore windowed rendering + // Returns true on success, false on failure. + // TODO(o3d): Make this pure virtual once it's implemented everywhere. + virtual bool CancelFullscreen(const DisplayWindow& display, + int width, int height) { return false; } @@ -532,6 +543,11 @@ class Renderer { write_mask_ = mask & 0xF; } + // Indicates whether this Renderer has yet presented to the screen. + bool presented_once() { + return presented_once_; + } + protected: typedef vector_map<String, StateHandler*> StateHandlerMap; typedef std::vector<ParamVector> ParamVectorArray; @@ -748,6 +764,9 @@ class Renderer { // Whether the backbuffer has been cleared this frame. bool back_buffer_cleared_; + // Whether we have ever completed a call to Present(). + bool presented_once_; + DISALLOW_COPY_AND_ASSIGN(Renderer); }; diff --git a/o3d/core/win/d3d9/renderer_d3d9.cc b/o3d/core/win/d3d9/renderer_d3d9.cc index 3c56994..f667ee4 100644 --- a/o3d/core/win/d3d9/renderer_d3d9.cc +++ b/o3d/core/win/d3d9/renderer_d3d9.cc @@ -422,6 +422,7 @@ Renderer::InitStatus InitializeD3D9Context( // Note: SwapEffect=DISCARD is req. for multisample to function ZeroMemory(d3d_present_parameters, sizeof(*d3d_present_parameters)); d3d_present_parameters->Windowed = !fullscreen; + d3d_present_parameters->hDeviceWindow = window; d3d_present_parameters->SwapEffect = D3DSWAPEFFECT_DISCARD; d3d_present_parameters->BackBufferFormat = D3DFMT_A8R8G8B8; d3d_present_parameters->EnableAutoDepthStencil = FALSE; @@ -1331,52 +1332,75 @@ bool RendererD3D9::GetDisplayMode(int id, DisplayMode *mode) { return success; } -bool RendererD3D9::SetFullscreen(bool fullscreen, - const DisplayWindow& display, - int mode_id) { - if (fullscreen != fullscreen_) { +bool RendererD3D9::GoFullscreen(const DisplayWindow& display, + int mode_id) { + if (!fullscreen_) { if (d3d_device_) { // Have we been initialized yet? const DisplayWindowWindows& platform_display = static_cast<const DisplayWindowWindows&>(display); HWND window = platform_display.hwnd(); int refresh_rate = 0; bool windowed = true; - if (fullscreen) { - // If fullscreen is requested but the mode is set to - // DISPLAY_MODE_DEFAULT then create a non-full-screen window at the - // current display resolution. If any other mode is chosen then the - // windows will change mode and create a true full-screen window. - if (mode_id != DISPLAY_MODE_DEFAULT) { - // Look up the refresh rate. - DisplayMode mode; - if (!GetDisplayMode(mode_id, &mode)) { - LOG(ERROR) << "Failed to GetDisplayMode"; - return false; - } - refresh_rate = mode.refresh_rate(); - windowed = false; - } - showing_fullscreen_message_ = true; - fullscreen_message_timer_.GetElapsedTimeAndReset(); // Reset the timer. - } else { - showing_fullscreen_message_ = false; + + // Look up the refresh rate, width and height. + DisplayMode mode; + if (!GetDisplayMode(mode_id, &mode)) { + LOG(ERROR) << "Failed to GetDisplayMode"; + return false; + } + + int width = mode.width(); + int height = mode.height(); + + // If fullscreen is requested but the mode is set to + // DISPLAY_MODE_DEFAULT then create a non-full-screen window at the + // current display resolution. If any other mode is chosen then the + // windows will change mode and create a true full-screen window. + if (mode_id != DISPLAY_MODE_DEFAULT) { + refresh_rate = mode.refresh_rate(); + windowed = false; } + + showing_fullscreen_message_ = true; + fullscreen_message_timer_.GetElapsedTimeAndReset(); // Reset the timer. + d3d_present_parameters_.FullScreen_RefreshRateInHz = refresh_rate; d3d_present_parameters_.hDeviceWindow = window; d3d_present_parameters_.Windowed = windowed; // Check if the window size is zero. Some drivers will fail because of // that so we'll force a small size in that case. - RECT windowRect; - ::GetWindowRect(window, &windowRect); - int width = windowRect.right - windowRect.left; - int height = windowRect.bottom - windowRect.top; + if (width == 0 || height == 0) { + width = 16; + height = 16; + } + fullscreen_ = true; + Resize(width, height); + } + } + return true; +} +bool RendererD3D9::CancelFullscreen(const DisplayWindow& display, + int width, + int height) { + if (fullscreen_) { + if (d3d_device_) { // Have we been initialized yet? + const DisplayWindowWindows& platform_display = + static_cast<const DisplayWindowWindows&>(display); + HWND window = platform_display.hwnd(); + showing_fullscreen_message_ = false; + d3d_present_parameters_.FullScreen_RefreshRateInHz = 0; + d3d_present_parameters_.hDeviceWindow = window; + d3d_present_parameters_.Windowed = true; + + // Check if the window size is zero. Some drivers will fail because of + // that so we'll force a small size in that case. if (width == 0 || height == 0) { width = 16; height = 16; } - fullscreen_ = fullscreen; + fullscreen_ = false; Resize(width, height); } } diff --git a/o3d/core/win/d3d9/renderer_d3d9.h b/o3d/core/win/d3d9/renderer_d3d9.h index e4a567c..4a7221b 100644 --- a/o3d/core/win/d3d9/renderer_d3d9.h +++ b/o3d/core/win/d3d9/renderer_d3d9.h @@ -77,15 +77,13 @@ class RendererD3D9 : public Renderer { // Attempts to reset the back buffer to its new dimensions. virtual void Resize(int width, int height); - // Turns fullscreen display on or off. - // Parameters: - // fullscreen: true for fullscreen, false for in-plugin display - // display: a platform-specific display identifier - // mode_id: a mode returned by GetDisplayModes, for fullscreen use. Ignored - // in non-fullscreen mode. - // Returns true on success, false on failure. - virtual bool SetFullscreen(bool fullscreen, const DisplayWindow& display, - int mode_id); + // Overridden from Renderer. + virtual bool GoFullscreen(const DisplayWindow& display, + int mode_id); + + // Overridden from Renderer. + virtual bool CancelFullscreen(const DisplayWindow& display, + int width, int height); // Tells whether we're currently displayed fullscreen or not. virtual bool fullscreen() const { diff --git a/o3d/plugin/cross/o3d_glue.cc b/o3d/plugin/cross/o3d_glue.cc index 9053255..5911285 100644 --- a/o3d/plugin/cross/o3d_glue.cc +++ b/o3d/plugin/cross/o3d_glue.cc @@ -110,10 +110,8 @@ PluginObject::PluginObject(NPP npp) pending_ticks_(0), #ifdef OS_WIN hWnd_(NULL), - fullscreen_hWnd_(NULL), - parent_hWnd_(NULL), plugin_hWnd_(NULL), - default_plugin_window_proc_(NULL), + content_hWnd_(NULL), got_dblclick_(false), painted_once_(false), #endif @@ -743,11 +741,11 @@ void PluginObject::StorePluginProperty(HWND hWnd, PluginObject *obj) { if (obj->GetHWnd()) { // Clear out the record from the old window first. ClearPluginProperty(obj->GetHWnd()); } + obj->SetHWnd(hWnd); StorePluginPropertyUnsafe(hWnd, obj); } void PluginObject::StorePluginPropertyUnsafe(HWND hWnd, PluginObject *obj) { - obj->SetHWnd(hWnd); if (hWnd) { SetProp(hWnd, kWindowPropertyName, static_cast<HANDLE>(obj)); ::DragAcceptFiles(hWnd, true); diff --git a/o3d/plugin/cross/o3d_glue.h b/o3d/plugin/cross/o3d_glue.h index 6143db2..12fb572 100644 --- a/o3d/plugin/cross/o3d_glue.h +++ b/o3d/plugin/cross/o3d_glue.h @@ -158,36 +158,24 @@ class PluginObject: public NPObject { public: #ifdef OS_WIN - void SetDefaultPluginWindowProc(WNDPROC proc) { - default_plugin_window_proc_ = proc; - } - WNDPROC GetDefaultPluginWindowProc() { - return default_plugin_window_proc_; - } void SetHWnd(HWND hWnd) { hWnd_ = hWnd; } HWND GetHWnd() { return hWnd_; } - void SetFullscreenHWnd(HWND hWnd) { - fullscreen_hWnd_ = hWnd; - } - HWND GetFullscreenHWnd() { - return fullscreen_hWnd_; - } - void SetParentHWnd(HWND hWnd) { - parent_hWnd_ = hWnd; - } - HWND GetParentHWnd() { - return parent_hWnd_; - } void SetPluginHWnd(HWND hWnd) { plugin_hWnd_ = hWnd; } HWND GetPluginHWnd() { return plugin_hWnd_; } + void SetContentHWnd(HWND hWnd) { + content_hWnd_ = hWnd; + } + HWND GetContentHWnd() { + return content_hWnd_; + } bool RecordPaint() { bool painted = painted_once_; painted_once_ = true; @@ -431,13 +419,11 @@ class PluginObject: public NPObject { int fullscreen_region_height_; int fullscreen_region_mode_id_; #ifdef OS_WIN - HWND hWnd_; // The window we are currenlty drawing to (use this) - HWND fullscreen_hWnd_; // The fullscreen window if we are fullscreen - HWND parent_hWnd_; - HWND plugin_hWnd_; // The window we were given inside the browser. + HWND hWnd_; // The window we are currently drawing to (use this). + HWND plugin_hWnd_; // The window we were given inside the browser. + HWND content_hWnd_; // The window containing the D3D or OpenGL content. HCURSOR cursors_[o3d::Cursor::NUM_CURSORS]; // loaded windows cursors. HCURSOR hCursor_; - WNDPROC default_plugin_window_proc_; bool painted_once_; #endif // OS_WIN }; diff --git a/o3d/plugin/npapi_host_control/win/host_control.cc b/o3d/plugin/npapi_host_control/win/host_control.cc index 957f465..47a4040 100644 --- a/o3d/plugin/npapi_host_control/win/host_control.cc +++ b/o3d/plugin/npapi_host_control/win/host_control.cc @@ -553,6 +553,25 @@ STDMETHODIMP CHostControl::Load(IPropertyBag* property_bag, return IPersistPropertyBagImpl<CHostControl>::Load(property_bag, error_log); } +STDMETHODIMP CHostControl::SetObjectRects(LPCRECT lprcPosRect, + LPCRECT lprcClipRect) { + if (plugin_proxy_.get()) { + NPWindow window = {0}; + window.window = m_hWnd; + window.type = NPWindowTypeWindow; + window.x = lprcPosRect->left; + window.y = lprcPosRect->top; + window.width = lprcPosRect->right - lprcPosRect->left; + window.height = lprcPosRect->bottom - lprcPosRect->top; + if (!plugin_proxy_->SetWindow(window)) { + return E_FAIL; + } + } + + return IOleInPlaceObjectWindowlessImpl::SetObjectRects(lprcPosRect, + lprcClipRect); +} + HRESULT CHostControl::GetStringProperty(NPPVariable np_property_variable, BSTR* string) { HRESULT hr; diff --git a/o3d/plugin/npapi_host_control/win/host_control.h b/o3d/plugin/npapi_host_control/win/host_control.h index ae37487..9a4fc68 100644 --- a/o3d/plugin/npapi_host_control/win/host_control.h +++ b/o3d/plugin/npapi_host_control/win/host_control.h @@ -170,6 +170,9 @@ END_PROP_MAP() // Method overridden from IPersistPropertyBagImpl. STDMETHOD(Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog)); + STDMETHOD(SetObjectRects(LPCRECT lprcPosRect, + LPCRECT lprcClipRect)); + // Returns the properties associated with the NPPVpluginNameString, and // NPPVpluginDescriptionString identifiers of the loaded plug-in. These // properties can be used for plug-in introspection and version-dependent diff --git a/o3d/plugin/npapi_host_control/win/np_plugin_proxy.cc b/o3d/plugin/npapi_host_control/win/np_plugin_proxy.cc index 04cd24a..7de9d67 100644 --- a/o3d/plugin/npapi_host_control/win/np_plugin_proxy.cc +++ b/o3d/plugin/npapi_host_control/win/np_plugin_proxy.cc @@ -286,6 +286,19 @@ bool NPPluginProxy::Init(NPBrowserProxy* browser_proxy, return true; } +bool NPPluginProxy::SetWindow(const NPWindow& window) { + if (plugin_funcs_.setwindow != NULL && + NPERR_NO_ERROR != plugin_funcs_.setwindow( + GetNPP(), + const_cast<NPWindow*>(&window))) { + plugin_funcs_.destroy(GetNPP(), NULL); + NP_Shutdown_(); + ATLASSERT(false && "Unknown failure re-setting plugin window."); + return false; + } + return true; +} + void NPPluginProxy::TearDown() { // Block until all stream operations requested by this plug-in have // completed. diff --git a/o3d/plugin/npapi_host_control/win/np_plugin_proxy.h b/o3d/plugin/npapi_host_control/win/np_plugin_proxy.h index 6f122d1..e3f1c9e 100644 --- a/o3d/plugin/npapi_host_control/win/np_plugin_proxy.h +++ b/o3d/plugin/npapi_host_control/win/np_plugin_proxy.h @@ -69,6 +69,11 @@ class NPPluginProxy { const std::vector<CStringA>& argument_names, const std::vector<CStringA>& argument_values); + // Sets the target window of the npapi plugin. This may be called + // repeatedly during its lifetime, in particular to set the plugin's + // size. + bool SetWindow(const NPWindow& window); + // Frees all resources allocated in Init, and blocks on all pending stream // operations. void TearDown(); diff --git a/o3d/plugin/win/main_win.cc b/o3d/plugin/win/main_win.cc index f2feeae..85bc28c 100644 --- a/o3d/plugin/win/main_win.cc +++ b/o3d/plugin/win/main_win.cc @@ -87,7 +87,7 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE instance, #endif // O3D_INTERNAL_PLUGIN namespace { -const wchar_t* const kFullScreenWindowClassName = L"O3DFullScreenWindowClass"; +const wchar_t* const kO3DWindowClassName = L"O3DWindowClass"; // We would normally make this a stack variable in main(), but in a // plugin, that's not possible, so we make it a global. When the DLL is loaded @@ -352,79 +352,6 @@ void HandleMouseEvent(PluginObject *obj, } } -// This returns 0 on success, 1 on failure, to match WindowProc. -LRESULT ForwardEvent(PluginObject *obj, - HWND hWnd, - UINT Msg, - WPARAM wParam, - LPARAM lParam, - bool translateCoords) { - DCHECK(obj); - DCHECK(obj->GetPluginHWnd()); - HWND dest_hwnd = obj->GetParentHWnd(); - DCHECK(hWnd); - DCHECK(dest_hwnd); - bool fullscreen = hWnd == obj->GetFullscreenHWnd(); - if (fullscreen) { - dest_hwnd = obj->GetPluginHWnd(); - } else if (obj->IsChrome()) { - // When trying to find the parent window of the Chrome plugin, new Chrome is - // different than old Chrome; it's got an extra wrapper window around the - // plugin that didn't used to be there. The wrapper won't listen to events, - // so if we see it, we have to go one window up the tree from there in order - // to find someone who'll listen to us. The new behavior is seen in nightly - // builds of Chromium as of 2.0.163.0 (9877) [but went in some time before - // that]; the old behavior is still exhibited by Chrome as of 1.0.154.48. - wchar_t chrome_class_name[] = L"WrapperNativeWindowClass"; - wchar_t buffer[sizeof(chrome_class_name) / sizeof(chrome_class_name[0])]; - if (!GetClassName(dest_hwnd, buffer, sizeof(buffer) / sizeof(buffer[0]))) { - return 1; - } - if (!wcscmp(chrome_class_name, buffer)) { - dest_hwnd = ::GetParent(dest_hwnd); - } - } - if (translateCoords) { - int x = GET_X_LPARAM(lParam); - int y = GET_Y_LPARAM(lParam); - - RECT rect0, rect1; - if (!::GetWindowRect(hWnd, &rect0)) { - DCHECK(false); - return 1; - } - if (!::GetWindowRect(dest_hwnd, &rect1)) { - DCHECK(false); - return 1; - } - int width = rect0.right - rect0.left; - int width_1 = rect1.right - rect1.left; - - int x_1; - int y_1; - - if (!fullscreen) { // Translate from plugin to browser offset coords. - x_1 = x - rect1.left + rect0.left; - } else { // Translate from screen to plugin offset coords. - // The plugin and the fullscreen window each fill their respective entire - // window, so there aren't any offsets to add or subtract. - x_1 = x * width_1 / width; - } - int height = rect0.bottom - rect0.top; - int height_1 = rect1.bottom - rect1.top; - if (!fullscreen) { // Translate from plugin to browser offset coords. - y_1 = y - rect1.top + rect0.top; - } else { // Translate from screen to plugin offset coords. - // The plugin and the fullscreen window each fill their respective entire - // window, so there aren't any offsets to add or subtract. - y_1 = y * height_1 / height; - } - - lParam = MAKELPARAM(x_1, y_1); - } - return !::PostMessage(dest_hwnd, Msg, wParam, lParam); -} - LRESULT HandleDragAndDrop(PluginObject *obj, WPARAM wParam) { HDROP hDrop = reinterpret_cast<HDROP>(wParam); UINT num_files = ::DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); @@ -507,11 +434,10 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { if (!obj->RecordPaint()) { ::SetPixelV(hdc, 0, 0, RGB(0, 0, 0)); } - obj->renderer()->set_need_to_render(true); } else { - // If there Client has no Renderer associated with it, paint the draw - // area gray. + // If the Client has no Renderer associated with it, paint the + // draw area gray. ::SelectObject(paint_struct.hdc, GetStockObject(DKGRAY_BRUSH)); ::Rectangle(paint_struct.hdc, paint_struct.rcPaint.left, @@ -521,29 +447,17 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { } } ::EndPaint(hWnd, &paint_struct); - break; + return 0; } case WM_SETCURSOR: { obj->set_cursor(obj->cursor()); return 1; } case WM_ERASEBKGND: { - return 1; // tell windows we don't need the background cleared + // Tell windows we don't need the background cleared. + return 1; } - case WM_SIZE: { - // Resize event called - if (reentrance_count.get() > 1) { - break; // Ignore this message; we're reentrant. - } - - // get new dimensions of window - int window_width = LOWORD(lParam); - int window_height = HIWORD(lParam); - // Tell the plugin that it has been resized - obj->Resize(window_width, window_height); - break; - } case WM_TIMER: { if (reentrance_count.get() > 1) { break; // Ignore this message; we're reentrant. @@ -619,20 +533,28 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { case WM_SYSKEYUP: return HandleKeyboardEvent(obj, hWnd, Msg, wParam, lParam); -#if(_WIN32_WINNT >= 0x0500) - case WM_APPCOMMAND: -#endif /* _WIN32_WINNT >= 0x0500 */ - return ForwardEvent(obj, hWnd, Msg, wParam, lParam, false); - case WM_DROPFILES: return HandleDragAndDrop(obj, wParam); + case WM_ACTIVATE: + // We don't receive WM_KILLFOCUS when Alt-Tabbing away from a + // full-screen window. We do however get WM_ACTIVATE. + if (LOWORD(wParam) == WA_INACTIVE) { + if (obj->fullscreen()) { + obj->CancelFullscreenDisplay(); + } + } + return 0; + case WM_KILLFOCUS: // If we lose focus [which also happens on alt+f4 killing the fullscreen // window] fall back to plugin mode to avoid lost-device awkwardness. // TODO: We'll have problems with this when dealing with e.g. // Japanese text input IME windows. - if (hWnd == obj->GetFullscreenHWnd()) { + if (obj->fullscreen()) { + // TODO(kbr): consider doing this somehow more asynchronously; + // not supposed to cause window activation in the WM_KILLFOCUS + // handler obj->CancelFullscreenDisplay(); return 0; } @@ -645,34 +567,63 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { // manually, its destructor will know not to. reentrance_count.decrement(); - if (hWnd == obj->GetFullscreenHWnd()) { - return ::CallWindowProc(::DefWindowProc, - hWnd, - Msg, - wParam, - lParam); - } else { - return ::CallWindowProc(obj->GetDefaultPluginWindowProc(), - hWnd, - Msg, - wParam, - lParam); - } + return ::CallWindowProc(::DefWindowProc, + hWnd, + Msg, + wParam, + lParam); } return 0; } -bool RegisterFullScreenWindowClass() { - WNDCLASSEX window_class = { sizeof(WNDCLASSEX) }; +static const wchar_t* kOrigWndProcName = L"o3dOrigWndProc"; + +LRESULT CALLBACK PluginWindowInterposer(HWND hWnd, + UINT Msg, + WPARAM wParam, + LPARAM lParam) { + switch (Msg) { + case WM_PAINT: { + // For nicer startup appearance, allow the browser to paint the + // plugin window until we start to draw 3D content. Forbid the + // browser from painting once we have started to draw to prevent + // a flash in Firefox upon our receiving focus the first time. + PluginObject *obj = PluginObject::GetPluginProperty(hWnd); + if (obj != NULL && obj->renderer() != NULL) { + if (obj->renderer()->presented_once()) { + // Tell Windows we painted the window region. + ::ValidateRect(hWnd, NULL); + return 0; + } + } + // Break out to call the original window procedure to paint the + // window. + break; + } + + default: + break; + } + + WNDPROC proc = static_cast<WNDPROC>(GetProp(hWnd, kOrigWndProcName)); + DCHECK(proc != NULL); + return CallWindowProc(proc, hWnd, Msg, wParam, lParam); +} + +bool RegisterO3DWindowClass() { + WNDCLASSEX window_class; + ZeroMemory(&window_class, sizeof(window_class)); + window_class.cbSize = sizeof(window_class); window_class.hInstance = g_module_instance; window_class.lpfnWndProc = WindowProc; - window_class.lpszClassName = kFullScreenWindowClassName; - window_class.style = CS_DBLCLKS; + window_class.lpszClassName = kO3DWindowClassName; + // We use CS_OWNDC in case we are rendering OpenGL into this window. + window_class.style = CS_DBLCLKS | CS_OWNDC; return RegisterClassEx(&window_class) != 0; } -void UnregisterFullScreenWindowClass() { - UnregisterClass(kFullScreenWindowClassName, g_module_instance); +void UnregisterO3DWindowClass() { + UnregisterClass(kO3DWindowClassName, g_module_instance); } NPError InitializePlugin() { @@ -696,58 +647,41 @@ NPError InitializePlugin() { DLOG(INFO) << "NP_Initialize"; - if (!RegisterFullScreenWindowClass()) + if (!RegisterO3DWindowClass()) return NPERR_MODULE_LOAD_FAILED_ERROR; return NPERR_NO_ERROR; } -void CleanupFullscreenWindow(PluginObject *obj) { - DCHECK(obj->GetFullscreenHWnd()); - obj->StorePluginProperty(obj->GetPluginHWnd(), obj); - ::DestroyWindow(obj->GetFullscreenHWnd()); - obj->SetFullscreenHWnd(NULL); -} - void CleanupAllWindows(PluginObject *obj) { - DCHECK(obj->GetHWnd()); + DCHECK(obj->GetContentHWnd()); DCHECK(obj->GetPluginHWnd()); - ::KillTimer(obj->GetHWnd(), 0); - if (obj->GetFullscreenHWnd()) { - CleanupFullscreenWindow(obj); - } - PluginObject::ClearPluginProperty(obj->GetHWnd()); - ::SetWindowLongPtr(obj->GetPluginHWnd(), - GWL_WNDPROC, - reinterpret_cast<LONG_PTR>( - obj->GetDefaultPluginWindowProc())); + ::KillTimer(obj->GetContentHWnd(), 0); + PluginObject::ClearPluginProperty(obj->GetContentHWnd()); + PluginObject::ClearPluginProperty(obj->GetPluginHWnd()); + ::DestroyWindow(obj->GetContentHWnd()); + obj->SetContentHWnd(NULL); obj->SetPluginHWnd(NULL); obj->SetHWnd(NULL); } -HWND CreateFullscreenWindow(PluginObject *obj, - int mode_id) { - o3d::DisplayMode mode; - if (!obj->renderer()->GetDisplayMode(mode_id, &mode)) { - return NULL; - } - CHECK(mode.width() > 0 && mode.height() > 0); - - HWND hWnd = CreateWindowEx(NULL, - kFullScreenWindowClassName, - L"O3D Test Fullscreen Window", - WS_POPUP, - 0, 0, - mode.width(), - mode.height(), - NULL, - NULL, - g_module_instance, - NULL); - - ShowWindow(hWnd, SW_SHOW); - return hWnd; +// Re-parents the content_hwnd into the containing_hwnd, resizing the +// content_hwnd to the given width and height in the process. +void ReplaceContentWindow(HWND content_hwnd, + HWND containing_hwnd, + int width, int height) { + ::ShowWindow(content_hwnd, SW_HIDE); + LONG_PTR style = ::GetWindowLongPtr(content_hwnd, GWL_STYLE); + style |= WS_CHILD; + ::SetWindowLongPtr(content_hwnd, GWL_STYLE, style); + ::SetParent(content_hwnd, containing_hwnd); + BOOL res = ::SetWindowPos(content_hwnd, containing_hwnd, + 0, 0, width, height, + SWP_NOZORDER | SWP_ASYNCWINDOWPOS); + DCHECK(res); + ::ShowWindow(content_hwnd, SW_SHOW); } + } // namespace anonymous #if defined(O3D_INTERNAL_PLUGIN) @@ -767,7 +701,7 @@ NPError OSCALL NP_Shutdown(void) { HANDLE_CRASHES; DLOG(INFO) << "NP_Shutdown"; - UnregisterFullScreenWindowClass(); + UnregisterO3DWindowClass(); #if !defined(O3D_INTERNAL_PLUGIN) @@ -870,30 +804,62 @@ NPError NPP_SetWindow(NPP instance, NPWindow *window) { } return NPERR_NO_ERROR; } - if (obj->GetHWnd() == hWnd) { - return NPERR_NO_ERROR; - } - if (obj->fullscreen()) { - // We can get here if the user alt+tabs away from the fullscreen plugin - // window or JavaScript resizes the plugin window. - DCHECK(obj->GetPluginHWnd()); - DCHECK(obj->GetFullscreenHWnd()); - DCHECK(obj->GetPluginHWnd() == hWnd); - - // Exit full screen if the plugin window is being modified. - obj->CancelFullscreenDisplay(); + if (obj->GetPluginHWnd() == hWnd) { + // May need to resize the content window. + DCHECK(obj->GetContentHWnd()); + // Avoid spurious resize requests. + if (window->width != obj->width() || + window->height != obj->height()) { + if (!obj->fullscreen()) { + ::SetWindowPos(obj->GetContentHWnd(), obj->GetPluginHWnd(), 0, 0, + window->width, window->height, + SWP_NOZORDER | SWP_NOREPOSITION); + } + // Even if we are in full-screen mode, store off the new width + // and height to restore to them later. + obj->Resize(window->width, window->height); + // Only propagate this resize event to the client if it isn't in + // full-screen mode. + if (!obj->fullscreen()) { + obj->client()->SendResizeEvent(obj->width(), obj->height(), false); + } + } return NPERR_NO_ERROR; } + DCHECK(!obj->GetPluginHWnd()); obj->SetPluginHWnd(hWnd); - obj->SetParentHWnd(::GetParent(hWnd)); - PluginObject::StorePluginProperty(hWnd, obj); - obj->SetDefaultPluginWindowProc( - reinterpret_cast<WNDPROC>( - ::SetWindowLongPtr(hWnd, - GWL_WNDPROC, - reinterpret_cast<LONG_PTR>(WindowProc)))); + + // Subclass the plugin window's window procedure to avoid processing + // WM_PAINT. This seems to only be necessary for Firefox, which + // overdraws our plugin the first time it gains focus. + SetProp(hWnd, kOrigWndProcName, + reinterpret_cast<HANDLE>(GetWindowLongPtr(hWnd, GWLP_WNDPROC))); + PluginObject::StorePluginPropertyUnsafe(hWnd, obj); + SetWindowLongPtr(hWnd, GWLP_WNDPROC, + reinterpret_cast<LONG_PTR>(PluginWindowInterposer)); + + // Create the content window, into which O3D always renders, rather + // than alternating rendering between the browser's window and a + // separate full-screen window. The O3D window is removed from the + // browser's hierarchy and made top-level in order to go to + // full-screen mode via Direct3D. This solves fundamental focus + // fighting problems seen on Windows Vista. + HWND content_window = + CreateWindow(kO3DWindowClassName, + L"O3D Window", + WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, + 0, 0, + window->width, window->height, + hWnd, + NULL, + g_module_instance, + NULL); + obj->Resize(window->width, window->height); + obj->SetContentHWnd(content_window); + PluginObject::StorePluginProperty(content_window, obj); + ::ShowWindow(content_window, SW_SHOW); // create and assign the graphics context DisplayWindowWindows default_display; @@ -937,32 +903,43 @@ bool PluginObject::GetDisplayMode(int mode_id, o3d::DisplayMode *mode) { bool PluginObject::RequestFullscreenDisplay() { bool success = false; DCHECK(GetPluginHWnd()); + DCHECK(GetContentHWnd()); if (!fullscreen_ && renderer_ && fullscreen_region_valid_) { DCHECK(renderer_->fullscreen() == fullscreen_); - DCHECK(!GetFullscreenHWnd()); - HWND drawing_hwnd = - CreateFullscreenWindow(this, fullscreen_region_mode_id_); - if (drawing_hwnd) { - ::KillTimer(GetHWnd(), 0); - SetFullscreenHWnd(drawing_hwnd); - StorePluginPropertyUnsafe(drawing_hwnd, this); - + // The focus window we pass into IDirect3D9::CreateDevice must not + // fight with the full-screen window for the focus. The best way + // to achieve this is to re-use the content window for full-screen + // mode. + ::ShowWindow(GetContentHWnd(), SW_HIDE); + ::SetParent(GetContentHWnd(), NULL); + // Remove WS_CHILD from the window style + LONG_PTR style = ::GetWindowLongPtr(GetContentHWnd(), GWL_STYLE); + style &= ~WS_CHILD; + ::SetWindowLongPtr(GetContentHWnd(), GWL_STYLE, style); + ::ShowWindow(GetContentHWnd(), SW_SHOW); + // We need to resize the full-screen window to the desired size of + // the display mode early, before calling + // Renderer::GoFullscreen(). + o3d::DisplayMode mode; + if (GetDisplayMode(fullscreen_region_mode_id_, &mode)) { + ::SetWindowPos(GetContentHWnd(), HWND_TOP, 0, 0, + mode.width(), mode.height(), + SWP_NOZORDER | SWP_NOREPOSITION | SWP_ASYNCWINDOWPOS); DisplayWindowWindows display; - display.set_hwnd(GetHWnd()); - if (renderer_->SetFullscreen(true, display, - fullscreen_region_mode_id_)) { + display.set_hwnd(GetContentHWnd()); + if (renderer_->GoFullscreen(display, + fullscreen_region_mode_id_)) { fullscreen_ = true; client()->SendResizeEvent(renderer_->width(), renderer_->height(), - true); + true); success = true; - } else { - CleanupFullscreenWindow(this); } - prev_width_ = renderer_->width(); - prev_height_ = renderer_->height(); - ::SetTimer(GetHWnd(), 0, 10, NULL); - } else { - LOG(ERROR) << "Failed to create fullscreen window."; + } + + if (!success) { + ReplaceContentWindow(GetContentHWnd(), GetPluginHWnd(), + prev_width_, prev_height_); + LOG(ERROR) << "Failed to switch to fullscreen mode."; } } return success; @@ -973,18 +950,15 @@ void PluginObject::CancelFullscreenDisplay() { if (fullscreen_) { DCHECK(renderer()); DCHECK(renderer()->fullscreen()); - ::KillTimer(GetHWnd(), 0); + fullscreen_ = false; DisplayWindowWindows display; - display.set_hwnd(GetPluginHWnd()); - if (!renderer_->SetFullscreen(false, display, 0)) { + display.set_hwnd(GetContentHWnd()); + if (!renderer_->CancelFullscreen(display, prev_width_, prev_height_)) { LOG(FATAL) << "Failed to get the renderer out of fullscreen mode!"; } - CleanupFullscreenWindow(this); - prev_width_ = renderer_->width(); - prev_height_ = renderer_->height(); + ReplaceContentWindow(GetContentHWnd(), GetPluginHWnd(), + prev_width_, prev_height_); client()->SendResizeEvent(prev_width_, prev_height_, false); - ::SetTimer(GetHWnd(), 0, 10, NULL); - fullscreen_ = false; } } } // namespace _o3d |