diff --git a/desktop/org.gnome.Geary.gschema.xml b/desktop/org.gnome.Geary.gschema.xml
index 9f2467b5..f0068798 100644
--- a/desktop/org.gnome.Geary.gschema.xml
+++ b/desktop/org.gnome.Geary.gschema.xml
@@ -63,6 +63,14 @@
True if we should display a short preview of each message.
+
+ false
+ Use single key shortcuts
+ Enables shortcuts for email actions that do not
+ require pressing <Ctrl> to emulate those used by
+ Gmail.
+
+
nothing
Languages that shall be used in the spell checker
diff --git a/src/client/application/application-client.vala b/src/client/application/application-client.vala
index 88d99c5b..2eef6a7f 100644
--- a/src/client/application/application-client.vala
+++ b/src/client/application/application-client.vala
@@ -243,6 +243,7 @@ public class Application.Client : Gtk.Application {
private File exec_dir;
private string binary;
private bool start_hidden = false;
+ private Gtk.CssProvider single_key_shortcuts = new Gtk.CssProvider();
private GLib.Cancellable controller_cancellable = new GLib.Cancellable();
private Components.Inspector? inspector = null;
private Geary.Nonblocking.Mutex controller_mutex = new Geary.Nonblocking.Mutex();
@@ -427,15 +428,14 @@ public class Application.Client : Gtk.Application {
provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
);
- provider.parsing_error.connect(on_css_parse_error);
- try {
- var file = GLib.File.new_for_uri(
- "resource:///org/gnome/Geary/geary.css"
- );
- provider.load_from_file(file);
- } catch (GLib.Error error) {
- warning("Could not load CSS: %s", error.message);
- }
+ load_css(provider,
+ "resource:///org/gnome/Geary/geary.css");
+ load_css(this.single_key_shortcuts,
+ "resource:///org/gnome/Geary/single-key-shortcuts.css");
+ update_single_key_shortcuts();
+ this.config.notify[Configuration.SINGLE_KEY_SHORTCUTS].connect(
+ on_single_key_shortcuts_toggled
+ );
MainWindow.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);
}
+ 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) {
Geary.Folder? folder = null;
string id = (string) target.get_child_value(0);
@@ -996,6 +1011,16 @@ public class Application.Client : Gtk.Application {
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() {
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) {
uint start = section.get_start_line();
uint end = section.get_end_line();
diff --git a/src/client/application/application-configuration.vala b/src/client/application/application-configuration.vala
index 051b4d7d..c8e95f83 100644
--- a/src/client/application/application-configuration.vala
+++ b/src/client/application/application-configuration.vala
@@ -9,7 +9,7 @@
/**
* 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";
@@ -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 MESSAGES_PANE_POSITION_KEY = "messages-pane-position";
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_VISIBLE_LANGUAGES = "spell-check-visible-languages";
public const string STARTUP_NOTIFICATIONS_KEY = "startup-notifications";
@@ -116,6 +117,8 @@ public class Application.Configuration {
get { return settings.get_boolean(DISPLAY_PREVIEW_KEY); }
}
+ public bool single_key_shortcuts { get; set; default = false; }
+
/**
* The set of enabled spell checker languages.
*
@@ -216,6 +219,8 @@ public class Application.Configuration {
gnome_interface = new Settings("org.gnome.desktop.interface");
Migrate.old_app_config(settings);
+
+ this.bind(SINGLE_KEY_SHORTCUTS, this, SINGLE_KEY_SHORTCUTS);
}
public void bind(string key, Object object, string property,
diff --git a/src/client/components/components-preferences-window.vala b/src/client/components/components-preferences-window.vala
index 198395ad..9b9772fd 100644
--- a/src/client/components/components-preferences-window.vala
+++ b/src/client/components/components-preferences-window.vala
@@ -65,6 +65,19 @@ public class Components.PreferencesWindow : Hdy.PreferencesWindow {
three_pane_view_row.activatable_widget = 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 "
+ );
+ 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();
startup_notifications.valign = CENTER;
@@ -87,6 +100,7 @@ public class Components.PreferencesWindow : Hdy.PreferencesWindow {
group.add(autoselect_row);
group.add(display_preview_row);
group.add(three_pane_view_row);
+ group.add(single_key_shortucts_row);
group.add(startup_notifications_row);
var page = new Hdy.PreferencesPage();
@@ -101,10 +115,31 @@ public class Components.PreferencesWindow : Hdy.PreferencesWindow {
insert_action_group(Action.Window.GROUP_NAME, window_actions);
Application.Configuration config = this.application.config;
- config.bind(Application.Configuration.AUTOSELECT_KEY, autoselect, "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.STARTUP_NOTIFICATIONS_KEY, startup_notifications, "state");
+ config.bind(
+ Application.Configuration.AUTOSELECT_KEY,
+ autoselect,
+ "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);
}
diff --git a/ui/application-main-window.ui b/ui/application-main-window.ui
index c2802888..2166b836 100644
--- a/ui/application-main-window.ui
+++ b/ui/application-main-window.ui
@@ -450,5 +450,8 @@ Please check your login name and try again.
+
diff --git a/ui/gtk/help-overlay.ui b/ui/gtk/help-overlay.ui
index 4fe38dd8..08c29751 100644
--- a/ui/gtk/help-overlay.ui
+++ b/ui/gtk/help-overlay.ui
@@ -280,7 +280,7 @@
@@ -301,21 +301,21 @@
@@ -332,6 +332,34 @@
exclam
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/org.gnome.Geary.gresource.xml b/ui/org.gnome.Geary.gresource.xml
index 0f1f8881..8ad731f0 100644
--- a/ui/org.gnome.Geary.gresource.xml
+++ b/ui/org.gnome.Geary.gresource.xml
@@ -45,5 +45,6 @@
signature-web-view.js
upgrade_dialog.glade
geary.css
+ single-key-shortcuts.css
diff --git a/ui/single-key-shortcuts.css b/ui/single-key-shortcuts.css
new file mode 100644
index 00000000..7073f754
--- /dev/null
+++ b/ui/single-key-shortcuts.css
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019 Michael Gratton
+ *
+ * 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 "i" { "mark-conversations-read" (1) };
+ bind "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;
+}