Click here to Skip to main content
11,922,345 members (39,595 online)
Click here to Skip to main content
Add your own
alternative version

Tagged as


2 bookmarked

A Simpler MRU for GTKMM C++

, 16 Aug 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
Sometimes you need a hammer for a job, not a bazooka

I guess I'm a glutton for punishment, or like the little bird who flies against the wind; I really enjoy developing desktop applications. Now its all about apps for phones and web applications, but I still really enjoy using my desktop and writing applications for it.

The complaint I most often hear from people opposed to adopting Linux as their desktop os is the lack of applications for it. Well, that won't change until people start writing those apps.

As far as desktop application design goes, everything should be as simple as possible, or so my philosophy goes. All components of application design should follow that simple rule where its makes sense, and I see no reason for that principal to not be included in the humble RUF, or Recently Used File list, also known as the MRU, or Most recent, so on...

The MRU (from now on) is a tradition, should be available on any mouse driven GUI, and should be easy to implement in any toolkit or framework. Imagine my surprise when I started doing the research on using the MRU object as implemented in GTKMM; its pretty much the most complicated collection of classes I've ever seen. And to display only the recent files relevant to your application you need to employ some sort of filter, and then there's all the complaints I read about those objects on the web, and after that I stopped worrying about it and wrote my own class.

I have a lot of respect for Murry Cumming and the GTKMM team, and the whole GTK project, its a huge effort to maintain a unified set of APIs and keep them working for a moving platform like GNU/Linux/Gnome, I am surely aware. I'm also aware that there are usually a huge number of underlying reasons as to why a developer or organization implements a feature set the way they do. But sometimes you just want a thing to just work the way you want them to.

When I got a little deeper into how GTKMM's RecentChooser classes (there's the base class Widget, a dialog object, an action object, as well as a menu object, then the filter you need to employ, and on and on) I simply shrugged my shoulders and told myself “I'm not doing that”. I get all the variations, obviously the action object is so you can add a history option to an edit menu, whatever. I just wanted the user to click on a dynamic menu that contained an MRU.

So with the history out of the way I bring you a simpler method using the STL and GTKMM's own menu api:

Using the code

My current application for the gnome Desktop is a classic Model-View-Controller impl with a Menu Bar, and of course under the File item is my MRU.

An MRU at the simplest level is a FIFO, and std::deque is perfect for that job. In my application's data class (a collections of structs, really) reference to a std::deque object.

