Reputation: 1327
I've been writing a Gtk+ application using gtkmm, and I'm trying to add a global keyboard shortcut which calls a callback. Unfortunately, the connect() method of Gtk::AccelGroup isn't available in gtkmm, apparently intentionally because you can make the connections using ActionGroups...
Anyway, I have the following code:
actions_= Gtk::ActionGroup::create();
actions_->set_accel_group(Gtk::AccelGroup::create());
actions_->add(
Gtk::Action::create("new"), Gtk::AccelKey("<control>n"),
sigc::mem_fun(this, &Window::new_buffer_thing)
);
_gtk_window().add_accel_group(actions_->get_accel_group());
Which compiles and runs without warning, but the keyboard shortcut does nothing. I've been fiddling with this for hours, so any help or direction would be appreciated!
Am I doing something obviously wrong? Why wouldn't the accelerator work?
Upvotes: 5
Views: 1791
Reputation: 361
After reading mariotomo's answer, here's my implementation of hidden menubar for gtkmm3.
Shortcut key accelerator works for hidden menubar :)
#include <iostream>
#include <gtkmm.h>
using Gtk::Application;
using Gtk::Box;
using Gtk::Builder;
using Gio::SimpleActionGroup;
using std::cout;
class ExampleWindow : public Gtk::Window
{
public:
ExampleWindow(const Glib::RefPtr<Application>& app);
private:
void on_action_file_new();
// for hidden menubar
void on_action_secret();
Box box1;
Box box2;
Glib::RefPtr<Builder> builder;
Glib::RefPtr<SimpleActionGroup> actiongroup;
};
ExampleWindow::ExampleWindow(const Glib::RefPtr<Application>& app)
: box1(Gtk::ORIENTATION_VERTICAL)
, box2(Gtk::ORIENTATION_VERTICAL)
{
set_title("Menubar test");
set_default_size(400, 200);
add(box1);
box1.add(box2);
//Define the actions:
actiongroup = Gio::SimpleActionGroup::create();
actiongroup->add_action("new" , sigc::mem_fun(*this, &ExampleWindow::on_action_file_new));
actiongroup->add_action("secret", sigc::mem_fun(*this, &ExampleWindow::on_action_secret));
insert_action_group("example" , actiongroup);
insert_action_group("example-hidden", actiongroup);
builder = Gtk::Builder::create();
app->set_accel_for_action("example.new" , "<Primary>n");
app->set_accel_for_action("example-hidden.secret", "<Primary>m");
const char *visible_ui_info =
"<interface>"
" <menu id='visible-menubar'>"
" <submenu>"
" <attribute name='label' translatable='yes'>_File</attribute>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_New</attribute>"
" <attribute name='action'>example.new</attribute>"
" <attribute name='accel'><Primary>n</attribute>"
" </item>"
" </section>"
" </submenu>"
" </menu>"
"</interface>";
const char *hidden_ui_info =
"<interface>"
" <menu id='hidden-menubar'>"
" <submenu>"
" <attribute name='label' translatable='yes'>_Secret</attribute>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Key</attribute>"
" <attribute name='action'>example-hidden.secret</attribute>"
" <attribute name='accel'><Primary>m</attribute>"
" </item>"
" </section>"
" </submenu>"
" </menu>"
"</interface>";
builder->add_from_string(visible_ui_info);
builder->add_from_string(hidden_ui_info);
// Get the visible menubar:
auto object1 = builder->get_object("visible-menubar");
auto gmenu1 = Glib::RefPtr<Gio::Menu>::cast_dynamic(object1);
auto menubar1 = Gtk::make_managed<Gtk::MenuBar>(gmenu1);
box1.pack_start(*menubar1, Gtk::PACK_SHRINK);
// Get the hidden menubar
auto object2 = builder->get_object("hidden-menubar");
auto gmenu2 = Glib::RefPtr<Gio::Menu>::cast_dynamic(object2);
auto menubar2 = Gtk::make_managed<Gtk::MenuBar>(gmenu2);
box2.pack_start(*menubar2, Gtk::PACK_SHRINK);
show_all_children();
box2.hide();
}
void ExampleWindow::on_action_file_new()
{
cout << "New menu item was selected.\n";
}
void ExampleWindow::on_action_secret()
{
cout << "Secret menu item was selected.\n";
}
int main()
{
auto app = Application::create("org.gtkmm.example");
ExampleWindow window(app);
return app->run(window);
}
Upvotes: 0
Reputation: 9728
a bit late to answer this, but I've been working at this same problem today, even if in a different environment: python, gtk2.
as far as I understand from a little experimenting with this tutorial, actions won't be active unless associated to a toolbox or a menubar. too bad, just do that, pack the toolbar into a VBox, and make it invisible, something like this:
actiongroup = gtk.ActionGroup('window-clip-actions')
accelgroup = gtk.AccelGroup()
fake_toolbar = gtk.Toolbar()
view.get_window().add_accel_group(accelgroup)
view.get_window().get_content_area().pack_start(fake_toolbar)
for shortcut, cb in (('<ctrl><shift>c', self.on_window_clip_copy),
('<ctrl><shift>v', self.on_window_clip_paste)):
action = gtk.Action(shortcut, shortcut, 'clip-action', None)
actiongroup.add_action_with_accel(action, shortcut)
action.connect("activate", cb)
action.set_accel_group(accelgroup)
action.connect_accelerator()
toolitem = action.create_tool_item()
fake_toolbar.insert(toolitem, -1)
fake_toolbar.set_visible(False)
it would be interesting to know if the same approach would help the OP.
Upvotes: 1