Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #import <AppKit/AppKit.h> | |
| 6 | |
| 7 #import "base/logging.h" | |
|
tapted
2017/03/02 09:34:59
nit: include
Sidney San Martín
2017/03/02 18:40:08
Done.
| |
| 8 #import "base/mac/scoped_objc_class_swizzler.h" | |
| 9 | |
| 10 // https://crbug.com/692408 | |
| 11 // rdar://30572648 | |
| 12 // | |
| 13 // Back as far as macOS 10.9, and up to at least macOS 10.12.3, an AppKit bug | |
| 14 // can leave window A in what looks like a key state while window B is actually | |
| 15 // key. Key presses go to window B even after you click on window A. | |
| 16 // | |
| 17 // To trigger the bug, open a menu which has custom views (e.g. the Help menu) | |
| 18 // and then, while the menu is open, click the titlebar of a different window | |
| 19 // to bring it to the front. Then, click the first window to bring it *back* to | |
| 20 // the front and try to type. Input will go to the other window. | |
| 21 // | |
| 22 // ## Cause | |
| 23 // When a menu has any custom views, AppKit uses a different class | |
| 24 // (NSCarbonMenuWindow) to represent its window than it does otherwise | |
| 25 // (NSLimitedMenuViewWindow). NSCarbonMenuWindow overrides -[NSWindow | |
| 26 // makeKeyWindow] to make itself the key window without telling the old key | |
| 27 // window that it's lost key status (so that its appearance doesn't change). It | |
| 28 // saves the old key window in an instance variable. | |
| 29 // | |
| 30 // When the menu closes, it doesn't just make the saved key window key again. | |
| 31 // Instead, it picks the frontmost window that can become key. When the | |
| 32 // frontmost window is different (clicking a window's titlebar brings it to the | |
| 33 // front) it never sends -[NSWindow resignKeyWindow] to the old key window, so | |
| 34 // it never loses key appearance and doesn't ask NSApplication to make it key | |
| 35 // when you click on it (since it thinks it's already key). | |
| 36 // | |
| 37 // ## Workaround | |
| 38 // This file hooks a method on NSCarbonMenuWindow to send -resignKeyWindow to | |
| 39 // the saved window if a different window has become key. | |
| 40 // | |
| 41 // ## If it's an AppKit bug, why work around it? | |
| 42 // The app/wrench/hotdog menu uses custom views, which gives Chrome more | |
| 43 // exposure to this bug than many apps, and users have run into it in the wild. | |
| 44 | |
| 45 @interface NSCarbonMenuWindowPatcher : NSObject | |
| 46 - (void)_restorePreviousKeyWindowFromSavedProperties; | |
| 47 @end | |
| 48 | |
| 49 @implementation NSCarbonMenuWindowPatcher | |
| 50 | |
| 51 static IMP g_original__restorePreviousKeyWindowFromSavedProperties; | |
| 52 | |
| 53 + (void)load { | |
| 54 Class NSCarbonMenuWindowClass = NSClassFromString(@"NSCarbonMenuWindow"); | |
|
tapted
2017/03/02 09:34:59
nit: should start with lowercase (perhaps theNSCar
Sidney San Martín
2017/03/02 18:40:09
Done. I made 'ns' lowercase, which seems to match
| |
| 55 DCHECK(NSCarbonMenuWindowClass); | |
| 56 if (NSCarbonMenuWindowClass == nil) | |
| 57 return; | |
| 58 CR_DEFINE_STATIC_LOCAL( | |
| 59 base::mac::ScopedObjCClassSwizzler, swizzler, | |
| 60 (NSCarbonMenuWindowClass, [self class], | |
| 61 @selector(_restorePreviousKeyWindowFromSavedProperties))); | |
| 62 g_original__restorePreviousKeyWindowFromSavedProperties = | |
| 63 swizzler.GetOriginalImplementation(); | |
| 64 } | |
| 65 | |
| 66 - (void)_restorePreviousKeyWindowFromSavedProperties { | |
| 67 NSWindow* rememberedKeyWindow = nil; | |
| 68 Ivar ivar = object_getInstanceVariable(self, "_rememberedKeyWindow", | |
| 69 (void**)&rememberedKeyWindow); | |
|
tapted
2017/03/02 09:34:59
nit: static_cast<void**> ? We try to avoid c-style
Sidney San Martín
2017/03/02 18:40:08
Done.
| |
| 70 DCHECK(ivar); | |
| 71 g_original__restorePreviousKeyWindowFromSavedProperties(self, _cmd); | |
| 72 if ([NSApp keyWindow] != rememberedKeyWindow) { | |
| 73 [rememberedKeyWindow resignKeyWindow]; | |
| 74 } | |
| 75 } | |
| 76 | |
| 77 @end | |
| OLD | NEW |