I started by adding some file menu entries, file 1..4, and binding them to a dummy function. I knew I could change the menu label and bind them to an actual function later (from my application's Glib::ustring ui_info);

"<Menuitem action=<'FileOpen'/>"
"<menuitem action='file1'/>"
"<menuitem action='file2'/>"
"<menuitem action='file3'/>"
"<menuitem action='file4'/>"

(And from my app's Gtk::ActionGroup object):

m_refActionGroup->add(Gtk::Action::create("file1", "file1",
   "Reopen this file"), sigc::mem_fun(*this, &ExampleWindow::on_dummy));
m_refActionGroup->add(Gtk::Action::create("file2", "file1",
   "Reopen this file"), sigc::mem_fun(*this, &ExampleWindow::on_dummy));
m_refActionGroup->add(Gtk::Action::create("file3", "file1",
   "Reopen this file"), sigc::mem_fun(*this, &ExampleWindow::on_dummy));
m_refActionGroup->add(Gtk::Action::create("file4", "file1",
   "Reopen this file"), sigc::mem_fun(*this, &ExampleWindow::on_dummy));

The “on_dummy” method is just an empty method, we need that because the ActionGroup template demands it be filled in, we'll fill it in with the real method later. Those menu entrties must be hidden on our application' initialization, OR filled in with the list generated from the last session;

Gtk::Widget* file1 = m_refUIManager->get_widget("/ui/MenuBar/FileMenu/file1");
Gtk::Widget* file2 = m_refUIManager->get_widget("/ui/MenuBar/FileMenu/file2");
Gtk::Widget* file3 = m_refUIManager->get_widget("/ui/MenuBar/FileMenu/file3");
Gtk::Widget* file4 = m_refUIManager->get_widget("/ui/MenuBar/FileMenu/file4");


My file open menu item, when activated, as well as opening a file, takes the path it got from a file picker and sends it to a method that inserts the file into the deque object, after checking the current size of the deque:

In a header file we have these declarations (more on the signal array 'mru_sig' later):

std::deque<Glib::ustring> mru; // our deque object
sigc::connection mru_sig[4]; // dynamic menu signals

Then in the implementation file, in our “mru manager” method, app is just a pointer to an “application structure”, a struct with the deque object, among other things:

// If the deque is more than four, we need to pop one file off it
if(app->mru.size() >= 4)

// then add the new file

// may not be nessessary

Pretty simple stuff. Now, every time a file is opened it'll be placed in our deque object, and round robin rotated to the bottom of the list ever time a new file is placed on it. In this case I'm keeping the number of recent files at 4, but it would be simple enough to adjust that number or make it user configurable if one wanted by adding an integer class member and using it instead of the “4” constant above.

Then comes the re-assignment of the menu signals, earlier in the method code I point to some empty Gtk::Widgets with a simple array of pointers:

Glib::RefPtr<Gtk::UIManager> m_refUIManager; // Typical GTKMM stuff
Gtk::Widget* file[4];

file[0] = m_refUIManager->get_widget("/ui/MenuBar/FileMenu/file1");
file[1] = m_refUIManager->get_widget("/ui/MenuBar/FileMenu/file2");
file[2] = m_refUIManager->get_widget("/ui/MenuBar/FileMenu/file3");
file[3] = m_refUIManager->get_widget("/ui/MenuBar/FileMenu/file4");

The paths refer to the ui file menus in the Gtk XML gui, if you're familiar with Gtk desktop programming with GTKMM you should be aware of how that works. We'll need these as references for the dynamic menus we'll be connecting the activation signals to. Speaking of which, here's how those signals are connected to our menu items;

int n = 0;

for(deque<Glib::ustring>::iterator it =
   app->mru.begin(); it < app->mru.end(); ++it) {
   const Glib::ustring& label =
      (*it).substr((*it).find_last_of("//") + 1, (*it).length());


   app->mru_sig[n] = dynamic_cast<Gtk::MenuItem*>(file[n])->signal_activate().
      connect(sigc::bind(sigc::mem_fun(*this, &ExampleWindow::on_mru), label));

   if(dynamic_cast<Gtk::MenuItem*>(file[n])->get_label().length() > 0)


We iterate through our list of 4 file paths, take out the last bit for the name we display in the menus, and then we do a generic signal disconnect on the item. If we don't signals will stack up on the item and we'd have several file paths flying at our “open file” method. We then connect a new signal bound with the path data we want the menu item to open.

The signal method is simplicity itself:

on_mru(Glib::ustring& label)
   deque<Glib::ustring>::iterator it = _app->mru.begin();
   for(; it < _app->mru.end(); ++it) {
      const Glib::ustring& text =
         (*it).substr((*it).find_last_of("//") + 1, (*it).length());

      if(text.find(label) != string::npos)
         // this is the file the user clicked on in the MRU
         cout << (*it).c_str() << endl;

The bound text from the label is searched for in the deque object, if we have a match we have our full path to the recently processed file.

Points of Interest

I'm not sure that the dummy method in the initialization area of the dynamic menu's is entirely nessessary, I need to play around with the code and use the actual "on_mru" method if possible, I think I used this technique becuase I didn't have any data to bind to the signal, but an empty string may have been able to serve just as well.

The "on_mru" method just takes the full path to the file from the deque object and displays it in the console, obviously you'll want to pass that off to the application's open file method.

The sample requires libgtkmm 2.4, and build with

g++ -Wall -std=c++11 -o menu `pkg-config --cflags --libs gtkmm-2.4`


1st version 8/15/14


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Tim ONeil
Architect MatterFab
United States United States
Lead architect for software development, MatterFab, Inc.

You may also be interested in...

Comments and Discussions

-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.151120.1 | Last Updated 16 Aug 2014
Article Copyright 2014 by Tim ONeil
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid