diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 1107a628a9e4..a75df27fce61 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -283,7 +283,7 @@ void Window::OnExecuteWindowsCommand(const std::string& command_name) { } void Window::OnTouchBarItemResult(const std::string& item_type, const std::string& item_id) { - Emit("_touch-bar-interaction", item_type, item_id); + Emit("-touch-bar-interaction", item_type, item_id); } #if defined(OS_WIN) @@ -844,8 +844,12 @@ void Window::SetVibrancy(mate::Arguments* args) { window_->SetVibrancy(type); } -void Window::InitTouchBar() { - window_->InitTouchBar(); +void Window::DestroyTouchBar() { + window_->DestroyTouchBar(); +} + +void Window::SetTouchBar(mate::Arguments* args) { + window_->SetTouchBar(args); } int32_t Window::ID() const { @@ -968,7 +972,8 @@ void Window::BuildPrototype(v8::Isolate* isolate, .SetMethod("setAutoHideCursor", &Window::SetAutoHideCursor) #endif .SetMethod("setVibrancy", &Window::SetVibrancy) - .SetMethod("initTouchBar", &Window::InitTouchBar) + .SetMethod("_destroyTouchBar", &Window::DestroyTouchBar) + .SetMethod("_setTouchBar", &Window::SetTouchBar) #if defined(OS_WIN) .SetMethod("hookWindowMessage", &Window::HookWindowMessage) .SetMethod("isWindowMessageHooked", &Window::IsWindowMessageHooked) diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index 3325c87fa9c8..54aa01d3886f 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -204,7 +204,8 @@ class Window : public mate::TrackableObject, void SetAutoHideCursor(bool auto_hide); void SetVibrancy(mate::Arguments* args); - void InitTouchBar(); + void DestroyTouchBar(); + void SetTouchBar(mate::Arguments* args); v8::Local WebContents(v8::Isolate* isolate); diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 2219a4d595d2..53068045ea77 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -33,6 +33,7 @@ #include "content/public/browser/render_widget_host_view.h" #include "content/public/common/content_switches.h" #include "ipc/ipc_message_macros.h" +#include "native_mate/constructor.h" #include "native_mate/dictionary.h" #include "third_party/skia/include/core/SkRegion.h" #include "ui/gfx/codec/png_codec.h" @@ -340,7 +341,10 @@ void NativeWindow::SetAutoHideCursor(bool auto_hide) { void NativeWindow::SetVibrancy(const std::string& filename) { } -void NativeWindow::InitTouchBar() { +void NativeWindow::DestroyTouchBar() { +} + +void NativeWindow::SetTouchBar(mate::Arguments* args) { } void NativeWindow::FocusOnWebView() { diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 3338396146c3..bd7584e0d103 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -23,6 +23,7 @@ #include "extensions/browser/app_window/size_constraints.h" #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia.h" +#include "native_mate/constructor.h" class SkRegion; @@ -170,7 +171,8 @@ class NativeWindow : public base::SupportsUserData, virtual void SetVibrancy(const std::string& type); // Touchbar API - virtual void InitTouchBar(); + virtual void DestroyTouchBar(); + virtual void SetTouchBar(mate::Arguments* args); // Webview APIs. virtual void FocusOnWebView(); diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index fec5eacb3a17..026f86e599c5 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -13,6 +13,7 @@ #include "atom/browser/native_window.h" #include "base/mac/scoped_nsobject.h" #include "content/public/browser/render_widget_host.h" +#include "native_mate/constructor.h" @class AtomNSWindow; @class AtomNSWindowDelegate; @@ -100,7 +101,9 @@ class NativeWindowMac : public NativeWindow, void SetAutoHideCursor(bool auto_hide) override; void SetVibrancy(const std::string& type) override; - void InitTouchBar() override; + void DestroyTouchBar() override; + void SetTouchBar(mate::Arguments* args) override; + std::vector GetTouchBarItems(); // content::RenderWidgetHost::InputEventObserver: void OnInputEvent(const blink::WebInputEvent& event) override; @@ -155,6 +158,8 @@ class NativeWindowMac : public NativeWindow, base::scoped_nsobject window_; base::scoped_nsobject window_delegate_; + std::vector touch_bar_items_; + // Event monitor for scroll wheel event. id wheel_event_monitor_; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 029cf6002da4..87a27cae07a0 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -352,6 +352,8 @@ bool ScopedDisableResize::disable_resize_ = false; - (void)setEnableLargerThanScreen:(bool)enable; - (void)enableWindowButtonsOffset; - (void)reloadTouchBar; +- (void)resetTouchBar; +- (NSTouchBar*)touchBarFromMutatableArray:(NSMutableArray*)items; @end @interface AtomNSWindow () @@ -359,6 +361,7 @@ bool ScopedDisableResize::disable_resize_ = false; @implementation AtomNSWindow NSMutableArray* bar_items_ = [[NSMutableArray alloc] init]; + std::map button_labels; - (void)setShell:(atom::NativeWindowMac*)shell { shell_ = shell; @@ -368,24 +371,52 @@ bool ScopedDisableResize::disable_resize_ = false; enable_larger_than_screen_ = enable; } +- (void)resetTouchBar { + bar_items_ = [[NSMutableArray alloc] init]; + self.touchBar = nil; + NSLog(@"Destroying TouchBar"); +} + - (void)reloadTouchBar { bar_items_ = [[NSMutableArray alloc] init]; - [bar_items_ addObject:@"com.electron.tb.button.1"]; - [bar_items_ addObject:@"com.electron.tb.button.2"]; + std::vector items = shell_->GetTouchBarItems(); + std::map new_button_labels; + button_labels = new_button_labels; + + NSLog(@"reload"); + for (mate::Dictionary &item : items ) { + NSLog(@"reload iter"); + std::string type; + std::string item_id; + if (item.Get("type", &type) && item.Get("id", &item_id)) { + NSLog(@"type: %@", [NSString stringWithUTF8String:type.c_str()]); + NSLog(@"id: %@", [NSString stringWithUTF8String:item_id.c_str()]); + if (type == "button") { + std::string label; + if (item.Get("label", &label)) { + [bar_items_ addObject:[NSString stringWithFormat:@"%@%@", ButtonIdentifier, [NSString stringWithUTF8String:item_id.c_str()]]]; + button_labels.insert(make_pair(item_id, label)); + } + } + } + } + // [bar_items_ addObject:@"com.electron.tb.button.1"]; + // [bar_items_ addObject:@"com.electron.tb.button.2"]; [bar_items_ addObject:NSTouchBarItemIdentifierOtherItemsProxy]; - NSLog(@"Reloading Touch Bar --> '%@'", bar_items_[1]); + // NSLog(@"Reloading Touch Bar --> '%@'", bar_items_[1]); self.touchBar = nil; } - (NSTouchBar *)makeTouchBar { NSLog(@"Making Touch Bar"); + return [self touchBarFromMutatableArray:bar_items_]; +} + +- (NSTouchBar *)touchBarFromMutatableArray:(NSMutableArray*)items { NSTouchBar* bar = [[NSTouchBar alloc] init]; bar.delegate = self; - // Set the default ordering of items. - - // NSLog(@"%@", bar_items_[1]); - bar.defaultItemIdentifiers = [bar_items_ copy]; + bar.defaultItemIdentifiers = [items copy]; return bar; } @@ -412,7 +443,7 @@ static NSTouchBarItemIdentifier LabelIdentifier = @"com.electron.tb.label."; if ([identifier hasPrefix:ButtonIdentifier]) { NSString *idCopy = [identifier copy]; idCopy = [identifier substringFromIndex:[ButtonIdentifier length]]; - NSButton *theButton = [NSButton buttonWithTitle:@"Electron Button" target:self action:@selector(buttonAction:)]; + NSButton *theButton = [NSButton buttonWithTitle:[NSString stringWithUTF8String:button_labels[std::string([idCopy UTF8String])].c_str()] target:self action:@selector(buttonAction:)]; theButton.tag = [idCopy floatValue]; NSCustomTouchBarItem *customItem = [[NSCustomTouchBarItem alloc] initWithIdentifier:identifier]; @@ -1420,8 +1451,22 @@ void NativeWindowMac::SetVibrancy(const std::string& type) { [effect_view setMaterial:vibrancyType]; } -void NativeWindowMac::InitTouchBar() { - [window_ reloadTouchBar]; +void NativeWindowMac::DestroyTouchBar() { + [window_ resetTouchBar]; +} + +void NativeWindowMac::SetTouchBar(mate::Arguments* args) { + std::vector items; + LOG(ERROR) << "FOO"; + if (args->GetNext(&items)) { + LOG(ERROR) << "BAR"; + touch_bar_items_ = items; + [window_ reloadTouchBar]; + } +} + +std::vector NativeWindowMac::GetTouchBarItems() { + return touch_bar_items_; } void NativeWindowMac::OnInputEvent(const blink::WebInputEvent& event) { diff --git a/default_app/default_app.js b/default_app/default_app.js index bfb97a9ab084..35e290b4e9d7 100644 --- a/default_app/default_app.js +++ b/default_app/default_app.js @@ -1,4 +1,4 @@ -const {app, BrowserWindow} = require('electron') +const {app, BrowserWindow,TouchBar} = require('electron') const path = require('path') let mainWindow = null @@ -24,5 +24,14 @@ exports.load = (appUrl) => { mainWindow = new BrowserWindow(options) mainWindow.loadURL(appUrl) mainWindow.focus() + + mainWindow.setTouchBar(new TouchBar([ + new (TouchBar.Button)({ + label: 'Hello World!', + click: () => { + console.log('Hello World Clicked') + } + }) + ])) }) } diff --git a/filenames.gypi b/filenames.gypi index 00297becef28..0e4ad206267c 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -30,6 +30,7 @@ 'lib/browser/api/session.js', 'lib/browser/api/screen.js', 'lib/browser/api/system-preferences.js', + 'lib/browser/api/touch-bar.js', 'lib/browser/api/tray.js', 'lib/browser/api/web-contents.js', 'lib/browser/chrome-extension.js', diff --git a/lib/browser/api/browser-window.js b/lib/browser/api/browser-window.js index 1aa34d45a0a9..fd72a4cf0f88 100644 --- a/lib/browser/api/browser-window.js +++ b/lib/browser/api/browser-window.js @@ -1,6 +1,6 @@ 'use strict' -const {ipcMain} = require('electron') +const {ipcMain,TouchBar} = require('electron') const {EventEmitter} = require('events') const {BrowserWindow} = process.atomBinding('window') const v8Util = process.atomBinding('v8_util') @@ -131,6 +131,11 @@ BrowserWindow.prototype._init = function () { return this.webContents.devToolsWebContents } }) + + // Proxy TouchBar events + this.on('-touch-bar-interaction', (event, item_type, id, ...args) => { + TouchBar._event(id, ...args) + }) } BrowserWindow.getFocusedWindow = () => { @@ -198,4 +203,15 @@ Object.assign(BrowserWindow.prototype, { } }) +// TouchBar API +BrowserWindow.prototype.setTouchBar = function (touchBar) { + if (touchBar === null || typeof touchBar === 'undefined') { + this._destroyTouchBar(); + } else if (Array.isArray(touchBar)) { + this._setTouchBar((new TouchBar(touchBar)).toJSON()); + } else { + this._setTouchBar(touchBar.toJSON()) + } +} + module.exports = BrowserWindow diff --git a/lib/browser/api/exports/electron.js b/lib/browser/api/exports/electron.js index 11698f1df557..3f4059521752 100644 --- a/lib/browser/api/exports/electron.js +++ b/lib/browser/api/exports/electron.js @@ -103,6 +103,12 @@ Object.defineProperties(exports, { return require('../system-preferences') } }, + TouchBar: { + enumerable: true, + get: function () { + return require('../touch-bar') + } + }, Tray: { enumerable: true, get: function () { diff --git a/lib/browser/api/touch-bar.js b/lib/browser/api/touch-bar.js new file mode 100644 index 000000000000..d8ce377bc86e --- /dev/null +++ b/lib/browser/api/touch-bar.js @@ -0,0 +1,89 @@ +const {EventEmitter} = require('events') +const {app} = require('electron') + +class TouchBar { + constructor (items) { + this.items = items; + if (!Array.isArray(items)) { + throw new Error('The items object provided has to be an array') + } + console.log(items) + items.forEach((item) => { + if (!item.id) { + throw new Error('Each item must be an instance of a TouchBarItem') + } + }) + } + + toJSON () { + return this.items.map((item) => item.toJSON ? item.toJSON() : item); + } +} + +let item_id_incrementor = 1 +const item_event_handlers = {} + +TouchBar._event = (id, ...args) => { + const id_parts = id.split('.') + const item_id = id_parts[id_parts.length - 1] + if (item_event_handlers[item_id]) item_event_handlers[item_id](...args) +} + +class TouchBarItem { + constructor (config) { + this.id = item_id_incrementor++ + const mConfig = Object.assign({}, config || {}) + Object.defineProperty(this, 'config', { + configurable: false, + enumerable: false, + get: () => mConfig + }) + this.config.id = `${this.config.id || this.id}`; + this.config.type = 'button'; + if (typeof this.config !== 'object' || this.config === null) { + throw new Error('Provided config must be a non-null object') + } + } + + toJSON () { + return this.config + } +} + +TouchBar.Button = class TouchBarButton extends TouchBarItem { + constructor (config) { + super(config) + this.config.type = 'button'; + const click = config.click + if (typeof click === 'function') { + item_event_handlers[`${this.id}`] = click + } + } +} + +TouchBar.ColorPicker = class TouchBarColorPicker extends TouchBarItem { + constructor (config) { + super(config) + this.config.type = 'colorpicker'; + const change = config.change + if (typeof change === 'function') { + item_event_handlers[`${this.id}`] = change + } + } +} + +TouchBar.Label = class TouchBarLabel extends TouchBarItem {} + +TouchBar.List = class TouchBarList extends TouchBarItem {} + +TouchBar.Slider = class TouchBarSlider extends TouchBarItem { + constructor (config) { + super(config) + const change = config.change + if (typeof change === 'function') { + item_event_handlers[this.id] = change + } + } +} + +module.exports = TouchBar;