Как включить длинную прокрутку меню gtk? - PullRequest
1 голос
/ 23 мая 2019

Я портирую программу с Linux Ubuntu 16.04 на Ubuntu 18.04 и 19. Я использую appindicator-1.0 вместе с меню Gtk + 2.0.Меню состоит из постоянных пунктов и множества динамически добавляемых пунктов.Если разрешение экрана не так хорошо, как должно быть, тогда последние пункты меню не видны.Ubuntu 16.04 автоматически добавляет верхнюю и нижнюю полосы со стрелками «^» и «v» для прокрутки меню, когда указатель мыши находится над этими полосами.Но в Linux Ubuntu 18.04 и 19 такие полосы прокрутки не появляются!Куда мне копать, чтобы решить эту проблему?

Кажется, проблема в настройках Gtk или Gnome ... Но настройки Gtk в dconf-editor похожи на Ubuntu 16.04 и 18.04./etc/gtk+-2.0 тоже самое.~ / .gtkrc-2.0 отсутствует.С другой стороны, прокрутка меню работает в любом месте в обычном окне GTK с панелью меню.Ubuntu 16.04 и Ubuntu 18.04 используют одну и ту же версию libappindicator 12.10.1.Означает ли это, что виноват appindicator?

$ cat menu.c 
#include <gtk/gtk.h>
#include <libappindicator/app-indicator.h>

#define LOGO_PNG "/home/super/my-project/menu-test/logo.png"

AppIndicator* c_indicator;
GtkWidget* c_menu;

void menu_quit_cb(GtkMenuItem* menuitem, gpointer user_data)
{
    gtk_main_quit();
}

int main(int argc, char *argv[])
{
    gtk_init(&argc, &argv);

    int i;
    GtkWidget* item;
    char title[128];

    c_menu = gtk_menu_new();

    item = gtk_menu_item_new_with_label("Quit");
    g_signal_connect(item, "activate", G_CALLBACK(menu_quit_cb), NULL);
    gtk_menu_shell_append(GTK_MENU_SHELL(c_menu), item);
    gtk_widget_show(item);

    gtk_menu_shell_append(GTK_MENU_SHELL(c_menu), gtk_separator_menu_item_new());

    for (i = 1; i <= 100; ++i) {
        snprintf(title, sizeof(title), "Item #%03u", i);
        item = gtk_menu_item_new_with_label(title);
        gtk_menu_shell_append(GTK_MENU_SHELL(c_menu), item);
        gtk_widget_show(item);
    }

    //

    c_indicator = app_indicator_new("Menu Test", LOGO_PNG, APP_INDICATOR_CATEGORY_APPLICATION_STATUS);
    app_indicator_set_status(c_indicator, APP_INDICATOR_STATUS_ACTIVE);
    app_indicator_set_icon(c_indicator, LOGO_PNG);
    app_indicator_set_menu(c_indicator, GTK_MENU(c_menu));

    gtk_main();

    return 0;
}

Я ожидаю того же поведения в меню в Linux Ubuntu 16.04 и 18.04.

Новая информация:

Кажется, это ошибка.Я сделал отчет об этом на bugs.launchpad.net и gitlab.gnome.org .

В качестве обходного пути я подключился к сигналу APP_INDICATOR_SIGNAL_SCROLL_EVENT приложения иреализовал прокрутку как часть моего кода:

#include <gtk/gtk.h>
#include <libappindicator/app-indicator.h>
#include <time.h>

#define LOGO_PNG "/home/super/my-project/menu-test/logo.png"

#define AMOUNT_OF_CONSTANT_ITEMS    (2)
#define AMOUNT_OF_DYNAMIC_ITEMS     (75)

AppIndicator* c_indicator;
GtkWidget* c_menu;
GtkWidget* c_item[AMOUNT_OF_DYNAMIC_ITEMS] = { NULL };
gint c_item_first = 0; // GTK_MENU_ITEM(c_item[c_item_first]) is the first visible dynamic item

