Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(191)

Side by Side Diff: chrome/browser/mac/patch_nsmenu_key_window_bug.mm

Issue 2710763003: Work around an AppKit bug that can leave two windows in a key state.
Patch Set: Nits (#import->#include, variable naming, C++ cast) Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/BUILD.gn ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 #include "base/logging.h"
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
Robert Sesek 2017/03/06 20:57:38 This CL makes sense, but I'm a little concerned ab
Sidney San Martín 2017/03/06 21:38:49 The bug also affects AppKit-provided menus like th
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");
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(
69 self, "_rememberedKeyWindow",
70 reinterpret_cast<void**>(&rememberedKeyWindow));
71 DCHECK(ivar);
72 g_original__restorePreviousKeyWindowFromSavedProperties(self, _cmd);
73 if ([NSApp keyWindow] != rememberedKeyWindow) {
74 [rememberedKeyWindow resignKeyWindow];
75 }
76 }
77
78 @end
OLDNEW
« no previous file with comments | « chrome/browser/BUILD.gn ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698