OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2009, Google Inc. | 2 * Copyright 2009, Google Inc. |
3 * All rights reserved. | 3 * All rights reserved. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are | 6 * modification, are permitted provided that the following conditions are |
7 * met: | 7 * met: |
8 * | 8 * |
9 * * Redistributions of source code must retain the above copyright | 9 * * Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
80 bool v8_disposed = v8::V8::Dispose(); | 80 bool v8_disposed = v8::V8::Dispose(); |
81 if (!v8_disposed) | 81 if (!v8_disposed) |
82 DLOG(ERROR) << "Failed to release V8 resources."; | 82 DLOG(ERROR) << "Failed to release V8 resources."; |
83 return true; | 83 return true; |
84 } | 84 } |
85 return true; | 85 return true; |
86 } | 86 } |
87 #endif // O3D_INTERNAL_PLUGIN | 87 #endif // O3D_INTERNAL_PLUGIN |
88 | 88 |
89 namespace { | 89 namespace { |
90 const wchar_t* const kFullScreenWindowClassName = L"O3DFullScreenWindowClass"; | 90 const wchar_t* const kO3DWindowClassName = L"O3DWindowClass"; |
91 | 91 |
92 // We would normally make this a stack variable in main(), but in a | 92 // We would normally make this a stack variable in main(), but in a |
93 // plugin, that's not possible, so we make it a global. When the DLL is loaded | 93 // plugin, that's not possible, so we make it a global. When the DLL is loaded |
94 // this it gets constructed and when it is unlooaded it is destructed. Note | 94 // this it gets constructed and when it is unlooaded it is destructed. Note |
95 // that this cannot be done in NP_Initialize and NP_Shutdown because those | 95 // that this cannot be done in NP_Initialize and NP_Shutdown because those |
96 // calls do not necessarily signify the DLL being loaded and unloaded. If the | 96 // calls do not necessarily signify the DLL being loaded and unloaded. If the |
97 // DLL is not unloaded then the values of global variables are preserved. | 97 // DLL is not unloaded then the values of global variables are preserved. |
98 base::AtExitManager g_at_exit_manager; | 98 base::AtExitManager g_at_exit_manager; |
99 | 99 |
100 static int HandleKeyboardEvent(PluginObject *obj, | 100 static int HandleKeyboardEvent(PluginObject *obj, |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
345 if (fake_dblclick) { | 345 if (fake_dblclick) { |
346 event.set_type(Event::TYPE_DBLCLICK); | 346 event.set_type(Event::TYPE_DBLCLICK); |
347 obj->client()->AddEventToQueue(event); | 347 obj->client()->AddEventToQueue(event); |
348 } | 348 } |
349 if (in_plugin && type == Event::TYPE_MOUSEDOWN && | 349 if (in_plugin && type == Event::TYPE_MOUSEDOWN && |
350 obj->HitFullscreenClickRegion(x, y)) { | 350 obj->HitFullscreenClickRegion(x, y)) { |
351 obj->RequestFullscreenDisplay(); | 351 obj->RequestFullscreenDisplay(); |
352 } | 352 } |
353 } | 353 } |
354 | 354 |
355 // This returns 0 on success, 1 on failure, to match WindowProc. | |
356 LRESULT ForwardEvent(PluginObject *obj, | |
357 HWND hWnd, | |
358 UINT Msg, | |
359 WPARAM wParam, | |
360 LPARAM lParam, | |
361 bool translateCoords) { | |
362 DCHECK(obj); | |
363 DCHECK(obj->GetPluginHWnd()); | |
364 HWND dest_hwnd = obj->GetParentHWnd(); | |
365 DCHECK(hWnd); | |
366 DCHECK(dest_hwnd); | |
367 bool fullscreen = hWnd == obj->GetFullscreenHWnd(); | |
368 if (fullscreen) { | |
369 dest_hwnd = obj->GetPluginHWnd(); | |
370 } else if (obj->IsChrome()) { | |
371 // When trying to find the parent window of the Chrome plugin, new Chrome is | |
372 // different than old Chrome; it's got an extra wrapper window around the | |
373 // plugin that didn't used to be there. The wrapper won't listen to events, | |
374 // so if we see it, we have to go one window up the tree from there in order | |
375 // to find someone who'll listen to us. The new behavior is seen in nightly | |
376 // builds of Chromium as of 2.0.163.0 (9877) [but went in some time before | |
377 // that]; the old behavior is still exhibited by Chrome as of 1.0.154.48. | |
378 wchar_t chrome_class_name[] = L"WrapperNativeWindowClass"; | |
379 wchar_t buffer[sizeof(chrome_class_name) / sizeof(chrome_class_name[0])]; | |
380 if (!GetClassName(dest_hwnd, buffer, sizeof(buffer) / sizeof(buffer[0]))) { | |
381 return 1; | |
382 } | |
383 if (!wcscmp(chrome_class_name, buffer)) { | |
384 dest_hwnd = ::GetParent(dest_hwnd); | |
385 } | |
386 } | |
387 if (translateCoords) { | |
388 int x = GET_X_LPARAM(lParam); | |
389 int y = GET_Y_LPARAM(lParam); | |
390 | |
391 RECT rect0, rect1; | |
392 if (!::GetWindowRect(hWnd, &rect0)) { | |
393 DCHECK(false); | |
394 return 1; | |
395 } | |
396 if (!::GetWindowRect(dest_hwnd, &rect1)) { | |
397 DCHECK(false); | |
398 return 1; | |
399 } | |
400 int width = rect0.right - rect0.left; | |
401 int width_1 = rect1.right - rect1.left; | |
402 | |
403 int x_1; | |
404 int y_1; | |
405 | |
406 if (!fullscreen) { // Translate from plugin to browser offset coords. | |
407 x_1 = x - rect1.left + rect0.left; | |
408 } else { // Translate from screen to plugin offset coords. | |
409 // The plugin and the fullscreen window each fill their respective entire | |
410 // window, so there aren't any offsets to add or subtract. | |
411 x_1 = x * width_1 / width; | |
412 } | |
413 int height = rect0.bottom - rect0.top; | |
414 int height_1 = rect1.bottom - rect1.top; | |
415 if (!fullscreen) { // Translate from plugin to browser offset coords. | |
416 y_1 = y - rect1.top + rect0.top; | |
417 } else { // Translate from screen to plugin offset coords. | |
418 // The plugin and the fullscreen window each fill their respective entire | |
419 // window, so there aren't any offsets to add or subtract. | |
420 y_1 = y * height_1 / height; | |
421 } | |
422 | |
423 lParam = MAKELPARAM(x_1, y_1); | |
424 } | |
425 return !::PostMessage(dest_hwnd, Msg, wParam, lParam); | |
426 } | |
427 | |
428 LRESULT HandleDragAndDrop(PluginObject *obj, WPARAM wParam) { | 355 LRESULT HandleDragAndDrop(PluginObject *obj, WPARAM wParam) { |
429 HDROP hDrop = reinterpret_cast<HDROP>(wParam); | 356 HDROP hDrop = reinterpret_cast<HDROP>(wParam); |
430 UINT num_files = ::DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); | 357 UINT num_files = ::DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); |
431 if (!num_files) { | 358 if (!num_files) { |
432 ::DragFinish(hDrop); | 359 ::DragFinish(hDrop); |
433 return 0; | 360 return 0; |
434 } | 361 } |
435 UINT path_len = ::DragQueryFile(hDrop, 0, NULL, 0); | 362 UINT path_len = ::DragQueryFile(hDrop, 0, NULL, 0); |
436 // Let's limit that length, just in case. | 363 // Let's limit that length, just in case. |
437 if (!path_len || path_len > 4096) { | 364 if (!path_len || path_len > 4096) { |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
500 PAINTSTRUCT paint_struct; | 427 PAINTSTRUCT paint_struct; |
501 HDC hdc = ::BeginPaint(hWnd, &paint_struct); | 428 HDC hdc = ::BeginPaint(hWnd, &paint_struct); |
502 if (paint_struct.rcPaint.right - paint_struct.rcPaint.left != 0 || | 429 if (paint_struct.rcPaint.right - paint_struct.rcPaint.left != 0 || |
503 paint_struct.rcPaint.bottom - paint_struct.rcPaint.top != 0) { | 430 paint_struct.rcPaint.bottom - paint_struct.rcPaint.top != 0) { |
504 if (obj->renderer()) { | 431 if (obj->renderer()) { |
505 // It appears to be necessary to use GDI to paint something at least | 432 // It appears to be necessary to use GDI to paint something at least |
506 // once before D3D rendering will work in Vista with Aero. | 433 // once before D3D rendering will work in Vista with Aero. |
507 if (!obj->RecordPaint()) { | 434 if (!obj->RecordPaint()) { |
508 ::SetPixelV(hdc, 0, 0, RGB(0, 0, 0)); | 435 ::SetPixelV(hdc, 0, 0, RGB(0, 0, 0)); |
509 } | 436 } |
510 | |
511 obj->renderer()->set_need_to_render(true); | 437 obj->renderer()->set_need_to_render(true); |
512 } else { | 438 } else { |
513 // If there Client has no Renderer associated with it, paint the draw | 439 // If the Client has no Renderer associated with it, paint the |
514 // area gray. | 440 // draw area gray. |
515 ::SelectObject(paint_struct.hdc, GetStockObject(DKGRAY_BRUSH)); | 441 ::SelectObject(paint_struct.hdc, GetStockObject(DKGRAY_BRUSH)); |
516 ::Rectangle(paint_struct.hdc, | 442 ::Rectangle(paint_struct.hdc, |
517 paint_struct.rcPaint.left, | 443 paint_struct.rcPaint.left, |
518 paint_struct.rcPaint.top, | 444 paint_struct.rcPaint.top, |
519 paint_struct.rcPaint.right, | 445 paint_struct.rcPaint.right, |
520 paint_struct.rcPaint.bottom); | 446 paint_struct.rcPaint.bottom); |
521 } | 447 } |
522 } | 448 } |
523 ::EndPaint(hWnd, &paint_struct); | 449 ::EndPaint(hWnd, &paint_struct); |
524 break; | 450 return 0; |
525 } | 451 } |
526 case WM_SETCURSOR: { | 452 case WM_SETCURSOR: { |
527 obj->set_cursor(obj->cursor()); | 453 obj->set_cursor(obj->cursor()); |
528 return 1; | 454 return 1; |
529 } | 455 } |
530 case WM_ERASEBKGND: { | 456 case WM_ERASEBKGND: { |
531 return 1; // tell windows we don't need the background cleared | 457 // Tell windows we don't need the background cleared. |
| 458 return 1; |
532 } | 459 } |
533 case WM_SIZE: { | |
534 // Resize event called | |
535 if (reentrance_count.get() > 1) { | |
536 break; // Ignore this message; we're reentrant. | |
537 } | |
538 | 460 |
539 // get new dimensions of window | |
540 int window_width = LOWORD(lParam); | |
541 int window_height = HIWORD(lParam); | |
542 | |
543 // Tell the plugin that it has been resized | |
544 obj->Resize(window_width, window_height); | |
545 break; | |
546 } | |
547 case WM_TIMER: { | 461 case WM_TIMER: { |
548 if (reentrance_count.get() > 1) { | 462 if (reentrance_count.get() > 1) { |
549 break; // Ignore this message; we're reentrant. | 463 break; // Ignore this message; we're reentrant. |
550 } | 464 } |
551 | 465 |
552 #if !defined(O3D_INTERNAL_PLUGIN) | 466 #if !defined(O3D_INTERNAL_PLUGIN) |
553 // TODO: Only logging for windows until we figure out the proper | 467 // TODO: Only logging for windows until we figure out the proper |
554 // mac way | 468 // mac way |
555 if (g_logger) g_logger->UpdateLogging(); | 469 if (g_logger) g_logger->UpdateLogging(); |
556 #endif | 470 #endif |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
612 break; | 526 break; |
613 | 527 |
614 case WM_CHAR: | 528 case WM_CHAR: |
615 case WM_SYSCHAR: | 529 case WM_SYSCHAR: |
616 case WM_KEYDOWN: | 530 case WM_KEYDOWN: |
617 case WM_KEYUP: | 531 case WM_KEYUP: |
618 case WM_SYSKEYDOWN: | 532 case WM_SYSKEYDOWN: |
619 case WM_SYSKEYUP: | 533 case WM_SYSKEYUP: |
620 return HandleKeyboardEvent(obj, hWnd, Msg, wParam, lParam); | 534 return HandleKeyboardEvent(obj, hWnd, Msg, wParam, lParam); |
621 | 535 |
622 #if(_WIN32_WINNT >= 0x0500) | |
623 case WM_APPCOMMAND: | |
624 #endif /* _WIN32_WINNT >= 0x0500 */ | |
625 return ForwardEvent(obj, hWnd, Msg, wParam, lParam, false); | |
626 | |
627 case WM_DROPFILES: | 536 case WM_DROPFILES: |
628 return HandleDragAndDrop(obj, wParam); | 537 return HandleDragAndDrop(obj, wParam); |
629 | 538 |
| 539 case WM_ACTIVATE: |
| 540 // We don't receive WM_KILLFOCUS when Alt-Tabbing away from a |
| 541 // full-screen window. We do however get WM_ACTIVATE. |
| 542 if (LOWORD(wParam) == WA_INACTIVE) { |
| 543 if (obj->fullscreen()) { |
| 544 obj->CancelFullscreenDisplay(); |
| 545 } |
| 546 } |
| 547 return 0; |
| 548 |
630 case WM_KILLFOCUS: | 549 case WM_KILLFOCUS: |
631 // If we lose focus [which also happens on alt+f4 killing the fullscreen | 550 // If we lose focus [which also happens on alt+f4 killing the fullscreen |
632 // window] fall back to plugin mode to avoid lost-device awkwardness. | 551 // window] fall back to plugin mode to avoid lost-device awkwardness. |
633 // TODO: We'll have problems with this when dealing with e.g. | 552 // TODO: We'll have problems with this when dealing with e.g. |
634 // Japanese text input IME windows. | 553 // Japanese text input IME windows. |
635 if (hWnd == obj->GetFullscreenHWnd()) { | 554 if (obj->fullscreen()) { |
| 555 // TODO(kbr): consider doing this somehow more asynchronously; |
| 556 // not supposed to cause window activation in the WM_KILLFOCUS |
| 557 // handler |
636 obj->CancelFullscreenDisplay(); | 558 obj->CancelFullscreenDisplay(); |
637 return 0; | 559 return 0; |
638 } | 560 } |
639 // FALL THROUGH | 561 // FALL THROUGH |
640 case WM_SETFOCUS: | 562 case WM_SETFOCUS: |
641 default: | 563 default: |
642 // Decrement reentrance_count here. It's OK if this call | 564 // Decrement reentrance_count here. It's OK if this call |
643 // boomerangs back to us, given that we're not in the middle of doing | 565 // boomerangs back to us, given that we're not in the middle of doing |
644 // anything caused by this message. Since we decrement reentrance_count | 566 // anything caused by this message. Since we decrement reentrance_count |
645 // manually, its destructor will know not to. | 567 // manually, its destructor will know not to. |
646 reentrance_count.decrement(); | 568 reentrance_count.decrement(); |
647 | 569 |
648 if (hWnd == obj->GetFullscreenHWnd()) { | 570 return ::CallWindowProc(::DefWindowProc, |
649 return ::CallWindowProc(::DefWindowProc, | 571 hWnd, |
650 hWnd, | 572 Msg, |
651 Msg, | 573 wParam, |
652 wParam, | 574 lParam); |
653 lParam); | |
654 } else { | |
655 return ::CallWindowProc(obj->GetDefaultPluginWindowProc(), | |
656 hWnd, | |
657 Msg, | |
658 wParam, | |
659 lParam); | |
660 } | |
661 } | 575 } |
662 return 0; | 576 return 0; |
663 } | 577 } |
664 | 578 |
665 bool RegisterFullScreenWindowClass() { | 579 static const wchar_t* kOrigWndProcName = L"o3dOrigWndProc"; |
666 WNDCLASSEX window_class = { sizeof(WNDCLASSEX) }; | 580 |
| 581 LRESULT CALLBACK PluginWindowInterposer(HWND hWnd, |
| 582 UINT Msg, |
| 583 WPARAM wParam, |
| 584 LPARAM lParam) { |
| 585 switch (Msg) { |
| 586 case WM_PAINT: { |
| 587 // For nicer startup appearance, allow the browser to paint the |
| 588 // plugin window until we start to draw 3D content. Forbid the |
| 589 // browser from painting once we have started to draw to prevent |
| 590 // a flash in Firefox upon our receiving focus the first time. |
| 591 PluginObject *obj = PluginObject::GetPluginProperty(hWnd); |
| 592 if (obj != NULL && obj->renderer() != NULL) { |
| 593 if (obj->renderer()->presented_once()) { |
| 594 // Tell Windows we painted the window region. |
| 595 ::ValidateRect(hWnd, NULL); |
| 596 return 0; |
| 597 } |
| 598 } |
| 599 // Break out to call the original window procedure to paint the |
| 600 // window. |
| 601 break; |
| 602 } |
| 603 |
| 604 default: |
| 605 break; |
| 606 } |
| 607 |
| 608 WNDPROC proc = static_cast<WNDPROC>(GetProp(hWnd, kOrigWndProcName)); |
| 609 DCHECK(proc != NULL); |
| 610 return CallWindowProc(proc, hWnd, Msg, wParam, lParam); |
| 611 } |
| 612 |
| 613 bool RegisterO3DWindowClass() { |
| 614 WNDCLASSEX window_class; |
| 615 ZeroMemory(&window_class, sizeof(window_class)); |
| 616 window_class.cbSize = sizeof(window_class); |
667 window_class.hInstance = g_module_instance; | 617 window_class.hInstance = g_module_instance; |
668 window_class.lpfnWndProc = WindowProc; | 618 window_class.lpfnWndProc = WindowProc; |
669 window_class.lpszClassName = kFullScreenWindowClassName; | 619 window_class.lpszClassName = kO3DWindowClassName; |
670 window_class.style = CS_DBLCLKS; | 620 // We use CS_OWNDC in case we are rendering OpenGL into this window. |
| 621 window_class.style = CS_DBLCLKS | CS_OWNDC; |
671 return RegisterClassEx(&window_class) != 0; | 622 return RegisterClassEx(&window_class) != 0; |
672 } | 623 } |
673 | 624 |
674 void UnregisterFullScreenWindowClass() { | 625 void UnregisterO3DWindowClass() { |
675 UnregisterClass(kFullScreenWindowClassName, g_module_instance); | 626 UnregisterClass(kO3DWindowClassName, g_module_instance); |
676 } | 627 } |
677 | 628 |
678 NPError InitializePlugin() { | 629 NPError InitializePlugin() { |
679 #if !defined(O3D_INTERNAL_PLUGIN) | 630 #if !defined(O3D_INTERNAL_PLUGIN) |
680 if (!o3d::SetupOutOfMemoryHandler()) | 631 if (!o3d::SetupOutOfMemoryHandler()) |
681 return NPERR_MODULE_LOAD_FAILED_ERROR; | 632 return NPERR_MODULE_LOAD_FAILED_ERROR; |
682 | 633 |
683 // Setup crash handler | 634 // Setup crash handler |
684 if (!g_exception_manager) { | 635 if (!g_exception_manager) { |
685 g_exception_manager = new ExceptionManager(false); | 636 g_exception_manager = new ExceptionManager(false); |
686 g_exception_manager->StartMonitoring(); | 637 g_exception_manager->StartMonitoring(); |
687 } | 638 } |
688 | 639 |
689 // Turn on the logging. | 640 // Turn on the logging. |
690 CommandLine::Init(0, NULL); | 641 CommandLine::Init(0, NULL); |
691 InitLogging(L"debug.log", | 642 InitLogging(L"debug.log", |
692 logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG, | 643 logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG, |
693 logging::DONT_LOCK_LOG_FILE, | 644 logging::DONT_LOCK_LOG_FILE, |
694 logging::APPEND_TO_OLD_LOG_FILE); | 645 logging::APPEND_TO_OLD_LOG_FILE); |
695 #endif // O3D_INTERNAL_PLUGIN | 646 #endif // O3D_INTERNAL_PLUGIN |
696 | 647 |
697 DLOG(INFO) << "NP_Initialize"; | 648 DLOG(INFO) << "NP_Initialize"; |
698 | 649 |
699 if (!RegisterFullScreenWindowClass()) | 650 if (!RegisterO3DWindowClass()) |
700 return NPERR_MODULE_LOAD_FAILED_ERROR; | 651 return NPERR_MODULE_LOAD_FAILED_ERROR; |
701 | 652 |
702 return NPERR_NO_ERROR; | 653 return NPERR_NO_ERROR; |
703 } | 654 } |
704 | 655 |
705 void CleanupFullscreenWindow(PluginObject *obj) { | |
706 DCHECK(obj->GetFullscreenHWnd()); | |
707 obj->StorePluginProperty(obj->GetPluginHWnd(), obj); | |
708 ::DestroyWindow(obj->GetFullscreenHWnd()); | |
709 obj->SetFullscreenHWnd(NULL); | |
710 } | |
711 | |
712 void CleanupAllWindows(PluginObject *obj) { | 656 void CleanupAllWindows(PluginObject *obj) { |
713 DCHECK(obj->GetHWnd()); | 657 DCHECK(obj->GetContentHWnd()); |
714 DCHECK(obj->GetPluginHWnd()); | 658 DCHECK(obj->GetPluginHWnd()); |
715 ::KillTimer(obj->GetHWnd(), 0); | 659 ::KillTimer(obj->GetContentHWnd(), 0); |
716 if (obj->GetFullscreenHWnd()) { | 660 PluginObject::ClearPluginProperty(obj->GetContentHWnd()); |
717 CleanupFullscreenWindow(obj); | 661 PluginObject::ClearPluginProperty(obj->GetPluginHWnd()); |
718 } | 662 ::DestroyWindow(obj->GetContentHWnd()); |
719 PluginObject::ClearPluginProperty(obj->GetHWnd()); | 663 obj->SetContentHWnd(NULL); |
720 ::SetWindowLongPtr(obj->GetPluginHWnd(), | |
721 GWL_WNDPROC, | |
722 reinterpret_cast<LONG_PTR>( | |
723 obj->GetDefaultPluginWindowProc())); | |
724 obj->SetPluginHWnd(NULL); | 664 obj->SetPluginHWnd(NULL); |
725 obj->SetHWnd(NULL); | 665 obj->SetHWnd(NULL); |
726 } | 666 } |
727 | 667 |
728 HWND CreateFullscreenWindow(PluginObject *obj, | 668 // Re-parents the content_hwnd into the containing_hwnd, resizing the |
729 int mode_id) { | 669 // content_hwnd to the given width and height in the process. |
730 o3d::DisplayMode mode; | 670 void ReplaceContentWindow(HWND content_hwnd, |
731 if (!obj->renderer()->GetDisplayMode(mode_id, &mode)) { | 671 HWND containing_hwnd, |
732 return NULL; | 672 int width, int height) { |
733 } | 673 ::ShowWindow(content_hwnd, SW_HIDE); |
734 CHECK(mode.width() > 0 && mode.height() > 0); | 674 LONG_PTR style = ::GetWindowLongPtr(content_hwnd, GWL_STYLE); |
| 675 style |= WS_CHILD; |
| 676 ::SetWindowLongPtr(content_hwnd, GWL_STYLE, style); |
| 677 ::SetParent(content_hwnd, containing_hwnd); |
| 678 BOOL res = ::SetWindowPos(content_hwnd, containing_hwnd, |
| 679 0, 0, width, height, |
| 680 SWP_NOZORDER | SWP_ASYNCWINDOWPOS); |
| 681 DCHECK(res); |
| 682 ::ShowWindow(content_hwnd, SW_SHOW); |
| 683 } |
735 | 684 |
736 HWND hWnd = CreateWindowEx(NULL, | |
737 kFullScreenWindowClassName, | |
738 L"O3D Test Fullscreen Window", | |
739 WS_POPUP, | |
740 0, 0, | |
741 mode.width(), | |
742 mode.height(), | |
743 NULL, | |
744 NULL, | |
745 g_module_instance, | |
746 NULL); | |
747 | |
748 ShowWindow(hWnd, SW_SHOW); | |
749 return hWnd; | |
750 } | |
751 } // namespace anonymous | 685 } // namespace anonymous |
752 | 686 |
753 #if defined(O3D_INTERNAL_PLUGIN) | 687 #if defined(O3D_INTERNAL_PLUGIN) |
754 namespace o3d { | 688 namespace o3d { |
755 #else | 689 #else |
756 extern "C" { | 690 extern "C" { |
757 #endif | 691 #endif |
758 | 692 |
759 NPError OSCALL NP_Initialize(NPNetscapeFuncs *browserFuncs) { | 693 NPError OSCALL NP_Initialize(NPNetscapeFuncs *browserFuncs) { |
760 HANDLE_CRASHES; | 694 HANDLE_CRASHES; |
761 NPError retval = InitializeNPNApi(browserFuncs); | 695 NPError retval = InitializeNPNApi(browserFuncs); |
762 if (retval != NPERR_NO_ERROR) return retval; | 696 if (retval != NPERR_NO_ERROR) return retval; |
763 return InitializePlugin(); | 697 return InitializePlugin(); |
764 } | 698 } |
765 | 699 |
766 NPError OSCALL NP_Shutdown(void) { | 700 NPError OSCALL NP_Shutdown(void) { |
767 HANDLE_CRASHES; | 701 HANDLE_CRASHES; |
768 DLOG(INFO) << "NP_Shutdown"; | 702 DLOG(INFO) << "NP_Shutdown"; |
769 | 703 |
770 UnregisterFullScreenWindowClass(); | 704 UnregisterO3DWindowClass(); |
771 | 705 |
772 #if !defined(O3D_INTERNAL_PLUGIN) | 706 #if !defined(O3D_INTERNAL_PLUGIN) |
773 | 707 |
774 if (g_logger) { | 708 if (g_logger) { |
775 // Do a last sweep to aggregate metrics before we shut down | 709 // Do a last sweep to aggregate metrics before we shut down |
776 g_logger->ProcessMetrics(true, false); | 710 g_logger->ProcessMetrics(true, false); |
777 delete g_logger; | 711 delete g_logger; |
778 g_logger = NULL; | 712 g_logger = NULL; |
779 g_logging_initialized = false; | 713 g_logging_initialized = false; |
780 stats_report::g_global_metrics.Uninitialize(); | 714 stats_report::g_global_metrics.Uninitialize(); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
863 PluginObject *obj = static_cast<PluginObject*>(instance->pdata); | 797 PluginObject *obj = static_cast<PluginObject*>(instance->pdata); |
864 | 798 |
865 HWND hWnd = static_cast<HWND>(window->window); | 799 HWND hWnd = static_cast<HWND>(window->window); |
866 if (!hWnd) { | 800 if (!hWnd) { |
867 // Chrome calls us this way before NPP_Destroy. | 801 // Chrome calls us this way before NPP_Destroy. |
868 if (obj->GetHWnd()) { | 802 if (obj->GetHWnd()) { |
869 CleanupAllWindows(obj); | 803 CleanupAllWindows(obj); |
870 } | 804 } |
871 return NPERR_NO_ERROR; | 805 return NPERR_NO_ERROR; |
872 } | 806 } |
873 if (obj->GetHWnd() == hWnd) { | 807 |
| 808 if (obj->GetPluginHWnd() == hWnd) { |
| 809 // May need to resize the content window. |
| 810 DCHECK(obj->GetContentHWnd()); |
| 811 // Avoid spurious resize requests. |
| 812 if (window->width != obj->width() || |
| 813 window->height != obj->height()) { |
| 814 if (!obj->fullscreen()) { |
| 815 ::SetWindowPos(obj->GetContentHWnd(), obj->GetPluginHWnd(), 0, 0, |
| 816 window->width, window->height, |
| 817 SWP_NOZORDER | SWP_NOREPOSITION); |
| 818 } |
| 819 // Even if we are in full-screen mode, store off the new width |
| 820 // and height to restore to them later. |
| 821 obj->Resize(window->width, window->height); |
| 822 // Only propagate this resize event to the client if it isn't in |
| 823 // full-screen mode. |
| 824 if (!obj->fullscreen()) { |
| 825 obj->client()->SendResizeEvent(obj->width(), obj->height(), false); |
| 826 } |
| 827 } |
874 return NPERR_NO_ERROR; | 828 return NPERR_NO_ERROR; |
875 } | 829 } |
876 if (obj->fullscreen()) { | |
877 // We can get here if the user alt+tabs away from the fullscreen plugin | |
878 // window or JavaScript resizes the plugin window. | |
879 DCHECK(obj->GetPluginHWnd()); | |
880 DCHECK(obj->GetFullscreenHWnd()); | |
881 DCHECK(obj->GetPluginHWnd() == hWnd); | |
882 | 830 |
883 // Exit full screen if the plugin window is being modified. | |
884 obj->CancelFullscreenDisplay(); | |
885 | |
886 return NPERR_NO_ERROR; | |
887 } | |
888 DCHECK(!obj->GetPluginHWnd()); | 831 DCHECK(!obj->GetPluginHWnd()); |
889 obj->SetPluginHWnd(hWnd); | 832 obj->SetPluginHWnd(hWnd); |
890 obj->SetParentHWnd(::GetParent(hWnd)); | 833 |
891 PluginObject::StorePluginProperty(hWnd, obj); | 834 // Subclass the plugin window's window procedure to avoid processing |
892 obj->SetDefaultPluginWindowProc( | 835 // WM_PAINT. This seems to only be necessary for Firefox, which |
893 reinterpret_cast<WNDPROC>( | 836 // overdraws our plugin the first time it gains focus. |
894 ::SetWindowLongPtr(hWnd, | 837 SetProp(hWnd, kOrigWndProcName, |
895 GWL_WNDPROC, | 838 reinterpret_cast<HANDLE>(GetWindowLongPtr(hWnd, GWLP_WNDPROC))); |
896 reinterpret_cast<LONG_PTR>(WindowProc)))); | 839 PluginObject::StorePluginPropertyUnsafe(hWnd, obj); |
| 840 SetWindowLongPtr(hWnd, GWLP_WNDPROC, |
| 841 reinterpret_cast<LONG_PTR>(PluginWindowInterposer)); |
| 842 |
| 843 // Create the content window, into which O3D always renders, rather |
| 844 // than alternating rendering between the browser's window and a |
| 845 // separate full-screen window. The O3D window is removed from the |
| 846 // browser's hierarchy and made top-level in order to go to |
| 847 // full-screen mode via Direct3D. This solves fundamental focus |
| 848 // fighting problems seen on Windows Vista. |
| 849 HWND content_window = |
| 850 CreateWindow(kO3DWindowClassName, |
| 851 L"O3D Window", |
| 852 WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, |
| 853 0, 0, |
| 854 window->width, window->height, |
| 855 hWnd, |
| 856 NULL, |
| 857 g_module_instance, |
| 858 NULL); |
| 859 obj->Resize(window->width, window->height); |
| 860 obj->SetContentHWnd(content_window); |
| 861 PluginObject::StorePluginProperty(content_window, obj); |
| 862 ::ShowWindow(content_window, SW_SHOW); |
897 | 863 |
898 // create and assign the graphics context | 864 // create and assign the graphics context |
899 DisplayWindowWindows default_display; | 865 DisplayWindowWindows default_display; |
900 default_display.set_hwnd(obj->GetHWnd()); | 866 default_display.set_hwnd(obj->GetHWnd()); |
901 | 867 |
902 obj->CreateRenderer(default_display); | 868 obj->CreateRenderer(default_display); |
903 obj->client()->Init(); | 869 obj->client()->Init(); |
904 | 870 |
905 // we set the timer to 10ms or 100fps. At the time of this comment | 871 // we set the timer to 10ms or 100fps. At the time of this comment |
906 // the renderer does a vsync the max fps it will run will be the refresh | 872 // the renderer does a vsync the max fps it will run will be the refresh |
(...skipping 23 matching lines...) Expand all Loading... |
930 namespace _o3d { | 896 namespace _o3d { |
931 bool PluginObject::GetDisplayMode(int mode_id, o3d::DisplayMode *mode) { | 897 bool PluginObject::GetDisplayMode(int mode_id, o3d::DisplayMode *mode) { |
932 return renderer()->GetDisplayMode(mode_id, mode); | 898 return renderer()->GetDisplayMode(mode_id, mode); |
933 } | 899 } |
934 | 900 |
935 // TODO: Where should this really live? It's platform-specific, but in | 901 // TODO: Where should this really live? It's platform-specific, but in |
936 // PluginObject, which mainly lives in cross/o3d_glue.h+cc. | 902 // PluginObject, which mainly lives in cross/o3d_glue.h+cc. |
937 bool PluginObject::RequestFullscreenDisplay() { | 903 bool PluginObject::RequestFullscreenDisplay() { |
938 bool success = false; | 904 bool success = false; |
939 DCHECK(GetPluginHWnd()); | 905 DCHECK(GetPluginHWnd()); |
| 906 DCHECK(GetContentHWnd()); |
940 if (!fullscreen_ && renderer_ && fullscreen_region_valid_) { | 907 if (!fullscreen_ && renderer_ && fullscreen_region_valid_) { |
941 DCHECK(renderer_->fullscreen() == fullscreen_); | 908 DCHECK(renderer_->fullscreen() == fullscreen_); |
942 DCHECK(!GetFullscreenHWnd()); | 909 // The focus window we pass into IDirect3D9::CreateDevice must not |
943 HWND drawing_hwnd = | 910 // fight with the full-screen window for the focus. The best way |
944 CreateFullscreenWindow(this, fullscreen_region_mode_id_); | 911 // to achieve this is to re-use the content window for full-screen |
945 if (drawing_hwnd) { | 912 // mode. |
946 ::KillTimer(GetHWnd(), 0); | 913 ::ShowWindow(GetContentHWnd(), SW_HIDE); |
947 SetFullscreenHWnd(drawing_hwnd); | 914 ::SetParent(GetContentHWnd(), NULL); |
948 StorePluginPropertyUnsafe(drawing_hwnd, this); | 915 // Remove WS_CHILD from the window style |
949 | 916 LONG_PTR style = ::GetWindowLongPtr(GetContentHWnd(), GWL_STYLE); |
| 917 style &= ~WS_CHILD; |
| 918 ::SetWindowLongPtr(GetContentHWnd(), GWL_STYLE, style); |
| 919 ::ShowWindow(GetContentHWnd(), SW_SHOW); |
| 920 // We need to resize the full-screen window to the desired size of |
| 921 // the display mode early, before calling |
| 922 // Renderer::GoFullscreen(). |
| 923 o3d::DisplayMode mode; |
| 924 if (GetDisplayMode(fullscreen_region_mode_id_, &mode)) { |
| 925 ::SetWindowPos(GetContentHWnd(), HWND_TOP, 0, 0, |
| 926 mode.width(), mode.height(), |
| 927 SWP_NOZORDER | SWP_NOREPOSITION | SWP_ASYNCWINDOWPOS); |
950 DisplayWindowWindows display; | 928 DisplayWindowWindows display; |
951 display.set_hwnd(GetHWnd()); | 929 display.set_hwnd(GetContentHWnd()); |
952 if (renderer_->SetFullscreen(true, display, | 930 if (renderer_->GoFullscreen(display, |
953 fullscreen_region_mode_id_)) { | 931 fullscreen_region_mode_id_)) { |
954 fullscreen_ = true; | 932 fullscreen_ = true; |
955 client()->SendResizeEvent(renderer_->width(), renderer_->height(), | 933 client()->SendResizeEvent(renderer_->width(), renderer_->height(), |
956 true); | 934 true); |
957 success = true; | 935 success = true; |
958 } else { | |
959 CleanupFullscreenWindow(this); | |
960 } | 936 } |
961 prev_width_ = renderer_->width(); | 937 } |
962 prev_height_ = renderer_->height(); | 938 |
963 ::SetTimer(GetHWnd(), 0, 10, NULL); | 939 if (!success) { |
964 } else { | 940 ReplaceContentWindow(GetContentHWnd(), GetPluginHWnd(), |
965 LOG(ERROR) << "Failed to create fullscreen window."; | 941 prev_width_, prev_height_); |
| 942 LOG(ERROR) << "Failed to switch to fullscreen mode."; |
966 } | 943 } |
967 } | 944 } |
968 return success; | 945 return success; |
969 } | 946 } |
970 | 947 |
971 void PluginObject::CancelFullscreenDisplay() { | 948 void PluginObject::CancelFullscreenDisplay() { |
972 DCHECK(GetPluginHWnd()); | 949 DCHECK(GetPluginHWnd()); |
973 if (fullscreen_) { | 950 if (fullscreen_) { |
974 DCHECK(renderer()); | 951 DCHECK(renderer()); |
975 DCHECK(renderer()->fullscreen()); | 952 DCHECK(renderer()->fullscreen()); |
976 ::KillTimer(GetHWnd(), 0); | 953 fullscreen_ = false; |
977 DisplayWindowWindows display; | 954 DisplayWindowWindows display; |
978 display.set_hwnd(GetPluginHWnd()); | 955 display.set_hwnd(GetContentHWnd()); |
979 if (!renderer_->SetFullscreen(false, display, 0)) { | 956 if (!renderer_->CancelFullscreen(display, prev_width_, prev_height_)) { |
980 LOG(FATAL) << "Failed to get the renderer out of fullscreen mode!"; | 957 LOG(FATAL) << "Failed to get the renderer out of fullscreen mode!"; |
981 } | 958 } |
982 CleanupFullscreenWindow(this); | 959 ReplaceContentWindow(GetContentHWnd(), GetPluginHWnd(), |
983 prev_width_ = renderer_->width(); | 960 prev_width_, prev_height_); |
984 prev_height_ = renderer_->height(); | |
985 client()->SendResizeEvent(prev_width_, prev_height_, false); | 961 client()->SendResizeEvent(prev_width_, prev_height_, false); |
986 ::SetTimer(GetHWnd(), 0, 10, NULL); | |
987 fullscreen_ = false; | |
988 } | 962 } |
989 } | 963 } |
990 } // namespace _o3d | 964 } // namespace _o3d |
991 } // namespace glue | 965 } // namespace glue |
OLD | NEW |