Добры молодцы из команды GTK навертали чертову уйму классов для отделения логики от интерфейса. Все эти GtkAction, GtkUiManager, GtkActivatable и прочие упоительные названия.
У GtkAction есть имя, иконка, тултип, состояния sensetive и visible. На их основе генерируется внешний вид и состояния менюшечек и тулбаров. Короче, всё как у взрослых.
Почти. Если не считать того досадного факта, что тултип абсолютно бесполезен, т.к. не используется при создании меню.
Ладно. Решаю по-быстрому накалякать пару костылей — у нас же ООП, реюз кода во все поля и всё такое прочее. Мы можем переопределять поведение объектов и разводить руками тучи.
GtkImageMenuItem реализует интерфейс GtkActivatable и через него получает апдейты состояния. Ок, унаследуем свой класс от GtkImageMenuItem и допишем нужный код по установке тултипа.
GtkAction рожает из себя менюшки на основе класса, указанного в одном из полей своего класса. Ок, унаследуем свой класс от GtkAction и переопределим поле, засунув туда собственный класс менюитема.
Всё красиво, всё поООПшному, архитектурные космонавты в восторге.
Стоп. Про что-то мы забыли. А кто создаёт GtkAction-ы? GtkAction-ы создаёт GtkActionGroup. Открываем код. Смотрим. Еще раз смотрим. Хлопаем глазами и не верим в то, что видим:
void
gtk_action_group_add_actions_full (GtkActionGroup       *action_group,
				   const GtkActionEntry *entries,
				   guint                 n_entries,
				   gpointer              user_data,
				   GDestroyNotify        destroy)
{
  /* Keep this in sync with the other 
   * gtk_action_group_add_..._actions_full() functions.
   */
  guint i;
  SharedData *shared_data;
  g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
  shared_data = g_slice_new0 (SharedData);
  shared_data->ref_count = 1;
  shared_data->data = user_data;
  shared_data->destroy = destroy;
  for (i = 0; i < n_entries; i++)
    {
      GtkAction *action;
      const gchar *label;
      const gchar *tooltip;
      if (!check_unique_action (action_group, entries[i].name))
        continue;
      label = gtk_action_group_translate_string (action_group, entries[i].label);
      tooltip = gtk_action_group_translate_string (action_group, entries[i].tooltip);
      action = gtk_action_new (entries[i].name,
			       label,
			       tooltip,
			       NULL);
Даааа, дааа, да! Развесистое дерево наследований. Абстрактные интерфейсы. Переменные класса. Фантастика на грани техники. Чертова уйма overengineered кода, который абсолютно бесполезен, потому что в итоге всё равно вся эта развесистая космическая архитектура запинается о вовремя подставленный gtk_action_new(), падает и разбивается к едреней фене. И хоронит под собой все ваши иллюзии, будто ООП волшебным образом превращает всех плохих программистов в хороших. Enjoy your code reuse.
А, да: баг репортить не буду. Если кому надо, репортите сами. Я ж обещал, что к разработке стека гномобиблиотек и пальцем не притронусь, даже на уровне отсылки багов. Лучше пойду придумаю обычный костыль с ручным назначением тултипов, без всей этой архитектурной космонавтики.
