diff --git a/configure.ac b/configure.ac index a36a942e0..6283679ad 100644 --- a/configure.ac +++ b/configure.ac @@ -10,6 +10,7 @@ AC_ISC_POSIX AC_PROG_CC AM_PROG_CC_STDC AC_HEADER_STDC +: ${CXXFLAGS="-std=c++20 -fcoroutines"} AC_PROG_CXX AC_PROG_MAKE_SET AC_PROG_RANLIB diff --git a/gtk/gtkbuilder/Makefile.am b/gtk/gtkbuilder/Makefile.am index f7d52bd6a..18e50073f 100644 --- a/gtk/gtkbuilder/Makefile.am +++ b/gtk/gtkbuilder/Makefile.am @@ -1,5 +1,37 @@ gtkbuilderdir = $(datadir)/synaptic/gtkbuilder/ -gtkbuilder_DATA = *.ui +gtkbuilder_DATA = \ + dialog_authentication.ui \ + dialog_changelog.ui \ + dialog_change_version.ui \ + dialog_conffile.ui \ + dialog_disc_label.ui \ + dialog_download_error.ui \ + dialog_new_repositroy.ui \ + dialog_quit.ui \ + dialog_task_descr.ui \ + dialog_unmet.ui \ + dialog_update_failed.ui \ + dialog_update_outdated.ui \ + dialog_upgrade.ui \ + dialog_welcome.ui \ + window_changes.ui \ + window_details.ui \ + window_disc_name.ui \ + window_fetch.ui \ + window_filters.ui \ + window_find.ui \ + window_iconlegend.ui \ + window_logview.ui \ + window_main.ui \ + window_preferences.ui \ + window_repositories.ui \ + window_rgdebinstall_progress.ui \ + window_rginstall_progress_msgs.ui \ + window_rginstall_progress.ui \ + window_setopt.ui \ + window_summary.ui \ + window_tasks.ui \ + window_zvtinstallprogress.ui EXTRA_DIST = $(gtkbuilder_DATA) diff --git a/gtk/rgchangelogdialog.cc b/gtk/rgchangelogdialog.cc index 08c9829d4..0b70502a7 100644 --- a/gtk/rgchangelogdialog.cc +++ b/gtk/rgchangelogdialog.cc @@ -20,7 +20,7 @@ #include "rgchangelogdialog.h" -void ShowChangelogDialog(RGWindow *me, RPackage *pkg) +task ShowChangelogDialog(RGWindow *me, RPackage *pkg) { RGFetchProgress *status = new RGFetchProgress(me);; status->setDescription(_("Downloading Changelog"), @@ -63,7 +63,7 @@ void ShowChangelogDialog(RGWindow *me, RPackage *pkg) gtk_text_buffer_insert_at_cursor(buffer, "\n", -1); } - dia.run(); + co_await dia.co_run(); // clean up delete status; diff --git a/gtk/rgchangelogdialog.h b/gtk/rgchangelogdialog.h index 529ebbed8..97bc3cf72 100644 --- a/gtk/rgchangelogdialog.h +++ b/gtk/rgchangelogdialog.h @@ -22,6 +22,7 @@ #include #include #include +#include #include -void ShowChangelogDialog(RGWindow *me, RPackage *pkg); +task ShowChangelogDialog(RGWindow *me, RPackage *pkg); diff --git a/gtk/rgmainwindow.cc b/gtk/rgmainwindow.cc index b1941239c..e7e98d605 100644 --- a/gtk/rgmainwindow.cc +++ b/gtk/rgmainwindow.cc @@ -1699,13 +1699,15 @@ void RGMainWindow::cbChangelogDialog(GSimpleAction *action, { RGMainWindow *me = (RGMainWindow*)data; - RPackage *pkg = me->selectedPackage(); - if(pkg == NULL) - return; - - me->setInterfaceLocked(TRUE); - ShowChangelogDialog(me, pkg); - me->setInterfaceLocked(FALSE); + start_task([me]() -> task { + RPackage *pkg = me->selectedPackage(); + if (pkg != NULL) { + me->setInterfaceLocked(TRUE); + co_await ShowChangelogDialog(me, pkg); + me->setInterfaceLocked(FALSE); + } + co_return nothing {}; + }); } diff --git a/gtk/rgpkgdetails.cc b/gtk/rgpkgdetails.cc index 7ec9b9784..1bf56d6b2 100644 --- a/gtk/rgpkgdetails.cc +++ b/gtk/rgpkgdetails.cc @@ -182,7 +182,11 @@ void RGPkgDetailsWindow::cbShowChangelog(GtkWidget *button, void *data) { RPackage *pkg = (RPackage*)data; RGWindow *parent = (RGWindow*)g_object_get_data(G_OBJECT(button), "me"); - ShowChangelogDialog(parent, pkg); + + start_task([parent, pkg]() -> task { + co_await ShowChangelogDialog(parent, pkg); + co_return nothing {}; + }); } gboolean RGPkgDetailsWindow::cbOpenLink(GtkWidget *label, diff --git a/gtk/rgpreferenceswindow.cc b/gtk/rgpreferenceswindow.cc index 88c847cee..a30c9010a 100644 --- a/gtk/rgpreferenceswindow.cc +++ b/gtk/rgpreferenceswindow.cc @@ -436,40 +436,34 @@ void RGPreferencesWindow::doneAction(GtkWidget *self, void *data) me->closeAction(self, data); } -void RGPreferencesWindow::changeFontAction(GtkWidget *self, void *data) +void RGPreferencesWindow::changeDefaultFontAction(GtkWidget *self, void *data) { - const char *fontName, *propName; - - switch (GPOINTER_TO_INT(data)) { - case FONT_DEFAULT: - propName = "Synaptic::FontName"; - fontName = "sans 10"; - break; - case FONT_TERMINAL: - propName = "Synaptic::TerminalFontName"; - fontName = "monospace 10"; - break; - default: - cerr << "changeFontAction called with unknown argument" << endl; - return; - } + auto me = static_cast(data); + me->co_changeFont("Synaptic::FontName", "sans 10").start_detached(); +} + +void RGPreferencesWindow::changeTerminalFontAction(GtkWidget *self, void *data) +{ + auto me = static_cast(data); + me->co_changeFont("Synaptic::TerminalFontName", "monospace 10").start_detached(); +} +task RGPreferencesWindow::co_changeFont(const char *propName, const char *defaultValue) +{ GtkWidget *fontsel = gtk_font_chooser_dialog_new(_("Choose font"), - GTK_WINDOW(gtk_widget_get_toplevel(self))); + GTK_WINDOW(window())); + gtk_window_set_modal(GTK_WINDOW(fontsel), true); gtk_font_chooser_set_font(GTK_FONT_CHOOSER(fontsel), - _config->Find(propName, fontName).c_str()); + _config->Find(propName, defaultValue).c_str()); - gint result = gtk_dialog_run(GTK_DIALOG(fontsel)); - if (result != GTK_RESPONSE_OK) { - gtk_widget_destroy(fontsel); - return; - } - - fontName = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(fontsel)); - //cout << "fontname: " << fontName << endl; + int result = co_await co_run_dialog(GTK_DIALOG(fontsel)); + if (result == GTK_RESPONSE_OK) { + auto fontName = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(fontsel)); + //cout << "fontname: " << fontName << endl; - _config->Set(propName, fontName); + _config->Set(propName, fontName); + } gtk_widget_destroy(fontsel); } @@ -902,26 +896,34 @@ void RGPreferencesWindow::cbToggleColumn(GtkWidget *self, char*path_string, void RGPreferencesWindow::colorClicked(GtkWidget *self, void *data) +{ + RGPreferencesWindow *me = (RGPreferencesWindow *) g_object_get_data(G_OBJECT(self), "me"); + int status = GPOINTER_TO_INT(data); + + me->co_colorClicked(status).start_detached(); +} + +task RGPreferencesWindow::co_colorClicked(int status) { GtkWidget *color_dialog; - RGPreferencesWindow *me; - me = (RGPreferencesWindow *) g_object_get_data(G_OBJECT(self), "me"); color_dialog = gtk_color_chooser_dialog_new(_("Color selection"), - GTK_WINDOW(gtk_builder_get_object(me->_builder, "window_preferences"))); + GTK_WINDOW(window())); + gtk_window_set_modal(GTK_WINDOW(color_dialog), true); gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(color_dialog), false); GdkRGBA *color = NULL; - color = RGPackageStatus::pkgStatus.getColor(GPOINTER_TO_INT(data)); + color = RGPackageStatus::pkgStatus.getColor(status); if (color != NULL) gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(color_dialog), color); - if (gtk_dialog_run(GTK_DIALOG(color_dialog)) == GTK_RESPONSE_OK) { + int response_id = co_await co_run_dialog(GTK_DIALOG(color_dialog)); + if (response_id == GTK_RESPONSE_OK) { GdkRGBA current_color; gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(color_dialog), ¤t_color); - RGPackageStatus::pkgStatus.setColor(GPOINTER_TO_INT(data), + RGPackageStatus::pkgStatus.setColor(status, gdk_rgba_copy(¤t_color)); - me->readColors(); + readColors(); } gtk_widget_destroy(color_dialog); } @@ -1171,7 +1173,7 @@ RGPreferencesWindow::RGPreferencesWindow(RGWindow *win, g_signal_connect(gtk_builder_get_object(_builder, "button_default_font"), "clicked", - G_CALLBACK(changeFontAction),GINT_TO_POINTER(FONT_DEFAULT)); + G_CALLBACK(changeDefaultFontAction), this); g_signal_connect(gtk_builder_get_object(_builder, "checkbutton_user_terminal_font"), "toggled", @@ -1182,8 +1184,8 @@ RGPreferencesWindow::RGPreferencesWindow(RGWindow *win, g_signal_connect(gtk_builder_get_object(_builder, "button_terminal_font"), "clicked", - G_CALLBACK(changeFontAction), - GINT_TO_POINTER(FONT_TERMINAL)); + G_CALLBACK(changeTerminalFontAction), + this); checkbuttonUserTerminalFontToggled(NULL, this); checkbuttonUserFontToggled(NULL, this); diff --git a/gtk/rgpreferenceswindow.h b/gtk/rgpreferenceswindow.h index 579fdb1a1..6b5afd58a 100644 --- a/gtk/rgpreferenceswindow.h +++ b/gtk/rgpreferenceswindow.h @@ -97,7 +97,9 @@ class RGPreferencesWindow:public RGGtkBuilderWindow { static void cbToggleColumn(GtkWidget *self, char *path, void *data); // callbacks - static void changeFontAction(GtkWidget *self, void *data); + static void changeDefaultFontAction(GtkWidget *self, void *data); + static void changeTerminalFontAction(GtkWidget *self, void *data); + task co_changeFont(const char *propName, const char *defaultValue); static void checkbuttonUserFontToggled(GtkWidget *self, void *data); static void checkbuttonUserTerminalFontToggled(GtkWidget *self, void *data); @@ -123,6 +125,7 @@ class RGPreferencesWindow:public RGGtkBuilderWindow { static void clearCacheAction(GtkWidget *self, void *data); static void colorClicked(GtkWidget *self, void *data); + task co_colorClicked(int status); static void buttonAuthenticationClicked(GtkWidget *self, void *data); static void useProxyToggled(GtkWidget *self, void *data); diff --git a/gtk/rguserdialog.cc b/gtk/rguserdialog.cc index 6412086a3..66c26de06 100644 --- a/gtk/rguserdialog.cc +++ b/gtk/rguserdialog.cc @@ -290,5 +290,18 @@ int RGGtkBuilderUserDialog::run(const char *name, bool return_gtk_response) return (res == GTK_RESPONSE_OK) || (res == GTK_RESPONSE_YES) || (res == GTK_RESPONSE_CLOSE); } +task RGGtkBuilderUserDialog::co_run(const char *name, bool return_gtk_response) +{ + if(name != NULL) + init(name); + + res = (GtkResponseType) co_await co_run_dialog(GTK_DIALOG(_dialog)); + gtk_widget_hide(_dialog); + + if(return_gtk_response) + co_return res; + else + co_return (res == GTK_RESPONSE_OK) || (res == GTK_RESPONSE_YES) || (res == GTK_RESPONSE_CLOSE); +} // vim:sts=4:sw=4 diff --git a/gtk/rguserdialog.h b/gtk/rguserdialog.h index b47c9a783..994bb08d6 100644 --- a/gtk/rguserdialog.h +++ b/gtk/rguserdialog.h @@ -27,6 +27,7 @@ #include "ruserdialog.h" #include "rgwindow.h" +#include "rgutils.h" class RGUserDialog : public RUserDialog { @@ -87,6 +88,7 @@ class RGGtkBuilderUserDialog : public RGUserDialog } int run(const char *name=NULL, bool return_gtk_response=false); + task co_run(const char *name=NULL, bool return_gtk_response=false); GtkBuilder *getGtkBuilder() { return builder; }; }; #endif diff --git a/gtk/rgutils.cc b/gtk/rgutils.cc index a7309687a..d6b2b7f66 100644 --- a/gtk/rgutils.cc +++ b/gtk/rgutils.cc @@ -315,4 +315,48 @@ const char *utf8(const char *str) } return escaped; } + +void g_main_context_schedule(std::coroutine_handle<> h) +{ + g_main_context_invoke( + g_main_context_default(), + [](gpointer data) -> gboolean { + auto h = std::coroutine_handle<>::from_address(data); + h.resume(); + return G_SOURCE_REMOVE; + }, + h.address() + ); +} + +struct DialogResponseCallback { + std::function func; +}; + +static void destroy_dialog_response_callback(gpointer data, GClosure *) +{ + delete static_cast(data); +} + +static void on_dialog_response(GtkDialog *, int response_id, gpointer user_data) +{ + auto *callback = static_cast(user_data); + callback->func(response_id); +} + +Awaiter co_run_dialog(GtkDialog *dialog) +{ + gtk_window_present(GTK_WINDOW(dialog)); + return Awaiter { + [dialog](std::function callback) { + auto *handler = new DialogResponseCallback { std::move(callback) }; + g_signal_connect_data(dialog, "response", + G_CALLBACK(on_dialog_response), + handler, + destroy_dialog_response_callback, + G_CONNECT_DEFAULT); + } + }; +} + // vim:ts=3:sw=3:et diff --git a/gtk/rgutils.h b/gtk/rgutils.h index 080200a8e..81ff9fc61 100644 --- a/gtk/rgutils.h +++ b/gtk/rgutils.h @@ -24,6 +24,12 @@ #define _RGMISC_H_ #include +#include +#include +#include +#include +#include +#include enum { PIXMAP_COLUMN, @@ -60,4 +66,196 @@ bool RunAsSudoUserCommand(std::vector cmd); std::string MarkupEscapeString(std::string str); std::string MarkupUnescapeString(std::string str); +struct nothing {}; + +void g_main_context_schedule(std::coroutine_handle<> h); + +template +void start_task(F&& f) +{ + f().start_detached(); +} + +template +struct task_awaitable; + +template +struct task_awaitable_owned; + +template +class task { +public: + struct promise_type { + std::optional value; + std::exception_ptr exception; + std::coroutine_handle<> continuation; + bool detached = false; + + task get_return_object() { + return task { + std::coroutine_handle::from_promise(*this) + }; + } + + std::suspend_always initial_suspend() noexcept { return {}; } + auto final_suspend() noexcept { + struct final_awaiter { + bool await_ready() const noexcept { return false; } + + void await_suspend(std::coroutine_handle h) const noexcept + { + auto &promise = h.promise(); + if (promise.continuation) { + promise.continuation.resume(); + } + if (promise.detached) { + h.destroy(); + } + } + + void await_resume() const noexcept {} + }; + + return final_awaiter {}; + } + + void return_value(T v) { value = std::move(v); } + void unhandled_exception() { exception = std::current_exception(); } + }; + + using handle_t = std::coroutine_handle; + + explicit task(handle_t h) : h_(h) {} + task(task&& o) noexcept : h_(o.h_) { o.h_ = {}; } + ~task() { if (h_) h_.destroy(); } + + T result() { + if (h_.promise().exception) + std::rethrow_exception(h_.promise().exception); + if (!h_.promise().value) { + if constexpr (std::is_same_v) { + return nothing {}; + } + } + return std::move(*h_.promise().value); + } + + handle_t handle() const { return h_; } + + void start_detached() + { + if (!h_) + return; + + h_.promise().detached = true; + g_main_context_schedule(h_); + h_ = {}; + } + + auto operator co_await() & { return task_awaitable{*this}; } + auto operator co_await() && { return task_awaitable_owned{std::move(*this)}; } + +private: + handle_t h_; +}; + +struct sleep_ms { + int ms; + + bool await_ready() const noexcept { return false; } + + void await_suspend(std::coroutine_handle<> h) + { + auto* source = g_timeout_source_new(ms); + g_source_set_callback( + source, + [](gpointer data) -> gboolean { + auto h = std::coroutine_handle<>::from_address(data); + h.resume(); + return G_SOURCE_REMOVE; + }, + h.address(), + nullptr + ); + g_source_attach(source, g_main_context_default()); + g_source_unref(source); + } + + void await_resume() const noexcept {} +}; + +template +struct task_awaitable { + task& t; + + bool await_ready() const noexcept { return false; } + + void await_suspend(std::coroutine_handle<> h) + { + t.handle().promise().continuation = h; + t.handle().resume(); + } + + T await_resume() + { + return t.result(); + } +}; + +template +struct task_awaitable_owned { + task t; + + bool await_ready() const noexcept { return false; } + + void await_suspend(std::coroutine_handle<> h) + { + t.handle().promise().continuation = h; + t.handle().resume(); + } + + T await_resume() + { + return t.result(); + } +}; + +template +struct Awaiter { + using F = std::function)>; + + F func; + std::coroutine_handle<> handle; + std::optional result; + std::exception_ptr exception; + + explicit Awaiter(F&& f) : func(std::forward(f)) {} + + bool await_ready() const { return false; } + + void await_suspend(std::coroutine_handle<> h) { + handle = h; + try { + func([this](T value) { + result = std::move(value); + if (handle) { + handle.resume(); + } + }); + } catch (...) { + exception = std::current_exception(); + handle.resume(); + } + } + + T await_resume() { + if (exception) { + std::rethrow_exception(exception); + } + return std::move(result.value()); + } +}; + +Awaiter co_run_dialog(GtkDialog *dialog); + #endif diff --git a/pixmaps/hicolor/16x16/actions/Makefile.am b/pixmaps/hicolor/16x16/actions/Makefile.am index f5fca54b0..b23cda6e8 100644 --- a/pixmaps/hicolor/16x16/actions/Makefile.am +++ b/pixmaps/hicolor/16x16/actions/Makefile.am @@ -1,5 +1,20 @@ status_icondir = $(datadir)/icons/hicolor/16x16/actions -status_icon_DATA = *.png +status_icon_DATA = \ + package-available-locked.png \ + package-available.png \ + package-broken.png \ + package-downgrade.png \ + package-install.png \ + package-installed-locked.png \ + package-installed-outdated.png \ + package-installed-updated.png \ + package-new.png \ + package-purge.png \ + package-reinstall.png \ + package-remove.png \ + package-supported.png \ + package-upgrade.png \ + system-upgrade.png EXTRA_DIST=$(status_icon_DATA) diff --git a/pixmaps/hicolor/24x24/actions/Makefile.am b/pixmaps/hicolor/24x24/actions/Makefile.am index a10916d5f..7acb400bc 100644 --- a/pixmaps/hicolor/24x24/actions/Makefile.am +++ b/pixmaps/hicolor/24x24/actions/Makefile.am @@ -1,4 +1,4 @@ icondir = $(datadir)/icons/hicolor/24x24/actions -icon_DATA = *.png +icon_DATA = system-upgrade.png EXTRA_DIST=$(icon_DATA) diff --git a/pixmaps/hicolor/256x256/apps/Makefile.am b/pixmaps/hicolor/256x256/apps/Makefile.am index 112d0948c..1c490c62a 100644 --- a/pixmaps/hicolor/256x256/apps/Makefile.am +++ b/pixmaps/hicolor/256x256/apps/Makefile.am @@ -1,4 +1,4 @@ icondir = $(datadir)/icons/hicolor/256x256/apps -icon_DATA = *.png +icon_DATA = synaptic.png EXTRA_DIST=$(icon_DATA) diff --git a/pixmaps/hicolor/scalable/apps/Makefile.am b/pixmaps/hicolor/scalable/apps/Makefile.am index 7a4c6b2b9..3d3b13aa1 100644 --- a/pixmaps/hicolor/scalable/apps/Makefile.am +++ b/pixmaps/hicolor/scalable/apps/Makefile.am @@ -1,4 +1,4 @@ icondir = $(datadir)/icons/hicolor/scalable/apps -icon_DATA = *.svg +icon_DATA = synaptic.svg EXTRA_DIST=$(icon_DATA) diff --git a/tests/Makefile.am b/tests/Makefile.am index bafd929e9..894bb40a0 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,5 +1,5 @@ -AM_CPPFLAGS = -I${top_srcdir}/common -I${top_srcdir}/gtk \ +AM_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/common -I${top_srcdir}/gtk \ @GTK_CFLAGS@ @VTE_CFLAGS@ @LP_CFLAGS@ $(LIBTAGCOLL_CFLAGS) $(LIBEPT_CFLAGS) -O0 -g3 noinst_PROGRAMS = test_rpackage test_rpackageview test_gtkpkglist test_rpackagefilter