diff --git a/kitty/main.py b/kitty/main.py index 74fba0226..e9a42f36f 100644 --- a/kitty/main.py +++ b/kitty/main.py @@ -11,6 +11,7 @@ import signal from gettext import gettext as _ from PyQt5.QtCore import Qt, QSocketNotifier, pyqtSignal +from PyQt5.QtGui import QIcon from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox from .config import load_config, validate_font @@ -31,6 +32,8 @@ class MainWindow(QMainWindow): self.report_error.connect(self.show_error, type=Qt.QueuedConnection) self.handle_unix_signals() self.boss = Boss(opts, self, dump_commands) + self.boss.term.title_changed.connect(self.setWindowTitle) + self.boss.term.icon_changed.connect(lambda name: self.setWindowIcon(QIcon.fromTheme(name))) self.setCentralWidget(self.boss.term) def on_unhandled_error(self, etype, value, tb): diff --git a/kitty/screen.py b/kitty/screen.py index e43514dc6..129cb37d7 100644 --- a/kitty/screen.py +++ b/kitty/screen.py @@ -222,6 +222,9 @@ class Screen(QObject): self.cursor.hidden = False self.cursor_changed(self.cursor) + def in_bracketed_paste_mode(self): + return mo.BRACKETED_PASTE in self.mode + def reset_mode(self, *modes, private=False): """Resets (disables) a given list of modes. diff --git a/kitty/term.py b/kitty/term.py index 83ea6698a..d96377920 100644 --- a/kitty/term.py +++ b/kitty/term.py @@ -8,7 +8,7 @@ from typing import Tuple, Iterator from PyQt5.QtCore import pyqtSignal, QTimer, QRect, Qt from PyQt5.QtGui import QColor, QPainter, QFont, QFontMetrics, QRegion, QPen, QPixmap -from PyQt5.QtWidgets import QWidget +from PyQt5.QtWidgets import QWidget, QApplication from .config import build_ansi_color_tables, Options, fg_color_table, bg_color_table from .data_types import Cursor, HAS_BG_MASK, COL_SHIFT, COL_MASK, as_color @@ -18,6 +18,7 @@ from .screen import wrap_cursor_position from .keys import key_event_to_data from .screen import Screen from pyte.streams import Stream, DebugStream +from pyte import modes as mo def ascii_width(fm: QFontMetrics) -> int: @@ -45,6 +46,8 @@ class TerminalWidget(QWidget): relayout_lines = pyqtSignal(object, object) write_to_child = pyqtSignal(object) + title_changed = pyqtSignal(object) + icon_changed = pyqtSignal(object) send_data_to_child = pyqtSignal(object) cells_per_line = 80 lines_per_screen = 24 @@ -56,7 +59,8 @@ class TerminalWidget(QWidget): self.tracker.dirtied.connect(self.update_screen) sclass = DebugStream if dump_commands else Stream self.screen = Screen(opts, self.tracker, parent=self) - self.screen.write_to_child.connect(self.write_to_child) + for s in 'write_to_child title_changed icon_changed'.split(): + getattr(self.screen, s).connect(getattr(self, s)) self.stream = sclass(self.screen) self.feed = self.stream.feed self.last_drew_cursor_at = (0, 0) @@ -235,3 +239,17 @@ class TerminalWidget(QWidget): ev.accept() return return QWidget.keyPressEvent(self, ev) + + def mousePressEvent(self, ev): + if ev.button() == Qt.MiddleButton: + c = QApplication.clipboard() + if c.supportsSelection(): + text = c.text(c.Selection) + if text: + text = text.encode('utf-8') + if self.screen.in_bracketed_paste_mode(): + text = mo.BRACKETED_PASTE_START + text + mo.BRACKETED_PASTE_END + self.send_data_to_child.emit(text) + ev.accept() + return + return QWidget.mousePressEvent(self, ev) diff --git a/pyte/modes.py b/pyte/modes.py index 5f7386cab..2b5c1500f 100644 --- a/pyte/modes.py +++ b/pyte/modes.py @@ -58,3 +58,9 @@ DECAWM = 7 << 5 #: *Column Mode*: selects the number of columns per line (80 or 132) #: on the screen. DECCOLM = 3 << 5 + +#: Bracketed paste mode +# http://cirw.in/blog/bracketed-paste +BRACKETED_PASTE = 2004 << 5 +BRACKETED_PASTE_START = '\033[200~'.encode('ascii') +BRACKETED_PASTE_END = '\033[201~'.encode('ascii')