// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include "base/gfx/rect.h" #include "webkit/glue/plugins/fake_plugin_window_tracker_mac.h" namespace webkit_glue { void NotifyBrowserOfPluginSelectWindow(uint32 window_id, CGRect bounds); void NotifyBrowserOfPluginShowWindow(uint32 window_id, CGRect bounds); void NotifyBrowserOfPluginHideWindow(uint32 window_id, CGRect bounds); void NotifyBrowserOfPluginDisposeWindow(uint32 window_id, CGRect bounds); } // The process that was frontmost when a plugin created a new window; generally // we expect this to be the browser UI process. static ProcessSerialNumber g_saved_front_process = { 0, 0 }; // Bring the plugin process to the front so that the user can see it. // TODO: Make this an IPC to order the plugin process above the browser // process but not necessarily the frontmost. static void SwitchToPluginProcess() { ProcessSerialNumber this_process, front_process; if (GetCurrentProcess(&this_process) != noErr) return; if (GetFrontProcess(&front_process) != noErr) return; Boolean matched = false; if (SameProcess(&this_process, &front_process, &matched) != noErr) return; if (!matched) { // TODO: We may need to keep a stack, or at least check the total window // count, since this won't work if a plugin opens more than one window at // a time. g_saved_front_process = front_process; SetFrontProcess(&this_process); } } // If the plugin process is still the front process, bring the prior // front process (normally this will be the browser process) back to // the front. // TODO: Make this an IPC message so that the browser can properly // reactivate the window. static void SwitchToSavedProcess() { ProcessSerialNumber this_process, front_process; if (GetCurrentProcess(&this_process) != noErr) return; if (GetFrontProcess(&front_process) != noErr) return; Boolean matched = false; if (SameProcess(&this_process, &front_process, &matched) != noErr) return; if (matched) { SetFrontProcess(&g_saved_front_process); } } #pragma mark - static Boolean ChromePluginIsWindowHilited(WindowRef window) { // TODO(stuartmorgan): Always returning true (instead of the real answer, // which would be false) means that clicking works, but it's not correct // either. Ideally we need a way to find out if the delegate corresponds // to a browser window that is active. const WebPluginDelegateImpl* delegate = FakePluginWindowTracker::SharedInstance()->GetDelegateForFakeWindow( window); Boolean isHilited = delegate ? true : IsWindowHilited(window); return isHilited; } static CGRect CGRectForWindow(WindowRef window) { CGRect bounds = { { 0, 0 }, { 0, 0 } }; HIWindowGetBounds(window, kWindowContentRgn, kHICoordSpace72DPIGlobal, &bounds); return bounds; } static void ChromePluginSelectWindow(WindowRef window) { SwitchToPluginProcess(); SelectWindow(window); webkit_glue::NotifyBrowserOfPluginSelectWindow(HIWindowGetCGWindowID(window), CGRectForWindow(window)); } static void ChromePluginShowWindow(WindowRef window) { SwitchToPluginProcess(); ShowWindow(window); webkit_glue::NotifyBrowserOfPluginShowWindow(HIWindowGetCGWindowID(window), CGRectForWindow(window)); } static void ChromePluginDisposeWindow(WindowRef window) { SwitchToSavedProcess(); webkit_glue::NotifyBrowserOfPluginDisposeWindow(HIWindowGetCGWindowID(window), CGRectForWindow(window)); DisposeWindow(window); } static void ChromePluginHideWindow(WindowRef window) { SwitchToSavedProcess(); webkit_glue::NotifyBrowserOfPluginHideWindow(HIWindowGetCGWindowID(window), CGRectForWindow(window)); HideWindow(window); } #pragma mark - struct interpose_substitution { const void* replacement; const void* original; }; #define INTERPOSE_FUNCTION(function) \ { reinterpret_cast(ChromePlugin##function), \ reinterpret_cast(function) } __attribute__((used)) static const interpose_substitution substitutions[] __attribute__((section("__DATA, __interpose"))) = { INTERPOSE_FUNCTION(IsWindowHilited), INTERPOSE_FUNCTION(SelectWindow), INTERPOSE_FUNCTION(ShowWindow), INTERPOSE_FUNCTION(DisposeWindow), INTERPOSE_FUNCTION(HideWindow), };