diff --git a/plugins/brackets-completion/brackets-completion.vala b/plugins/brackets-completion/brackets-completion.vala index ba3727e80..9a86edac0 100644 --- a/plugins/brackets-completion/brackets-completion.vala +++ b/plugins/brackets-completion/brackets-completion.vala @@ -11,6 +11,7 @@ public class Scratch.Plugins.BracketsCompletion : Peas.ExtensionBase, Scratch.Se public Object object { owned get; set construct; } + private Gtk.EventControllerKey key_controller; private Gee.HashMap brackets; private Gee.HashMap keys; private Gtk.TextBuffer current_buffer; @@ -40,6 +41,12 @@ public class Scratch.Plugins.BracketsCompletion : Peas.ExtensionBase, Scratch.Se plugins = (Scratch.Services.Interface) object; plugins.hook_document.connect (on_hook_document); + plugins.hook_window.connect ((w) => { + key_controller = new Gtk.EventControllerKey (w) { + propagation_phase = CAPTURE + }; + key_controller.key_pressed.connect (on_key_down); + }); } public void deactivate () { @@ -52,14 +59,12 @@ public class Scratch.Plugins.BracketsCompletion : Peas.ExtensionBase, Scratch.Se current_buffer = doc.source_view.buffer; if (current_source_view != null) { - current_source_view.key_press_event.disconnect (on_key_down); current_source_view.event_after.disconnect (on_event_after); current_source_view.backspace.disconnect (on_backspace); } current_source_view = doc.source_view; - current_source_view.key_press_event.connect (on_key_down); current_source_view.event_after.connect (on_event_after); current_source_view.backspace.connect (on_backspace); } @@ -163,8 +168,17 @@ public class Scratch.Plugins.BracketsCompletion : Peas.ExtensionBase, Scratch.Se current_buffer.end_user_action (); } - private bool on_key_down (Gdk.EventKey event) { - if (Gdk.ModifierType.MOD1_MASK in event.state || Gdk.ModifierType.CONTROL_MASK in event.state) { + private bool on_key_down ( + uint keyval, + uint keycode, + Gdk.ModifierType state + ) requires (current_source_view != null && current_buffer != null) { + + if (!current_source_view.is_focus) { + return false; + } + + if (Gdk.ModifierType.MOD1_MASK in state || Gdk.ModifierType.CONTROL_MASK in state) { return false; } @@ -173,7 +187,7 @@ public class Scratch.Plugins.BracketsCompletion : Peas.ExtensionBase, Scratch.Se return false; } - if (keys.has_key (event.keyval) && current_buffer.has_selection) { + if (keys.has_key (keyval) && current_buffer.has_selection) { Gtk.TextIter start, end; current_buffer.get_selection_bounds (out start, out end); diff --git a/plugins/markdown-actions/markdown-actions.vala b/plugins/markdown-actions/markdown-actions.vala index 65b712da7..aac82f871 100644 --- a/plugins/markdown-actions/markdown-actions.vala +++ b/plugins/markdown-actions/markdown-actions.vala @@ -26,11 +26,13 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Scratch.Services public void update_state () {} + private Gtk.EventControllerKey key_controller; + private bool is_markdown = false; + public void activate () { plugins = (Scratch.Services.Interface) object; plugins.hook_document.connect ((doc) => { if (current_source != null) { - current_source.key_press_event.disconnect (shortcut_handler); current_source.notify["language"].disconnect (configure_shortcuts); } @@ -39,30 +41,44 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Scratch.Services current_source.notify["language"].connect (configure_shortcuts); }); + plugins.hook_window.connect ((w) => { + key_controller = new Gtk.EventControllerKey (w) { + propagation_phase = CAPTURE + }; + key_controller.key_pressed.connect (shortcut_handler); + }); } private void configure_shortcuts () { var lang = current_source.language; - if (lang != null && lang.id == "markdown") { - current_source.key_press_event.connect (shortcut_handler); - } else { - current_source.key_press_event.disconnect (shortcut_handler); - } + is_markdown = (lang != null && lang.id == "markdown"); } - private bool shortcut_handler (Gdk.EventKey evt) { - var control = (evt.state & Gdk.ModifierType.CONTROL_MASK) != 0; - var shift = (evt.state & Gdk.ModifierType.SHIFT_MASK) != 0; - var other_mods = (evt.state & Gtk.accelerator_get_default_mod_mask () & - ~Gdk.ModifierType.SHIFT_MASK & - ~Gdk.ModifierType.CONTROL_MASK) != 0; + private bool shortcut_handler ( + Gtk.EventController controller, + uint keyval, + uint keycode, + Gdk.ModifierType state + ) requires (current_source != null) { - if (evt.is_modifier == 1 || other_mods == true) { + if (!current_source.is_focus) { return false; } + if (!is_markdown || !Gtk.accelerator_valid (keyval, state)) { + return false; + } + + var mods = (state & Gtk.accelerator_get_default_mod_mask ()); + if (((mods & ~Gdk.ModifierType.SHIFT_MASK) & ~Gdk.ModifierType.CONTROL_MASK) != 0) { + // A modifier other than Control or Shift is down + return false; + } + + var control = (mods & Gdk.ModifierType.CONTROL_MASK) != 0; + var shift = (mods & Gdk.ModifierType.SHIFT_MASK) != 0; if (control && shift) { - switch (evt.keyval) { + switch (keyval) { case Gdk.Key.B: add_markdown_tag ("**"); return true; @@ -75,7 +91,7 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Scratch.Services } } - if (evt.keyval == Gdk.Key.Return) { + if (keyval == Gdk.Key.Return) { char ul_marker; int ol_number = 1; string item_text; @@ -99,6 +115,7 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Scratch.Services return true; } } + return false; } @@ -233,7 +250,6 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Scratch.Services public void deactivate () { if (current_source != null) { - current_source.key_press_event.disconnect (shortcut_handler); current_source.notify["language"].disconnect (configure_shortcuts); } } diff --git a/plugins/vim-emulation/vim-emulation.vala b/plugins/vim-emulation/vim-emulation.vala index 394c5e5c8..b20a6cdac 100644 --- a/plugins/vim-emulation/vim-emulation.vala +++ b/plugins/vim-emulation/vim-emulation.vala @@ -34,6 +34,8 @@ public class Scratch.Plugins.VimEmulation : Peas.ExtensionBase, Scratch.Services Scratch.Widgets.SourceView? view = null; Scratch.Services.Interface plugins; + private Gtk.EventControllerKey key_controller; + public Object object { owned get; set construct; } construct { @@ -48,36 +50,49 @@ public class Scratch.Plugins.VimEmulation : Peas.ExtensionBase, Scratch.Services plugins = (Scratch.Services.Interface) object; plugins.hook_document.connect ((doc) => { this.view = doc.source_view; - this.view.key_press_event.disconnect (handle_key_press); - this.view.key_press_event.connect (handle_key_press); this.views.add (view); }); + plugins.hook_window.connect ((w) => { + key_controller = new Gtk.EventControllerKey (w) { + propagation_phase = CAPTURE + }; + + key_controller.key_pressed.connect (handle_key_press); + }); } public void deactivate () { - foreach (var v in views) { - v.key_press_event.disconnect (handle_key_press); - } + } - private bool handle_key_press (Gdk.EventKey event) { + private bool handle_key_press ( + Gtk.EventController controller, + uint keyval, + uint keycode, + Gdk.ModifierType state + ) requires (view != null) { + + if (!view.is_focus) { + return false; + } + //some extensions to the default navigating - bool ctrl = (event.state & Gdk.ModifierType.CONTROL_MASK) != 0; - bool shift = (event.state & Gdk.ModifierType.SHIFT_MASK) != 0; + bool ctrl = (state & Gdk.ModifierType.CONTROL_MASK) != 0; + bool shift = (state & Gdk.ModifierType.SHIFT_MASK) != 0; - if (ctrl && event.keyval == Gdk.Key.Up) { + if (ctrl && (keyval == Gdk.Key.Up)) { move_paragraph (true, shift); return true; } - if (ctrl && event.keyval == Gdk.Key.Down) { + if (ctrl && (keyval == Gdk.Key.Down)) { move_paragraph (false, shift); return true; } int old_len = number.length; // Firstly let's set the mode - switch (event.keyval) { + switch (keyval) { //mode changing case Gdk.Key.i: if (mode == Mode.INSERT) { @@ -97,12 +112,17 @@ public class Scratch.Plugins.VimEmulation : Peas.ExtensionBase, Scratch.Services } if (mode == Mode.INSERT) { - action += event.str; + //NOTE event.str` is gone in Gtk4 so use a different method + var uc = (unichar) (Gdk.keyval_to_unicode (keyval)); + if (uc.isprint ()) { + action += uc.to_string (); + } + return false; } // Parse commands - switch (event.keyval) { + switch (keyval) { //numbers case Gdk.Key.@1: number += "1"; diff --git a/plugins/word-completion/completion-provider.vala b/plugins/word-completion/completion-provider.vala index 4f2430c8b..d7878a1ed 100644 --- a/plugins/word-completion/completion-provider.vala +++ b/plugins/word-completion/completion-provider.vala @@ -111,7 +111,6 @@ public class Scratch.Plugins.CompletionProvider : Gtk.SourceCompletionProvider, return true; } - private bool get_proposals (out GLib.List? props, bool no_minimum) { string to_find = ""; Gtk.TextBuffer temp_buffer = buffer; diff --git a/plugins/word-completion/plugin.vala b/plugins/word-completion/plugin.vala index 7719a5c2f..0a3872629 100644 --- a/plugins/word-completion/plugin.vala +++ b/plugins/word-completion/plugin.vala @@ -24,6 +24,7 @@ public class Scratch.Plugins.Completion : Peas.ExtensionBase, Scratch.Services.A public Object object { owned get; set construct; } private List text_view_list = new List (); + private Gtk.EventControllerKey key_controller; public Euclide.Completion.Parser parser {get; private set;} public Gtk.SourceView? current_view {get; private set;} public Scratch.Services.Document current_document {get; private set;} @@ -53,6 +54,13 @@ public class Scratch.Plugins.Completion : Peas.ExtensionBase, Scratch.Services.A }); plugins.hook_document.connect (on_new_source_view); + plugins.hook_window.connect ((w) => { + key_controller = new Gtk.EventControllerKey (w) { + propagation_phase = CAPTURE + }; + + key_controller.key_pressed.connect (on_key_press); + }); } public void deactivate () { @@ -78,7 +86,7 @@ public class Scratch.Plugins.Completion : Peas.ExtensionBase, Scratch.Services.A current_document = doc; current_view = doc.source_view; - current_view.key_press_event.connect (on_key_press); + current_view.completion.show.connect (() => { completion_in_progress = true; }); @@ -120,10 +128,18 @@ public class Scratch.Plugins.Completion : Peas.ExtensionBase, Scratch.Services.A return false; } - private bool on_key_press (Gtk.Widget view, Gdk.EventKey event) { - var kv = event.keyval; + private bool on_key_press ( + uint keyval, + uint keycode, + Gdk.ModifierType state + ) requires (current_view != null) { + + var kv = keyval; + if (!current_view.is_focus) { + return false; + } /* Pass through any modified keypress except Shift or Capslock */ - Gdk.ModifierType mods = event.state & Gdk.ModifierType.MODIFIER_MASK + Gdk.ModifierType mods = state & Gdk.ModifierType.MODIFIER_MASK & ~Gdk.ModifierType.SHIFT_MASK & ~Gdk.ModifierType.LOCK_MASK; if (mods > 0 ) { @@ -166,8 +182,6 @@ public class Scratch.Plugins.Completion : Peas.ExtensionBase, Scratch.Services.A } private void cleanup (Gtk.SourceView view) { - current_view.key_press_event.disconnect (on_key_press); - current_view.completion.get_providers ().foreach ((p) => { try { /* Only remove provider added by this plug in */ diff --git a/src/Widgets/SearchBar.vala b/src/Widgets/SearchBar.vala index 8fb50588d..630c96d17 100644 --- a/src/Widgets/SearchBar.vala +++ b/src/Widgets/SearchBar.vala @@ -1,7 +1,7 @@ /* * Copyright (C) 2011-2012 Lucas Baudin * 2013 Mario Guerriero - 2014-2023 elementary, Inc. (https://elementary.io) + 2014-2026 elementary, Inc. (https://elementary.io) * * This file is part of Code. * @@ -53,10 +53,23 @@ namespace Scratch.Widgets { private Gtk.SourceSearchContext? search_context; private uint update_search_label_timeout_id = 0; private Gtk.Revealer revealer; + private Gtk.EventControllerKey key_controller; public bool is_focused { get { - return search_entry.has_focus || replace_entry.has_focus; + return search_is_focused || replace_is_focused; + } + } + + public bool search_is_focused { + get { + return search_entry.has_focus; + } + } + + public bool replace_is_focused { + get { + return replace_entry.has_focus; } } @@ -72,6 +85,12 @@ namespace Scratch.Widgets { } } + public bool has_search_term { + get { + return search_entry.text != ""; + } + } + public uint search_occurrences { get { if (search_context == null || @@ -226,7 +245,6 @@ namespace Scratch.Widgets { // Connecting to some signals search_entry.changed.connect (on_search_parameters_changed); - search_entry.key_press_event.connect (on_search_entry_key_press); search_entry.focus_in_event.connect (on_search_entry_focused_in); search_entry.icon_release.connect ((p0, p1) => { if (p0 == Gtk.EntryIconPosition.PRIMARY) { @@ -234,7 +252,6 @@ namespace Scratch.Widgets { } }); replace_entry.activate.connect (on_replace_entry_activate); - replace_entry.key_press_event.connect (on_replace_entry_key_press); var entry_path = new Gtk.WidgetPath (); entry_path.append_type (typeof (Gtk.Widget)); @@ -259,6 +276,11 @@ namespace Scratch.Widgets { add (revealer); update_search_widgets (); + + key_controller = new Gtk.EventControllerKey (window) { + propagation_phase = CAPTURE + }; + key_controller.key_pressed.connect (on_key_pressed); } public void set_text_view (Scratch.Widgets.SourceView? text_view) { @@ -522,58 +544,50 @@ namespace Scratch.Widgets { search_entry.text = text; } - private bool on_search_entry_key_press (Gdk.EventKey event) { - /* We don't need to perform search if there is nothing to search... */ - if (search_entry.text == "") { + private bool on_key_pressed (uint keyval, uint keycode, Gdk.ModifierType state) { + if (!(search_is_focused || replace_is_focused)) { return false; } - - string key = Gdk.keyval_name (event.keyval); - if (Gdk.ModifierType.SHIFT_MASK in event.state) { - key = "" + key; + /* We don't need to perform search if there is nothing to search... */ + if (!has_search_term) { + return false; } - switch (key) { - case "Return": - case "Up": - search_previous (); - return true; - case "Return": - case "Down": - search_next (); - return true; - case "Tab": - if (search_entry.is_focus) { - replace_entry.grab_focus (); - } - - return true; + string key = Gdk.keyval_name (keyval); + if (Gdk.ModifierType.SHIFT_MASK in state) { + key = "" + key; } - return false; - } + if (search_is_focused) { + switch (key) { + case "Return": + case "Up": + search_previous (); + return true; + case "Return": + case "Down": + search_next (); + return true; + case "Tab": + focus_replace_entry (); + return true; + } + } else { + switch (Gdk.keyval_name (keyval)) { + case "Up": + search_previous (); + return true; + case "Down": + search_next (); + return true; + case "Tab": + focus_search_entry (); + return true; + } - private bool on_replace_entry_key_press (Gdk.EventKey event) { - /* We don't need to perform search if there is nothing to search… */ - if (search_entry.text == "") { return false; } - switch (Gdk.keyval_name (event.keyval)) { - case "Up": - search_previous (); - return true; - case "Down": - search_next (); - return true; - case "Tab": - if (replace_entry.is_focus) { - search_entry.grab_focus (); - } - - return true; - } - return false; }