Philipp Hörist pushed to branch master at gajim / gajim
Commits:
9 changed files:
- gajim/application.py
- gajim/chat_control_base.py
- gajim/common/config.py
- gajim/common/setting_values.py
- gajim/conversation_textview.py
- gajim/data/gui/preferences_window.ui
- gajim/gtk/htmltextview.py
- gajim/gtk/preferences.py
- gajim/message_window.py
Changes:
| ... | ... | @@ -558,7 +558,6 @@ class GajimApplication(Gtk.Application): |
| 558 | 558 |
'win.switch-tab-7': ['<Alt>7', '<Alt>KP_7'],
|
| 559 | 559 |
'win.switch-tab-8': ['<Alt>8', '<Alt>KP_8'],
|
| 560 | 560 |
'win.switch-tab-9': ['<Alt>9', '<Alt>KP_9'],
|
| 561 |
- 'win.copy-text': ['<Control><Shift>c'],
|
|
| 562 | 561 |
}
|
| 563 | 562 |
|
| 564 | 563 |
for action, accels in shortcuts.items():
|
| ... | ... | @@ -82,6 +82,14 @@ if app.is_installed('GSPELL'): |
| 82 | 82 |
from gi.repository import Gspell # pylint: disable=ungrouped-imports
|
| 83 | 83 |
|
| 84 | 84 |
|
| 85 |
+if sys.platform == 'darwin':
|
|
| 86 |
+ COPY_MODIFIER = Gdk.ModifierType.META_MASK
|
|
| 87 |
+ COPY_MODIFIER_KEYS = (Gdk.KEY_Meta_L, Gdk.KEY_Meta_R)
|
|
| 88 |
+else:
|
|
| 89 |
+ COPY_MODIFIER = Gdk.ModifierType.CONTROL_MASK
|
|
| 90 |
+ COPY_MODIFIER_KEYS = (Gdk.KEY_Control_L, Gdk.KEY_Control_R)
|
|
| 91 |
+ |
|
| 92 |
+ |
|
| 85 | 93 |
################################################################################
|
| 86 | 94 |
class ChatControlBase(ChatCommandProcessor, CommandTools, EventHelper):
|
| 87 | 95 |
"""
|
| ... | ... | @@ -187,9 +195,8 @@ class ChatControlBase(ChatCommandProcessor, CommandTools, EventHelper): |
| 187 | 195 |
id_ = self.conv_textview.connect('quote', self.on_quote)
|
| 188 | 196 |
self.handlers[id_] = self.conv_textview.tv
|
| 189 | 197 |
|
| 190 |
- id_ = self.conv_textview.tv.connect('grab-focus',
|
|
| 191 |
- self._on_html_textview_grab_focus)
|
|
| 192 |
- self.handlers[id_] = self.conv_textview.tv
|
|
| 198 |
+ self.conv_textview.tv.connect('key-press-event',
|
|
| 199 |
+ self._on_conv_textview_key_press_event)
|
|
| 193 | 200 |
|
| 194 | 201 |
self.conv_scrolledwindow = self.xml.conversation_scrolledwindow
|
| 195 | 202 |
self.conv_scrolledwindow.add(self.conv_textview.tv)
|
| ... | ... | @@ -279,6 +286,27 @@ class ChatControlBase(ChatCommandProcessor, CommandTools, EventHelper): |
| 279 | 286 |
# to properly use the super, because of the old code.
|
| 280 | 287 |
CommandTools.__init__(self)
|
| 281 | 288 |
|
| 289 |
+ def _on_conv_textview_key_press_event(self, textview, event):
|
|
| 290 |
+ if event.keyval in COPY_MODIFIER_KEYS:
|
|
| 291 |
+ # Don’t route modifier keys for copy action to the Message Input
|
|
| 292 |
+ # otherwise pressing CTRL/META + c (the next event after that)
|
|
| 293 |
+ # will not reach the textview (because the Message Input would get
|
|
| 294 |
+ # focused).
|
|
| 295 |
+ return Gdk.EVENT_PROPAGATE
|
|
| 296 |
+ |
|
| 297 |
+ if event.get_state() & COPY_MODIFIER:
|
|
| 298 |
+ # Don’t reroute the event if it is META + c and the
|
|
| 299 |
+ # textview has a selection
|
|
| 300 |
+ if event.keyval == Gdk.KEY_c:
|
|
| 301 |
+ if textview.get_buffer().props.has_selection:
|
|
| 302 |
+ return Gdk.EVENT_PROPAGATE
|
|
| 303 |
+ |
|
| 304 |
+ # Focus the Messsage Input and resend the event
|
|
| 305 |
+ textview.unselect()
|
|
| 306 |
+ self.msg_textview.grab_focus()
|
|
| 307 |
+ self.msg_textview.get_toplevel().propagate_key_event(event)
|
|
| 308 |
+ return Gdk.EVENT_STOP
|
|
| 309 |
+ |
|
| 282 | 310 |
@property
|
| 283 | 311 |
def type(self):
|
| 284 | 312 |
return self._type
|
| ... | ... | @@ -511,10 +539,6 @@ class ChatControlBase(ChatCommandProcessor, CommandTools, EventHelper): |
| 511 | 539 |
self.msg_textview.emit('insert-emoji')
|
| 512 | 540 |
return Gdk.EVENT_STOP
|
| 513 | 541 |
|
| 514 |
- if action == 'copy-text':
|
|
| 515 |
- self.conv_textview.tv.emit('copy-clipboard')
|
|
| 516 |
- return Gdk.EVENT_STOP
|
|
| 517 |
- |
|
| 518 | 542 |
return Gdk.EVENT_PROPAGATE
|
| 519 | 543 |
|
| 520 | 544 |
def add_actions(self):
|
| ... | ... | @@ -643,13 +667,6 @@ class ChatControlBase(ChatCommandProcessor, CommandTools, EventHelper): |
| 643 | 667 |
gspell_lang = checker.get_language()
|
| 644 | 668 |
self.contact.settings.set('speller_language', gspell_lang.get_code())
|
| 645 | 669 |
|
| 646 |
- def _on_html_textview_grab_focus(self, textview):
|
|
| 647 |
- # Abort signal so the textview does not get focused
|
|
| 648 |
- # Focus the MessageInputTextView instead
|
|
| 649 |
- GObject.signal_stop_emission_by_name(textview, 'grab-focus')
|
|
| 650 |
- self.msg_textview.grab_focus()
|
|
| 651 |
- return Gdk.EVENT_STOP
|
|
| 652 |
- |
|
| 653 | 670 |
def on_banner_label_populate_popup(self, _label, menu):
|
| 654 | 671 |
"""
|
| 655 | 672 |
Override the default context menu and add our own menuitems
|
| ... | ... | @@ -240,7 +240,6 @@ class Config: |
| 240 | 240 |
'muclumbus_api_jid': [opt_str, 'rodrigo.de.mucobedo@dreckshal.de'],
|
| 241 | 241 |
'muclumbus_api_http_uri': [opt_str, 'https://search.jabbercat.org/api/1.0/search'],
|
| 242 | 242 |
'muclumbus_api_pref': [opt_str, 'http', _('API Preferences. Possible values: \'http\', \'iq\'')],
|
| 243 |
- 'auto_copy': [opt_bool, True, _('Selecting text will copy it to the clipboard')],
|
|
| 244 | 243 |
'command_system_execute': [opt_bool, False, _('If enabled, Gajim will execute commands (/show, /sh, /execute, /exec).')],
|
| 245 | 244 |
'groupchat_roster_width': [opt_int, 210, _('Width of group chat roster in pixel')],
|
| 246 | 245 |
'dev_force_bookmark_2': [opt_bool, False, _('Force Bookmark 2 usage')],
|
| ... | ... | @@ -176,7 +176,6 @@ APP_SETTINGS = { |
| 176 | 176 |
'muclumbus_api_jid': 'rodrigo.de.mucobedo@dreckshal.de',
|
| 177 | 177 |
'muclumbus_api_http_uri': 'https://search.jabbercat.org/api/1.0/search',
|
| 178 | 178 |
'muclumbus_api_pref': 'http',
|
| 179 |
- 'auto_copy': True,
|
|
| 180 | 179 |
'command_system_execute': False,
|
| 181 | 180 |
'groupchat_roster_width': 210,
|
| 182 | 181 |
'dev_force_bookmark_2': False,
|
| ... | ... | @@ -74,96 +74,6 @@ TRUST_SYMBOL_DATA = { |
| 74 | 74 |
}
|
| 75 | 75 |
|
| 76 | 76 |
|
| 77 |
-def is_selection_modified(mark):
|
|
| 78 |
- name = mark.get_name()
|
|
| 79 |
- return name in ('selection_bound', 'insert')
|
|
| 80 |
- |
|
| 81 |
-def has_focus(widget):
|
|
| 82 |
- return widget.get_state_flags() & Gtk.StateFlags.FOCUSED == \
|
|
| 83 |
- Gtk.StateFlags.FOCUSED
|
|
| 84 |
- |
|
| 85 |
-class TextViewImage(Gtk.Image):
|
|
| 86 |
- |
|
| 87 |
- def __init__(self, anchor, text):
|
|
| 88 |
- super(TextViewImage, self).__init__()
|
|
| 89 |
- self.anchor = anchor
|
|
| 90 |
- self._selected = False
|
|
| 91 |
- self._disconnect_funcs = []
|
|
| 92 |
- self.connect('parent-set', self.on_parent_set)
|
|
| 93 |
- self.set_tooltip_markup(text)
|
|
| 94 |
- self.anchor.plaintext = text
|
|
| 95 |
- |
|
| 96 |
- def _get_selected(self):
|
|
| 97 |
- parent = self.get_parent()
|
|
| 98 |
- if not parent or not self.anchor:
|
|
| 99 |
- return False
|
|
| 100 |
- buffer_ = parent.get_buffer()
|
|
| 101 |
- position = buffer_.get_iter_at_child_anchor(self.anchor)
|
|
| 102 |
- bounds = buffer_.get_selection_bounds()
|
|
| 103 |
- return bounds and position.in_range(*bounds)
|
|
| 104 |
- |
|
| 105 |
- def get_state(self):
|
|
| 106 |
- parent = self.get_parent()
|
|
| 107 |
- if not parent:
|
|
| 108 |
- return Gtk.StateType.NORMAL
|
|
| 109 |
- if self._selected:
|
|
| 110 |
- if has_focus(parent):
|
|
| 111 |
- return Gtk.StateType.SELECTED
|
|
| 112 |
- return Gtk.StateType.ACTIVE
|
|
| 113 |
- return Gtk.StateType.NORMAL
|
|
| 114 |
- |
|
| 115 |
- def _update_selected(self):
|
|
| 116 |
- selected = self._get_selected()
|
|
| 117 |
- if self._selected != selected:
|
|
| 118 |
- self._selected = selected
|
|
| 119 |
- self.queue_draw()
|
|
| 120 |
- |
|
| 121 |
- def _do_connect(self, widget, signal, callback):
|
|
| 122 |
- id_ = widget.connect(signal, callback)
|
|
| 123 |
- def disconnect():
|
|
| 124 |
- widget.disconnect(id_)
|
|
| 125 |
- self._disconnect_funcs.append(disconnect)
|
|
| 126 |
- |
|
| 127 |
- def _disconnect_signals(self):
|
|
| 128 |
- for func in self._disconnect_funcs:
|
|
| 129 |
- func()
|
|
| 130 |
- self._disconnect_funcs = []
|
|
| 131 |
- |
|
| 132 |
- def on_parent_set(self, widget, old_parent):
|
|
| 133 |
- parent = self.get_parent()
|
|
| 134 |
- if not parent:
|
|
| 135 |
- self._disconnect_signals()
|
|
| 136 |
- return
|
|
| 137 |
- if isinstance(parent, Gtk.EventBox):
|
|
| 138 |
- parent = parent.get_parent()
|
|
| 139 |
- if not parent:
|
|
| 140 |
- self._disconnect_signals()
|
|
| 141 |
- return
|
|
| 142 |
- |
|
| 143 |
- self._do_connect(parent, 'style-set', self.do_queue_draw)
|
|
| 144 |
- self._do_connect(parent, 'focus-in-event', self.do_queue_draw)
|
|
| 145 |
- self._do_connect(parent, 'focus-out-event', self.do_queue_draw)
|
|
| 146 |
- |
|
| 147 |
- textbuf = parent.get_buffer()
|
|
| 148 |
- self._do_connect(textbuf, 'mark-set', self.on_mark_set)
|
|
| 149 |
- self._do_connect(textbuf, 'mark-deleted', self.on_mark_deleted)
|
|
| 150 |
- |
|
| 151 |
- def do_queue_draw(self, *args):
|
|
| 152 |
- self.queue_draw()
|
|
| 153 |
- return False
|
|
| 154 |
- |
|
| 155 |
- def on_mark_set(self, buf, iterat, mark):
|
|
| 156 |
- self.on_mark_modified(mark)
|
|
| 157 |
- return False
|
|
| 158 |
- |
|
| 159 |
- def on_mark_deleted(self, buf, mark):
|
|
| 160 |
- self.on_mark_modified(mark)
|
|
| 161 |
- return False
|
|
| 162 |
- |
|
| 163 |
- def on_mark_modified(self, mark):
|
|
| 164 |
- if is_selection_modified(mark):
|
|
| 165 |
- self._update_selected()
|
|
| 166 |
- |
|
| 167 | 77 |
class ConversationTextview(GObject.GObject):
|
| 168 | 78 |
"""
|
| 169 | 79 |
Class for the conversation textview (where user reads already said messages)
|
| 1 | 1 |
<?xml version="1.0" encoding="UTF-8"?>
|
| 2 |
-<!-- Generated with glade 3.36.0 -->
|
|
| 2 |
+<!-- Generated with glade 3.22.2 -->
|
|
| 3 | 3 |
<interface>
|
| 4 | 4 |
<requires lib="gtk+" version="3.22"/>
|
| 5 | 5 |
<object class="GtkAdjustment" id="adjustment_status_auto_away">
|
| ... | ... | @@ -534,60 +534,7 @@ |
| 534 | 534 |
<property name="orientation">vertical</property>
|
| 535 | 535 |
<property name="spacing">6</property>
|
| 536 | 536 |
<child>
|
| 537 |
- <object class="GtkFrame">
|
|
| 538 |
- <property name="visible">True</property>
|
|
| 539 |
- <property name="can_focus">False</property>
|
|
| 540 |
- <property name="label_xalign">0</property>
|
|
| 541 |
- <property name="shadow_type">none</property>
|
|
| 542 |
- <child>
|
|
| 543 |
- <object class="GtkAlignment">
|
|
| 544 |
- <property name="visible">True</property>
|
|
| 545 |
- <property name="can_focus">False</property>
|
|
| 546 |
- <child>
|
|
| 547 |
- <object class="GtkBox">
|
|
| 548 |
- <property name="visible">True</property>
|
|
| 549 |
- <property name="can_focus">False</property>
|
|
| 550 |
- <property name="margin_top">6</property>
|
|
| 551 |
- <property name="orientation">vertical</property>
|
|
| 552 |
- <property name="spacing">6</property>
|
|
| 553 |
- <child>
|
|
| 554 |
- <object class="GtkCheckButton" id="auto_copy">
|
|
| 555 |
- <property name="label" translatable="yes">Enable auto copy</property>
|
|
| 556 |
- <property name="can_focus">True</property>
|
|
| 557 |
- <property name="receives_default">False</property>
|
|
| 558 |
- <property name="tooltip_text" translatable="yes">If enabled, selected text will automatically be copied to the clipboard, otherwise you can copy text with CTRL + SHIFT + C</property>
|
|
| 559 |
- <property name="halign">start</property>
|
|
| 560 |
- <property name="use_underline">True</property>
|
|
| 561 |
- <property name="draw_indicator">True</property>
|
|
| 562 |
- <signal name="toggled" handler="on_auto_copy_toggled" swapped="no"/>
|
|
| 563 |
- </object>
|
|
| 564 |
- <packing>
|
|
| 565 |
- <property name="expand">False</property>
|
|
| 566 |
- <property name="fill">True</property>
|
|
| 567 |
- <property name="position">0</property>
|
|
| 568 |
- </packing>
|
|
| 569 |
- </child>
|
|
| 570 |
- </object>
|
|
| 571 |
- </child>
|
|
| 572 |
- </object>
|
|
| 573 |
- </child>
|
|
| 574 |
- <child type="label">
|
|
| 575 |
- <object class="GtkLabel">
|
|
| 576 |
- <property name="visible">True</property>
|
|
| 577 |
- <property name="can_focus">False</property>
|
|
| 578 |
- <property name="label" translatable="yes">General</property>
|
|
| 579 |
- <style>
|
|
| 580 |
- <class name="bold"/>
|
|
| 581 |
- <class name="margin-top6"/>
|
|
| 582 |
- </style>
|
|
| 583 |
- </object>
|
|
| 584 |
- </child>
|
|
| 585 |
- </object>
|
|
| 586 |
- <packing>
|
|
| 587 |
- <property name="expand">False</property>
|
|
| 588 |
- <property name="fill">True</property>
|
|
| 589 |
- <property name="position">0</property>
|
|
| 590 |
- </packing>
|
|
| 537 |
+ <placeholder/>
|
|
| 591 | 538 |
</child>
|
| 592 | 539 |
<child>
|
| 593 | 540 |
<object class="GtkFrame">
|
| ... | ... | @@ -713,26 +713,10 @@ class HtmlTextView(Gtk.TextView): |
| 713 | 713 |
self.plugin_modified = False
|
| 714 | 714 |
self._cursor_changed = False
|
| 715 | 715 |
|
| 716 |
- self.connect('button-release-event', self._on_button_release)
|
|
| 717 | 716 |
if standalone:
|
| 718 | 717 |
self.connect('query-tooltip', self._query_tooltip)
|
| 719 | 718 |
self.create_tags()
|
| 720 | 719 |
|
| 721 |
- @staticmethod
|
|
| 722 |
- def _on_button_release(textview, event):
|
|
| 723 |
- if event.button == 1:
|
|
| 724 |
- # Left Mouse button
|
|
| 725 |
- |
|
| 726 |
- if not app.settings.get('auto_copy'):
|
|
| 727 |
- return Gdk.EVENT_PROPAGATE
|
|
| 728 |
- |
|
| 729 |
- if not textview.get_buffer().get_has_selection():
|
|
| 730 |
- return Gdk.EVENT_PROPAGATE
|
|
| 731 |
- selected = textview.get_selected_text()
|
|
| 732 |
- clipboard = textview.get_clipboard(Gdk.SELECTION_CLIPBOARD)
|
|
| 733 |
- clipboard.set_text(selected, -1)
|
|
| 734 |
- return Gdk.EVENT_PROPAGATE
|
|
| 735 |
- |
|
| 736 | 720 |
def create_tags(self):
|
| 737 | 721 |
color = app.css_config.get_value('.gajim-url', StyleAttr.COLOR)
|
| 738 | 722 |
|
| ... | ... | @@ -887,3 +871,8 @@ class HtmlTextView(Gtk.TextView): |
| 887 | 871 |
self.add_child_at_anchor(emoji, anchor)
|
| 888 | 872 |
buffer_.delete_mark(start_mark)
|
| 889 | 873 |
buffer_.delete_mark(end_mark)
|
| 874 |
+ |
|
| 875 |
+ def unselect(self):
|
|
| 876 |
+ buffer_ = self.get_buffer()
|
|
| 877 |
+ insert_iter = buffer_.get_iter_at_mark(buffer_.get_insert())
|
|
| 878 |
+ buffer_.select_range(insert_iter, insert_iter)
|
| ... | ... | @@ -119,11 +119,6 @@ class Preferences(Gtk.ApplicationWindow): |
| 119 | 119 |
self._ui.sort_by_show_in_muc_checkbutton.set_active(st)
|
| 120 | 120 |
|
| 121 | 121 |
### Chat tab ###
|
| 122 |
- ## General Settings
|
|
| 123 |
- |
|
| 124 |
- # Enable auto copy
|
|
| 125 |
- st = app.settings.get('auto_copy')
|
|
| 126 |
- self._ui.auto_copy.set_active(st)
|
|
| 127 | 122 |
|
| 128 | 123 |
## Chat Settings
|
| 129 | 124 |
# Use speller
|
| ... | ... | @@ -492,9 +487,6 @@ class Preferences(Gtk.ApplicationWindow): |
| 492 | 487 |
ctrl.roster.invalidate_sort()
|
| 493 | 488 |
|
| 494 | 489 |
### Chat tab ###
|
| 495 |
- def on_auto_copy_toggled(self, widget):
|
|
| 496 |
- self.on_checkbutton_toggled(widget, 'auto_copy')
|
|
| 497 |
- |
|
| 498 | 490 |
def on_speller_checkbutton_toggled(self, widget):
|
| 499 | 491 |
active = widget.get_active()
|
| 500 | 492 |
app.settings.set('use_speller', active)
|
| ... | ... | @@ -193,7 +193,6 @@ class MessageWindow(EventHelper): |
| 193 | 193 |
'switch-tab-7',
|
| 194 | 194 |
'switch-tab-8',
|
| 195 | 195 |
'switch-tab-9',
|
| 196 |
- 'copy-text',
|
|
| 197 | 196 |
]
|
| 198 | 197 |
|
| 199 | 198 |
disabled_for_emacs = (
|