summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-04 17:27:08 +0000
committerstuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-04 17:27:08 +0000
commita96ec6a0045c0b1926c9e4c553b67e42a43a430b (patch)
tree017387bccd62964c28a0892b78614a0f1820282e
parent39a2e833dc1983b78e9cf78df3d8f3cda3f150c9 (diff)
downloadchromium_src-a96ec6a0045c0b1926c9e4c553b67e42a43a430b.zip
chromium_src-a96ec6a0045c0b1926c9e4c553b67e42a43a430b.tar.gz
chromium_src-a96ec6a0045c0b1926c9e4c553b67e42a43a430b.tar.bz2
Don't allow the browser to stay above a modal plugin window (Mac)
There's a flicker of the modal window being hidden then coming forward again, and the menus still work, so we'll most likely have fake the modality more aggressively at some point. This gets us the basic infrastructure though, and solves the severe usability problem. BUG=20798 TEST=Open a modal plugin window (e.g., Gmail upload). Switch to another app, then back to Chrome; the plugin window should come to the front. Review URL: http://codereview.chromium.org/355021 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@30965 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/mac_util.h3
-rw-r--r--base/mac_util.mm10
-rw-r--r--chrome/browser/app_controller_mac.mm9
-rw-r--r--chrome/browser/plugin_carbon_interpose_mac.cc20
-rw-r--r--chrome/browser/plugin_process_host.h14
-rw-r--r--chrome/browser/plugin_process_host_mac.cc23
-rw-r--r--chrome/browser/plugin_service.cc26
-rw-r--r--chrome/common/notification_type.h4
-rw-r--r--chrome/common/plugin_messages_internal.h10
-rw-r--r--chrome/plugin/plugin_thread.cc12
-rw-r--r--chrome/plugin/plugin_thread.h3
11 files changed, 118 insertions, 16 deletions
diff --git a/base/mac_util.h b/base/mac_util.h
index 3c99b2a..093ae63 100644
--- a/base/mac_util.h
+++ b/base/mac_util.h
@@ -75,6 +75,9 @@ void RequestFullScreen();
// this will show the menu bar. Must be called on main thread.
void ReleaseFullScreen();
+// Activates the process with the given PID.
+void ActivateProcess(pid_t);
+
// Pulls a snapshot of the entire browser into png_representation.
void GrabWindowSnapshot(NSWindow* window,
std::vector<unsigned char>* png_representation);
diff --git a/base/mac_util.mm b/base/mac_util.mm
index 3ffab82..de07c88 100644
--- a/base/mac_util.mm
+++ b/base/mac_util.mm
@@ -178,4 +178,14 @@ void GrabWindowSnapshot(NSWindow* window,
}
}
+void ActivateProcess(pid_t pid) {
+ ProcessSerialNumber process;
+ OSStatus status = GetProcessForPID(pid, &process);
+ if (status == noErr) {
+ SetFrontProcess(&process);
+ } else {
+ LOG(WARNING) << "Unable to get process for pid " << pid;
+ }
+}
+
} // namespace mac_util
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index c173740..50973f6 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -34,6 +34,7 @@
#include "chrome/browser/sessions/tab_restore_service.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
#include "chrome/browser/profile_manager.h"
@@ -333,6 +334,14 @@ static bool g_is_opening_new_window = false;
[self openPendingURLs];
}
+// This is called after profiles have been loaded and preferences registered.
+// It is safe to access the default profile here.
+- (void)applicationDidBecomeActive:(NSNotification*)notify {
+ NotificationService::current()->Notify(NotificationType::APP_ACTIVATED,
+ NotificationService::AllSources(),
+ NotificationService::NoDetails());
+}
+
// Helper function for populating and displaying the in progress downloads at
// exit alert panel.
- (BOOL)userWillWaitForInProgressDownloads:(int)downloadCount {
diff --git a/chrome/browser/plugin_carbon_interpose_mac.cc b/chrome/browser/plugin_carbon_interpose_mac.cc
index e9a4997..1957f47 100644
--- a/chrome/browser/plugin_carbon_interpose_mac.cc
+++ b/chrome/browser/plugin_carbon_interpose_mac.cc
@@ -9,8 +9,10 @@
namespace webkit_glue {
-void NotifyBrowserOfPluginSelectWindow(uint32 window_id, CGRect bounds);
-void NotifyBrowserOfPluginShowWindow(uint32 window_id, CGRect bounds);
+void NotifyBrowserOfPluginSelectWindow(uint32 window_id, CGRect bounds,
+ bool modal);
+void NotifyBrowserOfPluginShowWindow(uint32 window_id, CGRect bounds,
+ bool modal);
void NotifyBrowserOfPluginHideWindow(uint32 window_id, CGRect bounds);
void NotifyBrowserOfPluginDisposeWindow(uint32 window_id, CGRect bounds);
@@ -75,6 +77,14 @@ static void MaybeReactivateSavedProcess() {
SwitchToSavedProcess();
}
+// Returns true if the given window is modal.
+static bool IsModalWindow(WindowRef window) {
+ WindowModality modality = kWindowModalityNone;
+ WindowRef modal_target = NULL;
+ OSStatus status = GetWindowModality(window, &modality, &modal_target);
+ return (status == noErr) && (modality != kWindowModalityNone);
+}
+
#pragma mark -
static Boolean ChromePluginIsWindowHilited(WindowRef window) {
@@ -100,14 +110,16 @@ static void ChromePluginSelectWindow(WindowRef window) {
SwitchToPluginProcess();
SelectWindow(window);
webkit_glue::NotifyBrowserOfPluginSelectWindow(HIWindowGetCGWindowID(window),
- CGRectForWindow(window));
+ CGRectForWindow(window),
+ IsModalWindow(window));
}
static void ChromePluginShowWindow(WindowRef window) {
SwitchToPluginProcess();
ShowWindow(window);
webkit_glue::NotifyBrowserOfPluginShowWindow(HIWindowGetCGWindowID(window),
- CGRectForWindow(window));
+ CGRectForWindow(window),
+ IsModalWindow(window));
}
static void ChromePluginDisposeWindow(WindowRef window) {
diff --git a/chrome/browser/plugin_process_host.h b/chrome/browser/plugin_process_host.h
index 3ce66b2..2717e0c 100644
--- a/chrome/browser/plugin_process_host.h
+++ b/chrome/browser/plugin_process_host.h
@@ -72,6 +72,12 @@ class PluginProcessHost : public ChildProcessHost,
void OnModalDialogResponse(const std::string& json_retval,
IPC::Message* sync_result);
+#if defined(OS_MACOSX)
+ // This function is called on the IO thread when the browser becomes the
+ // active application.
+ void OnAppActivation();
+#endif
+
const WebPluginInfo& info() const { return info_; }
#if defined(OS_WIN)
@@ -113,8 +119,10 @@ class PluginProcessHost : public ChildProcessHost,
#endif
#if defined(OS_MACOSX)
- void OnPluginSelectWindow(uint32 window_id, gfx::Rect window_rect);
- void OnPluginShowWindow(uint32 window_id, gfx::Rect window_rect);
+ void OnPluginSelectWindow(uint32 window_id, gfx::Rect window_rect,
+ bool modal);
+ void OnPluginShowWindow(uint32 window_id, gfx::Rect window_rect,
+ bool modal);
void OnPluginHideWindow(uint32 window_id, gfx::Rect window_rect);
void OnPluginDisposeWindow(uint32 window_id, gfx::Rect window_rect);
#endif
@@ -155,6 +163,8 @@ class PluginProcessHost : public ChildProcessHost,
std::set<uint32> plugin_visible_windows_set_;
// Tracks full screen windows currently visible
std::set<uint32> plugin_fullscreen_windows_set_;
+ // Tracks modal windows currently visible
+ std::set<uint32> plugin_modal_windows_set_;
#endif
DISALLOW_COPY_AND_ASSIGN(PluginProcessHost);
diff --git a/chrome/browser/plugin_process_host_mac.cc b/chrome/browser/plugin_process_host_mac.cc
index 6e6bb18..f003a4c 100644
--- a/chrome/browser/plugin_process_host_mac.cc
+++ b/chrome/browser/plugin_process_host_mac.cc
@@ -14,13 +14,19 @@
#include "chrome/browser/plugin_process_host.h"
void PluginProcessHost::OnPluginSelectWindow(uint32 window_id,
- gfx::Rect window_rect) {
+ gfx::Rect window_rect,
+ bool modal) {
plugin_visible_windows_set_.insert(window_id);
+ if (modal)
+ plugin_modal_windows_set_.insert(window_id);
}
void PluginProcessHost::OnPluginShowWindow(uint32 window_id,
- gfx::Rect window_rect) {
+ gfx::Rect window_rect,
+ bool modal) {
plugin_visible_windows_set_.insert(window_id);
+ if (modal)
+ plugin_modal_windows_set_.insert(window_id);
CGRect window_bounds = {
{ window_rect.x(), window_rect.y() },
{ window_rect.width(), window_rect.height() }
@@ -39,6 +45,7 @@ void PluginProcessHost::OnPluginShowWindow(uint32 window_id,
void PluginProcessHost::OnPluginHideWindow(uint32 window_id,
gfx::Rect window_rect) {
plugin_visible_windows_set_.erase(window_id);
+ plugin_modal_windows_set_.erase(window_id);
if (plugin_fullscreen_windows_set_.find(window_id) !=
plugin_fullscreen_windows_set_.end()) {
plugin_fullscreen_windows_set_.erase(window_id);
@@ -52,3 +59,15 @@ void PluginProcessHost::OnPluginDisposeWindow(uint32 window_id,
gfx::Rect window_rect) {
OnPluginHideWindow(window_id, window_rect);
}
+
+void PluginProcessHost::OnAppActivation() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+
+ // If our plugin process has any modal windows up, we need to bring it forward
+ // so that they act more like an in-process modal window would.
+ if (!plugin_modal_windows_set_.empty()) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableFunction(mac_util::ActivateProcess, handle()));
+ }
+}
diff --git a/chrome/browser/plugin_service.cc b/chrome/browser/plugin_service.cc
index 54577a7..f9153c6 100644
--- a/chrome/browser/plugin_service.cc
+++ b/chrome/browser/plugin_service.cc
@@ -29,6 +29,18 @@
#include "webkit/glue/plugins/plugin_constants_win.h"
#include "webkit/glue/plugins/plugin_list.h"
+#if defined(OS_MACOSX)
+static void NotifyPluginsOfActivation() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+
+ for (ChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS);
+ !iter.Done(); ++iter) {
+ PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
+ plugin->OnAppActivation();
+ }
+}
+#endif
+
// static
PluginService* PluginService::GetInstance() {
return Singleton<PluginService>::get();
@@ -72,6 +84,12 @@ PluginService::PluginService()
NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
NotificationService::AllSources());
+#if defined(OS_MACOSX)
+ // We need to know when the browser comes forward so we can bring modal plugin
+ // windows forward too.
+ registrar_.Add(this, NotificationType::APP_ACTIVATED,
+ NotificationService::AllSources());
+#endif
}
PluginService::~PluginService() {
@@ -243,6 +261,14 @@ void PluginService::Observe(NotificationType type,
break;
}
+#if defined(OS_MACOSX)
+ case NotificationType::APP_ACTIVATED: {
+ ChromeThread::PostTask(ChromeThread::IO, FROM_HERE,
+ NewRunnableFunction(&NotifyPluginsOfActivation));
+ break;
+ }
+#endif
+
default:
DCHECK(false);
}
diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h
index 1ea5923..db22312 100644
--- a/chrome/common/notification_type.h
+++ b/chrome/common/notification_type.h
@@ -205,6 +205,10 @@ class NotificationType {
// details are passed.
ALL_APPWINDOWS_CLOSED,
+ // This message is sent when the application is made active (Mac OS X only
+ // at present). No source or details are passed.
+ APP_ACTIVATED,
+
// Indicates that a top window has been closed. The source is the HWND
// that was closed, no details are expected.
WINDOW_CLOSED,
diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h
index cd44d21..f9a5bbf 100644
--- a/chrome/common/plugin_messages_internal.h
+++ b/chrome/common/plugin_messages_internal.h
@@ -131,14 +131,16 @@ IPC_BEGIN_MESSAGES(PluginProcessHost)
// Notifies the browser that the plugin has selected a window (i.e., brought
// it to the front and wants it to have keyboard focus).
- IPC_MESSAGE_CONTROL2(PluginProcessHostMsg_PluginSelectWindow,
+ IPC_MESSAGE_CONTROL3(PluginProcessHostMsg_PluginSelectWindow,
uint32 /* window ID */,
- gfx::Rect /* window rect */)
+ gfx::Rect /* window rect */,
+ bool /* modal */)
// Notifies the browser that the plugin has shown a window.
- IPC_MESSAGE_CONTROL2(PluginProcessHostMsg_PluginShowWindow,
+ IPC_MESSAGE_CONTROL3(PluginProcessHostMsg_PluginShowWindow,
uint32 /* window ID */,
- gfx::Rect /* window rect */)
+ gfx::Rect /* window rect */,
+ bool /* modal */)
// Notifies the browser that the plugin has hidden a window.
IPC_MESSAGE_CONTROL2(PluginProcessHostMsg_PluginHideWindow,
diff --git a/chrome/plugin/plugin_thread.cc b/chrome/plugin/plugin_thread.cc
index 5969089..85caf16 100644
--- a/chrome/plugin/plugin_thread.cc
+++ b/chrome/plugin/plugin_thread.cc
@@ -166,22 +166,26 @@ bool GetPluginFinderURL(std::string* plugin_finder_url) {
#if defined(OS_MACOSX)
__attribute__((visibility("default")))
-void NotifyBrowserOfPluginSelectWindow(uint32 window_id, CGRect bounds) {
+void NotifyBrowserOfPluginSelectWindow(uint32 window_id, CGRect bounds,
+ bool modal) {
PluginThread* plugin_thread = PluginThread::current();
if (plugin_thread) {
gfx::Rect window_bounds(bounds);
plugin_thread->Send(
- new PluginProcessHostMsg_PluginSelectWindow(window_id, window_bounds));
+ new PluginProcessHostMsg_PluginSelectWindow(window_id, window_bounds,
+ modal));
}
}
__attribute__((visibility("default")))
-void NotifyBrowserOfPluginShowWindow(uint32 window_id, CGRect bounds) {
+void NotifyBrowserOfPluginShowWindow(uint32 window_id, CGRect bounds,
+ bool modal) {
PluginThread* plugin_thread = PluginThread::current();
if (plugin_thread) {
gfx::Rect window_bounds(bounds);
plugin_thread->Send(
- new PluginProcessHostMsg_PluginShowWindow(window_id, window_bounds));
+ new PluginProcessHostMsg_PluginShowWindow(window_id, window_bounds,
+ modal));
}
}
diff --git a/chrome/plugin/plugin_thread.h b/chrome/plugin/plugin_thread.h
index c6f05ba..435d8c3 100644
--- a/chrome/plugin/plugin_thread.h
+++ b/chrome/plugin/plugin_thread.h
@@ -35,6 +35,9 @@ class PluginThread : public ChildThread {
// Callback for when a channel has been created.
void OnCreateChannel(int renderer_id, bool off_the_record);
void OnPluginMessage(const std::vector<uint8> &data);
+#if defined(OS_MACOSX)
+ void OnAppActivated();
+#endif
// The plugin module which is preloaded in Init
base::NativeLibrary preloaded_plugin_module_;