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

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: Created 3 years, 10 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 #import <objc/runtime.h>
7
8 // https://crbug.com/692408
Avi (use Gerrit) 2017/02/28 16:24:24 Radar # too?
Sidney San Martín 2017/03/01 00:50:20 Done.
9 //
10 // Back as far as macOS 10.9, and up to at least macOS 10.12.3, an AppKit bug
11 // can leave window A in what looks like a key state while window B is actually
12 // key. Key presses go to window B even after you click on window A.
13 //
14 // To trigger the bug, open a menu which has custom views (e.g. the wrench
15 // menu) and then, while the menu is open, click the titlebar of a different
16 // window to bring it to the front. Then, click the first window to bring it
17 // *back* to the front and try to type. Input will go to the other window.
18 //
19 // ## Cause
20 // When a menu has any custom views, AppKit uses a different window
21 // class (NSCarbonMenuWindow) to represent it than it does otherwise
22 // (NSLimitedMenuViewWindow). NSCarbonMenuWindow overrides -[NSWindow
23 // makeKeyWindow] to make itself the key window without telling the old key
24 // window that it's lost key status (so that its appearance doesn't change). It
25 // saves the old key window in an instance variable.
26 //
27 // When the menu closes, it doesn't just make the saved key window key again.
28 // Instead, it picks the frontmost window that can become key. When the
29 // frontmost window is different — and clicking a window's titlebar brings it
30 // to the front — it never sends -[NSWindow resignKeyWindow] to the old key
31 // window, so it never loses key appearance and doesn't ask NSApplication to
32 // make it key when you click on it (since it thinks it's already key).
33 //
34 // ## Solution
35 // This category replaces a method on NSCarbonMenuWindow to send
36 // -resignKeyWindow to the saved window if the AppKit implementation made a
37 // different window key. It degrades to a noop if NSCarbonMenuWindow, its
38 // _rememberedKeyWindow ivar, or its
39 // _restorePreviousKeyWindowFromSavedProperties method no longer exists.
40
41 WEAK_IMPORT_ATTRIBUTE
tapted 2017/02/28 23:24:13 Is this needed? I don't see it elsewhere in Chrome
Sidney San Martín 2017/03/01 00:50:20 Added a comment — or did you just mean a comment h
42 @interface NSCarbonMenuWindow : NSWindow
43 - (void)_restorePreviousKeyWindowFromSavedProperties;
44 @end
45
46 static void (*_restorePreviousKeyWindowFromSavedProperties)(NSCarbonMenuWindow*,
47 SEL);
48
49 static void _restorePreviousKeyWindowFromSavedProperties_patch(
50 NSCarbonMenuWindow* self,
51 SEL _cmd) {
52 NSWindow* rememberedKeyWindow = nil;
53 object_getInstanceVariable(self, "_rememberedKeyWindow",
tapted 2017/03/01 02:12:20 What happens if `_rememberedKeyWindow` gets rename
Sidney San Martín 2017/03/01 03:08:35 In that case, object_getInstanceVariable() returns
tapted 2017/03/01 07:56:02 The return value of object_getInstanceVariable isn
Sidney San Martín 2017/03/01 17:42:59 OK, done.
54 (void**)&rememberedKeyWindow);
55 _restorePreviousKeyWindowFromSavedProperties(self, _cmd);
56 if ([NSApp keyWindow] != rememberedKeyWindow) {
tapted 2017/02/28 23:24:13 What happens when switching applications? I think
Sidney San Martín 2017/03/01 00:50:20 Switching applications is OK. This all happens in
57 [rememberedKeyWindow resignKeyWindow];
tapted 2017/02/28 23:24:13 Is the menu still open at this point? Can we do so
Sidney San Martín 2017/03/01 00:50:20 Every NSCarbonMenuWindow has this bug, not just th
tapted 2017/03/01 02:12:20 I was going to ask "does Chrome have any other men
Sidney San Martín 2017/03/01 03:08:35 That's awesome! I just updated the radar with repr
58 }
59 }
60
61 @implementation NSCarbonMenuWindow (KeyWindowPatch)
62
63 + (void)load {
64 _restorePreviousKeyWindowFromSavedProperties =
tapted 2017/02/28 23:24:13 This needs to safely bail out (and DCHECK) if Appl
Sidney San Martín 2017/03/01 00:50:20 It should be safe in these cases; let me know if i
tapted 2017/03/01 02:12:20 Is that how WEAK_IMPORT_ATTRIBUTE works? Wouldn't
Sidney San Martín 2017/03/01 03:08:35 I'm as sure as I can be that this attribute affect
tapted 2017/03/01 07:56:02 Maybe we can make a little test project? My readin
tapted 2017/03/01 08:20:35 Is the API documented to do nothing? Is it really
Sidney San Martín 2017/03/01 17:42:59 It's not mentioned for this function, but many run
Sidney San Martín 2017/03/01 17:42:59 You're right that it'll fail at compile time if th
tapted 2017/03/01 22:56:46 I guess this thread falls under "general advice" (
tapted 2017/03/01 22:56:46 Does + (void)load behave different? I suspect it d
65 (void (*)(NSCarbonMenuWindow*, SEL))method_setImplementation(
66 class_getInstanceMethod(
67 [self class],
68 @selector(_restorePreviousKeyWindowFromSavedProperties)),
69 (IMP)_restorePreviousKeyWindowFromSavedProperties_patch);
70 }
71
72 @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