Index: chrome/browser/chrome_application_mac.mm |
diff --git a/chrome/browser/chrome_application_mac.mm b/chrome/browser/chrome_application_mac.mm |
index 94c975bd64b661b12a3641a2dea6239d59058b82..9453bc0f32334fc287a73575b606ed9815eb1655 100644 |
--- a/chrome/browser/chrome_application_mac.mm |
+++ b/chrome/browser/chrome_application_mac.mm |
@@ -4,8 +4,9 @@ |
#import "chrome/browser/chrome_application_mac.h" |
-#import "base/histogram.h" |
-#import "base/logging.h" |
+#include "base/histogram.h" |
+#include "base/logging.h" |
+#include "base/message_loop.h" |
#import "base/scoped_nsobject.h" |
#import "base/sys_string_conversions.h" |
#import "chrome/app/breakpad_mac.h" |
@@ -13,6 +14,15 @@ |
#import "chrome/browser/cocoa/objc_method_swizzle.h" |
#import "chrome/browser/renderer_host/render_widget_host_view_mac.h" |
+// When C++ exceptions are disabled, the C++ library defines |try| and |
+// |catch| so as to allow exception-expecting C++ code to build properly when |
+// language support for exceptions is not present. These macros interfere |
+// with the use of |@try| and |@catch| in Objective-C files such as this one. |
+// Undefine these macros here, after everything has been #included, since |
+// there will be no C++ uses and only Objective-C uses from this point on. |
+#undef try |
+#undef catch |
+ |
// The implementation of NSExceptions break various assumptions in the |
// Chrome code. This category defines a replacement for |
// -initWithName:reason:userInfo: for purposes of forcing a break in |
@@ -244,18 +254,34 @@ BOOL SwizzleNSExceptionInit() { |
} |
- (void)sendEvent:(NSEvent*)event { |
- // The superclass's |sendEvent:| sends keyboard events to the menu and the key |
- // view loop before dispatching them to |keyDown:|. Since we want to send keys |
- // to the renderer before sending them to the menu, and we never want them to |
- // the kev view loop when the web is focussed, we change this behavior. |
- if ([[self keyWindow] |
- isKindOfClass:[ChromeEventProcessingWindow class]]) { |
- if ([static_cast<ChromeEventProcessingWindow*>([self keyWindow]) |
- shortcircuitEvent:event]) |
- return; |
+ // Messages from renderers and plug-ins can cause unfortunate |
+ // interactions with modal event loops (consider a control which |
+ // talks to a tab which is closed while you're click-dragging the |
+ // mouse). This turns off handling of nested events for the |
+ // duration of -sendEvent: handling, then restores the prior. Any |
+ // event-handling code which needs nested events to work in a modal |
+ // loop should explicitly turn handling back on using similar code. |
+ bool wasEnabled = MessageLoop::current()->NestableTasksAllowed(); |
+ MessageLoop::current()->SetNestableTasksAllowed(false); |
+ |
+ @try { |
+ // The superclass's |sendEvent:| sends keyboard events to the menu |
+ // and the key view loop before dispatching them to |
+ // |keyDown:|. Since we want to send keys to the renderer before |
+ // sending them to the menu, and we never want them to go to the |
+ // key view loop when the web is focussed, we change this |
+ // behavior. |
+ ChromeEventProcessingWindow* keyWindow = |
+ static_cast<ChromeEventProcessingWindow*>([self keyWindow]); |
+ if (![keyWindow isKindOfClass:[ChromeEventProcessingWindow class]] || |
+ ![keyWindow shortcircuitEvent:event]) { |
+ [super sendEvent:event]; |
+ } |
+ } @finally { |
+ // ALWAYS set things back the way we found them, no matter what. |
+ // Leaving nested tasks turned off breaks about a million things. |
+ MessageLoop::current()->SetNestableTasksAllowed(wasEnabled); |
} |
- |
- [super sendEvent:event]; |
} |
// NSExceptions which are caught by the event loop are logged here. |