summaryrefslogtreecommitdiffstats
path: root/o3d/plugin
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 /o3d/plugin
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
Diffstat (limited to 'o3d/plugin')
-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
7 files changed, 229 insertions, 231 deletions
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