From fadf7f1e18471efc499ddb84e86f533d10216b6f Mon Sep 17 00:00:00 2001 From: Ioan Dragomir <123ioandragomir123@gmail.com> Date: Wed, 4 Sep 2024 15:50:40 +0300 Subject: [PATCH 1/2] Refactor to use gdk_threads_add_idle instead of gdk_threads_enter/leave --- dialogs.c | 122 ++++++++++++++++++++++++++--------------- oscmain.c | 7 --- oscplot.c | 5 -- plugins/fmcomms2_adv.c | 34 +++++++++--- 4 files changed, 104 insertions(+), 64 deletions(-) diff --git a/dialogs.c b/dialogs.c index c98af6a20..c3dae6eb9 100644 --- a/dialogs.c +++ b/dialogs.c @@ -68,6 +68,16 @@ struct _Dialogs GtkWidget *ver_progress_bar; }; +/* Container for the contents of the iio context selection menu, passed when + * refreshing the list asynchronously. + * Allocated by caller, freed by callee. Strings are strdup-ed and not referenced + * anywhere else, so must be freed as well. */ +struct refresh_usb_info { + int num_devices; + gint index; // Index of active item + char **device_list; +}; + static Dialogs dialogs; static GtkWidget *serial_num; static GtkWidget *fru_date; @@ -318,10 +328,6 @@ static bool widget_set_cursor(GtkWidget *widget, GdkCursorType type) watchCursor = gdk_cursor_new_for_display(display, type); gdk_window_set_cursor(gdkWindow, watchCursor); - while (gtk_events_pending()) - gtk_main_iteration(); - - return true; } @@ -432,6 +438,53 @@ static struct iio_context * get_context(Dialogs *data) } } +/* Change UI state to indicate the USB device list is being refreshed. + * Not thread safe by itself - should be queued using gdk_threads_add_idle(), not g_idle_add_full() */ +static bool refresh_usb_clear(void *) +{ + + gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(dialogs.connect_usbd)))); + widget_set_cursor(dialogs.connect, GDK_WATCH); + + return false; +} + +/* Update UI with refreshed USB device list. Assumes refresh_usb_clear was called befrehand. + * Not thread safe by itself - should be queued using gdk_threads_add_idle(), not g_idle_add_full() */ +static bool refresh_usb_update_list(struct refresh_usb_info *info) +{ + int i; + + widget_use_parent_cursor(dialogs.connect); + + if (info->num_devices) + { + for(i = 0; i < info->num_devices; i++) + { + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(dialogs.connect_usbd), info->device_list[i]); + free(info->device_list[i]); + } + free(info->device_list); + + gtk_combo_box_set_active(GTK_COMBO_BOX(dialogs.connect_usbd), info->index); + gtk_widget_set_sensitive(dialogs.connect_usb, true); + gtk_widget_set_sensitive(dialogs.connect_usbd,true); + } + else + { + // There are no devices + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(dialogs.connect_usbd), NO_DEVICES); + + gtk_combo_box_set_active(GTK_COMBO_BOX(dialogs.connect_usbd),0); + gtk_widget_set_sensitive(dialogs.connect_usbd, false); + } + + gdk_threads_add_idle(G_SOURCE_FUNC(connect_clear), dialogs.connect_usb); + + free(info); + + return false; +} static void refresh_usb_thread(void) { @@ -440,17 +493,19 @@ static void refresh_usb_thread(void) GtkListStore *liststore; ssize_t ret; unsigned int i = 0; - gint index = 0; gchar *tmp, *tmp1, *pid, *buf; char *current = NULL; char filter[sizeof("local:ip:usb:")]; char *p; bool scan = false; gchar *active_uri = NULL; + struct refresh_usb_info *usb_devices_info = malloc(sizeof(struct refresh_usb_info)); - gdk_threads_enter(); - widget_set_cursor(dialogs.connect, GDK_WATCH); + usb_devices_info->device_list = NULL; + usb_devices_info->num_devices = 0; + usb_devices_info->index = 0; + gdk_threads_add_idle(G_SOURCE_FUNC(refresh_usb_clear), NULL); if (gtk_combo_box_get_active(GTK_COMBO_BOX(dialogs.connect_usbd)) != -1) { active_uri = gtk_combo_box_text_get_active_text( GTK_COMBO_BOX_TEXT(dialogs.connect_usbd)); @@ -471,9 +526,7 @@ static void refresh_usb_thread(void) g_signal_handler_block(GTK_COMBO_BOX(dialogs.connect_usbd), dialogs.usbd_signals); } - /* clear everything, and scan again */ - liststore = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(dialogs.connect_usbd))); - gtk_list_store_clear(liststore); + /* Scan again */ p = filter; if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialogs.filter_local))) { @@ -500,9 +553,14 @@ static void refresh_usb_thread(void) ret = iio_scan_context_get_info_list(ctxs, &info); if (ret < 0) goto err_free_ctxs; + + usb_devices_info->num_devices = ret; + if (!ret) goto err_free_info_list; + usb_devices_info->device_list = calloc(ret, sizeof(char *)); + for (i = 0; i < (size_t) ret; i++) { tmp = strdup(iio_context_info_get_description(info[i])); pid = strdup(iio_context_info_get_description(info[i])); @@ -531,7 +589,7 @@ static void refresh_usb_thread(void) } } if (active_pid != -1 && current && !strcmp(pid, current)) { - index = i; + usb_devices_info->index = i; } usb_pids[i]=pid; @@ -539,17 +597,17 @@ static void refresh_usb_thread(void) if (!tmp1) tmp1 = tmp; buf = malloc(strlen(iio_context_info_get_uri(info[i])) + - strlen(tmp1) + 5); + strlen(tmp1) + 5); // will be freed by `refresh_usb_update_list` sprintf(buf, "%s [%s]", tmp1, iio_context_info_get_uri(info[i])); tmp1 = NULL; - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(dialogs.connect_usbd), buf); + usb_devices_info->device_list[i] = buf; + if (active_uri && !g_strcmp0(active_uri, buf)) { - index = i; + usb_devices_info->index = i; } - free(buf); free(tmp); } @@ -559,37 +617,16 @@ static void refresh_usb_thread(void) iio_scan_context_destroy(ctxs); nope: - widget_use_parent_cursor(dialogs.connect); - - if (!i) { - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(dialogs.connect_usbd), NO_DEVICES); - gtk_combo_box_set_active(GTK_COMBO_BOX(dialogs.connect_usbd),0); - gtk_widget_set_sensitive(dialogs.connect_usbd, false); - /* Force a clear */ - connect_clear(dialogs.connect_net); - gdk_threads_leave(); - return; - } - - gtk_widget_set_sensitive(dialogs.connect_usb, true); - gtk_widget_set_sensitive(dialogs.connect_usbd,true); - - gtk_combo_box_set_active(GTK_COMBO_BOX(dialogs.connect_usbd), index); + gdk_threads_add_idle(G_SOURCE_FUNC(refresh_usb_update_list), usb_devices_info); if (dialogs.usbd_signals) { g_signal_handler_unblock(GTK_COMBO_BOX(dialogs.connect_usbd), dialogs.usbd_signals); } - if (current) { free(current); current = NULL; } - - /* Fill things in */ - connect_clear(dialogs.connect_usb); - gdk_threads_leave(); - } @@ -839,7 +876,7 @@ static bool connect_clear(GtkWidget *widget) if (!widget) { printf("nope - not callback\n"); - return true; + return false; } if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) { /* set - fill in */ @@ -865,7 +902,7 @@ static bool connect_clear(GtkWidget *widget) g_object_unref(buf); } - return true; + return false; } static bool refresh_connect_attributes() @@ -1129,7 +1166,6 @@ static gboolean version_info_show(gpointer data) if (!release && !data) return false; - gdk_threads_enter(); internal_vbox = GTK_WIDGET(gtk_builder_get_object(builder, "msg_dialog_vbox")); @@ -1195,8 +1231,6 @@ static gboolean version_info_show(gpointer data) gtk_widget_hide(_dialogs->latest_version); end: - gdk_threads_leave(); - return false; } @@ -1223,7 +1257,7 @@ static gpointer version_check(gpointer data) /* * Periodically animate the progress bar as long as the version checking thread - * is still working. When the thread has finished, signal (using g_idle_add()) + * is still working. When the thread has finished, signal (using gdk_threads_add_idle()) * the GUI to run the dialog that contains latest version information. */ static gboolean version_progress_update(gpointer data) @@ -1235,7 +1269,7 @@ static gboolean version_progress_update(gpointer data) if (ver_check_done) { if (_dialogs) gtk_widget_hide(_dialogs->ver_progress_window); - g_idle_add(version_info_show, (gpointer)_dialogs); + gdk_threads_add_idle(version_info_show, (gpointer)_dialogs); } return !ver_check_done; diff --git a/oscmain.c b/oscmain.c index d99816a74..eec0c9497 100644 --- a/oscmain.c +++ b/oscmain.c @@ -229,11 +229,6 @@ gint main (int argc, char **argv) break; } -#ifndef __MINGW__ - /* XXX: Enabling threading when compiling for Windows will lock the UI - * as soon as the main window is moved. */ - gdk_threads_init(); -#endif gtk_init(&argc, &argv); signal(SIGTERM, sigterm); @@ -242,7 +237,6 @@ gint main (int argc, char **argv) signal(SIGHUP, sigterm); #endif - gdk_threads_enter(); init_application(); c = load_default_profile(profile, true); if (!ctx_destroyed_by_do_quit) { @@ -258,7 +252,6 @@ gint main (int argc, char **argv) } else application_quit(); } - gdk_threads_leave(); if (profile) free(profile); diff --git a/oscplot.c b/oscplot.c index bd2c85a4d..4b1a85f76 100644 --- a/oscplot.c +++ b/oscplot.c @@ -4798,11 +4798,6 @@ void cb_saveas_response(GtkDialog *dialog, gint response_id, OscPlot *plot) gtk_widget_hide(priv->saveas_dialog); if (priv->save_as_png) { - int i = 0, timeout = 1000; - while (gtk_events_pending() && i < timeout) { - i++; - gtk_main_iteration(); - } screenshot_saveas_png(plot); priv->save_as_png = false; } diff --git a/plugins/fmcomms2_adv.c b/plugins/fmcomms2_adv.c index 4bc8134e1..3a3cb421b 100644 --- a/plugins/fmcomms2_adv.c +++ b/plugins/fmcomms2_adv.c @@ -85,6 +85,14 @@ struct w_info { const char * const name; }; +/* Container for passing both the progress bar and fraction to + * set_calibration_progress_ui. + * Allocated by caller, freed by callee. */ +struct set_calibration_progress_params { + GtkProgressBar *pbar; + float fraction; +}; + static struct w_info attrs[] = { {SPINBUTTON, "adi,agc-adc-large-overload-exceed-counter"}, {SPINBUTTON, "adi,agc-adc-large-overload-inc-steps"}, @@ -814,17 +822,27 @@ static int get_cal_samples(long long cal_tone, long long cal_freq) return env_samples; } -static void set_calibration_progress(GtkProgressBar *pbar, float fraction) -{ - if (gtk_widget_get_visible(GTK_WIDGET(pbar))) { +static bool set_calibration_progress_ui(struct set_calibration_progress_params *params) { + if (gtk_widget_get_visible(GTK_WIDGET(params->pbar))) { char ptext[64]; - gdk_threads_enter(); - snprintf(ptext, sizeof(ptext), "Calibration Progress (%.2f %%)", fraction * 100); - gtk_progress_bar_set_text(pbar, ptext); - gtk_progress_bar_set_fraction(pbar, fraction); - gdk_threads_leave(); + snprintf(ptext, sizeof(ptext), "Calibration Progress (%.2f %%)", params->fraction * 100); + gtk_progress_bar_set_text(params->pbar, ptext); + gtk_progress_bar_set_fraction(params->pbar, params->fraction); } + + free(params); + + return false; +} + +static void set_calibration_progress(GtkProgressBar *pbar, float fraction) +{ + struct set_calibration_progress_params *params = malloc(sizeof(struct set_calibration_progress_params)); + params->pbar = pbar; + params->fraction = fraction; + + gdk_threads_add_idle(G_SOURCE_FUNC(set_calibration_progress_ui), params); } static void calibrate (gpointer button) From 272a0161c42ea07163e53313f0b0fe5bb5737a5d Mon Sep 17 00:00:00 2001 From: Ioan Dragomir Date: Mon, 16 Sep 2024 15:24:26 +0300 Subject: [PATCH 2/2] Fix omitted unused parameter Signed-off-by: Ioan Dragomir --- dialogs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dialogs.c b/dialogs.c index c3dae6eb9..b10e4f51b 100644 --- a/dialogs.c +++ b/dialogs.c @@ -440,9 +440,8 @@ static struct iio_context * get_context(Dialogs *data) /* Change UI state to indicate the USB device list is being refreshed. * Not thread safe by itself - should be queued using gdk_threads_add_idle(), not g_idle_add_full() */ -static bool refresh_usb_clear(void *) +static bool refresh_usb_clear(void *UNUSED(param)) { - gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(dialogs.connect_usbd)))); widget_set_cursor(dialogs.connect, GDK_WATCH);