summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkbr@google.com <kbr@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-17 21:42:54 +0000
committerkbr@google.com <kbr@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-17 21:42:54 +0000
commit9149cdc6f2acf0db263281ce2d4bb40112847582 (patch)
treef2749b3565b65aad5ed076201a3eacdbc496f95e
parent0cbacf170644b4efce6c98b6637bba942b9110a5 (diff)
downloadchromium_src-9149cdc6f2acf0db263281ce2d4bb40112847582.zip
chromium_src-9149cdc6f2acf0db263281ce2d4bb40112847582.tar.gz
chromium_src-9149cdc6f2acf0db263281ce2d4bb40112847582.tar.bz2
Rewrote full-screen support on Windows. O3D now always creates its own
window in which to render, rather than rendering into either the browser's window or 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. This change allowed the event forwarding code in the plugin's window message loop to be deleted, but a new workaround for a flicker upon the first mouse click in O3D in Firefox was required. Split the Renderer's fullscreen API into GoFullscreen and CancelFullscreen to solve chicken-and-egg problems with coming out of full-screen mode. Changed how the plugin detects resize events. Rather than responding to WM_SIZE messages, NPP_SetWindow is now responsible for propagating resize events to the client. Changed the ActiveX host control to call NPP_SetWindow in response to SetObjectRects. Fixed RendererGL::IsCurrent() on non-Mac platforms. Removed the bogus current_renderer_ static variable. Tested the following scenarios in IE and Firefox on Windows: - Full-screen involving display mode change, Escape to exit. - Full-screen involving display mode change, Alt-Tab to exit. - Full-screen involving display mode change, Alt-F4 to exit. - Full-screen involving display mode change, timeout to exit. - Full-screen with no display mode change, Escape to exit. - Full-screen with no display mode change, Alt-Tab to exit. - Full-screen with no display mode change, Alt-F4 to exit. - Full-screen with no display mode change, timeout to exit. - Beach demo, particle demo, other tests. Tested the following scenarios on the Mac in Safari (for which the code path didn't change): - Full-screen, escape to exit. - Full-screen, Alt-Tab to exit. - Full-screen, timeout to exit. When http://crbug.com/21921 is fixed, full-screen mode will work on Windows Vista with Aero on in Chrome. Review URL: http://codereview.chromium.org/210005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@26489 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--o3d/core/cross/gl/renderer_gl.cc22
-rw-r--r--o3d/core/cross/gl/renderer_gl.h51
-rw-r--r--o3d/core/cross/renderer.cc4
-rw-r--r--o3d/core/cross/renderer.h33
-rw-r--r--o3d/core/win/d3d9/renderer_d3d9.cc80
-rw-r--r--o3d/core/win/d3d9/renderer_d3d9.h16
-rw-r--r--o3d/plugin/cross/o3d_glue.cc6
-rw-r--r--o3d/plugin/cross/o3d_glue.h32
-rw-r--r--o3d/plugin/npapi_host_control/win/host_control.cc19
-rw-r--r--o3d/plugin/npapi_host_control/win/host_control.h3
-rw-r--r--o3d/plugin/npapi_host_control/win/np_plugin_proxy.cc13
-rw-r--r--o3d/plugin/npapi_host_control/win/np_plugin_proxy.h5
-rw-r--r--o3d/plugin/win/main_win.cc382
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