Merge branch 'mainline' into letorbi/gmime-3

This commit is contained in:
Torben 2019-12-10 12:35:00 +01:00
commit 619b6fb838
19 changed files with 273 additions and 161 deletions

View file

@ -29,6 +29,7 @@ Getting in Touch
* Geary wiki: https://wiki.gnome.org/Apps/Geary
* Mailing list: http://mail.gnome.org/mailman/listinfo/geary-list
* IRC Channel: [#geary on irc.gimp.org](irc://irc.gimp.org/%23geary)
* Matrix channel: [#_gimpnet_#geary:gnome.org](https://riot.im/app/#/room/#_gimpnet_#geary:gnome.org)
**Code Of Conduct**

View file

@ -756,13 +756,17 @@ public class Application.Client : Gtk.Application {
// shut the whole thing down if destroy_controller() takes too
// long to complete
int64 start_usec = get_monotonic_time();
while (!controller_closed) {
while (!controller_closed && Gtk.events_pending()) {
Gtk.main_iteration();
int64 delta_usec = get_monotonic_time() - start_usec;
if (delta_usec >= FORCE_SHUTDOWN_USEC) {
debug("Forcing shutdown of Geary, %ss passed...",
(delta_usec / USEC_PER_SEC).to_string());
// Use a warning here so a) it's usually logged
// and b) we can run under gdb with
// G_DEBUG=fatal-warnings and have it break when
// this happens, and maybe debug it.
warning("Forcing shutdown of Geary, %ss passed...",
(delta_usec / USEC_PER_SEC).to_string());
Posix.exit(2);
}
}
@ -833,8 +837,10 @@ public class Application.Client : Gtk.Application {
// Opens the controller
private async void create_controller() {
bool first_run = false;
bool open_failed = false;
int mutex_token = Geary.Nonblocking.Mutex.INVALID_TOKEN;
try {
int mutex_token = yield this.controller_mutex.claim_async();
mutex_token = yield this.controller_mutex.claim_async();
if (this.controller == null) {
message(
"%s %s%s prefix=%s exec_dir=%s is_installed=%s",
@ -851,9 +857,28 @@ public class Application.Client : Gtk.Application {
);
first_run = !this.engine.has_accounts;
}
this.controller_mutex.release(ref mutex_token);
} catch (Error err) {
error("Error creating controller: %s", err.message);
open_failed = true;
warning("Error creating controller: %s", err.message);
var dialog = new Dialogs.ProblemDetailsDialog(
null,
this,
new Geary.ProblemReport(err)
);
dialog.run();
}
if (mutex_token != Geary.Nonblocking.Mutex.INVALID_TOKEN) {
try {
this.controller_mutex.release(ref mutex_token);
} catch (GLib.Error error) {
warning("Failed to release controller mutex: %s",
error.message);
}
}
if (open_failed) {
quit();
}
if (first_run) {

View file

@ -119,47 +119,6 @@ public class Application.Configuration : Geary.BaseObject {
public bool single_key_shortcuts { get; set; default = false; }
/**
* The set of enabled spell checker languages.
*
* This specifies the languages used for spell checking by the
* client. By default, the set will contain languages based on
* environment variables.
*
* @see Util.International.get_user_preferred_languages
*/
public string[] spell_check_languages {
owned get {
GLib.Variant? value =
settings.get_value(SPELL_CHECK_LANGUAGES).get_maybe();
string[] langs = (value != null)
? value.get_strv()
: Util.International.get_user_preferred_languages();
return langs;
}
set {
settings.set_value(
SPELL_CHECK_LANGUAGES,
new GLib.Variant.maybe(null, new GLib.Variant.strv(value))
);
}
}
/**
* The set of visible spell checker languages.
*
* This is the list of languages shown when selecting languages to
* be used for spell checking.
*/
public string[] spell_check_visible_languages {
owned get {
return settings.get_strv(SPELL_CHECK_VISIBLE_LANGUAGES);
}
set {
settings.set_strv(SPELL_CHECK_VISIBLE_LANGUAGES, value);
}
}
public bool startup_notifications {
get { return settings.get_boolean(STARTUP_NOTIFICATIONS_KEY); }
set { set_boolean(STARTUP_NOTIFICATIONS_KEY, value); }
@ -190,22 +149,6 @@ public class Application.Configuration : Geary.BaseObject {
set { settings.set_double(CONVERSATION_VIEWER_ZOOM_KEY, value); }
}
public int[] composer_window_size {
owned get {
int[] size = new int[2];
var s = settings.get_value(COMPOSER_WINDOW_SIZE_KEY);
if (s.n_children () == 2) {
size = { (int) s.get_child_value(0), (int) s.get_child_value(1)};
} else {
size = {-1,-1};
}
return size;
}
set {
settings.set_value(COMPOSER_WINDOW_SIZE_KEY, value);
}
}
/** The number of seconds to wait before sending an email. */
public int undo_send_delay {
get { return settings.get_int(UNDO_SEND_DELAY); }
@ -233,6 +176,78 @@ public class Application.Configuration : Geary.BaseObject {
message("Unable to set configuration value %s = %s", name, value.to_string());
}
/** Returns the saved size of the composer window. */
public int[] get_composer_window_size() {
int[] size = new int[2];
var s = this.settings.get_value(COMPOSER_WINDOW_SIZE_KEY);
if (s.n_children () == 2) {
size = { (int) s.get_child_value(0), (int) s.get_child_value(1)};
} else {
size = {-1,-1};
}
return size;
}
/** Sets the saved size of the composer window. */
public void set_composer_window_size(int[] value) {
this.settings.set_value(COMPOSER_WINDOW_SIZE_KEY, value);
}
/**
* Returns enabled spell checker languages.
*
* This specifies the languages used for spell checking by the
* client. By default, the set will contain languages based on
* environment variables.
*
* @see Util.International.get_user_preferred_languages
*/
public string[] get_spell_check_languages() {
GLib.Variant? value = this.settings.get_value(
SPELL_CHECK_LANGUAGES
).get_maybe();
string[] langs = (value != null)
? value.get_strv()
: Util.International.get_user_preferred_languages();
return langs;
}
/**
* Sets enabled spell checker languages.
*
* This specifies the languages used for spell checking by the
* client. By default, the set will contain languages based on
* environment variables.
*
* @see Util.International.get_user_preferred_languages
*/
public void set_spell_check_languages(string[] value) {
this.settings.set_value(
SPELL_CHECK_LANGUAGES,
new GLib.Variant.maybe(null, new GLib.Variant.strv(value))
);
}
/**
* Returns visible spell checker languages.
*
* This is the list of languages shown when selecting languages to
* be used for spell checking.
*/
public string[] get_spell_check_visible_languages() {
return this.settings.get_strv(SPELL_CHECK_VISIBLE_LANGUAGES);
}
/**
* Sets visible spell checker languages.
*
* This is the list of languages shown when selecting languages to
* be used for spell checking.
*/
public void set_spell_check_visible_languages(string[] value) {
this.settings.set_strv(SPELL_CHECK_VISIBLE_LANGUAGES, value);
}
public Geary.SearchQuery.Strategy get_search_strategy() {
switch (settings.get_string(SEARCH_STRATEGY_KEY).down()) {
case "exact":

View file

@ -121,7 +121,8 @@ internal class Application.Controller : Geary.BaseObject {
* Constructs a new instance of the controller.
*/
public async Controller(Client application,
GLib.Cancellable cancellable) {
GLib.Cancellable cancellable)
throws GLib.Error {
this.application = application;
this.controller_open = cancellable;
@ -139,16 +140,12 @@ internal class Application.Controller : Geary.BaseObject {
this.application.get_web_extensions_dir(),
this.application.get_user_cache_directory().get_child("web-resources")
);
try {
Components.WebView.load_resources(
this.application.get_user_config_directory()
);
Composer.WebView.load_resources();
ConversationWebView.load_resources();
Accounts.SignatureWebView.load_resources();
} catch (Error err) {
error("Error loading web resources: %s", err.message);
}
Components.WebView.load_resources(
this.application.get_user_config_directory()
);
Composer.WebView.load_resources();
ConversationWebView.load_resources();
Accounts.SignatureWebView.load_resources();
this.folks = Folks.IndividualAggregator.dup();
if (!this.folks.is_prepared) {
@ -173,12 +170,8 @@ internal class Application.Controller : Geary.BaseObject {
this.plugin_manager.load();
// Migrate configuration if necessary.
try {
Migrate.xdg_config_dir(this.application.get_user_data_directory(),
this.application.get_user_config_directory());
} catch (Error e) {
error("Error migrating configuration directories: %s", e.message);
}
Migrate.xdg_config_dir(this.application.get_user_data_directory(),
this.application.get_user_config_directory());
// Hook up cert, accounts and credentials machinery
@ -187,12 +180,7 @@ internal class Application.Controller : Geary.BaseObject {
cancellable
);
SecretMediator? libsecret = null;
try {
libsecret = yield new SecretMediator(cancellable);
} catch (GLib.Error err) {
error("Error opening libsecret: %s", err.message);
}
SecretMediator? libsecret = yield new SecretMediator(cancellable);
application.engine.account_available.connect(on_account_available);
@ -214,18 +202,10 @@ internal class Application.Controller : Geary.BaseObject {
on_report_problem
);
try {
yield this.account_manager.connect_goa(cancellable);
} catch (GLib.Error err) {
warning("Error opening GOA: %s", err.message);
}
yield this.account_manager.connect_goa(cancellable);
// Start loading accounts
try {
yield this.account_manager.load_accounts(cancellable);
} catch (Error e) {
warning("Error loading accounts: %s", e.message);
}
yield this.account_manager.load_accounts(cancellable);
// Expunge any deleted accounts in the background, so we're
// not blocking the app continuing to open.

View file

@ -669,9 +669,11 @@ public class Application.MainWindow :
// selection changed callback. That will check to
// ensure that we're not setting it again.
if (to_select != null) {
// Prefer the inboxes branch if it exists
if (to_select.special_folder_type != INBOX ||
!this.folder_list.select_inbox(to_select.account)) {
// Prefer the inboxes branch if it is a thing, but
// only for non-interactive calls
if (is_interactive ||
(to_select.special_folder_type != INBOX ||
!this.folder_list.select_inbox(to_select.account))) {
this.folder_list.select_folder(to_select);
}
} else {
@ -949,7 +951,7 @@ public class Application.MainWindow :
to_add.account, _("Labels")
);
this.progress_monitor.add(to_add.account.opening_monitor);
this.progress_monitor.add(to_add.account.background_progress);
Geary.Smtp.ClientService? smtp = (
to_add.account.outgoing as Geary.Smtp.ClientService
);
@ -1010,7 +1012,7 @@ public class Application.MainWindow :
to_remove.commands.undone.disconnect(on_command_undo);
to_remove.commands.redone.disconnect(on_command_redo);
this.progress_monitor.remove(to_remove.account.opening_monitor);
this.progress_monitor.remove(to_remove.account.background_progress);
Geary.Smtp.ClientService? smtp = (
to_remove.account.outgoing as Geary.Smtp.ClientService
);
@ -1215,6 +1217,7 @@ public class Application.MainWindow :
this.spinner.set_size_request(STATUS_BAR_HEIGHT - 2, -1);
this.spinner.set_progress_monitor(progress_monitor);
this.status_bar.add(this.spinner);
this.status_bar.show_all();
}
/** {@inheritDoc} */

View file

@ -211,15 +211,11 @@ public class Components.InspectorLogView : Gtk.Grid {
}
private inline bool should_append(Geary.Logging.Record record) {
// Blacklist GdkPixbuf since it spams us e.g. when window
// focus changes, including between MainWindow and the
// Inspector, which is very annoying.
record.fill_well_known_sources();
return (
record.domain != "GdkPixbuf" &&
(record.account == null ||
this.account_filter == null ||
record.account.information == this.account_filter)
record.account == null ||
this.account_filter == null ||
record.account.information == this.account_filter
);
}

View file

@ -175,8 +175,9 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
private static inline void update_spellcheck(WebKit.WebContext context,
Application.Configuration config) {
context.set_spell_checking_enabled(config.spell_check_languages.length > 0);
context.set_spell_checking_languages(config.spell_check_languages);
string[] langs = config.get_spell_check_languages();
context.set_spell_checking_enabled(langs.length > 0);
context.set_spell_checking_languages(langs);
}
private static inline uint to_wk2_font_size(Pango.FontDescription font) {

View file

@ -126,13 +126,16 @@ public class MainWindowInfoBar : Gtk.InfoBar {
}
private void show_details() {
Dialogs.ProblemDetailsDialog dialog =
new Dialogs.ProblemDetailsDialog(
get_toplevel() as Application.MainWindow,
var main = get_toplevel() as Application.MainWindow;
if (main != null) {
var dialog = new Dialogs.ProblemDetailsDialog(
main,
main.application,
this.report
);
dialog.run();
dialog.destroy();
dialog.run();
dialog.destroy();
}
}
[GtkCallback]

View file

@ -27,7 +27,6 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
/// Translators: Title for an empty composer window
private const string DEFAULT_TITLE = _("New Message");
public enum ComposeType {
NEW_MESSAGE,
REPLY,
@ -386,6 +385,9 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
[GtkChild]
private Gtk.Label info_label;
[GtkChild]
private Gtk.ProgressBar background_progress;
private GLib.SimpleActionGroup composer_actions = new GLib.SimpleActionGroup();
private GLib.SimpleActionGroup editor_actions = new GLib.SimpleActionGroup();
@ -468,6 +470,12 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
private Application.Client application;
// Timeout for showing the slow image paste pulsing bar
private Geary.TimeoutManager show_background_work_timeout = null;
// Timer for pulsing progress bar
private Geary.TimeoutManager background_work_pulse;
public Widget(Application.Client application,
Geary.Account initial_account,
@ -593,6 +601,14 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
this.editor.mouse_target_changed.connect(on_mouse_target_changed);
this.editor.selection_changed.connect(on_selection_changed);
this.show_background_work_timeout = new Geary.TimeoutManager.milliseconds(
Util.Gtk.SHOW_PROGRESS_TIMEOUT_MSEC, this.on_background_work_timeout
);
this.background_work_pulse = new Geary.TimeoutManager.milliseconds(
Util.Gtk.PROGRESS_PULSE_TIMEOUT_MSEC, this.background_progress.pulse
);
this.background_work_pulse.repetition = FOREVER;
load_entry_completions();
}
@ -885,6 +901,9 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
on_account_unavailable
);
this.show_background_work_timeout.reset();
this.background_work_pulse.reset();
base.destroy();
}
@ -2036,30 +2055,39 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
private void paste_image() {
// The slow operations here are creating the PNG and, to a lesser extent,
// requesting the image from the clipboard
this.container.top_window.application.mark_busy();
this.show_background_work_timeout.start();
get_clipboard(Gdk.SELECTION_CLIPBOARD).request_image((clipboard, pixbuf) => {
if (pixbuf != null) {
try {
uint8[] buffer;
pixbuf.save_to_buffer(out buffer, "png");
Geary.Memory.ByteBuffer byte_buffer = new Geary.Memory.ByteBuffer(buffer, buffer.length);
MemoryOutputStream os = new MemoryOutputStream(null);
pixbuf.save_to_stream_async.begin(os, "png", null, (obj, res) => {
try {
pixbuf.save_to_stream_async.end(res);
os.close();
GLib.DateTime time_now = new GLib.DateTime.now();
string filename = PASTED_IMAGE_FILENAME_TEMPLATE.printf(time_now.hash());
Geary.Memory.ByteBuffer byte_buffer = new Geary.Memory.ByteBuffer.from_memory_output_stream(os);
string unique_filename;
add_inline_part(byte_buffer, filename, out unique_filename);
this.editor.insert_image(
Components.WebView.INTERNAL_URL_PREFIX + unique_filename
);
} catch (Error error) {
warning("Failed to paste image %s", error.message);
}
GLib.DateTime time_now = new GLib.DateTime.now();
string filename = PASTED_IMAGE_FILENAME_TEMPLATE.printf(time_now.hash());
string unique_filename;
add_inline_part(byte_buffer, filename, out unique_filename);
this.editor.insert_image(
Components.WebView.INTERNAL_URL_PREFIX + unique_filename
);
throw new Geary.EngineError.UNSUPPORTED("Mock method");
} catch (Error error) {
this.application.controller.report_problem(
new Geary.ProblemReport(error)
);
}
stop_background_work_pulse();
});
} else {
warning("Failed to get image from clipboard");
stop_background_work_pulse();
}
this.container.top_window.application.unmark_busy();
});
}
@ -2279,7 +2307,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
this.select_dictionary_button, config
);
this.spell_check_popover.selection_changed.connect((active_langs) => {
config.spell_check_languages = active_langs;
config.set_spell_check_languages(active_langs);
update_subject_spell_checker();
});
}
@ -2482,7 +2510,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
private void update_subject_spell_checker() {
Gspell.Language? lang = null;
string[] langs = this.application.config.spell_check_languages;
string[] langs = this.application.config.get_spell_check_languages();
if (langs.length == 1) {
lang = Gspell.Language.lookup(langs[0]);
} else {
@ -2807,4 +2835,18 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
Components.WebView.INTERNAL_URL_PREFIX + unique_filename
);
}
/** Shows and starts pulsing the progress meter. */
private void on_background_work_timeout() {
this.background_progress.fraction = 0.0;
this.background_work_pulse.start();
this.background_progress.show();
}
/** Hides and stops pulsing the progress meter. */
private void stop_background_work_pulse() {
this.background_progress.hide();
this.background_work_pulse.reset();
this.show_background_work_timeout.reset();
}
}

View file

@ -66,7 +66,7 @@ public class Composer.Window : Gtk.ApplicationWindow, Container {
if (monitor == null) {
monitor = display.get_monitor_at_point(1, 1);
}
int[] size = this.application.config.composer_window_size;
int[] size = this.application.config.get_composer_window_size();
//check if stored values are reasonable
if (monitor != null &&
size[0] >= 0 && size[0] <= monitor.geometry.width &&
@ -94,9 +94,9 @@ public class Composer.Window : Gtk.ApplicationWindow, Container {
// Only store if the values are reasonable-looking.
if (width > 0 && width <= monitor.geometry.width &&
height > 0 && height <= monitor.geometry.height) {
this.application.config.composer_window_size = {
width, height
};
this.application.config.set_composer_window_size({
width, height
});
}
}
}

View file

@ -191,8 +191,8 @@ public class SpellCheckPopover {
private void setup_popover() {
// We populate the popover with the list of languages that the user wants to see
string[] languages = Util.International.get_available_dictionaries();
string[] enabled_langs = this.config.spell_check_languages;
string[] visible_langs = this.config.spell_check_visible_languages;
string[] enabled_langs = this.config.get_spell_check_languages();
string[] visible_langs = this.config.get_spell_check_visible_languages();
content = new Gtk.Box(Gtk.Orientation.VERTICAL, 6);
search_box = new Gtk.SearchEntry();
@ -302,7 +302,7 @@ public class SpellCheckPopover {
bool is_visible) {
langs_list.invalidate_filter();
string[] visible_langs = this.config.spell_check_visible_languages;
string[] visible_langs = this.config.get_spell_check_visible_languages();
string lang = row.lang_code;
if (is_visible) {
if (!(lang in visible_langs)) {
@ -317,7 +317,7 @@ public class SpellCheckPopover {
}
visible_langs = new_langs;
}
this.config.spell_check_visible_languages = visible_langs;
this.config.set_spell_check_visible_languages(visible_langs);
}
}

View file

@ -30,10 +30,6 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
private const int MAX_PREVIEW_BYTES = Geary.Email.MAX_PREVIEW_BYTES;
private const int SHOW_PROGRESS_TIMEOUT_MSEC = 1000;
private const int HIDE_PROGRESS_TIMEOUT_MSEC = 1000;
private const int PULSE_TIMEOUT_MSEC = 250;
private const int MAX_INLINE_IMAGE_MAJOR_DIM = 1024;
private const string ACTION_CONVERSATION_NEW = "conversation-new";
@ -494,14 +490,14 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
this.body_container.set_has_tooltip(true); // Used to show link URLs
this.show_progress_timeout = new Geary.TimeoutManager.milliseconds(
SHOW_PROGRESS_TIMEOUT_MSEC, this.on_show_progress_timeout
Util.Gtk.SHOW_PROGRESS_TIMEOUT_MSEC, this.on_show_progress_timeout
);
this.hide_progress_timeout = new Geary.TimeoutManager.milliseconds(
HIDE_PROGRESS_TIMEOUT_MSEC, this.on_hide_progress_timeout
Util.Gtk.HIDE_PROGRESS_TIMEOUT_MSEC, this.on_hide_progress_timeout
);
this.progress_pulse = new Geary.TimeoutManager.milliseconds(
PULSE_TIMEOUT_MSEC, this.body_progress.pulse
Util.Gtk.PROGRESS_PULSE_TIMEOUT_MSEC, this.body_progress.pulse
);
this.progress_pulse.repetition = FOREVER;
}

View file

@ -51,7 +51,8 @@ public class Dialogs.ProblemDetailsDialog : Hdy.Dialog {
private Geary.ServiceInformation? service;
public ProblemDetailsDialog(Application.MainWindow parent,
public ProblemDetailsDialog(Gtk.Window? parent,
Application.Client application,
Geary.ProblemReport report) {
Object(
transient_for: parent,
@ -83,7 +84,7 @@ public class Dialogs.ProblemDetailsDialog : Hdy.Dialog {
);
this.log_pane = new Components.InspectorLogView(
parent.application.config, account
application.config, account
);
this.log_pane.load(report.earliest_log, report.latest_log);
this.log_pane.record_selection_changed.connect(
@ -91,7 +92,7 @@ public class Dialogs.ProblemDetailsDialog : Hdy.Dialog {
);
this.system_pane = new Components.InspectorSystemView(
parent.application
application
);
/// Translators: Title for problem report dialog error

View file

@ -8,6 +8,13 @@
namespace Util.Gtk {
/** Delay before showing progress bar for background operations. */
public const int SHOW_PROGRESS_TIMEOUT_MSEC = 1000;
/** Minimum time for display of progress bar for background operations. */
public const int HIDE_PROGRESS_TIMEOUT_MSEC = 1000;
/** Frequency for pulse of progress bar for background operations. */
public const int PROGRESS_PULSE_TIMEOUT_MSEC = 250;
/**
* Given an HTML-style color spec, parses the color and sets it to
* the source RGB of the Cairo context. (Borrowed from Shotwell.)

View file

@ -131,10 +131,10 @@ public abstract class Geary.Account : BaseObject, Logging.Source {
*/
public Geary.ContactStore contact_store { get; protected set; }
public Geary.ProgressMonitor search_upgrade_monitor { get; protected set; }
public Geary.ProgressMonitor db_upgrade_monitor { get; protected set; }
public Geary.ProgressMonitor db_vacuum_monitor { get; protected set; }
public Geary.ProgressMonitor opening_monitor { get; protected set; }
public ProgressMonitor background_progress { get; protected set; }
public ProgressMonitor search_upgrade_monitor { get; protected set; }
public ProgressMonitor db_upgrade_monitor { get; protected set; }
public ProgressMonitor db_vacuum_monitor { get; protected set; }
public signal void opened();

View file

@ -494,6 +494,9 @@ public void log_to(FileStream? stream) {
public GLib.LogWriterOutput default_log_writer(GLib.LogLevelFlags levels,
GLib.LogField[] fields) {
Record record = new Record(fields, levels, GLib.get_real_time());
if (should_blacklist(record)) {
return GLib.LogWriterOutput.HANDLED;
}
// Keep the old first record so we don't cause any records to be
// finalised while under the lock, leading to deadlock if
@ -537,6 +540,24 @@ public GLib.LogWriterOutput default_log_writer(GLib.LogLevelFlags levels,
return GLib.LogWriterOutput.HANDLED;
}
private bool should_blacklist(Record record) {
return (
// GdkPixbuf spams us e.g. when window focus changes,
// including between MainWindow and the Inspector, which is
// very annoying.
(record.levels == GLib.LogLevelFlags.LEVEL_DEBUG &&
record.domain == "GdkPixbuf") ||
// GAction does not support disabling parameterised actions
// with specific values, but GTK complains if the parameter is
// set to null to achieve the same effect, and they aren't
// interested in supporting that: GNOME/gtk!1151
(record.levels == GLib.LogLevelFlags.LEVEL_WARNING &&
record.domain == "Gtk" &&
record.message.has_prefix("actionhelper:") &&
record.message.has_suffix("target type NULL)"))
);
}
private inline void write_record(Record record,
GLib.LogLevelFlags levels) {
// Print a log message to the stream if configured, or if the

View file

@ -57,10 +57,13 @@ internal class Geary.ImapEngine.AccountProcessor :
private AccountOperation? current_op = null;
private GLib.Cancellable? op_cancellable = null;
private ProgressMonitor? progress;
public AccountProcessor() {
public AccountProcessor(ProgressMonitor? progress = null) {
this.queue.allow_duplicates = false;
this.is_running = true;
this.progress = progress;
this.run.begin();
}
@ -109,6 +112,10 @@ internal class Geary.ImapEngine.AccountProcessor :
debug("Executing operation: %s", op.to_string());
this.current_op = op;
if (this.progress != null) {
this.progress.notify_start();
}
Error? op_error = null;
int network_errors = 0;
while (op_error == null) {
@ -139,6 +146,10 @@ internal class Geary.ImapEngine.AccountProcessor :
this.current_op = null;
this.op_cancellable = null;
if (this.progress != null) {
this.progress.notify_finish();
}
}
}
}

View file

@ -106,7 +106,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
() => { this.update_remote_folders(); }
);
this.opening_monitor = new ReentrantProgressMonitor(Geary.ProgressType.ACTIVITY);
this.background_progress = new ReentrantProgressMonitor(ACTIVITY);
this.search_upgrade_monitor = local.search_index_monitor;
this.db_upgrade_monitor = local.upgrade_monitor;
this.db_vacuum_monitor = local.vacuum_monitor;
@ -119,11 +119,11 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
if (open)
throw new EngineError.ALREADY_OPEN("Account %s already opened", to_string());
opening_monitor.notify_start();
this.background_progress.notify_start();
try {
yield internal_open_async(cancellable);
} finally {
opening_monitor.notify_finish();
this.background_progress.notify_finish();
}
}
@ -131,7 +131,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
this.open_cancellable = new Cancellable();
this.remote_ready_lock = new Nonblocking.Semaphore(this.open_cancellable);
this.processor = new AccountProcessor();
this.processor = new AccountProcessor(this.background_progress);
this.processor.operation_error.connect(on_operation_error);
this.processor.set_logging_parent(this);

View file

@ -850,6 +850,16 @@
</style>
</object>
</child>
<child type="overlay">
<object class="GtkProgressBar" id="background_progress">
<property name="can_focus">False</property>
<property name="valign">start</property>
<style>
<class name="osd"/>
<class name="top"/>
</style>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>