jankat
(jen)
March 6, 2025, 8:45pm
1
Hello, I am having trouble adding custom keyboard shortcuts to gtk4 application. I just need to call a simple function like.
void printmsg(void) {
printf(“hello, world\n”);
}
Documentation goes over accelerators but it only shows how to set shortcuts for “actions” like “window.close” and I couldn’t figure out how to make custom actions for existing classes either.
Thank you!
CodedOre
(CodedOre)
March 6, 2025, 8:49pm
2
You can add new actions by running Gtk.WidgetClass.install_action
:
However, this only works when initially setting up the class, and therefore only for a subclass.
Is there a good reason you can’t use a subclass of Gtk.Widget
?
Hi,
I usually use actions for that, but there seems to be another way:
jankat
(jen)
March 6, 2025, 10:59pm
5
Hello, thank you for the instructions and links, I really appreciate it.
I couldn’t get it to work tho, here is what I put together for now.
/* window */
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "MMenu");
gtk_window_set_default_size(GTK_WINDOW(window), 600, 250);
/* shortcut */
GtkEventController *controller = gtk_shortcut_controller_new();
gtk_widget_add_controller(window, controller);
GtkShortcutAction *action = gtk_callback_action_new(printmsg, NULL, NULL);
GtkShortcutTrigger *trigger = gtk_shortcut_trigger_parse_string("<Alt>c");
GtkShortcut *shortcut = gtk_shortcut_new(trigger, action);
gtk_shortcut_controller_add_shortcut(GTK_SHORTCUT_CONTROLLER(controller), shortcut);
printmsg:
gboolean printmsg(GtkWidget *widget, GVariant *args, gpointer user_data) {
printf("hello, world");
return true;
}
I messed around with gtk_keyval_trigger_new but it was the same result.
Could you please explain how you use actions? That could work just well.
CodedOre
(CodedOre)
March 7, 2025, 8:32am
6
First of all, you want your window
to be a subclass of Gtk.ApplicationWindow
. This allows you to extend it, for example with new actions.
Then, when the class is initialized, you run Gtk.WidgetClass.install_action
to add the action to the subclass.
Using C, this should look similar to this:
// The class structure
struct _ExampleAppWindow
{
GtkApplicationWindow parent;
};
// Definition of subclass
G_DEFINE_TYPE(ExampleAppWindow, example_app_window, GTK_TYPE_APPLICATION_WINDOW);
// Instance initialization (run for every instance)
static void
example_app_window_init (ExampleAppWindow *app)
{
}
// Class initialization (run onces for the class)
static void
example_app_window_class_init (ExampleAppWindowClass *class)
{
// Install actions here like this
gtk_widget_class_install_action(*class, "window.printmsg", NULL, example_app_window_printmsg)
}
// Constructor for window subclass
ExampleAppWindow *
example_app_window_new (ExampleApp *app)
{
return g_object_new (EXAMPLE_APP_WINDOW_TYPE, "application", app, NULL);
}
// Your callback function for the action
void
example_app_window_printmsg (Gtk.Widget *widget, const char *action_name, GVariant *parameter)
{
// Run your action code here
}
You can install actions to any custom widget in this way, it just needs to be a subclass you’ve defined.
1 Like
Note that subclassing is not strictly necessary to add actions.
It’s also possible to insert a Gio.SimpleActionGroup()
to any widget, and add custom actions to it.
I gave a few examples in old topics:
1 Like
Strange, your code looks fine…
I tried this in Python, and it works:
c = Gtk.ShortcutController()
a = Gtk.CallbackAction.new(lambda *_a: print(_a) or True, None, None)
t = Gtk.ShortcutTrigger.parse_string("<Control>l")
s = Gtk.Shortcut.new(t, a)
c.add_shortcut(s)
window.add_controller(c)
Also, be careful, some <Alt>
shortcuts are captured by desktop environments, so won’t reach your app.
xerxes2
(Jens Persson)
March 7, 2025, 5:25pm
9
Like gwillems first said, I usually just use actions for hotkeys. But using shortcuts seems to work fine too.
import gi
from gi.repository import Gio
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk
class Main:
def __init__(self, app):
self.window = Gtk.ApplicationWindow.new(app)
_action = Gio.SimpleAction.new("action0", None)
_action.connect("activate", self.action_callback)
app.add_action(_action)
app.set_accels_for_action("app.action0", ["<Ctrl>h"])
c = Gtk.ShortcutController()
a = Gtk.CallbackAction.new(self.action_callback, None, None)
t = Gtk.ShortcutTrigger.parse_string("<Control>l")
s = Gtk.Shortcut.new(t, a)
c.add_shortcut(s)
self.window.add_controller(c)
self.window.present()
def action_callback(self, _1, _2, _3=None, _4=None):
print("hello world")
app = Gtk.Application()
app.connect('activate', Main)
app.run(None)
jankat
(jen)
March 7, 2025, 10:39pm
10
Thank you, I will definitely look into this.
1 Like
jankat
(jen)
March 7, 2025, 10:41pm
11
I will have to read about subclasses to try this but it looked like something too advanced for a simple process so I didn’t look much into this. Still, if it can solve the problem I have zero complaints.
jankat
(jen)
March 7, 2025, 10:43pm
12
Thank you very much for the example, it works perfectly. I will still check other suggested methods to see if there is any simpler ways but this definetely solves my current problem.
Holger
March 8, 2025, 11:10am
13
Here is another example of how I worked it out for myself:
/*
* Mo 11. Nov 11:38:44 CET 2024
*/
#include"shortcout-callback.h"
gboolean callback( GtkWidget* widget, GVariant* args, gpointer user_data)
{
g_print("Callback\n");
}
void destroy(gpointer data)
{
g_print("destroy\n");
}
void activate (GtkApplication *app, gpointer data)
{
GtkWidget *window;
GtkEventController *shortcut_controller;
GtkShortcut *shortcut;
GtkShortcutTrigger *trigger;
GtkShortcutAction *action;
window =gtk_application_window_new(app);
gtk_widget_set_size_request(window,50,50);
// Create a GtkShortCutTrigger
trigger = gtk_shortcut_trigger_parse_string ("<Control><Alt>S");
// create a GtkShortCutCallback
action = gtk_callback_action_new (callback, data, destroy);
//Create a ShortCut - Connect action to the trigger
shortcut =gtk_shortcut_new (trigger, action);
// Creating a Shortcut Controller
shortcut_controller = gtk_shortcut_controller_new();
// Area for which the controller works
// gtk_shortcut_controller_set_scope (GTK_SHORTCUT_CONTROLLER(shortcut_controller),GTK_SHORTCUT_SCOPE_MANAGED);
// gtk_shortcut_controller_set_scope (GTK_SHORTCUT_CONTROLLER(shortcut_controller),GTK_SHORTCUT_SCOPE_LOCAL);
gtk_shortcut_controller_set_scope (GTK_SHORTCUT_CONTROLLER(shortcut_controller),GTK_SHORTCUT_SCOPE_GLOBAL);
//Add a shortcut
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER(shortcut_controller),shortcut);
// Setting the ShortCutController on the widget
gtk_widget_add_controller (window,shortcut_controller);
gtk_widget_set_visible(window,TRUE);
}
Have fun testing and programming
system
(system)
Closed
March 22, 2025, 11:10am
14
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.