VMDisplayQemuTerminalWindowController.swift 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. //
  2. // Copyright © 2022 osy. All rights reserved.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. import SwiftTerm
  17. class VMDisplayQemuTerminalWindowController: VMDisplayQemuWindowController, VMDisplayTerminal {
  18. private var terminalView: TerminalView!
  19. private var vmSerialPort: CSPort?
  20. private var serialConfig: UTMQemuConfigurationSerial? {
  21. vmQemuConfig?.serials[id]
  22. }
  23. override var defaultTitle: String {
  24. if isSecondary {
  25. return String.localizedStringWithFormat(NSLocalizedString("%@ (Terminal %lld)", comment: "VMDisplayQemuTerminalWindowController"), vmQemuConfig.information.name, id + 1)
  26. } else {
  27. return super.defaultTitle
  28. }
  29. }
  30. convenience init(secondaryFromSerialPort serialPort: CSPort, vm: UTMQemuVirtualMachine, id: Int) {
  31. self.init(vm: vm, id: id)
  32. self.vmSerialPort = serialPort
  33. }
  34. override func windowDidLoad() {
  35. terminalView = TerminalView(frame: displayView.bounds)
  36. terminalView.terminalDelegate = self
  37. terminalView.autoresizingMask = [.width, .height]
  38. displayView.addSubview(terminalView)
  39. vmSerialPort?.delegate = self // can be nil for primary window
  40. super.windowDidLoad()
  41. }
  42. override func enterLive() {
  43. super.enterLive()
  44. captureMouseToolbarItem.isEnabled = false
  45. setupTerminal(terminalView, using: serialConfig!.terminal!, for: window!)
  46. }
  47. override func enterSuspended(isBusy busy: Bool) {
  48. if vm.state == .vmStopped {
  49. vmSerialPort = nil
  50. }
  51. super.enterSuspended(isBusy: busy)
  52. }
  53. override func resizeConsoleButtonPressed(_ sender: Any) {
  54. let cmd = resizeCommand(for: terminalView, using: serialConfig!.terminal!)
  55. vmSerialPort?.write(cmd.data(using: .nonLossyASCII)!)
  56. }
  57. override func spiceDidCreateSerial(_ serial: CSPort) {
  58. if !isSecondary, vmSerialPort == nil {
  59. vmSerialPort = serial
  60. serial.delegate = self
  61. } else {
  62. super.spiceDidCreateSerial(serial)
  63. }
  64. }
  65. override func spiceDidDestroySerial(_ serial: CSPort) {
  66. if vmSerialPort == serial {
  67. if isSecondary {
  68. DispatchQueue.main.async {
  69. self.close()
  70. }
  71. }
  72. serial.delegate = nil
  73. vmSerialPort = nil
  74. } else {
  75. super.spiceDidDestroySerial(serial)
  76. }
  77. }
  78. }
  79. extension VMDisplayQemuTerminalWindowController: TerminalViewDelegate {
  80. func sizeChanged(source: TerminalView, newCols: Int, newRows: Int) {
  81. }
  82. func setTerminalTitle(source: TerminalView, title: String) {
  83. window!.subtitle = title
  84. }
  85. func hostCurrentDirectoryUpdate(source: TerminalView, directory: String?) {
  86. }
  87. func send(source: TerminalView, data: ArraySlice<UInt8>) {
  88. if let vmSerialPort = vmSerialPort {
  89. vmSerialPort.write(Data(data))
  90. }
  91. }
  92. func scrolled(source: TerminalView, position: Double) {
  93. }
  94. }
  95. extension VMDisplayQemuTerminalWindowController: CSPortDelegate {
  96. func portDidDisconect(_ port: CSPort) {
  97. }
  98. func port(_ port: CSPort, didError error: String) {
  99. showErrorAlert(error)
  100. }
  101. func port(_ port: CSPort, didRecieveData data: Data) {
  102. if let terminalView = terminalView {
  103. let arr = [UInt8](data)[...]
  104. DispatchQueue.main.async {
  105. terminalView.feed(byteArray: arr)
  106. }
  107. }
  108. }
  109. func defaultSerialWrite(data: Data) {
  110. if let vmSerialPort = vmSerialPort {
  111. vmSerialPort.write(data)
  112. }
  113. }
  114. }