Gtk::Notebook with different accelerators on each page



Hi,

I've got a little problem with a Gtk::Notebook with different context menus
on each page. Some of the context menus have accelerators and obviously, I
only want the accelerators of the context menu on the current notebook page
to be active.

So the question is how to call Gtk::Menu::accelerate() for each context menu
properly. No matter whether I pass it the toplevel Gtk::Window as argument
or one of the widgets contained on the notebook pages, accelerate() will
always look up the toplevel window for me and add all accelerators of all
context menus there. Obviously, this is not what I want, because then, all
accelerators are active all the time and if there are overlapping
accelerators on different pages, only the first one will ever be called.
This problem is demonstated by running the sample application below with
"./acceltest --accelerate-toplevel". Pressing Ctrl-C and Ctrl-V will always
call copyPage1()/pastePage2(), regardless of the current notebook page.

Next idea: Use different Gtk::AccelGroups and call
Gtk::Window::add_accel_group()/remove_accel_group() such that only the
accelerators for the currently mapped page are added. Complicated by the
fact that Gtk::Menu::accelerate() ultimately expects a Gtk::Window instead
of a Gtk::AccelGroup, so I use dummy Gtk::Windows just for accelerator
storage. This nearly works, however, only for accelerator keys defined on
the first notebook page. If the same accelerator key is used on the 2nd
page, it works there and calls the right function, but accelerators keys
defined only on the 2nd page don't work at all. Demonstrated by running
"./acceltest" and pressing Ctrl-C and Ctrl-V on both pages. copyPage1() and
copyPage2() will be called properly, but pastePage2() isn't.

How am I supposed to do this properly with gtkmm?

Thanks,
Martin



/* Compile with:
gcc -o acceltest acceltest.cc -Wall $(pkg-config --cflags --libs gtkmm-2.4)
*/
#include <string>
#include <iostream>
#include <gtkmm.h>


using namespace std;


class NotebookPage: public Gtk::EventBox {
  public:
    NotebookPage();
    Gtk::Menu & get_menu() { return mContextMenu; }
    Gtk::Window & get_accel_window() { return mAccelWindow; }
    bool on_button_press_event(GdkEventButton *ev);
    void on_map();
    void on_unmap();
    
  private:
    Gtk::Menu mContextMenu;
    Gtk::Window mAccelWindow;
};

class MainWin: public Gtk::Window {
  public:
    MainWin(bool accelerateToplevel);
    
  private:
    Gtk::Notebook mNotebook;
    NotebookPage mPage1, mPage2;
    
    void copyPage1() { cerr << "Copy Page 1" << endl; }
    void copyPage2() { cerr << "Copy Page 2" << endl; }
    void pastePage2() { cerr << "Paste Page 2" << endl; }
};


NotebookPage::NotebookPage() {
  set_size_request(100, 100);
}


bool
NotebookPage::on_button_press_event(GdkEventButton *ev) {
  if (ev->type == GDK_BUTTON_PRESS && ev->button == 3) {
    mContextMenu.popup(ev->button, ev->time);
    return true;
  }
  return false;
}


void
NotebookPage::on_map() {
  Gtk::EventBox::on_map();
  Gtk::Window *w = dynamic_cast<Gtk::Window *>(get_toplevel());
  if (w) {
    w->add_accel_group(mAccelWindow.get_accel_group());
  }
}


void
NotebookPage::on_unmap() {
  Gtk::Window *w = dynamic_cast<Gtk::Window *>(get_toplevel());
  if (w) {
    w->remove_accel_group(mAccelWindow.get_accel_group());
  }
  Gtk::EventBox::on_unmap();
}


MainWin::MainWin(bool accelerateToplevel) {
  mPage1.get_menu().items().push_back(
      Gtk::Menu_Helpers::MenuElem("Copy Page 1", Gtk::AccelKey("<control>C"),
      sigc::mem_fun(*this, &MainWin::copyPage1)));
  mPage1.get_menu().accelerate(accelerateToplevel ? *this : mPage1.get_accel_window());
  
  mPage2.get_menu().items().push_back(
      Gtk::Menu_Helpers::MenuElem("Copy Page 2", Gtk::AccelKey("<control>C"),
      sigc::mem_fun(*this, &MainWin::copyPage2)));
  mPage2.get_menu().items().push_back(
      Gtk::Menu_Helpers::MenuElem("Paste Page 2", Gtk::AccelKey("<control>V"),
      sigc::mem_fun(*this, &MainWin::pastePage2)));
  mPage2.get_menu().accelerate(accelerateToplevel ? *this : mPage2.get_accel_window());
  
  mNotebook.append_page(mPage1, "Page 1");
  mNotebook.append_page(mPage2, "Page 2");
  add(mNotebook);
  show_all();
}


int
main(int argc, char *argv[]) {
  Gtk::Main m(argc, argv);
  MainWin w(argc >= 2 && string(argv[1]) == "--accelerate-toplevel");
  m.run(w);
  return 0;
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]