[balsa/gtk4: 173/294] Various: Stop using gtk_dialog_run()
- From: Peter Bloomfield <peterb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [balsa/gtk4: 173/294] Various: Stop using gtk_dialog_run()
- Date: Sun, 10 Oct 2021 00:03:10 +0000 (UTC)
commit 8aaa71293e92e3a9ad210e6fe60d9126f4628bf4
Author: Peter Bloomfield <PeterBloomfield bellsouth net>
Date: Wed Oct 7 10:55:45 2020 -0400
Various: Stop using gtk_dialog_run()
Put all the sending code in a thread, so that prompting the user for a
password does not block the main thread.
libbalsa/identity.c
libbalsa/libbalsa-gpgme-cb.c
libbalsa/libbalsa-gpgme.c
src/sendmsg-window.c
src/sendmsg-window.h
libbalsa/identity.c | 84 ++++++++++++++------
libbalsa/libbalsa-gpgme-cb.c | 181 +++++++++++++++++++++++++++++++++----------
libbalsa/libbalsa-gpgme.c | 5 +-
src/sendmsg-window.c | 160 ++++++++++++++++++++++++++------------
src/sendmsg-window.h | 2 +
5 files changed, 316 insertions(+), 116 deletions(-)
---
diff --git a/libbalsa/identity.c b/libbalsa/identity.c
index 84dfb2256..9439d79df 100644
--- a/libbalsa/identity.c
+++ b/libbalsa/identity.c
@@ -1053,36 +1053,70 @@ ident_dialog_add_entry(GtkWidget * grid, gint row, GtkDialog * dialog,
gtk_widget_grab_focus(entry);
}
+typedef struct {
+ GObject *object;
+ const char *target;
+ char *keyid;
+ GError *error;
+} choose_key_info;
-static void
-choose_key(GtkButton *button, gpointer user_data)
+static gboolean
+choose_key_thread_idle(gpointer data)
{
- const gchar *target;
- gpgme_protocol_t protocol;
- gchar *email;
- gchar *keyid;
- GError *error = NULL;
-
- target = g_object_get_data(G_OBJECT(button), "target");
- if (strcmp(target, "identity-keyid") == 0) {
- protocol = GPGME_PROTOCOL_OpenPGP;
- } else {
- protocol = GPGME_PROTOCOL_CMS;
- }
-
- email = ident_dialog_get_text(G_OBJECT(user_data), "identity-address");
- keyid = libbalsa_gpgme_get_seckey(protocol, email, GTK_WINDOW(user_data), &error);
- if (keyid != NULL) {
- display_frame_set_field(G_OBJECT(user_data), target, keyid);
- g_free(keyid);
- }
- if (error != NULL) {
+ choose_key_info *info = data;
+
+ if (info->keyid != NULL) {
+ display_frame_set_field(info->object, info->target, info->keyid);
+ g_free(info->keyid);
+ }
+
+ if (info->error != NULL) {
libbalsa_information(LIBBALSA_INFORMATION_WARNING,
- _("Error selecting key: %s"), error->message);
- g_clear_error(&error);
- }
+ _("Error selecting key: %s"), info->error->message);
+ g_error_free(info->error);
+ }
+
+ g_object_unref(info->object);
+ g_free(info);
+
+ return G_SOURCE_REMOVE;
}
+static gpointer
+choose_key_thread_func(gpointer data)
+{
+ choose_key_info *info = data;
+ gpgme_protocol_t protocol;
+ char *email;
+
+ protocol = (strcmp(info->target, "identity-keyid") == 0) ?
+ GPGME_PROTOCOL_OpenPGP : GPGME_PROTOCOL_CMS;
+ email = ident_dialog_get_text(info->object, "identity-address");
+
+ info->error = NULL;
+ info->keyid = libbalsa_gpgme_get_seckey(protocol, email, GTK_WINDOW(info->object), &info->error);
+ g_idle_add(choose_key_thread_idle, info);
+
+ return NULL;
+}
+
+static void
+choose_key(GtkButton *button, gpointer user_data)
+{
+ GObject *object = user_data;
+ choose_key_info *info;
+ GThread *thread;
+
+ info = g_new(choose_key_info, 1);
+ info->object = g_object_ref(object);
+ info->target = g_object_get_data(G_OBJECT(button), "target");
+
+ /* Ask the user for a key in a subthread, because it blocks while
+ * the user chooses. */
+
+ thread = g_thread_new("choose-key", choose_key_thread_func, info);
+ g_thread_unref(thread);
+}
/*
* Add a GtkEntry to the given dialog with a label next to it
diff --git a/libbalsa/libbalsa-gpgme-cb.c b/libbalsa/libbalsa-gpgme-cb.c
index d06aef9eb..310d06521 100644
--- a/libbalsa/libbalsa-gpgme-cb.c
+++ b/libbalsa/libbalsa-gpgme-cb.c
@@ -151,16 +151,47 @@ row_activated_cb(GtkTreeView *tree_view,
gtk_tree_model_get(model, &iter, GPG_KEY_PTR_COLUMN, &key, -1);
dialog = libbalsa_key_dialog(window, GTK_BUTTONS_CLOSE, key, GPG_SUBKEY_CAP_ALL, NULL, NULL);
- g_signal_connect(dialog, "response", G_CALLBACK(gtk_window_destroy), NULL);
+ g_signal_connect(dialog, "response", G_CALLBACK(gtk_widget_destroy), NULL);
gtk_widget_show(dialog);
}
}
+static struct {
+ GMutex lock;
+ GCond cond;
+ gboolean done;
+} select_key;
-gpgme_key_t
-lb_gpgme_select_key(const gchar * user_name, lb_key_sel_md_t mode, GList * keys,
- gpgme_protocol_t protocol, GtkWindow * parent)
+static void
+select_key_response(GtkDialog *dialog,
+ int response_id,
+ gpointer user_data)
+{
+ gpgme_key_t *use_key = user_data;
+
+ if (response_id != GTK_RESPONSE_OK)
+ *use_key = NULL;
+
+ g_mutex_lock(&select_key.lock);
+ select_key.done = TRUE;
+ g_cond_signal(&select_key.cond);
+ g_mutex_unlock(&select_key.lock);
+
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+}
+
+typedef struct {
+ const gchar *user_name;
+ lb_key_sel_md_t mode;
+ GList *keys;
+ GtkWindow *parent;
+ gpgme_key_t *use_key;
+} select_key_info;
+
+static gboolean
+select_key_idle(gpointer user_data)
{
+ select_key_info *info = user_data;
GtkWidget *dialog;
GtkWidget *content_area;
GtkWidget *vbox;
@@ -168,17 +199,17 @@ lb_gpgme_select_key(const gchar * user_name, lb_key_sel_md_t mode, GList * keys,
GtkWidget *scrolled_window;
GtkWidget *tree_view;
GtkListStore *model;
- GtkTreeSortable *sortable;
+ GtkTreeSortable *sortable;
GtkTreeSelection *selection;
GtkTreeIter iter;
gchar *prompt;
- gpgme_key_t use_key = NULL;
- GtkCellRenderer *renderer;
- GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+ GList *l;
/* FIXME: create dialog according to the Gnome HIG */
dialog = gtk_dialog_new_with_buttons(_("Select key"),
- parent,
+ info->parent,
GTK_DIALOG_DESTROY_WITH_PARENT |
libbalsa_dialog_flags(),
_("_OK"), GTK_RESPONSE_OK,
@@ -186,37 +217,39 @@ lb_gpgme_select_key(const gchar * user_name, lb_key_sel_md_t mode, GList * keys,
NULL);
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_OK, FALSE);
- geometry_manager_attach(GTK_WINDOW(dialog), "KeyList");
+ geometry_manager_attach(GTK_WINDOW(dialog), "KeyList");
content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
#if HAVE_MACOSX_DESKTOP
- libbalsa_macosx_menu_for_parent(dialog, parent);
+ libbalsa_macosx_menu_for_parent(dialog, info->parent);
#endif
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
gtk_widget_set_vexpand (vbox, TRUE);
gtk_container_add(GTK_CONTAINER(content_area), vbox);
gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
- switch (mode) {
+
+ switch (info->mode) {
case LB_SELECT_PRIVATE_KEY:
prompt =
g_strdup_printf(_("Select the private key for the signer “%s”"),
- user_name);
+ info->user_name);
break;
case LB_SELECT_PUBLIC_KEY_USER:
prompt =
g_strdup_printf(_("Select the public key for the recipient “%s”"),
- user_name);
+ info->user_name);
break;
case LB_SELECT_PUBLIC_KEY_ANY:
prompt =
g_strdup_printf(_("There seems to be no public key for recipient "
"“%s” in your key ring.\nIf you are sure that the "
"recipient owns a different key, select it from "
- "the list."), user_name);
+ "the list."), info->user_name);
break;
default:
g_assert_not_reached();
- }
+ }
+
label = libbalsa_create_wrap_label(prompt, FALSE);
g_free(prompt);
gtk_container_add(GTK_CONTAINER(vbox), label);
@@ -249,11 +282,11 @@ lb_gpgme_select_key(const gchar * user_name, lb_key_sel_md_t mode, GList * keys,
g_object_set_data(G_OBJECT(selection), "first", GUINT_TO_POINTER(1));
gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
g_signal_connect(selection, "changed",
- G_CALLBACK(key_selection_changed_cb), &use_key);
+ G_CALLBACK(key_selection_changed_cb), info->use_key);
/* add the keys */
- while (keys != NULL) {
- gpgme_key_t key = (gpgme_key_t) keys->data;
+ for (l = info->keys; l != NULL; l = l->next) {
+ gpgme_key_t key = (gpgme_key_t) l->data;
/* simply add the primary uid -- the user can show the full key details */
if ((key->uids != NULL) && (key->uids->uid != NULL) && (key->subkeys != NULL)) {
@@ -274,7 +307,6 @@ lb_gpgme_select_key(const gchar * user_name, lb_key_sel_md_t mode, GList * keys,
g_free(bits);
g_free(created);
}
- keys = g_list_next(keys);
}
g_object_unref(model);
@@ -303,43 +335,112 @@ lb_gpgme_select_key(const gchar * user_name, lb_key_sel_md_t mode, GList * keys,
gtk_container_add(GTK_CONTAINER(scrolled_window), tree_view);
g_signal_connect(tree_view, "row-activated", G_CALLBACK(row_activated_cb), dialog);
- gtk_widget_show_all(content_area);
+ g_signal_connect(dialog, "response", G_CALLBACK(select_key_response), info->use_key);
+ g_free(info);
+ gtk_widget_show_all(dialog);
- if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_OK) {
- use_key = NULL;
- }
- gtk_widget_destroy(dialog);
+ return G_SOURCE_REMOVE;
+}
+
+gpgme_key_t
+lb_gpgme_select_key(const gchar * user_name, lb_key_sel_md_t mode, GList * keys,
+ gpgme_protocol_t protocol, GtkWindow * parent)
+{
+ gpgme_key_t use_key = NULL;
+ select_key_info *info;
+
+ g_return_val_if_fail(libbalsa_am_i_subthread(), NULL);
+
+ info = g_new(select_key_info, 1);
+ info->user_name = user_name;
+ info->mode = mode;
+ info->keys = keys;
+ info->parent = parent;
+ info->use_key = &use_key;
+
+ g_idle_add(select_key_idle, info);
+
+ g_mutex_lock(&select_key.lock);
+ select_key.done = FALSE;
+ while (!select_key.done)
+ g_cond_wait(&select_key.cond, &select_key.lock);
+ g_mutex_unlock(&select_key.lock);
return use_key;
}
+static struct {
+ GMutex lock;
+ GCond cond;
+ int result;
+} accept_low_trust_key;
-gboolean
-lb_gpgme_accept_low_trust_key(const gchar *user_name,
- gpgme_key_t key,
- GtkWindow *parent)
+static void
+accept_low_trust_key_response(GtkDialog *dialog,
+ int response_id,
+ gpointer user_data)
{
- GtkWidget *dialog;
- gint result;
- gchar *message2;
+ g_mutex_lock(&accept_low_trust_key.lock);
+ accept_low_trust_key.result = response_id;
+ g_cond_signal(&accept_low_trust_key.cond);
+ g_mutex_unlock(&accept_low_trust_key.lock);
- /* paranoia checks */
- g_return_val_if_fail((user_name != NULL) && (key != NULL), FALSE);
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+}
+
+typedef struct {
+ gpgme_key_t key;
+ GtkWindow *parent;
+} accept_low_trust_key_info;
+
+static gboolean
+accept_low_trust_key_idle(gpointer user_data)
+{
+ accept_low_trust_key_info *info = user_data;
+ GtkWidget *dialog;
+ char *message2;
/* create the dialog */
message2 = g_strdup_printf(_("The owner trust for this key is “%s” only.\nUse this key anyway?"),
- libbalsa_gpgme_validity_to_gchar_short(key->owner_trust));
- dialog = libbalsa_key_dialog(parent, GTK_BUTTONS_YES_NO, key, GPG_SUBKEY_CAP_ENCRYPT, _("Insufficient
key owner trust"),
+ libbalsa_gpgme_validity_to_gchar_short(info->key->owner_trust));
+ dialog = libbalsa_key_dialog(info->parent, GTK_BUTTONS_YES_NO, info->key, GPG_SUBKEY_CAP_ENCRYPT,
_("Insufficient key owner trust"),
message2);
+ g_free(message2);
#if HAVE_MACOSX_DESKTOP
- libbalsa_macosx_menu_for_parent(dialog, parent);
+ libbalsa_macosx_menu_for_parent(dialog, info->parent);
#endif
+ g_free(info);
+
/* ask the user */
- result = gtk_dialog_run(GTK_DIALOG(dialog));
- gtk_widget_destroy(dialog);
+ g_signal_connect(dialog, "response", G_CALLBACK(accept_low_trust_key_response), NULL);
+ gtk_widget_show_all(dialog);
+
+ return G_SOURCE_REMOVE;
+}
+
+gboolean
+lb_gpgme_accept_low_trust_key(const gchar *user_name,
+ gpgme_key_t key,
+ GtkWindow *parent)
+{
+ accept_low_trust_key_info *info;
+
+ /* paranoia checks */
+ g_return_val_if_fail((user_name != NULL) && (key != NULL), FALSE);
+
+ info = g_new(accept_low_trust_key_info, 1);
+ info->key = key;
+ info->parent = parent;
+ g_idle_add(accept_low_trust_key_idle, info);
+
+ g_mutex_lock(&accept_low_trust_key.lock);
+ accept_low_trust_key.result = 0;
+ while (accept_low_trust_key.result == 0)
+ g_cond_wait(&accept_low_trust_key.cond, &accept_low_trust_key.lock);
+ g_mutex_unlock(&accept_low_trust_key.lock);
- return result == GTK_RESPONSE_YES;
+ return accept_low_trust_key.result == GTK_RESPONSE_YES;
}
diff --git a/libbalsa/libbalsa-gpgme.c b/libbalsa/libbalsa-gpgme.c
index c4ebae683..f99bfe24f 100644
--- a/libbalsa/libbalsa-gpgme.c
+++ b/libbalsa/libbalsa-gpgme.c
@@ -823,8 +823,9 @@ libbalsa_gpgme_get_seckey(gpgme_protocol_t protocol,
GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
_("No private key for protocol %s is available for the signer “%s”"),
libbalsa_gpgme_protocol_name(protocol), name);
- (void) gtk_dialog_run(GTK_DIALOG(dialog));
- gtk_widget_destroy(dialog);
+
+ g_signal_connect(dialog, "response", G_CALLBACK(gtk_widget_destroy), NULL);
+ gtk_widget_show(dialog);
}
}
gpgme_release(ctx);
diff --git a/src/sendmsg-window.c b/src/sendmsg-window.c
index 1d4e962cb..0387851a0 100644
--- a/src/sendmsg-window.c
+++ b/src/sendmsg-window.c
@@ -5459,29 +5459,90 @@ check_autocrypt_recommendation(BalsaSendmsg *bsmsg)
/* "send message" menu and toolbar callback.
+ *
+ * Sending or queuing a message may require user interaction in the form
+ * of a response to some information. The process is carried out in a
+ * subthread, which can block pending the user's response, to avoid
+ * blocking the main thread.
*/
-static gint
-send_message_handler(BalsaSendmsg * bsmsg, gboolean queue_only)
+
+static struct {
+ GMutex lock;
+ GCond cond;
+ int choice;
+} send_message;
+
+static void
+send_message_thread_response(GtkDialog *dialog,
+ int response_id,
+ gpointer user_data)
+{
+ g_mutex_lock(&send_message.lock);
+ send_message.choice = response_id;
+ g_cond_signal(&send_message.cond);
+ g_mutex_unlock(&send_message.lock);
+
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+}
+
+typedef struct {
+ GtkWindow *window;
+ gboolean warn_mp;
+ gboolean warn_html_sign;
+} send_message_info;
+
+static gboolean
+send_message_thread_idle(gpointer user_data)
+{
+ send_message_info *info = user_data;
+ GtkWidget *dialog;
+ GString *string =
+ g_string_new(_("You selected OpenPGP security for this message.\n"));
+
+ if (info->warn_html_sign)
+ g_string_append(string,
+ _("The message text will be sent as plain text and as "
+ "HTML, but only the plain part can be signed.\n"));
+ if (info->warn_mp)
+ g_string_append(string,
+ _("The message contains attachments, which cannot be "
+ "signed or encrypted.\n"));
+ g_string_append(string,
+ _("You should select MIME mode if the complete "
+ "message shall be protected. Do you really want to proceed?"));
+ dialog =
+ gtk_message_dialog_new(info->window,
+ GTK_DIALOG_DESTROY_WITH_PARENT |
+ GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_OK_CANCEL, "%s", string->str);
+#if HAVE_MACOSX_DESKTOP
+ libbalsa_macosx_menu_for_parent(dialog, info->window);
+#endif
+ g_string_free(string, TRUE);
+ g_free(info);
+
+ g_signal_connect(dialog, "response", G_CALLBACK(send_message_thread_response), NULL);
+
+ return G_SOURCE_REMOVE;
+}
+
+static gpointer
+send_message_thread(gpointer data)
{
+ BalsaSendmsg *bsmsg = data;
LibBalsaMsgCreateResult result;
LibBalsaMessage *message;
LibBalsaMailbox *fcc;
GtkTreeIter iter;
GError * error = NULL;
- if (!bsmsg->ready_to_send)
- return FALSE;
-
- if(!subject_not_empty(bsmsg))
- return FALSE;
-
#ifdef ENABLE_AUTOCRYPT
if (!check_autocrypt_recommendation(bsmsg)) {
- return FALSE;
+ return NULL;
}
#else
if (!check_suggest_encryption(bsmsg)) {
- return FALSE;
+ return NULL;
}
#endif /* ENABLE_AUTOCRYPT */
@@ -5496,40 +5557,23 @@ send_message_handler(BalsaSendmsg * bsmsg, gboolean queue_only)
bsmsg->send_mp_alt;
if (warn_mp || warn_html_sign) {
+ send_message_info *info;
/* we are going to RFC2440 sign/encrypt a multipart, or to
* RFC2440 sign a multipart/alternative... */
- GtkWidget *dialog;
- gint choice;
- GString * string =
- g_string_new(_("You selected OpenPGP security for this message.\n"));
-
- if (warn_html_sign)
- string =
- g_string_append(string,
- _("The message text will be sent as plain text and as "
- "HTML, but only the plain part can be signed.\n"));
- if (warn_mp)
- string =
- g_string_append(string,
- _("The message contains attachments, which cannot be "
- "signed or encrypted.\n"));
- string =
- g_string_append(string,
- _("You should select MIME mode if the complete "
- "message shall be protected. Do you really want to proceed?"));
- dialog = gtk_message_dialog_new
- (GTK_WINDOW(bsmsg->window),
- GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
- GTK_MESSAGE_QUESTION,
- GTK_BUTTONS_OK_CANCEL, "%s", string->str);
-#if HAVE_MACOSX_DESKTOP
- libbalsa_macosx_menu_for_parent(dialog, GTK_WINDOW(bsmsg->window));
-#endif
- g_string_free(string, TRUE);
- choice = gtk_dialog_run(GTK_DIALOG(dialog));
- gtk_widget_destroy(dialog);
- if (choice != GTK_RESPONSE_OK)
- return FALSE;
+ info = g_new(send_message_info, 1);
+ info->window = GTK_WINDOW(bsmsg->window);
+ info->warn_mp = warn_mp;
+ info->warn_html_sign = warn_html_sign;
+ g_idle_add(send_message_thread_idle, info);
+
+ g_mutex_lock(&send_message.lock);
+ send_message.choice = 0;
+ while (send_message.choice == 0)
+ g_cond_wait(&send_message.cond, &send_message.lock);
+ g_mutex_unlock(&send_message.lock);
+
+ if (send_message.choice != GTK_RESPONSE_OK)
+ return NULL;
}
}
@@ -5541,7 +5585,7 @@ send_message_handler(BalsaSendmsg * bsmsg, gboolean queue_only)
_("sending message with GPG mode %d"),
libbalsa_message_get_gpg_mode(message));
- if(queue_only)
+ if(bsmsg->queue_only)
result = libbalsa_message_queue(message, balsa_app.outbox, fcc,
libbalsa_identity_get_smtp_server(bsmsg->ident),
bsmsg->flow, &error);
@@ -5549,7 +5593,7 @@ send_message_handler(BalsaSendmsg * bsmsg, gboolean queue_only)
result = libbalsa_message_send(message, balsa_app.outbox, fcc,
balsa_find_sentbox_by_url,
libbalsa_identity_get_smtp_server(bsmsg->ident),
- balsa_app.send_progress_dialog,
+ balsa_app.send_progress_dialog,
GTK_WINDOW(balsa_app.main_window),
bsmsg->flow, &error);
if (result == LIBBALSA_MESSAGE_CREATE_OK) {
@@ -5591,12 +5635,27 @@ send_message_handler(BalsaSendmsg * bsmsg, gboolean queue_only)
LIBBALSA_INFORMATION_ERROR,
_("Send failed: %s"), msg);
}
- return FALSE;
+ return NULL;
}
gtk_widget_destroy(bsmsg->window);
- return TRUE;
+ return NULL;
+}
+
+static void
+send_message_handler(BalsaSendmsg * bsmsg)
+{
+ GThread *thread;
+
+ if (!bsmsg->ready_to_send)
+ return;
+
+ if(!subject_not_empty(bsmsg))
+ return;
+
+ thread = g_thread_new("send-message", send_message_thread, bsmsg);
+ g_thread_unref(thread);
}
@@ -5606,7 +5665,8 @@ sw_toolbar_send_activated(GSimpleAction * action, GVariant * parameter, gpointer
{
BalsaSendmsg *bsmsg = data;
- send_message_handler(bsmsg, balsa_app.always_queue_sent_mail);
+ bsmsg->queue_only = balsa_app.always_queue_sent_mail;
+ send_message_handler(bsmsg);
}
static void
@@ -5614,7 +5674,8 @@ sw_send_activated(GSimpleAction * action, GVariant * parameter, gpointer data)
{
BalsaSendmsg *bsmsg = data;
- send_message_handler(bsmsg, FALSE);
+ bsmsg->queue_only = FALSE;
+ send_message_handler(bsmsg);
}
@@ -5623,7 +5684,8 @@ sw_queue_activated(GSimpleAction * action, GVariant * parameter, gpointer data)
{
BalsaSendmsg *bsmsg = data;
- send_message_handler(bsmsg, TRUE);
+ bsmsg->queue_only = TRUE;
+ send_message_handler(bsmsg);
}
static gboolean
diff --git a/src/sendmsg-window.h b/src/sendmsg-window.h
index 28ac8fad9..9092ce5ee 100644
--- a/src/sendmsg-window.h
+++ b/src/sendmsg-window.h
@@ -103,7 +103,9 @@ G_BEGIN_DECLS
GtkTextMark *insert_mark;
GtkWidget *paned;
+
gboolean ready_to_send;
+ gboolean queue_only; /* Set when about to send */
};
BalsaSendmsg *sendmsg_window_compose(void);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]