2

I'm trying to add support for exposing NSTouchBar buttons via a plugin to an application that I cannot otherwise modify. The plugin, a shared library, is loaded at runtime after the main window has been created. I've created an AppDelegate as follows:

@interface AppDelegate : NSResponder <NSTouchBarDelegate>
@end

With an @implmentation that implements the makeTouchBar and touchBar functions:

- (NSTouchBar *) makeTouchBar
- (nullable NSTouchBarItem *) touchBar:(NSTouchBar *)touchBar
                       makeItemForIdentifier: (NSTouchBarItemIdentifier)identifier

I finally try to inject it into the application, I have the following in the onload function that's called in the dynamic library when it's loaded into the application.

NSWindow *w = [NSApp mainWindow];

AppDelegate *a = [[AppDelegate alloc] init];
a.nextResponder = w.nextResponder;
w.nextResponder = a;

// Re-setting FirstResponder will trigger AppDelegate::makeTouchBar
// that was attached above.
NSResponder *n = w.firstResponder;
[w makeFirstResponder: nil];
[w makeFirstResponder: n];

however... AppDelegate::touchBar will never be called, thus the touchbar will never be populated with my test buttons.

If I create a new project in Xcode, and use the exact same AppDelegate implementation (copy-paste of the same @interface and @implementation), I get functional buttons that are both shown and responds to press events, so it's the injection part that seems to be broken. (In Xcode everything is hooked up via MainMenu.xib I guess)

Update: The main problem was that the application was compiled in a way that prevented TouchBar to work. Perhaps built on an older version of Mac OS.

dsvensson
  • 1,401
  • 12
  • 20

1 Answers1

2

If this object really should act as the application delegate (as the name suggests) -- rather than inserting it in the main window's responder chain, it would be better to actually set it as the NSApp's delegate. The set delegate's touchBar is also used when building the touch bar (see NSTouchBar Discovery and the Responder Chain).

If that doesn't work for your plugin (maybe the application already has a specific app delegate it needs), you could insert it into NSApp's responder chain instead of the mainWindow's.

Both of these also have the benefit of making the touch bar be associated at the application level rather than window. So if the main/key window changes, the provided touch bar will always be used.

Taylor
  • 3,183
  • 17
  • 18
  • Nothing broke when setting NSApp.delegate, the application works just like before. touchBar of my AppDelegate is still not called though. I tried setting NSApp.delegate=myappdelegate, myappdelegate.touchBar=nil, NSApp.touchBar=nil, myappdelegate.nextResponder=NSApp.nextResponder, NSApp.nextResponder=myappdelegate. The application in question is Emacs, and I'm trying to add a touchbar via a native elisp module loaded when I evaluate (module-load "/path/to/module"). – dsvensson Jan 05 '17 at 14:42
  • myappdelegate.touchBar is still created by makeTouchBar. I tried assigning myappdelegate.touchBar to NSApp.touchBar, but still no touchbar. – dsvensson Jan 05 '17 at 14:52
  • Could it be that the application I'm trying to inject the touchbar into, Emacs in this case, is compiled with some option that disables touchbar support? I'm using latest from https://emacsformacosx.com/ – dsvensson Jan 05 '17 at 14:58
  • Ah yeah. It looks like that app is not able to display touch bar content for some reason... You can see this by showing the standard open panel from within it: the panel has "Cancel" and "Open" buttons in the touch bar in other apps, but is missing them in emacs – Taylor Jan 05 '17 at 23:32
  • Turns out emacs was compiled in such a way that it wasn't possible to enable TouchBar. When building it on my laptop, it worked. I'm setting mainWindow.delegate = mydelegate, and mainWindow.touchBar=nil to trigger an update of the touchbar. – dsvensson Jan 08 '17 at 14:19
  • @dsvensson would you mind share your working code? I'm trying to do something similar and having trouble. – Gaelan Dec 16 '17 at 19:29