Linux -- это интересно

Как убрать меню в GTK-приложениях?


Рубрика: Hужное/полезное
Метки: | |
Просмотров: 6806

gtk без меню

Вам никогда не хотелось бы убрать меню у большинства программ? Оказывается, есть достаточно простой способ.

Скажу по себе, в меню большинства графических приложений я лезу крайне редко. Тогда зачем мне его постоянно видеть. Ведь оно занимает и лишнее место на экране, и портит внешний вид программы.

Недавно на LOR'e я встретил простое решение, которое позволяет скрыть меню у GTK-приложений. Используя горячие клавиши alt-m и ctrl-m можно прятать/показывать это самое меню, а так же есть возможность указать, для каких программ всё оставить как есть.

В каких же приложениях меню лучше не убирать? Для примера, это Gnome-Terminal. Если его не указать в исключениях, то меню вы не увидите вовсе :) Кстати, оно там и так убирается. Потом, Gimp. Тут, думаю, без комментариев. Так же, меня ждал подводный камень с Gnome-Panel. После перезагрузки с него пропали "Приложения, Переход, Система" и кнопка завершения сеанса/работы.

Остальное - по своему желанию.

Вот код библиотеки:

/*
gcc -shared  `pkg-config gtk+-x11-2.0 --cflags --libs` -o libwinmenu.so main.c
*/
#include <gtk gtk.h="">
#include <gdk gdkkeysyms.h="">
#define _gtk_marshal_VOID__VOID g_cclosure_marshal_VOID__VOID
#define _gtk_marshal_NONE__NONE _gtk_marshal_VOID__VOID
static GObject* (*old_gtk_menu_bar_constructor)(GType type, guint n_construct_properties, GObjectConstructParam *construct_params) = NULL;
static GObject* (*old_gtk_window_constructor)(GType type, guint n_construct_properties, GObjectConstructParam *construct_params) = NULL;
static void     (*old_widget_show) (GtkWidget * widget) = NULL;
static void toggle_menu_bar (GtkWidget *widget, gpointer user_data)
{
   GtkWidget * wdg = GTK_WIDGET(user_data);
   GTK_WIDGET_GET_CLASS(wdg)->show = old_widget_show;
   if (GTK_WIDGET_VISIBLE(wdg))
      gtk_widget_hide(wdg);
   else
      gtk_widget_show(wdg);
}
static void anchor_event (GtkWidget *widget, GtkWidget *previous_toplevel, gpointer   user_data)
{
   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
   if (GTK_WIDGET_TOPLEVEL (toplevel)) {
      if (previous_toplevel) 
          g_signal_handlers_disconnect_by_func(previous_toplevel, G_CALLBACK(toggle_menu_bar), widget);
      g_signal_connect (toplevel, "toggle-menu-bar", G_CALLBACK(toggle_menu_bar), widget);
    }
}
static void show (GtkWidget *widget)
{
   if (GTK_IS_MENU_BAR(widget))
      return;
   old_widget_show(widget);
}
GObject* new_gtk_menu_bar_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params)
{
   GObject * ret = old_gtk_menu_bar_constructor(type,n_construct_properties,construct_params);
   g_signal_connect (ret, "hierarchy-changed", G_CALLBACK(anchor_event), NULL);
   g_signal_connect (ret, "can_activate_accel", G_CALLBACK(gtk_true), NULL);
   return ret;
}
G_MODULE_EXPORT void
gtk_module_init (gint * argc, gchar *** argv)
{
   GtkWidget *fc;
   GObjectClass *klass;
   const gchar *app_whitelist = "gnome-terminal, gimp, mousepad, gnome-panel, gimp-2.6";
   if (strstr (app_whitelist, g_get_prgname()) != NULL)
    return;
   g_signal_new ("toggle-menu-bar",
                 GTK_TYPE_WINDOW,
                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                 0,
                 NULL, NULL,
                 _gtk_marshal_VOID__VOID,
                 G_TYPE_NONE,
                 0);
   fc = gtk_menu_bar_new();
   klass = GTK_MENU_BAR_GET_CLASS(fc);
   old_gtk_menu_bar_constructor = klass->constructor;
   klass->constructor = new_gtk_menu_bar_constructor;
   old_widget_show = GTK_WIDGET_CLASS(klass)->show;
   GTK_WIDGET_CLASS(klass)->show = show;
   fc = gtk_window_new(GTK_WINDOW_TOPLEVEL);
   klass = GTK_WINDOW_GET_CLASS(fc);
   gtk_binding_entry_add_signal (gtk_binding_set_by_class (klass), GDK_m, GDK_CONTROL_MASK,
                                "toggle-menu-bar", 0);
   gtk_binding_entry_add_signal (gtk_binding_set_by_class (klass), GDK_m, GDK_MOD1_MASK,
                                "toggle-menu-bar", 0);
}

Сохраняем его в файле main.c и собираем командой:

gcc -shared `pkg-config gtk+-x11-2.0 --cflags --libs` -o libwinmenu.so main.c

Далее, полученную libwinmenu.so нужно скопировать в нужное место:

sudo cp libwinmenu.so /usr/lib/gtk-2.0/modules/
После чего надо прописать в ~/.gnomerc или в ~/.xinitrc или в ~/.xsession строку:
export GTK_MODULES=winmenu

Ну, вот и всё. Теперь при запуске GTK-приложений меню по умолчанию будет спрятано.

Так же, я пользуюсь браузером SeaMonkey. Для него есть плагин Compact Menu 2, которым так же поддерживаются Thunderbird и Firefox.

На этом всё. Большинство повседневно используемых мной приложений стали выглядеть немного аккуратнее :)

PS "белый список" приложений находится в строке:

const gchar *app_whitelist = "gnome-terminal, gimp, mousepad, gnome-panel, gimp-2.6";
Комментариев: 2 RSS

Как вариант, можно еще апплет Globalmenu установить, тогда меню будет на панели, а не в окне приложения, что, например, для того же Gimp просто офигенно удобно.

https://launchpad.net/~globalmenu-team/+archive/ppa

Спасибо большое, все работает отлично!

Система: Linux Mint 13

Данная штучка работает только не совсем так как описано выше, в нашем случае библиотеки заголовочных файлов не находятся так как неверно указано название файлов, ниже я выкладываю рабочий пример проверенный мною, и подходящий для большинства debian-оподобных.

/*
gcc -shared  `pkg-config gtk+-x11-2.0 --cflags --libs` -o libwinmenu.so main.c
*/
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#define _gtk_marshal_VOID__VOID g_cclosure_marshal_VOID__VOID
#define _gtk_marshal_NONE__NONE _gtk_marshal_VOID__VOID
static GObject* (*old_gtk_menu_bar_constructor)(GType type, guint n_construct_properties, GObjectConstructParam *construct_params) = NULL;
static GObject* (*old_gtk_window_constructor)(GType type, guint n_construct_properties, GObjectConstructParam *construct_params) = NULL;
static void     (*old_widget_show) (GtkWidget * widget) = NULL;
static void toggle_menu_bar (GtkWidget *widget, gpointer user_data)
{
   GtkWidget * wdg = GTK_WIDGET(user_data);
   GTK_WIDGET_GET_CLASS(wdg)->show = old_widget_show;
   if (GTK_WIDGET_VISIBLE(wdg))
      gtk_widget_hide(wdg);
   else
      gtk_widget_show(wdg);
}
static void anchor_event (GtkWidget *widget, GtkWidget *previous_toplevel, gpointer   user_data)
{
   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
   if (GTK_WIDGET_TOPLEVEL (toplevel)) {
      if (previous_toplevel) 
          g_signal_handlers_disconnect_by_func(previous_toplevel, G_CALLBACK(toggle_menu_bar), widget);
      g_signal_connect (toplevel, "toggle-menu-bar", G_CALLBACK(toggle_menu_bar), widget);
    }
}
static void show (GtkWidget *widget)
{
   if (GTK_IS_MENU_BAR(widget))
      return;
   old_widget_show(widget);
}
GObject* new_gtk_menu_bar_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params)
{
   GObject * ret = old_gtk_menu_bar_constructor(type,n_construct_properties,construct_params);
   g_signal_connect (ret, "hierarchy-changed", G_CALLBACK(anchor_event), NULL);
   g_signal_connect (ret, "can_activate_accel", G_CALLBACK(gtk_true), NULL);
   return ret;
}
G_MODULE_EXPORT void
gtk_module_init (gint * argc, gchar *** argv)
{
   GtkWidget *fc;
   GObjectClass *klass;
   const gchar *app_whitelist = "gnome-terminal, gimp, mousepad, gnome-panel, gimp-2.6";
   if (strstr (app_whitelist, g_get_prgname()) != NULL)
    return;
   g_signal_new ("toggle-menu-bar",
                 GTK_TYPE_WINDOW,
                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                 0,
                 NULL, NULL,
                 _gtk_marshal_VOID__VOID,
                 G_TYPE_NONE,
                 0);
   fc = gtk_menu_bar_new();
   klass = GTK_MENU_BAR_GET_CLASS(fc);
   old_gtk_menu_bar_constructor = klass->constructor;
   klass->constructor = new_gtk_menu_bar_constructor;
   old_widget_show = GTK_WIDGET_CLASS(klass)->show;
   GTK_WIDGET_CLASS(klass)->show = show;
   fc = gtk_window_new(GTK_WINDOW_TOPLEVEL);
   klass = GTK_WINDOW_GET_CLASS(fc);
   gtk_binding_entry_add_signal (gtk_binding_set_by_class (klass), GDK_m, GDK_CONTROL_MASK,
                                "toggle-menu-bar", 0);
   gtk_binding_entry_add_signal (gtk_binding_set_by_class (klass), GDK_m, GDK_MOD1_MASK,
                                "toggle-menu-bar", 0);
}

Сборка осуществляется той же командой что и выше или описанной вначале исходника.

Внимание! Собираем из под рута, далее после сборки копируем либу, и теперь самый важный момент.

В описании написано что нужно закинуть строчку инициализации в одного из файла будь то: ~/.gnomerc или в ~/.xinitrc или в ~/.xsession но в моем случае это не сработало, Поскольку у меня DE - Xfce то пришлось закидывать в этот файлик /etc/xdg/xfce4/xinitrc я добавил в секцию где описаны export'ы библиотеки GLADE(#Modify libglade and glade environment variables so that). Вот впринципе и все, извиняюсь если что непонятно объяснил.

Оставьте комментарий!
Используйте нормальные имена.Войти через loginza
Если вы уже зарегистрированы как комментатор или хотите зарегистрироваться, укажите пароль и свой действующий email.
(При регистрации на указанный адрес придет письмо с кодом активации и ссылкой на ваш персональный аккаунт, где вы сможете изменить свои данные, включая адрес сайта, ник, описание, контакты и т.д.)



 
(обязательно)