static struct timespec time_diff(struct timespec end, struct timespec start)
{
    struct timespec temp;
    if (end.tv_nsec < start.tv_nsec) {
        temp.tv_sec = end.tv_sec - start.tv_sec - 1;
        temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
    } else {
        temp.tv_sec = end.tv_sec - start.tv_sec;
        temp.tv_nsec = end.tv_nsec - start.tv_nsec;
    }
    return temp;
}

static gboolean not_elapsed_enough()
{
    static struct timespec last_moment = { 0, 0 };
    struct timespec current_moment;
    struct timespec temp;

    clock_gettime(CLOCK_MONOTONIC_COARSE, &current_moment);
    if (0 == last_moment.tv_sec && 0 == last_moment.tv_nsec) {
        last_moment = current_moment;
        return FALSE;
    }
    temp = time_diff(current_moment, last_moment);
    if (temp.tv_sec == 0 && temp.tv_nsec < 99999999)
        return TRUE; // do not enough time elapsed
    last_moment = current_moment;
    return FALSE;
}

void appind_scroll_event_cb(AppIndicator* indicator, gint delta, GdkScrollDirection direction, gpointer user_data)
{
    if (not_elapsed_enough()) return;

    if (GDK_SCROLL_UP == direction) {
        GtkWidget* item = c_item[c_item_first];
        g_object_ref(item); // do not destroy item togather with container
        gtk_container_remove(GTK_CONTAINER(c_menu), item); // remove item from menu
        gtk_menu_shell_insert(GTK_MENU_SHELL(c_menu), item, AMOUNT_OF_CONSTANT_ITEMS + AMOUNT_OF_DYNAMIC_ITEMS);
        g_object_unref(item);
        gtk_widget_show(item);
        ++c_item_first;
        if (c_item_first >= AMOUNT_OF_DYNAMIC_ITEMS)
            c_item_first = 0;
    } else if (GDK_SCROLL_DOWN == direction) {
        if (0 == c_item_first)
            c_item_first = AMOUNT_OF_DYNAMIC_ITEMS;
        --c_item_first;
        GtkWidget* item = c_item[c_item_first];
        g_object_ref(item);
        gtk_container_remove(GTK_CONTAINER(c_menu), item);
        gtk_menu_shell_insert(GTK_MENU_SHELL(c_menu), item, AMOUNT_OF_CONSTANT_ITEMS);
        g_object_unref(item);
        gtk_widget_show(item);
    }
}

int main(int argc, char *argv[])
{
    gtk_init(&argc, &argv);

    int i;
    GtkWidget* item;
    char title[128];

    c_menu = gtk_menu_new();

    item = gtk_menu_item_new_with_label("Quit");
    g_signal_connect(item, "activate", G_CALLBACK(gtk_main_quit), NULL);
    gtk_menu_shell_append(GTK_MENU_SHELL(c_menu), item);
    gtk_widget_show(item);

    item = gtk_menu_item_new_with_label("---------------------");
    gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE);
    gtk_menu_shell_append(GTK_MENU_SHELL(c_menu), item);
    gtk_widget_show(item);

    for (i = 1; i <= AMOUNT_OF_DYNAMIC_ITEMS; ++i) {
        snprintf(title, sizeof(title), "Item #%03u", i);
        item = gtk_menu_item_new_with_label(title);
        gtk_menu_shell_append(GTK_MENU_SHELL(c_menu), item);
        gtk_widget_show(item);
        c_item[i - 1] = item;
    }

    //

    c_indicator = app_indicator_new("Menu Test", LOGO_PNG, APP_INDICATOR_CATEGORY_APPLICATION_STATUS);
    app_indicator_set_status(c_indicator, APP_INDICATOR_STATUS_ACTIVE);
    app_indicator_set_icon(c_indicator, LOGO_PNG);
    app_indicator_set_menu(c_indicator, GTK_MENU(c_menu));
    g_signal_connect(c_indicator, APP_INDICATOR_SIGNAL_SCROLL_EVENT, G_CALLBACK(appind_scroll_event_cb), NULL);

    gtk_main();

    return 0;
}

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

...