mirror of
https://github.com/Eugeny/tabby.git
synced 2025-06-08 21:40:03 +00:00
macOS touchbar support
This commit is contained in:
parent
8f2d2cbe30
commit
5e07dd5442
@ -183,7 +183,6 @@ setupMenu = () => {
|
||||
{
|
||||
role: 'window',
|
||||
submenu: [
|
||||
{role: 'close'},
|
||||
{role: 'minimize'},
|
||||
{role: 'zoom'},
|
||||
{type: 'separator'},
|
||||
|
@ -11,6 +11,7 @@ import { DockingService } from '../services/docking.service'
|
||||
import { TabRecoveryService } from '../services/tabRecovery.service'
|
||||
import { ThemesService } from '../services/themes.service'
|
||||
import { UpdaterService, Update } from '../services/updater.service'
|
||||
import { TouchbarService } from '../services/touchbar.service'
|
||||
|
||||
import { SafeModeModalComponent } from './safeModeModal.component'
|
||||
import { AppService, IToolbarButton, ToolbarButtonProvider } from '../api'
|
||||
@ -62,6 +63,7 @@ export class AppRootComponent {
|
||||
private tabRecovery: TabRecoveryService,
|
||||
private hotkeys: HotkeysService,
|
||||
private updater: UpdaterService,
|
||||
private touchbar: TouchbarService,
|
||||
public hostApp: HostAppService,
|
||||
public config: ConfigService,
|
||||
public app: AppService,
|
||||
@ -121,6 +123,8 @@ export class AppRootComponent {
|
||||
this.updater.check().then(update => {
|
||||
this.appUpdate = update
|
||||
})
|
||||
|
||||
this.touchbar.update()
|
||||
}
|
||||
|
||||
onGlobalHotkey () {
|
||||
|
@ -5,6 +5,7 @@ export abstract class BaseTabComponent {
|
||||
private static lastTabID = 0
|
||||
id: number
|
||||
title: string
|
||||
titleChange$ = new Subject<string>()
|
||||
customTitle: string
|
||||
scrollable: boolean
|
||||
hasActivity = false
|
||||
@ -23,6 +24,13 @@ export abstract class BaseTabComponent {
|
||||
})
|
||||
}
|
||||
|
||||
setTitle (title: string) {
|
||||
this.title = title]
|
||||
if (!this.customTitle) {
|
||||
this.titleChange$.next(title)
|
||||
}
|
||||
}
|
||||
|
||||
displayActivity (): void {
|
||||
this.hasActivity = true
|
||||
}
|
||||
|
@ -69,6 +69,7 @@ export class TabHeaderComponent {
|
||||
let modal = this.ngbModal.open(RenameTabModalComponent)
|
||||
modal.componentInstance.value = this.tab.customTitle || this.tab.title
|
||||
modal.result.then(result => {
|
||||
this.tab.setTitle(result)
|
||||
this.tab.customTitle = result
|
||||
}).catch(() => null)
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import { HotkeysService, AppHotkeyProvider } from './services/hotkeys.service'
|
||||
import { DockingService } from './services/docking.service'
|
||||
import { TabRecoveryService } from './services/tabRecovery.service'
|
||||
import { ThemesService } from './services/themes.service'
|
||||
import { TouchbarService } from './services/touchbar.service'
|
||||
import { UpdaterService } from './services/updater.service'
|
||||
|
||||
import { AppRootComponent } from './components/appRoot.component'
|
||||
@ -44,6 +45,7 @@ const PROVIDERS = [
|
||||
LogService,
|
||||
TabRecoveryService,
|
||||
ThemesService,
|
||||
TouchbarService,
|
||||
UpdaterService,
|
||||
{ provide: HotkeyProvider, useClass: AppHotkeyProvider, multi: true },
|
||||
{ provide: Theme, useClass: StandardTheme, multi: true },
|
||||
|
@ -2,8 +2,8 @@ import { Subject, AsyncSubject } from 'rxjs'
|
||||
import { Injectable, ComponentFactoryResolver, Injector, Optional } from '@angular/core'
|
||||
import { DefaultTabProvider } from '../api/defaultTabProvider'
|
||||
import { BaseTabComponent } from '../components/baseTab.component'
|
||||
import { Logger, LogService } from '../services/log.service'
|
||||
import { ConfigService } from '../services/config.service'
|
||||
import { Logger, LogService } from './log.service'
|
||||
import { ConfigService } from './config.service'
|
||||
|
||||
export declare type TabComponentType = new (...args: any[]) => BaseTabComponent
|
||||
|
||||
@ -11,9 +11,12 @@ export declare type TabComponentType = new (...args: any[]) => BaseTabComponent
|
||||
export class AppService {
|
||||
tabs: BaseTabComponent[] = []
|
||||
activeTab: BaseTabComponent
|
||||
activeTabChange$ = new Subject<BaseTabComponent>()
|
||||
lastTabIndex = 0
|
||||
logger: Logger
|
||||
tabsChanged$ = new Subject<void>()
|
||||
tabOpened$ = new Subject<BaseTabComponent>()
|
||||
tabClosed$ = new Subject<BaseTabComponent>()
|
||||
ready$ = new AsyncSubject<void>()
|
||||
|
||||
constructor (
|
||||
@ -35,6 +38,7 @@ export class AppService {
|
||||
this.tabs.push(componentRef.instance)
|
||||
this.selectTab(componentRef.instance)
|
||||
this.tabsChanged$.next()
|
||||
this.tabOpened$.next(componentRef.instance)
|
||||
|
||||
return componentRef.instance
|
||||
}
|
||||
@ -59,6 +63,7 @@ export class AppService {
|
||||
this.activeTab.blurred$.next()
|
||||
}
|
||||
this.activeTab = tab
|
||||
this.activeTabChange$.next(tab)
|
||||
if (this.activeTab) {
|
||||
this.activeTab.focused$.next()
|
||||
}
|
||||
@ -107,6 +112,7 @@ export class AppService {
|
||||
this.selectTab(this.tabs[newIndex])
|
||||
}
|
||||
this.tabsChanged$.next()
|
||||
this.tabClosed$.next(tab)
|
||||
}
|
||||
|
||||
emitReady () {
|
||||
|
@ -10,6 +10,7 @@ export class ElectronService {
|
||||
globalShortcut: any
|
||||
screen: any
|
||||
remote: any
|
||||
TouchBar: typeof Electron.TouchBar
|
||||
private electron: any
|
||||
|
||||
constructor () {
|
||||
@ -22,6 +23,7 @@ export class ElectronService {
|
||||
this.clipboard = this.electron.clipboard
|
||||
this.ipcRenderer = this.electron.ipcRenderer
|
||||
this.globalShortcut = this.remote.globalShortcut
|
||||
this.TouchBar = this.remote.TouchBar
|
||||
}
|
||||
|
||||
remoteRequire (name: string): any {
|
||||
|
69
terminus-core/src/services/touchbar.service.ts
Normal file
69
terminus-core/src/services/touchbar.service.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { Injectable, Inject, NgZone } from '@angular/core'
|
||||
import { Subject, Subscription } from 'rxjs'
|
||||
import { AppService } from './app.service'
|
||||
import { ConfigService } from './config.service'
|
||||
import { ElectronService } from './electron.service'
|
||||
import { BaseTabComponent } from '../components/baseTab.component'
|
||||
import { IToolbarButton, ToolbarButtonProvider } from '../api'
|
||||
|
||||
@Injectable()
|
||||
export class TouchbarService {
|
||||
tabSelected$ = new Subject<number>()
|
||||
private titleSubscriptions = new Map<BaseTabComponent, Subscription>()
|
||||
private tabsSegmentedControl: Electron.TouchBarSegmentedControl
|
||||
private tabSegments: Electron.SegmentedControlSegment[] = []
|
||||
|
||||
constructor (
|
||||
private app: AppService,
|
||||
@Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
|
||||
private config: ConfigService,
|
||||
private electron: ElectronService,
|
||||
private zone: NgZone,
|
||||
) {
|
||||
app.tabsChanged$.subscribe(() => this.update())
|
||||
app.activeTabChange$.subscribe(() => this.update())
|
||||
app.tabOpened$.subscribe(tab => {
|
||||
let sub = tab.titleChange$.subscribe(title => {
|
||||
this.tabSegments[app.tabs.indexOf(tab)].label = title
|
||||
this.tabsSegmentedControl.segments = this.tabSegments
|
||||
})
|
||||
this.titleSubscriptions.set(tab, sub)
|
||||
})
|
||||
app.tabClosed$.subscribe(tab => {
|
||||
this.titleSubscriptions.get(tab).unsubscribe()
|
||||
this.titleSubscriptions.delete(tab)
|
||||
})
|
||||
}
|
||||
|
||||
update () {
|
||||
let buttons: IToolbarButton[] = []
|
||||
this.config.enabledServices(this.toolbarButtonProviders).forEach(provider => {
|
||||
buttons = buttons.concat(provider.provide())
|
||||
})
|
||||
buttons.sort((a, b) => (a.weight || 0) - (b.weight || 0))
|
||||
this.tabSegments = this.app.tabs.map(tab => ({
|
||||
label: tab.title,
|
||||
}))
|
||||
this.tabsSegmentedControl = new this.electron.TouchBar.TouchBarSegmentedControl({
|
||||
segments: this.tabSegments,
|
||||
selectedIndex: this.app.tabs.indexOf(this.app.activeTab),
|
||||
change: (selectedIndex) => this.zone.run(() => {
|
||||
this.app.selectTab(this.app.tabs[selectedIndex])
|
||||
})
|
||||
})
|
||||
let touchBar = new this.electron.TouchBar({
|
||||
items: [
|
||||
this.tabsSegmentedControl,
|
||||
new this.electron.TouchBar.TouchBarSpacer({size: 'flexible'}),
|
||||
new this.electron.TouchBar.TouchBarSpacer({size: 'small'}),
|
||||
...buttons.map(button => new this.electron.TouchBar.TouchBarButton({
|
||||
label: button.title,
|
||||
// backgroundColor: '#0022cc',
|
||||
click: () => this.zone.run(() => button.click()),
|
||||
}))
|
||||
]
|
||||
})
|
||||
this.electron.app.window.setTouchBar(touchBar)
|
||||
}
|
||||
|
||||
}
|
@ -28,7 +28,7 @@ export class SettingsTabComponent extends BaseTabComponent {
|
||||
) {
|
||||
super()
|
||||
this.hotkeyDescriptions = config.enabledServices(hotkeyProviders).map(x => x.hotkeys).reduce((a, b) => a.concat(b))
|
||||
this.title = 'Settings'
|
||||
this.setTitle('Settings')
|
||||
this.scrollable = true
|
||||
this.screens = this.docking.getScreens()
|
||||
this.settingsProviders = config.enabledServices(this.settingsProviders)
|
||||
|
@ -18,17 +18,14 @@ export class ButtonProvider extends ToolbarButtonProvider {
|
||||
}
|
||||
|
||||
activate () {
|
||||
let modal = this.ngbModal.open(SSHModalComponent)
|
||||
modal.result.then(() => {
|
||||
//this.terminal.openTab(shell)
|
||||
})
|
||||
this.ngbModal.open(SSHModalComponent)
|
||||
}
|
||||
|
||||
provide (): IToolbarButton[] {
|
||||
return [{
|
||||
icon: 'globe',
|
||||
weight: 5,
|
||||
title: 'SSH connections',
|
||||
title: 'SSH',
|
||||
click: async () => {
|
||||
this.activate()
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ export class TerminalTabComponent extends BaseTabComponent {
|
||||
) {
|
||||
super()
|
||||
this.decorators = this.decorators || []
|
||||
this.title = 'Terminal'
|
||||
this.setTitle('Terminal')
|
||||
this.resize$.first().subscribe(async (resizeEvent) => {
|
||||
if (!this.session) {
|
||||
this.session = this.sessions.addSession(
|
||||
@ -211,11 +211,7 @@ export class TerminalTabComponent extends BaseTabComponent {
|
||||
}
|
||||
|
||||
attachHTermHandlers (hterm: any) {
|
||||
hterm.setWindowTitle = (title) => {
|
||||
this.zone.run(() => {
|
||||
this.title = title
|
||||
})
|
||||
}
|
||||
hterm.setWindowTitle = title => this.zone.run(() => this.setTitle(title))
|
||||
|
||||
const _setAlternateMode = hterm.setAlternateMode.bind(hterm)
|
||||
hterm.setAlternateMode = (state) => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user