Update MainWindow shortcuts to be keybinding signal based
Use keybinding ("action") signals and a GtkBindingSet to hook up most
of MainWindow's actions to keyboard shortcuts, rather than use
the application to do so. Remove single-key shortcuts, and update
shortcuts used to avoid collisions. Replace "focus conversation list"
action with general navigation between panes.
🚨 Remove MainWindow hack that enabled single key shortcuts to work 🚨
This commit is contained in:
parent
e11e2bd279
commit
fb1439264a
2 changed files with 316 additions and 134 deletions
|
|
@ -14,7 +14,6 @@ public class Application.MainWindow :
|
|||
// Named actions.
|
||||
public const string ACTION_ARCHIVE_CONVERSATION = "archive-conversation";
|
||||
public const string ACTION_CONVERSATION_DOWN = "down-conversation";
|
||||
public const string ACTION_CONVERSATION_LIST = "focus-conversation-list";
|
||||
public const string ACTION_CONVERSATION_UP = "up-conversation";
|
||||
public const string ACTION_DELETE_CONVERSATION = "delete-conversation";
|
||||
public const string ACTION_EMPTY_SPAM = "empty-spam";
|
||||
|
|
@ -43,7 +42,6 @@ public class Application.MainWindow :
|
|||
private const ActionEntry[] WINDOW_ACTIONS = {
|
||||
{ Action.Window.CLOSE, on_close },
|
||||
|
||||
{ ACTION_CONVERSATION_LIST, on_conversation_list },
|
||||
{ ACTION_FIND_IN_CONVERSATION, on_find_in_conversation_action },
|
||||
{ ACTION_SEARCH, on_search_activated },
|
||||
{ ACTION_EMPTY_SPAM, on_empty_spam },
|
||||
|
|
@ -75,64 +73,154 @@ public class Application.MainWindow :
|
|||
private const int MIN_CONVERSATION_COUNT = 50;
|
||||
|
||||
|
||||
public static void add_accelerators(Client owner) {
|
||||
static construct {
|
||||
// Set up default keybindings
|
||||
unowned Gtk.BindingSet bindings = Gtk.BindingSet.by_class(
|
||||
(ObjectClass) typeof(MainWindow).class_ref()
|
||||
);
|
||||
|
||||
//
|
||||
// Replying & forwarding
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.R, CONTROL_MASK,
|
||||
"reply-conversation-sender", 0
|
||||
);
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.R, CONTROL_MASK | SHIFT_MASK,
|
||||
"reply-conversation-all", 0
|
||||
);
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.L, CONTROL_MASK,
|
||||
"forward-conversation", 0
|
||||
);
|
||||
|
||||
// Marking actions
|
||||
//
|
||||
// Unread is the primary action, so it doesn't get the <Shift>
|
||||
// modifier
|
||||
owner.add_window_accelerators(
|
||||
ACTION_MARK_AS_UNREAD, { "<Ctrl>U", "<Shift>U" }
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.U, CONTROL_MASK,
|
||||
"mark-conversations-read", 1, typeof(bool), true
|
||||
);
|
||||
owner.add_window_accelerators(
|
||||
ACTION_MARK_AS_READ, { "<Ctrl><Shift>U", "<Shift>I" }
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.U, CONTROL_MASK | SHIFT_MASK,
|
||||
"mark-conversations-read", 1, typeof(bool), false
|
||||
);
|
||||
// Ephy uses Ctrl+D for bookmarking
|
||||
owner.add_window_accelerators(
|
||||
ACTION_MARK_AS_STARRED, { "<Ctrl>D", "S" }
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.D, CONTROL_MASK,
|
||||
"mark-conversations-starred", 1, typeof(bool), true
|
||||
);
|
||||
owner.add_window_accelerators(
|
||||
ACTION_MARK_AS_UNSTARRED, { "<Ctrl><Shift>D", "D" }
|
||||
);
|
||||
owner.add_window_accelerators(
|
||||
ACTION_TOGGLE_SPAM, { "<Ctrl>J", "exclam" } // Exclamation mark (!)
|
||||
);
|
||||
|
||||
// Replying & forwarding
|
||||
owner.add_window_accelerators(
|
||||
ACTION_REPLY_CONVERSATION, { "<Ctrl>R", "R" }
|
||||
);
|
||||
owner.add_window_accelerators(
|
||||
ACTION_REPLY_ALL_CONVERSATION, { "<Ctrl><Shift>R", "<Shift>R" }
|
||||
);
|
||||
owner.add_window_accelerators(
|
||||
ACTION_FORWARD_CONVERSATION, { "<Ctrl>L", "F" }
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.D, CONTROL_MASK | SHIFT_MASK,
|
||||
"mark-conversations-starred", 1, typeof(bool), false
|
||||
);
|
||||
|
||||
//
|
||||
// Moving & labelling
|
||||
owner.add_window_accelerators(
|
||||
ACTION_SHOW_COPY_MENU, { "<Ctrl>L", "L" }
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.B, CONTROL_MASK,
|
||||
"show-copy-menu", 0
|
||||
);
|
||||
owner.add_window_accelerators(
|
||||
ACTION_SHOW_MOVE_MENU, { "<Ctrl>M", "M" }
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.M, CONTROL_MASK,
|
||||
"show-move-menu", 0
|
||||
);
|
||||
owner.add_window_accelerators(
|
||||
ACTION_ARCHIVE_CONVERSATION, { "<Ctrl>K", "A", "Y" }
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.K, CONTROL_MASK,
|
||||
"archive-conversations", 0
|
||||
);
|
||||
owner.add_window_accelerators(
|
||||
ACTION_TRASH_CONVERSATION, { "Delete", "BackSpace" }
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.J, CONTROL_MASK,
|
||||
"junk-conversations", 0
|
||||
);
|
||||
owner.add_window_accelerators(
|
||||
ACTION_DELETE_CONVERSATION, { "<Shift>Delete", "<Shift>BackSpace" }
|
||||
// Many ways to trash
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.BackSpace, 0,
|
||||
"trash-conversations", 0
|
||||
);
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.Delete, 0,
|
||||
"trash-conversations", 0
|
||||
);
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.KP_Delete, 0,
|
||||
"trash-conversations", 0
|
||||
);
|
||||
// Many ways to delete
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.BackSpace, SHIFT_MASK,
|
||||
"delete-conversations", 0
|
||||
);
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.Delete, SHIFT_MASK,
|
||||
"delete-conversations", 0
|
||||
);
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.KP_Delete, SHIFT_MASK,
|
||||
"delete-conversations", 0
|
||||
);
|
||||
|
||||
//
|
||||
// Find & search
|
||||
owner.add_window_accelerators(
|
||||
ACTION_FIND_IN_CONVERSATION, { "<Ctrl>F", "slash" }
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.F, CONTROL_MASK,
|
||||
"find", 0
|
||||
);
|
||||
owner.add_window_accelerators(
|
||||
ACTION_SEARCH, { "<Ctrl>S" }
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.S, CONTROL_MASK,
|
||||
"search", 0
|
||||
);
|
||||
|
||||
//
|
||||
// Navigation
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.Left, MOD1_MASK,
|
||||
"navigate", 1,
|
||||
typeof(Gtk.ScrollType), Gtk.ScrollType.PAGE_LEFT
|
||||
);
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.Right, MOD1_MASK,
|
||||
"navigate", 1,
|
||||
typeof(Gtk.ScrollType), Gtk.ScrollType.PAGE_RIGHT
|
||||
);
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.comma, CONTROL_MASK,
|
||||
"navigate", 1,
|
||||
typeof(Gtk.ScrollType), Gtk.ScrollType.STEP_UP
|
||||
);
|
||||
Gtk.BindingEntry.add_signal(
|
||||
bindings,
|
||||
Gdk.Key.period, CONTROL_MASK,
|
||||
"navigate", 1,
|
||||
typeof(Gtk.ScrollType), Gtk.ScrollType.STEP_DOWN
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static void add_accelerators(Client owner) {
|
||||
// Zoom
|
||||
owner.add_window_accelerators(
|
||||
ACTION_ZOOM+("('in')"), { "<Ctrl>equal", "<Ctrl>plus" }
|
||||
|
|
@ -143,19 +231,9 @@ public class Application.MainWindow :
|
|||
owner.add_window_accelerators(
|
||||
ACTION_ZOOM+("('normal')"), { "<Ctrl>0" }
|
||||
);
|
||||
|
||||
// Navigation
|
||||
owner.add_window_accelerators(
|
||||
ACTION_CONVERSATION_LIST, { "<Ctrl>B" }
|
||||
);
|
||||
owner.add_window_accelerators(
|
||||
ACTION_CONVERSATION_UP, { "<Ctrl>bracketleft", "K" }
|
||||
);
|
||||
owner.add_window_accelerators(
|
||||
ACTION_CONVERSATION_DOWN, { "<Ctrl>bracketright", "J" }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private enum ConversationCount { NONE, SINGLE, MULTIPLE; }
|
||||
|
||||
|
||||
|
|
@ -274,6 +352,129 @@ public class Application.MainWindow :
|
|||
public signal void retry_service_problem(Geary.ClientService.Status problem);
|
||||
|
||||
|
||||
/** Keybinding signal for replying to sender for the current conversation. */
|
||||
[Signal (action=true)]
|
||||
public virtual signal void reply_conversation_sender() {
|
||||
activate_action(get_window_action(ACTION_REPLY_CONVERSATION));
|
||||
}
|
||||
|
||||
/** Keybinding signal for replying to all for the current conversation. */
|
||||
[Signal (action=true)]
|
||||
public virtual signal void reply_conversation_all() {
|
||||
activate_action(get_window_action(ACTION_REPLY_ALL_CONVERSATION));
|
||||
}
|
||||
|
||||
/** Keybinding signal for forwarding the current conversation. */
|
||||
[Signal (action=true)]
|
||||
public virtual signal void forward_conversation() {
|
||||
activate_action(get_window_action(ACTION_FORWARD_CONVERSATION));
|
||||
}
|
||||
|
||||
/** Keybinding signal for marking the current selection read. */
|
||||
[Signal (action=true)]
|
||||
public virtual signal void mark_conversations_read(bool prefer_read) {
|
||||
activate_action(
|
||||
prefer_read
|
||||
? get_window_action(ACTION_MARK_AS_READ)
|
||||
: get_window_action(ACTION_MARK_AS_UNREAD)
|
||||
);
|
||||
}
|
||||
|
||||
/** Keybinding signal for marking the current selection starred. */
|
||||
[Signal (action=true)]
|
||||
public virtual signal void mark_conversations_starred(bool prefer_starred) {
|
||||
activate_action(
|
||||
prefer_starred
|
||||
? get_window_action(ACTION_MARK_AS_STARRED)
|
||||
: get_window_action(ACTION_MARK_AS_UNSTARRED)
|
||||
);
|
||||
}
|
||||
|
||||
/** Keybinding signal for showing the copy/label menu. */
|
||||
[Signal (action=true)]
|
||||
public virtual signal void show_copy_menu() {
|
||||
activate_action(get_window_action(ACTION_SHOW_COPY_MENU));
|
||||
}
|
||||
|
||||
/** Keybinding signal for showing the move menu. */
|
||||
[Signal (action=true)]
|
||||
public virtual signal void show_move_menu() {
|
||||
activate_action(get_window_action(ACTION_SHOW_MOVE_MENU));
|
||||
}
|
||||
|
||||
/** Keybinding signal for archiving the current selection. */
|
||||
[Signal (action=true)]
|
||||
public virtual signal void archive_conversations() {
|
||||
activate_action(get_window_action(ACTION_ARCHIVE_CONVERSATION));
|
||||
}
|
||||
|
||||
/** Keybinding signal for junking the current selection. */
|
||||
[Signal (action=true)]
|
||||
public virtual signal void junk_conversations() {
|
||||
activate_action(get_window_action(ACTION_TOGGLE_SPAM));
|
||||
}
|
||||
|
||||
/** Keybinding signal for trashing the current selection. */
|
||||
[Signal (action=true)]
|
||||
public virtual signal void trash_conversations() {
|
||||
// XXX the Shift+BackSpace combo above doesn't seem to work
|
||||
// for delete, so double-check here.
|
||||
activate_action(
|
||||
!this.is_shift_down
|
||||
? get_window_action(ACTION_TRASH_CONVERSATION)
|
||||
: get_window_action(ACTION_DELETE_CONVERSATION)
|
||||
);
|
||||
}
|
||||
|
||||
/** Keybinding signal for deleting the current selection. */
|
||||
[Signal (action=true)]
|
||||
public virtual signal void delete_conversations() {
|
||||
activate_action(get_window_action(ACTION_DELETE_CONVERSATION));
|
||||
}
|
||||
|
||||
/** Keybinding signal for activating conversation search. */
|
||||
[Signal (action=true)]
|
||||
public virtual signal void search() {
|
||||
activate_action(get_window_action(ACTION_SEARCH));
|
||||
}
|
||||
|
||||
/** Keybinding signal for activating in-conversation find. */
|
||||
[Signal (action=true)]
|
||||
public virtual signal void find() {
|
||||
activate_action(get_window_action(ACTION_FIND_IN_CONVERSATION));
|
||||
}
|
||||
|
||||
/** Keybinding signal for shifting the keyboard focus. */
|
||||
[Signal (action=true)]
|
||||
public virtual signal void navigate(Gtk.ScrollType type) {
|
||||
switch (type) {
|
||||
case Gtk.ScrollType.PAGE_LEFT:
|
||||
if (get_direction() != RTL) {
|
||||
focus_previous_pane();
|
||||
} else {
|
||||
focus_next_pane();
|
||||
}
|
||||
break;
|
||||
case Gtk.ScrollType.PAGE_RIGHT:
|
||||
if (get_direction() != RTL) {
|
||||
focus_next_pane();
|
||||
} else {
|
||||
focus_previous_pane();
|
||||
}
|
||||
break;
|
||||
case Gtk.ScrollType.STEP_UP:
|
||||
activate_action(get_window_action(ACTION_CONVERSATION_UP));
|
||||
break;
|
||||
case Gtk.ScrollType.STEP_DOWN:
|
||||
activate_action(get_window_action(ACTION_CONVERSATION_DOWN));
|
||||
break;
|
||||
default:
|
||||
this.get_window().beep();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal MainWindow(Client application) {
|
||||
Object(
|
||||
application: application,
|
||||
|
|
@ -699,7 +900,7 @@ public class Application.MainWindow :
|
|||
return closed;
|
||||
}
|
||||
|
||||
public void search(string text, bool is_interactive) {
|
||||
public void show_search(string text, bool is_interactive) {
|
||||
Geary.SearchFolder? search_folder = null;
|
||||
if (this.selected_account != null) {
|
||||
search_folder = this.selected_account.get_special_folder(
|
||||
|
|
@ -962,7 +1163,7 @@ public class Application.MainWindow :
|
|||
this.notify["has-toplevel-focus"].connect(on_has_toplevel_focus);
|
||||
|
||||
// Search bar
|
||||
this.search_bar.search_text_changed.connect(do_search);
|
||||
this.search_bar.search_text_changed.connect(on_search);
|
||||
this.search_bar.show();
|
||||
this.search_bar_box.pack_start(this.search_bar, false, false, 0);
|
||||
|
||||
|
|
@ -1019,68 +1220,7 @@ public class Application.MainWindow :
|
|||
/** {@inheritDoc} */
|
||||
public override bool key_press_event(Gdk.EventKey event) {
|
||||
check_shift_event(event);
|
||||
|
||||
/* Ensure that single-key command (SKC) shortcuts don't
|
||||
* interfere with text input.
|
||||
*
|
||||
* The default GtkWindow::key_press_event implementation calls
|
||||
* gtk_window_activate_key -- which would activate the SKC,
|
||||
* before calling gtk_window_propagate_key_event -- which
|
||||
* would send the event to any focused text entry control, so
|
||||
* we need to override that. A quick hack is to just call
|
||||
* gtk_window_propagate_key_event here, then chain up. But
|
||||
* that means two calls to that method for every key press,
|
||||
* which in the worst case means all widgets in the focus
|
||||
* chain would be consulted to handle the press twice, which
|
||||
* sucks.
|
||||
*
|
||||
* Worse however, is that due to WK2 Bug 136430[0], WebView
|
||||
* instances duplicate any key events they don't handle. For
|
||||
* the editor, that means simple key presses like 'a' will
|
||||
* only result in a single event, since the web view adds the
|
||||
* letter to the document. But if not handled, e.g. when the
|
||||
* user presses Shift, Ctrl, or similar, then it also produces
|
||||
* a second event. Combined with the
|
||||
* gtk_window_propagate_key_event above, this leads to a
|
||||
* cambrian explosion of key events - an exponential number
|
||||
* are generated, which is bad. This problem also applies to
|
||||
* ConversationWebView instances, since none of them handle
|
||||
* events.
|
||||
*
|
||||
* See also the note in EmailEntry::on_key_press.
|
||||
*
|
||||
* The work around here is completely override the default
|
||||
* implementation to reverse it. So if something related to
|
||||
* key handling breaks in the future, this might be a good
|
||||
* place to start looking. Better alternatives welcome.
|
||||
*
|
||||
* [0] - <https://bugs.webkit.org/show_bug.cgi?id=136430>
|
||||
*/
|
||||
|
||||
bool handled = false;
|
||||
Gdk.ModifierType state = (
|
||||
event.state & Gtk.accelerator_get_default_mod_mask()
|
||||
);
|
||||
if (state > 0 && state != Gdk.ModifierType.SHIFT_MASK) {
|
||||
// Have a modifier held down (Ctrl, Alt, etc) that is used
|
||||
// as an accelerator so we don't need to worry about SKCs,
|
||||
// and the key press can be handled normally. Can't do
|
||||
// this with Shift though since that will stop chars being
|
||||
// typed in the composer that conflict with accels, like
|
||||
// `!`.
|
||||
handled = base.key_press_event(event);
|
||||
} else {
|
||||
// No modifier used as an accelerator is down, so kluge
|
||||
// input handling to make SKCs work per the above.
|
||||
handled = propagate_key_event(event);
|
||||
if (!handled) {
|
||||
handled = activate_key(event);
|
||||
}
|
||||
if (!handled) {
|
||||
handled = Gtk.bindings_activate_event(this, event);
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
return base.key_press_event(event);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
|
|
@ -1632,6 +1772,51 @@ public class Application.MainWindow :
|
|||
}
|
||||
}
|
||||
|
||||
private void focus_next_pane() {
|
||||
var focus = get_focus();
|
||||
if (focus != null) {
|
||||
if (focus == this.folder_list ||
|
||||
focus.is_ancestor(this.folder_list)) {
|
||||
focus = this.conversation_list_view;
|
||||
} else if (focus == this.conversation_list_view ||
|
||||
focus.is_ancestor(this.conversation_list_view)) {
|
||||
focus = this.conversation_viewer.visible_child;
|
||||
} else if (focus == this.conversation_viewer ||
|
||||
focus.is_ancestor(this.conversation_viewer)) {
|
||||
focus = this.folder_list;
|
||||
}
|
||||
}
|
||||
|
||||
if (focus != null) {
|
||||
focus.focus(TAB_FORWARD);
|
||||
} else {
|
||||
get_window().beep();
|
||||
}
|
||||
}
|
||||
|
||||
private void focus_previous_pane() {
|
||||
var focus = get_focus();
|
||||
if (focus != null) {
|
||||
if (focus == this.folder_list ||
|
||||
focus.is_ancestor(this.folder_list)) {
|
||||
focus = this.conversation_viewer.visible_child;
|
||||
} else if (focus == this.conversation_list_view ||
|
||||
focus.is_ancestor(this.conversation_list_view)) {
|
||||
focus = this.folder_list;
|
||||
} else if (focus == this.conversation_viewer ||
|
||||
focus.is_ancestor(this.conversation_viewer)) {
|
||||
focus = this.conversation_list_view;
|
||||
}
|
||||
}
|
||||
|
||||
if (focus != null) {
|
||||
focus.focus(TAB_FORWARD);
|
||||
} else {
|
||||
get_window().beep();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private SimpleAction get_window_action(string name) {
|
||||
return (SimpleAction) lookup_action(name);
|
||||
}
|
||||
|
|
@ -1640,6 +1825,14 @@ public class Application.MainWindow :
|
|||
return (SimpleAction) this.edit_actions.lookup_action(name);
|
||||
}
|
||||
|
||||
private void activate_action(GLib.Action? action) {
|
||||
if (action != null && action.get_enabled()) {
|
||||
action.activate(null);
|
||||
} else {
|
||||
get_window().beep();
|
||||
}
|
||||
}
|
||||
|
||||
private void on_scan_completed(Geary.App.ConversationMonitor monitor) {
|
||||
// Done scanning. Check if we have enough messages to fill
|
||||
// the conversation list; if not, trigger a load_more();
|
||||
|
|
@ -1864,8 +2057,8 @@ public class Application.MainWindow :
|
|||
this.select_folder.begin(folder, true);
|
||||
}
|
||||
|
||||
private void do_search(string text) {
|
||||
search(text, true);
|
||||
private void on_search(string text) {
|
||||
show_search(text, true);
|
||||
}
|
||||
|
||||
private void on_visible_conversations_changed(Gee.Set<Geary.App.Conversation> visible) {
|
||||
|
|
@ -1912,10 +2105,6 @@ public class Application.MainWindow :
|
|||
}
|
||||
}
|
||||
|
||||
private void on_conversation_list() {
|
||||
this.conversation_list_view.grab_focus();
|
||||
}
|
||||
|
||||
private void on_find_in_conversation_action() {
|
||||
this.conversation_viewer.enable_find();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,14 +71,14 @@
|
|||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes" context="shortcut window">Label conversation</property>
|
||||
<property name="accelerator"><primary>L</property>
|
||||
<property name="accelerator"><primary>B</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes" context="shortcut window">Trash conversation</property>
|
||||
<property name="accelerator">Delete Back</property>
|
||||
<property name="accelerator">Delete BackSpace</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
|
|
@ -93,7 +93,7 @@
|
|||
<property name="visible">True</property>
|
||||
<property name="title"
|
||||
translatable="yes" context="shortcut window">Delete conversation</property>
|
||||
<property name="accelerator"><Shift>Delete <Shift>Back</property>
|
||||
<property name="accelerator"><Shift>Delete <Shift>BackSpace</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
@ -231,35 +231,28 @@
|
|||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes" context="shortcut window">Focus the next pane</property>
|
||||
<property name="accelerator">F6</property>
|
||||
<property name="accelerator"><Alt>Right</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes" context="shortcut window">Focus the previous pane</property>
|
||||
<property name="accelerator"><Shift>F6</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes" context="shortcut window">Focus the conversation list</property>
|
||||
<property name="accelerator"><primary>B</property>
|
||||
<property name="accelerator"><Alt>Left</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes" context="shortcut window">Select the conversation down</property>
|
||||
<property name="accelerator"><primary>bracketright J</property>
|
||||
<property name="accelerator"><primary>period</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes" context="shortcut window">Select the conversation up</property>
|
||||
<property name="accelerator"><primary>bracketleft K</property>
|
||||
<property name="accelerator"><primary>comma</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue