Re-implement single key shortcuts as a preference
Add new `single-key-shortcuts` GSetting, Application.Configuration property and add UI for it in the Preferences window. When enabled, load in new `single-key-shortcuts.css` file that has the appropriate bindings. Update bindings to match Google's current set, and update shortcut help to match.
This commit is contained in:
parent
fb1439264a
commit
259ebe50fd
8 changed files with 166 additions and 18 deletions
|
|
@ -63,6 +63,14 @@
|
||||||
<description>True if we should display a short preview of each message.</description>
|
<description>True if we should display a short preview of each message.</description>
|
||||||
</key>
|
</key>
|
||||||
|
|
||||||
|
<key name="single-key-shortcuts" type="b">
|
||||||
|
<default>false</default>
|
||||||
|
<summary>Use single key shortcuts</summary>
|
||||||
|
<description>Enables shortcuts for email actions that do not
|
||||||
|
require pressing <Ctrl> to emulate those used by
|
||||||
|
Gmail.</description>
|
||||||
|
</key>
|
||||||
|
|
||||||
<key name="spell-check-languages" type="mas">
|
<key name="spell-check-languages" type="mas">
|
||||||
<default>nothing</default>
|
<default>nothing</default>
|
||||||
<summary>Languages that shall be used in the spell checker</summary>
|
<summary>Languages that shall be used in the spell checker</summary>
|
||||||
|
|
|
||||||
|
|
@ -243,6 +243,7 @@ public class Application.Client : Gtk.Application {
|
||||||
private File exec_dir;
|
private File exec_dir;
|
||||||
private string binary;
|
private string binary;
|
||||||
private bool start_hidden = false;
|
private bool start_hidden = false;
|
||||||
|
private Gtk.CssProvider single_key_shortcuts = new Gtk.CssProvider();
|
||||||
private GLib.Cancellable controller_cancellable = new GLib.Cancellable();
|
private GLib.Cancellable controller_cancellable = new GLib.Cancellable();
|
||||||
private Components.Inspector? inspector = null;
|
private Components.Inspector? inspector = null;
|
||||||
private Geary.Nonblocking.Mutex controller_mutex = new Geary.Nonblocking.Mutex();
|
private Geary.Nonblocking.Mutex controller_mutex = new Geary.Nonblocking.Mutex();
|
||||||
|
|
@ -427,15 +428,14 @@ public class Application.Client : Gtk.Application {
|
||||||
provider,
|
provider,
|
||||||
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
|
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
|
||||||
);
|
);
|
||||||
provider.parsing_error.connect(on_css_parse_error);
|
load_css(provider,
|
||||||
try {
|
"resource:///org/gnome/Geary/geary.css");
|
||||||
var file = GLib.File.new_for_uri(
|
load_css(this.single_key_shortcuts,
|
||||||
"resource:///org/gnome/Geary/geary.css"
|
"resource:///org/gnome/Geary/single-key-shortcuts.css");
|
||||||
);
|
update_single_key_shortcuts();
|
||||||
provider.load_from_file(file);
|
this.config.notify[Configuration.SINGLE_KEY_SHORTCUTS].connect(
|
||||||
} catch (GLib.Error error) {
|
on_single_key_shortcuts_toggled
|
||||||
warning("Could not load CSS: %s", error.message);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
MainWindow.add_accelerators(this);
|
MainWindow.add_accelerators(this);
|
||||||
Composer.Widget.add_accelerators(this);
|
Composer.Widget.add_accelerators(this);
|
||||||
|
|
@ -980,6 +980,21 @@ public class Application.Client : Gtk.Application {
|
||||||
set_accels_for_action("app." + action, accelerators);
|
set_accels_for_action("app." + action, accelerators);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void update_single_key_shortcuts() {
|
||||||
|
if (this.config.single_key_shortcuts) {
|
||||||
|
Gtk.StyleContext.add_provider_for_screen(
|
||||||
|
Gdk.Display.get_default().get_default_screen(),
|
||||||
|
this.single_key_shortcuts,
|
||||||
|
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Gtk.StyleContext.remove_provider_for_screen(
|
||||||
|
Gdk.Display.get_default().get_default_screen(),
|
||||||
|
this.single_key_shortcuts
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Geary.Folder? get_folder_from_action_target(GLib.Variant target) {
|
private Geary.Folder? get_folder_from_action_target(GLib.Variant target) {
|
||||||
Geary.Folder? folder = null;
|
Geary.Folder? folder = null;
|
||||||
string id = (string) target.get_child_value(0);
|
string id = (string) target.get_child_value(0);
|
||||||
|
|
@ -996,6 +1011,16 @@ public class Application.Client : Gtk.Application {
|
||||||
return folder;
|
return folder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void load_css(Gtk.CssProvider provider, string resource_uri) {
|
||||||
|
provider.parsing_error.connect(on_css_parse_error);
|
||||||
|
try {
|
||||||
|
var file = GLib.File.new_for_uri(resource_uri);
|
||||||
|
provider.load_from_file(file);
|
||||||
|
} catch (GLib.Error error) {
|
||||||
|
warning("Could not load CSS: %s", error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void on_activate_about() {
|
private void on_activate_about() {
|
||||||
this.show_about.begin();
|
this.show_about.begin();
|
||||||
}
|
}
|
||||||
|
|
@ -1146,6 +1171,10 @@ public class Application.Client : Gtk.Application {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void on_single_key_shortcuts_toggled() {
|
||||||
|
update_single_key_shortcuts();
|
||||||
|
}
|
||||||
|
|
||||||
private void on_css_parse_error(Gtk.CssSection section, GLib.Error error) {
|
private void on_css_parse_error(Gtk.CssSection section, GLib.Error error) {
|
||||||
uint start = section.get_start_line();
|
uint start = section.get_start_line();
|
||||||
uint end = section.get_end_line();
|
uint end = section.get_end_line();
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
/**
|
/**
|
||||||
* Provides properties to access application GSettings values.
|
* Provides properties to access application GSettings values.
|
||||||
*/
|
*/
|
||||||
public class Application.Configuration {
|
public class Application.Configuration : Geary.BaseObject {
|
||||||
|
|
||||||
|
|
||||||
public const string ASK_OPEN_ATTACHMENT_KEY = "ask-open-attachment";
|
public const string ASK_OPEN_ATTACHMENT_KEY = "ask-open-attachment";
|
||||||
|
|
@ -24,6 +24,7 @@ public class Application.Configuration {
|
||||||
public const string FOLDER_LIST_PANE_POSITION_VERTICAL_KEY = "folder-list-pane-position-vertical";
|
public const string FOLDER_LIST_PANE_POSITION_VERTICAL_KEY = "folder-list-pane-position-vertical";
|
||||||
public const string MESSAGES_PANE_POSITION_KEY = "messages-pane-position";
|
public const string MESSAGES_PANE_POSITION_KEY = "messages-pane-position";
|
||||||
public const string SEARCH_STRATEGY_KEY = "search-strategy";
|
public const string SEARCH_STRATEGY_KEY = "search-strategy";
|
||||||
|
public const string SINGLE_KEY_SHORTCUTS = "single-key-shortcuts";
|
||||||
public const string SPELL_CHECK_LANGUAGES = "spell-check-languages";
|
public const string SPELL_CHECK_LANGUAGES = "spell-check-languages";
|
||||||
public const string SPELL_CHECK_VISIBLE_LANGUAGES = "spell-check-visible-languages";
|
public const string SPELL_CHECK_VISIBLE_LANGUAGES = "spell-check-visible-languages";
|
||||||
public const string STARTUP_NOTIFICATIONS_KEY = "startup-notifications";
|
public const string STARTUP_NOTIFICATIONS_KEY = "startup-notifications";
|
||||||
|
|
@ -116,6 +117,8 @@ public class Application.Configuration {
|
||||||
get { return settings.get_boolean(DISPLAY_PREVIEW_KEY); }
|
get { return settings.get_boolean(DISPLAY_PREVIEW_KEY); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool single_key_shortcuts { get; set; default = false; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The set of enabled spell checker languages.
|
* The set of enabled spell checker languages.
|
||||||
*
|
*
|
||||||
|
|
@ -216,6 +219,8 @@ public class Application.Configuration {
|
||||||
gnome_interface = new Settings("org.gnome.desktop.interface");
|
gnome_interface = new Settings("org.gnome.desktop.interface");
|
||||||
|
|
||||||
Migrate.old_app_config(settings);
|
Migrate.old_app_config(settings);
|
||||||
|
|
||||||
|
this.bind(SINGLE_KEY_SHORTCUTS, this, SINGLE_KEY_SHORTCUTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bind(string key, Object object, string property,
|
public void bind(string key, Object object, string property,
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,19 @@ public class Components.PreferencesWindow : Hdy.PreferencesWindow {
|
||||||
three_pane_view_row.activatable_widget = three_pane_view;
|
three_pane_view_row.activatable_widget = three_pane_view;
|
||||||
three_pane_view_row.add_action(three_pane_view);
|
three_pane_view_row.add_action(three_pane_view);
|
||||||
|
|
||||||
|
var single_key_shortucts = new Gtk.Switch();
|
||||||
|
single_key_shortucts.valign = CENTER;
|
||||||
|
|
||||||
|
var single_key_shortucts_row = new Hdy.ActionRow();
|
||||||
|
/// Translators: Preferences label
|
||||||
|
single_key_shortucts_row.title = _("Use _single key email shortcuts");
|
||||||
|
single_key_shortucts_row.tooltip_text = _(
|
||||||
|
"Enable keyboard shortcuts for email actions that do not require pressing <Ctrl>"
|
||||||
|
);
|
||||||
|
single_key_shortucts_row.use_underline = true;
|
||||||
|
single_key_shortucts_row.activatable_widget = single_key_shortucts;
|
||||||
|
single_key_shortucts_row.add_action(single_key_shortucts);
|
||||||
|
|
||||||
var startup_notifications = new Gtk.Switch();
|
var startup_notifications = new Gtk.Switch();
|
||||||
startup_notifications.valign = CENTER;
|
startup_notifications.valign = CENTER;
|
||||||
|
|
||||||
|
|
@ -87,6 +100,7 @@ public class Components.PreferencesWindow : Hdy.PreferencesWindow {
|
||||||
group.add(autoselect_row);
|
group.add(autoselect_row);
|
||||||
group.add(display_preview_row);
|
group.add(display_preview_row);
|
||||||
group.add(three_pane_view_row);
|
group.add(three_pane_view_row);
|
||||||
|
group.add(single_key_shortucts_row);
|
||||||
group.add(startup_notifications_row);
|
group.add(startup_notifications_row);
|
||||||
|
|
||||||
var page = new Hdy.PreferencesPage();
|
var page = new Hdy.PreferencesPage();
|
||||||
|
|
@ -101,10 +115,31 @@ public class Components.PreferencesWindow : Hdy.PreferencesWindow {
|
||||||
insert_action_group(Action.Window.GROUP_NAME, window_actions);
|
insert_action_group(Action.Window.GROUP_NAME, window_actions);
|
||||||
|
|
||||||
Application.Configuration config = this.application.config;
|
Application.Configuration config = this.application.config;
|
||||||
config.bind(Application.Configuration.AUTOSELECT_KEY, autoselect, "state");
|
config.bind(
|
||||||
config.bind(Application.Configuration.DISPLAY_PREVIEW_KEY, display_preview, "state");
|
Application.Configuration.AUTOSELECT_KEY,
|
||||||
config.bind(Application.Configuration.FOLDER_LIST_PANE_HORIZONTAL_KEY, three_pane_view, "state");
|
autoselect,
|
||||||
config.bind(Application.Configuration.STARTUP_NOTIFICATIONS_KEY, startup_notifications, "state");
|
"state"
|
||||||
|
);
|
||||||
|
config.bind(
|
||||||
|
Application.Configuration.DISPLAY_PREVIEW_KEY,
|
||||||
|
display_preview,
|
||||||
|
"state"
|
||||||
|
);
|
||||||
|
config.bind(
|
||||||
|
Application.Configuration.FOLDER_LIST_PANE_HORIZONTAL_KEY,
|
||||||
|
three_pane_view,
|
||||||
|
"state"
|
||||||
|
);
|
||||||
|
config.bind(
|
||||||
|
Application.Configuration.SINGLE_KEY_SHORTCUTS,
|
||||||
|
single_key_shortucts,
|
||||||
|
"state"
|
||||||
|
);
|
||||||
|
config.bind(
|
||||||
|
Application.Configuration.STARTUP_NOTIFICATIONS_KEY,
|
||||||
|
startup_notifications,
|
||||||
|
"state"
|
||||||
|
);
|
||||||
|
|
||||||
this.delete_event.connect(on_delete);
|
this.delete_event.connect(on_delete);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -450,5 +450,8 @@ Please check your login name and try again.</property>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="geary-main-window"/>
|
||||||
|
</style>
|
||||||
</template>
|
</template>
|
||||||
</interface>
|
</interface>
|
||||||
|
|
|
||||||
|
|
@ -280,7 +280,7 @@
|
||||||
<object class="GtkShortcutsShortcut">
|
<object class="GtkShortcutsShortcut">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="title" translatable="yes" context="shortcut window">Reply to all</property>
|
<property name="title" translatable="yes" context="shortcut window">Reply to all</property>
|
||||||
<property name="accelerator"><Shift>R</property>
|
<property name="accelerator">A</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
|
@ -301,21 +301,21 @@
|
||||||
<object class="GtkShortcutsShortcut">
|
<object class="GtkShortcutsShortcut">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="title" translatable="yes" context="shortcut window">Mark/un-mark starred</property>
|
<property name="title" translatable="yes" context="shortcut window">Mark/un-mark starred</property>
|
||||||
<property name="accelerator">S D</property>
|
<property name="accelerator">S</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkShortcutsShortcut">
|
<object class="GtkShortcutsShortcut">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="title" translatable="yes" context="shortcut window">Archive conversation</property>
|
<property name="title" translatable="yes" context="shortcut window">Archive conversation</property>
|
||||||
<property name="accelerator">A Y</property>
|
<property name="accelerator">E</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkShortcutsShortcut">
|
<object class="GtkShortcutsShortcut">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="title" translatable="yes" context="shortcut window">Move conversation</property>
|
<property name="title" translatable="yes" context="shortcut window">Move conversation</property>
|
||||||
<property name="accelerator">M</property>
|
<property name="accelerator">V</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
|
@ -332,6 +332,34 @@
|
||||||
<property name="accelerator">exclam</property>
|
<property name="accelerator">exclam</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkShortcutsShortcut">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="title" translatable="yes" context="shortcut window">Delete conversation</property>
|
||||||
|
<property name="accelerator">numbersign</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkShortcutsShortcut">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="title" translatable="yes" context="shortcut window">Find in current conversation</property>
|
||||||
|
<property name="accelerator">slash</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">J</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">K</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
|
||||||
|
|
@ -45,5 +45,6 @@
|
||||||
<file compressed="true">signature-web-view.js</file>
|
<file compressed="true">signature-web-view.js</file>
|
||||||
<file compressed="true" preprocess="xml-stripblanks">upgrade_dialog.glade</file>
|
<file compressed="true" preprocess="xml-stripblanks">upgrade_dialog.glade</file>
|
||||||
<file compressed="true">geary.css</file>
|
<file compressed="true">geary.css</file>
|
||||||
|
<file compressed="true">single-key-shortcuts.css</file>
|
||||||
</gresource>
|
</gresource>
|
||||||
</gresources>
|
</gresources>
|
||||||
|
|
|
||||||
39
ui/single-key-shortcuts.css
Normal file
39
ui/single-key-shortcuts.css
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Michael Gratton <mike@vee.net>
|
||||||
|
*
|
||||||
|
* This software is licensed under the GNU Lesser General Public License
|
||||||
|
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These match Gmail's as of time of commit. Taken from:
|
||||||
|
* https://support.google.com/mail/answer/6594
|
||||||
|
*/
|
||||||
|
@binding-set SingleKeyShortcuts {
|
||||||
|
bind "r" { "reply-conversation-sender" () };
|
||||||
|
bind "a" { "reply-conversation-all" () };
|
||||||
|
bind "f" { "forward-conversation" () };
|
||||||
|
|
||||||
|
bind "<Shift>i" { "mark-conversations-read" (1) };
|
||||||
|
bind "<Shift>u" { "mark-conversations-read" (0) };
|
||||||
|
bind "s" { "mark-conversations-starred" (1) };
|
||||||
|
|
||||||
|
bind "l" { "show-copy-menu" () };
|
||||||
|
bind "v" { "show-move-menu" () };
|
||||||
|
|
||||||
|
bind "e" { "archive-conversations" () };
|
||||||
|
/* ! */
|
||||||
|
bind "exclam" { "junk-conversations" () };
|
||||||
|
/* # */
|
||||||
|
bind "numbersign" { "delete-conversations" () };
|
||||||
|
|
||||||
|
/* / */
|
||||||
|
bind "slash" { "find" () };
|
||||||
|
|
||||||
|
bind "k" { "navigate" (step-up) };
|
||||||
|
bind "j" { "navigate" (step-down) };
|
||||||
|
}
|
||||||
|
|
||||||
|
window.geary-main-window {
|
||||||
|
-gtk-key-bindings: SingleKeyShortcuts;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue