Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(558)

Unified Diff: plugin/win/main_win.cc

Issue 210005: Rewrote full-screen support on Windows. O3D now always creates its own... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/o3d/
Patch Set: '' Created 11 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « plugin/npapi_host_control/win/np_plugin_proxy.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: plugin/win/main_win.cc
===================================================================
--- plugin/win/main_win.cc (revision 26426)
+++ plugin/win/main_win.cc (working copy)
@@ -87,7 +87,7 @@
#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 @@
}
}
-// 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 @@
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 @@
}
}
::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 @@
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 @@
// 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 @@
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 @@
HANDLE_CRASHES;
DLOG(INFO) << "NP_Shutdown";
- UnregisterFullScreenWindowClass();
+ UnregisterO3DWindowClass();
#if !defined(O3D_INTERNAL_PLUGIN)
@@ -870,31 +804,63 @@
}
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;
default_display.set_hwnd(obj->GetHWnd());
@@ -937,33 +903,44 @@
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 @@
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
« no previous file with comments | « plugin/npapi_host_control/win/np_plugin_proxy.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698