gtk_widget_add_tick_callback() и gtk_main_iteration()
У меня два окна GTK
-
Нормальное (основное) окно, которое запускает анимацию, рисует материал в обратном вызове, зарегистрированный gtk_widget_add_tick_callback()
.
-
В какой-то момент создается вторичное окно, которое запускает модальный цикл:
void show_modal()
{
GtkWindow* gw = gtkwindow(this);
if( parent() )
gtk_window_set_transient_for(gw, gtkwindow( parent() ));
gtk_widget_show(GTK_WIDGET(gw));
gtk_window_set_modal(gw,TRUE);
gtk_window_set_keep_above(gw,TRUE);
this->update_window_state(gool::WINDOW_SHOWN);
while( this->is_valid_window() )
{
if(this->_window_state == WINDOW_HIDDEN) break;
if(this->_window_state == WINDOW_STATE_NA) break;
gtk_main_iteration(); // gtk_main_iteration_do(true);
}
}
Проблема. Анимация в главном окне работает нормально до show_modal()
. Он выглядит как gtk_main_iteration();
блокирует тики, добавленные функцией gtk_widget_add_tick_callback()
. Как только я закрываю вторичное окно, и поэтому while() {gtk_main_iteration();}
цикл завершается, анимации в главном окне снова запускаются.
Любая идея о том, как сделать "анимацию дружественных" модальных петель в GTK?
UPDATE: оно выглядит как gtk_main_iteration();
блокирует не только тики, но и любые обновления любых окон, кроме "текущего" - они просто застывают. В чем же причина такого поведения GTK?
ОБНОВЛЕНИЕ # 2:
gtk_dialog_run();
ведет себя точно так же, как gtk_main_iteration();
- блокирует любые обновления в любом окне, кроме активного окна.
Ответы
Ответ 1
Кажется, по определению: link
gboolean gtk_main_iteration (void);
Выполняет одиночную итерацию mainloop. Если никакие события не ожидают обработки GTK+ будет блокироваться до тех пор, пока не будет замечено следующее событие. Если вы не захотите заблокировать просмотр gtk_main_iteration_do()
или проверьте, не gtk_events_pending()
ли какие-либо события с gtk_events_pending()
.
Объяснение предлагает использовать gtk_main_iteration_do(FALSE)
если вы не хотите блокировать:
gboolean gtk_main_iteration_do (gboolean blocking);
Выполняет одиночную итерацию mainloop. Если никакие события не доступны или возвращаются или блокируются в зависимости от значения blocking
: TRUE
если вы хотите GTK+ блокировать, если события не ожидаются
Что касается gtk_dialog_run
: он также блокирует по дизайну ссылку
gint gtk_dialog_run (GtkDialog *dialog);
Блоки в рекурсивном основном цикле до тех пор, пока диалог не испустит "ответный" сигнал или не будет уничтожен. [...]
Я читал о людях, которые решают это, используя несколько потоков: обрабатывайте графический интерфейс в основном потоке и выполняйте фоновую работу в другой. Там статья об этом здесь, что может быть полезным.
Ответ 2
Я предполагаю, что show_modal
вызывается из обратного вызова или другого действия в основном контексте. Вы можете попробовать добавить свое модальное окно в основной контекст, используя invoke или signal_idle.
Таким образом show_modal
выполнения show_modal
закончится.
#include <gtkmm.h>
#include <string>
int main()
{
auto Application = Gtk::Application::create();
Gtk::Window window;
Gtk::Window* window2;
Gtk::Button button;
window.add(button);
//I hope timeout behaves similar to ticks. I have no idea how animations in GTK work
int i=0;
Glib::MainContext::get_default()->signal_timeout().connect([&]()->bool{
button.set_label(std::to_string(i++));
return true;
}, 1000);
button.signal_clicked().connect([&]{
Glib::MainContext::get_default()->invoke([&]()->bool{
window2 = new Gtk::Window;
window2->set_modal(true);
window2->set_keep_above(true);
window2->signal_delete_event().connect([&](GdkEventAny* any_event)->bool{
delete window2;
return false;
});
window2->show_all();
return false;
});
});
window.show_all();
return Application->run(window);
}